Как сделать i18n с помощью Handlebars.js(шаблоны усов)?
В настоящее время я использую Handlebars.js(связанный с Backbone и jQuery), чтобы сделать веб-приложение практически полностью обработанной клиентской стороной, и у меня возникли проблемы с интернационализацией этого приложения.
Как я могу сделать эту работу?
Есть ли какие-либо плагины?
Ответы
Ответ 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>