web-dev-qa-db-ja.com

Angular 2でDatePipeのロケールを動的に変更する

ユーザーが言語を切り替えることができるAngularプロジェクトを作成しています。ロケールを動的にすることは可能ですか?

NgModuleに追加できることを見てきましたが、そこに置くと動的ではないと推測していますか?または、サービスまたは何かを通じてそれを何らかの形で変更できますか?

11

providersを使用すると、NgModuleのデフォルトロケールを変更できます。これを行うには、angle/coreからLOCALE_IDをインポートし、ロケール言語をフェッチして、同じものをプロバイダーに渡す必要があります。

import { LOCALE_ID } from '@angular/core';

@NgModule({
    imports: [//your imports],
    providers: [
        { provide: LOCALE_ID, useValue: "en-US" }
    ]
})

...
...
{
  provide: LOCALE_ID,
  deps: [SettingsService],      //some service handling global settings
  useFactory: (settingsService) => settingsService.getLanguage()  //returns locale string
}

これがお役に立てば幸いです。

11
Amol Bhor

サービスからロケールを設定するには、@ AmolBhorの回答のように、工場で_LOCALE_ID_プロバイダーを_app.module_に追加する必要があります

_{
  provide: LOCALE_ID,
  deps: [SettingsService],      //some service handling global settings
  useFactory: (settingsService) => settingsService.getLanguage()  //returns locale string
}
_

残念ながら、DatePipe JITの言語を変更することはできません。 Angularコンパイラは、ブートストラップ中に_LOCALE_ID_を必要とします。

Angularにはいくつかのバグレポートがあります。

これにはいくつかの回避策があります。

回避策#1

再ブートストラップangularモジュール:

_let _platformRef: NgModuleRef<Object>;
if(_platformRef) { _platformRef.destroy(); }
platformBrowserDynamic(providers)
    .bootstrapModule(AppModule, {providers})
    .then(platformRef => {
        _platformRef = platformRef;
    })
_

* UpgradeModuleを使用してAngularJSを破棄する方法がないため、これはHybrid Angular/AngularJSでは機能しません。

回避策#2

DatePipe、NumberPipeを上書きするには-必要なもの:

_@Pipe({name: 'datepipe', pure: true})
export class MyDatePipe implements PipeTransform {
  transform(value: any, pattern?: string): string | null {
    // transform value as you like (you can use moment.js and format by locale_id from your custom service)
    return DateUtils.format(value);
  }
}
_

回避策#3

Ex用のカスタムPipesですでにローカライズを処理するライブラリを使用するには:

回避策#4

_LOCALE_ID_を使用するすべてのパイプには、プライベートフィールドlocaleまたは_ locale、パイプのインスタンスが1つあるため、言語変更時にそのパイプでこのフィールドをオーバーライドできます。

TypeScriptはJavaScriptの単なる構文糖だからです。 JavaScriptにはプライベートフィールドはありません。

また、ApplicationRefのtick()メソッドを使用して、アプリケーションの変更検出を処理することを忘れないでください。

_@Injectable()
export class DynamicLocaleService {
  private i18nPipes: PipeTransform[];

  constructor(
    datePipe: DatePipe,
    currencyPipe: CurrencyPipe,
    decimalPipe: DecimalPipe,
    percentPipe: PercentPipe,
    private applicationRef: ApplicationRef,
  ) {
    this.i18nPipes = [
      datePipe,
      currencyPipe,
      decimalPipe,
      percentPipe,
    ]
  }

  setLocale(lang: string): void {
    this.i18nPipes.forEach(pipe => {
      if(pipe.hasOwnProperty("locale")) {
        pipe["locale"] = lang;
      } else if (pipe.hasOwnProperty("_locale")) {
        pipe["_locale"] = lang
      }
    })
    this.applicationRef.tick()
  }
}
_

回避策#5

言語が変更されたときにアプリケーションをリロードします。

_window.location.reload()
_

残念ながら、上記のすべては回避策です。

しかし、別の解決策もあります。言語ごとに複数のバンドルを使用できます。これは、アプリが高速になるため、おそらくより良いアプローチになるでしょう。しかし、このソリューションはすべてのアプリケーションに適用できるわけではなく、質問に答えることはありません。

18
Anton Temchenko

あなたのサービスを

import { Injectable } from '@angular/core';

@Injectable()
export class LocaleService {

  //Chosse Locale From This Link
  //https://github.com/angular/angular/tree/master/packages/common/locales
  constructor() { }

  private _locale: string;

  set locale(value: string) {
    this._locale = value;
  }
  get locale(): string {
    return this._locale || 'en-US';
  }

  public registerCulture(culture: string) {
    debugger;
    if (!culture) {
      return;
    }
    switch (culture) {
      case 'en-uk': {
        this._locale = 'en';
        console.log('Application Culture Set to English');
        break;
      }
      case 'zh-hk': {
        this._locale = 'zh-Hant';
        console.log('Application Culture Set to Traditional Chinese');
        break;
      }
      case 'zh-cn': {
        this._locale = 'zh-Hans';
        console.log('Application Culture Set to Simplified Chinese');
        break;
      }
      default: {
        this._locale = 'en';
        console.log('Application Culture Set to English');
        break;
      }
    }
  }
}

そして、App.module.tsで

最初に必要なローカライズをインポートします

import localeEN from '@angular/common/locales/en';
import localezhHant from '@angular/common/locales/zh-Hant';
import localezhHans from '@angular/common/locales/zh-Hans';

プロバイダーセクションより

{
  provide: LOCALE_ID,
  deps: [LocaleService],
  useFactory: (LocaleService: { locale: string; }) => LocaleService.locale
}

最後に

registerLocaleData(localeEN);
registerLocaleData(localezhHant);
registerLocaleData(localezhHans);

それが誰かを助けることを願っています

ロケールを動的に変更したい場合は、目的のコンポーネントにLocaleServiceを挿入し、registerCultureメソッドを使用して、必要なカルチャをこれに渡します

0
Saurabh