2010-09-05 2 views
9

Sto utilizzando 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.i18n con file di proprietà codificati UTF-8 nell'applicazione JSF 2.0

Prima di tutto ho definito pacchetti (* _locale.properties) per ogni lingua. I file sono nella codifica UTF-8. locali secondo luogo, ho definito il difetto e supportato in faces-config.xml

<locale-config> 
    <default-locale>iw</default-locale> 
    <supported-locale>en</supported-locale> 
    <supported-locale>ru</supported-locale> 
</locale-config> 

Che Ho aggiunto un filtro personalizzato che imposterà la codifica risposta charcter UTF-8.

<filter> 
    <filter-name>encodingFilter</filter-name> 
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 
    <init-param> 
     <param-name>encoding</param-name> 
     <param-value>UTF-8</param-value> 
    </init-param> 
    <init-param> 
     <param-name>forceEncoding</param-name> 
     <param-value>true</param-value> 
    </init-param> 
</filter> 
<filter-mapping> 
    <filter-name>encodingFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

E infine quando creo un semplice xhtml per eseguire il debug l'uscita Vedo molto strani risultati

<f:loadBundle basename="i18n.frontend.homepage" var="msg"/> 
<strong>i18n: </strong><h:outputText value="#{msg.language}"/> 
<br/> 
<strong>Locale: </strong> 
<h:outputText value="#{facesContext.externalContext.response.locale}"/> 
<br/> 
<strong>Encoding: </strong> 
<h:outputText value="#{facesContext.externalContext.response.characterEncoding}"/> 

Il risultato è:

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

Cosa c'è di sbagliato con la mia configurazione?

risposta

22

destro, è possibile creare un costume ResourceBundle o utilizzare il convertitore native2ascii (se necessario con il plugin Maven 2 per effettuare la conversione più trasparente). Dato che l'altra risposta è dettagliata solo con l'ultimo approccio, ecco un'altra risposta su come è possibile creare un custom ResourceBundle per caricare i file di proprietà come UTF-8 in un'applicazione JSF 2.x su ambiente basato su Java SE 1.6.

faces-config.xml

<application> 
    <resource-bundle> 
     <base-name>com.example.i18n.Text</base-name> 
     <var>text</var> 
    </resource-bundle> 
</application> 

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<String> 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; 
     } 
    } 
} 

Questo si aspetta UTF-8 file di proprietà codificati come text.properties, text_en.properties, ecc in com.example.i18n pacchetto. Non c'è bisogno di native2ascii.

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

+0

Questo è un grande strumento. Sarà aggiunto a OmniFaces un giorno? – Med

+1

@Med: ho preso in considerazione questo, ma ho deciso che questo è al limite con "Hacky". Piuttosto, usa gli editor corretti e crea strumenti come Eclipse e/o Maven/Ant. Ad esempio, quando si utilizza l'editor di file di proprietà built-in di Eclipse, UTF-8 verrà salvato in modo trasparente come ISO-8859-1 con codepoint unicode dove necessario. – BalusC

+0

Ok, ho capito il tuo punto! Grazie. – Med

3

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

precedenza per Java 1.6 PropertyResourceBundle aveva solo un costruttore che ha la seguente documentazione The property file read with this constructor must be encoded in ISO-8859-1. Ciò significa che è possibile utilizzare solo il testo inglese in gruppi di risorse.

ci sono due soluzioni per questo problema:

Il primo sta scrivendo un componente wich loadBundle personalizzato utilizzerà il metodo ResourceBundle instantiation corretta.

Il secondo (La mia scelta) utilizza il convertitore Native-to-ASCII che può essere utilizzato con Maven utilizzando Native2Ascii maven plugin.

Ecco l'esempio di configurazione:

<plugin> 
    <groupId>org.codehaus.mojo</groupId> 
    <artifactId>native2ascii-maven-plugin</artifactId> 
    <executions> 
     <execution> 
      <goals> 
       <goal>native2ascii</goal> 
      </goals> 
      <configuration> 
       <src>${basedir}/src/main/resources</src>     
       <dest>${project.build.directory}/native2ascii</dest> 
       <encoding>UTF8</encoding> 
       <includes>**/*.properties</includes> 
      </configuration> 
     </execution> 
    </executions> 
</plugin> 
0

Ho lo stesso problema con l'applicazione SWT standalone. Questo è il caricatore di risorse modificato generato da WindowBuilder. Idea di base: la classe Messages contiene solo le risorse nei campi stringa. Quindi li converto in UTF8 (se possibile) 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 
      } 
     } 
    } 
} 

}