【问题标题】:Angular 5 Pipes and dynamic localeAngular 5 管道和动态语言环境
【发布时间】:2018-04-19 20:44:42
【问题描述】:

我目前有内置 Angular 4 的应用程序,并希望升级到 Angular 5。我正在阅读他们如何处理管道中的语言环境,看来升级不再是一种选择。据我所知,他们希望你要么 1.手动导入不同的文化 2. 为每种文化构建一个单独的应用程序

问题是我在一家支持 351 种不同文化的国际公司工作,我们有 15 个应用程序。如果我想像他们一样继续升级,角度团队真的说我现在必须构建 5265 个不同的应用程序吗?如果我带着那个去我的老板那里,我可能会被赶出房间。

在我们的 angularJs 应用程序中,我们刚刚下载了用户登录时在运行时需要的 $locale 服务,并将提供程序设置为该服务。 Angular 没有这样的东西吗?如果不是,我不确定企业级应用程序如何使用这种语言,除非开发人员足够幸运,只需要支持一种文化。

【问题讨论】:

标签: angular angular-i18n angular5


【解决方案1】:

我遇到了同样的问题,并找到了解决方法。

我决定在资产文件夹中发布角度语言环境数据(来自 cldr)。 Cldr 数据来自 node_mopdules\@angular\common\locales (您将在 typescript 中导入的内容)。 就在引导之前,使用 APP_INITIALIZER,我从给定特定 locale_id 的资产中加载正确的文化数据。

诀窍是避免使用 import 关键字,因为 EC2015 不支持动态导入。 为了从 js 文件中获取文化数据,我编写了这个“脏”代码:

import { Injectable, Inject, LOCALE_ID } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class LoaderService {

  constructor(protected httpClient: HttpClient,
              @Inject(LOCALE_ID) protected locale: string) { }

private async loadAngularCulture(locale) {
      let angularLocaleText = await this.httpClient.get(`assets/angular-locales/${locale}.js`).toPromise();

      // extracting the part of the js code before the data, 
      // and i didn't need the plural so i just replace plural by null.
      const startPos = angularLocaleText.indexOf('export default ');
      angularLocaleText = 'return ' + angularLocaleText.substring(startPos + 15).replace('plural', null);

      // The trick is here : to read cldr data, i use a function
      const f = new Function(angularLocaleText);
      const angularLocale = f();

      // console.log(angularLocale);

      // And now, just registrer the object you just created with the function
      registerLocaleData(angularLocale);
  }

并且是我的 mainModule,使用 APP_INITIALIZER :

export function configFactory(intlLoader: SfkIntlLoaderService) {
  return intlLoader.initializer();
}

export function localFunction() {
  // the rule to get you language according. 
  // Here, for demo, i just read it from localstorage
  return localStorage.getItem('LANGUGAGE');
}

@NgModule({
 declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  )
  ],
  providers: [
    LoaderService,
    {
      provide: LOCALE_ID,
      deps: [],
      useFactory: localFunction
    },
    {
      provide: APP_INITIALIZER,
      useFactory: configFactory,
      deps: [LoaderService],
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

希望这会有所帮助!

【讨论】:

  • transform函数可以有多个变量,需要写成:transform(value: any, ...args) { return super.transform(value, ...args); }
【解决方案2】:

在 github 上就这个问题进行交流后,已经开始使用的一个想法是创建一个我在 APP_INITIALIZER 中调用的服务,您可以在下面看到。由于构建时的动态字符串,angular-cli 将为每种文化创建一个块,然后在我提供从服务调用收到的文化字符串后在运行时加载正确的块。

setLocale(localeId: string): Promise<any> {
    this.culture = localeId;
    return new Promise((resolve, reject) => {
      System.import(`@angular/common/locales/${localeId}.js`).then(
        module => {
          registerLocaleData(module.default);
          resolve();
        },
        () => {
          System.import(`@angular/common/locales/${localeId.split('-')[0]}.js`).then(module => {
            registerLocaleData(module.default);
            resolve();
          }, reject);
        }
      );
    });
  }

【讨论】:

    【解决方案3】:

    我对 angular4 有同样的问题,我想将 AOT 与多种语言一起使用。这就是我所做的:

    用于设置语言环境的管道周围的简单包装器。

    @Pipe({name: 'datepipe', pure: true})
    export class MyDatePipe extends DatePipe implements PipeTransform {
      constructor(private win: WindowRef) {
        super(win.ln);
      }
    
      transform(value: any, pattern?: string): string | null {
        return super.transform(value, pattern);
      }
    }
    

    地区服务:

    function _window(): any {
      // return the global native browser window object
      return window;
    }
    
    @Injectable()
    export class WindowRef {
      get nativeWindow(): any {
        return _window();
      }
    
      //default locale
      public ln = 'en';
    
    
      constructor() {
        try {
           if (!isNullOrUndefined(this.nativeWindow.navigator.language) && this.nativeWindow.navigator.language !== '') {
            this.ln = this.nativeWindow.navigator.language;
          }
        }finally {}
      }
    }
    

    这适用于 angular4,但对于 angular5,我必须在我的 main.ts 中导入支持的语言环境

    import { registerLocaleData } from '@angular/common';
    import localeFr from '@angular/common/locales/fr';
    
    registerLocaleData(localeFr);
    

    【讨论】:

    • 对,但这意味着我必须手动导入 350 个语言环境
    • AFAIK,是的。您可以在 github 上创建 PR 或 issue 来注册所有本地人。
    • 暂时可以使用折旧的管道。
    • 是的,我想升级到 5 没有障碍。但它开始看起来是我能够使用的最高版本,因为我认为适合我的管道将是离开 6
    • notIsNullOrUndefined(something) => !!something
    猜你喜欢
    • 2019-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-01
    相关资源
    最近更新 更多