i18n-node icon indicating copy to clipboard operation
i18n-node copied to clipboard

Missing translations in handlebars when using blocks

Open mauron85 opened this issue 10 years ago • 5 comments

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);
      };
    }
  });
}

mauron85 avatar Jul 31 '14 21:07 mauron85

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 avatar Aug 15 '14 06:08 lamnn1807

@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);
});

r0hitsharma avatar Jan 19 '16 15:01 r0hitsharma

Note to myself: we need more examples covering best practices for loooot's of template engines

mashpie avatar Jan 31 '16 19:01 mashpie

been recently using @root

{{#each errors.currentPassword}}
<li>{{@root.__this}}</li>
{{/each}}

mashpie avatar Aug 15 '20 17:08 mashpie

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.

delfuego avatar Jun 01 '23 01:06 delfuego