import _objectSpread from "@babel/runtime/helpers/objectSpread"; import _typeof from "@babel/runtime/helpers/typeof"; import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _createClass from "@babel/runtime/helpers/createClass"; import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn"; import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf"; import _inherits from "@babel/runtime/helpers/inherits"; import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized"; import baseLogger from './logger.js'; import EventEmitter from './EventEmitter.js'; import postProcessor from './postProcessor.js'; import * as utils from './utils.js'; var Translator = /*#__PURE__*/ function (_EventEmitter) { _inherits(Translator, _EventEmitter); function Translator(services) { var _this; var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classCallCheck(this, Translator); _this = _possibleConstructorReturn(this, _getPrototypeOf(Translator).call(this)); EventEmitter.call(_assertThisInitialized(_assertThisInitialized(_this))); // <=IE10 fix (unable to call parent constructor) utils.copy(['resourceStore', 'languageUtils', 'pluralResolver', 'interpolator', 'backendConnector', 'i18nFormat'], services, _assertThisInitialized(_assertThisInitialized(_this))); _this.options = options; if (_this.options.keySeparator === undefined) { _this.options.keySeparator = '.'; } _this.logger = baseLogger.create('translator'); return _this; } _createClass(Translator, [{ key: "changeLanguage", value: function changeLanguage(lng) { if (lng) this.language = lng; } }, { key: "exists", value: function exists(key) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { interpolation: {} }; var resolved = this.resolve(key, options); return resolved && resolved.res !== undefined; } }, { key: "extractFromKey", value: function extractFromKey(key, options) { var nsSeparator = options.nsSeparator || this.options.nsSeparator; if (nsSeparator === undefined) nsSeparator = ':'; var keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator; var namespaces = options.ns || this.options.defaultNS; if (nsSeparator && key.indexOf(nsSeparator) > -1) { var parts = key.split(nsSeparator); if (nsSeparator !== keySeparator || nsSeparator === keySeparator && this.options.ns.indexOf(parts[0]) > -1) namespaces = parts.shift(); key = parts.join(keySeparator); } if (typeof namespaces === 'string') namespaces = [namespaces]; return { key: key, namespaces: namespaces }; } }, { key: "translate", value: function translate(keys, options) { var _this2 = this; if (_typeof(options) !== 'object' && this.options.overloadTranslationOptionHandler) { /* eslint prefer-rest-params: 0 */ options = this.options.overloadTranslationOptionHandler(arguments); } if (!options) options = {}; // non valid keys handling if (keys === undefined || keys === null) return ''; if (!Array.isArray(keys)) keys = [String(keys)]; // separators var keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator; // get namespace(s) var _this$extractFromKey = this.extractFromKey(keys[keys.length - 1], options), key = _this$extractFromKey.key, namespaces = _this$extractFromKey.namespaces; var namespace = namespaces[namespaces.length - 1]; // return key on CIMode var lng = options.lng || this.language; var appendNamespaceToCIMode = options.appendNamespaceToCIMode || this.options.appendNamespaceToCIMode; if (lng && lng.toLowerCase() === 'cimode') { if (appendNamespaceToCIMode) { var nsSeparator = options.nsSeparator || this.options.nsSeparator; return namespace + nsSeparator + key; } return key; } // resolve from store var resolved = this.resolve(keys, options); var res = resolved && resolved.res; var resUsedKey = resolved && resolved.usedKey || key; var resExactUsedKey = resolved && resolved.exactUsedKey || key; var resType = Object.prototype.toString.apply(res); var noObject = ['[object Number]', '[object Function]', '[object RegExp]']; var joinArrays = options.joinArrays !== undefined ? options.joinArrays : this.options.joinArrays; // object var handleAsObjectInI18nFormat = !this.i18nFormat || this.i18nFormat.handleAsObject; var handleAsObject = typeof res !== 'string' && typeof res !== 'boolean' && typeof res !== 'number'; if (handleAsObjectInI18nFormat && res && handleAsObject && noObject.indexOf(resType) < 0 && !(typeof joinArrays === 'string' && resType === '[object Array]')) { if (!options.returnObjects && !this.options.returnObjects) { this.logger.warn('accessing an object - but returnObjects options is not enabled!'); return this.options.returnedObjectHandler ? this.options.returnedObjectHandler(resUsedKey, res, options) : "key '".concat(key, " (").concat(this.language, ")' returned an object instead of string."); } // if we got a separator we loop over children - else we just return object as is // as having it set to false means no hierarchy so no lookup for nested values if (keySeparator) { var resTypeIsArray = resType === '[object Array]'; var copy = resTypeIsArray ? [] : {}; // apply child translation on a copy /* eslint no-restricted-syntax: 0 */ var newKeyToUse = resTypeIsArray ? resExactUsedKey : resUsedKey; for (var m in res) { if (Object.prototype.hasOwnProperty.call(res, m)) { var deepKey = "".concat(newKeyToUse).concat(keySeparator).concat(m); copy[m] = this.translate(deepKey, _objectSpread({}, options, { joinArrays: false, ns: namespaces })); if (copy[m] === deepKey) copy[m] = res[m]; // if nothing found use orginal value as fallback } } res = copy; } } else if (handleAsObjectInI18nFormat && typeof joinArrays === 'string' && resType === '[object Array]') { // array special treatment res = res.join(joinArrays); if (res) res = this.extendTranslation(res, keys, options); } else { // string, empty or null var usedDefault = false; var usedKey = false; // fallback value if (!this.isValidLookup(res) && options.defaultValue !== undefined) { usedDefault = true; if (options.count !== undefined) { var suffix = this.pluralResolver.getSuffix(lng, options.count); res = options["defaultValue".concat(suffix)]; } if (!res) res = options.defaultValue; } if (!this.isValidLookup(res)) { usedKey = true; res = key; } // save missing var updateMissing = options.defaultValue && options.defaultValue !== res && this.options.updateMissing; if (usedKey || usedDefault || updateMissing) { this.logger.log(updateMissing ? 'updateKey' : 'missingKey', lng, namespace, key, updateMissing ? options.defaultValue : res); var lngs = []; var fallbackLngs = this.languageUtils.getFallbackCodes(this.options.fallbackLng, options.lng || this.language); if (this.options.saveMissingTo === 'fallback' && fallbackLngs && fallbackLngs[0]) { for (var i = 0; i < fallbackLngs.length; i++) { lngs.push(fallbackLngs[i]); } } else if (this.options.saveMissingTo === 'all') { lngs = this.languageUtils.toResolveHierarchy(options.lng || this.language); } else { lngs.push(options.lng || this.language); } var send = function send(l, k) { if (_this2.options.missingKeyHandler) { _this2.options.missingKeyHandler(l, namespace, k, updateMissing ? options.defaultValue : res, updateMissing, options); } else if (_this2.backendConnector && _this2.backendConnector.saveMissing) { _this2.backendConnector.saveMissing(l, namespace, k, updateMissing ? options.defaultValue : res, updateMissing, options); } _this2.emit('missingKey', l, namespace, k, res); }; if (this.options.saveMissing) { var needsPluralHandling = options.count !== undefined && typeof options.count !== 'string'; if (this.options.saveMissingPlurals && needsPluralHandling) { lngs.forEach(function (l) { var plurals = _this2.pluralResolver.getPluralFormsOfKey(l, key); plurals.forEach(function (p) { return send([l], p); }); }); } else { send(lngs, key); } } } // extend res = this.extendTranslation(res, keys, options, resolved); // append namespace if still key if (usedKey && res === key && this.options.appendNamespaceToMissingKey) res = "".concat(namespace, ":").concat(key); // parseMissingKeyHandler if (usedKey && this.options.parseMissingKeyHandler) res = this.options.parseMissingKeyHandler(res); } // return return res; } }, { key: "extendTranslation", value: function extendTranslation(res, key, options, resolved) { var _this3 = this; if (this.i18nFormat && this.i18nFormat.parse) { res = this.i18nFormat.parse(res, options, resolved.usedLng, resolved.usedNS, resolved.usedKey, { resolved: resolved }); } else if (!options.skipInterpolation) { // i18next.parsing if (options.interpolation) this.interpolator.init(_objectSpread({}, options, { interpolation: _objectSpread({}, this.options.interpolation, options.interpolation) })); // interpolate var data = options.replace && typeof options.replace !== 'string' ? options.replace : options; if (this.options.interpolation.defaultVariables) data = _objectSpread({}, this.options.interpolation.defaultVariables, data); res = this.interpolator.interpolate(res, data, options.lng || this.language, options); // nesting if (options.nest !== false) res = this.interpolator.nest(res, function () { return _this3.translate.apply(_this3, arguments); }, options); if (options.interpolation) this.interpolator.reset(); } // post process var postProcess = options.postProcess || this.options.postProcess; var postProcessorNames = typeof postProcess === 'string' ? [postProcess] : postProcess; if (res !== undefined && res !== null && postProcessorNames && postProcessorNames.length && options.applyPostProcessor !== false) { res = postProcessor.handle(postProcessorNames, res, key, options, this); } return res; } }, { key: "resolve", value: function resolve(keys) { var _this4 = this; var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var found; var usedKey; // plain key var exactUsedKey; // key with context / plural var usedLng; var usedNS; if (typeof keys === 'string') keys = [keys]; // forEach possible key keys.forEach(function (k) { if (_this4.isValidLookup(found)) return; var extracted = _this4.extractFromKey(k, options); var key = extracted.key; usedKey = key; var namespaces = extracted.namespaces; if (_this4.options.fallbackNS) namespaces = namespaces.concat(_this4.options.fallbackNS); var needsPluralHandling = options.count !== undefined && typeof options.count !== 'string'; var needsContextHandling = options.context !== undefined && typeof options.context === 'string' && options.context !== ''; var codes = options.lngs ? options.lngs : _this4.languageUtils.toResolveHierarchy(options.lng || _this4.language, options.fallbackLng); namespaces.forEach(function (ns) { if (_this4.isValidLookup(found)) return; usedNS = ns; codes.forEach(function (code) { if (_this4.isValidLookup(found)) return; usedLng = code; var finalKey = key; var finalKeys = [finalKey]; if (_this4.i18nFormat && _this4.i18nFormat.addLookupKeys) { _this4.i18nFormat.addLookupKeys(finalKeys, key, code, ns, options); } else { var pluralSuffix; if (needsPluralHandling) pluralSuffix = _this4.pluralResolver.getSuffix(code, options.count); // fallback for plural if context not found if (needsPluralHandling && needsContextHandling) finalKeys.push(finalKey + pluralSuffix); // get key for context if needed if (needsContextHandling) finalKeys.push(finalKey += "".concat(_this4.options.contextSeparator).concat(options.context)); // get key for plural if needed if (needsPluralHandling) finalKeys.push(finalKey += pluralSuffix); } // iterate over finalKeys starting with most specific pluralkey (-> contextkey only) -> singularkey only var possibleKey; /* eslint no-cond-assign: 0 */ while (possibleKey = finalKeys.pop()) { if (!_this4.isValidLookup(found)) { exactUsedKey = possibleKey; found = _this4.getResource(code, ns, possibleKey, options); } } }); }); }); return { res: found, usedKey: usedKey, exactUsedKey: exactUsedKey, usedLng: usedLng, usedNS: usedNS }; } }, { key: "isValidLookup", value: function isValidLookup(res) { return res !== undefined && !(!this.options.returnNull && res === null) && !(!this.options.returnEmptyString && res === ''); } }, { key: "getResource", value: function getResource(code, ns, key) { var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; if (this.i18nFormat && this.i18nFormat.getResource) return this.i18nFormat.getResource(code, ns, key, options); return this.resourceStore.getResource(code, ns, key, options); } }]); return Translator; }(EventEmitter); export default Translator;