Angular 5管道和动态语言环境

3
我目前正在使用 Angular 4 构建应用程序,想要升级到 Angular 5。我在阅读有关管道中如何处理区域设置的内容时发现,升级似乎已经不再是一个选项。根据我所知,他们希望你要么手动导入不同的语言环境,要么为每个语言环境构建一个单独的应用程序。
问题在于,我在一家支持 351 种不同文化的国际公司工作,我们有 15 个应用程序。Angular 团队真的在说如果我想继续升级,现在就必须构建 5265 个不同的应用程序吗?如果我向我的老板提出这个问题,我可能会被赶出房间。
在我们的 AngularJS 应用程序中,我们只需要在用户登录时下载我们需要的 $locale 服务并设置提供者即可。对于 Angular,是否有类似的方法?如果没有,除非开发人员足够幸运只需支持一种语言环境,否则企业级应用程序如何使用这种语言?

请阅读我在这里的回答:https://dev59.com/X1cP5IYBdhLWcg3whKN3#49675774,希望能有所帮助。 - Anton Temchenko
3个回答

2

在 Github 上讨论这个问题后,我们想出了一个解决方案:创建一个服务,并使用 APP_INITIALIZER 调用它,具体代码如下。由于构建时的动态字符串,angular-cli 会为每种语言环境创建一个 chunk,在运行时根据服务返回的语言环境加载正确的 chunk。

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);
        }
      );
    });
  }

0

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

我决定在资产文件夹中发布来自cldr的angular本地化数据。 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);
  }

这是我的主模块,使用了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); } - criticalJ

0

我在使用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个本地化文件。 - Jason
据我所知,可以。你可以在 Github 上创建一个 PR 或 issue 来注册所有的本地化信息。 - Robin Dijkhof
目前您可以使用已弃用的管道。 - Robin Dijkhof
是的,我想升级到5应该没有障碍。但是看起来这可能是我能够升级的最高版本,因为我认为对我有用的管道将在6中消失。 - Jason
notIsNullOrUndefined(something) => !!something - Sampgun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接