i18n-node
i18n-node copied to clipboard
Missing translations in handlebars when using blocks
In handlebar template when using blocks (each, with ...)
{{#each errors.currentPassword}}
<li>{{__ this}}</li>
{{/each}}
function getLocaleFromObject returns undefined instead of locale, which results in missing translation.
I think problem is in applyAPItoObject function. I have fixed it my binding i18n obj as this.
function applyAPItoObject(request, response) {
// attach to itself if not provided
var object = response || request;
api.forEach(function (method) {
// be kind rewind, or better not touch anything already exiting
if (!object[method]) {
i18n[method] = i18n[method].bind(i18n); // this is the fix
object[method] = function () {
return i18n[method].apply(request, arguments);
};
}
});
}
Helpers receive the current context as the this
context of the function.
// register hbs helpers
hbs.registerHelper('__', function () {
return i18n.__.apply(this, arguments);
});
hbs.registerHelper('__n', function () {
return i18n.__n.apply(this, arguments);
});
So that getLocaleFromObject(this)
will receive this
in {{__ this}}
as the current context. And this.locale
is undefined.
// called like __({phrase: "Hello", locale: "en"})
if (typeof phrase === 'object') {
if (typeof phrase.locale === 'string' && typeof phrase.phrase === 'string') {
msg = translate(phrase.locale, phrase.phrase);
}
}
// called like __("Hello")
else {
// get translated message with locale from scope (deprecated) or object
msg = translate(getLocaleFromObject(this), phrase);
}
That's the problem. And here is the solution.
// set default locale
app.locals.locale = 'en';
// register hbs helpers that still receive the current context as the `this`, but `i18n.__` will take `app.locals` as the `this`
hbs.registerHelper('__', function () {
return i18n.__.apply(app.locals, arguments);
});
hbs.registerHelper('__n', function () {
return i18n.__n.apply(app.locals, arguments);
});
You could change app.locals.locale
in a route.
app.all('/?*', function (req, res, next) {
res.app.locals.locale = 'vi';
next();
});
@lamnn1807, setting an app.locals.locale
would override the locale in all routes.
I found out that since the locale is always present in the root
object, you could pass it on when not present in this
context.
handlebars.registerHelper('__', function(string, options){
// supplement locale for block helpers
this.locale = this.locale || options.data.root.locale;
return i18n.__.apply(this, arguments);
});
handlebars.registerHelper('__n', function (string, options) {
// supplement locale for block helpers
this.locale = this.locale || options.data.root.locale;
return i18n.__n.apply(this, arguments);
});
Note to myself: we need more examples covering best practices for loooot's of template engines
been recently using @root
{{#each errors.currentPassword}}
<li>{{@root.__this}}</li>
{{/each}}
Is there any chance that the fix above by @r0hitsharma could be integrated into the latest version? It's easy enough to use as a workaround, but having to include it in every single Handlebars helper is far less efficient than including it once in the base library.