Angular通过配置文件设置LOCALE_ID报错修复方案
从配置文件设置Angular LOCALE_ID的实现问题
初始实现逻辑
目标是通过LOCALE_ID令牌,从配置文件读取值设置应用的区域语言标识。已在app.module.ts中配置APP_INITIALIZER,负责应用启动阶段把配置项加载到ConfigService,最初尝试在模块提供者列表中同时添加依赖ConfigService的LOCALE_ID提供者,预期配置加载完成后可正常读取配置中的语言字段,初始代码如下:
const initConfigProvider = { provide: APP_INITIALIZER, useFactory: (confService: ConfigService) => () => confService.loadConfig$().toPromise(), deps: [ConfigService], multi: true }; const initLocaleProvider = { provide: LOCALE_ID, useFactory: (confService: ConfigService) => () => { return confService.config.uiCulture; }, deps: [ConfigService] }; @NgModule({ ... providers: [ ... initConfigProvider, initLocaleProvider ] })
运行报错信息
项目启动后抛出三类错误:
ERROR TypeError: value.replace is not a function at CldrIntlService.set localeId [as localeId] (index.js:196:1) at new CldrIntlService (index.js:184:1) at cldrServiceFactory (index.js:134:1) ERROR Error: Cannot instantiate cyclic dependency! IntlService at throwCyclicDependencyError (core.js:5439:1) at R3Injector.hydrate (core.js:11245:1) at R3Injector.get (core.js:11071:1) ERROR Error: InvalidPipeArgument: 'locale.toLowerCase is not a function' for pipe 'DecimalPipe' at invalidPipeArgumentError (common.js:4152:1) at DecimalPipe.transform (common.js:4887:1)
修复方案
现有实现不需要完全重构,只需要做两处小调整即可解决问题:
- 修正
LOCALE_ID工厂函数的返回值LOCALE_ID的useFactory要求直接返回字符串类型的区域标识,现有代码多套了一层箭头函数,实际返回的是函数类型值,框架拿到非字符串值调用.replace()、.toLowerCase()等字符串方法时就会抛出类型错误。 - 规避循环依赖
循环依赖是因为LOCALE_ID初始化时会触发IntlService实例化,如果ConfigService在加载配置阶段注入了任何依赖LOCALE_ID的服务(比如数字、日期管道、i18n相关服务),就会形成依赖环。只需要保证ConfigService的loadConfig$()逻辑只做配置拉取、本地存储的纯逻辑,不注入、调用任何i18n相关服务即可。
修正后的LOCALE_ID提供者代码如下:
const initLocaleProvider = { provide: LOCALE_ID, useFactory: (confService: ConfigService) => { // 直接返回配置中的字符串值,不要嵌套额外的函数 return confService.config.uiCulture; }, deps: [ConfigService] };
补充说明:
APP_INITIALIZER返回的Promise完成resolve前,Angular会阻塞应用启动,只要配置加载逻辑在APP_INITIALIZER中正确执行,ConfigService中存储的配置值在LOCALE_ID工厂执行时就是可用的。如果项目集成了带自定义CldrIntlService的第三方组件库,需要将自定义的LOCALE_ID提供者放在第三方i18n模块引入顺序之后,保证自定义提供者的优先级更高,不会被库的默认配置覆盖。
内容的提问来源于stack exchange,提问作者Frimlik
相关产品推荐
相关产品推荐

