【问题标题】:Resolving spring:messages in javascript for i18n internationalization为 i18n 国际化解析 spring:messages in javascript
【发布时间】: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 中,弹簧标签被拾取。

感谢您的帮助!

【问题讨论】:

    标签: javascript spring spring-mvc internationalization dojo


    【解决方案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);
    

    这里有几点需要注意:

    • &lt;spring:message /&gt; 标签默认同时转义 HTML 和 JS,我们不需要指定 javaScriptEscape 属性
    • &lt;spring:message /&gt; 标签提供text 属性是有意义的,因为它可以用作后备(如果没有给定语言的翻译)以及注释(此元素代表什么)。甚至可以创建一个工具来扫描文件中的&lt;spring:message /&gt; 标签并自动生成属性文件
    • 为了防止 Handlebars 转义 HTML 内容,我使用了三重 {{{curly braces}}}

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

    【讨论】:

    • 很好的答案,但 spring:message 标签应该正确终止以避免错误。我试图编辑,但由于它只添加了 2 个字符,所以告诉我离开,因为显然它不够有建设性,除非有 6 个或更多字符:)
    • @GreenDay:谢谢,我自己没有注意到这个问题。现在应该没问题了。
    • @PawełDyda 请注意,我使用双引号来写出翻译后的字符串。这是因为法语或意大利语中的某些单词可能包含撇号。 这不就是 javaScriptEscape='true' 应该注意的吗? 标签默认同时转义HTML和JS,我们不需要指定javaScriptEscape属性 那你上面为什么指定呢?
    • @domenicop:基本上,我从问题中重写了代码,没有考虑太多。没错,spring:message 标签默认转义文本(暗示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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-07
          • 1970-01-01
          • 1970-01-01
          • 2019-08-05
          • 2017-06-09
          • 2012-02-25
          相关资源
          最近更新 更多