|
|
5 months ago | |
|---|---|---|
| .. | ||
| curr | 5 months ago | |
| dates | 5 months ago | |
| nums | 5 months ago | |
| test | 5 months ago | |
| unts | 5 months ago | |
| README.md | 5 months ago | |
| active-formats.svelte.ts | 5 months ago | |
| active-runtime.svelte.ts | 5 months ago | |
| auto-state.ts | 5 months ago | |
| consts.ts | 5 months ago | |
| engine-formats.ts | 5 months ago | |
| errors.ts | 5 months ago | |
| helpers.ts | 5 months ago | |
| index.ts | 5 months ago | |
| locale-state.ts | 5 months ago | |
| types.ts | 6 months ago | |
README.md
Formats
Formats es la API publica del artefacto fmts. Su responsabilidad es
centralizar todos los formatos que dependen de locale: numeros, moneda,
unidades y fechas. No traduce textos, no decide idioma y no depende de Lang;
solo consume una fuente de locale cuando se quiere reactividad.
El objetivo es que una app tenga una sola verdad:
App.setLocale('es-AR');
App.Formats.numbers.format(1234.5);
App.Formats.currency.getCurrency(); // ARS
App.Formats.units.getSystem(); // metric
App.Formats.dates.getDateOrder();
Mapa del modulo
| Pieza | Factory | Responsabilidad |
|---|---|---|
formats |
createEngineFormats, createActiveFormats |
Agrega numbers, currency, units y dates bajo un mismo locale. |
numbers |
createEngineNumbers, createActiveNumbers |
Formato y parseo numerico, separadores, porcentajes, compact, currency/unit via Intl.NumberFormat. |
currency |
createEngineCurrency, createActiveCurrency |
Moneda por region, formato de moneda, conversion y cache de rates. |
units |
createEngineUnits, createActiveUnits |
Sistema metrico/imperial, unidades por defecto y conversiones. |
dates |
createEngineDates, createActiveDates |
Orden de fecha, ciclo horario y formato fecha/hora. |
Todos los submodulos siguen el mismo patron:
Engine*es puro y no depende de Svelte.Active*envuelve el engine con reactividad Svelte 5.localepuede ser string o funcion en engines.localeSourcees la entrada reactiva en active wrappers.dispose()existe aunque hoy casi todo sea puro, para mantener el contrato comun.
Uso rapido
import { createEngineFormats } from '$fmts';
const formats = createEngineFormats({ locale: 'es-ES' });
formats.numbers.format(1234.5); // "1234,5" segun Intl del runtime
formats.currency.format(12.5); // "12,50 EUR"
formats.units.formatDefault(20, 'distance'); // "20 km"
formats.dates.formatDateTime(new Date());
En una app Svelte:
import { createActiveFormats } from '$fmts';
const Formats = createActiveFormats({
locale: 'en-US'
});
Formats.setLocale('fr-FR');
Formats.currency.format(99.5);
Bajo createActiveApp(...) normalmente no se crea a mano: App.Formats recibe
el localeSource de la app y se mueve con App.setLocale(...).
LocaleSource
Formats consume el alias compartido LocaleSource de $locale:
import type { LocaleSource } from '$locale';
interface LocaleSource<L extends string = string> {
getLocale: () => L;
onLocaleChange?: (fn: (locale: L) => void) => () => void;
}
createActiveFormats({ localeSource }) suscribe esa fuente y propaga los cambios
a todos los submotores. Si el source no tiene onLocaleChange, el engine puede
leer getLocale() cuando se formatea, pero no recibe notificaciones activas.
Locale por defecto
Cuando no se pasa locale ni localeSource, se usa
DEFAULT_LOCALE = 'en-US'. Esto evita depender del locale implicito del runtime,
que puede variar entre navegador, servidor, tests y CI.
Si quieres que el default de proyecto sea otro, pasalo en el composition root:
const App = createActiveApp({
formats: { locale: 'es-ES' }
});
Regla Auto / Manual
Todos los valores derivados siguen la misma dinamica:
setX('auto'); // vuelve a derivar desde locale/Intl/framework
clearX(); // equivalente semantico de volver a auto
isXAuto(); // true si el usuario no fijo un valor manual
Un valor explicito siempre gana sobre el locale. Si el usuario fija currency,
system, hourCycle, dateOrder o separadores numericos, cambiar el locale no
debe mover ese valor hasta que vuelva a auto.
| Modulo | Valor derivado | Deriva de | Fijar | Volver a auto |
|---|---|---|---|---|
currency |
moneda | region del locale | setCurrency('EUR') |
setCurrency('auto') / clearCurrency() |
units |
sistema metrico/imperial | region del locale | setSystem('metric') |
setSystem('auto') / clearSystem() |
dates |
dateOrder |
$libs/days + locale |
setDateOrder('YMD') |
setDateOrder('auto') / clearDateOrder() |
dates |
hourCycle |
$libs/days + locale |
setHourCycle(12) |
setHourCycle('auto') / clearHourCycle() |
numbers |
separadores y grouping | Intl.NumberFormat |
setDecimalSeparator(',') |
setDecimalSeparator('auto') / clearDecimalSeparator() |
Ejemplo:
formats.currency.setCurrency('EUR');
formats.setLocale('en-US');
formats.currency.getCurrency(); // EUR: valor fijado por usuario
formats.currency.clearCurrency();
formats.currency.getCurrency(); // USD: vuelve a derivar del locale
Numbers
numbers es la base para el resto cuando se inyecta en currency o units.
formats.numbers.format(1234567.89);
formats.numbers.formatPercent(0.42);
formats.numbers.formatCompact(1200000);
formats.numbers.formatCurrency(99.5, 'EUR');
formats.numbers.formatUnit(20, 'kilometer');
formats.numbers.parse('1.234,50');
formats.numbers.getDecimalSeparator();
formats.numbers.getGroupSeparator();
Los separadores pueden quedar en auto o ser preferencias de usuario:
formats.numbers.setDecimalSeparator(',');
formats.numbers.clearDecimalSeparator();
Currency
currency resuelve moneda desde la region explicita del locale. No hace fallback
por idioma porque eso produce errores como tratar es-AR como es-ES.
formats.setLocale('es-AR');
formats.currency.getCurrency(); // ARS
formats.setLocale('es');
formats.currency.getCurrency(); // defaultCurrency, porque no hay region
Para conversiones se inyecta un provider de rates:
import { createRates } from '$fmts/curr';
const rates = createRates({
initial: {
base: 'EUR',
rates: { USD: 1.08, GBP: 0.86 }
}
});
const formats = createEngineFormats({
locale: 'es-ES',
currency: { rates }
});
await formats.currency.convert(10, 'USD');
Si falta un provider o un rate, currency puede emitir diagnosticos por el
logger inyectado. Las categorias y mensajes viven en constantes del submodulo.
Units
units resuelve sistema por region y marca unidades por defecto en
unts/unit-definitions.ts.
formats.units.getSystem(); // metric | imperial
formats.units.getDefaultUnit('distance'); // kilometer | mile
formats.units.isDefaultUnit('mile', 'distance', 'imperial');
formats.units.formatDefault(20, 'distance');
formats.units.convert(1, 'mile', 'kilometer');
El sistema tambien respeta auto/manual:
formats.units.setSystem('imperial');
formats.setLocale('es-ES');
formats.units.getSystem(); // imperial
formats.units.clearSystem();
formats.units.getSystem(); // metric
Dates
dates usa $libs/days como base pura y fmts/dates como capa de
engine/configuracion.
formats.dates.getDateOrder();
formats.dates.getHourCycle();
formats.dates.formatDate(new Date());
formats.dates.formatTime(new Date());
formats.dates.formatDateTime(new Date());
getHourCycle() deriva del locale a traves de las utilidades de days; si el
usuario fija setHourCycle(12) o setHourCycle(24), esa preferencia queda
bloqueada hasta clearHourCycle().
Active listeners
Los wrappers activos exponen listeners para que una UI o un modulo superior pueda reaccionar sin inspeccionar internals:
const offLocale = Formats.numbers.onLocaleChange((locale) => {
console.log('locale changed', locale);
});
const offPrefs = Formats.dates.onPreferenceChange(() => {
console.log('date preferences changed');
});
const offCurrency = Formats.currency.onCurrencyChange((currency) => {
console.log('currency changed', currency);
});
dispose() limpia estas suscripciones.
Integracion recomendada
En aapp, Formats debe compartir locale con Lang y Frontend:
const App = createActiveApp({
lang: { locale: 'es-ES', schema },
formats: {
currency: { defaultCurrency: 'EUR' }
}
});
App.setLocale('ar');
App.Formats.dates.formatDate(new Date());
Si un modulo necesita solo formatos sin toda la app, usa el engine aislado:
const formats = createEngineFormats({
locale: () => requestLocale
});
Testing
Tests utiles:
npx vitest run src/arts/fmts/test/fmtspara validar locale compartido, auto/manual y UI./test/ecosystempara validarLang + Formats + Frontend + Domjuntos.