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.properties
, text_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 } } } }
}