We have an approach for lazy loading and setting the LOCALE_ID of the Angular application from the API (by loading the user profile data during on startup). This worked fine on Angular 7 but when I've upgraded to Angular 8 it stopped working. When the localeFactory is called (see below) the localeService.getLocale()
is undefined, it has not been initialized yet.
We initialize it in a SharedResolver
which is in a SharedModule
which is included in the imports of the AppModule
.
What is the right approach for doing this in Angular 8? In didn't see anything specific to this in the documentation of changes so I guess it's something indirect.
Any input on what approach I should take here? Thanks
Please see relevant code below:
app.module.ts
export function localeFactory(localeService: LocaleService) {
console.log('locale factory called');
// This is `undefined` here now for some reason
console.log(localeService.getLocale());
return localeService.getLocale() || 'en';
}
...
const APP_LOCALE_ID = {
provide: LOCALE_ID,
deps: [LocaleService],
useFactory: localeFactory
};
@NgModule({
imports: [
BrowserModule,
FormsModule,
HttpClientModule,
BrowserAnimationsModule,
AppRoutingModule,
SharedModule.forRoot(), // <- in this module we have the SharedResolver
AccountModule,
ApiModule,
GenesysSubprojectModule
],
declarations: [AppComponent],
providers: [
AppRouteGuard,
BreadcrumbService,
{
provide: APP_INITIALIZER,
useFactory: appInitializerFactory,
deps: [PlatformLocation, BootstrapService],
multi: true
},
{ provide: ErrorHandler, useClass: GlobalErrorHandler },
AppRouteGuard,
BreadcrumbService,
// TODO - This doesn't work anymore!
APP_LOCALE_ID
],
bootstrap: [AppComponent]
})
export class AppModule {}
shared-resolve.ts
export class SharedResolve implements Resolve<any> {
...
resolve(route: ActivatedRouteSnapshot) {
...
const observables = forkJoin(
this.authService.getPermissions(),
this.authService.getCurrentProfileFromApi(),
this.languageApi.getActiveLanguages(), // TODO - cache
this.tenantSettingsApi.getLogo(logoLastModificationTime),
this.dashboardApi.getDashboardSettings(),
this.reportApi.getReportSettings(),
this.publicSettingsApi.getSettings(),
this.tenantSettingsApi.getInitializationSettings()
) as Observable<any[]>;
return observables
.pipe(
flatMap(result => {
...
const profile: CurrentUserProfileExtEditDto = result[1];
...
const languageName =
profile.languageName || navigator.language; // browser default language
console.log('Set locale to languageName=' + languageName);
this.storageService.setLocale(languageName);
this.localeService.setLocale(languageName);
Yep, that's an Ivy i18n issue in v8.x.x
. I've posted it in the Angular repo and has been confirmed by @Ocombe (who is working on Ivy i18n).
If you are in a hurry, as a workaround, you can do this:
As Ivy is searching for a runtime locale, you can simply provide a default language in the AppModule
like this and then provide your APP_INITIALIZER
:
...
providers: [
...
{ provide: LOCALE_ID, useValue: 'en' }
{
provide: APP_INITIALIZER,
useFactory: initializeAppSettings,
deps: [AppInitializerService],
multi: true
}
...
]
...
This will first set the default locale and then run your APP_INITIALIZER
. Next, in your CoreModule
(only loaded once), simply provide the new LOCALE_ID
fetched from the backend:
...
providers: [
...
{
provide: LOCALE_ID,
useFactory: (localeService: LocaleService) => localeService.getCurrentLocale(),
deps: [LocaleService]
}
...
]
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With