Angular 语言更改时刷新管道

Angular refresh pipe on language change

我有一个语言选择器和默认管道,例如根据所选语言的数字或货币格式。但是,当我更改语言时(例如从 en-US 更改为 fr-FR),即使 LOCALE_IDTranslateService.currentLanguage 已正确更新,千位分隔符也不会更改。如何在不重新加载页面的情况下解决此问题?

i18n.service.ts

import { Injectable } from '@angular/core';
import { TranslateService, LangChangeEvent } from '@ngx-translate/core';
import { Subscription } from 'rxjs';

import * as moment from 'moment';

import { Logger } from './logger.service';
import enUS from '../../../translations/en-US.json';
import frFR from '../../../translations/fr-FR.json';

import { languageSettings } from '@env/language-settings';

const log = new Logger('I18nService');
const languageKey = 'language';


export interface LanguageContext {
    code: string;
    label: string;
}

@Injectable({
  providedIn: 'root'
})
export class I18nService {

  defaultLanguage!: string;
  supportedLanguages!: LanguageContext[];

  private langChangeSubscription!: Subscription;

  constructor(private translateService: TranslateService) {
    // Embed languages to avoid extra HTTP requests
    translateService.setTranslation('en-US', enUS);
    translateService.setTranslation('fr-FR', frFR);
  }

  /**
   * Initializes i18n for the application.
   * Loads language from local storage if present, or sets default language.
   * @param defaultLanguage The default language to use.
   * @param supportedLanguages The list of supported languages.
   */
  init() {
    this.defaultLanguage = languageSettings.defaultLanguage;
    this.supportedLanguages = languageSettings.supportedLanguages;
    this.language = '';

    // Warning: this subscription will always be alive for the app's lifetime
    this.langChangeSubscription = this.translateService.onLangChange
      .subscribe((event: LangChangeEvent) => { localStorage.setItem(languageKey, event.lang); });
  }

  /**
   * Cleans up language change subscription.
   */
  destroy() {
    if (this.langChangeSubscription) {
      this.langChangeSubscription.unsubscribe();
    }
  }

  /**
   * Sets the current language.
   * Note: The current language is saved to the local storage.
   * If no parameter is specified, the language is loaded from local storage (if present).
   * @param language The IETF language code to set.
   */
  set language(language: string) {
    language = language || localStorage.getItem(languageKey) || this.translateService.getBrowserCultureLang();
    const supportedLanguagesCodes = this.supportedLanguages.map(lang => lang.code);
    let isSupportedLanguage = supportedLanguagesCodes.includes(language);

    // If no exact match is found, search without the region
    if (language && !isSupportedLanguage) {
      language = language.split('-')[0];
      language = supportedLanguagesCodes.find(supportedLanguage => supportedLanguage.startsWith(language)) || '';
      isSupportedLanguage = Boolean(language);
    }

    // Fallback if language is not supported
    if (!isSupportedLanguage) {
      language = this.defaultLanguage;
    }

    log.debug(`Language set to ${language}`);
    this.translateService.use(language);

    // Influde moment pipes to change language
    moment.locale(language);
  }

  /**
   * Gets the current language.
   * @return The current language code.
   */
  get language(): string {
    return this.translateService.currentLang;
  }

}

app.module.ts 提供商

  { provide: DEFAULT_CURRENCY_CODE, useValue: 'USD' },
  { provide: MAT_DATE_LOCALE, useValue: languageSettings.defaultLanguage },
  { provide: LOCALE_ID, useFactory: (i18nService: I18nService) => {             
      // Locale cant set dynamic > Change require reboot
      i18nService.init();
      return i18nService.language;
    },
    deps: [I18nService]
  }

最后我决定制作自定义动态管道来替换默认管道。这是 DecimalPipe

的示例
import { DecimalPipe } from '@angular/common';
import { Pipe, PipeTransform } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Pipe({ name: 'number', pure: false })
export class DynamicDecimalPipe implements PipeTransform {
  constructor(private translateService: TranslateService) {}
  transform(n: number, format?: string): string {
    const decimalPipe: DecimalPipe = new DecimalPipe(this.translateService.currentLang)
    return format ? decimalPipe.transform(n, format) : decimalPipe.transform(n)
  }
}