UNPKG

dbl-utils

Version:

Utilities for dbl, adba and others projects

399 lines (368 loc) 11.1 kB
import moment from "moment"; import { deepMerge } from "./object-mutation"; /** * Configuration object for text translation. * @interface Config * @property {string} lang - The current language. * @property {Object} dictionary - The dictionary of translations. * @property {Object} formatDate - The date formats. * @property {Object} formatTime - The time formats. * @property {Object} formatDateTime - The date-time formats. * @property {Object} formatNumber - The number formats. * @property {Object} formatNumberCompact - The compact number formats. * @property {Object} formatCurrency - The currency formats. * @property {Object} tasks - The tasks to perform if language changes. */ interface Config { lang: string; dictionary: Record<string, any>; formatDate: Record<string, any>; formatTime: Record<string, any>; formatDateTime: Record<string, any>; formatNumber: Record<string, any>; formatNumberCompact: Record<string, any>; formatCurrency: Record<string, any>; tasks: Record<string, (lang: string) => void>; } const config: Config = { lang: '_default', dictionary: { default: {} }, formatDate: { default: 'MM/DD/YYYY' }, formatTime: { default: 'HH:mm:ss' }, formatDateTime: { default: 'MM/DD/YYYY HH:mm:ss' }, formatNumber: { default: {} }, formatNumberCompact: { default: '0.00a' }, formatCurrency: { default: { currency: 'USD', style: 'currency' } }, tasks: {} }; let isTrackingText = false; let trackingTextSet = new Set<string>(); /** * Enable or disable text tracking. * When enabled every translation key requested will be stored. * * @param setTracking - Whether tracking should be enabled * * @example * ```ts * trackingTexts(true); * t('hello'); * trackingTexts(false); * getTexts(); // ['hello'] * ``` */ export function trackingTexts(setTracking: boolean = true): void { isTrackingText = setTracking; } /** * Retrieve the list of tracked texts. * * @returns Array of unique translation keys requested * * @example * ```ts * getTexts(); * ``` */ export function getTexts(): string[] { return Array.from(trackingTextSet); } /** * Adds a dictionary to the configuration object. * @param {Object} dictionary - The dictionary to add. * @returns {boolean} True if added correctly, false otherwise. * * @example * ```ts * addDictionary({ es: { hello: 'Hola' } }); * ``` */ export const addDictionary = (dictionary: object): boolean => { if (typeof dictionary !== 'object') return false; deepMerge(config.dictionary, dictionary); return true; } /** * Adds date formats to the configuration object. * @param {Object} formats - The date formats to add. * @returns {boolean} True if added correctly, false otherwise. * * @example * ```ts * addFormatDate({ es: 'DD/MM/YYYY' }); * ``` */ export const addFormatDate = (formats: object): boolean => { if (typeof formats !== 'object') return false; deepMerge(config.formatDate, formats); return true; } /** * Adds time formats to the configuration object. * @param {Object} formats - The time formats to add. * @returns {boolean} True if added correctly, false otherwise. * * @example * ```ts * addFormatTime({ es: 'HH:mm' }); * ``` */ export const addFormatTime = (formats: object): boolean => { if (typeof formats !== 'object') return false; deepMerge(config.formatTime, formats); return true; } /** * Adds date-time formats to the configuration object. * @param {Object} formats - The date-time formats to add. * @returns {boolean} True if added correctly, false otherwise. * * @example * ```ts * addFormatDateTime({ es: 'DD/MM HH:mm' }); * ``` */ export const addFormatDateTime = (formats: object): boolean => { if (typeof formats !== 'object') return false; deepMerge(config.formatDateTime, formats); return true; } /** * Adds number formats to the configuration object. * @param {Object} formats - The number formats to add. * @returns {boolean} True if added correctly, false otherwise. * * @example * ```ts * addFormatNumber({ es: { short: { maximumFractionDigits: 1 } } }); * ``` */ export const addFormatNumber = (formats: object): boolean => { if (typeof formats !== 'object') return false; deepMerge(config.formatNumber, formats); return true; } /** * Adds compact number formats to the configuration object. * @param {Object} formats - The compact number formats to add. * @returns {boolean} True if added correctly, false otherwise. * * @example * ```ts * addFormatNumberCompact({ es: '0a' }); * ``` */ export const addFormatNumberCompact = (formats: object): boolean => { if (typeof formats !== 'object') return false; deepMerge(config.formatNumberCompact, formats); return true; } /** * Adds currency formats to the configuration object. * @param {Object} formats - The currency formats to add. * @returns {boolean} True if added correctly, false otherwise. * * @example * ```ts * addFormatCurrency({ es: { short: { currency: 'EUR' } } }); * ``` */ export const addFormatCurrency = (formats: object): boolean => { if (typeof formats !== 'object') return false; Object.values(formats).forEach(format => (format.style = 'currency')); deepMerge(config.formatCurrency, formats); return true; } /** * Adds tasks to be executed on language change. * @param {Object} tasks - The tasks to add. * @returns {boolean} True if added correctly, false otherwise. * * @example * ```ts * addTasks({ reload: lang => console.log(lang) }); * ``` */ export const addTasks = (tasks: Record<string, (lang: string) => void>): boolean => { Object.entries(tasks).forEach(([key, task]) => { if (typeof task === 'function') config.tasks[key] = task; }); return true; } /** * Removes a specific task. * @param {string} key - The key of the task to remove. * @returns {boolean} True if removed, false otherwise. * * @example * ```ts * removeTask('reload'); * ``` */ export const removeTask = (key: string): boolean => { if (!config.tasks[key]) return false; delete config.tasks[key]; return true; } /** * Sets the current language. * @param {string} newLang - The new language to set. * @returns {boolean} True if set correctly, false otherwise. * * @example * ```ts * setLang('es'); * ``` */ export const setLang = (newLang: string): boolean => { if (!newLang || config.lang === newLang) return false; moment.locale(newLang); config.lang = newLang; Object.values(config.tasks).forEach(task => task(newLang)); return true; } /** * Gets the current language. * @returns {string} The current language. * * @example * ```ts * const lang = getLang(); * ``` */ export const getLang = (): string => { return config.lang; } /** * Selects a text from the default dictionary. * @param {string} text - The text to select. * @param {string} [context] - The context of the text. * @returns {string} The selected text from the default dictionary. */ const selectFromDefault = (text: string, context?: string): string => { const dictDefault = config.dictionary.default; if (context && typeof dictDefault[context] === 'object' && dictDefault[context][text]) return dictDefault[context][text]; return dictDefault[text] || text; } /** * Function to translate texts. * @param {string} text - The text to translate. * @param {string} [context] - The context of the text. * @returns {string} The translated text. * * @example * ```ts * addDictionary({ es: { hello: 'Hola' } }); * setLang('es'); * t('hello'); // 'Hola' * ``` */ const t = (text: string, context?: string): string => { if (isTrackingText) { trackingTextSet.add(text); } if (config.lang === '_default') return selectFromDefault(text, context); const dict1 = config.dictionary[config.lang]; if (typeof dict1 !== 'object') return selectFromDefault(text, context); const objContext = context && dict1[context]; if (typeof objContext === 'object' && objContext[text]) return objContext[text]; return dict1[text] || selectFromDefault(text); } /** * Formats a value according to the current language and context. * @param {Record<string, any>} formatObject - The configuration object to use. * @param {string} [context] - The context of the value. * @returns {string} The formatted value. */ function formatGeneric(formatObject: Record<string, any>, context?: string): string { if (context && formatObject[context]) { return formatObject[context]; } else if (config.lang !== '_default' && formatObject[config.lang]) { return context && formatObject[config.lang][context] ? formatObject[config.lang][context] : formatObject[config.lang].default || formatObject[config.lang]; } return context && formatObject.default[context] ? formatObject.default[context] : formatObject.default; } /** * Formats a date according to the current language and context. * @param {string} [context] - The context of the date. * @returns {string} The formatted date. * * @example * ```ts * formatDate(); * ``` */ export const formatDate = (context?: string): string => { return formatGeneric(config.formatDate, context); } /** * Formats a time according to the current language and context. * @param {string} [context] - The context of the time. * @returns {string} The formatted time. * * @example * ```ts * formatTime(); * ``` */ export const formatTime = (context?: string): string => { return formatGeneric(config.formatTime, context); } /** * Formats a date-time according to the current language and context. * @param {string} [context] - The context of the date-time. * @returns {string} The formatted date-time. * * @example * ```ts * formatDateTime(); * ``` */ export const formatDateTime = (context?: string): string => { return formatGeneric(config.formatDateTime, context); } /** * Formats a number according to the current language and context. * @param {string} [context] - The context of the number. * @returns {string} The formatted number. * * @example * ```ts * formatNumber(); * ``` */ export const formatNumber = (context?: string): string => { return formatGeneric(config.formatNumber, context); } /** * Formats a compact number according to the current language and context. * @param {string} [context] - The context of the compact number. * @returns {string} The formatted compact number. * * @example * ```ts * formatNumberCompact(); * ``` */ export const formatNumberCompact = (context?: string): string => { return formatGeneric(config.formatNumberCompact, context); } /** * Formats a currency according to the current language and context. * @param {string} [context] - The context of the currency. * @returns {string} The formatted currency. * * @example * ```ts * formatCurrency(); * ``` */ export const formatCurrency = (context?: string): string => { return formatGeneric(config.formatCurrency, context); } export default t;