2010-09-05 8 views
9

J'utilise jsf-ri 2.0.3 où un support hébreu et russe est nécessaire. Le problème est que je vois du charabia sur l'écran au lieu du texte correct. J'ai d'abord défini des bundles (* _locale.properties) pour chaque langue. Les fichiers sont en codage UTF-8. Deuxièmement, j'ai défini la valeur par défaut et locales dans soutenais faces-config.xmli18n avec les fichiers de propriétés codés UTF-8 dans l'application JSF 2.0

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

Que j'ai ajouté un filtre personnalisé qui définira le codage charcter de réponse en 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> 

Et enfin quand je crée simple xhtml pour déboguer la sortie que je vois un résultat très étrange

<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}"/> 

Le résultat est:

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

Quel est le problème avec ma configuration?

Répondre

22

droit, vous pouvez créer une ResourceBundle ou utiliser le convertisseur native2ascii (si nécessaire avec le plugin Maven 2 pour rendre plus transparente la conversion). Puisque l'autre réponse ne va qu'avec la dernière approche en détail, voici une autre réponse pour créer un fichier ResourceBundle personnalisé pour charger les fichiers de propriétés en UTF-8 dans une application JSF 2.x sur un environnement 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; 
     } 
    } 
} 

Cela suppose que UTF-8 propriétés codées fichiers comme text.properties, text_en.properties, etc dans le paquet com.example.i18n. Pas besoin de native2ascii. Par ailleurs, avec la nouvelle déclaration <resource-bundle> de style JSF 2.0 dans faces-config.xml, vous n'avez plus besoin de <f:loadBundle> dans les vues. Tout le texte sera directement disponible par #{text} dans toutes les vues.

+0

Ceci est un excellent outil. Sera-t-il ajouté à OmniFaces un jour? – Med

+1

@Med: Je l'ai considéré, mais j'ai décidé que c'est sur le bord avec "Hacky". Utilisez plutôt les bons éditeurs et construisez des outils tels que Eclipse et/ou Maven/Ant. Par exemple, lors de l'utilisation de l'éditeur de fichier de propriétés intégré Eclipse, UTF-8 sera sauvé en tant que ISO-8859-1 avec des points de code Unicode si nécessaire. – BalusC

+0

Ok, j'ai compris! Merci. – Med

3

Eh bien, après une enquête approfondie, j'ai trouvé la solution.

Un peu plus tôt à Java 1.6 PropertyResourceBundle avait un seul constructeur qui a la documentation suivante The property file read with this constructor must be encoded in ISO-8859-1. Cela signifie qu'il est possible d'utiliser uniquement le texte anglais dans les faisceaux de ressources.

Il existe deux solutions pour ce problème:

Le premier est en train d'écrire un composant loadBundle personnalisé Wich utilisera la méthode ResourceBundle instanciation correcte.

Le second (Mon choix) utilise le convertisseur Native-to-ASCII qui peut être utilisé avec maven en utilisant le Native2Ascii maven plugin.

Voici l'exemple de configuration:

<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

J'ai le même problème avec l'application SWT autonome. C'est un chargeur de ressources modifié généré par WindowBuilder. Idée de base - La classe Messages contient uniquement des ressources dans les champs de chaîne. Donc, je les convertis en UTF8 (si possible) après chargement brut 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 
      } 
     } 
    } 
} 

}