问题描述
|
我制作了一个i18n支持的Spring(2.5.6)Web应用程序,该应用程序带有属性文件(例如:messages_en_US.properties,messages_de_DE.properties)。
该.properties文件带有Unicode。例如:
busy = Besch\\u00E4ftigt
从messageSource
读取busy
关键字时,得出以下结果:
...
private static ReloadableResourceBundleMessageSource messageSource;
/**
* Gets a message from the resources (.properties) defined in the applicationContext.xml
*
* @param input string to hook up
* @return the the message hooked up from the resources
*/
public static String getMessage(String input){
System.out.println(input); //busy
System.out.println(messageSource.getDefaultEncoding()); //UTF-8
System.out.println(messageSource.getMessage(input,null,null)); //Beschu00E4ftigt
return messageSource.getMessage(input,null);
}
...
所以没有the4
服务器上的文件也是UTF-8:
发生问题的环境:
Tomcat 5.5.28(从common/lib
运行jsp-api.jar
和servlet-api.jar
)
JDK 1.5.0_22
JSTL 1.1.2(从应用程序lib
读取)
Tomcat 6.0.32(从lib
运行jsp-api.jar
和servlet-api.jar
)
JDK 1.5.0_22
JSTL 1.1.2(从应用程序lib
读取)
解决问题的环境(分布完全相同):
-Tomcat 6.0.32(从lib
运行jsp-api.jar
和servlet-api.jar
)
-JDK 1.6.0_13
-JSTL 1.1.2(从应用程序lib
中读取)
如果您需要更多信息,请告诉我。而且不要说我不需要更新JDK,因为这是不可能的。
更新applicationContext.xml中的绑定messageSource
<b:bean id=\"messageSource\" class=\"org.springframework.context.support.ReloadableResourceBundleMessageSource\">
<b:property name=\"defaultEncoding\" value=\"UTF-8\"/>
<b:property name=\"fallbackToSystemLocale\" value=\"false\" />
<b:property name=\"basenames\">
<b:list>
<b:value>classpath:messages</b:value>
<b:value>/public/custom/i18n/portalmessages</b:value>
</b:list>
</b:property>
<b:property name=\"cacheSeconds\" value=\"1\"/>
</b:bean>
更新2:将资源属性文件放置在classpath上并使用classloader:
urlclassloader cl = (urlclassloader) IoUtils.class.getClassLoader();
InputStream resourceAsstream = cl.getResourceAsstream(\"messages_de_DE.properties\");
Properties prop = new Properties();
prop.load(resourceAsstream);
System.out.println(\"From classpath --> \" + prop.get(\"busy\")); //Beschäftigt
System.out.println(\"From i18n folder --> \" + I18nFunctions.getMessage(\"busy\")); //Beschu00E4ftigt
解决方法
我看了一下
DefaultPropertiesPersister
的源代码(ReloadableResourceBundleMessageSource
在内部使用了它)。
如果指定了defaultEncoding
,则从Reader
逐行手动加载属性,而不是使用常规的Properties.load()
方法。
在将键/值对添加到Properties
对象之前,在String
上调用unescape()
方法
protected String unescape(String str) {
StringBuffer outBuffer = new StringBuffer(str.length());
for (int index = 0; index < str.length();) {
char c = str.charAt(index++);
if (c == \'\\\\\') {
c = str.charAt(index++);
if (c == \'t\') {
c = \'\\t\';
}
else if (c == \'r\') {
c = \'\\r\';
}
else if (c == \'n\') {
c = \'\\n\';
}
else if (c == \'f\') {
c = \'\\f\';
}
}
outBuffer.append(c);
}
return outBuffer.toString();
}
这是ѭ4字符被删除的地方。
如果您按如下方式创建DefaultPropertiesPersister
的子类
package com.something;
import org.apache.commons.lang.StringEscapeUtils;
import org.springframework.util.DefaultPropertiesPersister;
public class MyPropertiesPersister extends DefaultPropertiesPersister {
protected String unescape(String str)
{
return StringEscapeUtils.unescapeJava(str);
}
}
像这样在您的spring配置中设置它:
<b:bean id=\"messageSource\" class=\"org.springframework.context.support.ReloadableResourceBundleMessageSource\">
<b:property name=\"defaultEncoding\" value=\"UTF-8\"/>
<b:property name=\"fallbackToSystemLocale\" value=\"false\" />
<b:property name=\"basenames\">
<b:list>
<b:value>classpath:messages</b:value>
<b:value>/public/custom/i18n/portalmessages</b:value>
</b:list>
</b:property>
<b:property name=\"cacheSeconds\" value=\"1\"/>
<b:property name=\"propertiesPersister\">
<b:bean class=\"com.something.MyPropertiesPersister\"/>
</b:property>
</b:bean>
它将工作..可能需要进一步的拼图才能获得与其他编码等有关的确切信息:)
,request.setCharacterEncoding(\"UTF-8\");
在任何“ 33”调用之前被调用时,它仅指示Servlet API使用哪种编码来解析POST(不是GET!)请求正文的参数。
您仍然必须更改响应编码以使用UTF-8,以便Servlet API知道应该使用哪种编码将字符作为字节发送到HTTP连接的另一端。您还必须通过HTTP响应标头指示Web浏览器所传输的字节的编码格式,以便Web浏览器可以正确地将其解码为字符。
在JSP中,这两个任务都可以通过文件顶部的这一简单行来完成。您需要将其应用于所有JSP,以及包含文件/片段。
<%@ page pageEncoding=\"UTF-8\" %>
否则,服务器平台默认编码将用于发送,客户端平台默认编码用于读取(尽管某些智能Web浏览器(如Firefox)可以在HTTP响应标头中未指定字符集时自动检测其字符集)。
也可以看看:
Unicode-如何正确获取字符?
更新:您确定unicode转义本身不会在Linux机器的属性文件中重新转义吗?也就是说,您看到的是\\u00E
,而且在所有地方都很喜欢,因此看不到\\\\u00E
?那可以解释这个问题。
,您需要确保以运行服务器的用户身份检查语言环境,或者更确切地说,需要检查服务器启动环境的语言环境。出于调试目的,您可以将启动脚本编辑为将“语言环境”的输出写入某个文件。
,从javadoc引用java.util.Properties,
load(InputStream)/ store(OutputStream,String)方法的工作方式与load(Reader)/ store(Writer,String)对相同,不同之处在于输入/输出流以ISO 8859-1字符编码进行编码。不能使用此编码直接表示的字符可以使用Unicode转义符编写;转义序列中只允许使用一个'u \'字符。 native2ascii工具可用于在其他字符编码之间来回转换属性文件。
也许您有一些构建阶段正在将您的UTF-8编码文件转换为ascii。尝试将属性文件的编码更改为8859-1。听起来您的属性文件已经适当地转义了Unicode字符。
也可以使用getClassLoader().getResourceAsStream(...)
自己获取流到属性文件的流,并加载到属性文件中。查看值是否为所需的字符串。这将使问题变成编码+打包问题,而不是弹簧问题。
根据评论主题更新:
Java 1.5 java.util.Properties没有load(Reader)
API。显然,这是Java 1.6时间框架中需要改进的地方。