i18n在JSF 2.0应用程序中使用UTF-8编码的属性文件

我正在使用jsf-ri 2.0.3,需要希伯来文和俄文的支持。 问题是我在屏幕上看到的是乱码而不是正确的文本。

首先,我为每种语言定义了捆绑包(* _locale.properties)。 这些文件采用UTF-8编码。 其次,我已经在faces-config.xml中定义了默认和支持的语言环境

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

比我添加了一个自定义filter,将设置响应字符编码为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> 

最后,当我创build一个简单的XHTML来debugging输出,我看到了一个非常奇怪的结果

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

结果是:

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

我的configuration有什么问题?

对了,你可以创build一个自定义的ResourceBundle或者使用native2ascii转换器(如果需要的话用Maven 2插件来使转换更加透明)。 由于其他答案只与最后一种方法有关,下面是另一个答案,您可以创build一个自定义的ResourceBundle以在基于Java SE 1.6的环境中的JSF 2.x应用程序中将属性文件加载为UTF-8。

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

这需要com.example.i18n包中的UTF-8编码属性文件,如text.propertiestext_en.properties等。 不需要native2ascii。

顺便说一句,在faces-config.xml使用新的JSF 2.0样式的<resource-bundle>声明,您不再需要在视图中使用<f:loadBundle> 。 所有的文字都可以通过#{text}在所有视图中直接使用。

那么经过深入调查,我find了解决办法。

早于Java 1.6 PropertyResourceBundle只有一个具有以下文档The property file read with this constructor must be encoded in ISO-8859-1. 这意味着在资源包中只能使用英文文本。

这个问题有两个解决scheme:

第一个是写一个自定义的loadBundle组件,它将使用正确的ResourceBundle实例化方法。

第二个(我的select)使用Native-to-ASCII转换器,可以使用Native2Ascii maven插件与maven一起使用。

这是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> 

我有与单独的SWT应用程序相同的问题。 这是由WindowBuilder生成的修改资源加载器。 基本思想 – 消息类只包含string字段中的资源。 所以我把它们转换为UTF8(如果可能的话)后,原始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 } } } } 

}