为 i18n 国际化解析 spring:messages in javascript
Posted
技术标签:
【中文标题】为 i18n 国际化解析 spring:messages in javascript【英文标题】:Resolving spring:messages in javascript for i18n internationalization 【发布时间】:2011-09-07 07:39:15 【问题描述】:我正在尝试将我们的一些代码国际化。我在 JSPX 中有一个页面,它使用 <spring:message>
标签来解析来自 message.properties
文件的字符串。这适用于 JSPX 页面中的 html 和 CSS,但是有一个 javascript 文件的来源,并且用<spring:message>
标记替换其中的字符串只是意味着它被逐字打印出来。
我的 JSPX 像这样获取 javascript:
<spring:theme code="jsFile" var="js" />
<script type="text/javascript" src="$js" />
我正在寻找替换字符串的JS如下:
buildList('settings', [
name: '<spring:message code="proj.settings.toggle" javaScriptEscape="true" />',
id:"setting1",
description: '<spring:message code="proj.settings.toggle.description" javaScriptEscape="true" />',
installed: true
]);
最后 message.properties 类似于:
proj.settings.toggle=Click here to toggle
proj.settings.toggle.description=This toggles between on and off
所以我想知道的是,这应该有效吗?从我在各种论坛上收集的信息来看,在我看来应该是这样,但我无法弄清楚我哪里出错了。有没有更好的方法来解决这个问题?
我还应该注意,这些文件在 WEB-INF 文件夹之外,但是通过将 ReloadableResourceBundleMessageSource 放在根 applicationContext.xml 中,弹簧标签被拾取。
感谢您的帮助!
【问题讨论】:
【参考方案1】:在我看来,您想要做的是将 JS 文件视为 JSP 文件并通过 spring:message 标签解析其内容。 我不会那样做。
通常 JS i18n 以两种方式之一完成:
通过从 JSP 页面写出已翻译字符串数组 通过创建翻译过滤器并将预翻译的JS文件提供给请求客户端如果您为客户端可翻译字符串创建一个中心位置,这两种方法的效果最好。 在您的上下文中,我会推荐第一种方法(更容易)。除非您的项目非常大,并且您在客户端有 很多 可翻译的字符串。所以修改看起来像:
<script type="text/javascript">
var strings = new Array();
strings['settings.toogle'] = "<spring:message code='proj.settings.toggle' javaScriptEscape='true' />";
strings['settings.toogle.description'] = "<spring:message code='proj.settings.toggle.description' javaScriptEscape='true' />";
</script>
<spring:theme code="jsFile" var="js" />
<script type="text/javascript" src="$js" />
在你的 JS 文件中:
buildList('settings', [
name: strings['settings.toggle'],
id:"setting1",
description: strings['settings.toggle.description'],
installed: true
]);
请注意,我使用双引号来写出翻译后的字符串。这是因为法语或意大利语中的某些单词可能包含撇号。
编辑:附加输入
出于这个原因,我们提供了对 JS 文件的翻译。通常,原因是我们想要动态地创建 UI 的某些部分。在某些情况下,我们需要本地化一些 3rd 方组件,我上面的回答很好地解决了它们。 对于我们想要动态创建 UI 部件的情况,使用模板而不是在 JavaScript 中连接 HTML 标记真的很有意义。我决定写这个,因为它提供了更清洁(并且可能可重复使用)的解决方案。 因此,与其将翻译传递给 JavaScript,不如创建一个模板并将其放在页面上(我的示例将使用 Handlebars.js,但我相信可以使用任何其他引擎):
<script id="article" type="text/x-handlebars-template">
<div class="head">
<p>
<span>
<spring:message code="article.subject.header" text="Subject: " />
</span>subject</p>
</div>
<div class="body">
body
</div>
</script>
在客户端(即在 JavaScript 中),您所要做的就是访问模板(下面的示例显然使用 jQuery)并编译:
var template = Handlebars.compile($("#article").html());
var html = template(subject: "It is really clean",
body: "<p>Don't you agree?</p><p>It looks much better than usual spaghetti with JavaScript variables.</p>"
);
$("#someDOMReference").html(html);
这里有几点需要注意:
<spring:message />
标签默认同时转义 HTML 和 JS,我们不需要指定 javaScriptEscape
属性
为<spring:message />
标签提供text
属性是有意义的,因为它可以用作后备(如果没有给定语言的翻译)以及注释(此元素代表什么)。甚至可以创建一个工具来扫描文件中的<spring:message />
标签并自动生成属性文件
为了防止 Handlebars 转义 HTML 内容,我使用了三重 curly braces
基本上就是这样。如果可能的话,我建议使用模板。
【讨论】:
很好的答案,但 spring:message 标签应该正确终止以避免错误。我试图编辑,但由于它只添加了 2 个字符,所以告诉我离开,因为显然它不够有建设性,除非有 6 个或更多字符:) @GreenDay:谢谢,我自己没有注意到这个问题。现在应该没问题了。 @PawełDyda 请注意,我使用双引号来写出翻译后的字符串。这是因为法语或意大利语中的某些单词可能包含撇号。 这不就是 javaScriptEscape='true' 应该注意的吗?javaScriptEscape='true'
)。问题是,有时您实际上不想转义这个东西(即您想保留 HTML 标记),然后您需要指定 javaScriptEscape='false'
并使用双引号。这就是为什么我在重新审视这个问题后决定保留它。【参考方案2】:
感谢您的回答。这是一个更通用的解决方案。
这个想法是提供一个名为“string.js”的动态javascript文件,其中包含一个在java资源包中注册的关联消息数组,使用当前用户语言。
1) 在 Spring Controller 中创建一个方法来从资源包中加载所有资源键,并返回视图“spring.jsp”
@RequestMapping(value="strings.js")
public ModelAndView strings(HttpServletRequest request)
// Retrieve the locale of the User
Locale locale = RequestContextUtils.getLocale(request);
// Use the path to your bundle
ResourceBundle bundle = ResourceBundle.getBundle("WEB-INF.i18n.messages", locale);
// Call the string.jsp view
return new ModelAndView("strings.jsp", "keys", bundle.getKeys());
2) 实现 View "strings.jsp"
<%@page contentType="text/javascript" pageEncoding="UTF-8"
%><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"
%><%@taglib prefix="spring" uri="http://www.springframework.org/tags"
%>var messages = new Array();
<c:forEach var="key" items="$keys">messages["<spring:message text='$key' javaScriptEscape='true'/>"] = "<spring:message code='$key' javaScriptEscape='true' />";
</c:forEach>
3) 在您的 HTML 源代码中导入“spring.js”。 Messages 数组可用并加载了正确的语言。
可能的问题:如果用户改变他的语言,“spring.js”必须由导航器重新加载,但它会被缓存。当用户更改他的语言(或其他技巧以重新加载文件)时,需要清除缓存。
【讨论】:
【参考方案3】:除了@Toilal 的回答之外,您还可以在strings.jsp 中添加一个辅助函数来更好地使用翻译数组:
<%@page contentType="text/javascript" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
var messages = new Array();
<c:forEach var="key" items="$keys">messages["<spring:message text='$key' javaScriptEscape='true'/>"] = "<spring:message code='$key' javaScriptEscape='true' />";
</c:forEach>
/**
* Tranlate a String by key, if key is not defined return the key.
*
* @author Pedro Peláez <aaaaa976 at gmail dot com>, Drupal/Wordpress authors, and others
* @param String key
* @returns String
*/
function t(key)
if (messages[key])
return messages[key];
return key;
然后在需要时使用:
alert(t("menu.section.main"));
【讨论】:
【参考方案4】:将 spring 的 message.properties 转换为 JavaScript 对象,然后在其他 JavaScript 文件中使用该对象非常简单。我们可以使用node module 进行转换
app.name=Application name
app.description=Application description
到
const messages = app: name: 'Application name', description: 'Application description' ;
然后应该为每个 messages.lang.properties 创建一个 messages_lang.js 文件并在模板中引用。在 thymeleaf 模板中,它看起来像这样:
<script th:src="@'/js/messages_' + $#locale + '.js'"></script>
<script>
console.log(messages.app.name, messages.app.description);
</script>
为此,我创建了一个快速grunt plugin。
【讨论】:
以上是关于为 i18n 国际化解析 spring:messages in javascript的主要内容,如果未能解决你的问题,请参考以下文章