import type { LocaleResolver, GlobLocale } from "./comn_types.ts"; import type { UnitCategoryData, UnitCategoryInstance, UnitCategoryKey, UnitDisplay, UnitInstance, UnitSystem } from "./unit_types.ts"; import { resolveLocale } from "./comn_engine.ts"; import { DEFAULT_ISO_LOCALE } from "@/ling/lib/consts.ts"; import { type LingNode, type LingInstance, ling } from "@/ling/lib"; import { unitData } from "./unit_data.ts"; import { unitsLingNode } from "./unit_langs.ts"; // ============================== // CONVERSIÓN DE TEMPERATURA // ============================== function convertTemp(value: number, from: string, to: string): number { if (from === to) return value; let c: number; switch (from) { case 'c': c = value; break; case 'f': c = (value - 32) * 5 / 9; break; case 'k': c = value - 273.15; break; default: c = value; } switch (to) { case 'c': return c; case 'f': return c * 9 / 5 + 32; case 'k': return c + 273.15; default: return c; } } // ============================== // CATEGORY ENGINE // ============================== function createCategory( categoryKey : UnitCategoryKey, category : UnitCategoryData, getSystem : () => UnitSystem, defaultLocale: LocaleResolver, ling : LingInstance, ): UnitCategoryInstance { function resolveTargetUnit(): string { return getSystem() === 'imperial' ? category.baseImperial : category.base; } function formatValue(value: number, unitKey: string, display: UnitDisplay, locale: GlobLocale): string { const formatted = new Intl.NumberFormat(locale, { maximumFractionDigits: 2 }).format(value); if (display === 'abbr') { // Lee símbolo de ling: units.weight.kg.abbr const abbr = ling.t(`units.${categoryKey}.${unitKey}.abbr` as any); return `${formatted} ${abbr}`; } // Lee nombre pluralizado de ling: units.weight.kg.name const name = ling.t(`units.${categoryKey}.${unitKey}.name` as any, { count: value }); return `${formatted} ${name}`; } function convert(value: number, from: string, to: string): number { if (from === to) return value; if (categoryKey === 'temp') return convertTemp(value, from, to); const fromData = category.units[from]; const toData = category.units[to]; if (!fromData || !toData) return value; return (value * fromData.factor) / toData.factor; } function f(value: number, display: UnitDisplay = 'abbr', locale: LocaleResolver = defaultLocale): string { const loc = resolveLocale(locale); const unit = resolveTargetUnit(); return formatValue(value, unit, display, loc); } function fTo(value: number, targetUnit?: string, display: UnitDisplay = 'abbr', locale: LocaleResolver = defaultLocale): string { const loc = resolveLocale(locale); const to = targetUnit ?? resolveTargetUnit(); const converted = convert(value, category.base, to); return formatValue(converted, to, display, loc); } return { f, fTo, convert }; } // ============================== // UNIT ENGINE // ============================== export function createUnit( ling : LingInstance, categories : Partial> = {}, opts : { selectedSystem?: UnitSystem } = {}, defaultLocale: LocaleResolver = 'es' ): UnitInstance { // El módulo registra sus propias traducciones en ling ling.extend('units', unitsLingNode); let currentSystem: UnitSystem = opts.selectedSystem ?? 'metric'; function getSystem(): UnitSystem { return currentSystem; } function setSystem(s: UnitSystem) { currentSystem = s; } const merged: Record = { ...unitData, ...categories, }; const makeCategory = (key: UnitCategoryKey) => createCategory(key, merged[key], getSystem, defaultLocale, ling); return { getSystem, setSystem, weight : makeCategory('weight'), length : makeCategory('length'), temp : makeCategory('temp'), volume : makeCategory('volume'), area : makeCategory('area'), }; }