@ngx-easy-i18n-js/core
Version:
The easy internationalization (i18n) library for Angular
1 lines • 75.6 kB
Source Map (JSON)
{"version":3,"file":"ngx-easy-i18n-js-core.mjs","sources":["../../../projects/core/src/lib/easy-i18n.loader.ts","../../../projects/core/src/lib/easy-i18n.store.ts","../../../projects/core/src/lib/easy-i18n.service.ts","../../../projects/core/src/lib/locale-date.pipe.ts","../../../projects/core/src/lib/locale-number.pipe.ts","../../../projects/core/src/lib/tr.directive.ts","../../../projects/core/src/lib/tr.pipe.ts","../../../projects/core/src/lib/plural.pipe.ts","../../../projects/core/src/lib/plural.directive.ts","../../../projects/core/src/lib/locale-percent.pipe.ts","../../../projects/core/src/lib/locale-currency.pipe.ts","../../../projects/core/src/lib/plural-content.directive.ts","../../../projects/core/src/lib/tr-content.directive.ts","../../../projects/core/src/public-api.ts","../../../projects/core/src/ngx-easy-i18n-js-core.ts"],"sourcesContent":["import { Observable, of } from 'rxjs';\r\nimport { EasyI18nMessages } from 'easy-i18n-js/lib/easy-i18n';\r\nimport { Injectable } from '@angular/core';\r\n\r\nexport abstract class EasyI18nLoader {\r\n /**\r\n * Return messages with locale\r\n * @param locale\r\n */\r\n public abstract getMessages(locale: string): Observable<EasyI18nMessages>;\r\n}\r\n\r\n/**\r\n * This loader is just a placeholder that does nothing, in case you don't need a loader at all\r\n */\r\n@Injectable()\r\nexport class EmptyEasyI18nLoader extends EasyI18nLoader {\r\n\r\n public getMessages(locale: string): Observable<EasyI18nMessages> {\r\n return of({});\r\n }\r\n}","import { defer, Observable, of } from 'rxjs';\r\nimport { Injectable } from '@angular/core';\r\n\r\nexport abstract class EasyI18nStore {\r\n /**\r\n * Return stored culture\r\n */\r\n public abstract get(): Observable<string | null>;\r\n\r\n public abstract save(locale: string): Observable<boolean>;\r\n}\r\n\r\n/**\r\n * This store, get stored culture\r\n */\r\n@Injectable()\r\nexport class EmptyEasyI18nStore extends EasyI18nStore {\r\n\r\n public override get(): Observable<string | null> {\r\n return of(null);\r\n }\r\n\r\n public override save(locale: string): Observable<boolean> {\r\n return of(true);\r\n }\r\n}\r\n\r\n/**\r\n * Use localStorage\r\n */\r\nexport class LocalStorageEasyI18nStore extends EasyI18nStore {\r\n\r\n constructor(\r\n private readonly key: string\r\n ) {\r\n super();\r\n }\r\n\r\n public override get(): Observable<string | null> {\r\n return defer(() => of(localStorage.getItem(this.key)));\r\n }\r\n\r\n public override save(locale: string): Observable<boolean> {\r\n return defer(() => {\r\n localStorage.setItem(this.key, locale);\r\n return of(true);\r\n });\r\n }\r\n}","import { DestroyRef, Inject, Injectable, InjectionToken } from '@angular/core';\r\nimport { registerLocaleData } from '@angular/common';\r\nimport { BehaviorSubject, filter, firstValueFrom, forkJoin, Observable, of, ReplaySubject, switchMap } from 'rxjs';\r\nimport { EasyI18nOptions, installEasyI18n, setEasyI18nMessages } from 'easy-i18n-js';\r\nimport * as lodash from 'lodash';\r\nimport { EasyI18nLoader } from './easy-i18n.loader';\r\nimport { catchError, map, tap } from 'rxjs/operators';\r\nimport { EasyI18nStore } from './easy-i18n.store';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { EasyI18nMessages } from 'easy-i18n-js/lib/easy-i18n';\r\n\r\nexport const EASY_I18N_OPTIONS = new InjectionToken<EasyI18nOptions>('EASY_I18N_OPTIONS');\r\nexport const NG_LOCALES = new InjectionToken<{ [key: string]: any; }>('NG_LOCALES');\r\nexport const USE_BROWSER_LANGUAGE = new InjectionToken<boolean>('USE_BROWSER_LANGUAGE');\r\nexport const DEFAULT_LANGUAGE = new InjectionToken<string>('DEFAULT_LANGUAGE');\r\nexport const FALLBACK_LANGUAGE = new InjectionToken<string>('FALLBACK_LANGUAGE');\r\nexport const DISCOVER = new InjectionToken<string>('DISCOVER');\r\n\r\nexport type LocaleStatus = 'none' | 'loading' | 'ready';\r\n\r\nconst cultureRegex = new RegExp('^([a-z]{2,3})(?:-([A-Z]{2,3})(?:-([a-zA-Z]{4}))?)?$');\r\n\r\nfunction getPossibleLocales(culture: string | undefined, discover: 'exact' | 'minimum' | 'all'): string[] {\r\n if (!culture) {\r\n return [];\r\n }\r\n\r\n if (discover === 'exact') {\r\n return [culture];\r\n }\r\n const match = culture.match(cultureRegex);\r\n\r\n if (discover === 'minimum') {\r\n return lodash.compact([match?.[1]]);\r\n }\r\n\r\n return lodash.compact(lodash.uniq([match?.[0], lodash.compact([match?.[1], match?.[2]]).join('-'), match?.[1]]));\r\n}\r\n\r\n@Injectable()\r\nexport class EasyI18nService {\r\n\r\n private _localeStatusSubject = new BehaviorSubject<LocaleStatus>('none');\r\n private _localeSubject = new ReplaySubject<string>(1);\r\n\r\n // Get status observable of loading locale\r\n public get localeStatus$(): Observable<LocaleStatus> {\r\n return this._localeStatusSubject.asObservable();\r\n }\r\n\r\n // Get locale observable\r\n public get locale$(): Observable<string> {\r\n return this._localeSubject.asObservable();\r\n }\r\n\r\n private _currentLocale: string | null = null;\r\n\r\n // Current locale\r\n get currentLocale(): string | null {\r\n return this._currentLocale;\r\n }\r\n\r\n private _ngLocale: string | null = null;\r\n\r\n // Current Angular locale\r\n get ngLocale(): string | null {\r\n return this._ngLocale;\r\n }\r\n\r\n private readonly otherLoaders: EasyI18nLoader[] = [];\r\n\r\n private currentMsg: EasyI18nMessages = {};\r\n\r\n constructor(\r\n @Inject(EASY_I18N_OPTIONS) private options: EasyI18nOptions,\r\n @Inject(NG_LOCALES) private ngLocales: { [key: string]: any; },\r\n @Inject(USE_BROWSER_LANGUAGE) private useBrowserLanguage: boolean,\r\n @Inject(DEFAULT_LANGUAGE) private defaultLanguage: string,\r\n @Inject(FALLBACK_LANGUAGE) private fallbackLanguage: string,\r\n @Inject(DISCOVER) private discover: 'exact' | 'minimum' | 'all',\r\n private loader: EasyI18nLoader,\r\n private store: EasyI18nStore,\r\n private destroyRef: DestroyRef\r\n ) {\r\n installEasyI18n(options);\r\n }\r\n\r\n public async initialize() {\r\n this._localeSubject.asObservable().pipe(\r\n takeUntilDestroyed(this.destroyRef),\r\n tap(() => this._localeStatusSubject.next('loading')),\r\n switchMap(culture => {\r\n const ngLocale = getPossibleLocales(culture, 'all').find(l => this.ngLocales?.[l]);\r\n if (ngLocale != null) {\r\n registerLocaleData(this.ngLocales[ngLocale]);\r\n\r\n this._ngLocale = ngLocale;\r\n } else {\r\n console.warn(`Not found locale data for currentLocale ${culture}`);\r\n\r\n if (culture !== (this.fallbackLanguage ?? this.defaultLanguage)) {\r\n const defaultNgLocale = getPossibleLocales(this.fallbackLanguage ?? this.defaultLanguage, 'all').find(l => this.ngLocales?.[l]);\r\n if (defaultNgLocale != null) {\r\n console.warn(`Use locale data with ${this.fallbackLanguage ?? this.defaultLanguage}`);\r\n registerLocaleData(this.ngLocales[defaultNgLocale]);\r\n\r\n this._ngLocale = defaultNgLocale;\r\n } else {\r\n console.warn(`Not found locale data for defaultLanguage ${this.fallbackLanguage ?? this.defaultLanguage}`);\r\n\r\n this._ngLocale = null;\r\n }\r\n }\r\n }\r\n\r\n const locales = lodash.uniq(\r\n [...getPossibleLocales(culture, this.discover), ...getPossibleLocales(this.fallbackLanguage ?? this.defaultLanguage, this.discover)]\r\n );\r\n\r\n return forkJoin(\r\n locales.flatMap(locale =>\r\n [\r\n this.loader.getMessages(locale).pipe(\r\n catchError(() => {\r\n return of({});\r\n })\r\n ),\r\n ...this.otherLoaders.map(l =>\r\n l.getMessages(locale).pipe(\r\n catchError(() => {\r\n return of({});\r\n })\r\n )\r\n )\r\n ]\r\n )\r\n ).pipe(\r\n map(res => lodash.defaultsDeep({}, ...lodash.compact(res))),\r\n tap(msg => {\r\n this.currentMsg = msg ?? {};\r\n\r\n setEasyI18nMessages(this.currentMsg, culture);\r\n\r\n this._currentLocale = lodash.head(locales) ?? culture;\r\n })\r\n );\r\n }),\r\n tap(() => this._localeStatusSubject.next('ready')),\r\n ).subscribe();\r\n\r\n this.store.get().pipe(\r\n takeUntilDestroyed(this.destroyRef),\r\n tap(stored => {\r\n const culture = stored ?? (this.useBrowserLanguage ? this.getBrowserCulture() : null) ?? this.defaultLanguage;\r\n if (!culture || !cultureRegex.test(culture)) {\r\n console.error(`Culture ${culture} is wrong format`);\r\n return;\r\n }\r\n this._localeSubject.next(culture);\r\n })\r\n ).subscribe();\r\n\r\n return firstValueFrom(this._localeStatusSubject.asObservable().pipe(\r\n filter(s => s === 'ready')\r\n ));\r\n }\r\n\r\n /**\r\n * Get plain message by key\r\n *\r\n * @param key key\r\n */\r\n public getPlainMessage(key: string): string | EasyI18nMessages | undefined {\r\n return lodash.get(this.currentMsg, key);\r\n }\r\n\r\n /**\r\n * Change current culture\r\n *\r\n * @param culture new culture\r\n * @param options\r\n */\r\n public registerCulture(culture: string, options?: {\r\n reload?: boolean;\r\n }): void {\r\n if (!culture || !cultureRegex.test(culture)) {\r\n console.error(`Culture ${culture} is wrong format`);\r\n return;\r\n }\r\n\r\n this.store.save(culture).pipe(\r\n tap(() => {\r\n if (options?.reload) {\r\n location.reload();\r\n } else {\r\n this._localeSubject.next(culture);\r\n }\r\n })\r\n ).subscribe();\r\n }\r\n\r\n /**\r\n * Get browser culture\r\n */\r\n public getBrowserCulture(): string | null {\r\n if (typeof window === 'undefined' || typeof window.navigator === 'undefined') {\r\n return null;\r\n }\r\n\r\n let browserCultureLang: any = window.navigator.languages ? window.navigator.languages[0] : null;\r\n return browserCultureLang ?? window.navigator.language ??\r\n (window.navigator as any).browserLanguage ?? (window.navigator as any).userLanguage;\r\n }\r\n\r\n public async appendLoader(loader: EasyI18nLoader) {\r\n this.otherLoaders.push(loader);\r\n\r\n return firstValueFrom(this._localeStatusSubject.asObservable().pipe(\r\n filter(s => s === 'ready'),\r\n switchMap(() => {\r\n const locales = lodash.uniq(\r\n [...getPossibleLocales(this._currentLocale!, this.discover), ...getPossibleLocales(this.fallbackLanguage ?? this.defaultLanguage, this.discover)]\r\n );\r\n\r\n return forkJoin(\r\n locales.map(locale =>\r\n loader.getMessages(locale).pipe(\r\n catchError(() => {\r\n return of({});\r\n })\r\n )\r\n )\r\n ).pipe(\r\n map(res => lodash.defaultsDeep(this.currentMsg, ...lodash.compact(res))),\r\n tap(msg => {\r\n setEasyI18nMessages(msg, this._currentLocale!);\r\n }),\r\n map(() => true)\r\n )\r\n })\r\n ), {\r\n defaultValue: false\r\n });\r\n }\r\n}\r\n","import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core';\r\nimport { EasyI18nService } from './easy-i18n.service';\r\nimport { formatDate } from '@angular/common';\r\n\r\n@Pipe({\r\n name: 'localeDate',\r\n standalone: true\r\n})\r\nexport class LocaleDatePipe implements PipeTransform {\r\n\r\n constructor(\r\n private easyI18nService: EasyI18nService,\r\n @Inject(LOCALE_ID) private localeId: string\r\n ) {\r\n }\r\n\r\n transform(value: string | number | Date, format: string, timezone?: string): string {\r\n return formatDate(value, format, this.easyI18nService.ngLocale ?? this.localeId, timezone);\r\n }\r\n}\r\n","import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core';\r\nimport { EasyI18nService } from './easy-i18n.service';\r\nimport { formatNumber } from '@angular/common';\r\n\r\n@Pipe({\r\n name: 'localeNumber',\r\n standalone: true\r\n})\r\nexport class LocaleNumberPipe implements PipeTransform {\r\n\r\n constructor(\r\n private easyI18nService: EasyI18nService,\r\n @Inject(LOCALE_ID) private localeId: string\r\n ) {\r\n }\r\n\r\n transform(value: number, digitsInfo?: string): string {\r\n return formatNumber(value, this.easyI18nService.ngLocale ?? this.localeId, digitsInfo);\r\n }\r\n}\r\n","import { Directive, ElementRef, Input, OnDestroy } from '@angular/core';\r\nimport * as lodash from 'lodash';\r\nimport { tr, TrOptions } from 'easy-i18n-js';\r\n\r\n@Directive({\r\n selector: '[tr]',\r\n standalone: true\r\n})\r\nexport class TrDirective implements OnDestroy {\r\n\r\n @Input()\r\n set trKey(key: string) {\r\n if (key !== this.currentKey) {\r\n this.currentKey = key;\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n @Input()\r\n set trNamespace(namespace: string) {\r\n if (namespace !== this.currentParams?.namespace) {\r\n this.currentParams = {\r\n ...(this.currentParams ?? {}),\r\n namespace\r\n };\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n @Input()\r\n set trGender(gender: 'male' | 'female' | 'other') {\r\n if (gender !== this.currentParams?.gender) {\r\n this.currentParams = {\r\n ...(this.currentParams ?? {}),\r\n gender\r\n };\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n @Input()\r\n set trArgs(args: string[]) {\r\n if (!lodash.isEqual(args, this.currentParams?.args)) {\r\n this.currentParams = {\r\n ...(this.currentParams ?? {}),\r\n args\r\n };\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n @Input()\r\n set trNamedArgs(namedArgs: Record<string, string>) {\r\n if (!lodash.isEqual(namedArgs, this.currentParams?.namedArgs)) {\r\n this.currentParams = {\r\n ...(this.currentParams ?? {}),\r\n namedArgs\r\n };\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n private currentKey?: string;\r\n\r\n private currentParams?: TrOptions;\r\n private lastParams?: TrOptions;\r\n\r\n private changes: MutationObserver;\r\n\r\n constructor(\r\n private el: ElementRef<HTMLElement>\r\n ) {\r\n this.changes = new MutationObserver(() => {\r\n this.render();\r\n });\r\n\r\n this.changes.observe(el.nativeElement, {\r\n childList: true,\r\n characterData: true,\r\n subtree: true\r\n });\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.changes.disconnect();\r\n }\r\n\r\n private render(paramsOnly = false): void {\r\n const nodes: NodeList = this.el.nativeElement.childNodes;\r\n\r\n nodes.forEach((node: any) => {\r\n if (node.nodeType === 3) { // Seulement les node de type 3, text\r\n if (node.lookupKey != null) {\r\n this.updateValue(node.lookupKey, node);\r\n } else if (this.currentKey != null) {\r\n this.updateValue(this.currentKey, this.el.nativeElement);\r\n } else {\r\n let key: string | null = null;\r\n const content = this.getContent(node);\r\n node.lookupKey = content.trim();\r\n\r\n // Si le contenu actuel est différent de la valeur traduite, la clef a changé\r\n if (content !== node.currentValue) {\r\n key = node.lookupKey;\r\n // On stocke la valeur originale qui doit ête la clef\r\n node.originalContent = content ?? node.originalContent;\r\n } else if (node.originalContent && paramsOnly) { // Le contenu actuel est la version traduite, si on a l'original\r\n // On prend la clef originale et on va vérifier si un paramètre a changé\r\n key = node.originalContent.trim();\r\n }\r\n\r\n this.updateValue(key, node);\r\n }\r\n }\r\n });\r\n }\r\n\r\n private updateValue(key: string | null, node: any): void {\r\n if (!key) {\r\n return;\r\n }\r\n\r\n // Si rien n'a changé on arrête\r\n if (node.lastKey === key && this.lastParams === this.currentParams) {\r\n return;\r\n }\r\n\r\n node.lastKey = key;\r\n this.lastParams = this.currentParams;\r\n\r\n if (!node.originalContent) {\r\n node.originalContent = this.getContent(node);\r\n }\r\n\r\n const res = tr(key, this.currentParams);\r\n\r\n if (this.currentKey && res === key) {\r\n return;\r\n }\r\n\r\n node.currentValue = res ?? node.originalContent ?? key;\r\n this.setContent(node, this.currentKey ? node.currentValue : node.originalContent.replace(key, node.currentValue));\r\n }\r\n\r\n private getContent(node: any): string {\r\n return node.textContent != null ? node.textContent : node.data;\r\n }\r\n\r\n private setContent(node: any, content: string): void {\r\n if (node.textContent != null) {\r\n node.textContent = content;\r\n } else {\r\n node.data = content;\r\n }\r\n }\r\n}\r\n","import { Pipe, PipeTransform } from '@angular/core';\r\nimport { tr, TrOptions } from 'easy-i18n-js';\r\n\r\n@Pipe({\r\n name: 'tr',\r\n standalone: true\r\n})\r\nexport class TrPipe implements PipeTransform {\r\n\r\n transform(text: string, options?: TrOptions): string {\r\n if (!text) {\r\n return text;\r\n }\r\n return tr(text, options);\r\n }\r\n\r\n}\r\n","import { Pipe, PipeTransform } from '@angular/core';\r\nimport { plural, PluralOptions } from 'easy-i18n-js';\r\n\r\n@Pipe({\r\n name: 'plural',\r\n standalone: true\r\n})\r\nexport class PluralPipe implements PipeTransform {\r\n\r\n transform(text: string, value: number, options?: PluralOptions): string {\r\n if (!text) {\r\n return text;\r\n }\r\n return plural(text, value, options);\r\n }\r\n\r\n}\r\n","import { Directive, ElementRef, Input, OnDestroy } from '@angular/core';\r\nimport * as lodash from 'lodash';\r\nimport { plural, PluralOptions } from 'easy-i18n-js';\r\n\r\n@Directive({\r\n selector: '[plural]',\r\n standalone: true\r\n})\r\nexport class PluralDirective implements OnDestroy {\r\n\r\n @Input('plural')\r\n set plural(value: number) {\r\n if (value !== this.currentValue) {\r\n this.currentValue = value;\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n @Input()\r\n set pluralKey(key: string) {\r\n if (key !== this.currentKey) {\r\n this.currentKey = key;\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n @Input()\r\n set pluralNamespace(namespace: string) {\r\n if (namespace !== this.currentParams?.namespace) {\r\n this.currentParams = {\r\n ...(this.currentParams ?? {}),\r\n namespace\r\n };\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n @Input()\r\n set pluralGender(gender: 'male' | 'female' | 'other') {\r\n if (gender !== this.currentParams?.gender) {\r\n this.currentParams = {\r\n ...(this.currentParams ?? {}),\r\n gender\r\n };\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n @Input()\r\n set pluralArgs(args: string[]) {\r\n if (!lodash.isEqual(args, this.currentParams?.args)) {\r\n this.currentParams = {\r\n ...(this.currentParams ?? {}),\r\n args\r\n };\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n @Input()\r\n set pluralNamedArgs(namedArgs: Record<string, string>) {\r\n if (!lodash.isEqual(namedArgs, this.currentParams?.namedArgs)) {\r\n this.currentParams = {\r\n ...(this.currentParams ?? {}),\r\n namedArgs\r\n };\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n @Input('pluralName')\r\n set pluralName(name: string) {\r\n if (name !== this.currentParams?.name) {\r\n this.currentParams = {\r\n ...(this.currentParams ?? {}),\r\n name\r\n };\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n @Input('pluralNumberFormatterFn')\r\n set pluralNumberFormatterFn(numberFormatterFn: (value: number) => string) {\r\n if (numberFormatterFn !== this.currentParams?.numberFormatterFn) {\r\n this.currentParams = {\r\n ...(this.currentParams ?? {}),\r\n numberFormatterFn\r\n };\r\n\r\n this.render(true);\r\n }\r\n }\r\n\r\n private currentKey?: string;\r\n\r\n private currentValue?: number;\r\n private lastValue?: number;\r\n\r\n private currentParams?: PluralOptions;\r\n private lastParams?: PluralOptions;\r\n\r\n private changes: MutationObserver;\r\n\r\n constructor(\r\n private el: ElementRef<HTMLElement>\r\n ) {\r\n this.changes = new MutationObserver(() => {\r\n this.render();\r\n });\r\n\r\n this.changes.observe(el.nativeElement, {\r\n childList: true,\r\n characterData: true,\r\n subtree: true\r\n });\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.changes.disconnect();\r\n }\r\n\r\n private render(paramsOnly = false): void {\r\n const nodes: NodeList = this.el.nativeElement.childNodes;\r\n\r\n if (this.currentKey) {\r\n this.updateValue(this.currentKey, this.el.nativeElement);\r\n } else {\r\n nodes.forEach((node: any) => {\r\n if (node.nodeType === 3) { // Seulement les node de type 3, text\r\n let key: string | null = null;\r\n const content = this.getContent(node);\r\n // Si le contenu actuel est différent de la valeur traduite, la clef a changé\r\n if (content !== node.currentValue) {\r\n key = content.trim();\r\n // On stocke la valeur originale qui doit ête la clef\r\n node.originalContent = content ?? node.originalContent;\r\n } else if (node.originalContent && paramsOnly) { // Le contenu actuel est la version traduite, si on a l'original\r\n // On prend la clef originale et on va vérifier si un paramètre a changé\r\n key = node.originalContent.trim();\r\n }\r\n\r\n this.updateValue(key, node);\r\n }\r\n });\r\n }\r\n }\r\n\r\n private updateValue(key: string | null, node: any): void {\r\n if (!key) {\r\n return;\r\n }\r\n\r\n // Si rien n'a changé on arrête\r\n if (node.lastKey === key && this.currentValue === this.lastValue && this.lastParams === this.currentParams) {\r\n return;\r\n }\r\n\r\n node.lastKey = key;\r\n this.lastValue = this.currentValue;\r\n this.lastParams = this.currentParams;\r\n\r\n if (!node.originalContent) {\r\n node.originalContent = this.getContent(node);\r\n }\r\n\r\n const res = this.currentValue != null ? plural(key, this.currentValue, this.currentParams) : '';\r\n\r\n // Même clef, donc non traduit\r\n if (this.currentKey && res === key) {\r\n return;\r\n }\r\n\r\n node.currentValue = res ?? node.originalContent ?? key;\r\n this.setContent(node, this.currentKey ? node.currentValue : node.originalContent.replace(key, node.currentValue));\r\n }\r\n\r\n private getContent(node: any): string {\r\n return node.textContent != null ? node.textContent : node.data;\r\n }\r\n\r\n private setContent(node: any, content: string): void {\r\n if (node.textContent != null) {\r\n node.textContent = content;\r\n } else {\r\n node.data = content;\r\n }\r\n }\r\n}\r\n","import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core';\r\nimport { EasyI18nService } from './easy-i18n.service';\r\nimport { formatPercent } from '@angular/common';\r\n\r\n@Pipe({\r\n name: 'localePercent',\r\n standalone: true\r\n})\r\nexport class LocalePercentPipe implements PipeTransform {\r\n\r\n constructor(\r\n private easyI18nService: EasyI18nService,\r\n @Inject(LOCALE_ID) private localeId: string\r\n ) {\r\n }\r\n\r\n transform(value: number, digitsInfo?: string): string {\r\n return formatPercent(value, this.easyI18nService.ngLocale ?? this.localeId, digitsInfo);\r\n }\r\n}\r\n","import { DEFAULT_CURRENCY_CODE, Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core';\r\nimport { EasyI18nService } from './easy-i18n.service';\r\nimport { formatCurrency, getCurrencySymbol } from '@angular/common';\r\n\r\n@Pipe({\r\n name: 'localeCurrency',\r\n standalone: true\r\n})\r\nexport class LocaleCurrencyPipe implements PipeTransform {\r\n\r\n constructor(\r\n private easyI18nService: EasyI18nService,\r\n @Inject(LOCALE_ID) private localeId: string,\r\n @Inject(DEFAULT_CURRENCY_CODE) private defaultCurrencyCode: string = 'USD'\r\n ) {\r\n }\r\n\r\n transform(value: number, currencyCode?: string, display: 'symbol' | 'symbol-narrow' | 'code' | string = 'symbol', digitsInfo?: string): string {\r\n const locale = this.easyI18nService.ngLocale ?? this.localeId;\r\n\r\n let currency: string = currencyCode ?? this.defaultCurrencyCode;\r\n if (display !== 'code') {\r\n if (display === 'symbol' || display === 'symbol-narrow') {\r\n currency = getCurrencySymbol(currency, display === 'symbol' ? 'wide' : 'narrow', locale);\r\n } else {\r\n currency = display;\r\n }\r\n }\r\n return formatCurrency(value, locale, currency, currencyCode, digitsInfo);\r\n }\r\n}\r\n","import {\n AfterContentInit,\n ChangeDetectorRef,\n ContentChildren,\n Directive,\n Input,\n OnDestroy,\n QueryList,\n Renderer2,\n TemplateRef,\n ViewContainerRef\n} from '@angular/core';\nimport { BehaviorSubject, merge, Subscription } from 'rxjs';\nimport { plural, PluralOptions } from 'easy-i18n-js';\nimport * as lodash from 'lodash';\n\n@Directive({\n selector: '[pluralElement]',\n standalone: true\n})\nexport class PluralElementDirective {\n\n @Input('pluralElement')\n public elementKey?: string;\n\n constructor(\n public readonly viewRef: ViewContainerRef,\n public readonly templateRef: TemplateRef<any>,\n ) {\n }\n}\n\n@Directive({\n selector: '[pluralContent]',\n standalone: true\n})\nexport class PluralContentDirective implements AfterContentInit, OnDestroy {\n\n @ContentChildren(PluralElementDirective)\n private elements?: QueryList<PluralElementDirective>;\n\n @Input('pluralContent')\n set pluralContent(key: string) {\n if (key !== this.currentKey) {\n this.currentKey = key;\n\n this.render();\n }\n }\n\n @Input('pluralValue')\n set pluralValue(value: number) {\n if (value !== this.currentValue) {\n this.currentValue = value;\n\n this.render();\n }\n }\n\n @Input()\n set pluralNamespace(namespace: string) {\n if (namespace !== this.currentParams?.namespace) {\n this.currentParams = {\n ...(this.currentParams ?? {}),\n namespace\n };\n\n this.render();\n }\n }\n\n @Input()\n set pluralGender(gender: 'male' | 'female' | 'other') {\n if (gender !== this.currentParams?.gender) {\n this.currentParams = {\n ...(this.currentParams ?? {}),\n gender\n };\n\n this.render();\n }\n }\n\n @Input()\n set pluralArgs(args: string[]) {\n if (!lodash.isEqual(args, this.currentParams?.args)) {\n this.currentParams = {\n ...(this.currentParams ?? {}),\n args\n };\n\n this.render();\n }\n }\n\n @Input()\n set pluralNamedArgs(namedArgs: Record<string, string>) {\n if (!lodash.isEqual(namedArgs, this.currentParams?.namedArgs)) {\n this.currentParams = {\n ...(this.currentParams ?? {}),\n namedArgs\n };\n\n this.render();\n }\n }\n\n @Input('pluralName')\n set pluralName(name: string) {\n if (name !== this.currentParams?.name) {\n this.currentParams = {\n ...(this.currentParams ?? {}),\n name\n };\n\n this.render();\n }\n }\n\n @Input('pluralNumberFormatterFn')\n set pluralNumberFormatterFn(numberFormatterFn: (value: number) => string) {\n if (numberFormatterFn !== this.currentParams?.numberFormatterFn) {\n this.currentParams = {\n ...(this.currentParams ?? {}),\n numberFormatterFn\n };\n\n this.render();\n }\n }\n\n @Input()\n set demarc(demarc: { start: string; end: string; }) {\n if (!lodash.isEqual(demarc, this._demarc)) {\n this.demarc = {\n ...this._demarc,\n ...demarc\n };\n\n this.render();\n }\n }\n\n private currentKey?: string;\n private currentValue?: number;\n private currentParams?: PluralOptions;\n\n private _demarc: { start: string; end: string; } = { start: '{', end: '}' };\n\n private subscription?: Subscription;\n\n constructor(\n private viewRef: ViewContainerRef,\n private renderer: Renderer2,\n private changeDetectorRef: ChangeDetectorRef,\n ) {\n }\n\n ngAfterContentInit(): void {\n if (this.elements) {\n this.subscription = merge(\n new BehaviorSubject(this.elements.toArray()),\n this.elements.changes\n ).subscribe(next => this.render());\n }\n }\n\n ngOnDestroy(): void {\n this.subscription?.unsubscribe();\n }\n\n private render(): void {\n if (this.elements == null || !this.currentKey || this.currentValue == null || !this._demarc?.start || !this._demarc?.end) {\n return;\n }\n\n this.viewRef.clear();\n\n const childElements = this.viewRef.element.nativeElement.children;\n for (const child of childElements) {\n this.renderer.removeChild(this.viewRef.element.nativeElement, child);\n }\n this.viewRef.element.nativeElement.textContent = '';\n\n const raw = plural(this.currentKey, this.currentValue, this.currentParams);\n\n let lastTokenEnd = 0;\n while (lastTokenEnd < raw.length) {\n const tokenStartDemarc = raw.indexOf(this._demarc?.start, lastTokenEnd);\n if (tokenStartDemarc < 0) {\n break;\n }\n const tokenStart = tokenStartDemarc + this._demarc?.start.length;\n const tokenEnd = raw.indexOf(this._demarc?.end, tokenStart);\n if (tokenEnd < 0) {\n throw new Error(`Encountered unterminated token in translation string '${this.currentKey}'`);\n }\n const tokenEndDemarc = tokenEnd + this._demarc?.end.length;\n\n const precedingText = raw.substring(lastTokenEnd, tokenStartDemarc);\n const precedingTextElement = this.renderer.createText(precedingText.replace(/ /g, '\\u00A0'));\n this.renderer.appendChild(this.viewRef.element.nativeElement, precedingTextElement);\n\n const elementKey = raw.substring(tokenStart, tokenEnd);\n const embeddedElementTemplate = this.elements.toArray().find(element => element.elementKey === elementKey);\n if (embeddedElementTemplate) {\n const embeddedElementView = embeddedElementTemplate.viewRef.createEmbeddedView(embeddedElementTemplate.templateRef);\n this.renderer.appendChild(this.viewRef.element.nativeElement, embeddedElementView.rootNodes[0]);\n } else {\n const missingTokenText = raw.substring(tokenStartDemarc, tokenEndDemarc);\n const missingTokenElement = this.renderer.createText(missingTokenText);\n this.renderer.appendChild(this.viewRef.element.nativeElement, missingTokenElement);\n }\n\n lastTokenEnd = tokenEndDemarc;\n }\n\n const trailingText = raw.substring(lastTokenEnd);\n const trailingTextElement = this.renderer.createText(trailingText.replace(/ /g, '\\u00A0'));\n this.renderer.appendChild(this.viewRef.element.nativeElement, trailingTextElement);\n\n this.changeDetectorRef.detectChanges();\n }\n}\n","import {\n AfterContentInit,\n ChangeDetectorRef,\n ContentChildren,\n Directive,\n Input,\n OnDestroy,\n QueryList,\n Renderer2,\n TemplateRef,\n ViewContainerRef\n} from '@angular/core';\nimport { BehaviorSubject, merge, Subscription } from 'rxjs';\nimport { tr, TrOptions } from 'easy-i18n-js';\nimport * as lodash from 'lodash';\n\n@Directive({\n selector: '[trElement]',\n standalone: true\n})\nexport class TrElementDirective {\n\n @Input('trElement')\n public elementKey?: string;\n\n constructor(\n public readonly viewRef: ViewContainerRef,\n public readonly templateRef: TemplateRef<any>,\n ) {\n }\n}\n\n@Directive({\n selector: '[trContent]',\n standalone: true\n})\nexport class TrContentDirective implements AfterContentInit, OnDestroy {\n\n @ContentChildren(TrElementDirective)\n private elements?: QueryList<TrElementDirective>;\n\n @Input('trContent')\n set trContent(key: string) {\n if (key !== this.currentKey) {\n this.currentKey = key;\n\n this.render();\n }\n }\n\n @Input()\n set trNamespace(namespace: string) {\n if (namespace !== this.currentParams?.namespace) {\n this.currentParams = {\n ...(this.currentParams ?? {}),\n namespace\n };\n\n this.render();\n }\n }\n\n @Input()\n set trGender(gender: 'male' | 'female' | 'other') {\n if (gender !== this.currentParams?.gender) {\n this.currentParams = {\n ...(this.currentParams ?? {}),\n gender\n };\n\n this.render();\n }\n }\n\n @Input()\n set trArgs(args: string[]) {\n if (!lodash.isEqual(args, this.currentParams?.args)) {\n this.currentParams = {\n ...(this.currentParams ?? {}),\n args\n };\n\n this.render();\n }\n }\n\n @Input()\n set trNamedArgs(namedArgs: Record<string, string>) {\n if (!lodash.isEqual(namedArgs, this.currentParams?.namedArgs)) {\n this.currentParams = {\n ...(this.currentParams ?? {}),\n namedArgs\n };\n\n this.render();\n }\n }\n\n @Input()\n set demarc(demarc: { start: string; end: string; }) {\n if (!lodash.isEqual(demarc, this._demarc)) {\n this.demarc = {\n ...this._demarc,\n ...demarc\n };\n\n this.render();\n }\n }\n\n private currentKey?: string;\n private currentParams?: TrOptions;\n\n private _demarc: { start: string; end: string; } = { start: '{', end: '}' };\n\n private subscription?: Subscription;\n\n constructor(\n private viewRef: ViewContainerRef,\n private renderer: Renderer2,\n private changeDetectorRef: ChangeDetectorRef,\n ) {\n }\n\n ngAfterContentInit(): void {\n if (this.elements) {\n this.subscription = merge(\n new BehaviorSubject(this.elements.toArray()),\n this.elements.changes\n ).subscribe(next => this.render());\n }\n }\n\n ngOnDestroy(): void {\n this.subscription?.unsubscribe();\n }\n\n private render(): void {\n if (this.elements == null || !this.currentKey || !this._demarc?.start || !this._demarc?.end) {\n return;\n }\n\n this.viewRef.clear();\n\n const childElements = this.viewRef.element.nativeElement.children;\n for (const child of childElements) {\n this.renderer.removeChild(this.viewRef.element.nativeElement, child);\n }\n this.viewRef.element.nativeElement.textContent = '';\n\n const raw = tr(this.currentKey, this.currentParams);\n\n let lastTokenEnd = 0;\n while (lastTokenEnd < raw.length) {\n const tokenStartDemarc = raw.indexOf(this._demarc?.start, lastTokenEnd);\n if (tokenStartDemarc < 0) {\n break;\n }\n const tokenStart = tokenStartDemarc + this._demarc?.start.length;\n const tokenEnd = raw.indexOf(this._demarc?.end, tokenStart);\n if (tokenEnd < 0) {\n throw new Error(`Encountered unterminated token in translation string '${this.currentKey}'`);\n }\n const tokenEndDemarc = tokenEnd + this._demarc?.end.length;\n\n const precedingText = raw.substring(lastTokenEnd, tokenStartDemarc);\n const precedingTextElement = this.renderer.createText(precedingText.replace(/ /g, '\\u00A0'));\n this.renderer.appendChild(this.viewRef.element.nativeElement, precedingTextElement);\n\n const elementKey = raw.substring(tokenStart, tokenEnd);\n const embeddedElementTemplate = this.elements.toArray().find(element => element.elementKey === elementKey);\n if (embeddedElementTemplate) {\n const embeddedElementView = embeddedElementTemplate.viewRef.createEmbeddedView(embeddedElementTemplate.templateRef);\n this.renderer.appendChild(this.viewRef.element.nativeElement, embeddedElementView.rootNodes[0]);\n } else {\n const missingTokenText = raw.substring(tokenStartDemarc, tokenEndDemarc);\n const missingTokenElement = this.renderer.createText(missingTokenText);\n this.renderer.appendChild(this.viewRef.element.nativeElement, missingTokenElement);\n }\n\n lastTokenEnd = tokenEndDemarc;\n }\n\n const trailingText = raw.substring(lastTokenEnd);\n const trailingTextElement = this.renderer.createText(trailingText.replace(/ /g, '\\u00A0'));\n this.renderer.appendChild(this.viewRef.element.nativeElement, trailingTextElement);\n\n this.changeDetectorRef.detectChanges();\n }\n}\n","import { ModuleWithProviders, NgModule, Provider, inject, provideAppInitializer, EnvironmentProviders } from '@angular/core';\r\nimport { LocaleDatePipe } from './lib/locale-date.pipe';\r\nimport { LocaleNumberPipe } from './lib/locale-number.pipe';\r\nimport { TrDirective } from './lib/tr.directive';\r\nimport { TrPipe } from './lib/tr.pipe';\r\nimport { PluralPipe } from './lib/plural.pipe';\r\nimport { PluralDirective } from './lib/plural.directive';\r\nimport { LocalePercentPipe } from './lib/locale-percent.pipe';\r\nimport { LocaleCurrencyPipe } from './lib/locale-currency.pipe';\r\nimport { EasyI18nOptions } from 'easy-i18n-js';\r\nimport {\r\n DEFAULT_LANGUAGE,\r\n DISCOVER,\r\n EASY_I18N_OPTIONS,\r\n EasyI18nService,\r\n FALLBACK_LANGUAGE,\r\n NG_LOCALES,\r\n USE_BROWSER_LANGUAGE\r\n} from './lib/easy-i18n.service';\r\nimport { EasyI18nLoader, EmptyEasyI18nLoader } from './lib/easy-i18n.loader';\r\nimport { PluralContentDirective, PluralElementDirective } from './lib/plural-content.directive';\r\nimport { TrContentDirective, TrElementDirective } from './lib/tr-content.directive';\r\nimport { EasyI18nStore, EmptyEasyI18nStore } from './lib/easy-i18n.store';\r\n\r\nexport * from './lib/locale-date.pipe';\r\nexport * from './lib/locale-number.pipe';\r\nexport * from './lib/locale-percent.pipe';\r\nexport * from './lib/locale-currency.pipe';\r\nexport * from './lib/tr.pipe';\r\nexport * from './lib/plural.pipe';\r\nexport * from './lib/tr.directive';\r\nexport * from './lib/tr-content.directive';\r\nexport * from './lib/plural.directive';\r\nexport * from './lib/plural-content.directive';\r\nexport * from './lib/easy-i18n.loader';\r\nexport * from './lib/easy-i18n.store';\r\nexport * from './lib/easy-i18n.service';\r\n\r\nexport interface EasyI18nModuleConfig {\r\n /**\r\n * Options fo easy i18 js library\r\n */\r\n options?: EasyI18nOptions;\r\n /**\r\n * Use specific loader\r\n */\r\n loader?: Provider;\r\n /**\r\n * Use specific store\r\n */\r\n store?: Provider;\r\n /**\r\n * Use specific loader\r\n */\r\n ngLocales?: { [key: string]: any; };\r\n /**\r\n * Use browser language\r\n */\r\n useBrowserLanguage?: boolean;\r\n /**\r\n * Default language use if no use browser language\r\n */\r\n defaultLanguage?: string;\r\n /**\r\n * Fallback language use if current language not found\r\n */\r\n fallbackLanguage?: string;\r\n /**\r\n * <code>exact</code> only fr-FR, <code>minimum</code> only fr, <code>all</code> fr-FR and fr\r\n */\r\n discover?: 'exact' | 'minimum' | 'all';\r\n}\r\n\r\n@NgModule({\r\n imports: [\r\n LocaleDatePipe,\r\n LocaleNumberPipe,\r\n TrDirective,\r\n TrPipe,\r\n PluralPipe,\r\n PluralDirective,\r\n LocalePercentPipe,\r\n LocaleCurrencyPipe,\r\n PluralElementDirective,\r\n PluralContentDirective,\r\n TrElementDirective,\r\n TrContentDirective\r\n ],\r\n exports: [\r\n LocaleDatePipe,\r\n LocaleNumberPipe,\r\n TrDirective,\r\n TrPipe,\r\n PluralPipe,\r\n PluralDirective,\r\n LocalePercentPipe,\r\n LocaleCurrencyPipe,\r\n PluralElementDirective,\r\n PluralContentDirective,\r\n TrElementDirective,\r\n TrContentDirective\r\n ]\r\n})\r\nexport class EasyI18nModule {\r\n\r\n /**\r\n * Use this method in your root module to provide the EasyI18nService\r\n */\r\n static forRoot(config: EasyI18nModuleConfig): ModuleWithProviders<EasyI18nModule> {\r\n return {\r\n ngModule: EasyI18nModule,\r\n providers: provideEasyI18n(config)\r\n };\r\n }\r\n}\r\n\r\nexport function provideEasyI18n(config: EasyI18nModuleConfig): Array<Provider | EnvironmentProviders> {\r\n return [\r\n config.loader || { provide: EasyI18nLoader, useClass: EmptyEasyI18nLoader },\r\n config.store || { provide: EasyI18nStore, useClass: EmptyEasyI18nStore },\r\n { provide: EASY_I18N_OPTIONS, useValue: config.options },\r\n { provide: NG_LOCALES, useValue: config.ngLocales },\r\n { provide: USE_BROWSER_LANGUAGE, useValue: config.useBrowserLanguage ?? true },\r\n { provide: DEFAULT_LANGUAGE, useValue: config.defaultLanguage ?? 'en-US' },\r\n { provide: FALLBACK_LANGUAGE, useValue: config.fallbackLanguage },\r\n { provide: DISCOVER, useValue: config.discover ?? 'all' },\r\n EasyI18nService,\r\n provideAppInitializer(() => {\r\n const initializerFn = ((easyI18nService: EasyI18nService) => {\r\n return async () =>\r\n easyI18nService.initialize()\r\n })(inject(EasyI18nService));\r\n return initializerFn();\r\n })\r\n ];\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.EasyI18nLoader","i2.EasyI18nStore","i1.EasyI18nService"],"mappings":"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