Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite translation "resolver" logic #67

Closed
jasonmit opened this issue Mar 10, 2015 · 5 comments
Closed

Rewrite translation "resolver" logic #67

jasonmit opened this issue Mar 10, 2015 · 5 comments

Comments

@jasonmit
Copy link
Member

So the end user's locale is pt-MZ. The app has strings for pt-PTand the default en. So what I think could happen at request/init time the user's locale is resolved into one which the app supports, in this case the process would be:

  1. Does the app support pt-MZ? No.
  2. What's the parent? pt-PT.
  3. Does the app support pt-PT? Yes!

So now the app executes with pt-PT as the resolved locale, and always with en as the fallback. So if someNewMessage string hasn't been translated to pt-PT yet, the default one, en is used instead.

this.intl.set('locales', ['pt-MZ', 'en']); will result in a resolvedLocales computed property (readOnly and private) to become ['pt-PT', 'en']

This will require the CLDR extracter to pull out the parent locale information for all the locales that are not targeted from the application.

Copy/pasting from a conversation I had with @ericf

The end goal, we can support this.intl.set('locales', [navigator.language, defaultLocale]) in its various fallback scenarios based on the information the CLDR data provides.

@ericf
Copy link

ericf commented Mar 14, 2015

The end goal, we can support this.intl.set('locales', [navigator.language, defaultLocale]) in its various fallback scenarios based on the information the CLDR data provides.

So there's three concepts here that seem to be mixed into single set() line:

  1. What are the app's available locales? (i.e. What does it have translations for?)
  2. What's the app's default locale?
  3. What's the user's desired locales? (possibly more than one)
  4. What locale is the app running in?

At build time we have answers to 1 and 2. At runtime our goal is to compute the value for 4. To do that we take the user's desired locales (3) and try resolve a match with one of the app's available locales (1). If a match is found that should become this.intl.set('locale', resolvedLocale). If no match was found, we fallback to the app's default locale (2).

Now when it's time to format a translated message, Ember Intl has a pragmatic feature that recognizes that any non-default locale's translations might be incomplete and missing translations for some new messages. — This is just a reality as translations are an async process which costs money and is done by people who are usually different than those writing the app's JS code. — To handle missing messages for the locale (4) the app is running it, it can fallback to using the message from the default locale (2).

There are two main ways this missing-translation-fallback feature can work:

  • The app is loaded with both the default locale translations (2), and the resolved locale translations (4).
  • This can be a build task which merges each of the app's available locales' translations (1) with the default locale's translations (2).

Is the built-time approach possible to do in Ember Intl? If so, that might be the desired option. If it's not practical to do, then the other approach could be implemented but maybe lazily to only load the default locale's translations if a missing message happens to be encountered.

@jasonmit
Copy link
Member Author

Is the built-time approach possible to do in Ember Intl? If so, that might be the desired option. If it's not practical to do, then the other approach could be implemented but maybe lazily to only load the default locale's translations if a missing message happens to be encountered.

Basically merge the default locale translations into all of the locale translations? If so, I've tried something similar in the past and ran into an issue where ember-cli addons can not manipulate files on the app tree, where the translations are currently. Essentially the app tree is merged last so anything that I do to the app tree within the addon doesn't stick.

I think eventually, we'll need to move away from the translations hanging on the app tree. The new structure will look like the following, and be more conducive to lazy loading strategies versus bundling everything into one large app.js:

/
 - /app
 - /translations
 - /cldrs
 - /vendor
 etc.

Once I implement this new structure, then implementing your proposal above sounds like the best solution 👍

@jasonmit
Copy link
Member Author

This can be a build task which merges each of the app's available locales' translations (1) with the default locale's translations (2).

@ericf @caridy I began to implement this and realized there is an issue with this approach. We need a way of marking the translations that were missing and merged in as come from the default locale. Otherwise, we'll be passing the wrong locale through to mf.

en, default

{
  "greeting": "hello",
  "photos": "{name} took {numPhotos, plural, =0 {no photos} =1 {one photo} other {# photos}} on {takenDate, date, long}." 
}

fr-fr

{
  "greeting": "bonjour" 
}

The result after merge for french is now:

{
  "greeting": "bonjour",
  "photos": "{name} took {numPhotos, plural, =0 {no photos} =1 {one photo} other {# photos}} on {takenDate, date, long}." 
}

Assume the app locale is french at runtime {{format-message (intl-get 'photos')}} will now use the wrong plural function, fr-fr, instead of en.

Proposed Solution

Implement some convention into the merging strategy to hang an additional object off the translation for translations that were merged in and the translation lookup will additionally check this object while trying to resolve a translation key.

fr-fr after merge will look like:

{
  "greeting": "bonjour",
  "_default": {
    "photos": "{name} took {numPhotos, plural, =0 {no photos} =1 {one photo} other {# photos}} on {takenDate, date, long}."
  }
}

Worth mentioning, the merged results are never written to the sourced translation files. These are only ever written to the build directory.

I also was planning to throw console warnings at build time for all translations that were merged in.

@jasonmit
Copy link
Member Author

Ping @ericf since we were going to discuss and never did

@vvohra
Copy link
Contributor

vvohra commented Mar 24, 2017

I just realized the issue talked about in two comments ago is happening and I wasn't really sure how to solve it either.

I'm not sure how big of an issue it is.
In the worst case scenario: there is a language that doesn't use one OR other and no part of the translation show up! But I don't think there is a language like this when glancing through the plural rules.

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

No branches or pull requests

3 participants