使用require.js、backbone和underscore本地化模板

15
这个问题涉及到使用require.js和backbone.js通过underscore模板进行模板化和本地化。应用程序需要在运行时进行本地化。
在采取可能会出现问题的路径之前,是否有比我考虑的更好的解决方案?我担心重复合并和处理语言数组会影响速度和内存。假设有2-3千个语言字符串。
当前的方法(可行,但看起来很占用处理器):
1.使用I18N捆绑方法创建包含所有模板翻译元素的语言"包含"。
2.将此对象/数组与backbone的模型属性合并,并将合并后的内容传递给underscore模板。

.

define(['backbone', 'models/model', 'text!template.html', 'i18n!my/nls/translatedbits'],
  function(Backbone, MyModel, TemplateText, TranslationObject) {
  var View = Backbone.View.extend({
    model: {},

    initialize : function(params) {
      this.model = new MyModel();
    },

    render : function(callBack) {
      // Get the model attributes
      var templateParams = _.clone(this.model.attributes);
      // Bolt on the tranlsated elements (established from require.js I18N plugin)
      templateParams.t = TranslationObject;
      // Pass the lot ot the template
      var template = _.template(TemplateText, this.model.attributes);
      $(this.el).html( template );
      return this;
    }

  });
  return View;
  }
);

然后模板将读取。
<%= modelAttribute1 %> <%= t.translationString1 %>

我是否可以使用更好的解决方案或更好的模板引擎?[更适合此目的 - mustache可能具有其他优点,但它能否更容易地本地化,或者能否缓存本地化结果以允许稍后传递模型属性?]

请注意,语言可能需要“即时”更改 - 这是我对I18N插件的另一个担忧。我最终可能会通过模板模型通过JSON请求获取翻译,但这仍然需要对象合并,这正是我试图避免的。


关于预编译模板为基于语言字符串的 JavaScript 文件(每种语言都有一个包含模板字符串的 JavaScript 文件,例如英文和法文各一个),您怎么看?当用户更新语言偏好时,加载一个不同的 JavaScript 模板文件来处理所有“静态”翻译,但保留模型属性,因为那些是动态的。 - DashK
@DashK - 谢谢。我考虑过两种方法。一种使用require有些繁琐,但我考虑创建一个模板模型,然后根据需要(通过require)加载每个模板,进行预解析和缓存等,然后将模板从模型中召回到视图中。另一种选择是在服务器端(使用php或node.js)进行预编译,通过JSON调用模板,但仍需要中间的缓存模型。但我认为必须有更好、更标准的方法,除非这些是唯一的选择?感谢您的建议。 - Robbie
2个回答

13
这是我目前正在做的事情(因为它似乎对他人有用,所以我将其公开)。 underi18n 是一个非常简单的库,用于在模板和代码中进行 i18n。
它提供了以下功能:
- 将 gettext 目录简单转换为 json 格式。 - 支持翻译字符串中的变量替换。
它不处理复数形式的翻译。
从 README 中可以看到:

目录

under18n 使用简单的 JSON 格式作为目录,遵循标准的 gettext 格式。 在以下示例中,
{
    'Developer': 'Προγραμματιστής',
    'Role ${role} does not exist in ${context}': 'Ο ρόλος ${role} δεν υπάρχει στο ${context}'
}

我们有两个翻译字符串,第二个字符串有两个变量: role context 。提供了一个简单的Python脚本来帮助您将标准的.mo文件转换为这种JSON格式。

用法

从json i18n目录创建一个MessageFactory

var t = underi18n.MessageFactory(catalog);

现在您可以进行行内翻译:

t('Developer') // returns "Προγραμματιστής"

t('Role ${role} does not exist in ${context}', {role: 'διαχειριστής', context: 'πρόγραμμα'})
// Returns "Ο ρόλος διαχειριστής δεν υπάρχει στο πρόγραμμα"

模板

通常,模板中的变量会使用某些分隔符来表示。例如,在mustache中使用{{ var }},而在underscore中使用<%= var %>作为默认值。我们使用同样的方法来指示可翻译的字符串。您可以将可翻译字符串的分隔符指定为RegExp,并指定您选择的模板语言中使用的左/右分隔符,方法是在under18n.templateSettings中设置。默认情况下,这遵循underscore约定:

templateSettings: {
    translate: /<%_([\s\S]+?)%>/g,
    i18nVarLeftDel: '<%=',
    i18nVarRightDel: '%>'
}

所以,<%_ i18n %> 用于表示可翻译的字符串,<%= var %> 用于表示模板中的变量。
您可以通过调用 under18n.template 来翻译模板,例如使用 underscore,您可以这样做:
var templ = _.template(under18n.template(myTemplate, t));

例子

假设有以下英语和希腊语的目录、工厂和模板,并且使用下划线模板,那么:

var test_en = {
        'files_label': 'Files',
        'num_files': 'There are ${num} files in this folder'
    },

    templ = '<h1><%= title %></h1>' +
            '<label><%_ files_label %></label>' +
            '<span><%_ num_files %></span>',

    t_en = underi18n.MessageFactory(test_en);
    t_el = underi18n.MessageFactory(test_el);

模板可以通过以下方式构建:
var toRender = _.template(underi18n.template(templ, t_en));
toRender({title: 'Summary', num: 3});

将产生

<h1>Summary</h1>
<label>Files</label>
<span>There are 3 files in this folder</span>

AMD加载

如果您使用RequireJS,under18n将注册为匿名模块。

我希望这可以解决您的问题,如果还有问题,请告诉我。我计划在某个阶段发布它,但是现在比永远好;)


+1 细节,谢谢(它可能值得更多!)。我将不得不测试它并反馈是否看起来更清洁。谢谢。 - Robbie
谢谢!非常欢迎提供反馈,这个程序已经在生产环境中运行一段时间并表现良好。请注意,如果您愿意,也可以在服务器上进行编译! - ggozad
这看起来像是一个搜索和替换函数,使用“在手”的字符串(对象)。我们可以通过requires I18N bundles将这些字符串/对象引入,但它仍然具有与直接运行underscore相同的缺点 - 没有缓存,并且会重复解析大量大型对象。或者我有什么遗漏的地方吗(如果有的话,请原谅)?谢谢。 - Robbie
我避免完全在客户端计算的方法是在服务器上准备国际化模板!这样你的客户端只需要加载本地化的模板即可。这样就没有解析和大对象了,事实上,你甚至不再需要underi18n。 - ggozad
这差不多是我的想法。但并不能解决问题。谢谢回复。 - Robbie
我不确定问题出在哪里。没有昂贵的操作,也不需要额外的缓存。作为奖励,您可以在i18n中获得变量。但也许我还没有真正理解问题所在。 - ggozad

9
为了完整性,我们提出的解决方案是:
  1. 当服务器请求模板时,一个cookie决定了语言,并传递正确的模板。

  2. 使用PHP后端对模板进行预解析;然后将其存储在正确语言的缓存中(memcached)。

  3. 一旦请求语言模板,它就会被浏览器和内部backbone模型缓存,以便JavaScript可以快速重复使用。

原因:
  • JS更快(远少于正则表达式替换)。虽然我们从未进行过基准测试,但当您完全删除函数时,这是唯一合乎逻辑的。
  • 避免了向客户端传输巨大的语言文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接