• Angular使用管道和指令进行多语言切换


            工作中经常遇到需要进行多种语言切换的项目。本文记录了一种在Angular页面中通过使用管道和自定义指令实现的语言切换方案。

    1、实现效果

            页面显示文字根据选择的语言自动进行翻译切换,如下图所示:

            此时,页面模板的字符串全部按照管道格式书写: 

    1. <h1>{{ "app.title" | translate}}</h1>
    2. <div>
    3. <span>{{ "app.demo.text" | translate}}</span>
    4. <input type="text" placeholder="{{ 'app.demo.placeholder' | translate}}">
    5. <button (click)="showMessage()">{{"app.demo.btn" | translate}}</button>
    6. </div>
    7. <button *ngFor="let lan of languages" (click)="setLanguage(lan.code)">
    8. {{lan.icon + " " + lan.text}}
    9. </button>

            其中 "app.title","app.demo.text",'app.demo.placeholder',"app.demo.btn" 等为各字符串的key,translate为管道选择器。translate管道通过key查找对应翻译进行翻译。用于查找翻译的字典通过加载文件方式加载到页面内存中。翻译文件格式如下:

            管道通过调用语言服务类(LanService)中的翻译方法查找对应翻译。

    2、语言服务类

            语言服务类(LanService)中主要包含加载翻译文件、同步翻译、异步翻译、设置语言方法。

    2.1、加载翻译文件方法

            通过HttpClient.get()加载翻译文件:

    1. /**
    2. * 加载翻译文件
    3. * @returns
    4. */
    5. loadTranslation(languageCode: string = this.curLanguage) {
    6. const jsonFile = `assets/language/${languageCode}.json`;
    7. this.isLoading = true;
    8. return new Promise<void>((resolve, reject) => {
    9. this.http.get<any>(jsonFile).subscribe(data => {
    10. this.translation = data;
    11. this.isLoading = false;
    12. this.lanChange.next(languageCode);
    13. resolve();
    14. }, err => {
    15. reject(`load translation json error: ${err}`);
    16. })
    17. });
    18. }

            文件加载完成后会发出一个语言切换的通知(this.lanChange.next(languageCode);),订阅了该通知的方法将执行对应订阅逻辑。

    2.2、同步翻译方法

            通过key获取当前字典中对应的翻译,未查找到对应key的翻译直接返回key,如果服务正在加载翻译文件也直接返回key:

    1. /**
    2. * 获取单个文本的翻译 同步方法
    3. * @param key 文本资源key
    4. * @returns 对应翻译结果字符串,未查找到返回key
    5. */
    6. translate(key: string) {
    7. if (this.isLoading) return key;
    8. else return this.translation[key] || key;
    9. }

            对于一些在确定语言包json已加载完成的场景中可以使用同步翻译方法获取翻译。比如页面中点击按钮提示的文字就可以采用同步方法获取翻译:

    1. /**
    2. * 弹出提示文字
    3. */
    4. showMessage() {
    5. alert(this.lanService.translate("app.welcome"));
    6. }

    2.3、异步翻译方法

            通过key获取当前字典中对应的翻译,返回数据以Observable格式封装。如果服务正在加载翻译文件,则订阅语言切换的通知,待文件加载完成发出通知后,再查找对应翻译;相反则直接查找翻译:

    1. /**
    2. * 获取单个文本的翻译 异步方法
    3. * @param key 文本资源key
    4. * @returns 对应翻译结果字符串,未查找到返回key
    5. */
    6. get(key: string) {
    7. if (this.isLoading) {
    8. return from(new Promise<string>(resolve => {
    9. this.lanChange.subscribe(lan => {
    10. resolve(this.translation[key] || key);
    11. })
    12. }));
    13. } else {
    14. return of(this.translation[key] || key);
    15. }
    16. }

    2.4、设置语言方法

            方法调用时,根据传入的语言重新加载翻译文件,加载后更新当前语言:

    1. /**
    2. * 设置页面语言
    3. * @param languageCode 语言代码 zh-CN | en-US
    4. */
    5. setLanguage(languageCode: string) {
    6. if (this.curLanguage != languageCode) {
    7. this.loadTranslation(languageCode).then(() => {
    8. this.curLanguage = languageCode;
    9. });
    10. }
    11. }

    3、页面启动加载翻译文件

            页面启动时需要加载翻译文件,可以在AppModule中注册页面启动的加载方法:

    1. export function StartUpServiceFactory(startUpService: StartUpService) {
    2. return () => startUpService.load();
    3. }
    4. const APP_INIT_PROVIDERS = [
    5. StartUpService,
    6. {
    7. provide: APP_INITIALIZER,
    8. useFactory: StartUpServiceFactory,
    9. deps: [StartUpService],
    10. multi: true
    11. }
    12. ];
    13. @NgModule({
    14. //...
    15. providers: [
    16. ...APP_INIT_PROVIDERS
    17. ],
    18. // ...
    19. })
    20. export class AppModule { }

            在启动服务类(StartUpService)中调用语言服务类(LanService)的加载翻译文件方法:

    1. /**
    2. * 启动加载项
    3. */
    4. load() {
    5. this.lan.loadTranslation();
    6. }

    4、管道方法

            管道方法中采用异步获取翻译的方式进行文本转换,会将传入的key及其翻译进行缓存,每次查询会优先查询缓存值。没有缓存才会进行异步获取翻译。管道还会订阅语言服务类(LanService)的语言切换通知,收到通知后重新获取翻译,更新翻译结果:

    1. transform(key: string) {
    2. if (this.cacheKey == key) return this.translation;
    3. this.cacheKey = key;
    4. this.updateTranslation(key);
    5. this.unsubscribe();
    6. if (!this.lanChange$) {
    7. this.lanChange$ = this.lanService.lanChange.subscribe(lan => {
    8. if (this.cacheKey) {
    9. this.cacheKey = "";
    10. this.updateTranslation(key);
    11. }
    12. });
    13. }
    14. return this.translation;
    15. }

            其中updateTranslation()方法完成了异步获取翻译的操作:

    1. /**
    2. * 异步更新翻译
    3. * @param key 字符串key
    4. */
    5. updateTranslation(key: string) {
    6. let callback = (tran: string) => {
    7. this.translation = tran || key;
    8. this.cacheKey = key;
    9. this._ref.markForCheck();
    10. }
    11. this.lanService.get(key).subscribe(callback);
    12. }

            为了使Angular状态检查能够检测到管道值的变化,管道装饰器的pure字段必须设置为false,否则页面不会渲染更新修改语言而导致的文本变化:

    1. @Pipe({
    2. name: 'translate',
    3. pure: false
    4. })
    5. export class TranslatePipe implements PipeTransform{}

    5、自定义指令实现

            使用上述管道就可以完全满足语言切换的需求,但是使用管道的时候,模板HTML页面代码中只能看到各字符串对应的key,如果是团队合作的代码或者长时间之前写的代码,就不能马上理解到key对应的翻译文本。这时候如果采用指令的形式实现,将key通过参数传入指令,通过指令修改元素innnerText。此时模板HTML页面中就可以保留任意语言对应的翻译,当然汉语最熟悉:

    1. "'app.title'">多语言切换演示

    2. <span [lan]="'app.demo.text'">文本内容演示span>
    3. <button [lan]="'app.demo.btn'" (click)="showMessage()">点击提示文字button>

            这样就既能满足切换语言需求,又能一眼看到中文信息,提高代码可读性。指令代码:

    1. /**
    2. * 传入的字符串key
    3. */
    4. @Input('lan')
    5. set lan(value: string) {
    6. this.key = value;
    7. this.setText(value);
    8. }
    9. /**
    10. * 异步获取翻译设置元素内容文本
    11. * @param key
    12. */
    13. setText(key: string) {
    14. key = key || '';
    15. if (key.length > 0) {
    16. const el = this.el.nativeElement;
    17. this.lanService.get(key).subscribe(tran => {
    18. el.innerText = tran;
    19. this.changeDetectorRef.markForCheck();
    20. });
    21. }
    22. }
    23. //订阅服务类通知更新翻译
    24. this.lanChange$ = this.lanService.lanChange.subscribe((lan) => {
    25. if (this.key.length > 0) {
    26. this.setText(this.key);
    27. }
    28. });

            但是像placeholder这种还是只能使用管道。

            完整项目代码下载:Angular使用管道和指令实现多语言切换示例,无第三方库引用-Typescript文档类资源-CSDN下载

  • 相关阅读:
    网站为什么要备案?网站备案流程是什么?
    【数学建模】2023数学建模国赛C题完整思路和代码解析
    港联证券:短债基金收益?
    【C++】【Opencv】cv::GaussianBlur、cv::filter2D()函数详解和示例
    海贼王大学生HTML网页制作作品 学生动漫网页设计模板下载 简单漫画网页设计成品 dreamweaver学生网站模板
    【数据结构】搜索二叉树(C++实现)
    深入理解KNN扩展到ANN
    Hough Transform Tutorial
    css实现滚动视差效果
    docker容器中elasticsearch配置跨域访问(elasticsearch-head插件访问不到es集群)
  • 原文地址:https://blog.csdn.net/evanyanglibo/article/details/128084926