Skip to content
This repository has been archived by the owner on Apr 18, 2023. It is now read-only.

Add support for translation fallback #256

Closed
jcbvm opened this issue Jun 24, 2015 · 21 comments
Closed

Add support for translation fallback #256

jcbvm opened this issue Jun 24, 2015 · 21 comments

Comments

@jcbvm
Copy link
Contributor

jcbvm commented Jun 24, 2015

Problem

Currently if a user has multiple locale translations defined, it has to define every translation key for each locale, even if some translations may be the same in a locale chain (i.e. en_US -> en).

Goal

Add the ability to omit translations keys in translations which are or may be defined in other translations files within the same locale chain.

Proposal

When a translation is being looked up via t('somekey') and the result is undefined, we need to track down if the translation is defined in one of the other translations in the current locale chain. This means that we have to lookup the current locale chain and see if there exists a translation in one of the parent locales (i.e. when a translation is not defined in 'en_US', we have to look if the translation exists in 'en', if so we return that translation).

Some key notes:

  • Fallback will occur on a string-by-string basis and not if the whole locale is undefined. This way we can omit only certain translation keys.
  • When we walk the chain, undefined locales should be skipped.
  • When we walked the whole chain and could not find the translation, the current default behavior of an undefined translation should be applied.

Considerations

It would be possible to let the defaultLocale be the endpoint of the chain, so if the translation cannot be found in the current locale chain, we will finally fallback to the defaultLocale. I'm not sure yet if this is desirable.

If there are plans to implement this, the defaultLocale defined in the ENV config should be stored and never be changed when setting the locale property.

Alternative Approach

An alternative approach would be to merge all translations within one locale chain. This requires to merge translations when initializing the translations and also when new translations are being added via addTranslations.

Some key notes:

  • The order is important, a more specific locale should overwrite translations of a less specific locale.

Drawbacks:

  • It is less efficient, because we have to rebuild the whole translation object when new locales are added, especially when adding a locale in the middle of the current locale chain.
@jamesarosen
Copy link
Owner

Would you mind writing this up more fully in RFC format? Some questions you might want to address:

  • Under what conditions could the user get into a state where the app is asking for translations in a locale that it (the app) doesn't define?
  • Would there be only one fallback or a chain?
  • How would fallbacks (e.g. nl -> en) work with locale variants (e.g. en-US -> en)?
  • Would fallback occur on a string-by-string basis or only if the whole locale is undefined?
  • How would this work with the multiple packages proposal?

@jcbvm jcbvm changed the title Add support for fallback locale Add support for translation fallback Jun 24, 2015
@jamesarosen
Copy link
Owner

Add the ability to omit translations keys in translations which are or may be defined in other translations files within the same locale chain.

t already does fallback within a Language Tag (e.g. en-US -> en). See this test.

I thought this was about having a locale outside that Language Tag at the root (e.g. es-ES -> es -> en).

@jcbvm
Copy link
Contributor Author

jcbvm commented Jul 1, 2015

Ah, I totally missed the point that t already supports the fallback. My first intention indeed was to support a language outside the chain. In my current project for example 'en' is the fallback no matter which language is used. I'm not sure though if support for this is needed in ember-i18n. If you think it would be nice I will change the descr. above.

@jamesarosen
Copy link
Owner

I'm going to make sure the docs clearly say that fallbacks within the language tag are supported.

@jamesarosen
Copy link
Owner

@jamesarosen
Copy link
Owner

If that's all you needed, feel free to close this issue. If you still want to pursue letting an app put an arbitrary locale at the root of the chain, I'd love to hear more. #262 may be relevant to that discussion.

@franzliedke
Copy link

I would certainly love to have that functionality. I sometimes have to wait for the Chinese translations to our app, and would prefer to simply have a fallback functionality in these cases.

@jcbvm
Copy link
Contributor Author

jcbvm commented Jul 2, 2015

Alright I will update the issue description than.

@baskarsugumar
Copy link

Yes I too have a same requirement as @franzliedke, even in our case, we have a default locale to override the keys if the same is missing in other language is missing. That is, lets have two different languages say A and B. And out which A is set to be default language. Now the user logs in to the system and has B as his language and in a page there seems to be a key which does not present in B and for the same need to return the value from the default language. considering the default translation file will have all the keys

@jamesarosen
Copy link
Owner

Given the current implementation, which limits translations to a single object per locale (e.g. app/locales/es/translations.js), you could implement this as merging the "foreign" translations onto the "default" ones?

Let's assume you develop in English and that locale file is always fully populated. You could then do

// app/locales/es/translations.js:

import Ember from "ember";
import en from "../en/translations";

export default Ember.merge(Ember.copy(en), {
  "some.string": "Spanish override"
});

That way, es/translations would start with en/translations and override as your translators filled it out.

Of course, RFC #255 complicates that since it proposes multiple files per locale.

@sandstrom
Copy link
Contributor

Being able to specify fallback languages would be great! We're currently using the work-around you suggested (thanks James!), but native support for de -> en (an example) would be good.

(related, having an event fired when fallback was triggered would make it easy to get notified about missing translations, while still showing something useful to the end-user)

@Turbo87
Copy link
Contributor

Turbo87 commented Feb 15, 2016

👍 for this. I was quite surprised that it didn't do fallback out of the box yet, especially because you're supposed to set defaultLocale in the config.

@jamesarosen
Copy link
Owner

This will likely be among the next things I work on for this project, but I don't know when that will be.

@sbsurf
Copy link

sbsurf commented Jun 2, 2016

+1

@nwhittaker
Copy link

Under what conditions could the user get into a state where the app is asking for translations in a locale that it (the app) doesn't define?

Resolving the locale via navigator.language is, for me, an easy way to fall into this state.

Java has the concept of a root locale. Maybe adopting something similar would simplify the fallback chain and remain unopinionated about what the default locale should be?

@jamesarosen
Copy link
Owner

Resolving the locale via navigator.language

I definitely recommend trying navigator.languages, in order. In fact, I recommend that so much I might add it to the library.

@sandstrom
Copy link
Contributor

sandstrom commented Aug 22, 2016

For anyone with this issue, you can patch something together with missing-message:

// FILE AT app/utils/i18n/missing-message.js
//
// NOTE if ember-i18n add support for fallback locales we won't need this
// https://github.com/jamesarosen/ember-i18n/issues/256

import Ember from 'ember';
import Locale from 'ember-i18n/utils/locale';

const FALLBACK_LOCALE = 'en';

let missingMessage = function(locale, key, data) {
  if (locale === FALLBACK_LOCALE || window.env === 'development') {
    return `Missing translation: ${key}`;
  } else {
    // NOTE This relies on internal APIs and is brittle.
    // Emulating the internals of ember-i18n's translate method.
    let i18n = this;

    let count = Ember.get(data, 'count');

    let defaults = Ember.makeArray(Ember.get(data, 'default'));
    defaults.unshift(key);

    let localeObj = new Locale(FALLBACK_LOCALE, Ember.getOwner(i18n));
    let template = localeObj.getCompiledTemplate(defaults, count);
    return template(data); // english fallback
  }
};

export default missingMessage;

@max-konin
Copy link

@sandstrom, a small fix of your patch:

// FILE AT app/utils/i18n/missing-message.js
//
// NOTE if ember-i18n add support for fallback locales we won't need this
// https://github.com/jamesarosen/ember-i18n/issues/256

import Ember from 'ember';
import Locale from 'ember-i18n/utils/locale';

const FALLBACK_LOCALE = 'en';

let missingMessage = function(locale, key, data) {
  if (locale === FALLBACK_LOCALE || window.env === 'development') {
    return `Missing translation: ${key}`;
  } else {
    // NOTE This relies on internal APIs and is brittle.
    // Emulating the internals of ember-i18n's translate method.
    let i18n = this;

    let count = Ember.get(data, 'count');

    let defaults = Ember.makeArray(Ember.get(data, 'default'));
    defaults.unshift(key);

    let localeObj = new Locale(FALLBACK_LOCALE, Ember.getOwner(i18n));
    let template = localeObj.getCompiledTemplate(defaults, count);
    return template(data); // english fallback
  }
};

export default missingMessage;

Without imports I have error: Ember/Locale is undefined

@mohanyin
Copy link

@sandstrom thanks for the patch!

@jamesarosen any updates on this issue? I'm willing to take a stab at building it into the library if nothing's already been started.

@sandstrom
Copy link
Contributor

@mohanyin afaik nothing has been started, feel free to make a stab at it 😄

@jamesarosen
Copy link
Owner

jamesarosen/ember-i18n has been deprecated in favor of ember-intl.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants