Интернационализированные этикетки в JSF/Facelets
-
01-07-2019 - |
Вопрос
Делает Фасетки есть ли какие-либо функции для более аккуратных или более читаемых текстовых меток интернационализированного пользовательского интерфейса, которые вы могли бы сделать с помощью JSF?
Например, в обычном JSF использование h:OutputFormat является очень подробным способом интерполяции переменных в сообщениях.
Разъяснение: Я знаю, что могу добавить запись в файле сообщений, которая выглядит следующим образом:
label.widget.count = You have a total of {0} widgets.
и отобразите это (если я использую Seam) с помощью:
<h:outputFormat value="#{messages['label.widget.count']}">
<f:param value="#{widgetCount}"/>
</h:outputFormat>
но для вывода одного предложения слишком много беспорядка - как раз из-за того, что JSF пользуется дурной славой.
Решение
Вы могли бы создать свою собственную библиотеку тегов faces, чтобы сделать ее менее подробной, что-то вроде:
<ph:i18n key="label.widget.count" p0="#{widgetCount}"/>
Затем создайте taglib в каталоге вашего представления:/components/ph.taglib.xml
<?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
<?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>
Вероятно, вы сможете найти элегантный способ передачи аргументов, проведя небольшое исследование.
Теперь зарегистрируйте свой новый taglib в web.xml
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>
/components/ph.taglib.xml
</param-value>
</context-param>
Просто добавьте xmlns:ph="http://peterhilton.com/core"
прислушайтесь к вашим взглядам, и все готово!
Другие советы
Поскольку вы используете Seam, вы можете использовать EL в файле сообщений.
Собственность:
label.widget.count = You have a total of #{widgetCount} widgets.
XHTML:
<h:outputFormat value="#{messages['label.widget.count']}" />
При этом по-прежнему используется OutputFormat, но он менее подробный.
Я никогда не сталкивался с другим способом сделать это, кроме OutputFormat.К сожалению, она довольно многословна.
Единственное, что я могу предложить, - это создать сообщение в вспомогательном компоненте, а затем вывести его, а не MessageFormat.
В моем случае у меня есть Spring's MessageSource, интегрированный с JSF (используя MessageSourcePropertyResolver - решатель MessageSourcePropertyResolver).Затем в ваших резервных компонентах довольно легко получать параметризованные сообщения - вам просто нужно знать, в какой локали находится ваш пользователь (опять же, у меня есть Locale, привязанный к свойству резервного компонента, поэтому он доступен через JSF или Java).
Я думаю, что параметры, особенно в сообщениях, - это единственное, что JSF действительно мог бы сделать лучше!
Я больше думал об этом, и мне пришло в голову, что я, вероятно, мог бы написать свою собственную функцию JSTL, которая принимает ключ сообщения и переменное количество параметров:
<h:outputText value="#{my:message('label.widget.count', widgetCount)}"/>
и если моя функция message HTML-кодирует результат перед выводом, мне даже не нужно было бы использовать h:outputText
#{my:message('label.widget.count', widgetCount)}
Вы можете использовать Интерполятор швов:
<h:outputText value="#{interpolator.interpolate(messages['label.widget.count'], widgetCount)}"/>
На нем есть @BypassInterceptors, так что производительность должна быть в порядке.
Вы можете использовать компонент напрямую, если будете интерполировать сообщения.
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}.
${messages['label.widget.count']}
этого достаточно.
Этот вариант отлично работает с использованием Spring:
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;
}
}
И...
Вам необходимо изменить EL-распознаватель в faces-config.xml
От org.springframework.web.jsf.el.SpringBeanFacesELResolver
Для
С уважением
<el-resolver>foo.ELResolver</el-resolver>
Используйте ResourceBundle и файлы свойств.