UNPKG

houser-js-utils

Version:

A comprehensive collection of TypeScript utility functions for common development tasks including array manipulation, string processing, date handling, random number generation, validation, and much more.

1 lines 23.6 kB
{"version":3,"file":"InternationalizationUtils.mjs","sources":["../src/InternationalizationUtils.ts"],"sourcesContent":["/**\n * @module InternationalizationUtils\n * @description A comprehensive collection of utility functions for internationalization and localization.\n * Provides methods for formatting dates, numbers, currencies, lists, handling plurals, relative time,\n * and accessing user locale preferences using the Intl API.\n * @example\n * ```typescript\n * import { InternationalizationUtils } from 'houser-js-utils';\n *\n * // Format currency\n * const price = InternationalizationUtils.formatCurrency(99.99, 'USD', 'en-US'); // \"$99.99\"\n *\n * // Format date\n * const date = InternationalizationUtils.formatDate(new Date(), 'en-US'); // \"1/1/2024\"\n *\n * // Get user's locale\n * const locale = InternationalizationUtils.getUserLocale(); // \"en-US\"\n * ```\n */\nexport const InternationalizationUtils = {\n /**\n * Formats a currency amount according to the specified locale and currency code.\n * @param amount - The numeric amount to format\n * @param currency - The currency code (e.g., 'USD', 'EUR', 'JPY')\n * @param locale - The locale to use for formatting (default: user's locale)\n * @param options - Additional Intl.NumberFormat options for customization\n * @returns The formatted currency string\n * @example\n * ```typescript\n * InternationalizationUtils.formatCurrency(99.99, 'USD', 'en-US'); // \"$99.99\"\n * InternationalizationUtils.formatCurrency(99.99, 'EUR', 'fr-FR'); // \"99,99 €\"\n * InternationalizationUtils.formatCurrency(1234.56, 'JPY', 'ja-JP'); // \"¥1,235\"\n * ```\n */\n formatCurrency(\n amount: number,\n currency: string = \"USD\",\n locale: string = InternationalizationUtils.getUserLocale(),\n options: Intl.NumberFormatOptions = {}\n ): string {\n return new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency,\n ...options,\n }).format(amount);\n },\n\n /**\n * Formats a date according to the specified locale and formatting options.\n * @param date - The date to format (Date object, timestamp, or date string)\n * @param locale - The locale to use for formatting (default: user's locale)\n * @param options - Intl.DateTimeFormat options for customization\n * @returns The formatted date string\n * @example\n * ```typescript\n * InternationalizationUtils.formatDate(new Date(), 'en-US'); // \"1/1/2024\"\n * InternationalizationUtils.formatDate(new Date(), 'fr-FR', { dateStyle: 'full' }); // \"lundi 1 janvier 2024\"\n * InternationalizationUtils.formatDate(Date.now(), 'de-DE', { year: 'numeric', month: 'long' }); // \"Januar 2024\"\n * ```\n */\n formatDate(\n date: Date | number | string,\n locale: string = InternationalizationUtils.getUserLocale(),\n options: Intl.DateTimeFormatOptions = {}\n ): string {\n const dateObj = typeof date === \"string\" ? new Date(date) : date;\n return new Intl.DateTimeFormat(locale, options).format(dateObj);\n },\n\n /**\n * Formats a date using a specific pattern string for custom date formats.\n * @param date - The date to format (Date object, timestamp, or date string)\n * @param format - The format pattern string (e.g., 'YYYY-MM-DD', 'DD/MM/YYYY')\n * @param locale - The locale to use (default: user's locale)\n * @returns The formatted date string according to the pattern\n * @example\n * ```typescript\n * InternationalizationUtils.formatDateWithPattern(new Date(), 'YYYY-MM-DD'); // \"2024-01-01\"\n * InternationalizationUtils.formatDateWithPattern(new Date(), 'DD/MM/YYYY'); // \"01/01/2024\"\n * InternationalizationUtils.formatDateWithPattern(new Date(), 'YYYY-MM-DD HH:mm:ss'); // \"2024-01-01 14:30:45\"\n * ```\n */\n formatDateWithPattern(\n date: Date | string | number,\n format: string = \"YYYY-MM-DD\",\n locale: string = navigator.language\n ): string {\n const d = new Date(date);\n\n // Create a formatter with the specified locale\n const formatter = new Intl.DateTimeFormat(locale, {\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hour12: false,\n timeZone: \"UTC\",\n });\n\n // Get the parts from the formatter\n let values: Record<string, string>;\n try {\n const parts = formatter.formatToParts(d);\n values = {};\n parts.forEach((part) => {\n values[part.type] = part.value;\n });\n } catch (e) {\n // Fallback for environments where formatToParts is not available\n const year = d.getUTCFullYear().toString();\n const month = (d.getUTCMonth() + 1).toString().padStart(2, \"0\");\n const day = d.getUTCDate().toString().padStart(2, \"0\");\n const hour = d.getUTCHours().toString().padStart(2, \"0\");\n const minute = d.getUTCMinutes().toString().padStart(2, \"0\");\n const second = d.getUTCSeconds().toString().padStart(2, \"0\");\n\n values = {\n year,\n month,\n day,\n hour,\n minute,\n second,\n };\n }\n\n // Map the parts to the format tokens\n return format.replace(/YYYY|MM|DD|HH|mm|ss/g, (match) => {\n switch (match) {\n case \"YYYY\":\n return values.year;\n case \"MM\":\n return values.month;\n case \"DD\":\n return values.day;\n case \"HH\":\n return values.hour;\n case \"mm\":\n return values.minute;\n case \"ss\":\n return values.second;\n default:\n return match;\n }\n });\n },\n\n /**\n * Formats a list of items according to locale-specific list formatting rules.\n * @param list - Array of strings to format into a list\n * @param locale - The locale to use for formatting (default: user's locale)\n * @param options - ListFormat options for type and style\n * @param options.type - The type of list: 'conjunction' (and), 'disjunction' (or), or 'unit'\n * @param options.style - The style: 'long', 'short', or 'narrow'\n * @returns The formatted list string\n * @example\n * ```typescript\n * InternationalizationUtils.formatList(['apple', 'banana', 'orange'], 'en-US'); // \"apple, banana, and orange\"\n * InternationalizationUtils.formatList(['red', 'blue'], 'en-US', { type: 'disjunction' }); // \"red or blue\"\n * InternationalizationUtils.formatList(['Jan', 'Feb', 'Mar'], 'fr-FR'); // \"Jan, Feb et Mar\"\n * ```\n */\n formatList(\n list: string[],\n locale: string = InternationalizationUtils.getUserLocale(),\n options: {\n type?: \"conjunction\" | \"disjunction\" | \"unit\";\n style?: \"long\" | \"short\" | \"narrow\";\n } = {}\n ): string {\n return (Intl as any).ListFormat(locale, options).format(list);\n },\n\n /**\n * Formats a number according to the specified locale and formatting options.\n * @param number - The number to format\n * @param locale - The locale to use for formatting (default: user's locale)\n * @param options - Intl.NumberFormat options for customization\n * @returns The formatted number string\n * @example\n * ```typescript\n * InternationalizationUtils.formatNumber(1234.56, 'en-US'); // \"1,234.56\"\n * InternationalizationUtils.formatNumber(1234.56, 'fr-FR'); // \"1 234,56\"\n * InternationalizationUtils.formatNumber(0.75, 'en-US', { style: 'percent' }); // \"75%\"\n * ```\n */\n formatNumber(\n number: number,\n locale: string = InternationalizationUtils.getUserLocale(),\n options: Intl.NumberFormatOptions = {}\n ): string {\n return new Intl.NumberFormat(locale, options).format(number);\n },\n\n /**\n * Determines the plural rule category for a given count according to locale rules.\n * @param count - The number to determine plural category for\n * @param locale - The locale to use for plural rules (default: user's locale)\n * @param options - Intl.PluralRules options\n * @returns The plural category: 'zero', 'one', 'two', 'few', 'many', or 'other'\n * @example\n * ```typescript\n * InternationalizationUtils.formatPlural(0, 'en-US'); // \"other\"\n * InternationalizationUtils.formatPlural(1, 'en-US'); // \"one\"\n * InternationalizationUtils.formatPlural(2, 'en-US'); // \"other\"\n * InternationalizationUtils.formatPlural(1, 'ru-RU'); // \"one\"\n * ```\n */\n formatPlural(\n count: number,\n locale: string = InternationalizationUtils.getUserLocale(),\n options: Intl.PluralRulesOptions = {}\n ): string {\n return new Intl.PluralRules(locale, options).select(count);\n },\n\n /**\n * Formats a relative time string (e.g., \"2 hours ago\", \"in 3 days\") for a given date.\n * @param date - The date to format relative to now (Date object, timestamp, or date string)\n * @param locale - The locale to use for formatting (default: user's locale)\n * @param options - Intl.RelativeTimeFormat options\n * @returns The formatted relative time string\n * @example\n * ```typescript\n * const now = new Date();\n * const anHourAgo = new Date(now.getTime() - 3600000);\n * InternationalizationUtils.formatRelativeTime(anHourAgo, 'en-US'); // \"1 hour ago\"\n *\n * const tomorrow = new Date(now.getTime() + 86400000);\n * InternationalizationUtils.formatRelativeTime(tomorrow, 'en-US'); // \"in 1 day\"\n * ```\n */\n formatRelativeTime(\n date: Date | number | string,\n locale: string = InternationalizationUtils.getUserLocale(),\n options: Intl.RelativeTimeFormatOptions = {}\n ): string {\n const dateObj = typeof date === \"string\" ? new Date(date) : date;\n const now = new Date();\n const diff =\n (dateObj instanceof Date ? dateObj.getTime() : dateObj) - now.getTime();\n const diffInSeconds = Math.round(diff / 1000);\n const diffInMinutes = Math.round(diffInSeconds / 60);\n const diffInHours = Math.round(diffInMinutes / 60);\n const diffInDays = Math.round(diffInHours / 24);\n\n const rtf = new Intl.RelativeTimeFormat(locale, options);\n\n if (Math.abs(diffInSeconds) < 60) {\n return rtf.format(diffInSeconds, \"second\");\n }\n if (Math.abs(diffInMinutes) < 60) {\n return rtf.format(diffInMinutes, \"minute\");\n }\n if (Math.abs(diffInHours) < 24) {\n return rtf.format(diffInHours, \"hour\");\n }\n return rtf.format(diffInDays, \"day\");\n },\n\n /**\n * Gets the localized display name for a calendar system.\n * @param calendar - The calendar code (e.g., 'gregory', 'buddhist', 'islamic')\n * @param locale - The locale to use for formatting (default: user's locale)\n * @param options - Additional DisplayNames options for customization\n * @returns The localized calendar display name\n * @example\n * ```typescript\n * InternationalizationUtils.getCalendarDisplayName('gregory', 'en-US'); // \"Gregorian Calendar\"\n * InternationalizationUtils.getCalendarDisplayName('buddhist', 'th-TH'); // \"ปฏิทินพุทธ\"\n * InternationalizationUtils.getCalendarDisplayName('islamic', 'ar-SA'); // \"التقويم الهجري\"\n * ```\n */\n getCalendarDisplayName(\n calendar: string,\n locale: string = InternationalizationUtils.getUserLocale(),\n options: Omit<Intl.DisplayNamesOptions, \"type\"> = {}\n ): string {\n return (\n new Intl.DisplayNames(locale, {\n type: \"calendar\",\n ...options,\n }).of(calendar) || calendar\n );\n },\n\n /**\n * Gets the localized display name for a currency.\n * @param currency - The currency code (e.g., 'USD', 'EUR', 'JPY')\n * @param locale - The locale to use for formatting (default: user's locale)\n * @param options - Additional DisplayNames options for customization\n * @returns The localized currency display name\n * @example\n * ```typescript\n * InternationalizationUtils.getCurrencyDisplayName('USD', 'en-US'); // \"US Dollar\"\n * InternationalizationUtils.getCurrencyDisplayName('EUR', 'fr-FR'); // \"euro\"\n * InternationalizationUtils.getCurrencyDisplayName('JPY', 'ja-JP'); // \"日本円\"\n * ```\n */\n getCurrencyDisplayName(\n currency: string,\n locale: string = InternationalizationUtils.getUserLocale(),\n options: Omit<Intl.DisplayNamesOptions, \"type\"> = {}\n ): string {\n return (\n new Intl.DisplayNames(locale, {\n type: \"currency\",\n ...options,\n }).of(currency) || currency\n );\n },\n\n /**\n * Gets the localized display name for a date/time field.\n * @param field - The field code (e.g., 'year', 'month', 'day', 'hour', 'minute')\n * @param locale - The locale to use for formatting (default: user's locale)\n * @param options - Additional DisplayNames options for customization\n * @returns The localized field display name\n * @example\n * ```typescript\n * InternationalizationUtils.getDateTimeFieldDisplayName('year', 'en-US'); // \"year\"\n * InternationalizationUtils.getDateTimeFieldDisplayName('month', 'fr-FR'); // \"mois\"\n * InternationalizationUtils.getDateTimeFieldDisplayName('day', 'es-ES'); // \"día\"\n * ```\n */\n getDateTimeFieldDisplayName(\n field: string,\n locale: string = InternationalizationUtils.getUserLocale(),\n options: Omit<Intl.DisplayNamesOptions, \"type\"> = {}\n ): string {\n return (\n new Intl.DisplayNames(locale, {\n type: \"dateTimeField\",\n ...options,\n }).of(field) || field\n );\n },\n\n /**\n * Gets the localized display name for a language.\n * @param language - The language code (e.g., 'en', 'fr', 'es', 'zh')\n * @param locale - The locale to use for formatting (default: user's locale)\n * @param options - Additional DisplayNames options for customization\n * @returns The localized language display name\n * @example\n * ```typescript\n * InternationalizationUtils.getLanguageDisplayName('en', 'en-US'); // \"English\"\n * InternationalizationUtils.getLanguageDisplayName('fr', 'fr-FR'); // \"français\"\n * InternationalizationUtils.getLanguageDisplayName('es', 'es-ES'); // \"español\"\n * ```\n */\n getLanguageDisplayName(\n language: string,\n locale: string = InternationalizationUtils.getUserLocale(),\n options: Omit<Intl.DisplayNamesOptions, \"type\"> = {}\n ): string {\n return (\n new Intl.DisplayNames(locale, {\n type: \"language\",\n ...options,\n }).of(language) || language\n );\n },\n\n /**\n * Gets the localized display name for a region/country.\n * @param region - The region/country code (e.g., 'US', 'FR', 'JP', 'GB')\n * @param locale - The locale to use for formatting (default: user's locale)\n * @param options - Additional DisplayNames options for customization\n * @returns The localized region display name\n * @example\n * ```typescript\n * InternationalizationUtils.getRegionDisplayName('US', 'en-US'); // \"United States\"\n * InternationalizationUtils.getRegionDisplayName('FR', 'fr-FR'); // \"France\"\n * InternationalizationUtils.getRegionDisplayName('JP', 'ja-JP'); // \"日本\"\n * ```\n */\n getRegionDisplayName(\n region: string,\n locale: string = InternationalizationUtils.getUserLocale(),\n options: Omit<Intl.DisplayNamesOptions, \"type\"> = {}\n ): string {\n return (\n new Intl.DisplayNames(locale, {\n type: \"region\",\n ...options,\n }).of(region) || region\n );\n },\n\n /**\n * Gets the localized display name for a writing script.\n * @param script - The script code (e.g., 'Latn', 'Cyrl', 'Arab', 'Hans')\n * @param locale - The locale to use for formatting (default: user's locale)\n * @param options - Additional DisplayNames options for customization\n * @returns The localized script display name\n * @example\n * ```typescript\n * InternationalizationUtils.getScriptDisplayName('Latn', 'en-US'); // \"Latin\"\n * InternationalizationUtils.getScriptDisplayName('Cyrl', 'ru-RU'); // \"кириллица\"\n * InternationalizationUtils.getScriptDisplayName('Arab', 'ar-SA'); // \"العربية\"\n * ```\n */\n getScriptDisplayName(\n script: string,\n locale: string = InternationalizationUtils.getUserLocale(),\n options: Omit<Intl.DisplayNamesOptions, \"type\"> = {}\n ): string {\n return (\n new Intl.DisplayNames(locale, {\n type: \"script\",\n ...options,\n }).of(script) || script\n );\n },\n\n /**\n * Gets the display names of a unit\n * @param unit - Unit code (e.g., 'meter', 'kilogram')\n * @param locale - Locale to use (e.g., 'en-US', 'fr-FR')\n * @param options - DisplayNames options\n * @returns Unit display name\n *\n * @example\n * ```typescript\n * getUnitDisplayName('meter', 'en-US') // 'meter'\n * getUnitDisplayName('kilogram', 'fr-FR') // 'kilogramme'\n * ```\n */\n getUnitDisplayName(\n unit: string,\n locale: string = InternationalizationUtils.getUserLocale(),\n options: Omit<Intl.DisplayNamesOptions, \"type\"> = {}\n ): string {\n return (\n new Intl.DisplayNames(locale, {\n type: \"unit\" as Intl.DisplayNamesOptions[\"type\"],\n ...options,\n }).of(unit) || unit\n );\n },\n\n /**\n * Gets the user's locale\n * @returns User's locale (e.g., 'en-US', 'fr-FR')\n *\n * @example\n * ```typescript\n * const locale = getUserLocale(); // 'en-US'\n * ```\n */\n getUserLocale(): string {\n return Intl.DateTimeFormat().resolvedOptions().locale;\n },\n\n /**\n * Gets the user's preferred language\n * @returns User's preferred language code (e.g., 'en-US', 'fr-FR')\n *\n * @example\n * ```typescript\n * const language = getUserLanguage(); // 'en-US'\n * ```\n */\n getUserLanguage(): string {\n return navigator.language || \"en-US\";\n },\n\n /**\n * Gets the user's preferred languages\n * @returns Array of user's preferred language codes\n *\n * @example\n * ```typescript\n * const languages = getUserLanguages(); // ['en-US', 'en', 'fr']\n * ```\n */\n getUserLanguages(): readonly string[] {\n return navigator.languages || [navigator.language || \"en-US\"];\n },\n\n /**\n * Gets the user's timezone\n * @returns User's timezone (e.g., 'America/New_York', 'Europe/Paris')\n *\n * @example\n * ```typescript\n * const timezone = getUserTimezone(); // 'America/New_York'\n * ```\n */\n getUserTimezone(): string {\n return Intl.DateTimeFormat().resolvedOptions().timeZone;\n },\n};\n"],"names":[],"mappings":"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"}