[ngx-formly] Use Angular Formly Extensions to automatically localize all field labels
In this lesson we're diving a bit deeper and learn how to inject services into Formly Extensions with the example of using ngx-translate to localize all of our form field labels.
Create Extension with Tranlsate service:
// translate.extension.ts import { TranslateService } from '@ngx-translate/core'; import { FormlyFieldConfig } from '@ngx-formly/core'; export class TranslateExtension { constructor(private translate: TranslateService) {} prePopulate(field: FormlyFieldConfig) { const to = field.templateOptions || {}; if (!to.label || to._translated) { return; } to._translated = true; field.expressionProperties = { ...(field.expressionProperties || {}), 'templateOptions.label': this.translate.stream( field.templateOptions.label ) }; } } export function registerTranslateExtension(translate: TranslateService) { return { extensions: [ { name: 'translate-extension', extension: new TranslateExtension(translate) } ] }; }
Define in module:
import { registerTranslateExtension } from './translate.extension'; // AoT requires an exported function for factories export function HttpLoaderFactory(httpClient: HttpClient) { return new TranslateHttpLoader(httpClient, 'assets/i18n/', '.json'); } export function minValidationMessage(err, field: FormlyFieldConfig) { return `Please provide a value bigger than ${err.min}. You provided ${err.actual}`; } export function ipValidationMessage(err, field: FormlyFieldConfig) { return `"${field.formControl.value}" is not a valid IP address`; } export function IpValidator(control: FormControl): ValidationErrors { return !control.value || /(\d{1,3}\.){3}\d{1,3}/.test(control.value) ? null : { ip: true }; } @NgModule({ declarations: [AppComponent, NgSelectFormlyComponent], imports: [ BrowserModule, SharedModule, AppRoutingModule, BrowserAnimationsModule, ReactiveFormsModule, NgSelectModule, HttpClientModule, TranslateModule.forRoot({ loader: { provide: TranslateLoader, useFactory: HttpLoaderFactory, deps: [HttpClient] } }), FormlyModule.forRoot({ validators: [ { name: 'ip', validation: IpValidator } ], validationMessages: [ { name: 'required', message: 'This field is required' }, { name: 'min', message: minValidationMessage }, { name: 'ip', message: ipValidationMessage } ], types: [ { name: 'my-autocomplete', component: NgSelectFormlyComponent } ], extensions: [ { name: 'data-cy- extension', extension: dataCyExtension } ] }), FormlyMaterialModule ], providers: [ { provide: FORMLY_CONFIG, multi: true, useFactory: registerTranslateExtension, deps: [TranslateService] } ], bootstrap: [AppComponent] }) export class AppModule {}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2020-04-29 [React] Handle Deep Object Comparison in React's useEffect hook with the useRef Hook
2020-04-29 [Angular] Dynamic replacement for index.html
2019-04-29 [Algorithm] Calculate Pow(x,n) using recursion
2019-04-29 [Vuex] Use Namespaces in Vuex Stores using TypeScript
2019-04-29 [Algorithm] Fibonacci Sequence - Anatomy of recursion and space complexity analysis
2017-04-29 [Node.js] Test Node RESTful API with Mocha and Chai
2016-04-29 [Typescript] Introduction to Generics in Typescript