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

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

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

2 ответов


используя 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
}

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


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

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

к сожалению, вы не можете изменить язык для DatePipe JIT. Угловой компилятор требует LOCALE_ID во время начальной загрузки.

есть некоторые сообщения об ошибках для Angular:

есть несколько обходных путей для этого:

Решение #1

Re-bootstrapping угловой модуль:

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

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

решение #4

каждая труба которые используют LOCALE_ID есть частное поле locale или _locale, поэтому вы можете переопределить это поле в этом канале при изменении языка, так как есть один экземпляр pipe.

это будет работать, потому что 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()

к сожалению, все выше обходные пути.

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