UNPKG

@softkit/i18n

Version:

This library is a simple wrapper based on [nestjs-i18n](https://nestjs-i18n.com/)

244 lines 10.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.I18nService = void 0; const tslib_1 = require("tslib"); /* eslint-disable @typescript-eslint/ban-ts-comment */ const common_1 = require("@nestjs/common"); const i18n_constants_1 = require("../i18n.constants"); const class_validator_1 = require("class-validator"); const utils_1 = require("../utils"); const loaders_utils_1 = require("../utils/loaders-utils"); const i18n_error_1 = require("../i18n.error"); const pluralKeys = ['zero', 'one', 'two', 'few', 'many', 'other']; let I18nService = class I18nService { constructor(i18nOptions, translations, supportedLanguages, logger, loaders) { this.i18nOptions = i18nOptions; this.translations = translations; this.supportedLanguages = supportedLanguages; this.logger = logger; this.loaders = loaders; this.pluralRules = new Map(); this.hbsHelper = (key, args, options) => { if (!options) { options = args; } const lang = options.lookupProperty(options.data.root, 'i18nLang'); return this.t(key, { lang, args }); }; } translate(key, options) { options = { lang: this.i18nOptions.fallbackLanguage, ...options, }; const { defaultValue } = options; let { lang } = options; if (lang === 'debug') { return key; } const previousFallbackLang = lang; lang = lang ?? this.i18nOptions.fallbackLanguage; lang = this.resolveLanguage(lang); const translationsByLanguage = this.translations[lang]; const translation = this.translateObject(key, (translationsByLanguage ?? key), lang, options, translationsByLanguage); if (translationsByLanguage == undefined || !translation) { const translationKeyMissing = `Translation "${key}" in "${lang}" does not exist.`; if (lang !== this.i18nOptions.fallbackLanguage || !!defaultValue) { if (this.i18nOptions.logging && this.i18nOptions.throwOnMissingKey) { throw new i18n_error_1.I18nError(translationKeyMissing); } const nextFallbackLanguage = this.getFallbackLanguage(lang); if (previousFallbackLang !== nextFallbackLanguage) { return this.translate(key, { ...options, lang: nextFallbackLanguage, }); } } this.logger.error(translationKeyMissing); } return (translation ?? key); } t(key, options) { return this.translate(key, options); } getSupportedLanguages() { return this.supportedLanguages; } getTranslations() { return this.translations; } async refresh() { if (Object.keys(this.translations).length === 0) { this.translations = await (0, loaders_utils_1.processTranslations)(this.loaders); } if (this.supportedLanguages.length === 0) { this.supportedLanguages = await (0, loaders_utils_1.processLanguages)(this.loaders); } } resolveLanguage(lang) { if (this.i18nOptions.fallbacks && !this.supportedLanguages.includes(lang)) { const sanitizedLang = lang.includes('-') ? [...lang.slice(0, Math.max(0, lang.indexOf('-'))), '-*'] : lang; for (const key in this.i18nOptions.fallbacks) { if (key === lang || key === sanitizedLang) { lang = this.i18nOptions.fallbacks[key]; break; } } } return lang; } async validate(value, options) { const errors = await (0, class_validator_1.validate)(value, this.i18nOptions.validatorOptions); return (0, utils_1.formatI18nErrors)(errors, this, options); } getFallbackLanguage(lang) { let regionSepIndex = -1; if (lang.includes('-')) { regionSepIndex = lang.lastIndexOf('-'); } if (lang.includes('_')) { regionSepIndex = lang.lastIndexOf('_'); } return regionSepIndex === -1 ? this.i18nOptions.fallbackLanguage : lang.slice(0, regionSepIndex); } translateObject(key, translations, lang, options, rootTranslations) { const keys = key.split('.'); const [firstKey] = keys; const args = options?.args; if (keys.length > 1 && translations instanceof Object && !translations[key]) { const newKey = keys.slice(1, keys.length).join('.'); if (translations && translations[firstKey]) { return this.translateObject(newKey, translations[firstKey], lang, options, rootTranslations); } } let translation; if (typeof translations === 'object' && translations[key]) { translation = translations[key]; } else { this.logger.error(`Error: Translation key not found, fix it! Key: ${key}`); translation = options?.defaultValue; } if (translation && args !== undefined && args !== null) { const pluralObject = this.getPluralObject(translation); if (pluralObject && !Array.isArray(args) && args['count'] !== undefined) { const count = Number(args['count']); if (!this.pluralRules.has(lang)) { this.pluralRules.set(lang, new Intl.PluralRules(lang)); } const pluralRules = this.pluralRules.get(lang); if (pluralRules) { const pluralCategory = pluralRules.select(count); const translationValue = pluralObject[pluralCategory]; if (count === 0 && pluralObject['zero']) { translation = pluralObject['zero']; } else if (translationValue) { translation = translationValue; } } } else if (translation instanceof Object) { const translations = translation; const result = Object.keys(translation).reduce((obj, nestedKey) => { return { ...obj, [nestedKey]: this.translateObject(nestedKey, translations, lang, options, rootTranslations), }; }, {}); if (Array.isArray(translation)) { return Object.values(result); } return result; } if (typeof translation === 'string') { const formatter = this.i18nOptions.formatter; if (formatter) { translation = formatter(translation, ...(Array.isArray(args) ? args : [args])); } } if (typeof translation === 'string') { const nestedTranslations = this.getNestedTranslations(translation); if (nestedTranslations && nestedTranslations.length > 0) { let offset = 0; for (const nestedTranslation of nestedTranslations) { const result = rootTranslations ? this.translateObject(nestedTranslation.key, rootTranslations, lang, { ...options, args: { parent: options && options.args, ...nestedTranslation.args, }, }) ?? '' : ''; translation = translation.slice(0, // @ts-ignore Math.max(0, nestedTranslation.index - offset)) + result + translation.slice(Math.max(0, // @ts-ignore nestedTranslation.index + nestedTranslation.length - offset)); // @ts-ignore offset = offset + (nestedTranslation.length - result.length); } } } } return translation; } getPluralObject(translation) { for (const k of pluralKeys) { if (translation[k]) { return translation; } } return undefined; } getNestedTranslations(translation) { const list = []; const regex = /\$t\((.*?)(,(.*?))?\)/g; let result; while ((result = regex.exec(translation))) { let key = undefined; let args = {}; let index = undefined; let length = undefined; if (result && result.length > 0) { key = result[1].trim(); index = result.index; length = result[0].length; if (result.length >= 3 && result[3]) { try { args = JSON.parse(result[3]); } catch (error) { this.logger.error(`Error while parsing JSON`, error); } } } if (key) { list.push({ index, length, key, args }); } result = undefined; } return list.length > 0 ? list : undefined; } }; exports.I18nService = I18nService; exports.I18nService = I18nService = tslib_1.__decorate([ (0, common_1.Injectable)(), tslib_1.__param(0, (0, common_1.Inject)(i18n_constants_1.I18N_OPTIONS)), tslib_1.__param(1, (0, common_1.Inject)(i18n_constants_1.I18N_TRANSLATIONS)), tslib_1.__param(2, (0, common_1.Inject)(i18n_constants_1.I18N_LANGUAGES)), tslib_1.__param(4, (0, common_1.Inject)(i18n_constants_1.I18N_LOADERS)), tslib_1.__metadata("design:paramtypes", [Object, Object, Array, common_1.Logger, Array]) ], I18nService); //# sourceMappingURL=i18n.service.js.map