首页 > 解决方案 > 在启动时从 Angular 8 应用程序中的 API 在运行时延迟加载和设置 LOCALE_ID

问题描述

我们有一种从 API 延迟加载和设置 Angular 应用程序的 LOCALE_ID 的方法(通过在启动时加载用户配置文件数据)。这在 Angular 7 上运行良好,但是当我升级到 Angular 8 时它停止工作。当 localeFactory 被调用(见下文)时localeService.getLocale(),它是未定义的,它还没有被初始化。我们将它初始化在 a SharedResolverwhich is in a SharedModulewhich 包含在AppModule. 在 Angular 8 中这样做的正确方法是什么?在更改文档中没有看到任何具体的内容,所以我想这是间接的。关于我应该在这里采取什么方法的任何意见?谢谢

请参阅下面的相关代码:

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 {}

共享解析.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);

标签: angularlocalizationlazy-loadingangular8

解决方案


是的,这是 Ivy i18n 中的问题v8.x.x。我已将其发布在 Angular 存储库中,并已得到 @Ocombe(正在研究 Ivy i18n)的确认。

如果您赶时间,作为一种解决方法,您可以这样做:

由于 Ivy 正在搜索运行时语言环境,您可以简单地提供AppModule类似这样的默认语言,然后提供您的APP_INITIALIZER

...
providers: [
    ...
    { provide: LOCALE_ID, useValue: 'en' }
    {
        provide: APP_INITIALIZER,
        useFactory: initializeAppSettings,
        deps: [AppInitializerService],
        multi: true
    }
    ...
]
...

这将首先设置默认语言环境,然后运行您的APP_INITIALIZER. 接下来,在您的CoreModule(仅加载一次)中,只需提供LOCALE_ID从后端获取的新内容:

...
providers: [
    ...
    {
        provide: LOCALE_ID,
        useFactory: (localeService: LocaleService) => localeService.getCurrentLocale(),
        deps: [LocaleService]
    }
    ...
]
...

推荐阅读