Подтвердить что ты не робот

Как сделать i18n с помощью Handlebars.js(шаблоны усов)?

В настоящее время я использую Handlebars.js(связанный с Backbone и jQuery), чтобы сделать веб-приложение практически полностью обработанной клиентской стороной, и у меня возникли проблемы с интернационализацией этого приложения.

Как я могу сделать эту работу?

Есть ли какие-либо плагины?

4b9b3361

Ответ 1

Я знаю, что на это был дан ответ, но я хотел бы поделиться своим простым решением. Чтобы использовать решение Gazler с использованием I18n.js(которое мы используем с нашим проектом на работе), я просто использовал очень простой помощник Handlebars, чтобы облегчить процесс локализации на лету:

Обработчик

Handlebars.registerHelper('I18n',
  function(str){
    return (I18n != undefined ? I18n.t(str) : str);
  }
);

Шаблон

<script id="my_template" type="x-handlebars-template">
    <div>{{I18n myVar}}</div>
</script>

Основное преимущество этого заключается в том, что нет дорогостоящей предварительной/пост-обработки всего json-объекта. Не говоря уже о том, что входящий json имеет вложенные объекты/массивы, время, затрачиваемое на поиск и анализ для них, может стать дорогостоящим, если объект огромен.

Ура!

Ответ 2

https://github.com/fnando/i18n-js - это рубиновая жемчужина, которая создаст файл интернационализации из вашей папки config/locales. Однако, если вы не используете рельсы, вы можете найти javascript, который используется самостоятельно здесь.

Затем вы просто сохраняете переводы во вложенном объекте.

I18n.translations = {"en":{"date":{"formats":{"default":"%Y-%m-%d","short":"%b %d","long":"%B %d, %Y"}}}};

То, что может быть полезно для вас, которое я использую в моих проектах, - это патч к усам, который автоматически переводит строки в формате @@translation_key @@

i18nize = function (result) {
    if (I18n) {
      var toBeTranslated = result.match(/@@([^@]*)@@/gm);
      if (!toBeTranslated) return result;
      for(var i = 0; i < toBeTranslated.length; i++) {
        result = result.replace(toBeTranslated[i], I18n.t(toBeTranslated[i].replace(/@/g, "")));
      }
    }
    return result;
};

Затем вы вызываете i18nize после рендеринга, чтобы вы могли помещать переводы в свои шаблоны, а не передавать их.

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

Надеюсь, что это поможет.

Ответ 3

На основе ответа @poweratom:

Только с ember.js, с параметрами, переданными в I18n.js.

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

Ember.Handlebars.helper "t", (str, options) ->
  if I18n? then I18n.t(str, options.hash) else str

Шаблон:

{{t 'sharings.index.title' count=length}}

YML:

en:
  sharings:
    index:
      title: To listen (%{count})

Ответ 4

С NodeJs/Express :

  • node-i18n (определить заголовок Accept-Language)

      app.use(i18n.init); 
    
  • Пример файла перевода

    {   
     "hello": "hello",   
     "home-page": {
       "home": "Home",
        "signup": "Sign Up"  
     } 
    }
    
  • В экспресс-контроллере

    ...
    data.tr = req.__('home-page');
    var template = Handlebars.compile(source);
    var result = template(data);
    
  • Шаблон руля

        <li class="active"><a href="/">{{tr.home}}</a></li>
    

Ответ 5

Ответ на этот вопрос отвечает, но это может быть случай, когда вы не хотите зависеть от каких-либо i8n lib и полностью использовать свои собственные. Я использую свое собственное вдохновение из https://gist.github.com/tracend/3261055

Ответ 6

для тех, кто не использует какую-либо инфраструктуру JS http://i18next.com выглядит многообещающе.

просто создайте помощники руля, чтобы переводить вызовы, как здесь http://i18next.com/pages/doc_templates.html

Ответ 7

Как уже установлено, у Руль нет установленного метода интернационализации, даже в 2019 году.

Существующие ответы не иллюстрируют более сложные/важные аспекты интернационализации на стороне клиента, такие как правила грамматики, или они создают зависимость от YML и/или Ember, или требуют рендеринга на стороне сервера (nodejs).

Основываясь на ответе @poweratom (который, в свою очередь, основан на ответе @Glazer), можно зарегистрировать помощника, который разрешает передачу параметров Handlebars (которые, конечно, в JS по умолчанию по умолчанию не определены).

Handlebars.registerHelper('i18n',
  function(str,o1,o2,o3){
    return new Handlebars.SafeString((typeof(i18n) !== "undefined" ? i18n(str,o1,o2,o3) : str));
  }
);

Используя это на i18njs.com (npm/roddeh-i18n), мы можем добавлять переводы, используя клиентскую только JSON/JavaScript:

i18n.translator.add({
  "values":{
    "Yes": "はい",
    "No": "いいえ",
    "It is %n": [[0,null,"%nです"]],
    "Do you want to continue?": "続けたいですか?",
    "Don't worry %{name}": "%{name}を心配しないでください",
    "%{name} uploaded %n photos to their %{album} album": "%{name}は彼の%{album}アルバムに写真%n枚をアップロードしました"
  },
  "contexts":[
    {
      "matches": { "gender": "male" },
      "values": { "%{name} uploaded %n photos to their %{album} album": [[0,null,"%{name}は彼の%{album}アルバムに写真%n枚をアップロードしました"]] }
    },
    {
      "matches": { "gender": "female" },
      "values": { "%{name} uploaded %n photos to their %{album} album": [[0,null,"%{name}は彼女の%{album}アルバムに写真%n枚をアップロードしました"]] }
    }
  ]
});

Мы можем создать шаблон руля, где мы передаем параметры в библиотеку. Например, форматирование числа (т.е. "% N") требует, чтобы первым параметром был путь к номеру. Таким образом, чтобы получить счет от объекта {"count": 3}, мы можем ссылаться на путь "./count" или просто "count". Условные совпадения требуют, чтобы последний параметр был путем к объекту, где совпадения будут найдены; обычно это просто корневой объект ".".

<script id="messagestemplate" type="text/x-handlebars-template">
  <p>
    {{i18n 'Do you want to continue?'}} {{i18n 'Yes'}}<br>
    {{i18n 'Don\'t worry %{name}' . }}<br>
    {{i18n 'It is %n' count}}<br>
    {{i18n '%{name} uploaded %n photos to their %{album} album' count . .}}
  </p>
</script>

И, наконец, шаблон можно отобразить как обычно с помощью Handlebars:

var userData = {
  gender: "male",
  name: "Scott",
  album: "Precious Memories",
  count: 1
};

var templateSource = $("#messagestemplate").html();
var messagesTemplate = Handlebars.compile(templateSource);
var renderedMessages = messagesTemplate(userData);

$('#target-message').html(renderedMessages);

Вот более полный пример:

// Using http://i18njs.com (npm/roddeh-i18n)

// Includes:
//   cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js
//   rawgit.com/components/handlebars.js/master/handlebars.js
//   cdn.jsdelivr.net/npm/[email protected]/dist/i18n.min.js


// REGISTER I18N HELPER   {{i18n 'Text to translate'}}

Handlebars.registerHelper('i18n',
  function(str,o1,o2,o3,o4,o5){
    return new Handlebars.SafeString((typeof(i18n) !== "undefined" ? i18n(str,o1,o2,o3,o4,o5) : str));
  }
);


// REGISTER THE TEMPLATE

var templateSource = $("#atemplate").html();
var template = Handlebars.compile(templateSource);

function updateMessage(data) {
  $('#target-message').html(template(data));
}


// ADD TRANSLATIONS

function setLanguage(lang) {
  // Spanish
  if (lang == 'es') {
    i18n.translator.reset();
    i18n.translator.add({
      "values":{
        "Yes": "Si",
        "No": "No",
        "Do you want to continue?": "¿Quieres continuar?",
        "Don't worry %{name}": "No te preocupes %{name}",
        "It is %n": [[0,null,"Es %n"]],
        "%{name} uploaded %n photos to their %{album} album":[
            [0, 0, "%{name} ha subido %n fotos a su album %{album}"],
            [1, 1, "%{name} ha subido %n foto a su album %{album}"],
            [2, null, "%{name} ha subido %n fotos a su album %{album}"]
         ]
      }
    });
  }

  // Japanese
  else if (lang == 'jp') {
    i18n.translator.reset();
    i18n.translator.add({
      "values":{
        "Yes": "はい",
        "No": "いいえ",
        "It is %n": [[0,null,"%nです"]],
        "Do you want to continue?": "続けたいですか?",
        "Don't worry %{name}": "%{name}を心配しないでください",
        "%{name} uploaded %n photos to their %{album} album": "%{name}は彼の%{album}アルバムに写真%n枚をアップロードしました"
      },
      "contexts":[
        {
          "matches":{ "gender":"male" },
          "values":{ "%{name} uploaded %n photos to their %{album} album": [[0,null,"%{name}は彼の%{album}アルバムに写真%n枚をアップロードしました"]] }
        },
        {
          "matches":{ "gender":"female" },
          "values":{ "%{name} uploaded %n photos to their %{album} album": [[0,null,"%{name}は彼女の%{album}アルバムに写真%n枚をアップロードしました"]] }
        }
      ]
    });
  }

  // Default Language (English)
  else {
    i18n.translator.reset();
    i18n.translator.add({
      "values":{
        "Yes": "Yes",
        "No": "No",
        "Do you want to continue?": "Do you want to continue?",
        "Don't worry %{name}": "Not to worry %{name}",
        "It is %n": [[0,null,"It %n"]],
        "%{name} uploaded %n photos to their %{album} album":[
            [0, 0, "%{name} uploaded %n photos to their %{album} album"],
            [1, 1, "%{name} uploaded %n photo to their %{album} album"],
            [2, null, "%{name} uploaded %n photos to their %{album} album"]
         ]
      }
    });
  }
}


// SET DEFAULT LANGUAGE TO BROWSER/SYSTEM SETTINGS

var browserLanguage = (navigator.languages && navigator.languages[0] || navigator.language || navigator.userLanguage || navigator.browserLanguage || navigator.systemLanguage || 'en').split('-')[0];

setLanguage(browserLanguage);


// RENDER THE TEMPLATE WITH DATA

var userData = {
  gender: "female",
  name: "Scott",
  album: "Precious Memories",
  count: 1
};

updateMessage(userData);


// USER-TRIGGERED LANGUAGE SELECTION

// note: the array around browserLanguage is important when setting radio buttons!
$("input[name=lang]")
  .val([browserLanguage])
  .click(
    function() {
      var lang = $('input[name=lang]:checked').val();
      setLanguage(lang);
      updateMessage(userData);
    }
  );
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/i18n.min.js"></script>
<script src="https://rawgit.com/components/handlebars.js/master/handlebars.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>

<h1>i18n with Handlebars</h1>

<label><input type="radio" name="lang" value="en"> English</label><br>
<label><input type="radio" name="lang" value="es"> Espanol</label><br>
<label><input type="radio" name="lang" value="jp"> Japanese</label>

<div id="target-message"></div>

<!--
  NOTE: The helper {{i18n ...}} is just a passthrough for
    the i18n library. Parameters come from the single object
    passed into the handlebars template. Formatting a
    number (i.e. "%n") requires the first parameter to be
    the path to the number.  For example, count from the
    object {"count":3} could be referenced by the path
    "./count" or just "count".  Conditional matches require
    the last parameter to be the path to the object where
    the matches will be found; usually just the root object ".".

    see:
      handlebarsjs paths:   https://handlebarsjs.com/#paths
      i18n formatting:      http://i18njs.com/#formatting
-->

<script id="atemplate" type="text/x-handlebars-template">
  <p>
    {{i18n 'Do you want to continue?'}} {{i18n 'Yes'}}<br>
    {{i18n 'Don\'t worry %{name}' . }}<br>
    {{i18n 'It is %n' count}}<br>
    {{i18n '%{name} uploaded %n photos to their %{album} album' count . .}}
  </p>
</script>