globalizejs / globalize

A JavaScript library for internationalization and localization that leverages the official Unicode CLDR JSON data
https://globalizejs.com
MIT License
4.8k stars 603 forks source link

Message inheritance #791

Closed HarryBurns closed 6 years ago

HarryBurns commented 6 years ago

Hi there!

Feature request for message inheritance.

In this help article (https://github.com/globalizejs/globalize/blob/master/doc/api/message/load-messages.md#messages-inheritance) I see an information about "Message inheritance", but I can't find how to get inheritance chain for the particular locale. Could you please add method that will return array of fallback locales for particular locale?

For example, for "uz-Cyrl-UZ" locale this array should be ["uz-Cyrl-UZ", "uz-Cyrl", "uz"].

I need this to load JSON files not only for selected locale but also for locales, that Globalize.js using as fallbacks.

And it will be great if I will be able to customize the inheritance chain. For example, I need to inherit it in that order: 1) My locale ("uz-Cyrl-UZ") 2) Fallbacks of my locale ("uz-Cyrl", "uz") 3) Default locale ("en-GB") 4) Fallbacks of default locale ("en") 5) Root locale for untranslated strings ("root").

Of course, I can do it manually by the function below.

  function translate(message) {
    const localeAndFallbacks = [`uz-Cyrl-UZ`, `uz-Cyrl`, `uz`, `en-US`, `en`, `root`];

    for (let i = 0; i < localeAndFallbacks.length; i++) {
      try {
        return Globalize(localeAndFallbacks[i]).formatMessage(message);
      } catch (ex) {} // continue
    }
  }

But can I be sure that GLobalize will not use fallbacks if I will not include cldr/unresolved.js file?

rxaviers commented 6 years ago

But can I be sure that GLobalize will not use fallbacks if I will not include cldr/unresolved.js file?

Yes.

For example, for "uz-Cyrl-UZ" locale this array should be ["uz-Cyrl-UZ", "uz-Cyrl", "uz"].

Only assuming the initial bundle is "uz-Cyrl-UZ" and there's no parent lookup, i.e., only truncate lookup.

Could you please add method that will return array of fallback locales for particular locale?

Yes, can you elaborate a proposal in terms of API?

HarryBurns commented 6 years ago

Actually, I don't know, because I need this only for messages subsystem, not for calendars, dates and other CLDR stuff. And I think it should work in a different way for messages translation and other CLDR stuff. For messages, it will be great to have the ability to customize fallback sequence.

Maybe something like that:

Globalize().formatMessage([`uz-Cyrl-UZ`, `uz-Cyrl`, `uz`, `en-US`, `en`, `root`], "translation-key", args);

But now I implemented fallbacks in my own code, and it works great.

The only bad thing is that Globalize("mylocale").formatMessage throw an exception if there is no such message translation. It's really slow. Why don't you return undefined instead?

rxaviers commented 6 years ago
Globalize().formatMessage([`uz-Cyrl-UZ`, `uz-Cyrl`, `uz`, `en-US`, `en`, `root`], "translation-key", args);

If you need customized fallback sequences, you can make such changes in supplemental/parentLocales.json and Globalize will follow your new rules. I am hesitant in including this adhoc signature to formatMessage.

The only bad thing is that Globalize("mylocale").formatMessage throw an exception if there is no such message translation. It's really slow. Why don't you return undefined instead?

To make it easier to spot these issues during development. It's expected you have translations for the keys you're using (including fallbacks). For the speed part, have you used the precompiled formatters + runtime code?

Closing this issue until we have any action item here.

HarryBurns commented 6 years ago

For the speed part, have you used the precompiled formatters + runtime code?

No, because I have an SPA with support of ~200 locales (with dynamic change) and I can't just generate formatters for each of them. I load it in dynamic. And the user can select any locale he wants. But there are two problems here:

1) User selected en-US locale. And I try to load en-US locale from CLDR, but there is no such locale in CLDR (only en). So I need to load some locale that CLDR will use as fallback of en-US. And I want to get that locale.

2) User selected en-US locale, and I load messages translations from en-US.json file (for example). But if there is no such file - I use 'en' fallback. This part I made with my own code because here I need my own fallback sequence. And this custom fallback sequence I need only there.

rxaviers commented 6 years ago

Considering this is a backend service, you could load CLDR and messages for all locales and create globalize instances on demand. Globalize will do the inheritance for you, for example, considering you load CLDR using en bundle, you can create globalize instances using en, en-US, en-Latn-US, that all of these are going to use the correct en data. Similar for messages.