Динамически изменять локаль для 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:
- https://github.com/angular/angular/issues/15039 (закрыто - не решено)
- https://github.com/angular/angular/issues/16960 (закрыто с обходным путем в комментариях)
есть несколько обходных путей для этого:
Решение #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()
к сожалению, все выше обходные пути.
но есть и другое решение - у вас может быть несколько пакетов для каждого языка, что, вероятно, будет лучше, так как приложение будет быстрее. Но это решение не применимо для каждого приложения и не отвечает на вопрос.