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 #713

Closed danmasta closed 7 years ago

danmasta commented 7 years ago

I'm seeing some inconsistencies with inheriting messages in globalize and I'm curious if this is a bug or if this is intentional.

We've been using globalize for a while, but came across an issue today when a package was attempting to load messages for en-US instead of just en.

Example: Load a message using the en-US locale

Globalize.loadMessages({ 'en-US': { 'common.legal.esrb.blood': 'Blood' }})

Attempting to retrieve the message for the en locale gives the following error: E_MISSING_MESSAGE_BUNDLE: Missing message bundle for locale 'en'.

Attempting to retrieve the message for the en-US locale gives the same error: E_MISSING_MESSAGE_BUNDLE: Missing message bundle for locale 'en-US'.

Why are en and en-US bundles missing?


However, based on this issue, if I add an empty bundle ahead of time like this:

Globalize.loadMessages({ 'en': {} });
Globalize.loadMessages({ 'en-US': {} });

The en-US locale works correctly and returns "Blood", but the en locale is still broken, with a different error message this time: E_MISSING_MESSAGE: Missing required message content 'common.legal.esrb.blood'.

Why do they both now have bundles, but en is still missing the message?


I then found this issue, where you recommend loading cldr json in it's most succint form. So I decided to try the same thing when loading json messages by first checking for the locale's cldr.attributes.minLanguageId.

By loading messages using a locale's cldr.attributes.minLanguageId, I was able to get both locales to work, but this seems like an odd workaround. I thought Globalize was supposed to handle language fallback, but it doesn't seem to work correctly all the time. Is this intentional? Can you help us understand what the recommended locale to load messages is?

Should we always load messages using the minimum language id?

rxaviers commented 7 years ago

Hi @danmasta, you did a good research. It works for me using the below code:

npm install globalize cldr-data
var Globalize = require( "globalize" );
Globalize.load( require( "cldr-data" ).entireSupplemental() ); // actually, you only need likelySubtags
Globalize.loadMessages({en: {'common.legal.esrb.blood': 'Blood'}})
Globalize('en').formatMessage('common.legal.esrb.blood')
// > 'Blood'
Globalize('en-US').formatMessage('common.legal.esrb.blood')
// > 'Blood'

Note en means en-US (actually it means: en has default content for en-US). More info here https://github.com/globalizejs/globalize#locales. More information about default content can be found here http://www.unicode.org/reports/tr35/tr35-info.html#Default_Content

rxaviers commented 7 years ago

Please, post new comments if you have any other questions.

It would be great if you could help improve the documentation to clarify the issues you faced.

danmasta commented 7 years ago

@rxaviers You're right, that example does work, but I was able to track the issue down further.

If you cache the globalize instances before using loadMessages, the bundle will be missing:

const Globalize = require('globalize');
const cldr = require('cldr-data');

Globalize.load(cldr.entireSupplemental());

// we cache the instances similar to this in our app
const en = Globalize('en');
const us = Globalize('en-US');

// notice we are loading messages for en-US
Globalize.loadMessages({'en-US': {'common.legal.esrb.blood': 'Blood'}});

en.formatMessage('common.legal.esrb.blood');
// > Error: E_MISSING_MESSAGE_BUNDLE: Missing message bundle for locale `en`.

us.formatMessage('common.legal.esrb.blood');
// > Error: E_MISSING_MESSAGE_BUNDLE: Missing message bundle for locale `en-US`.

However, if we change 1 line to load messages for en instead of en-US:

// notice we are now loading messages to en
Globalize.loadMessages({'en': {'common.legal.esrb.blood': 'Blood'}});

en.formatMessage('common.legal.esrb.blood');
// > Blood

us.formatMessage('common.legal.esrb.blood');
// > Blood

Then everything works fine.

It seems related to caching of the globalize instance. Any idea why that happens?

Also, thanks for the great package!

astewart commented 5 years ago

@rxaviers shouldn't then I be able to load en-US.

var Globalize = require("globalize");
var cldr = require("cldr-data");

Globalize.load(cldr.all());
Globalize.loadMessages({
  "en-US": { "common.legal.esrb.blood": "Blood" }
});
Globalize("en-US").formatMessage("common.legal.esrb.blood");

This gives the initial error from above: Error: E_MISSING_MESSAGE_BUNDLE: Missing message bundle for locale `en-US`.

rxaviers commented 5 years ago

@rxaviers shouldn't then I be able to load en-US.

Let's proceed with that in #852 👍