robisim74/angular-l10n

Browser language is not set correctly

Closed this issue · 4 comments

Hi Roberto,

We just updated our app to Angular v9 and we updated your library after that and we got it to work, except for setting the browser language. We support multipe languages, but setting the browser to en-GB and loading the app it defaults back to en-US (default locale). If I set the browser to nl-NL it works fine and it loads the dutch translations in the initial load. (Changing languages after the initial load works fine).

In the docs I have seen the L10nUserLanguage class-interface, but I don't want the user-language loaded from the server. So I'm not sure if I can/have to use that.

I have also tried it in your angular-l10n-app but it didn't work their either. The only changes I made in your app are the following:

l10n-config.ts:

export const l10nConfig: L10nConfig = {
    format: 'language-region',
    providers: [
        { name: 'app', asset: './assets/i18n/app', options: { version: '9.0.0' } }
    ],
    fallback: false,
    cache: true,
    keySeparator: '.',
    defaultLocale: { language: 'en-US', currency: 'USD', timeZone: 'America/Los_Angeles' },
    schema: [
        { locale: { language: 'en-US', currency: 'USD', timeZone: 'America/Los_Angeles' }, dir: 'ltr', text: 'United States' },
        *{ locale: { language: 'en-GB', currency: 'GBP', timeZone: 'Europe/London' }, dir: 'ltr', text: 'United Kingdom' },*
        { locale: { language: 'it-IT', currency: 'EUR', timeZone: 'Europe/Rome' }, dir: 'ltr', text: 'Italia' }
    ],
    defaultRouting: true
};

And I added the app-en-GB.json and the lazy-en-GB.json files to the i18n folder.

I then run the app using the ng serve -o command. The app loads in the broswer, but it defaults back to en-US and when I click the United Kindom button it correctly loads the en-GB file.

Hopefully you can help me figure this out.
Kind Regards

The behavior of the browser language has not changed in the new version: when you use a language-region format, during the first load the library tries to take the language:

  • from the link (if any)
  • then in the storage (if any)
  • finally the default

That's because getBrowserLanguage method takes only the first part (the language), since not all browsers return the region:

export function getBrowserLanguage(): string | null {
let browserLanguage = null;
if (navigator !== undefined && navigator.language) {
browserLanguage = navigator.language;
}
if (browserLanguage != null) {
browserLanguage = browserLanguage.split('-')[0];
}
return browserLanguage;
}

You can change the way the browser language is obtained by implementing L10nUserLanguage
class-interface: https://robisim74.github.io/angular-l10n/injectables/L10nUserLanguage.html#source

Thank you for your quick response.

It is still not clear to me how the getBrowserLanguage method get's into play based on the bullets you provided. (but maybe that's not really important)

I'm now trying to implement the get method from the L10nnUserLanguage but so far without success. Hopefully you can point me in the right direction. What I'm trying to do is the following

app.component.ts

export class AppComponent implements OnInit, L10nUserLanguage {
  constructor(
    @Inject(L10N_LOCALE) public locale: L10nLocale,
    private _translation: L10nTranslationService
  ) { }

  ngOnInit(): void {
   ...
  }

  get(): Promise<string> {
    return Promise.resolve('nl');
  }

  setLocale(locale: L10nLocale): void {
    this._translation.setLocale(locale);
  }
}

for now I'm tryig to return a static language code that we support, but the locale is still set to en-US (default). If and when I get that working I can apply my own logic to get the language.

For completion I'll include our l10n-config.ts

export const l10nConfig: L10nConfig = {
  format: 'language-region',
  providers: [
    { name: 'app', asset: '/shared-files-output/locale', options: { version: '9.1.0' } }
  ],
  fallback: true,
  cache: true,
  keySeparator: '.',
  defaultLocale: { language: 'en-US', currency: 'USD', timeZone: 'America/Los_Angeles'},
  schema: [
    { locale: { language: 'en-US', currency: 'USD', timeZone: 'America/Los_Angeles'}, dir: 'ltr', text: 'United States' },
    { locale: { language: 'en-GB', currency: 'GBP', timeZone: 'Europe/London'}, dir: 'ltr', text: 'United Kingdom' },
    { locale: { language: 'nl', currency: 'EUR', timeZone: 'Europe/Amsterdam'}, dir: 'ltr', text: 'Nederland' },
    { locale: { language: 'fr',currency: 'EUR', timeZone: 'Europe/Paris'}, dir: 'ltr', text: 'France' },
    { locale: { language: 'de', currency: 'EUR', timeZone: 'Europe/Berlin'}, dir: 'ltr', text: 'Deutschland' }
  ],
  defaultRouting: true
};

Hopefully you can help me figure this out.
Kind Regards

As in the docs (https://github.com/robisim74/angular-l10n#user-language), the library tries to take the user's browser language, before falling back on the default locale: only the language, not language-region, because there are inconsistencies between browsers for language-region.

If you want language-region, you have to override L10nUserLanguage, for example:

@Injectable() export class UserLanguage implements L10nUserLanguage {

    public get(): Promise<string | null> {
        let browserLanguage = null;
        if (navigator !== undefined && navigator.language) {
            // Takes the complete locale, not only the language as in the the default version
            console.log(navigator.language);
            browserLanguage = navigator.language;
        }
        return Promise.resolve(browserLanguage);
    }

}

and then in AppModule:

        L10nTranslationModule.forRoot(
            l10nConfig,
            {
                userLanguage: UserLanguage
            }
        )

Plus, you're using a mix of formats at the same time, not only language-region like en-GB, but also only language like nl, therefore you should change again:

@Injectable() export class UserLanguage implements L10nUserLanguage {

    public get(): Promise<string | null> {
        let browserLanguage = null;
        if (navigator !== undefined && navigator.language) {
            console.log(navigator.language);
            const lang = navigator.language.split('-')[0];
            if (lang === 'en') {
                // Takes the complete locale
                browserLanguage = navigator.language;
            } else {
                // Takes only the language
                browserLanguage = lang;
            }
        }
        return Promise.resolve(browserLanguage);
    }

}

Thanks again for the quick reply.

I was missing the part of adding it to the AppModule. It's working as a charm now.

Thank you very much.