Formato internacional con la API Intl

Intermedio
JavaScript
JavaScript
Actualizado: 19/04/2026

Qué es la API Intl

La API Intl es el espacio de nombres estándar de JavaScript para tareas de internacionalización: dar formato a números, fechas, listas y textos de forma coherente con el idioma y la región del usuario. Está disponible en todos los navegadores modernos y en Node.js sin librerías externas.

Cada servicio (NumberFormat, DateTimeFormat, RelativeTimeFormat, ListFormat, entre otros) sigue el mismo patrón: creas un formateador pasándole un locale ("es-ES", "en-US", …) y un objeto de opciones, y después invocas su método format con el dato que quieres representar.

const formatter = new Intl.NumberFormat("es-ES");
console.log(formatter.format(1234567.89)); // "1.234.567,89"

El locale puede ser una cadena o un array. Si el primer locale no es soportado, el motor busca el siguiente. También existe Intl.getCanonicalLocales para normalizar identificadores.

Formato de números con Intl.NumberFormat

Intl.NumberFormat cubre los casos más habituales: número decimal, moneda, porcentaje y unidad.

Número decimal y agrupación

const esES = new Intl.NumberFormat("es-ES");
const enUS = new Intl.NumberFormat("en-US");

console.log(esES.format(1234567.89)); // "1.234.567,89"
console.log(enUS.format(1234567.89)); // "1,234,567.89"

El separador de miles y el decimal dependen del locale. También es posible desactivar el agrupamiento:

const plain = new Intl.NumberFormat("es-ES", { useGrouping: false });
console.log(plain.format(1234567.89)); // "1234567,89"

Moneda (EUR, USD, JPY…)

Para mostrar cantidades monetarias se usa style: "currency" y la divisa ISO 4217:

const eur = new Intl.NumberFormat("es-ES", { style: "currency", currency: "EUR" });
const usd = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" });
const jpy = new Intl.NumberFormat("ja-JP", { style: "currency", currency: "JPY" });

console.log(eur.format(1299.5));  // "1.299,50 €"
console.log(usd.format(1299.5));  // "$1,299.50"
console.log(jpy.format(1299.5));  // "¥1,300" (yen: sin decimales)

El formateador conoce cuántos decimales usa cada divisa. Con currencyDisplay se controla si se muestra el símbolo, el código o el nombre:

const code = new Intl.NumberFormat("es-ES", {
  style: "currency",
  currency: "EUR",
  currencyDisplay: "code"
});

console.log(code.format(1299.5)); // "1.299,50 EUR"

Porcentajes

El estilo "percent" multiplica el valor por 100 y añade el símbolo adecuado:

const pct = new Intl.NumberFormat("es-ES", { style: "percent", maximumFractionDigits: 1 });

console.log(pct.format(0.1258)); // "12,6 %"

Las opciones minimumFractionDigits y maximumFractionDigits controlan los decimales; minimumSignificantDigits/maximumSignificantDigits permiten fijar cifras significativas en lugar de decimales fijos.

Compacto y unidades

Para cifras grandes existe notation: "compact", y para unidades físicas (kilómetros, megabytes…) el estilo "unit":

const compact = new Intl.NumberFormat("es-ES", { notation: "compact" });
console.log(compact.format(1250000)); // "1,3 M"

const mb = new Intl.NumberFormat("es-ES", { style: "unit", unit: "megabyte" });
console.log(mb.format(512)); // "512 MB"

Formato de fechas con Intl.DateTimeFormat

Intl.DateTimeFormat formatea objetos Date según el locale y devuelve una cadena con la estructura propia de cada idioma.

Fecha y hora por locale

const date = new Date("2026-04-17T10:30:00Z");

const esES = new Intl.DateTimeFormat("es-ES", { dateStyle: "long", timeStyle: "short" });
const enUS = new Intl.DateTimeFormat("en-US", { dateStyle: "long", timeStyle: "short" });

console.log(esES.format(date)); // "17 de abril de 2026, 12:30"
console.log(enUS.format(date)); // "April 17, 2026 at 12:30 PM"

Los styles (full, long, medium, short) son la forma más cómoda y accesible. Alternativamente, se pueden especificar componentes sueltos:

const custom = new Intl.DateTimeFormat("es-ES", {
  weekday: "long",
  day: "numeric",
  month: "long",
  year: "numeric"
});

console.log(custom.format(date)); // "viernes, 17 de abril de 2026"

Zonas horarias

La opción timeZone indica qué huso se debe usar para representar la fecha. Los nombres siguen la base de datos IANA (Europe/Madrid, America/New_York, Asia/Tokyo):

const madrid = new Intl.DateTimeFormat("es-ES", {
  dateStyle: "short",
  timeStyle: "short",
  timeZone: "Europe/Madrid"
});

const tokio = new Intl.DateTimeFormat("ja-JP", {
  dateStyle: "short",
  timeStyle: "short",
  timeZone: "Asia/Tokyo"
});

console.log(madrid.format(date)); // "17/4/26, 12:30"
console.log(tokio.format(date));  // "2026/04/17 19:30"

Es útil para mostrar al usuario una hora coherente con su ubicación sin tener que manipular el Date manualmente.

formatToParts

formatToParts devuelve el resultado descompuesto en fragmentos tipados (day, month, literal, …). Es la forma correcta de construir una cadena a medida sin romper la internacionalización:

const parts = esES.formatToParts(date);
// [ {type:"day", value:"17"}, {type:"literal", value:" de "}, {type:"month", value:"abril"}, ... ]

Tiempos relativos con Intl.RelativeTimeFormat

Intl.RelativeTimeFormat expresa diferencias de tiempo en forma narrativa: "hace 3 días", "en 2 meses". No calcula la diferencia, solo la formatea; la cuenta la proporcionas tú.

const rtf = new Intl.RelativeTimeFormat("es-ES", { numeric: "auto" });

console.log(rtf.format(-1,  "day"));   // "ayer"
console.log(rtf.format(-3,  "day"));   // "hace 3 días"
console.log(rtf.format( 2,  "month")); // "dentro de 2 meses"
console.log(rtf.format( 0,  "week"));  // "esta semana"

Con numeric: "always" siempre aparece el número; con "auto" se usan expresiones naturales cuando existen. Una función auxiliar típica combina la diferencia real con el formateador:

function relativeFromNow(date, locale = "es-ES") {
  const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
  const diffMs = date.getTime() - Date.now();
  const diffDays = Math.round(diffMs / 86400000);

  if (Math.abs(diffDays) < 30) return rtf.format(diffDays, "day");
  const diffMonths = Math.round(diffDays / 30);
  if (Math.abs(diffMonths) < 12) return rtf.format(diffMonths, "month");
  const diffYears = Math.round(diffMonths / 12);
  return rtf.format(diffYears, "year");
}

const inAWeek = new Date(Date.now() + 7 * 86400000);
console.log(relativeFromNow(inAWeek)); // "dentro de 7 días"

Listas idiomáticas con Intl.ListFormat

Unir varios elementos con comas y una conjunción es una operación muy dependiente del idioma. Intl.ListFormat se encarga del separador y de la última conjunción:

const esConjunction = new Intl.ListFormat("es-ES", { style: "long", type: "conjunction" });
const enConjunction = new Intl.ListFormat("en-US", { style: "long", type: "conjunction" });

console.log(esConjunction.format(["manzana", "pera", "uva"]));
// "manzana, pera y uva"

console.log(enConjunction.format(["apple", "pear", "grape"]));
// "apple, pear, and grape"

Cambiando type se obtiene una disyunción (o) o una lista de unidades:

const esOr = new Intl.ListFormat("es-ES", { type: "disjunction" });
console.log(esOr.format(["rojo", "verde", "azul"]));
// "rojo, verde o azul"

El estilo "short" o "narrow" produce variantes más compactas, útiles para interfaces reducidas.

Patrones habituales

Detectar el locale del usuario

En el navegador, navigator.language y navigator.languages dan el idioma preferido. En Node puede tomarse de process.env.LANG o de una cabecera HTTP. Lo sensato es pasarlo como primer argumento al formateador:

const userLocale = (typeof navigator !== "undefined" && navigator.language) || "es-ES";
const nf = new Intl.NumberFormat(userLocale, { style: "currency", currency: "EUR" });
console.log(nf.format(1999));

Reutilizar formateadores

Crear un formateador tiene coste. En rutas calientes (render de listas, tablas), crea el formateador una vez y reutilízalo:

const priceFormatter = new Intl.NumberFormat("es-ES", {
  style: "currency",
  currency: "EUR"
});

function renderRow(product) {
  return `${product.name} — ${priceFormatter.format(product.price)}`;
}

Buenas prácticas

  • Pasa siempre un locale explícito en código de servidor; en cliente, toma el del usuario (navigator.language).
  • Declara un locale de fallback en el array: new Intl.NumberFormat(["gl-ES", "es-ES"], opts) asegura resultado aunque el primero no esté soportado.
  • Para monedas, usa el código ISO 4217 (EUR, USD, JPY). El formateador aplica los decimales propios de cada divisa.
  • Reutiliza instancias de formateadores; crearlos tiene un coste apreciable.
  • Cuando necesites construir un texto a medida, usa formatToParts en lugar de parsear la cadena resultante.
  • Para tiempos relativos, combina Intl.RelativeTimeFormat con el cálculo de la diferencia; numeric: "auto" produce textos más naturales.

Resumen

La API Intl cubre sin librerías externas las necesidades de formato más frecuentes en aplicaciones internacionales: números, monedas, porcentajes, fechas con zonas horarias, tiempos relativos y listas. Cada servicio sigue el mismo patrón —locale más opciones más format— y se integra con el motor del navegador o de Node, que ya conoce las convenciones de cada idioma. Adoptarla desde el principio ahorra dependencias y evita errores sutiles en productos multilingües.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, JavaScript es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de JavaScript

Explora más contenido relacionado con JavaScript y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

  • Conocer la API Intl y los servicios de internacionalización nativos del navegador y Node.
  • Formatear números, monedas y porcentajes con Intl.NumberFormat.
  • Formatear fechas y horas con Intl.DateTimeFormat, incluyendo zonas horarias.
  • Expresar tiempos relativos legibles con Intl.RelativeTimeFormat.
  • Unir elementos en una lista idiomática con Intl.ListFormat.
  • Seleccionar locales (es-ES, en-US, fallback) y opciones para cada formateador.

Cursos que incluyen esta lección

Esta lección forma parte de los siguientes cursos estructurados con rutas de aprendizaje