1

I'm trying to achieve asynchronous fetching of translations. I set up the publicOnly to true as docs say:

// config/ember-intl.js
module.exports = function() {
  return {
    publicOnly: true
  }
};

Skipped the step of setting up the locales key, because translations are stored in /translations folder.

Next, I should modify beforeModel hook to asynchronously fetch the translations, and that's where docs are pretty vague:

// app/routes/application.js
export default Ember.Route.extend({
  intl: Ember.inject.service(),
  async beforeModel() {
    let translations = await fetch('/api/translations.json');
    this.get('intl').addTranslations('en-us', translations);
    this.get('intl').setLocale('en-us');
  }
});

How these lines supposed to work:

let translations = await fetch('/api/translations.json');
this.get('intl').addTranslations('en-us', translations);

In runtime I have no translations.json file anywhere in the dist folder. I've got dist/translations/en-us.json only for my one and only translation and no clue how to make it work.

Service API misses documentation of addTranslations method.

Would appreciate any help.

NullVoxPopuli
  • 61,906
  • 73
  • 206
  • 352
Ivan C.
  • 33
  • 3

2 Answers2

2

This is what I was using back when I was doing async translations (and I may bring this back as my application grows)

This is in services/intl.ts

import IntlService from 'ember-intl/services/intl';
import fetch from 'fetch';

import config from 'emberclear/config/environment';

export default class EmberClearIntl extends IntlService {
  async loadTranslations(locale: string) {
    let response = await fetch(`${config.hostUrl}/translations/${locale}.json`);
    let translations = await response.json();

    this.addTranslations(locale, translations);
  }

  lookup(key: string, localeName: string, options: any = {}) {
    const localeNames = this.localeWithDefault(localeName);
    const translation = this._adapter.lookup(localeNames, key);

    if (!options.resilient && translation === undefined) {
      const missingMessage = this._owner.resolveRegistration('util:intl/missing-message');

      return missingMessage.call(this, key, [localeNames]);
    }

    return translation;
  }
};

I believe it's inspired by one of the github issues on the ember-intl repository, and I modified it to work with my setup. (like, the config.hostUrl stuff -- this is just set to my domain at the moment, but it may be handy if your site isn't deployed at the root of your domain).

Usage in my application route:

import Route from '@ember/routing/route';
import { service } from '@ember-decorators/service';

import EmberClearIntl from 'emberclear/services/intl';

export default class ApplicationRoute extends Route {
  @service intl!: EmberClearIntl;

  async beforeModel() {
    const locale = 'en-us';

    await this.intl.loadTranslations(locale);

    this.intl.setLocale(locale);
  }
}

Something I haven't yet figured out is how to best manage async translations with a progressive web app. In the current version of my app, I've removed the async behavior and just bundle the translation file (just one) with my app.

NullVoxPopuli
  • 61,906
  • 73
  • 206
  • 352
  • 1
    Hey thanks for sharing! Shame that there is no clear explanation for async translations in docs. I assume that this should be the most common case of using. Why would anyone want to put all the translations (I have 10+) in the app bundle, bloating its size. Anyway I'll come back to this later. – Ivan C. Aug 20 '18 at 08:16
  • 1
    Yeah, if you end up finding a pattern you like, maybe it'd be worth submitting a PR for some documentation to the ember-intl repo? – NullVoxPopuli Aug 20 '18 at 09:34
  • 1
    Good point. I think the lack of clear docs on ember-intl is still due to usage of ember-i18n (mostly). ember-i18n is on its way to deprecation tho. – Ivan C. Aug 20 '18 at 12:32
0

You're right that the Docs aren't clear - the response object isn't the JSON itself. Change the path for the fetch and add translations.json() instead of just translations:

// app/routes/application.js
export default Ember.Route.extend({
  intl: service(),
  async beforeModel() {
    let translations = await fetch('/translations/en-us.json');
    this.intl.addTranslations('en-us', translations.json());
    this.intl.setLocale('en-us');
  }
});