Etichette internazionalizzate in JSF/Facelets
-
01-07-2019 - |
Domanda
Fa Facelette hai qualche funzionalità per etichette di testo dell'interfaccia utente internazionalizzate più ordinate o più leggibili che cosa potresti fare altrimenti utilizzando JSF?
Ad esempio, con il semplice JSF, l'utilizzo di h:outputFormat è un modo molto dettagliato per interpolare le variabili nei messaggi.
Una precisazione: So che posso aggiungere una voce nel file di messaggio simile a:
label.widget.count = You have a total of {0} widgets.
e visualizzarlo (se sto usando Seam) con:
<h:outputFormat value="#{messages['label.widget.count']}">
<f:param value="#{widgetCount}"/>
</h:outputFormat>
ma è un sacco di confusione produrre una frase - proprio il genere di cose che dà a JSF una cattiva reputazione.
Soluzione
Potresti creare la tua libreria di tag volti per renderla meno dettagliata, qualcosa del tipo:
<ph:i18n key="label.widget.count" p0="#{widgetCount}"/>
Quindi crea la taglib nella tua directory di visualizzazione:/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>
creare /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>
Probabilmente puoi trovare un modo elegante per esporre le argomentazioni con un po' di ricerca.
Ora registra il tuo nuovo taglib in web.xml
<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>
/components/ph.taglib.xml
</param-value>
</context-param>
Basta aggiungere xmlns:ph="http://peterhilton.com/core"
alle tue visualizzazioni e il gioco è fatto!
Altri suggerimenti
Dato che stai usando Seam, puoi usare EL nel file dei messaggi.
Proprietà:
label.widget.count = You have a total of #{widgetCount} widgets.
XHTML:
<h:outputFormat value="#{messages['label.widget.count']}" />
Utilizza ancora outputFormat, ma è meno dettagliato.
Non ho mai trovato un altro modo per farlo oltre a outputFormat.Sfortunatamente è piuttosto prolisso.
L'unica altra cosa che posso suggerire è creare il messaggio in un bean di supporto e quindi emetterlo anziché messageFormat.
Nel mio caso ho MessageSource di Spring integrato con JSF (utilizzando MessageSourcePropertyResolver).Quindi, è abbastanza semplice nei tuoi bean di supporto ottenere messaggi parametrizzati: devi solo sapere in quale locale si trova il tuo utente (di nuovo, ho legato il locale a una proprietà del bean di supporto in modo che sia accessibile tramite JSF o Java).
Penso che i parametri, in particolare nei messaggi, siano una cosa che JSF potrebbe davvero fare meglio!
Ci ho pensato di più e mi viene in mente che probabilmente potrei scrivere la mia funzione JSTL che accetta una chiave di messaggio e un numero variabile di parametri:
<h:outputText value="#{my:message('label.widget.count', widgetCount)}"/>
e se la mia funzione di messaggio codifica in HTML il risultato prima dell'output, non avrei nemmeno bisogno di usare h:outputText
#{my:message('label.widget.count', widgetCount)}
Puoi usare Seam Interpolator:
<h:outputText value="#{interpolator.interpolate(messages['label.widget.count'], widgetCount)}"/>
Ha @BypassInterceptors quindi le prestazioni dovrebbero essere ok.
Puoi usare direttamente il Bean se interpoli i messaggi.
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']}
è sufficiente.
Questo funziona benissimo usando 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;
}
}
E...
È necessario sostituire l'EL-Resolver faces-config.xml
da org.springframework.web.jsf.el.SpringBeanFacesELResolver
A
Saluti
<el-resolver>foo.ELResolver</el-resolver>
Utilizzare ResourceBundle e file delle proprietà.