La API Intl de JavaScript proporciona internacionalización nativa en el navegador y en Node.js sin necesidad de librerías como moment, date-fns o numeral. Cada constructor de Intl acepta un locale (como 'es-ES' o 'en-US') y opciones de formato, produciendo resultados consistentes con las convenciones tipográficas de cada idioma y región.
Intl.NumberFormat: números, monedas y unidades
Formatear números y monedas respetando el separador de miles y de decimales de cada idioma es tarea de Intl.NumberFormat. Las instancias son reutilizables y más eficientes que crear el formateador en cada llamada.
const formatEur = new Intl.NumberFormat('es-ES', {
style: 'currency',
currency: 'EUR',
});
console.log(formatEur.format(1234567.89)); // "1.234.567,89 "
const formatUsd = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
});
console.log(formatUsd.format(1234567)); // "$1,234,567"
const formatPct = new Intl.NumberFormat('es-ES', {
style: 'percent',
maximumFractionDigits: 1,
});
console.log(formatPct.format(0.1234)); // "12,3 %"
const formatBytes = new Intl.NumberFormat('es-ES', {
style: 'unit',
unit: 'megabyte',
unitDisplay: 'short',
});
console.log(formatBytes.format(1024)); // "1.024 MB"
Intl.DateTimeFormat: fechas y horas localizadas
Intl.DateTimeFormat formatea objetos Date con el formato, el idioma y la zona horaria correctos:
const fecha = new Date('2024-12-25T18:00:00Z');
const formatoLargo = new Intl.DateTimeFormat('es-ES', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
});
console.log(formatoLargo.format(fecha)); // "miércoles, 25 de diciembre de 2024"
const formatoCorto = new Intl.DateTimeFormat('es-ES', {
dateStyle: 'short',
timeStyle: 'short',
timeZone: 'Europe/Madrid',
});
console.log(formatoCorto.format(fecha)); // "25/12/2024, 19:00"
// Formato relativo de partes individuales
const partes = new Intl.DateTimeFormat('es-ES', {
weekday: 'short', month: 'short', day: 'numeric',
}).formatToParts(fecha);
// [{ type: 'weekday', value: 'mié.' }, { type: 'literal', value: ', ' }, ...]
Intl.RelativeTimeFormat: tiempos relativos
Mostrar "hace 3 días" o "en 2 horas" en el idioma correcto sin librerías:
const rtf = new Intl.RelativeTimeFormat('es-ES', { numeric: 'auto' });
console.log(rtf.format(-1, 'day')); // "ayer"
console.log(rtf.format(0, 'day')); // "hoy"
console.log(rtf.format(1, 'day')); // "mañana"
console.log(rtf.format(-3, 'hour')); // "hace 3 horas"
console.log(rtf.format(5, 'minute')); // "dentro de 5 minutos"
function tiempoRelativo(fecha) {
const segundos = (fecha - Date.now()) / 1000;
const umbrales = [
[60, 'second'],
[3600, 'minute'],
[86400, 'hour'],
[2592000, 'day'],
[31536000, 'month'],
];
for (const [limite, unidad] of umbrales) {
if (Math.abs(segundos) < limite) {
const divisor = umbrales[umbrales.indexOf([limite, unidad]) - 1]?.[0] ?? 1;
return rtf.format(Math.round(segundos / divisor), unidad);
}
}
return rtf.format(Math.round(segundos / 31536000), 'year');
}
Intl.Collator: ordenar strings en español
El ordenamiento alfabético varía por idioma. En español, la ñ va entre n y o; en sueco la å va al final. Intl.Collator ordena correctamente:
const collator = new Intl.Collator('es-ES', { sensitivity: 'base' });
const nombres = ['Ñoño', 'Nacho', 'Óscar', 'Ana', 'Álvaro'];
nombres.sort((a, b) => collator.compare(a, b));
// ["Álvaro", "Ana", "Nacho", "Ñoño", "Óscar"]
// Búsqueda insensible a mayúsculas y acentos
const hayCoincidencia = (lista, busqueda) =>
lista.some(item => collator.compare(item, busqueda) === 0);
hayCoincidencia(['Óscar', 'Nacho'], 'oscar'); // true
Intl.PluralRules y Intl.ListFormat
PluralRules devuelve la categoría plural ('one', 'few', 'many', etc.) para un número dado en el idioma especificado. ListFormat une un array de strings con el conector correcto ("y", "or", "and"):
const pr = new Intl.PluralRules('es-ES');
const mensajes = { one: 'resultado', other: 'resultados' };
const n = 3;
console.log(`${n} ${mensajes[pr.select(n)]}`); // "3 resultados"
const lf = new Intl.ListFormat('es-ES', { style: 'long', type: 'conjunction' });
console.log(lf.format(['manzanas', 'naranjas', 'peras']));
// "manzanas, naranjas y peras"
const lfOr = new Intl.ListFormat('es-ES', { type: 'disjunction' });
console.log(lfOr.format(['PDF', 'Word', 'Excel']));
// "PDF, Word o Excel"
Usar la API Intl nativa en lugar de librerías de terceros reduce el tamaño del bundle, garantiza que el formato sigue los estándares Unicode CLDR y funciona con las configuraciones regionales del sistema operativo del usuario.
