UNPKG

@nexim/localizer

Version:

Lightweight i18n utilities to handle translations, number formatting, date/time localization using native browser APIs.

168 lines (166 loc) 5.95 kB
/* @nexim/localizer v1.1.1 */ "use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/main.ts var main_exports = {}; __export(main_exports, { Localizer: () => Localizer }); module.exports = __toCommonJS(main_exports); var import_logger = require("@alwatr/logger"); var import_package_tracer = require("@alwatr/package-tracer"); var import_unicode_digits = require("@alwatr/unicode-digits"); __dev_mode__: import_package_tracer.packageTracer.add("@nexim/localizer", "1.1.1"); var _Localizer = class _Localizer { /** * Creates a new instance of the Localizer class. * * @param options__ - Configuration options for localization */ constructor(options__) { this.options__ = options__; this.logger_ = (0, import_logger.createLogger)("@nexim/localizer"); this.numberFormatter_ = new Intl.NumberFormat(this.options__.locale.code); this.unicodeDigits_ = new import_unicode_digits.UnicodeDigits(this.options__.locale.language); } /** * Retrieves a localized message by key from the resource dictionary. * * @param key - The key to lookup in the resource dictionary * @returns The localized message string * * @remarks * - Returns "\{key\}" if the key is not found in the dictionary * - Returns an empty string if the key is null or undefined * * @example * ```typescript * const localizer = new Localizer({...}); * console.log(localizer.message('hello_world')); // "Hello world!" * console.log(localizer.message('missing_key')); // "{missing_key}" * ``` */ message(key) { if (!key) return ""; const msg = this.options__.resource?.[key]; if (msg === void 0) { this.logger_.accident("message", "l10n_key_not_found", "Key not defined in the localization resource", { key, locale: this.options__.locale }); return `{${key}}`; } return msg; } /** * Formats a number according to the current locale settings. * * @param number - The number to format * @param decimal - Number of decimal places (default: 2) * @returns Formatted number string using locale-specific formatting * * @example * ```typescript * const localizer = new Localizer({...}); * console.log(localizer.number(1234.567)); // "1,234.57" * console.log(localizer.number(1234.567, 1)); // "1,234.6" * ``` */ number(number, decimal = 2) { if (number == null) return ""; decimal = Math.pow(10, decimal); number = Math.round(number * decimal) / decimal; return this.numberFormatter_.format(number); } /** * Replaces all numeric digits in a string with their locale-specific Unicode equivalents. * * @param str - The input string containing numbers to replace * @returns String with numbers converted to locale-specific digits * * @example * ```typescript * const localizer = new Localizer({locale: {code: 'fa-IR', language: 'fa'}, ...}); * console.log(localizer.replaceNumber('123')); // '۱۲۳' * ``` */ replaceNumber(str) { return this.unicodeDigits_.translate(str); } /** * Formats a date according to the current locale settings. * * @param date - Date to format (as Date object or timestamp) * @param options - Intl.DateTimeFormatOptions for customizing the output * @returns Localized date string * * @example * ```typescript * const localizer = new Localizer({...}); * console.log(localizer.time(new Date())); // "4/21/2025" * ``` */ time(date, options) { if (typeof date === "number") date = new Date(date); return date.toLocaleDateString(this.options__.locale.code, options); } /** * Creates a relative time string comparing two dates. * * @param date - The date to compare (as Date object or timestamp) * @param from - Reference date for comparison (defaults to current time) * @param options - Formatting options for relative time * @returns Localized relative time string * * @example * ```typescript * const localizer = new Localizer({...}); * const date = new Date(Date.now() - 3600000); // 1 hour ago * console.log(localizer.relativeTime(date)); // "1 hour ago" * ``` */ relativeTime(date, from = Date.now(), options = { numeric: "auto", style: "narrow" }) { const rtf = new Intl.RelativeTimeFormat(this.options__.locale.code, options); if (typeof date !== "number") date = date.getTime(); if (typeof from !== "number") from = from.getTime(); const diffSec = (from - date) / 1e3; for (const unit of _Localizer.timeUnits_) { const interval = Math.floor(Math.abs(diffSec / unit.seconds)); if (interval >= 1) { return rtf.format(diffSec > 0 ? interval : -interval, unit.label); } } return rtf.format(0, "second"); } }; /** * Time units used for relative time calculations. * @internal */ _Localizer.timeUnits_ = [ { label: "year", seconds: 31536e3 }, { label: "month", seconds: 2592e3 }, { label: "week", seconds: 604800 }, { label: "day", seconds: 86400 }, { label: "hour", seconds: 3600 }, { label: "minute", seconds: 60 }, { label: "second", seconds: 1 } ]; var Localizer = _Localizer; //# sourceMappingURL=main.cjs.map