How to update localeData and LOCALE_ID for i18n sites dynamically during build in Angular 9?
Asked Answered
U

2

9

I'm trying to build an application that supports multiple languages – up to 20 actually.

The default language is en-US. During the build the translated versions are created which works fine.

However, in all builds the LOCALE_ID is always en-US. So I can't rely on the locale in pipes etc. It is not updated with the locale set in the build confuguration.

I get this warning (here for German) during compilation for each locale as well:

Locale data for 'de-DE' cannot be found. No locale data will be included for this locale.


This is how the build config looks in angular.json:

"production-de": {
  "fileReplacements": [
    {
      "replace": "src/environments/environment.ts",
      "with": "src/environments/environment.prod.ts"
    }
  ],
  "optimization": true,
  "outputHashing": "all",
  "sourceMap": false,
  "extractCss": true,
  "namedChunks": false,
  "aot": true,
  "extractLicenses": true,
  "vendorChunk": false,
  "buildOptimizer": true,
  "budgets": [
    {
      "type": "initial",
      "maximumWarning": "2mb",
      "maximumError": "5mb"
    },
    {
      "type": "anyComponentStyle",
      "maximumWarning": "6kb"
    }
  ],
  "outputPath": "dist/de",
  "baseHref": "/de/",
  "i18nLocale": "de-DE",
  "i18nFile": "src/locale/messages/messages.de.xlf",
  "i18nFormat": "xlf"
},

The application is build using this command:

ng build configuration=production-de

This is how my app.module.ts looks:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, LOCALE_ID } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { HttpClientModule } from '@angular/common/http';
import { registerLocaleData } from '@angular/common';

import localeEn from '@angular/common/locales/en';
import localeEnExtra from '@angular/common/locales/extra/en';

registerLocaleData(localeEn, 'en-US', localeEnExtra);

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [
    {
      provide: LOCALE_ID,
      useValue: 'en-US'
    }
  ],
  bootstrap: [
    AppComponent
  ]
})

export class AppModule { }

It seems that registerLocaleData and also the provider for LOCALE_ID are not updated during the build.

I already tried to remove registerLocaleData and the LOCALE_ID provider, as en-US is the default setting in Angular. But it doesn't change the behaviour.


Must I replace the app.module.ts as well with different values for registerLocaleData? This would be a huge overhead regarding the 20 languages.

Or is there a different but correct way to deploy the application in multiple languages?

Am I missing some configuration?

Undenominational answered 2/3, 2020 at 15:43 Comment(4)
It is a project that you migrated from angular v8 or earlier? With angular 9 and @angular/localize, the configuration file is different from what you haveTersina
@Tersina The project was started with 9 rc3 and is now running on 9.0.2. But yes, some configuration was used from another Angular 8 app. So, the config for i18n is wrong with Angular 9? At least the localize package is installed and added to polyfill.ts as well.Undenominational
WIth Angular 8 and previous versions, one build was needed per language with angular i18n. With angular 9, you can have just one build, but the configuration is different. And I guess you still need a factory to provide LOCAL_ID, based on url or otherTersina
Thank you @David. You helped me a lot, putting me on the right track.Undenominational
U
2

With the help of David's comment I found that there where multiple mistakes in the configuration, because parts where taken from an Angular 8 project.

The config for i18n in Angular 9 is different and I found the solution by checking the schema of the angular.json file in ./node_modules/@angular/cli/lib/config/schema.json.

There's only one general build configuration now and I added i18n options to the actual project settings. This is what I added to the angular.json:

"projects": {
  "app": {
    "i18n": {
      "sourceLocale": "en",
      "locales": {
        "de": "src/locale/messages/messages.de.xlf"
      }
    },
    "architect": {
      "build": {
        "configurations": {
          "de": {
            "localize": ["de"]
          }
        }
      },
      "serve": {
        "configurations": {
          "de": {
            "browserTarget": "app:build:de"
          }
        }
      },

Now I can serve my application in any language using the CLI:

ng serve --configuration=de

And I can build all packages using:

ng build --prod --localize

Finally this has the effect that LOCALE_ID is set with the correct value at all times.

Undenominational answered 9/3, 2020 at 14:16 Comment(1)
So you don't need to provide: LOCALE_ID on appModule and registerLocaleData(localeEn, 'en-US', localeEnExtra) ?Poler
H
0

You could use a factory on providers

providers: [
    {
      provide: LOCALE_ID,
      useFactory: langServiceFactory,
      deps: []
    }
  ],

For more information about Factories https://angular.io/guide/dependency-injection-providers

Hillock answered 4/3, 2020 at 16:49 Comment(1)
You could detect navigator.language an then resolve this with either serviceHillock

© 2022 - 2024 — McMap. All rights reserved.