Динамическое изменение языкового стандарта для DatePipe в Angular 2

Я создаю проект Angular, где пользователь имеет возможность переключать языки. Можно ли сделать динамику локали?

Я видел, что вы можете добавить его в NgModule, но я предполагаю, что он не динамический, когда я его там положил? Или я могу изменить его каким-то образом через сервис или что-то еще?

Ответ 1

Используя providers, вы можете изменить языковой стандарт по умолчанию в своем NgModule. для этого вам нужно импортировать LOCALE_ID из angular/core и выбрать язык языкового стандарта для передачи того же самого поставщикам.

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
}

Надеюсь, это поможет вам.

Ответ 2

Чтобы установить локаль из сервиса, вам нужно добавить провайдера LOCALE_ID с фабрикой к app.module, как в ответе @AmolBhor

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

* Это не будет работать для Hybrid Angular/AngularJS, поскольку нет способа уничтожить AngularJS с помощью UpgradeModule.

Обходной путь № 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

Чтобы использовать библиотеку, которая уже обрабатывает локализацию с помощью пользовательских Pipes, например:

Обходной путь № 4

Каждый канал, который использует LOCALE_ID, имеет закрытое поле locale или _locale, поэтому вы можете переопределить это поле в этих каналах при смене языка, так как существует один экземпляр канала.

Это будет работать, потому что TypeScript - это просто синтаксический сахар для JavaScript. А в JavaScript нет приватных полей.

Также не забудьте обработать обнаружение изменений в приложении, используя метод tick() в ApplicationRef.

@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()

К сожалению, все вышеперечисленное - обходной путь.

Но есть и другое решение - вы можете иметь несколько пакетов для каждого языка, что, вероятно, будет лучше, так как приложение будет работать быстрее. Но это решение не применимо для каждого приложения и не отвечает на вопрос.

Ответ 3

Имейте свое Обслуживание как

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, передайте необходимую культуру в эту