i18n con i file di proprietà codificati UTF-8 nell’applicazione JSF 2.0

Sto usando jsf-ri 2.0.3 dove è necessario il supporto per l’ebraico e il russo. Il problema è che vedo dei messaggi senza senso sullo schermo invece del testo corretto.

Prima di tutto ho definito i bundle (* _locale.properties) per ogni lingua. I file sono nella codifica UTF-8. In secondo luogo, ho definito le impostazioni internazionali predefinite e supportate in faces-config.xml

 iw en ru  

Poi ho aggiunto un filtro personalizzato che imposterà la codifica del codice di risposta su UTF-8.

  encodingFilter org.springframework.web.filter.CharacterEncodingFilter  encoding UTF-8   forceEncoding true    encodingFilter /*  

E infine quando creo un semplice xhtml per eseguire il debug dell’output, vedo risultati molto strani

  i18n:  
Locale:
Encoding:

Il risultato è:

 i18n: ×¢×ר×ת Locale: en_US Encoding: UTF-8 

Cosa c’è di sbagliato nella mia configurazione?

È ansible creare un ResourceBundle personalizzato o utilizzare il convertitore native2ascii (se necessario con il plug-in Maven 2 per rendere la conversione più trasparente). Dal momento che l’altra risposta riguarda solo l’ultimo approccio in dettaglio, ecco un’altra risposta su come è ansible creare un ResourceBundle personalizzato per caricare i file delle proprietà come UTF-8 in un’applicazione JSF 2.x su ambiente basato su Java SE 1.6.

faces-config.xml

   com.example.i18n.Text text   

com.example.i18n.Text

 package com.example.i18n; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; import java.util.Enumeration; import java.util.Locale; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import javax.faces.context.FacesContext; public class Text extends ResourceBundle { protected static final String BUNDLE_NAME = "com.example.i18n.text"; protected static final String BUNDLE_EXTENSION = "properties"; protected static final String CHARSET = "UTF-8"; protected static final Control UTF8_CONTROL = new UTF8Control(); public Text() { setParent(ResourceBundle.getBundle(BUNDLE_NAME, FacesContext.getCurrentInstance().getViewRoot().getLocale(), UTF8_CONTROL)); } @Override protected Object handleGetObject(String key) { return parent.getObject(key); } @Override public Enumeration getKeys() { return parent.getKeys(); } protected static class UTF8Control extends Control { public ResourceBundle newBundle (String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException { // The below code is copied from default Control#newBundle() implementation. // Only the PropertyResourceBundle line is changed to read the file as UTF-8. String bundleName = toBundleName(baseName, locale); String resourceName = toResourceName(bundleName, BUNDLE_EXTENSION); ResourceBundle bundle = null; InputStream stream = null; if (reload) { URL url = loader.getResource(resourceName); if (url != null) { URLConnection connection = url.openConnection(); if (connection != null) { connection.setUseCaches(false); stream = connection.getInputStream(); } } } else { stream = loader.getResourceAsStream(resourceName); } if (stream != null) { try { bundle = new PropertyResourceBundle(new InputStreamReader(stream, CHARSET)); } finally { stream.close(); } } return bundle; } } } 

Ciò si aspetta che i file delle proprietà con codifica UTF-8 come text.properties , text_en.properties , ecc. com.example.i18n pacchetto com.example.i18n . Non c’è bisogno di native2ascii.

A proposito, con la nuova dichiarazione stile JSF 2.0 in faces-config.xml , non è più necessario nelle viste. Tutto il testo sarà direttamente disponibile con #{text} in tutte le viste.

Bene, dopo un’indagine approfondita ho trovato la soluzione.

Precedentemente a java 1.6 PropertyResourceBundle aveva un solo costruttore che ha la seguente documentazione. The property file read with this constructor must be encoded in ISO-8859-1. Ciò significa che è ansible utilizzare solo il testo inglese nei pacchetti di risorse.

Esistono due soluzioni per questo problema:

Il primo sta scrivendo un componente loadBundle personalizzato che utilizzerà il metodo di istanza ResourceBundle corretto.

Il secondo (La mia scelta) sta usando il convertitore Native-to-ASCII che può essere usato con Maven usando il plugin Maven di Native2Ascii .

Ecco l’esempio di configurazione:

  org.codehaus.mojo native2ascii-maven-plugin    native2ascii   ${basedir}/src/main/resources ${project.build.directory}/native2ascii UTF8 **/*.properties     

Ho lo stesso problema con l’applicazione SWT standalone. Questo è il caricatore di risorse modificato generato da WindowBuilder. Idea di base: la class Messages contiene solo le risorse nei campi stringa. Quindi li converto in UTF8 (se ansible) dopo il caricamento raw ISO-8859-1.

 import java.lang.reflect.Field; import org.eclipse.osgi.util.NLS; public class Messages extends NLS { private static final String BUNDLE_NAME = "org.digimead.tabuddy.desktop.res.messages"; //$NON-NLS-1$ public static String MainWindow_newShell_text; public static String MainWindow_actionOpenFile_text; public static String MainWindow_actionCloseFile_text; // ////////////////////////////////////////////////////////////////////////// // // Constructor // // ////////////////////////////////////////////////////////////////////////// private Messages() { // do not instantiate } // ////////////////////////////////////////////////////////////////////////// // // Class initialization // // ////////////////////////////////////////////////////////////////////////// static { // load message values from bundle file NLS.initializeMessages(BUNDLE_NAME, Messages.class); final Field[] fieldArray = Messages.class.getDeclaredFields(); final int len = fieldArray.length; for (int i = 0; i < len; i++) { final Field field = (Field) fieldArray[i]; if (field.getType() == java.lang.String.class) { if (!field.isAccessible()) field.setAccessible(true); try { final String rawValue = (String) field.get(null); field.set(null, new String(rawValue.getBytes("ISO-8859-1"), "UTF-8")); } catch (Exception e) { // skip field modification } } } } 

}