@ngneat/transloco
Version:
The internationalization (i18n) library for Angular
1,652 lines (1,640 loc) • 91.1 kB
JavaScript
import flat from 'flat';
import { take, map, catchError, retry, shareReplay, switchMap, tap } from 'rxjs/operators';
import { __assign, __read, __extends, __spread, __values } from 'tslib';
import { InjectionToken, Inject, Injectable, Injector, Optional, Component, Input, NgModule, ChangeDetectorRef, Pipe, Directive, ElementRef, TemplateRef, ViewContainerRef, ComponentFactoryResolver, APP_INITIALIZER, defineInjectable, inject } from '@angular/core';
import { of, from, BehaviorSubject, combineLatest, EMPTY, forkJoin, Subject } from 'rxjs';
/**
* @fileoverview added by tsickle
* Generated from: lib/transloco.loader.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var DefaultLoader = /** @class */ (function () {
function DefaultLoader(translations) {
this.translations = translations;
}
/**
* @param {?} lang
* @return {?}
*/
DefaultLoader.prototype.getTranslation = /**
* @param {?} lang
* @return {?}
*/
function (lang) {
return of(this.translations.get(lang) || {});
};
return DefaultLoader;
}());
/** @type {?} */
var TRANSLOCO_LOADER = new InjectionToken('TRANSLOCO_LOADER');
/**
* @fileoverview added by tsickle
* Generated from: lib/helpers.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} obj
* @param {?} path
* @return {?}
*/
function getValue(obj, path) {
/* For cases where the key is like: 'general.something.thing' */
if (obj && obj.hasOwnProperty(path)) {
return obj[path];
}
return path.split('.').reduce((/**
* @param {?} p
* @param {?} c
* @return {?}
*/
function (p, c) { return p && p[c]; }), obj);
}
/**
* @param {?} obj
* @param {?} prop
* @param {?} val
* @return {?}
*/
function setValue(obj, prop, val) {
obj = __assign({}, obj);
/** @type {?} */
var split = prop.split('.');
/** @type {?} */
var lastIndex = split.length - 1;
split.reduce((/**
* @param {?} acc
* @param {?} part
* @param {?} index
* @return {?}
*/
function (acc, part, index) {
if (index === lastIndex) {
acc[part] = val;
}
else {
acc[part] = Array.isArray(acc[part]) ? acc[part].slice() : __assign({}, acc[part]);
}
return acc && acc[part];
}), obj);
return obj;
}
/**
* @param {?} collection
* @return {?}
*/
function size(collection) {
if (!collection) {
return 0;
}
if (Array.isArray(collection)) {
return collection.length;
}
if (isObject(collection)) {
return Object.keys(collection).length;
}
return !!collection ? collection.length : 0;
}
/**
* @param {?} collection
* @return {?}
*/
function isEmpty(collection) {
return size(collection) === 0;
}
/**
* @param {?} val
* @return {?}
*/
function isFunction(val) {
return typeof val === 'function';
}
/**
* @param {?} val
* @return {?}
*/
function isString(val) {
return typeof val === 'string';
}
/**
* @param {?} val
* @return {?}
*/
function isNumber(val) {
return typeof val === 'number';
}
/**
* @param {?} item
* @return {?}
*/
function isObject(item) {
return item && typeof item === 'object' && !Array.isArray(item);
}
/**
* @param {?} val
* @return {?}
*/
function coerceArray(val) {
return Array.isArray(val) ? val : [val];
}
/*
* @example
*
* given: path-to-happiness => pathToHappiness
* given: path_to_happiness => pathToHappiness
* given: path-to_happiness => pathToHappiness
*
*/
/**
* @param {?} str
* @return {?}
*/
function toCamelCase(str) {
return str
.replace(/(?:^\w|[A-Z]|\b\w)/g, (/**
* @param {?} word
* @param {?} index
* @return {?}
*/
function (word, index) { return (index == 0 ? word.toLowerCase() : word.toUpperCase()); }))
.replace(/\s+|_|-|\//g, '');
}
/**
* @return {?}
*/
function isBrowser() {
return typeof window !== 'undefined';
}
/**
* @param {?} value
* @return {?}
*/
function isNil(value) {
return value === null || value === undefined;
}
/**
* @param {?} value
* @return {?}
*/
function isDefined(value) {
return isNil(value) === false;
}
/**
* @param {?} value
* @return {?}
*/
function toNumber(value) {
if (isNumber(value))
return value;
if (isString(value) && !isNaN(Number(value) - parseFloat(value))) {
return Number(value);
}
return null;
}
/**
* @param {?} item
* @return {?}
*/
function isScopeObject(item) {
return item && typeof item.scope === 'string';
}
/**
* @param {?} item
* @return {?}
*/
function hasInlineLoader(item) {
return item && isObject(item.loader);
}
/**
* @param {?} obj
* @return {?}
*/
function unflatten(obj) {
return flat.unflatten(obj, { safe: true });
}
/**
* @param {?} obj
* @return {?}
*/
function flatten(obj) {
return flat(obj, { safe: true });
}
/**
* @fileoverview added by tsickle
* Generated from: lib/transloco.config.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
var TRANSLOCO_CONFIG = new InjectionToken('TRANSLOCO_CONFIG', {
providedIn: 'root',
factory: (/**
* @return {?}
*/
function () {
return {};
})
});
/** @type {?} */
var defaultConfig = {
defaultLang: 'en',
reRenderOnLangChange: false,
prodMode: false,
failedRetries: 2,
availableLangs: [],
missingHandler: {
logMissingKey: true,
useFallbackTranslation: false,
allowEmpty: false
},
flatten: {
aot: false
},
interpolation: ['{{', '}}']
};
/**
* @deprecated
* @param {?=} config
* @return {?}
*/
function provideTranslocoConfig(config) {
if (config === void 0) { config = defaultConfig; }
return {
provide: TRANSLOCO_CONFIG,
useValue: __assign({}, defaultConfig, config)
};
}
/**
* Sets up TranslocoConfig object.
*
* @param {?=} config The partial config object to load, this is optional,
* will be spread after defaultConfig.
* @return {?}
*/
function translocoConfig(config) {
if (config === void 0) { config = defaultConfig; }
return __assign({}, defaultConfig, config);
}
/**
* @fileoverview added by tsickle
* Generated from: lib/transloco.transpiler.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
var TRANSLOCO_TRANSPILER = new InjectionToken('TRANSLOCO_TRANSPILER');
var DefaultTranspiler = /** @class */ (function () {
function DefaultTranspiler(userConfig) {
this.interpolationMatcher = resolveMatcher(userConfig);
}
/**
* @param {?} value
* @param {?=} params
* @param {?=} translation
* @return {?}
*/
DefaultTranspiler.prototype.transpile = /**
* @param {?} value
* @param {?=} params
* @param {?=} translation
* @return {?}
*/
function (value, params, translation) {
var _this = this;
if (params === void 0) { params = {}; }
if (isString(value)) {
return value.replace(this.interpolationMatcher, (/**
* @param {?} _
* @param {?} match
* @return {?}
*/
function (_, match) {
match = match.trim();
if (isDefined(params[match])) {
return params[match];
}
return isDefined(translation[match]) ? _this.transpile(translation[match], params, translation) : '';
}));
}
else if (params) {
if (isObject(value)) {
value = this.handleObject(value, params, translation);
}
else if (Array.isArray(value)) {
value = this.handleArray(value, params, translation);
}
}
return value;
};
/**
*
* @example
*
* const en = {
* a: {
* b: {
* c: "Hello {{ value }}"
* }
* }
* }
*
* const params = {
* "b.c": { value: "Transloco "}
* }
*
* service.selectTranslate('a', params);
*
* // the first param will be the result of `en.a`.
* // the second param will be `params`.
* parser.transpile(value, params, {});
*
*
*/
/**
*
* \@example
*
* const en = {
* a: {
* b: {
* c: "Hello {{ value }}"
* }
* }
* }
*
* const params = {
* "b.c": { value: "Transloco "}
* }
*
* service.selectTranslate('a', params);
*
* // the first param will be the result of `en.a`.
* // the second param will be `params`.
* parser.transpile(value, params, {});
*
*
* @protected
* @param {?} value
* @param {?=} params
* @param {?=} translation
* @return {?}
*/
DefaultTranspiler.prototype.handleObject = /**
*
* \@example
*
* const en = {
* a: {
* b: {
* c: "Hello {{ value }}"
* }
* }
* }
*
* const params = {
* "b.c": { value: "Transloco "}
* }
*
* service.selectTranslate('a', params);
*
* // the first param will be the result of `en.a`.
* // the second param will be `params`.
* parser.transpile(value, params, {});
*
*
* @protected
* @param {?} value
* @param {?=} params
* @param {?=} translation
* @return {?}
*/
function (value, params, translation) {
var _this = this;
if (params === void 0) { params = {}; }
/** @type {?} */
var result = value;
Object.keys(params).forEach((/**
* @param {?} p
* @return {?}
*/
function (p) {
// get the value of "b.c" inside "a" => "Hello {{ value }}"
/** @type {?} */
var v = getValue(result, p);
// get the params of "b.c" => { value: "Transloco" }
/** @type {?} */
var getParams = getValue(params, p);
// transpile the value => "Hello Transloco"
/** @type {?} */
var transpiled = _this.transpile(v, getParams, translation);
// set "b.c" to `transpiled`
result = setValue(result, p, transpiled);
}));
return result;
};
/**
* @protected
* @param {?} value
* @param {?=} params
* @param {?=} translation
* @return {?}
*/
DefaultTranspiler.prototype.handleArray = /**
* @protected
* @param {?} value
* @param {?=} params
* @param {?=} translation
* @return {?}
*/
function (value, params, translation) {
var _this = this;
if (params === void 0) { params = {}; }
return value.map((/**
* @param {?} v
* @return {?}
*/
function (v) { return _this.transpile(v, params, translation); }));
};
/** @nocollapse */
DefaultTranspiler.ctorParameters = function () { return [
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [TRANSLOCO_CONFIG,] }] }
]; };
return DefaultTranspiler;
}());
/**
* @param {?=} userConfig
* @return {?}
*/
function resolveMatcher(userConfig) {
var _a = __read(userConfig && userConfig.interpolation ? userConfig.interpolation : defaultConfig.interpolation, 2), start = _a[0], end = _a[1];
return new RegExp(start + "(.*?)" + end, 'g');
}
/**
* @param {?} argsString
* @return {?}
*/
function getFunctionArgs(argsString) {
/** @type {?} */
var splitted = argsString ? argsString.split(',') : [];
/** @type {?} */
var args = [];
for (var i = 0; i < splitted.length; i++) {
/** @type {?} */
var value = splitted[i].trim();
while (value[value.length - 1] === '\\') {
i++;
value = value.replace('\\', ',') + splitted[i];
}
args.push(value);
}
return args;
}
var FunctionalTranspiler = /** @class */ (function (_super) {
__extends(FunctionalTranspiler, _super);
function FunctionalTranspiler(injector) {
var _this = _super.call(this) || this;
_this.injector = injector;
return _this;
}
/**
* @param {?} value
* @param {?=} params
* @param {?=} translation
* @return {?}
*/
FunctionalTranspiler.prototype.transpile = /**
* @param {?} value
* @param {?=} params
* @param {?=} translation
* @return {?}
*/
function (value, params, translation) {
var _this = this;
if (params === void 0) { params = {}; }
/** @type {?} */
var transpiled = value;
if (isString(value)) {
transpiled = value.replace(/\[\[\s*(\w+)\((.*)\)\s*]]/g, (/**
* @param {?} match
* @param {?} functionName
* @param {?} args
* @return {?}
*/
function (match, functionName, args) {
try {
/** @type {?} */
var func = _this.injector.get(functionName);
return func.transpile.apply(func, __spread(getFunctionArgs(args)));
}
catch (e) {
/** @type {?} */
var message = "There is an error in: '" + value + "'. \n Check that the you used the right syntax in your translation and that the implementation of " + functionName + " is correct.";
if (e.message.includes('NullInjectorError')) {
message = "You are using the '" + functionName + "' function in your translation but no provider was found!";
}
throw new Error(message);
}
}));
}
return _super.prototype.transpile.call(this, transpiled, params, translation);
};
FunctionalTranspiler.decorators = [
{ type: Injectable }
];
/** @nocollapse */
FunctionalTranspiler.ctorParameters = function () { return [
{ type: Injector }
]; };
return FunctionalTranspiler;
}(DefaultTranspiler));
/**
* @fileoverview added by tsickle
* Generated from: lib/transloco-missing-handler.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
var TRANSLOCO_MISSING_HANDLER = new InjectionToken('TRANSLOCO_MISSING_HANDLER');
var DefaultHandler = /** @class */ (function () {
function DefaultHandler() {
}
/**
* @param {?} key
* @param {?} config
* @return {?}
*/
DefaultHandler.prototype.handle = /**
* @param {?} key
* @param {?} config
* @return {?}
*/
function (key, config) {
if (config.missingHandler.logMissingKey && !config.prodMode) {
/** @type {?} */
var msg = "Missing translation for '" + key + "'";
console.warn("%c " + msg, 'font-size: 12px; color: red');
}
return key;
};
return DefaultHandler;
}());
/**
* @fileoverview added by tsickle
* Generated from: lib/transloco.interceptor.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
var TRANSLOCO_INTERCEPTOR = new InjectionToken('TRANSLOCO_INTERCEPTOR');
var DefaultInterceptor = /** @class */ (function () {
function DefaultInterceptor() {
}
/**
* @param {?} translation
* @param {?} lang
* @return {?}
*/
DefaultInterceptor.prototype.preSaveTranslation = /**
* @param {?} translation
* @param {?} lang
* @return {?}
*/
function (translation, lang) {
return translation;
};
/**
* @param {?} key
* @param {?} value
* @param {?} lang
* @return {?}
*/
DefaultInterceptor.prototype.preSaveTranslationKey = /**
* @param {?} key
* @param {?} value
* @param {?} lang
* @return {?}
*/
function (key, value, lang) {
return value;
};
return DefaultInterceptor;
}());
/**
* @fileoverview added by tsickle
* Generated from: lib/transloco-fallback-strategy.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
var TRANSLOCO_FALLBACK_STRATEGY = new InjectionToken('TRANSLOCO_FALLBACK_STRATEGY');
var DefaultFallbackStrategy = /** @class */ (function () {
function DefaultFallbackStrategy(userConfig) {
this.userConfig = userConfig;
}
/**
* @param {?} failedLang
* @return {?}
*/
DefaultFallbackStrategy.prototype.getNextLangs = /**
* @param {?} failedLang
* @return {?}
*/
function (failedLang) {
/** @type {?} */
var fallbackLang = this.userConfig.fallbackLang;
if (!fallbackLang) {
throw new Error('When using the default fallback, a fallback language must be provided in the config!');
}
return Array.isArray(fallbackLang) ? fallbackLang : [fallbackLang];
};
/** @nocollapse */
DefaultFallbackStrategy.ctorParameters = function () { return [
{ type: undefined, decorators: [{ type: Inject, args: [TRANSLOCO_CONFIG,] }] }
]; };
return DefaultFallbackStrategy;
}());
/**
* @fileoverview added by tsickle
* Generated from: lib/merge-config.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} defaultConfig
* @param {?} userConfig
* @return {?}
*/
function mergeConfig(defaultConfig, userConfig) {
return __assign({}, defaultConfig, userConfig, { missingHandler: __assign({}, defaultConfig.missingHandler, userConfig.missingHandler), flatten: __assign({}, defaultConfig.flatten, userConfig.flatten) });
}
/**
* @fileoverview added by tsickle
* Generated from: lib/shared.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/*
* @example
*
* given: lazy-page/en => lazy-page
*
*/
/**
* @param {?} lang
* @return {?}
*/
function getScopeFromLang(lang) {
if (!lang) {
return '';
}
/** @type {?} */
var split = lang.split('/');
split.pop();
return split.join('/');
}
/*
* @example
*
* given: lazy-page/en => en
*
*/
/**
* @param {?} lang
* @return {?}
*/
function getLangFromScope(lang) {
if (!lang) {
return '';
}
/** @type {?} */
var split = lang.split('/');
return split.pop();
}
/**
* \@example
*
* getPipeValue('todos|scoped', 'scoped') [true, 'todos']
* getPipeValue('en|static', 'static') [true, 'en']
* getPipeValue('en', 'static') [false, 'en']
* @param {?} str
* @param {?} value
* @param {?=} char
* @return {?}
*/
function getPipeValue(str, value, char) {
if (char === void 0) { char = '|'; }
if (isString(str)) {
/** @type {?} */
var splitted = str.split(char);
/** @type {?} */
var lastItem = splitted.pop();
return lastItem === value ? [true, splitted.toString()] : [false, lastItem];
}
return [false, ''];
}
/**
* @param {?} service
* @param {?} lang
* @return {?}
*/
function shouldListenToLangChanges(service, lang) {
var _a = __read(getPipeValue(lang, 'static'), 1), hasStatic = _a[0];
if (hasStatic === false) {
// If we didn't get 'lang|static' check if it's set in the global level
return service.config.reRenderOnLangChange;
}
// We have 'lang|static' so don't listen to lang changes
return false;
}
/**
* @param {?} listenToLangChange
* @return {?}
*/
function listenOrNotOperator(listenToLangChange) {
return listenToLangChange ? (/**
* @param {?} source
* @return {?}
*/
function (source) { return source; }) : take(1);
}
/**
* @param {?} inlineLoader
* @param {?} scope
* @return {?}
*/
function prependScope(inlineLoader, scope) {
return Object.keys(inlineLoader).reduce((/**
* @param {?} acc
* @param {?} lang
* @return {?}
*/
function (acc, lang) {
acc[scope + "/" + lang] = inlineLoader[lang];
return acc;
}), {});
}
/**
* @param {?} providerScope
* @param {?} scope
* @return {?}
*/
function resolveInlineLoader(providerScope, scope) {
return hasInlineLoader(providerScope) ? prependScope(providerScope.loader, scope) : null;
}
/**
* @param {?} lang
* @return {?}
*/
function getEventPayload(lang) {
return {
scope: getScopeFromLang(lang) || null,
langName: getLangFromScope(lang),
lang: lang
};
}
/**
* @fileoverview added by tsickle
* Generated from: lib/resolve-loader.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} path
* @param {?} mainLoader
* @param {?} inlineLoader
* @param {?} data
* @return {?}
*/
function resolveLoader(path, mainLoader, inlineLoader, data) {
if (inlineLoader) {
/** @type {?} */
var pathLoader = inlineLoader[path];
if (isFunction(pathLoader) === false) {
throw "You're using an inline loader but didn't provide a loader for " + path;
}
return inlineLoader[path]().then((/**
* @param {?} res
* @return {?}
*/
function (res) { return (res.default ? res.default : res); }));
}
return mainLoader.getTranslation(path, data);
}
/**
* @fileoverview added by tsickle
* Generated from: lib/get-fallbacks-loaders.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @param {?} mainPath
* @param {?} fallbackPath
* @param {?} mainLoader
* @param {?} inlineLoader
* @param {?} data
* @return {?}
*/
function getFallbacksLoaders(mainPath, fallbackPath, mainLoader, inlineLoader, data) {
return [mainPath, fallbackPath].map((/**
* @param {?} path
* @return {?}
*/
function (path) {
/** @type {?} */
var loader = resolveLoader(path, mainLoader, inlineLoader, data);
return from(loader).pipe(map((/**
* @param {?} translation
* @return {?}
*/
function (translation) { return ({
translation: translation,
lang: path
}); })));
}));
}
/**
* @fileoverview added by tsickle
* Generated from: lib/transloco.service.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
var service;
/**
* @template T
* @param {?} key
* @param {?=} params
* @param {?=} lang
* @return {?}
*/
function translate(key, params, lang) {
if (params === void 0) { params = {}; }
return service.translate(key, params, lang);
}
var TranslocoService = /** @class */ (function () {
function TranslocoService(loader, parser, missingHandler, interceptor, userConfig, fallbackStrategy) {
var _this = this;
this.loader = loader;
this.parser = parser;
this.missingHandler = missingHandler;
this.interceptor = interceptor;
this.userConfig = userConfig;
this.fallbackStrategy = fallbackStrategy;
this.translations = new Map();
this.cache = new Map();
this.firstFallbackLang = null;
this.availableLangs = [];
this.isResolvedMissingOnce = false;
this.events = new Subject();
this.events$ = this.events.asObservable();
this.failedLangs = new Set();
if (!this.loader) {
this.loader = new DefaultLoader(this.translations);
}
service = this;
this.mergedConfig = mergeConfig(defaultConfig, userConfig);
this.setAvailableLangs(this.mergedConfig.availableLangs);
this.setFallbackLangForMissingTranslation(this.mergedConfig);
this.setDefaultLang(this.mergedConfig.defaultLang);
this.lang = new BehaviorSubject(this.getDefaultLang());
// Don't use distinctUntilChanged as we need the ability to update
// the value when using setTranslation or setTranslationKeys
this.langChanges$ = this.lang.asObservable();
/**
* When we have a failure, we want to define the next language that succeeded as the active
*/
this.subscription = this.events$.subscribe((/**
* @param {?} e
* @return {?}
*/
function (e) {
if (e.type === 'translationLoadSuccess' && e.wasFailure) {
// Handle scoped lang
/** @type {?} */
var lang = getLangFromScope(e.payload.lang);
_this.setActiveLang(lang);
}
}));
}
Object.defineProperty(TranslocoService.prototype, "config", {
get: /**
* @return {?}
*/
function () {
return this.mergedConfig;
},
enumerable: true,
configurable: true
});
/**
* @return {?}
*/
TranslocoService.prototype.getDefaultLang = /**
* @return {?}
*/
function () {
return this.defaultLang;
};
/**
* @param {?} lang
* @return {?}
*/
TranslocoService.prototype.setDefaultLang = /**
* @param {?} lang
* @return {?}
*/
function (lang) {
this.defaultLang = lang;
};
/**
* @return {?}
*/
TranslocoService.prototype.getActiveLang = /**
* @return {?}
*/
function () {
return this.lang.getValue();
};
/**
* @template THIS
* @this {THIS}
* @param {?} lang
* @return {THIS}
*/
TranslocoService.prototype.setActiveLang = /**
* @template THIS
* @this {THIS}
* @param {?} lang
* @return {THIS}
*/
function (lang) {
(/** @type {?} */ (this)).parser.onLangChanged && (/** @type {?} */ (this)).parser.onLangChanged(lang);
(/** @type {?} */ (this)).lang.next(lang);
return (/** @type {?} */ (this));
};
/**
* @param {?} langs
* @return {?}
*/
TranslocoService.prototype.setAvailableLangs = /**
* @param {?} langs
* @return {?}
*/
function (langs) {
this.availableLangs = langs;
};
/**
* Gets the available languages.
*
* @returns
* An array of the available languages. Can be either a `string[]` or a `{ id: string; label: string }[]`
* depending on how the available languages are set in your module.
*/
/**
* Gets the available languages.
*
* @return {?}
* An array of the available languages. Can be either a `string[]` or a `{ id: string; label: string }[]`
* depending on how the available languages are set in your module.
*/
TranslocoService.prototype.getAvailableLangs = /**
* Gets the available languages.
*
* @return {?}
* An array of the available languages. Can be either a `string[]` or a `{ id: string; label: string }[]`
* depending on how the available languages are set in your module.
*/
function () {
return this.availableLangs;
};
/**
* @param {?} path
* @param {?=} options
* @return {?}
*/
TranslocoService.prototype.load = /**
* @param {?} path
* @param {?=} options
* @return {?}
*/
function (path, options) {
var _this = this;
if (options === void 0) { options = {}; }
if (this.cache.has(path) === false) {
/** @type {?} */
var loadTranslation = void 0;
/** @type {?} */
var isScope = this._isLangScoped(path);
/** @type {?} */
var scope = isScope ? getScopeFromLang(path) : null;
if (this.useFallbackTranslation(path)) {
// if the path is scope the fallback should be `scope/fallbackLang`;
/** @type {?} */
var fallback = isScope ? scope + "/" + this.firstFallbackLang : this.firstFallbackLang;
/** @type {?} */
var loaders = getFallbacksLoaders(path, fallback, this.loader, options.inlineLoader, { scope: scope });
loadTranslation = forkJoin(loaders);
}
else {
/** @type {?} */
var loader = resolveLoader(path, this.loader, options.inlineLoader, { scope: scope });
loadTranslation = from(loader);
}
/** @type {?} */
var load$ = loadTranslation.pipe(retry(this.config.failedRetries), tap((/**
* @param {?} translation
* @return {?}
*/
function (translation) {
if (Array.isArray(translation)) {
translation.forEach((/**
* @param {?} t
* @return {?}
*/
function (t) {
_this.handleSuccess(t.lang, t.translation);
// Save the fallback in cache so we'll not create a redundant request
if (t.lang !== path) {
_this.cache.set(t.lang, of({}));
}
}));
return;
}
_this.handleSuccess(path, translation);
})), catchError((/**
* @return {?}
*/
function () { return _this.handleFailure(path, options); })), shareReplay(1));
this.cache.set(path, load$);
}
return this.cache.get(path);
};
/**
* Gets the instant translated value of a key
*
* @example
*
* translate<string>('hello')
* translate('hello', { value: 'value' })
* translate<string[]>(['hello', 'key'])
* translate('hello', { }, 'en')
* translate('scope.someKey', { }, 'en')
*/
/**
* Gets the instant translated value of a key
*
* \@example
*
* translate<string>('hello')
* translate('hello', { value: 'value' })
* translate<string[]>(['hello', 'key'])
* translate('hello', { }, 'en')
* translate('scope.someKey', { }, 'en')
* @template T
* @param {?} key
* @param {?=} params
* @param {?=} lang
* @return {?}
*/
TranslocoService.prototype.translate = /**
* Gets the instant translated value of a key
*
* \@example
*
* translate<string>('hello')
* translate('hello', { value: 'value' })
* translate<string[]>(['hello', 'key'])
* translate('hello', { }, 'en')
* translate('scope.someKey', { }, 'en')
* @template T
* @param {?} key
* @param {?=} params
* @param {?=} lang
* @return {?}
*/
function (key, params, lang) {
var _this = this;
if (params === void 0) { params = {}; }
if (lang === void 0) { lang = this.getActiveLang(); }
if (!key)
return (/** @type {?} */ (key));
var _a = this.resolveLangAndScope(lang), scope = _a.scope, resolveLang = _a.resolveLang;
if (Array.isArray(key)) {
return (/** @type {?} */ (key.map((/**
* @param {?} k
* @return {?}
*/
function (k) { return _this.translate(scope ? scope + "." + k : k, params, resolveLang); }))));
}
key = scope ? scope + "." + key : key;
/** @type {?} */
var translation = this.getTranslation(resolveLang);
/** @type {?} */
var value = translation[key];
if (!value) {
return this._handleMissingKey(key, value, params);
}
return this.parser.transpile(value, params, translation);
};
/**
* Gets the translated value of a key as observable
*
* @example
*
* selectTranslate<string>('hello').subscribe(value => ...)
* selectTranslate<string>('hello', {}, 'es').subscribe(value => ...)
* selectTranslate<string>('hello', {}, 'todos').subscribe(value => ...)
* selectTranslate<string>('hello', {}, { scope: 'todos' }).subscribe(value => ...)
*
*/
/**
* Gets the translated value of a key as observable
*
* \@example
*
* selectTranslate<string>('hello').subscribe(value => ...)
* selectTranslate<string>('hello', {}, 'es').subscribe(value => ...)
* selectTranslate<string>('hello', {}, 'todos').subscribe(value => ...)
* selectTranslate<string>('hello', {}, { scope: 'todos' }).subscribe(value => ...)
*
* @template T
* @param {?} key
* @param {?=} params
* @param {?=} lang
* @param {?=} _isObject
* @return {?}
*/
TranslocoService.prototype.selectTranslate = /**
* Gets the translated value of a key as observable
*
* \@example
*
* selectTranslate<string>('hello').subscribe(value => ...)
* selectTranslate<string>('hello', {}, 'es').subscribe(value => ...)
* selectTranslate<string>('hello', {}, 'todos').subscribe(value => ...)
* selectTranslate<string>('hello', {}, { scope: 'todos' }).subscribe(value => ...)
*
* @template T
* @param {?} key
* @param {?=} params
* @param {?=} lang
* @param {?=} _isObject
* @return {?}
*/
function (key, params, lang, _isObject) {
var _this = this;
if (_isObject === void 0) { _isObject = false; }
/** @type {?} */
var inlineLoader = null;
/** @type {?} */
var load = (/**
* @param {?} lang
* @param {?=} options
* @return {?}
*/
function (lang, options) {
return _this.load(lang, options).pipe(map((/**
* @return {?}
*/
function () { return (_isObject ? _this.translateObject(key, params, lang) : _this.translate(key, params, lang)); })));
});
if (isNil(lang)) {
return this.langChanges$.pipe(switchMap((/**
* @param {?} lang
* @return {?}
*/
function (lang) { return load(lang); })));
}
if (isScopeObject(lang)) {
// it's a scope object.
/** @type {?} */
var providerScope = (/** @type {?} */ (lang));
lang = providerScope.scope;
inlineLoader = resolveInlineLoader(providerScope, providerScope.scope);
}
lang = (/** @type {?} */ (lang));
if (this.isLang(lang) || this.isScopeWithLang(lang)) {
return load(lang);
}
// it's a scope
/** @type {?} */
var scope = lang;
return this.langChanges$.pipe(switchMap((/**
* @param {?} lang
* @return {?}
*/
function (lang) { return load(scope + "/" + lang, { inlineLoader: inlineLoader }); })));
};
/**
* Whether the scope with lang
*
* @example
*
* todos/en => true
* todos => false
*/
/**
* Whether the scope with lang
*
* \@example
*
* todos/en => true
* todos => false
* @private
* @param {?} lang
* @return {?}
*/
TranslocoService.prototype.isScopeWithLang = /**
* Whether the scope with lang
*
* \@example
*
* todos/en => true
* todos => false
* @private
* @param {?} lang
* @return {?}
*/
function (lang) {
return this.isLang(getLangFromScope(lang));
};
/**
* @template T
* @param {?} key
* @param {?=} params
* @param {?=} lang
* @return {?}
*/
TranslocoService.prototype.translateObject = /**
* @template T
* @param {?} key
* @param {?=} params
* @param {?=} lang
* @return {?}
*/
function (key, params, lang) {
var _this = this;
if (lang === void 0) { lang = this.getActiveLang(); }
var e_1, _a;
if (isString(key) || Array.isArray(key)) {
if (Array.isArray(key)) {
return (/** @type {?} */ (key.map((/**
* @param {?} k
* @return {?}
*/
function (k) { return _this.translateObject(scope_1 ? scope_1 + "." + k : k, params, resolveLang_1); }))));
}
var _b = this.resolveLangAndScope(lang), resolveLang_1 = _b.resolveLang, scope_1 = _b.scope;
/** @type {?} */
var translation = this.getTranslation(resolveLang_1);
key = scope_1 ? scope_1 + "." + key : key;
/** @type {?} */
var value = unflatten(this.getObjectByKey(translation, key));
/* If an empty object was returned we want to try and translate the key as a string and not an object */
return isEmpty(value) ? this.translate(key, params, lang) : this.parser.transpile(value, params, translation);
}
/** @type {?} */
var translations = [];
try {
for (var _c = __values(this.getEntries(key)), _d = _c.next(); !_d.done; _d = _c.next()) {
var _e = __read(_d.value, 2), _key = _e[0], _params = _e[1];
translations.push(this.translateObject(_key, _params, lang));
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
}
finally { if (e_1) throw e_1.error; }
}
return translations;
};
/**
* @template T
* @param {?} key
* @param {?=} params
* @param {?=} lang
* @return {?}
*/
TranslocoService.prototype.selectTranslateObject = /**
* @template T
* @param {?} key
* @param {?=} params
* @param {?=} lang
* @return {?}
*/
function (key, params, lang) {
var _this = this;
if (isString(key) || Array.isArray(key)) {
return this.selectTranslate(key, params, lang, true);
}
var _a = __read(this.getEntries(key)), _b = __read(_a[0], 2), firstKey = _b[0], firstParams = _b[1], rest = _a.slice(1);
/* In order to avoid subscribing multiple times to the load language event by calling selectTranslateObject for each pair,
* we listen to when the first key has been translated (the language is loaded) and translate the rest synchronously */
return this.selectTranslateObject(firstKey, firstParams, lang).pipe(map((/**
* @param {?} value
* @return {?}
*/
function (value) {
var e_2, _a;
/** @type {?} */
var translations = [value];
try {
for (var rest_1 = __values(rest), rest_1_1 = rest_1.next(); !rest_1_1.done; rest_1_1 = rest_1.next()) {
var _b = __read(rest_1_1.value, 2), _key = _b[0], _params = _b[1];
translations.push(_this.translateObject(_key, _params, lang));
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (rest_1_1 && !rest_1_1.done && (_a = rest_1.return)) _a.call(rest_1);
}
finally { if (e_2) throw e_2.error; }
}
return translations;
})));
};
/**
* @param {?=} langOrScope
* @return {?}
*/
TranslocoService.prototype.getTranslation = /**
* @param {?=} langOrScope
* @return {?}
*/
function (langOrScope) {
if (langOrScope) {
if (this.isLang(langOrScope)) {
return this.translations.get(langOrScope) || {};
}
else {
// This is a scope, build the scope value from the translation object
var _a = this.resolveLangAndScope(langOrScope), scope = _a.scope, resolveLang = _a.resolveLang;
/** @type {?} */
var translation = this.translations.get(resolveLang) || {};
return this.getObjectByKey(translation, scope);
}
}
return this.translations;
};
/**
* Gets an object of translations for a given language
*
* @example
*
* selectTranslation().subscribe() - will return the current lang translation
* selectTranslation('es').subscribe()
* selectTranslation('admin-page').subscribe() - will return the current lang scope translation
* selectTranslation('admin-page/es').subscribe()
*/
/**
* Gets an object of translations for a given language
*
* \@example
*
* selectTranslation().subscribe() - will return the current lang translation
* selectTranslation('es').subscribe()
* selectTranslation('admin-page').subscribe() - will return the current lang scope translation
* selectTranslation('admin-page/es').subscribe()
* @param {?=} lang
* @return {?}
*/
TranslocoService.prototype.selectTranslation = /**
* Gets an object of translations for a given language
*
* \@example
*
* selectTranslation().subscribe() - will return the current lang translation
* selectTranslation('es').subscribe()
* selectTranslation('admin-page').subscribe() - will return the current lang scope translation
* selectTranslation('admin-page/es').subscribe()
* @param {?=} lang
* @return {?}
*/
function (lang) {
var _this = this;
/** @type {?} */
var language$ = this.langChanges$;
if (lang) {
/** @type {?} */
var scopeLangSpecified = getLangFromScope(lang) !== lang;
if (this.isLang(lang) || scopeLangSpecified) {
language$ = of(lang);
}
else {
language$ = this.langChanges$.pipe(map((/**
* @param {?} currentLang
* @return {?}
*/
function (currentLang) { return lang + "/" + currentLang; })));
}
}
return language$.pipe(switchMap((/**
* @param {?} language
* @return {?}
*/
function (language) { return _this.load(language).pipe(map((/**
* @return {?}
*/
function () { return _this.getTranslation(language); }))); })));
};
/**
* Sets or merge a given translation object to current lang
*
* @example
*
* setTranslation({ ... })
* setTranslation({ ... }, 'en')
* setTranslation({ ... }, 'es', { merge: false } )
* setTranslation({ ... }, 'todos/en', { merge: false } )
*/
/**
* Sets or merge a given translation object to current lang
*
* \@example
*
* setTranslation({ ... })
* setTranslation({ ... }, 'en')
* setTranslation({ ... }, 'es', { merge: false } )
* setTranslation({ ... }, 'todos/en', { merge: false } )
* @param {?} translation
* @param {?=} lang
* @param {?=} options
* @return {?}
*/
TranslocoService.prototype.setTranslation = /**
* Sets or merge a given translation object to current lang
*
* \@example
*
* setTranslation({ ... })
* setTranslation({ ... }, 'en')
* setTranslation({ ... }, 'es', { merge: false } )
* setTranslation({ ... }, 'todos/en', { merge: false } )
* @param {?} translation
* @param {?=} lang
* @param {?=} options
* @return {?}
*/
function (translation, lang, options) {
if (lang === void 0) { lang = this.getActiveLang(); }
if (options === void 0) { options = {}; }
var _a;
/** @type {?} */
var defaults = { merge: true, emitChange: true };
/** @type {?} */
var mergedOptions = __assign({}, defaults, options);
/** @type {?} */
var scope = getScopeFromLang(lang);
/**
* If this isn't a scope we use the whole translation as is
* otherwise we need to flat the scope and use it
* @type {?}
*/
var flattenScopeOrTranslation = translation;
// Merged the scoped language into the active language
if (scope) {
/** @type {?} */
var key = this.getMappedScope(scope);
flattenScopeOrTranslation = flatten((_a = {}, _a[key] = translation, _a));
}
/** @type {?} */
var currentLang = scope ? getLangFromScope(lang) : lang;
/** @type {?} */
var mergedTranslation = __assign({}, (mergedOptions.merge && this.getTranslation(currentLang)), flattenScopeOrTranslation);
/** @type {?} */
var flattenTranslation = this.mergedConfig.flatten.aot ? mergedTranslation : flatten(mergedTranslation);
/** @type {?} */
var withHook = this.interceptor.preSaveTranslation(flattenTranslation, currentLang);
this.translations.set(currentLang, withHook);
mergedOptions.emitChange && this.setActiveLang(this.getActiveLang());
};
/**
* Sets translation key with given value
*
* @example
*
* setTranslationKey('key', 'value')
* setTranslationKey('key.nested', 'value')
* setTranslationKey('key.nested', 'value', 'en')
* setTranslationKey('key.nested', 'value', 'en', { emitChange: false } )
*/
/**
* Sets translation key with given value
*
* \@example
*
* setTranslationKey('key', 'value')
* setTranslationKey('key.nested', 'value')
* setTranslationKey('key.nested', 'value', 'en')
* setTranslationKey('key.nested', 'value', 'en', { emitChange: false } )
* @param {?} key
* @param {?} value
* @param {?=} lang
* @param {?=} options
* @return {?}
*/
TranslocoService.prototype.setTranslationKey = /**
* Sets translation key with given value
*
* \@example
*
* setTranslationKey('key', 'value')
* setTranslationKey('key.nested', 'value')
* setTranslationKey('key.nested', 'value', 'en')
* setTranslationKey('key.nested', 'value', 'en', { emitChange: false } )
* @param {?} key
* @param {?} value
* @param {?=} lang
* @param {?=} options
* @return {?}
*/
function (key, value, lang,
// Todo: Use Omit and merge options and lang to one object in v3
options) {
if (lang === void 0) { lang = this.getActiveLang(); }
if (options === void 0) { options = {}; }
var _a;
/** @type {?} */
var withHook = this.interceptor.preSaveTranslationKey(key, value, lang);
/** @type {?} */
var newValue = (_a = {},
_a[key] = withHook,
_a);
this.setTranslation(newValue, lang, __assign({}, options, { merge: true }));
};
/**
* Sets the fallback lang for the currently active language
* @param fallbackLang
*/
/**
* Sets the fallback lang for the currently active language
* @param {?} __0
* @return {?}
*/
TranslocoService.prototype.setFallbackLangForMissingTranslation = /**
* Sets the fallback lang for the currently active language
* @param {?} __0
* @return {?}
*/
function (_a) {
var fallbackLang = _a.fallbackLang;
/** @type {?} */
var lang = Array.isArray(fallbackLang) ? fallbackLang[0] : fallbackLang;
if (this.useFallbackTranslation(lang) && fallbackLang) {
this.firstFallbackLang = lang;
}
};
/**
* @internal
*/
/**
* \@internal
* @param {?} key
* @param {?} value
* @param {?=} params
* @return {?}
*/
TranslocoService.prototype._handleMissingKey = /**
* \@internal
* @param {?} key
* @param {?} value
* @param {?=} params
* @return {?}
*/
function (key, value, params) {
if (this.config.missingHandler.allowEmpty && value === '') {
return '';
}
if (this.useFallbackTranslation() && !this.isResolvedMissingOnce) {
// We need to set it to true to prevent a loop
this.isResolvedMissingOnce = true;
/** @type {?} */
var fallbackValue = this.translate(key, params, this.firstFallbackLang);
this.isResolvedMissingOnce = false;
return fallbackValue;
}
return this.missingHandler.handle(key, this.getMissingHandlerData(), params);
};
/**
* @internal
*/
/**
* \@internal
* @param {?} lang
* @return {?}
*/
TranslocoService.prototype._isLangScoped = /**
* \@internal
* @param {?} lang
* @return {?}
*/
function (lang) {
return this.getAvailableLangsIds().indexOf(lang) === -1;
};
/**
* Checks if a given string is one of the specified available languages.
* @returns
* True if the given string is an available language.
* False if the given string is not an available language.
*/
/**
* Checks if a given string is one of the specified available languages.
* @param {?} lang
* @return {?}
* True if the given string is an available language.
* False if the given string is not an available language.
*/
TranslocoService.prototype.isLang = /**
* Checks if a given string is one of the specified available l