使用requireJS和预编译的Handlebars模板加载翻译(i18next)



我有一个requireJS设置,其中包含预编译的Handlebars模板和数据库中的翻译i18next。我需要按照以下顺序做一些事情:

  1. 从数据库加载我的翻译
  2. 在Handlebars中注册一个帮助程序,以便可以翻译预编译模板中的值

我的requireJS配置文件如下:

require.config({
  deps: ["main"],   
  paths: {
    'handlebars.runtime': "../assets/js/libs/handlebars.runtime.amd.min",
    i18n: "../assets/js/libs/i18next-1.7.1",
    // Shim Plugin
    use: "../assets/js/plugins/use"
  },
  use: {
    i18n: {
      attach: "i18n"
    }
  } 
});

我的main.js文件如下所示,它需要namespace.js:

require([
  'namespace',
  'modules/Transport'
], function (
  namespace,
  $,
  Transport
) {
  var Router = Backbone.Router.extend({
    routes: {
      '*any':                'any'
    },

我的namespace.js将尝试注册Handlebars帮助程序,然后用翻译初始化i18:

define([
  "handlebars.runtime",
  "use!i18n"
], function(
  Handlebars,
  i18n
) {   
  var defaultLanguage = 'en';
  var translations;
  $.when(
      $.getJSON('/api/translations', function (result) {
        translations = result;
      })
  ).then(function () {
    i18n.init({ useCookie: false, resStore: translations, lng: defaultLanguage });
    Handlebars.default.registerHelper('t', function(i18n_key) {
      var result = i18n.t(i18n_key);
      return new Handlebars.default.SafeString(result);
    });
  });

我的modules/Transport.js模块将依赖于namespace.js,并将加载预编译的模板。加载预编译模板时,它在Handlebars.default.templates中可用。所以我的模块看起来是这样的:

define([
  'namespace',
  'templates/compiled/transport_template'
], function(
  namespace,
) {
  i18n.t('translate something');
  var template = Handlebars.default.templates['transport_template'];

我遇到的问题是,我不能让requireJS首先加载翻译,然后再注册助手并在我的模块中进行一些翻译。模块和模板在对数据库的异步调用完成之前就被加载了,所以我总是在没有加载东西(或者助手,或者i18next模块)时出错

我真的很困惑,在加载模块之前,我如何设置requireJS来先加载Handlebars和i18next?

几个注意事项:

  • RequireJS提供了一个内置的shim配置属性,您可能不需要use.js
  • i18next提供AMD模块版本(可在其主页上获得),因此您不需要填充它。不确定他们是否遵循最佳实践,但它有效
  • 永远不要在AMD模块中使用全局对象,始终明确要求对象作为依赖项
  • 考虑到所有这些,你几乎已经达到了你需要达到的水平;只要您需要在另一个模块中使用其t函数,您就可以简单地使用require('i18next')。剩下的问题是如何确保i18next正确初始化,我在下面给出了答案
  • 我不熟悉Handlebars,尤其是它的助手功能,所以这可能只是你一半问题的答案

不久前,我不得不用i18next解决本质上相同的问题;我基本上将它的模块封装在另一个模块中,该模块在返回它之前初始化i18next

i18next-wapper.js

define(function (require) {
    var i18next = require('i18next-actual');
    i18next.init(...);
    return i18next;
});

为了增加透明度,您可以使用路径:

requirejs.config({
    paths: {
        'i18next-actual': 'path/to/i18next.amd-$version',
        'i18next': 'path/to/i18next-wrapper',
    }
});

这样,require('i18next')的所有用户模块都将确保它被初始化一次,并且实际的i18next模块不必修改。

因此,这有望回答您的问题,即如何在需要i18next的模块之前先加载和初始化它。您应该能够对任何其他模块执行同样的操作。

如果你可以使用它,其他人可能会帮助处理Handlebars的细节,或者你可以从这里开始。

编辑:我忘记了i18next的异步特性。我记得包装了t函数来检查initialized标志,以确保i18next确实已完全加载(包括翻译)。虽然这样做有效,但我最终认为增加的复杂性不值得立即使用,并决定使用getAsync: false i18next选项。你可能不同意。

最新更新