Question

I have a bunch of controllers, with some properties generated with a translation library:

App.CallsStatusTotalsPerHourChartController = Ember.ArrayController.extend({
    title: Ember.I18n.t('dashboard.calls-per-hour.title'),
    subTitle: Ember.I18n.t('dashboard.calls-per-hour.subtitle'),
    noDataText: Ember.I18n.t('dashboard.calls-per-hour.no-data'),
    content: []
});

The problem is that the language file is not yet loaded (it takes some time), so at definition time, Ember.I18n.t has no data, and all translations are failing. There are several solutions to this, but the one which seems simpler to me is the following:

Instead of calling Ember.I18n.t directly, I would called a delayedT, which would be based on a property:

function delayedT(key) {
    return property depending on App.languageLoaded, to do Ember.I18n.t(key)
}

This property will be computed whenever an application flag is set: App.languageLoaded. Whenever the language file has finished loading, I would do App.set('languageLoaded', true) and that would fire all translations. This way translations would be performed only once for the application, at the right time (when the language data has arrived).

Does that make sense at all? How would I implement delayedT?

Was it helpful?

Solution

First, I would recommend not setting properties on the App global.

Overall, you could solve this by creating computed properties that invalidate when the language is loaded.

Here is some untested code to illustrate the approach. Create a Translator class:

App.Translator = Ember.Object.extend({
  languageLoaded: false,
  translate: function(key){
    if (this.get('languageLoaded')) {
      return Ember.I18n.t(key);
    }
  }
});

Register it as a singleton, and inject it onto controllers:

Ember.Application.initializer({
    name: 'setup translation',
    initialize: function(container, application) {
        application.register('translator:main', App.Translator);
        container.injection('controller', 'translator', 'translator:main');
    }
});

Then in your controller, you can have a property that is dependent on the languageLoaded property (so when languageLoaded becomes true, it will invalidate and re-run:

App.CallsStatusTotalsPerHourChartController = Ember.ArrayController.extend({
  title: function(){
    return this.get('translator').translate('dashboard.calls-per-hour.title');
  }.property('translator.languageLoaded'),
});

You can shorten this with a macro:

function t(key){
  return function(){
    return this.get('translator').translate(key);
  }.property('translator.languageLoaded')
}

App.CallsStatusTotalsPerHourChartController = Ember.ArrayController.extend({
  title: t('dashboard.calls-per-hour.title'),
  subTitle: t('dashboard.calls-per-hour. subtitle'),
  noDataText: t('dashboard.calls-per-hour.no-data'),
  content: []
});

When your language becomes loaded, don't forget to lookup the translator and set the boolean:

// yippee, my language finally loaded
Ember.run(function(){
  this.container.lookup('translator:main').set('languageLoaded', true);
});

There are ways to use promises in here if you really want, but I probably wouldn't bother.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top