Internationalised labels in JSF/Facelets
Facelets是否具有通过使用JSF可以更整洁或更可读的国际化用户界面文本标签的功能?
例如,对于纯JSF,使用h:outputFormat是在消息中插入变量的非常冗长的方法。
说明:我知道我可以添加一个如下所示的消息文件条目:
1 | label.widget.count = You have a total of {0} widgets. |
并显示以下内容(如果我正在使用Seam):
1 2 3 | <h:outputFormat value="#{messages['label.widget.count']}"> <f:param value="#{widgetCount}"/> </h:outputFormat> |
但是输出一个句子会很混乱-只是那种使JSF不好名的东西。
由于您正在使用Seam,因此可以在消息文件中使用EL。
属性:
1 | label.widget.count = You have a total of #{widgetCount} widgets. |
XHTML:
1 | <h:outputFormat value="#{messages['label.widget.count']}" /> |
这仍然使用outputFormat,但是不太冗长。
您可以使用接缝内插器:
1 | <h:outputText value="#{interpolator.interpolate(messages['label.widget.count'], widgetCount)}"/> |
上面带有@BypassInterceptors,因此性能应该可以。
您可以创建自己的faces标签库,以使其不再那么冗长,例如:
1 | <ph:i18n key="label.widget.count" p0="#{widgetCount}"/> |
然后在视图目录中创建taglib:/components/ph.taglib.xml
1 2 3 4 5 6 7 8 9 10 11 12 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE facelet-taglib PUBLIC"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN""https://facelets.dev.java.net/source/browse/*checkout*/facelets/src/etc/facelet-taglib_1_0.dtd"> <facelet-taglib xmlns="http://java.sun.com/JSF/Facelet"> <namespace>http://peterhilton.com/core</namespace> <tag> <tag-name>i18n</tag-name> <source>i18n.xhtml</source> </tag> </facelet-taglib> |
创建/components/i18n.xhtml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <h:outputFormat value="#{messages[key]}"> <!-- crude but it works --> <f:param value="#{p0}" /> <f:param value="#{p1}" /> <f:param value="#{p2}" /> <f:param value="#{p3}" /> </h:outputFormat> </ui:composition> |
通过一些研究,您可能会找到一种传递论点的优雅方法。
现在在web.xml中注册新的taglib
1 2 3 4 5 6 | <context-param> <param-name>facelets.LIBRARIES</param-name> <param-value> /components/ph.taglib.xml </param-value> </context-param> |
只需将
我一直在考虑这个问题,我想到我可能可以编写自己的JSTL函数,该函数需要一个消息密钥和可变数量的参数:
1 | <h:outputText value="#{my:message('label.widget.count', widgetCount)}"/> |
,如果我的消息功能在输出之前对结果进行HTML编码,则我什至不需要使用h:outputText
1 | #{my:message('label.widget.count', widgetCount)} |
除了outputFormat之外,我再也没有遇到过其他方法。不幸的是,它很冗长。
我只能建议的另一件事是在后备bean中创建消息,然后将其输出而不是messageFormat。
在我的情况下,我将Spring的MessageSource与JSF集成在一起(使用MessageSourcePropertyResolver)。然后,在支持bean中获取参数化消息非常容易-您只需要知道用户所在的语言环境即可(同样,我将Locale绑定到支持bean属性,因此可以通过JSF或Java对其进行访问)。铅>
我认为参数-特别是消息中的参数-是JSF确实可以做得更好的一件事!
如果对消息进行插值,则可以直接使用Bean。
1 2 3 | label.widget.count = You have a total of #{widgetCount} widgets. label.welcome.message = Welcome to #{request.contextPath}! label.welcome.url = Your path is ${pageContext.servletContext}. |
使用Spring可以很好地工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package foo; import javax.el.ELContext; import javax.el.ELException; import javax.el.ExpressionFactory; import javax.el.ResourceBundleELResolver; import javax.faces.context.FacesContext; import org.springframework.web.jsf.el.SpringBeanFacesELResolver; public class ELResolver extends SpringBeanFacesELResolver { private static final ExpressionFactory FACTORY = FacesContext .getCurrentInstance().getApplication().getExpressionFactory(); private static final ResourceBundleELResolver RESOLVER = new ResourceBundleELResolver(); @Override public Object getValue(ELContext elContext, Object base, Object property) throws ELException { Object result = super.getValue(elContext, base, property); if (result == null) { result = RESOLVER.getValue(elContext, base, property); if (result instanceof String) { String el = (String) result; if (el.contains("${") | el.contains("#{")) { result = FACTORY.createValueExpression(elContext, el, String.class).getValue(elContext); } } } return result; } } |
然后...
您需要将
致谢
1 | <el-resolver>foo.ELResolver</el-resolver> |
使用ResourceBundle和属性文件。