如何使用 Velocity 模板正确显示西班牙文字符?
How do I get Spanish characters to display properly using a Velocity template?
我正在使用 Velocity 和消息资源包生成 html 页面。当我将墨西哥指定为我的语言环境时,我的 messages-es_MX.properties 将作为消息资源的来源进行处理。这正如我所期望的那样。但是字符 (áéíóúüñ¿¡) 显示不正确。
我的留言属性:
customer.greeting=áéíóúüñ¿¡
对于我的第一次尝试,我得到了以下信息:
- html header 在生成的页面中:
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- 速度属性包含:
- input.encoding=utf-8
- output.encoding=utf-8
- html文件编码:
UTF-8
- messages_es_MX.properties编码:
ISO-8859-1
输出到 html for ${customer.greeting}
:
�������
然后我意识到属性文件的编码不正确;它也应该是 UTF-8。
第二次尝试:
- html header 在生成的页面中:
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- 速度属性包含:
- input.encoding=utf-8
- output.encoding=utf-8
- html文件编码:
UTF-8
- messages_es_MX.properties编码:
UTF-8
输出到html:
áéÃóúüñ¿¡
关于如何让它工作有什么建议吗?
好吧,事实证明这比我想象的要棘手,但这是解决方案。开始之前,请确保所有 html 和属性文件均以 UTF-8 编码。并且所有 Velocity 配置也都引用 UTF-8。不应引用 ISO-8859-1。
潜在的问题是,默认情况下,ResourceBundle
假定 属性 文件采用 ISO-8859-1
编码。可以覆盖它,但需要一段自定义代码。
而不是调用
ResourceBundle bundle = ResourceBundle.getBundle("messages", MEXICO);
我需要为自定义控件实现添加一个参数:
ResourceBundle bundle = ResourceBundle.getBundle("messages", MEXICO, new UTF8Control());
UTF8Control class 看起来像这样:
package test;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Locale;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.ResourceBundle.Control;
public class UTF8Control extends Control {
public ResourceBundle newBundle(String baseName, Locale locale,
String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
// The below is a copy of the default implementation.
String bundleName = toBundleName(baseName, locale);
String resourceName = toResourceName(bundleName, "properties");
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 {
// Only this line is changed to make it to read properties files
// as UTF-8.
bundle = new PropertyResourceBundle(new InputStreamReader(
stream, "UTF-8"));
} finally {
stream.close();
}
}
return bundle;
}
}
感谢最初发帖的@BalusC this related answer。
所以,第 1 部分解决了。但是仍然有一个问题,因为我使用的是 VelocityTools,我可以在 ResourceTool
的源代码中看到它调用 ResourceBundle.getBundle(...)
而没有传递任何 Control 实现。这意味着它将使用 ISO-8859-1,而我无法传入我的 UTF8Control...
除非我覆盖 ResourceTool class 的方法来获取包:
package test;
import java.util.Locale;
import java.util.ResourceBundle;
import org.apache.velocity.tools.ConversionUtils;
import org.apache.velocity.tools.generic.ResourceTool;
public class UTF8ResourceTool extends ResourceTool {
/**
* Retrieves the {@link ResourceBundle} for the specified baseName and
* locale, if such exists, using UTF-8 encoding. If the baseName or locale is null or if the
* locale argument cannot be converted to a {@link Locale}, then this will
* return null.
*/
protected ResourceBundle getBundle(String baseName, Object loc) {
Locale locale = (loc == null) ? getLocale() : toLocale(loc);
if (baseName == null || locale == null) {
return null;
}
return ResourceBundle.getBundle(baseName, locale, new UTF8Control());
}
/* Copied here from parent class because it's private there */
private Locale toLocale(Object obj) {
if (obj == null) {
return null;
}
if (obj instanceof Locale) {
return (Locale) obj;
}
String s = String.valueOf(obj);
return ConversionUtils.toLocale(s);
}
}
在我的 UTF8ResourceTool class 中,我只覆盖了一个方法 getBundle
(而且我不得不从父 class 中逐字复制一个私有方法)。覆盖方法在获取资源包时将UTFControl作为第三个参数传递,这样我们就可以使用UTF-8编码拉取资源。
现在唯一剩下的就是更新我的 Velocity 配置,以便我引用我的自定义 UTF8ResourceTool
而不是 Velocity Tools 的 ResourceTool
:
EasyFactoryConfiguration config = new EasyFactoryConfiguration();
config.toolbox(Scope.APPLICATION).tool("msg", UTF8ResourceTool.class)
.property("bundles", "messages/messages").property("locale", locale)
.tool("date", DateTool.class).tool("number", NumberTool.class)
.tool("string", StringTool.class).tool("esc", EscapeTool.class)
.tool("base64", Base64Tool.class);
把它们放在一起,我的 html ${customer.greeting}
输出是:
áéíóúüñ¿¡
我正在使用 Velocity 和消息资源包生成 html 页面。当我将墨西哥指定为我的语言环境时,我的 messages-es_MX.properties 将作为消息资源的来源进行处理。这正如我所期望的那样。但是字符 (áéíóúüñ¿¡) 显示不正确。
我的留言属性:
customer.greeting=áéíóúüñ¿¡
对于我的第一次尝试,我得到了以下信息:
- html header 在生成的页面中:
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- 速度属性包含:
- input.encoding=utf-8
- output.encoding=utf-8
- html文件编码:
UTF-8
- messages_es_MX.properties编码:
ISO-8859-1
输出到 html for ${customer.greeting}
:
�������
然后我意识到属性文件的编码不正确;它也应该是 UTF-8。
第二次尝试:
- html header 在生成的页面中:
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- 速度属性包含:
- input.encoding=utf-8
- output.encoding=utf-8
- 速度属性包含:
- html文件编码:
UTF-8
- messages_es_MX.properties编码:
UTF-8
输出到html:
áéÃóúüñ¿¡
关于如何让它工作有什么建议吗?
好吧,事实证明这比我想象的要棘手,但这是解决方案。开始之前,请确保所有 html 和属性文件均以 UTF-8 编码。并且所有 Velocity 配置也都引用 UTF-8。不应引用 ISO-8859-1。
潜在的问题是,默认情况下,ResourceBundle
假定 属性 文件采用 ISO-8859-1
编码。可以覆盖它,但需要一段自定义代码。
而不是调用
ResourceBundle bundle = ResourceBundle.getBundle("messages", MEXICO);
我需要为自定义控件实现添加一个参数:
ResourceBundle bundle = ResourceBundle.getBundle("messages", MEXICO, new UTF8Control());
UTF8Control class 看起来像这样:
package test;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Locale;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.ResourceBundle.Control;
public class UTF8Control extends Control {
public ResourceBundle newBundle(String baseName, Locale locale,
String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
// The below is a copy of the default implementation.
String bundleName = toBundleName(baseName, locale);
String resourceName = toResourceName(bundleName, "properties");
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 {
// Only this line is changed to make it to read properties files
// as UTF-8.
bundle = new PropertyResourceBundle(new InputStreamReader(
stream, "UTF-8"));
} finally {
stream.close();
}
}
return bundle;
}
}
感谢最初发帖的@BalusC this related answer。
所以,第 1 部分解决了。但是仍然有一个问题,因为我使用的是 VelocityTools,我可以在 ResourceTool
的源代码中看到它调用 ResourceBundle.getBundle(...)
而没有传递任何 Control 实现。这意味着它将使用 ISO-8859-1,而我无法传入我的 UTF8Control...
除非我覆盖 ResourceTool class 的方法来获取包:
package test;
import java.util.Locale;
import java.util.ResourceBundle;
import org.apache.velocity.tools.ConversionUtils;
import org.apache.velocity.tools.generic.ResourceTool;
public class UTF8ResourceTool extends ResourceTool {
/**
* Retrieves the {@link ResourceBundle} for the specified baseName and
* locale, if such exists, using UTF-8 encoding. If the baseName or locale is null or if the
* locale argument cannot be converted to a {@link Locale}, then this will
* return null.
*/
protected ResourceBundle getBundle(String baseName, Object loc) {
Locale locale = (loc == null) ? getLocale() : toLocale(loc);
if (baseName == null || locale == null) {
return null;
}
return ResourceBundle.getBundle(baseName, locale, new UTF8Control());
}
/* Copied here from parent class because it's private there */
private Locale toLocale(Object obj) {
if (obj == null) {
return null;
}
if (obj instanceof Locale) {
return (Locale) obj;
}
String s = String.valueOf(obj);
return ConversionUtils.toLocale(s);
}
}
在我的 UTF8ResourceTool class 中,我只覆盖了一个方法 getBundle
(而且我不得不从父 class 中逐字复制一个私有方法)。覆盖方法在获取资源包时将UTFControl作为第三个参数传递,这样我们就可以使用UTF-8编码拉取资源。
现在唯一剩下的就是更新我的 Velocity 配置,以便我引用我的自定义 UTF8ResourceTool
而不是 Velocity Tools 的 ResourceTool
:
EasyFactoryConfiguration config = new EasyFactoryConfiguration();
config.toolbox(Scope.APPLICATION).tool("msg", UTF8ResourceTool.class)
.property("bundles", "messages/messages").property("locale", locale)
.tool("date", DateTool.class).tool("number", NumberTool.class)
.tool("string", StringTool.class).tool("esc", EscapeTool.class)
.tool("base64", Base64Tool.class);
把它们放在一起,我的 html ${customer.greeting}
输出是:
áéíóúüñ¿¡