@ngx-translate/core
Version:
1,055 lines (1,042 loc) • 41.8 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, EventEmitter, InjectionToken, Inject, Directive, Input, Pipe, NgModule } from '@angular/core';
import { of, isObservable, forkJoin, concat, defer } from 'rxjs';
import { take, shareReplay, map, concatMap, switchMap } from 'rxjs/operators';
class TranslateLoader {
}
/**
* This loader is just a placeholder that does nothing, in case you don't need a loader at all
*/
class TranslateFakeLoader extends TranslateLoader {
getTranslation(lang) {
return of({});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateFakeLoader, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateFakeLoader });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateFakeLoader, decorators: [{
type: Injectable
}] });
class MissingTranslationHandler {
}
/**
* This handler is just a placeholder that does nothing, in case you don't need a missing translation handler at all
*/
class FakeMissingTranslationHandler {
handle(params) {
return params.key;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: FakeMissingTranslationHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: FakeMissingTranslationHandler });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: FakeMissingTranslationHandler, decorators: [{
type: Injectable
}] });
/* tslint:disable */
/**
* Determines if two objects or two values are equivalent.
*
* Two objects or values are considered equivalent if at least one of the following is true:
*
* * Both objects or values pass `===` comparison.
* * Both objects or values are of the same type and all of their properties are equal by
* comparing them with `equals`.
*
* @param o1 Object or value to compare.
* @param o2 Object or value to compare.
* @returns true if arguments are equal.
*/
function equals(o1, o2) {
if (o1 === o2)
return true;
if (o1 === null || o2 === null)
return false;
if (o1 !== o1 && o2 !== o2)
return true; // NaN === NaN
let t1 = typeof o1, t2 = typeof o2, length, key, keySet;
if (t1 == t2 && t1 == 'object') {
if (Array.isArray(o1)) {
if (!Array.isArray(o2))
return false;
if ((length = o1.length) == o2.length) {
for (key = 0; key < length; key++) {
if (!equals(o1[key], o2[key]))
return false;
}
return true;
}
}
else {
if (Array.isArray(o2)) {
return false;
}
keySet = Object.create(null);
for (key in o1) {
if (!equals(o1[key], o2[key])) {
return false;
}
keySet[key] = true;
}
for (key in o2) {
if (!(key in keySet) && typeof o2[key] !== 'undefined') {
return false;
}
}
return true;
}
}
return false;
}
/* tslint:enable */
function isDefined(value) {
return typeof value !== 'undefined' && value !== null;
}
function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item));
}
function mergeDeep(target, source) {
let output = Object.assign({}, target);
if (isObject(target) && isObject(source)) {
Object.keys(source).forEach((key) => {
if (isObject(source[key])) {
if (!(key in target)) {
Object.assign(output, { [key]: source[key] });
}
else {
output[key] = mergeDeep(target[key], source[key]);
}
}
else {
Object.assign(output, { [key]: source[key] });
}
});
}
return output;
}
class TranslateParser {
}
class TranslateDefaultParser extends TranslateParser {
templateMatcher = /{{\s?([^{}\s]*)\s?}}/g;
interpolate(expr, params) {
let result;
if (typeof expr === 'string') {
result = this.interpolateString(expr, params);
}
else if (typeof expr === 'function') {
result = this.interpolateFunction(expr, params);
}
else {
// this should not happen, but an unrelated TranslateService test depends on it
result = expr;
}
return result;
}
getValue(target, key) {
let keys = typeof key === 'string' ? key.split('.') : [key];
key = '';
do {
key += keys.shift();
if (isDefined(target) && isDefined(target[key]) && (typeof target[key] === 'object' || !keys.length)) {
target = target[key];
key = '';
}
else if (!keys.length) {
target = undefined;
}
else {
key += '.';
}
} while (keys.length);
return target;
}
interpolateFunction(fn, params) {
return fn(params);
}
interpolateString(expr, params) {
if (!params) {
return expr;
}
return expr.replace(this.templateMatcher, (substring, b) => {
let r = this.getValue(params, b);
return isDefined(r) ? r : substring;
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateDefaultParser, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateDefaultParser });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateDefaultParser, decorators: [{
type: Injectable
}] });
class TranslateCompiler {
}
/**
* This compiler is just a placeholder that does nothing, in case you don't need a compiler at all
*/
class TranslateFakeCompiler extends TranslateCompiler {
compile(value, lang) {
return value;
}
compileTranslations(translations, lang) {
return translations;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateFakeCompiler, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateFakeCompiler });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateFakeCompiler, decorators: [{
type: Injectable
}] });
class TranslateStore {
/**
* The default lang to fallback when translations are missing on the current lang
*/
defaultLang;
/**
* The lang currently used
*/
currentLang = this.defaultLang;
/**
* a list of translations per lang
*/
translations = {};
/**
* an array of langs
*/
langs = [];
/**
* An EventEmitter to listen to translation change events
* onTranslationChange.subscribe((params: TranslationChangeEvent) => {
* // do something
* });
*/
onTranslationChange = new EventEmitter();
/**
* An EventEmitter to listen to lang change events
* onLangChange.subscribe((params: LangChangeEvent) => {
* // do something
* });
*/
onLangChange = new EventEmitter();
/**
* An EventEmitter to listen to default lang change events
* onDefaultLangChange.subscribe((params: DefaultLangChangeEvent) => {
* // do something
* });
*/
onDefaultLangChange = new EventEmitter();
}
const USE_STORE = new InjectionToken('USE_STORE');
const USE_DEFAULT_LANG = new InjectionToken('USE_DEFAULT_LANG');
const DEFAULT_LANGUAGE = new InjectionToken('DEFAULT_LANGUAGE');
const USE_EXTEND = new InjectionToken('USE_EXTEND');
class TranslateService {
store;
currentLoader;
compiler;
parser;
missingTranslationHandler;
useDefaultLang;
isolate;
extend;
loadingTranslations;
pending = false;
_onTranslationChange = new EventEmitter();
_onLangChange = new EventEmitter();
_onDefaultLangChange = new EventEmitter();
_defaultLang;
_currentLang;
_langs = [];
_translations = {};
_translationRequests = {};
/**
* An EventEmitter to listen to translation change events
* onTranslationChange.subscribe((params: TranslationChangeEvent) => {
* // do something
* });
*/
get onTranslationChange() {
return this.isolate ? this._onTranslationChange : this.store.onTranslationChange;
}
/**
* An EventEmitter to listen to lang change events
* onLangChange.subscribe((params: LangChangeEvent) => {
* // do something
* });
*/
get onLangChange() {
return this.isolate ? this._onLangChange : this.store.onLangChange;
}
/**
* An EventEmitter to listen to default lang change events
* onDefaultLangChange.subscribe((params: DefaultLangChangeEvent) => {
* // do something
* });
*/
get onDefaultLangChange() {
return this.isolate ? this._onDefaultLangChange : this.store.onDefaultLangChange;
}
/**
* The default lang to fallback when translations are missing on the current lang
*/
get defaultLang() {
return this.isolate ? this._defaultLang : this.store.defaultLang;
}
set defaultLang(defaultLang) {
if (this.isolate) {
this._defaultLang = defaultLang;
}
else {
this.store.defaultLang = defaultLang;
}
}
/**
* The lang currently used
*/
get currentLang() {
return this.isolate ? this._currentLang : this.store.currentLang;
}
set currentLang(currentLang) {
if (this.isolate) {
this._currentLang = currentLang;
}
else {
this.store.currentLang = currentLang;
}
}
/**
* an array of langs
*/
get langs() {
return this.isolate ? this._langs : this.store.langs;
}
set langs(langs) {
if (this.isolate) {
this._langs = langs;
}
else {
this.store.langs = langs;
}
}
/**
* a list of translations per lang
*/
get translations() {
return this.isolate ? this._translations : this.store.translations;
}
set translations(translations) {
if (this.isolate) {
this._translations = translations;
}
else {
this.store.translations = translations;
}
}
/**
*
* @param store an instance of the store (that is supposed to be unique)
* @param currentLoader An instance of the loader currently used
* @param compiler An instance of the compiler currently used
* @param parser An instance of the parser currently used
* @param missingTranslationHandler A handler for missing translations.
* @param useDefaultLang whether we should use default language translation when current language translation is missing.
* @param isolate whether this service should use the store or not
* @param extend To make a child module extend (and use) translations from parent modules.
* @param defaultLanguage Set the default language using configuration
*/
constructor(store, currentLoader, compiler, parser, missingTranslationHandler, useDefaultLang = true, isolate = false, extend = false, defaultLanguage) {
this.store = store;
this.currentLoader = currentLoader;
this.compiler = compiler;
this.parser = parser;
this.missingTranslationHandler = missingTranslationHandler;
this.useDefaultLang = useDefaultLang;
this.isolate = isolate;
this.extend = extend;
/** set the default language from configuration */
if (defaultLanguage) {
this.setDefaultLang(defaultLanguage);
}
}
/**
* Sets the default language to use as a fallback
*/
setDefaultLang(lang) {
if (lang === this.defaultLang) {
return;
}
let pending = this.retrieveTranslations(lang);
if (typeof pending !== "undefined") {
// on init set the defaultLang immediately
if (this.defaultLang == null) {
this.defaultLang = lang;
}
pending.pipe(take(1))
.subscribe((res) => {
this.changeDefaultLang(lang);
});
}
else { // we already have this language
this.changeDefaultLang(lang);
}
}
/**
* Gets the default language used
*/
getDefaultLang() {
return this.defaultLang;
}
/**
* Changes the lang currently used
*/
use(lang) {
// don't change the language if the language given is already selected
if (lang === this.currentLang) {
return of(this.translations[lang]);
}
let pending = this.retrieveTranslations(lang);
if (typeof pending !== "undefined") {
// on init set the currentLang immediately
if (!this.currentLang) {
this.currentLang = lang;
}
pending.pipe(take(1))
.subscribe((res) => {
this.changeLang(lang);
});
return pending;
}
else { // we have this language, return an Observable
this.changeLang(lang);
return of(this.translations[lang]);
}
}
/**
* Retrieves the given translations
*/
retrieveTranslations(lang) {
let pending;
// if this language is unavailable or extend is true, ask for it
if (typeof this.translations[lang] === "undefined" || this.extend) {
this._translationRequests[lang] = this._translationRequests[lang] || this.getTranslation(lang);
pending = this._translationRequests[lang];
}
return pending;
}
/**
* Gets an object of translations for a given language with the current loader
* and passes it through the compiler
*/
getTranslation(lang) {
this.pending = true;
const loadingTranslations = this.currentLoader.getTranslation(lang).pipe(shareReplay(1), take(1));
this.loadingTranslations = loadingTranslations.pipe(map((res) => this.compiler.compileTranslations(res, lang)), shareReplay(1), take(1));
this.loadingTranslations
.subscribe({
next: (res) => {
this.translations[lang] = this.extend && this.translations[lang] ? { ...res, ...this.translations[lang] } : res;
this.updateLangs();
this.pending = false;
},
error: (err) => {
this.pending = false;
}
});
return loadingTranslations;
}
/**
* Manually sets an object of translations for a given language
* after passing it through the compiler
*/
setTranslation(lang, translations, shouldMerge = false) {
translations = this.compiler.compileTranslations(translations, lang);
if ((shouldMerge || this.extend) && this.translations[lang]) {
this.translations[lang] = mergeDeep(this.translations[lang], translations);
}
else {
this.translations[lang] = translations;
}
this.updateLangs();
this.onTranslationChange.emit({ lang: lang, translations: this.translations[lang] });
}
/**
* Returns an array of currently available langs
*/
getLangs() {
return this.langs;
}
/**
* Add available langs
*/
addLangs(langs) {
langs.forEach((lang) => {
if (this.langs.indexOf(lang) === -1) {
this.langs.push(lang);
}
});
}
/**
* Update the list of available langs
*/
updateLangs() {
this.addLangs(Object.keys(this.translations));
}
/**
* Returns the parsed result of the translations
*/
getParsedResult(translations, key, interpolateParams) {
let res;
if (key instanceof Array) {
let result = {}, observables = false;
for (let k of key) {
result[k] = this.getParsedResult(translations, k, interpolateParams);
if (isObservable(result[k])) {
observables = true;
}
}
if (observables) {
const sources = key.map(k => isObservable(result[k]) ? result[k] : of(result[k]));
return forkJoin(sources).pipe(map((arr) => {
let obj = {};
arr.forEach((value, index) => {
obj[key[index]] = value;
});
return obj;
}));
}
return result;
}
if (translations) {
res = this.parser.interpolate(this.parser.getValue(translations, key), interpolateParams);
}
if (typeof res === "undefined" && this.defaultLang != null && this.defaultLang !== this.currentLang && this.useDefaultLang) {
res = this.parser.interpolate(this.parser.getValue(this.translations[this.defaultLang], key), interpolateParams);
}
if (typeof res === "undefined") {
let params = { key, translateService: this };
if (typeof interpolateParams !== 'undefined') {
params.interpolateParams = interpolateParams;
}
res = this.missingTranslationHandler.handle(params);
}
return typeof res !== "undefined" ? res : key;
}
/**
* Gets the translated value of a key (or an array of keys)
* @returns the translated key, or an object of translated keys
*/
get(key, interpolateParams) {
if (!isDefined(key) || !key.length) {
throw new Error(`Parameter "key" required`);
}
// check if we are loading a new translation to use
if (this.pending) {
return this.loadingTranslations.pipe(concatMap((res) => {
res = this.getParsedResult(res, key, interpolateParams);
return isObservable(res) ? res : of(res);
}));
}
else {
let res = this.getParsedResult(this.translations[this.currentLang], key, interpolateParams);
return isObservable(res) ? res : of(res);
}
}
/**
* Returns a stream of translated values of a key (or an array of keys) which updates
* whenever the translation changes.
* @returns A stream of the translated key, or an object of translated keys
*/
getStreamOnTranslationChange(key, interpolateParams) {
if (!isDefined(key) || !key.length) {
throw new Error(`Parameter "key" required`);
}
return concat(defer(() => this.get(key, interpolateParams)), this.onTranslationChange.pipe(switchMap((event) => {
const res = this.getParsedResult(event.translations, key, interpolateParams);
if (typeof res.subscribe === 'function') {
return res;
}
else {
return of(res);
}
})));
}
/**
* Returns a stream of translated values of a key (or an array of keys) which updates
* whenever the language changes.
* @returns A stream of the translated key, or an object of translated keys
*/
stream(key, interpolateParams) {
if (!isDefined(key) || !key.length) {
throw new Error(`Parameter "key" required`);
}
return concat(defer(() => this.get(key, interpolateParams)), this.onLangChange.pipe(switchMap((event) => {
const res = this.getParsedResult(event.translations, key, interpolateParams);
return isObservable(res) ? res : of(res);
})));
}
/**
* Returns a translation instantly from the internal state of loaded translation.
* All rules regarding the current language, the preferred language of even fallback languages will be used except any promise handling.
*/
instant(key, interpolateParams) {
if (!isDefined(key) || !key.length) {
throw new Error(`Parameter "key" required`);
}
let res = this.getParsedResult(this.translations[this.currentLang], key, interpolateParams);
if (isObservable(res)) {
if (key instanceof Array) {
let obj = {};
key.forEach((value, index) => {
obj[key[index]] = key[index];
});
return obj;
}
return key;
}
else {
return res;
}
}
/**
* Sets the translated value of a key, after compiling it
*/
set(key, value, lang = this.currentLang) {
this.translations[lang][key] = this.compiler.compile(value, lang);
this.updateLangs();
this.onTranslationChange.emit({ lang: lang, translations: this.translations[lang] });
}
/**
* Changes the current lang
*/
changeLang(lang) {
this.currentLang = lang;
this.onLangChange.emit({ lang: lang, translations: this.translations[lang] });
// if there is no default lang, use the one that we just set
if (this.defaultLang == null) {
this.changeDefaultLang(lang);
}
}
/**
* Changes the default lang
*/
changeDefaultLang(lang) {
this.defaultLang = lang;
this.onDefaultLangChange.emit({ lang: lang, translations: this.translations[lang] });
}
/**
* Allows to reload the lang file from the file
*/
reloadLang(lang) {
this.resetLang(lang);
return this.getTranslation(lang);
}
/**
* Deletes inner translation
*/
resetLang(lang) {
this._translationRequests[lang] = undefined;
this.translations[lang] = undefined;
}
/**
* Returns the language code name from the browser, e.g. "de"
*/
getBrowserLang() {
if (typeof window === 'undefined' || typeof window.navigator === 'undefined') {
return undefined;
}
let browserLang = window.navigator.languages ? window.navigator.languages[0] : null;
browserLang = browserLang || window.navigator.language || window.navigator.browserLanguage || window.navigator.userLanguage;
if (typeof browserLang === 'undefined') {
return undefined;
}
if (browserLang.indexOf('-') !== -1) {
browserLang = browserLang.split('-')[0];
}
if (browserLang.indexOf('_') !== -1) {
browserLang = browserLang.split('_')[0];
}
return browserLang;
}
/**
* Returns the culture language code name from the browser, e.g. "de-DE"
*/
getBrowserCultureLang() {
if (typeof window === 'undefined' || typeof window.navigator === 'undefined') {
return undefined;
}
let browserCultureLang = window.navigator.languages ? window.navigator.languages[0] : null;
browserCultureLang = browserCultureLang || window.navigator.language || window.navigator.browserLanguage || window.navigator.userLanguage;
return browserCultureLang;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateService, deps: [{ token: TranslateStore }, { token: TranslateLoader }, { token: TranslateCompiler }, { token: TranslateParser }, { token: MissingTranslationHandler }, { token: USE_DEFAULT_LANG }, { token: USE_STORE }, { token: USE_EXTEND }, { token: DEFAULT_LANGUAGE }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateService, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: TranslateStore }, { type: TranslateLoader }, { type: TranslateCompiler }, { type: TranslateParser }, { type: MissingTranslationHandler }, { type: undefined, decorators: [{
type: Inject,
args: [USE_DEFAULT_LANG]
}] }, { type: undefined, decorators: [{
type: Inject,
args: [USE_STORE]
}] }, { type: undefined, decorators: [{
type: Inject,
args: [USE_EXTEND]
}] }, { type: undefined, decorators: [{
type: Inject,
args: [DEFAULT_LANGUAGE]
}] }]; } });
class TranslateDirective {
translateService;
element;
_ref;
key;
lastParams;
currentParams;
onLangChangeSub;
onDefaultLangChangeSub;
onTranslationChangeSub;
set translate(key) {
if (key) {
this.key = key;
this.checkNodes();
}
}
set translateParams(params) {
if (!equals(this.currentParams, params)) {
this.currentParams = params;
this.checkNodes(true);
}
}
constructor(translateService, element, _ref) {
this.translateService = translateService;
this.element = element;
this._ref = _ref;
// subscribe to onTranslationChange event, in case the translations of the current lang change
if (!this.onTranslationChangeSub) {
this.onTranslationChangeSub = this.translateService.onTranslationChange.subscribe((event) => {
if (event.lang === this.translateService.currentLang) {
this.checkNodes(true, event.translations);
}
});
}
// subscribe to onLangChange event, in case the language changes
if (!this.onLangChangeSub) {
this.onLangChangeSub = this.translateService.onLangChange.subscribe((event) => {
this.checkNodes(true, event.translations);
});
}
// subscribe to onDefaultLangChange event, in case the default language changes
if (!this.onDefaultLangChangeSub) {
this.onDefaultLangChangeSub = this.translateService.onDefaultLangChange.subscribe((event) => {
this.checkNodes(true);
});
}
}
ngAfterViewChecked() {
this.checkNodes();
}
checkNodes(forceUpdate = false, translations) {
let nodes = this.element.nativeElement.childNodes;
// if the element is empty
if (!nodes.length) {
// we add the key as content
this.setContent(this.element.nativeElement, this.key);
nodes = this.element.nativeElement.childNodes;
}
for (let i = 0; i < nodes.length; ++i) {
let node = nodes[i];
if (node.nodeType === 3) { // node type 3 is a text node
let key;
if (forceUpdate) {
node.lastKey = null;
}
if (isDefined(node.lookupKey)) {
key = node.lookupKey;
}
else if (this.key) {
key = this.key;
}
else {
let content = this.getContent(node);
let trimmedContent = content.trim();
if (trimmedContent.length) {
node.lookupKey = trimmedContent;
// we want to use the content as a key, not the translation value
if (content !== node.currentValue) {
key = trimmedContent;
// the content was changed from the user, we'll use it as a reference if needed
node.originalContent = content || node.originalContent;
}
else if (node.originalContent) { // the content seems ok, but the lang has changed
// the current content is the translation, not the key, use the last real content as key
key = node.originalContent.trim();
}
else if (content !== node.currentValue) {
// we want to use the content as a key, not the translation value
key = trimmedContent;
// the content was changed from the user, we'll use it as a reference if needed
node.originalContent = content || node.originalContent;
}
}
}
this.updateValue(key, node, translations);
}
}
}
updateValue(key, node, translations) {
if (key) {
if (node.lastKey === key && this.lastParams === this.currentParams) {
return;
}
this.lastParams = this.currentParams;
let onTranslation = (res) => {
if (res !== key) {
node.lastKey = key;
}
if (!node.originalContent) {
node.originalContent = this.getContent(node);
}
node.currentValue = isDefined(res) ? res : (node.originalContent || key);
// we replace in the original content to preserve spaces that we might have trimmed
this.setContent(node, this.key ? node.currentValue : node.originalContent.replace(key, node.currentValue));
this._ref.markForCheck();
};
if (isDefined(translations)) {
let res = this.translateService.getParsedResult(translations, key, this.currentParams);
if (isObservable(res)) {
res.subscribe({ next: onTranslation });
}
else {
onTranslation(res);
}
}
else {
this.translateService.get(key, this.currentParams).subscribe(onTranslation);
}
}
}
getContent(node) {
return isDefined(node.textContent) ? node.textContent : node.data;
}
setContent(node, content) {
if (isDefined(node.textContent)) {
node.textContent = content;
}
else {
node.data = content;
}
}
ngOnDestroy() {
if (this.onLangChangeSub) {
this.onLangChangeSub.unsubscribe();
}
if (this.onDefaultLangChangeSub) {
this.onDefaultLangChangeSub.unsubscribe();
}
if (this.onTranslationChangeSub) {
this.onTranslationChangeSub.unsubscribe();
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateDirective, deps: [{ token: TranslateService }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: { translate: "translate", translateParams: "translateParams" }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateDirective, decorators: [{
type: Directive,
args: [{
selector: '[translate],[ngx-translate]'
}]
}], ctorParameters: function () { return [{ type: TranslateService }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { translate: [{
type: Input
}], translateParams: [{
type: Input
}] } });
class TranslatePipe {
translate;
_ref;
value = '';
lastKey = null;
lastParams = [];
onTranslationChange;
onLangChange;
onDefaultLangChange;
constructor(translate, _ref) {
this.translate = translate;
this._ref = _ref;
}
updateValue(key, interpolateParams, translations) {
let onTranslation = (res) => {
this.value = res !== undefined ? res : key;
this.lastKey = key;
this._ref.markForCheck();
};
if (translations) {
let res = this.translate.getParsedResult(translations, key, interpolateParams);
if (isObservable(res.subscribe)) {
res.subscribe(onTranslation);
}
else {
onTranslation(res);
}
}
this.translate.get(key, interpolateParams).subscribe(onTranslation);
}
transform(query, ...args) {
if (!query || !query.length) {
return query;
}
// if we ask another time for the same key, return the last value
if (equals(query, this.lastKey) && equals(args, this.lastParams)) {
return this.value;
}
let interpolateParams = undefined;
if (isDefined(args[0]) && args.length) {
if (typeof args[0] === 'string' && args[0].length) {
// we accept objects written in the template such as {n:1}, {'n':1}, {n:'v'}
// which is why we might need to change it to real JSON objects such as {"n":1} or {"n":"v"}
let validArgs = args[0]
.replace(/(\')?([a-zA-Z0-9_]+)(\')?(\s)?:/g, '"$2":')
.replace(/:(\s)?(\')(.*?)(\')/g, ':"$3"');
try {
interpolateParams = JSON.parse(validArgs);
}
catch (e) {
throw new SyntaxError(`Wrong parameter in TranslatePipe. Expected a valid Object, received: ${args[0]}`);
}
}
else if (typeof args[0] === 'object' && !Array.isArray(args[0])) {
interpolateParams = args[0];
}
}
// store the query, in case it changes
this.lastKey = query;
// store the params, in case they change
this.lastParams = args;
// set the value
this.updateValue(query, interpolateParams);
// if there is a subscription to onLangChange, clean it
this._dispose();
// subscribe to onTranslationChange event, in case the translations change
if (!this.onTranslationChange) {
this.onTranslationChange = this.translate.onTranslationChange.subscribe((event) => {
if (this.lastKey && event.lang === this.translate.currentLang) {
this.lastKey = null;
this.updateValue(query, interpolateParams, event.translations);
}
});
}
// subscribe to onLangChange event, in case the language changes
if (!this.onLangChange) {
this.onLangChange = this.translate.onLangChange.subscribe((event) => {
if (this.lastKey) {
this.lastKey = null; // we want to make sure it doesn't return the same value until it's been updated
this.updateValue(query, interpolateParams, event.translations);
}
});
}
// subscribe to onDefaultLangChange event, in case the default language changes
if (!this.onDefaultLangChange) {
this.onDefaultLangChange = this.translate.onDefaultLangChange.subscribe(() => {
if (this.lastKey) {
this.lastKey = null; // we want to make sure it doesn't return the same value until it's been updated
this.updateValue(query, interpolateParams);
}
});
}
return this.value;
}
/**
* Clean any existing subscription to change events
*/
_dispose() {
if (typeof this.onTranslationChange !== 'undefined') {
this.onTranslationChange.unsubscribe();
this.onTranslationChange = undefined;
}
if (typeof this.onLangChange !== 'undefined') {
this.onLangChange.unsubscribe();
this.onLangChange = undefined;
}
if (typeof this.onDefaultLangChange !== 'undefined') {
this.onDefaultLangChange.unsubscribe();
this.onDefaultLangChange = undefined;
}
}
ngOnDestroy() {
this._dispose();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslatePipe, deps: [{ token: TranslateService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "16.0.0", ngImport: i0, type: TranslatePipe, name: "translate", pure: false });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslatePipe });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslatePipe, decorators: [{
type: Injectable
}, {
type: Pipe,
args: [{
name: 'translate',
pure: false // required to update the value when the promise is resolved
}]
}], ctorParameters: function () { return [{ type: TranslateService }, { type: i0.ChangeDetectorRef }]; } });
class TranslateModule {
/**
* Use this method in your root module to provide the TranslateService
*/
static forRoot(config = {}) {
return {
ngModule: TranslateModule,
providers: [
config.loader || { provide: TranslateLoader, useClass: TranslateFakeLoader },
config.compiler || { provide: TranslateCompiler, useClass: TranslateFakeCompiler },
config.parser || { provide: TranslateParser, useClass: TranslateDefaultParser },
config.missingTranslationHandler || { provide: MissingTranslationHandler, useClass: FakeMissingTranslationHandler },
TranslateStore,
{ provide: USE_STORE, useValue: config.isolate },
{ provide: USE_DEFAULT_LANG, useValue: config.useDefaultLang },
{ provide: USE_EXTEND, useValue: config.extend },
{ provide: DEFAULT_LANGUAGE, useValue: config.defaultLanguage },
TranslateService
]
};
}
/**
* Use this method in your other (non root) modules to import the directive/pipe
*/
static forChild(config = {}) {
return {
ngModule: TranslateModule,
providers: [
config.loader || { provide: TranslateLoader, useClass: TranslateFakeLoader },
config.compiler || { provide: TranslateCompiler, useClass: TranslateFakeCompiler },
config.parser || { provide: TranslateParser, useClass: TranslateDefaultParser },
config.missingTranslationHandler || { provide: MissingTranslationHandler, useClass: FakeMissingTranslationHandler },
{ provide: USE_STORE, useValue: config.isolate },
{ provide: USE_DEFAULT_LANG, useValue: config.useDefaultLang },
{ provide: USE_EXTEND, useValue: config.extend },
{ provide: DEFAULT_LANGUAGE, useValue: config.defaultLanguage },
TranslateService
]
};
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.0", ngImport: i0, type: TranslateModule, declarations: [TranslatePipe,
TranslateDirective], exports: [TranslatePipe,
TranslateDirective] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateModule });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: TranslateModule, decorators: [{
type: NgModule,
args: [{
declarations: [
TranslatePipe,
TranslateDirective
],
exports: [
TranslatePipe,
TranslateDirective
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { DEFAULT_LANGUAGE, FakeMissingTranslationHandler, MissingTranslationHandler, TranslateCompiler, TranslateDefaultParser, TranslateDirective, TranslateFakeCompiler, TranslateFakeLoader, TranslateLoader, TranslateModule, TranslateParser, TranslatePipe, TranslateService, TranslateStore, USE_DEFAULT_LANG, USE_EXTEND, USE_STORE };
//# sourceMappingURL=ngx-translate-core.mjs.map