You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

11 KiB

glob — Módulo de globalización

glob es la capa de globalización del proyecto. Agrupa cuatro módulos de formateo y conversión —número, moneda, fecha/hora y unidades— bajo un único punto de entrada con locale compartido.


Índice

  1. Diseño
  2. LocaleResolver
  3. createGlob
  4. numr — Números
  5. curr — Moneda
  6. dati — Fecha y hora
  7. unit — Unidades
  8. Referencia de tipos

Diseño

Principios

  • Un locale, todos los módulos. El locale vive en la instancia ling. Cuando se llama a glob.setLocale(), todos los módulos formatean con el nuevo locale de forma automática, sin necesidad de recrearlos.
  • Módulos independientes. Cada módulo (numr, curr, dati, unit) puede instanciarse de forma autónoma con createNumr, createCurr, etc., sin necesitar createGlob.
  • Locale reactivo. Cada función f() acepta un LocaleResolver opcional. Si se omite, usa el default configurado al crear la instancia (que puede ser una función que lee el locale en tiempo de ejecución).
  • Fábricas puras. No hay clases ni singletons. Cada llamada a createX() devuelve un objeto cerrado con su estado interno.

Estructura de archivos

src/glob/
├── comn_types.ts     — GlobLocale, LocaleResolver
├── comn_engine.ts    — resolveLocale()
├── glob_types.ts     — GlobConfig, GlobInstance
├── glob_engine.ts    — createGlob()
├── numr_types.ts     — NumrConfig, NumrInstance
├── numr_engine.ts    — createNumr()
├── curr_types.ts     — CurrDefinition, CurrConfig, CurrInstance
├── curr_engine.ts    — createCurr()
├── dati_types.ts     — DatiConfig, DatiInstance, DatiOptions
├── dati_engine.ts    — createDati()
├── unit_types.ts     — UnitCategory, UnitConfig, UnitInstance
├── unit_engine.ts    — createUnit()
└── unit_langs.ts     — defaultCategories (definiciones por defecto)

Flujo de locale en createGlob

glob.setLocale('en')
  └─▶ ling.setLocale('en')           // fuente de verdad
  └─▶ listeners.forEach(fn => fn())  // notifica suscriptores externos

glob.numr.f(1234)
  └─▶ resolveLocale(getLocale)       // llama a ling.getLocale() en cada f()
  └─▶ Intl.NumberFormat('en').format(1234)

Los módulos reciben getLocale (una función () => GlobLocale) como defaultLocale, por lo que leen el locale actual en cada invocación sin necesidad de reconectarse.


LocaleResolver

type LocaleResolver = GlobLocale | (() => GlobLocale);

Todos los métodos f() aceptan un LocaleResolver como último parámetro. Puede ser:

Forma Cuándo usarla
'es' Locale fijo en esa llamada concreta
() => user.locale Locale dinámico que se lee en cada llamada
(omitido) Usa el defaultLocale configurado al crear la instancia

resolveLocale(l) en comn_engine.ts normaliza ambas formas:

resolveLocale('es')           // → 'es'
resolveLocale(() => 'en')     // → 'en'

createGlob

Punto de entrada principal. Crea una instancia integrada con locale compartido.

import { createGlob } from '@/glob/glob_engine';

const glob = createGlob({
    locale: 'es',
    ling,               // instancia de LingInstance
    numr: { maxDecimals: 2 },
    curr: {
        definitions: { EUR: eurDef, USD: usdDef },
        selectedCurrency: 'EUR',
    },
    dati: { selectedTimeFormat: '24h' },
    unit: { selectedSystem: 'metric' },
});

API de GlobInstance

Método / propiedad Descripción
getLocale() Locale activo (delegado a ling)
setLocale(locale) Cambia el locale en ling y notifica suscriptores
onLocaleChange(fn) Suscribe un listener; devuelve función de desuscripción
t(key, params?) Traducción via ling.t
ts(key, params?) Traducción con soporte plural via ling.ts
ling La instancia LingInstance completa
numr Módulo de números
curr Módulo de moneda
dati Módulo de fecha/hora
unit Módulo de unidades

Cambio reactivo de locale

glob.setLocale('en');

glob.numr.f(1234.5);  // '1,234.5'
glob.curr.f(99);      // '99.00 €'
glob.dati.f(new Date()); // 'March 2, 2026'

Suscriptor de cambios

const unsub = glob.onLocaleChange(locale => {
    console.log('Nuevo locale:', locale);
});

glob.setLocale('fr');  // → 'Nuevo locale: fr'
unsub();               // elimina el listener

numr

Formateo de números usando Intl.NumberFormat.

Creación independiente

import { createNumr } from '@/glob/numr_engine';

const numr = createNumr({ minDecimals: 0, maxDecimals: 2 }, 'es');

f(n, opts?, locale?)

numr.f(1234567.89)                          // '1.234.567,89'  (es)
numr.f(1234567.89, {}, 'en')               // '1,234,567.89'
numr.f(1234.5,  { maxDecimals: 0 })        // '1.235'
numr.f(0.1234,  { minDecimals: 2, maxDecimals: 4 }) // '0,1234'
Parámetro Tipo Default
n number —
opts.minDecimals number 0
opts.maxDecimals number 2
locale LocaleResolver defaultLocale de instancia

curr

Formateo y conversión de moneda.

Definir monedas

import type { CurrDefinition } from '@/glob/curr_types';
import { p } from '@/ling/engine';

const EUR: CurrDefinition = {
    symbol: '€',
    code: 'EUR',
    name: p({
        es: { one: 'euro',   other: 'euros'   },
        en: { one: 'euro',   other: 'euros'   },
    }),
    conversionValue: 1,       // relativo a moneda base
};

Creación independiente

import { createCurr } from '@/glob/curr_engine';

const curr = createCurr(
    { EUR, USD, MXN },   // definiciones
    ling,                // instancia LingInstance
    { selectedCurrency: 'EUR', decimals: 2 },
    'es'                 // defaultLocale
);

f(amount, display?, locale?)

curr.f(99.5)                   // '99,50 €'   (symbol, es)
curr.f(99.5, 'symbol', 'en')   // '99.50 €'
curr.f(99.5, 'code')           // '99,50 EUR'
curr.f(1,    'name')           // '1,00 euro'
curr.f(2,    'name')           // '2,00 euros'
display Resultado ejemplo
'symbol' (default) 99,50 €
'code' 99,50 EUR
'name' 99,50 euros

Conversión

curr.convert(100, 'EUR', 'USD')   // → 108  (si USD.conversionValue = 1.08)
curr.convertTo(100, 'USD')        // convierte desde selectedCurrency

conversionValue puede ser un número estático o una función () => number para tasas dinámicas:

const USD: CurrDefinition = {
    // ...
    conversionValue: () => fetchLiveRate('USD'),
};

Gestión de moneda activa

curr.getCurrency()       // 'EUR'
curr.setCurrency('USD')  // cambia la moneda activa
curr.get('EUR')          // → CurrDefinition | undefined

dati

Formateo de fechas y horas usando Intl.DateTimeFormat.

Creación independiente

import { createDati } from '@/glob/dati_engine';

const dati = createDati({ selectedTimeFormat: '24h' }, 'es');

f(date, opts?, locale?)

const d = new Date('2026-03-02T15:30:00');

dati.f(d)                           // '2 de marzo de 2026'         (long, es)
dati.f(d, 'short')                  // '2/3/26'
dati.f(d, { date: 'long', time: 'short' })  // '2 de marzo de 2026, 15:30'
dati.f(d, { time: 'short' }, 'en')  // '3:30 PM'  (si timeFormat = '12h')

DatiOptions

Valor Resultado
'long' (default) Solo fecha en formato largo
'short' Solo fecha en formato corto
{ date: 'long' } Solo fecha larga
{ time: 'short' } Solo hora corta
{ date: 'long', time: 'short' } Fecha y hora

Preferencias

dati.setTimeFormat('12h')   // '12h' | '24h'
dati.getTimeFormat()        // '12h'

dati.setDateOrder('MDY')    // 'DMY' | 'MDY' | 'YMD'
dati.getDateOrder()         // 'MDY'

dateOrder está almacenado en el estado pero el orden real lo gestiona Intl.DateTimeFormat según el locale. Se expone para que la UI pueda reflejarlo.


unit

Conversión y formateo de unidades de medida. Soporta dos sistemas: metric e imperial.

Categorías disponibles

Categoría Base métrica Base imperial Unidades
weight kg lb kg, g, lb, oz, t
length m mi km, m, cm, mm, mi, ft, in, yd
temp c f c, f, k
volume l gal l, ml, m³, gal, fl oz, pt
area m² ft² m², km², ha, ft², mi², ac

Creación independiente

import { createUnit } from '@/glob/unit_engine';

const unit = createUnit({}, { selectedSystem: 'metric' }, 'es');

Sistema activo

unit.setSystem('imperial')
unit.getSystem()           // 'imperial'

category.f(value, display?, locale?)

Formatea el valor en la unidad base del sistema activo:

unit.weight.f(70)                  // '70 kg'   (metric, symbol)
unit.weight.f(70, 'name')          // '70 kilogramos'
unit.weight.f(70, 'symbol', 'en')  // '70 kg'

unit.setSystem('imperial');
unit.weight.f(70)                  // '154,32 lb'

category.fTo(value, targetUnit?, display?, locale?)

Convierte desde la base métrica y formatea en la unidad destino:

unit.length.fTo(1000, 'km')   // '1 km'
unit.temp.fTo(100, 'f')       // '212 °F'   (100°C → °F)
unit.area.fTo(10000, 'ha')    // '1 ha'

Si se omite targetUnit, usa la base del sistema activo.

category.convert(value, from, to)

Conversión numérica pura, sin formateo:

unit.weight.convert(1, 'kg', 'lb')   // 2.204...
unit.temp.convert(100, 'c', 'f')     // 212
unit.length.convert(1, 'mi', 'km')   // 1.609...

La temperatura usa conversión directa (no por factor lineal), manejada internamente con convertTemp().

Personalizar categorías

Se pueden sobreescribir las categorías por defecto o añadir nuevas unidades:

const unit = createUnit(
    {
        weight: {
            base: 'kg',
            baseImperial: 'lb',
            units: {
                // solo las unidades que necesitas
                kg: { factor: 1, system: 'metric', symbol: { es: 'kg', en: 'kg' }, name: ... },
            },
        },
    },
    { selectedSystem: 'metric' },
    'es'
);

Referencia de tipos

GlobLocale

type GlobLocale = SupportedLocale | (string & {});

Acepta cualquier código BCP 47 ('es', 'en', 'fr', 'es-MX', etc.).

LocaleResolver

type LocaleResolver = GlobLocale | (() => GlobLocale);

CurrDefinition

interface CurrDefinition {
    symbol          : string;
    code            : string;
    name            : LingPluralFn<Record<never, never>>;
    conversionValue?: number | (() => number | null) | null;
}

UnitDefinition

interface UnitDefinition {
    symbol : LingRecord;           // { es: 'kg', en: 'kg' }
    name   : LingPluralFn<...>;    // plural bilingüe
    factor : number;               // relativo a la base de la categoría
    system : 'metric' | 'imperial';
}

La conversión entre unidades (excepto temperatura) se calcula como:

resultado = (valor × factor_origen) / factor_destino

donde factor es la equivalencia de cada unidad respecto a la base de la categoría (ej. kg tiene factor 1, g tiene factor 0.001).

Powered by TurnKey Linux.