UNPKG

@ngneat/transloco

Version:

The internationalization (i18n) library for Angular

1,652 lines (1,640 loc) 91.1 kB
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