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

Allow overriding the locale for individual translations #312

Closed
wants to merge 1 commit into from
Closed

Allow overriding the locale for individual translations #312

wants to merge 1 commit into from

Conversation

digitalcora
Copy link
Contributor

I had some free time, so here is my initial stab at #298. I couldn't find a way to stub the ENV value so I could test that it's correctly loaded into the service, but I manually confirmed that it works.

(this.get('allowLocaleOverride') !== undefined),
{ id: 'ember-i18n.locale-override' }
);
locale = new Locale(data.locale, this.container);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part seems inefficient, but addressing it would probably require a larger change (for instance, locales could be cached on the service when they are initialized).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. we only want to warn if data.locale is defined
  2. we can make it slightly more efficient by saving off the warning text as a const at the top of the file
  3. we could cache Locales in a closure-local map in the locale.js file and use the fact that returning an object from a constructor aborts the construction:
const seenLocales = {};

function Locale(name, container) {
  if (seenLocales[name]) { return seenLocales[name]; }
  seenLocales[name] = this;
  ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we only want to warn if data.locale is defined

This is inside the if (data.locale && ...) so the warning should only be seen in that case.

we could cache Locales in a closure-local map in the locale.js file

Clever! I will see if this works.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is inside the if (data.locale && ...)

d'oh

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though I can't help thinking that from the outside, it's very counter-intuitive that new Locale only really constructs a new locale the first time it's called with a given argument, and thereafter just returns the previously-constructed object. At that point it's really more like a lazily-populated hash. Maybe a "locales" service or something?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That file is private, so we can change its API. We can change the exported function to localeFor(name, container), which uses the map and the Locale constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like a good simple solution, I will try going in that direction.

@digitalcora
Copy link
Contributor Author

@jamesarosen I tried changing things to use your localeFor-style proposal, but that caused test failures related to adding translations at runtime. Strangely, using your originally proposed approach (returning from the constructor) does work.

I've addressed the outstanding feedback and rebased. The .string issue seems to have mysteriously disappeared... so I guess this should be good to go.

@digitalcora
Copy link
Contributor Author

@jamesarosen Any further changes needed? Could this be merged and released? (I guess it should have a changelog entry, I could write that if you like)

@digitalcora
Copy link
Contributor Author

When testing this in my app, I discovered a need to find whether a given translation exists in another locale. So I extracted _getLocaleWithOverride and applied it to exists as well. Not sure what's up with the test failures on Travis – I don't get them locally, and they seem unrelated to my changes.

@@ -13,6 +15,10 @@ export default class Locale {
// 3. Default `rtl` to `false`
// 4. Ensure `pluralForm` is defined
constructor(id, container) {
if (initializedLocales[id]) {
return initializedLocales[id];
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You never populate initializedLocales with this after the if.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argh. You're completely right. Unfortunately, actually doing this causes adding translations at runtime to stop working. So I guess this method of caching won't work after all. I'm really not sure how to handle this correctly, the architecture is hard for me to follow... should I just take it out for now? I can personally live with the sub-optimal performance, since my use case is not very intensive (this may be a case of premature optimization).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you try removing the if around locale.rebuild() in addTranslations?

I think we need to do some substantial re-architecting anyway to support #255. Probably best to think about the two problems together.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tried that, but the test for adding translations at runtime still fails.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I'll give #255 a shot first. I may try moving some of the addTranslations logic into Locale so the I18nService doesn't have to worry about state management.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright. For now I'll proceed with using this branch in my app, since it seems stable and I haven't noticed any performance hits (I have a small number of translations, and the cross-locale lookup is only performed once on page load). I will keep an eye on that task.

@digitalcora
Copy link
Contributor Author

@jamesarosen I've resolved conflicts with current master and removed the defunct attempt at caching. How would you like to handle this? Should it still wait on #255? Can it be merged with a potential caveat about performance? (I've been using this in production for a month now and haven't seen any breaking issues with it, but also haven't examined performance too closely)

@jamesarosen
Copy link
Owner

Sorry I've let this sit so long. I want to work on #255 very soon. I'll try to eke out some time this week. Once I have a better picture of that work, I'll let you know what we should do with this. I definitely want either this code or this idea in the project.

@digitalcora
Copy link
Contributor Author

Rebased this on v4.2.0 to resolve conflicts. @jamesarosen how's it going? 😃

@jamesarosen
Copy link
Owner

I'm hoping to do some of this heavier work over the break right before the new year. I'll keep you updated.

@digitalcora
Copy link
Contributor Author

Hi @jamesarosen, just want to confirm whether this is still slated to be merged at some point. In our limited use case we've had no problems with it, and have been using it in production since October – but we don't want to maintain a fork of ember-i18n indefinitely.

Of course, I'd be happy to write a changelog entry and wiki documentation for this feature, or any other friction-reducing tasks that would help.

@jamesarosen
Copy link
Owner

There's not much movement on ember-i18n these days because I'm working on a release for another project right now. But after that release will be some I18n work, which will be a perfect time to pick this up again.

Thanks for testing it out!

@sbsurf
Copy link

sbsurf commented Jun 2, 2016

This would definitely be useful. I could use this as a way to inject missing translation fallbacks, while overriding the missingMessage function to just return the english translation.

@sandstrom
Copy link
Contributor

sandstrom commented Aug 23, 2016

@jamesarosen This would be a wonderful addition! ⛵

Is there anything in particular holding this PR back? (except the failing build 😄 )

@sandstrom
Copy link
Contributor

sandstrom commented Aug 23, 2016

@Grantovich Great initiative!

What do you think about this:

this.trigger('missing', this.get('locale'), key, data); // current
this.trigger('missing', locale.id, key, data); // my suggestion

Otherwise the missing message will trigger with the wrong locale, no?

source:

this.trigger('missing', this.get('locale'), key, data);

@digitalcora
Copy link
Contributor Author

@sandstrom Thanks for the catch – I haven't been keeping this up-to-date lately since it seems there isn't much interest in merging it, and our project that uses this fork is in maintenance mode. If @jamesarosen gives the go-ahead, I would be happy to revisit it.

(tagging @jasonmit since from #381 (comment) it looks like we might be duplicating some effort)

@jpsirois
Copy link

jpsirois commented Dec 6, 2017

I just had this exact same need for a project. And I extended the i18n services with the changes from this PR and it just work. Is this something still in consideration? I think this PR is worth consideration.

@sandstrom
Copy link
Contributor

friendly ping @jamesarosen 😄

@jamesarosen
Copy link
Owner

I don't have any objections. I'd love one of the other maintainers to take a look and help shepherd this.

@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

Successfully merging this pull request may close these issues.

6 participants