java JSF 2.0 应用程序中带有 UTF-8 编码属性文件的 i18n
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3645491/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
i18n with UTF-8 encoded properties files in JSF 2.0 application
提问by Maxim Manco
I am using jsf-ri 2.0.3 where Hebrew and Russian support is needed. The problem is that I see gibberish on the screen instead of the correct text.
我在需要希伯来语和俄语支持的地方使用 jsf-ri 2.0.3。问题是我在屏幕上看到的是乱码而不是正确的文本。
First of all I have defined bundles (*_locale.properties) for each language. The files is in UTF-8 encoding. Secondly, I've defined the default and supported locales in faces-config.xml
首先,我为每种语言定义了包 (*_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>
Than I've added a custom filter that will set the response charcter encoding to UTF-8.
比我添加了一个自定义过滤器,它将响应字符编码设置为 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>
And finally when I create a simple xhtml to debug the output I see a very strange results
最后,当我创建一个简单的 xhtml 来调试输出时,我看到了一个非常奇怪的结果
<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}"/>
The result is:
结果是:
i18n: ×¢×ר××a
Locale: en_US
Encoding: UTF-8
What is wrong with my configuration?
我的配置有什么问题?
回答by BalusC
Right, you can create a custom ResourceBundle
or use the native2ascii converter (if necessary with the Maven 2 plugin to make the conversion more transparent). Since the other answer only goes with the last approach in detail, here's another answer how you could create a custom ResourceBundle
to load properties files as UTF-8 in a JSF 2.x application on Java SE 1.6 based environment.
是的,您可以创建自定义ResourceBundle
或使用 native2ascii 转换器(如有必要,使用 Maven 2 插件使转换更加透明)。由于另一个答案仅详细说明了最后一种方法,因此这里有另一个答案,您可以ResourceBundle
在基于 Java SE 1.6 的环境中创建自定义以在 JSF 2.x 应用程序中以 UTF-8 格式加载属性文件。
faces-config.xml
faces-config.xml
<application>
<resource-bundle>
<base-name>com.example.i18n.Text</base-name>
<var>text</var>
</resource-bundle>
</application>
com.example.i18n.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<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;
}
}
}
This expects UTF-8 encoded properties files like text.properties
, text_en.properties
, etc in com.example.i18n
package. No need for native2ascii.
此预计UTF-8编码的属性文件喜欢text.properties
,text_en.properties
等在com.example.i18n
包。不需要 native2ascii。
By the way, with the new JSF 2.0 style <resource-bundle>
declaration in faces-config.xml
, you don't need <f:loadBundle>
in the views anymore. All text will be directly available by #{text}
in all views.
顺便说一下,有了新的 JSF 2.0 样式<resource-bundle>
声明faces-config.xml
,您就不再需要<f:loadBundle>
在视图中了。所有文本都可以#{text}
在所有视图中直接使用。
回答by Maxim Manco
Well, after a deep investigation I have found the solution.
好吧,经过深入调查,我找到了解决方案。
Earlier to java 1.6 PropertyResourceBundle
had only one constructor which has the following documentation The property file read with this constructor must be encoded in ISO-8859-1.
This means that it is possible to use only English text in the resource bundles.
在 Java 1.6PropertyResourceBundle
之前,只有一个构造函数具有以下文档。The property file read with this constructor must be encoded in ISO-8859-1.
这意味着可以在资源包中仅使用英文文本。
There are two solutions for this issue:
这个问题有两种解决方案:
The first one is writing a custom loadBundle component wich will use the correct ResourceBundle
instantiation method.
第一个是编写一个自定义的 loadBundle 组件,它将使用正确的ResourceBundle
实例化方法。
The second one (My choice) is using the Native-to-ASCIIconverter which can be used with maven using the Native2Ascii maven plugin.
第二个(我的选择)是使用Native-to-ASCII转换器,它可以使用Native2Ascii maven plugin与 maven 一起使用。
Here is the configuration example:
下面是配置示例:
<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>
回答by Ezhik
I have the same issue with standalone SWT application. This is modified resource loader generated by WindowBuilder. Basic idea - Messages class contain only resources in string fields. So I convert them to UTF8 (if possible) after raw ISO-8859-1 loading.
我对独立的 SWT 应用程序有同样的问题。这是由 WindowBuilder 生成的修改后的资源加载器。基本思想 - Messages 类只包含字符串字段中的资源。所以我在原始 ISO-8859-1 加载后将它们转换为 UTF8(如果可能)。
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
}
}
}
}
}
}