robisim74 / angular-l10n

Angular library to translate texts, dates and numbers
MIT License
380 stars 59 forks source link

locale.language always empty string after upgrade from Angular 9 -> 10 #321

Closed ThorstenKunz closed 3 years ago

ThorstenKunz commented 3 years ago

I have been using angular-l10n for a while and it works well. Now I am upgrading our project from Angular 9.0.5 to 10.2.4 and none of my l10n based pipes seem to work anymore. After some digging it looks like the constructor injection for the L10nLocale interface always return an object with the "language" field being set to an empty string value.

The angular-l10n package was upgraded from 9.1.0 to 10.1.2.

Here is the constructor injection into the controller constructor(@Inject(L10N_LOCALE) public locale: L10nLocale) { } and here is how I use it in the template {{ value | l10nNumber:locale.language:{ digits: '1.2-4', style: 'percent' } }}

I didn't change anything in the initialization or configuration and I could not find any migration guide for the 9.1 to 10.1 versions so I assumere there is nothing to do.

Any idea what I am missing here? Everything else in the application seems to work just fine after the migration work - only locale.language dependent things are breaking.

Thanks

robisim74 commented 3 years ago

Hi @ThorstenKunz,

no, there have been no changes in version 10, except dependencies and some fixes (SSR and routing).

First, try uninstalling and reinstalling the package (may be a dirty installation).

An empty locale.language should be possible only if the translation data are not loaded during the bootstrap of the app (in fact, it is evaluated and released only after a correct loading of the data). Try to add this log in your AppComponent and check for other errors:

this.translation.onChange().subscribe({:
    next: (locale: L10nLocale) => {
        console.log(locale);
        console.log(this.translation.data);
    }
});
this.translation.onError().subscribe({
    next: (error: any) => {
        if (error) console.log(error);
    }
});
ThorstenKunz commented 3 years ago

Man, that was VERY helpful! Thanks! Hooking into the onError() printed angular-l10n (L10nDefaultTranslationLoader): Asset not found.

What I don't get tho is why it doesn't use the defaultLocale if there are no assets for the locale requested by the browser? So lets say I have browser locale de but my assets don't have that defined. Usually that should then default to defaultLocale: { language: 'en', currency: 'USD' }, being put into L10nLocale but instead I get the above error and it is empty. Only if I add add de property to my assets configuration everything works. But I don't think adding all possible browser provided languages is feasible. Is there anything else besides defining a defaultLocale in L10nConfig in order to get the defaulting work as in 9?

Thanks again

robisim74 commented 3 years ago

Here you can see how the locale is determined: https://github.com/robisim74/angular-l10n/blob/master/projects/angular-l10n/src/lib/services/l10n-translation.service.ts#L129-L157

After trying routing & storage, it tries to get the browser language: if the locale is not in the schema property of the config, the default locale is used: the schema property should match the assets you actually have. The library, does not fallback to default locale if the asset is not found.

If you want to fallback, handle the error and set the default locale:

this.translation.onError().subscribe({
    next: (error: any) => {
        if (error) console.log(error);
        this.translation.setLocale(this.l10nConfig.defaultLocale);
    }
});

Or create you custom L10nTranslationFallback.

ThorstenKunz commented 3 years ago

btw: I am not using the translations functionalities but only the localization pipes (l10ndate, l10number, etc.) in my app. So I double checked and I do get the same Asset not found error on the working angular 9 version. But for some reason that doesn't affect the correct injection of locale: L10nLocale - which is really the only thing I care about. Only in 10 I get an empty locale.language injection in case of a missing asset property even if it is defined in the schema array.

robisim74 commented 3 years ago

Interesting: but if you're not using translations, just localization, just set the providers to an empty array in the config:

    providers: [
    ],
ThorstenKunz commented 3 years ago

Interesting: but if you're not using translations, just localization, just set the providers to an empty array in the config:

    providers: [
    ],

That works and is the cleanest solution for me. Thanks a lot!

So just FYI: if you define assets in providers array you have to provide an asset property for all entries in schema or else locale.language injection will be empty if you reuquest a language that is defined in schema array without a matching asset key. At least that is how it appears to me.