解决spring:用于i18n国际化的javascript消息

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解决spring:用于i18n国际化的javascript消息相关的知识,希望对你有一定的参考价值。

我试图将我们的一些代码国际化。我在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中,可以获取spring标记。

谢谢你的帮助!

答案

在我看来,你想要做的是将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的某些部分。还有一些情况我们需要本地化一些第三方组件,我上面的答案很好地处理它们。 对于我们想要动态创建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属性
  • text标签提供<spring:message />属性是有意义的,因为它可以用作后备(如果没有给定语言的翻译)以及注释(这个元素代表什么)。甚至可以创建一个工具来扫描<spring:message />标签的文件并自动生成属性文件
  • 为了防止Handlebars逃避HTML内容,我使用了三个{{{curly braces}}}

基本上就是这样。如果可能,我建议使用模板。

另一答案

感谢您的回答。这是一个更通用的解决方案。

我们的想法是提供一个名为“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”,但它将被缓存。当用户更改其语言(或其他技巧以重新加载文件)时,需要清除缓存。

另一答案

除了回答@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"));
另一答案

将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} .js文件。{lang} .properties并在模板中引用。在百里香叶模板中,它看起来像这样:

  <script th:src="@{'/js/messages_' + ${#locale}  + '.js'}"></script> 
  <script>
    console.log(messages.app.name, messages.app.description);
  </script>

我为此创造了一个快速的grunt plugin

以上是关于解决spring:用于i18n国际化的javascript消息的主要内容,如果未能解决你的问题,请参考以下文章

从源码MessageSource的三个实现出发实战spring·i18n国际化

spring的i18n国际化消息翻译

Java Spring国际化(i18n)问题

Java国际化(i18n)

Spring BootSpringMVC进行i18n国际化支持:使用MessageSource

Spring BootSpringMVC进行i18n国际化支持:使用MessageSource