我已经完成了使用2.3 Servlet规范将i18n引入J2EE Web应用程序的任务(相当艰巨)。该应用程序非常大,并且已经积极开发了8年以上。
因此,我想第一时间解决问题,因此可以限制我花时间遍历JSP,JavaScript文件,Servlet和其他地方,用消息束中的值替换硬编码的字符串。
这里没有使用任何框架。我该如何寻求支持i18n。请注意,我希望每个视图有一个JSP,该视图从一个或多个属性文件中加载文本,而对于每个受支持的语言环境,则不要一个不同的JSP。
我想我的主要问题是我是否可以在“后端”中的某个位置设置语言环境(即,从登录时的用户配置文件读取语言环境,并将其存储在会话中的值),然后期望JSP页面将能够从中正确加载指定的字符串。正确的属性文件(例如,当语言环境为法语时,则来自messages_fr.properties),而不是在每个JSP中添加逻辑以查找正确的语言环境。
有什么想法可以解决这个问题吗?
国际化应用程序时,有很多事情需要注意:
语言环境检测
您需要考虑的第一件事是检测最终用户的语言环境。根据您要支持的内容,这可能很简单,也可能有些复杂。
request.getLocale()
__如果您只想支持第一种方法,或者您不打算添加任何其他依赖项(例如Spring Framework),那么 JSTL 方法就足够了。
当我们在 Spring Framework上时, 它具有很多不错的功能,您可以使用它们来检测Locale(例如CookieLocaleResolver,AcceptHeaderLocaleResolver,SessionLocaleResolver和LocaleChangeInterceptor)以及外部化字符串和格式化消息(请参见spring:message选项卡)。 Spring Framework将使您能够轻松地实现上述所有方案,这就是为什么我更喜欢它。
字符串外部化
这应该很容易,对吗?好吧,大多数情况是- 只需使用适当的标签即可。您可能面对的唯一问题是外部化客户端(JavaScript)文本。有几种可能的方法,但让我提及以下两种:
级联
我不想这么说,但是从Localizability的角度来看,连接确实很痛苦。它们很常见,大多数人都没有意识到。
那么什么是串联呢?
原则上,每个英语句子都需要翻译成目标语言。问题是,正确翻译的消息多次使用与其英语对应词不同的词序(因此,英语“安全策略”被翻译成波兰语“ Politykabezpieczeństwa” –“ policy”是“ polityka” –次序不同)。
好的,但是它和软件有什么关系?
在Web应用程序中,您可以像这样连接字符串:
String securityPolicy = "Security " + "policy";
或像这样:
<p><span style="font-weight:bold">Security</span> policy</p>
两者都会有问题。在第一种情况下,你将需要使用MessageFormat.format()方法和外部化字符串作为(例如)"Security {0}",并"policy"在后者,你会外部化全段(p标签)的内容, 包括 span标签。我知道这对翻译人员来说是痛苦的,但实际上没有更好的方法。 有时,您必须在段落中使用动态内容-JSTL fmt:format标记也将在此处为您提供帮助(它在后端使用了MessageFormat)。
MessageFormat.format()
"Security {0}"
"policy"
版面
在本地化应用程序中,经常会发生翻译字符串比英语更长的情况。结果看起来很难看。以某种方式,您需要修复样式。再次有两种方法:
!important
文化特定问题
避免使用可能特定于西方文化的图形,颜色和声音。如果您确实需要它,请提供本地化方法。避免使用对方向敏感的图形(因为当您尝试本地化为阿拉伯语或希伯来语时会出现问题)。另外,不要假设整个世界都使用相同的数字(即阿拉伯语不是这样)。
日期和时区
至少可以说,用Java时间处理日期并非易事。如果除了格里高利日历之外不支持其他功能,则可以坚持使用内置的日期和日历类。您可以使用JSTL fmt:timeZone,fmt:formatDate和fmt:parseDate在JSP中正确设置时区,格式和解析日期。
我强烈建议像这样使用fmt:formatDate:
<fmt:formatDate value="${someController.somedate}" timeZone="${someController.detectedTimeZone}" dateStyle="default" timeStyle="default" />
将日期和时间隐藏到有效(最终用户)时区很重要。将其转换为易于理解的格式也很重要-这就是为什么我建议使用默认格式样式的原因。 顺便说一句。时区检测并非易事,因为Web浏览器不太适合发送任何内容。相反,您可以将“首选时区”字段添加到“用户”偏好设置中(如果有的话),或者通过客户端脚本从Web浏览器获取当前时区偏移量(请参见Date对象的方法)。
数字和货币
数字和货币应转换为本地格式。可以通过与格式化日期类似的方式来完成此操作(解析也类似地进行):
<fmt:formatNumber value="1.21" type="currency"/>
复合消息
您已经被警告不要连接字符串。相反,您可能会使用MessgageFormat。但是,我必须指出,您应尽量减少使用复合消息。那只是因为目标语法规则通常有很大不同,所以翻译人员可能不仅需要重新排列句子(可以使用占位符和来解决MessageFormat.format()),还可以根据要替换的内容以不同的方式翻译整个句子。让我给你举一些例子:
MessgageFormat
// Multiple plural forms English: 4 viruses found. Polish: Znaleziono 4 wirusy. **OR** Znaleziono 5 wirusów. // Conjugation English: Program encountered incorrect character | Application encountered incorrect character. Polish: Program napotkał nieznaną literę | Aplikacja napotkała nieznaną literę.
字符编码
如果您打算本地化为不支持ISO 8859-1代码页的语言,则需要支持Unicode-最好的方法是将页面编码设置为UTF-8。我见过有人这样做:
<%@ page contentType="text/html; charset=UTF-8" %>
我必须警告您:这 还不够 。您实际上需要此声明:
<%@page pageEncoding="UTF-8" %>
同样,为了安全起见,您仍然需要在页面标题中声明编码:
<META http-equiv="Content-Type" content="text/html;charset=UTF-8">
我给您的清单并不详尽,但这是一个很好的起点。祝好运 :)