¿Cómo hacer i18n con Handlebars.js (plantillas de bigote)?
⏰ 10 minutos de lectura
mdcarter
Actualmente estoy usando Handlebars.js (asociado con Backbone y jQuery) para hacer que una aplicación web se represente casi en su totalidad en el lado del cliente, y tengo problemas con la internacionalización de esta aplicación.
Sé que esto ha sido respondido, pero me gustaría compartir mi solución simple. Para construir sobre la solución de Gazler usando I18n.js (que usamos con nuestro proyecto en el trabajo), solo usé un asistente de Handlebars muy simple para facilitar el proceso para hacer la localización sobre la marcha:
La principal ventaja de esto es que no hay un procesamiento previo o posterior costoso en todo el objeto json. Sin mencionar que si el json entrante tiene objetos/matrices anidados, el tiempo dedicado a buscarlos y analizarlos puede ser costoso si el objeto es enorme.
¡Salud!
Preferiría esta solución en comparación con las de @Gazler
Estoy recibiendo este error: TypeError: I18n.t is not a function. ¿Cualquier sugerencia?
– slackmart
25 de marzo de 2015 a las 22:17
@sgmart, el requisito previo para usar I18n incluye la biblioteca I18n (o equivalente): github.com/fnando/i18n-js
– átomo de poder
25 de marzo de 2015 a las 23:38
¿Qué pasa si un objeto con valores de traducción dinámicos tiene que ser analizado por el asistente de traducción? {{ I18n 'key' {dynamic: 'value'} }} no parece funcionar.
– Rvanlaak
22 de noviembre de 2018 a las 10:16
mirador
https://github.com/fnando/i18n-js es una gema rubí que creará un archivo de internacionalización desde su carpeta config/locales. Sin embargo, si no está utilizando rieles, puede encontrar el javascript utilizado por sí solo aquí.
Luego, simplemente almacena las traducciones en un objeto anidado.
Algo que también te puede servir que yo uso en mis proyectos es un parche para bigote que automáticamente traduce cadenas en el formato @@[email protected]@
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;
};
Luego llamas a i18nize después renderizar para permitirle poner traducciones en sus plantillas en lugar de pasarlas.
Tenga cuidado con parchear el bigote, ya que no podrá portar sus plantillas a las implementaciones estándar del bigote. Sin embargo, en mi caso, los beneficios ofrecidos superaron este problema.
Espero que esto ayude.
Eso es realmente genial, me perdí por completo el hecho de que podía “volver a analizar” la plantilla una vez renderizada con una función mía, eso es exactamente lo que haré, creo, tal vez con R.js o algo así. muchas gracias =)
– mdcarter
13/10/2011 a las 21:09
jvenezia
Basado en la respuesta de @poweratom:
Solo con ember.js lo mismo con las opciones pasadas a I18n.js.
Se volverá a cargar mágicamente si se utilizan propiedades calculadas.
Ember.Handlebars.helper "t", (str, options) ->
if I18n? then I18n.t(str, options.hash) else str
Modelo:
{{t 'sharings.index.title' count=length}}
Yml:
en:
sharings:
index:
title: To listen (%{count})
La pregunta está respondida, pero puede ser un caso en el que no desee depender de ninguna i8n lib y usar completamente la suya. Estoy usando mi propia inspiración de https://gist.github.com/tracend/3261055
presa1
Con NodeJs/Express :
nodo-i18n (detectar el encabezado Accept-Language)
Como ya se estableció, el uso de Handlebars para la internacionalización significa que tendrá que registrar un asistente personalizado para vincular a la biblioteca i18n de su elección. La mayoría de las bibliotecas i18n no tienen este “pegamento” listo para usar, pero es bastante fácil de agregar.
Sobre la base de la respuesta de @poweratom (que a su vez se basa en la de @Glazer), uno puede registrar un ayudante que permite pasar los parámetros del manillar.
Las respuestas existentes usan otras bibliotecas, pero prefiero http://i18njs.com (npm/roddeh-i18n) porque tiene un mejor soporte para los aspectos más importantes de la internacionalización del lado del cliente, como las reglas gramaticales (y no crea una dependencia de YML y/o Ember, y no requiere del lado del servidor). renderizado con nodejs).
Con el ayudante registrado arriba, podemos agregar traducciones usando solo lado del cliente 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枚をアップロードしました"]] }
}
]
});
Ahora, cualquier plantilla de manillar que creemos se puede internacionalizar simplemente pasando los parámetros a la biblioteca. Por ejemplo, formatear un número (es decir, “%n”) requiere que el primer parámetro sea la ruta al número. Entonces, para obtener el recuento de un objeto {“count”:3}, podríamos hacer referencia a la ruta “./count” o simplemente “count”. Las coincidencias condicionales requieren que el último parámetro sea la ruta al objeto donde se encontrarán las coincidencias; generalmente solo el objeto raíz “.”.
<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>
Y finalmente, la plantilla se puede representar de forma normal con 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);
Aquí hay un ejemplo más completo:
// 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){
return new Handlebars.SafeString((typeof(i18n) !== "undefined" ? i18n.apply(null, arguments) : 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's %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>
El sitio estático para i18njs <i18njs.com> no es compatible con https por alguna razón. Sin embargo, a SO le gusta cambiar todos los enlaces a HTTPS de vez en cuando. Si el enlace está roto, intente volver a http://….
– Jaime
12 abr a las 16:10
¿Ha sido útil esta solución?
Tu feedback nos ayuda a saber si la solución es correcta y está funcionando. De esta manera podemos revisar y corregir el contenido.
Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos.
Configurar y más información
podrías usar i18next.com para i18n-> viene con ayudante de manillar: i18next.com/pages/doc_templates.html
– jamuhl
18 de septiembre de 2012 a las 11:21
Nuevo ayudante de manillar para i18siguiente
– MortezaE
16 de julio a las 18:47