@nexim/localizer
Version:
Lightweight i18n utilities to handle translations, number formatting, date/time localization using native browser APIs.
146 lines • 5.17 kB
JavaScript
import { createLogger } from './logger.js';
import { convertDigits } from './unicode-digits.js';
const logger = createLogger('@nexim/localizer');
/**
* Provides localization and internationalization functionality.
*
* @remarks
* This class handles number formatting, text translation, date formatting,
* and relative time calculations based on the specified locale.
*/
export class Localizer {
/**
* Time units used for relative time calculations.
* @internal
*/
constructor(options__) {
this.options__ = options__;
this.numberFormatter_ = new Intl.NumberFormat(this.options__.locale.code);
}
/**
* 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 === undefined) {
logger.error('message', `key_not_found: ${key}`);
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 convertDigits(str, this.options__.locale.language);
}
/**
* 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) / 1000;
// Find the appropriate unit for the time difference
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: 31536000 },
{ label: 'month', seconds: 2592000 },
{ label: 'week', seconds: 604800 },
{ label: 'day', seconds: 86400 },
{ label: 'hour', seconds: 3600 },
{ label: 'minute', seconds: 60 },
{ label: 'second', seconds: 1 },
];
//# sourceMappingURL=main.js.map