Marionette.Renderer, Underscore шаблоны и интернационализация с i18next

В настоящее время мы нуждаемся в добавлении интернационализации в приложение среднего размера, используя Backbone.Marionette и шаблоны подчеркивания.

После некоторого тщательного исследования появляются два правильных варианта:

  • underi18n, который обеспечивает прямую интеграцию с подчеркиванием, но не имеет множественного числа, что становится необходимым для поддержки не только французского и английского
  • i18next, который предоставляет мощный API, но только прямую интеграцию с шаблонами руля

Нам потребуется более длительный срок для локализации на многие другие языки (надеюсь!), Так что underi18n, вероятно, потерпит неудачу, и тогда единственными жизнеспособными решениями станет i18next.

Прежде чем идти дальше, я опишу два моих вопроса, а затем предоставлю полный контекст и процесс исследования, через который я прошел.

  1. Как я могу централизовать локализацию моих шаблонов, используя i18next и Marionette
  2. Как я могу добавить глобального помощника во все мои шаблоны подчеркивания

Централизация локализации шаблонов

Одна вещь, которую я нахожу очень неприятной с i18n, это то, как вы должны вызывать ее во всех своих функциях onRender, что означает добавление вызова в каждый из наших десятков текущих представлений и всех наших будущих представлений. На мой взгляд, поправьте меня, если я ошибаюсь, это будет выглядеть так:

MyView = Marionette.ItemView.extend({

  template: myUnlocalizedTemplate,

  onRender: function () {
    /* ... some logic ... */
    this.$el.i18n();
  }
  /* And everything else... */
});

и повторяться снова и снова.

Я нахожу это очень неудобным с точки зрения реализации и обслуживания, поэтому я начал копаться в Backbone и Marionette, вспомнив из прошлого проекта, что был какой-то способ предварительной обработки шаблонов в глобальном масштабе.
Я натыкаюсь на Marionette.Renderer, который кажется подходящим инструментом для работы. Но прежде чем приступить к полной установке и внедрению i18next, я хочу убедиться, что я на правильном пути.
Потому что, если я могу ясно видеть, как underi18n и _.template(under18n.template(myTemplate, t)); мог бы быть хорошо интегрирован с Renderer и предоставить мне глобальное решение для предварительной обработки и локализации моих шаблонов, я не уверен в том, что делать с i18next в этом случае.
Тот факт, что я не смог найти никого, кто бы делал это, также беспокоит меня, все ли используют шаблоны руля или звонят вручную .i18n() в каждом взгляде? На данный момент нет элементов jquery для привязки перевода, поэтому я довольно озадачен тем, как это возможно.

Буду очень признателен за ответ, предоставляющий пример того, чего я пытаюсь достичь, дополнительную документацию или советы о том, как двигаться дальше!

2 ответа

Решение

Я наконец нашел хороший выход из этого. Вот оно, как я надеюсь, это может помочь другим в этой ситуации.

/* Some initializer
 * ...
 */

// Init i18n and
// Start the app in the callback
$(function() { 
  i18n.init({
    function (t) {
      App.start();
    }
  });
});

// Following in the initialize:after
// We'll override the default Marionette.Renderer.render function
App.on('initialize:after', function() {
  overwriteRenderer();
});

function overwriteRenderer() {
  // Simply use a closure to close over the current render function
  var render = Marionette.Renderer.render;

  // Then override it
  Marionette.Renderer.render = function (template, data){

    // Extend data to inject our translate helper    
    data = _.extend(data, {_t: i18n.t});

    // And finally return the result of calling the original render function
    // With our injected helper
    return render(template, data);
  };
}


// Then in any template, simply use it as follow
// Do not forget the `=` to output the translation in the final DOM
<div>
  <%= _t("my_key", {options: "my options"} %>
</div>

Как показано, я разработал это, внедрив функцию translate во все шаблоны в качестве помощника вида. Это решение хорошее и чистое, поскольку оно делегирует большую часть перевода шаблонам, где, как я считаю, должно быть. Это также не требует изменения какого-либо представления, резко ограничивая количество изменений, необходимых для выполнения локализации в существующем проекте.

Еще одна приятная деталь: вы также можете вставить переменную в свою интерполяцию, что означает что-то вроде этого:

<div>
  <%= myVar %>
</div>

можно превратить в нечто подобное для интерполяции

<div>
  <%= _t("my_key", {option: myVar} %>
</div>

Или даже

<div>
  <%= _t("my_key", {option: _t(myDynamicKey)} %>
</div>

И в файле po

msgid "my_translation_with_interpolation"
msgstr "My translation with __option__"

Позволяет вам динамически вводить ключ, который будет локализован и затем интерполирован в исходной строке.

Надеюсь, это поможет кому-то еще.

Другое решение, если вам нужен доступ к экземпляру представления в помощниках:

// Global template helpers in Marionette
var _mixinTemplateHelpers = Marionette.View.prototype.mixinTemplateHelpers;
Marionette.View.prototype.mixinTemplateHelpers = function(target) {
    var _this = this;
    target = _.extend({
        // generate a unique id in the view's scope
        _id: function(baseName) {
            return _this.cid + '-' + baseName;
        },
    }, target);
    return _mixinTemplateHelpers.call(this, target);
};
Другие вопросы по тегам