UNPKG

i18n-js

Version:

A small library to provide I18n on JavaScript.

300 lines 13.9 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.I18n = void 0; const get_1 = __importDefault(require("lodash/get")); const has_1 = __importDefault(require("lodash/has")); const merge_1 = __importDefault(require("lodash/merge")); const Locales_1 = require("./Locales"); const Pluralization_1 = require("./Pluralization"); const MissingTranslation_1 = require("./MissingTranslation"); const helpers_1 = require("./helpers"); const DEFAULT_I18N_OPTIONS = { defaultLocale: "en", locale: "en", defaultSeparator: ".", placeholder: /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm, enableFallback: false, missingBehavior: "message", missingTranslationPrefix: "", missingPlaceholder: (_i18n, placeholder) => `[missing "${placeholder}" value]`, nullPlaceholder: (i18n, placeholder, message, options) => i18n.missingPlaceholder(i18n, placeholder, message, options), transformKey: (key) => key, }; class I18n { constructor(translations = {}, options = {}) { this._locale = DEFAULT_I18N_OPTIONS.locale; this._defaultLocale = DEFAULT_I18N_OPTIONS.defaultLocale; this._version = 0; this.onChangeHandlers = []; this.translations = {}; this.t = this.translate; this.p = this.pluralize; this.l = this.localize; this.distanceOfTimeInWords = this.timeAgoInWords; const { locale, enableFallback, missingBehavior, missingTranslationPrefix, missingPlaceholder, nullPlaceholder, defaultLocale, defaultSeparator, placeholder, transformKey, } = Object.assign(Object.assign({}, DEFAULT_I18N_OPTIONS), options); this.locale = locale; this.defaultLocale = defaultLocale; this.defaultSeparator = defaultSeparator; this.enableFallback = enableFallback; this.locale = locale; this.missingBehavior = missingBehavior; this.missingTranslationPrefix = missingTranslationPrefix; this.missingPlaceholder = missingPlaceholder; this.nullPlaceholder = nullPlaceholder; this.placeholder = placeholder; this.pluralization = new Pluralization_1.Pluralization(this); this.locales = new Locales_1.Locales(this); this.missingTranslation = new MissingTranslation_1.MissingTranslation(this); this.transformKey = transformKey; this.interpolate = helpers_1.interpolate; this.store(translations); } store(translations) { (0, merge_1.default)(this.translations, translations); this.hasChanged(); } get locale() { return this._locale || this.defaultLocale || "en"; } set locale(newLocale) { if (typeof newLocale !== "string") { throw new Error(`Expected newLocale to be a string; got ${(0, helpers_1.inferType)(newLocale)}`); } const changed = this._locale !== newLocale; this._locale = newLocale; if (changed) { this.hasChanged(); } } get defaultLocale() { return this._defaultLocale || "en"; } set defaultLocale(newLocale) { if (typeof newLocale !== "string") { throw new Error(`Expected newLocale to be a string; got ${(0, helpers_1.inferType)(newLocale)}`); } const changed = this._defaultLocale !== newLocale; this._defaultLocale = newLocale; if (changed) { this.hasChanged(); } } translate(scope, options) { options = Object.assign({}, options); const translationOptions = (0, helpers_1.createTranslationOptions)(this, scope, options); let translation; const hasFoundTranslation = translationOptions.some((translationOption) => { if ((0, helpers_1.isSet)(translationOption.scope)) { translation = (0, helpers_1.lookup)(this, translationOption.scope, options); } else if ((0, helpers_1.isSet)(translationOption.message)) { translation = translationOption.message; } return translation !== undefined && translation !== null; }); if (!hasFoundTranslation) { return this.missingTranslation.get(scope, options); } if (typeof translation === "string") { translation = this.interpolate(this, translation, options); } else if (typeof translation === "object" && translation && (0, helpers_1.isSet)(options.count)) { translation = (0, helpers_1.pluralize)({ i18n: this, count: options.count || 0, scope: translation, options, baseScope: (0, helpers_1.getFullScope)(this, scope, options), }); } if (options && translation instanceof Array) { translation = translation.map((entry) => typeof entry === "string" ? (0, helpers_1.interpolate)(this, entry, options) : entry); } return translation; } pluralize(count, scope, options) { return (0, helpers_1.pluralize)({ i18n: this, count, scope, options: Object.assign({}, options), baseScope: (0, helpers_1.getFullScope)(this, scope, options !== null && options !== void 0 ? options : {}), }); } localize(type, value, options) { options = Object.assign({}, options); if (value === undefined || value === null) { return ""; } switch (type) { case "currency": return this.numberToCurrency(value); case "number": return (0, helpers_1.formatNumber)(value, Object.assign({ delimiter: ",", precision: 3, separator: ".", significant: false, stripInsignificantZeros: false }, (0, helpers_1.lookup)(this, "number.format"))); case "percentage": return this.numberToPercentage(value); default: { let localizedValue; if (type.match(/^(date|time)/)) { localizedValue = this.toTime(type, value); } else { localizedValue = value.toString(); } return (0, helpers_1.interpolate)(this, localizedValue, options); } } } toTime(scope, input) { const date = (0, helpers_1.parseDate)(input); const format = (0, helpers_1.lookup)(this, scope); if (date.toString().match(/invalid/i)) { return date.toString(); } if (!format) { return date.toString(); } return this.strftime(date, format); } numberToCurrency(input, options = {}) { return (0, helpers_1.formatNumber)(input, Object.assign(Object.assign(Object.assign({ delimiter: ",", format: "%u%n", precision: 2, separator: ".", significant: false, stripInsignificantZeros: false, unit: "$" }, (0, helpers_1.camelCaseKeys)(this.get("number.format"))), (0, helpers_1.camelCaseKeys)(this.get("number.currency.format"))), options)); } numberToPercentage(input, options = {}) { return (0, helpers_1.formatNumber)(input, Object.assign(Object.assign(Object.assign({ delimiter: "", format: "%n%", precision: 3, stripInsignificantZeros: false, separator: ".", significant: false }, (0, helpers_1.camelCaseKeys)(this.get("number.format"))), (0, helpers_1.camelCaseKeys)(this.get("number.percentage.format"))), options)); } numberToHumanSize(input, options = {}) { return (0, helpers_1.numberToHumanSize)(this, input, Object.assign(Object.assign(Object.assign({ delimiter: "", precision: 3, significant: true, stripInsignificantZeros: true, units: { billion: "Billion", million: "Million", quadrillion: "Quadrillion", thousand: "Thousand", trillion: "Trillion", unit: "", } }, (0, helpers_1.camelCaseKeys)(this.get("number.human.format"))), (0, helpers_1.camelCaseKeys)(this.get("number.human.storage_units"))), options)); } numberToHuman(input, options = {}) { return (0, helpers_1.numberToHuman)(this, input, Object.assign(Object.assign(Object.assign({ delimiter: "", separator: ".", precision: 3, significant: true, stripInsignificantZeros: true, format: "%n %u", roundMode: "default", units: { billion: "Billion", million: "Million", quadrillion: "Quadrillion", thousand: "Thousand", trillion: "Trillion", unit: "", } }, (0, helpers_1.camelCaseKeys)(this.get("number.human.format"))), (0, helpers_1.camelCaseKeys)(this.get("number.human.decimal_units"))), options)); } numberToRounded(input, options) { return (0, helpers_1.formatNumber)(input, Object.assign({ unit: "", precision: 3, significant: false, separator: ".", delimiter: "", stripInsignificantZeros: false }, options)); } numberToDelimited(input, options = {}) { return (0, helpers_1.numberToDelimited)(input, Object.assign({ delimiterPattern: /(\d)(?=(\d\d\d)+(?!\d))/g, delimiter: ",", separator: "." }, options)); } withLocale(locale, callback) { return __awaiter(this, void 0, void 0, function* () { const originalLocale = this.locale; try { this.locale = locale; yield callback(); } finally { this.locale = originalLocale; } }); } strftime(date, format, options = {}) { return (0, helpers_1.strftime)(date, format, Object.assign(Object.assign(Object.assign({}, (0, helpers_1.camelCaseKeys)((0, helpers_1.lookup)(this, "date"))), { meridian: { am: (0, helpers_1.lookup)(this, "time.am") || "AM", pm: (0, helpers_1.lookup)(this, "time.pm") || "PM", } }), options)); } update(path, override, options = { strict: false }) { if (options.strict && !(0, has_1.default)(this.translations, path)) { throw new Error(`The path "${path}" is not currently defined`); } const currentNode = (0, get_1.default)(this.translations, path); const currentType = (0, helpers_1.inferType)(currentNode); const overrideType = (0, helpers_1.inferType)(override); if (options.strict && currentType !== overrideType) { throw new Error(`The current type for "${path}" is "${currentType}", but you're trying to override it with "${overrideType}"`); } let newNode; if (overrideType === "object") { newNode = Object.assign(Object.assign({}, currentNode), override); } else { newNode = override; } const components = path.split(this.defaultSeparator); const prop = components.pop(); let buffer = this.translations; for (const component of components) { if (!buffer[component]) { buffer[component] = {}; } buffer = buffer[component]; } buffer[prop] = newNode; this.hasChanged(); } toSentence(items, options = {}) { const { wordsConnector, twoWordsConnector, lastWordConnector } = Object.assign(Object.assign({ wordsConnector: ", ", twoWordsConnector: " and ", lastWordConnector: ", and " }, (0, helpers_1.camelCaseKeys)((0, helpers_1.lookup)(this, "support.array"))), options); const size = items.length; switch (size) { case 0: return ""; case 1: return `${items[0]}`; case 2: return items.join(twoWordsConnector); default: return [ items.slice(0, size - 1).join(wordsConnector), lastWordConnector, items[size - 1], ].join(""); } } timeAgoInWords(fromTime, toTime, options = {}) { return (0, helpers_1.timeAgoInWords)(this, fromTime, toTime, options); } onChange(callback) { this.onChangeHandlers.push(callback); return () => { this.onChangeHandlers.splice(this.onChangeHandlers.indexOf(callback), 1); }; } get version() { return this._version; } formatNumber(input, options = {}) { options = Object.assign(Object.assign({ delimiter: ",", precision: 3, separator: ".", unit: "", format: "%u%n", significant: false, stripInsignificantZeros: false }, (0, helpers_1.camelCaseKeys)(this.get("number.format"))), options); return (0, helpers_1.formatNumber)(input, options); } get(scope) { return (0, helpers_1.lookup)(this, scope); } runCallbacks() { this.onChangeHandlers.forEach((callback) => callback(this)); } hasChanged() { this._version += 1; this.runCallbacks(); } } exports.I18n = I18n; //# sourceMappingURL=I18n.js.map