ToolPal
Números y símbolos matemáticos sobre fondo oscuro

Formato de números en JavaScript: Guía completa de Intl.NumberFormat

📷 Antoine Dautry / Pexels

Formato de números en JavaScript: Guía completa de Intl.NumberFormat

Domina el formato de números para audiencias internacionales. Aprende a usar Intl.NumberFormat para divisas, porcentajes y visualización de números según la configuración regional en JavaScript.

10 de abril de 20267 min de lectura

La primera vez que me tocó internacionalizar una aplicación web, pensé que con cambiar el símbolo de la moneda era suficiente. Craso error. Un usuario español me escribió confundido porque los precios no tenían sentido: yo mostraba $1,234.56 y él lo leía como "uno coma doscientos treinta y cuatro punto cincuenta y seis dólares" — que en español equivaldría a algo completamente diferente.

El problema de fondo es que los números no son universales. Las convenciones de formato varían enormemente de un país a otro, y si no se tiene en cuenta, la experiencia de usuario se resiente. Por suerte, JavaScript incluye una API nativa que resuelve todo esto de forma elegante.

El problema: distintos formatos en cada región

El número 1234567.89 se escribe de maneras muy diferentes según el lugar:

  • España / México / Argentina: 1.234.567,89 (punto como separador de miles, coma como decimal)
  • Estados Unidos / Reino Unido: 1,234,567.89 (coma como separador de miles, punto como decimal)
  • Francia / Bélgica: 1 234 567,89 (espacio como separador de miles, coma como decimal)
  • Suiza: 1'234'567.89 (apóstrofo como separador de miles)
  • India: 12,34,567.89 (agrupación especial de dígitos)

En el mundo hispanohablante, 1,234.56 puede interpretarse como "uno coma doscientos treinta y cuatro" — es decir, aproximadamente 1,23, no 1.234. En una aplicación financiera o de comercio electrónico, eso es un error serio.

Intentar manejar todos estos casos con manipulación de cadenas manual es un camino directo a los bugs. La API Intl.NumberFormat existe precisamente para evitar ese problema.

La API Intl.NumberFormat de JavaScript

El espacio de nombres Intl fue introducido con ES2015 y contiene varias herramientas de internacionalización. Intl.NumberFormat es el componente específico para formatear números. El soporte de navegadores es excelente: funciona en todos los navegadores modernos y en Node.js 10+, sin polyfills.

// Uso básico
const formateador = new Intl.NumberFormat('es-ES');
formateador.format(1234567.89);
// "1.234.567,89"

// Uso puntual
new Intl.NumberFormat('es-ES').format(1234567.89);
// "1.234.567,89"

// Comparación con otras configuraciones regionales
new Intl.NumberFormat('en-US').format(1234567.89);
// "1,234,567.89"

new Intl.NumberFormat('de-DE').format(1234567.89);
// "1.234.567,89"

Controlar los decimales

// Siempre mostrar 2 decimales
new Intl.NumberFormat('es-ES', {
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
}).format(1234.5);
// "1.234,50"

// Máximo 3 decimales, sin ceros innecesarios
new Intl.NumberFormat('es-ES', {
  minimumFractionDigits: 0,
  maximumFractionDigits: 3
}).format(1234.5);
// "1.234,5"

Desactivar el separador de miles

Para años, identificadores u otros números que no necesitan separador:

new Intl.NumberFormat('es-ES', {
  useGrouping: false
}).format(2024);
// "2024" (no "2.024")

Formato de divisas

El formato de divisas es donde Intl.NumberFormat demuestra todo su valor. Las reglas varían según la divisa: número de decimales, posición del símbolo, espaciado — todo es diferente.

// Euro (formato español)
new Intl.NumberFormat('es-ES', {
  style: 'currency',
  currency: 'EUR'
}).format(1234.56);
// "1.234,56 €"

// Dólar estadounidense
new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
}).format(1234.56);
// "$1,234.56"

// Yen japonés (sin decimales)
new Intl.NumberFormat('ja-JP', {
  style: 'currency',
  currency: 'JPY'
}).format(1234);
// "¥1,234"

// Peso mexicano
new Intl.NumberFormat('es-MX', {
  style: 'currency',
  currency: 'MXN'
}).format(1234.56);
// "$1,234.56"

Punto importante: la divisa (currency) y la configuración regional (el estilo de formato) son parámetros independientes. Se puede mostrar USD con formato español — útil cuando un usuario español compra algo en dólares:

new Intl.NumberFormat('es-ES', {
  style: 'currency',
  currency: 'USD'
}).format(1234.56);
// "1.234,56 US$"

Modo de visualización de la divisa

const importe = 1234.56;

// Símbolo (predeterminado)
new Intl.NumberFormat('es-ES', {
  style: 'currency',
  currency: 'USD',
  currencyDisplay: 'symbol'
}).format(importe);
// "1.234,56 US$"

// Código ISO
new Intl.NumberFormat('es-ES', {
  style: 'currency',
  currency: 'USD',
  currencyDisplay: 'code'
}).format(importe);
// "1.234,56 USD"

// Nombre completo
new Intl.NumberFormat('es-ES', {
  style: 'currency',
  currency: 'USD',
  currencyDisplay: 'name'
}).format(importe);
// "1.234,56 dólares estadounidenses"

Con currencyDisplay: 'name' en español, obtenemos "dólares estadounidenses" — la API conoce los nombres localizados de todas las divisas.

Trampa a evitar: divisas como el yen japonés (JPY) o el won coreano (KRW) no tienen subdivisiones. En modo currency, no muestran decimales y los valores decimales se redondean automáticamente.

Formato de porcentajes

El formato de porcentajes tiene una trampa habitual:

// Atención: pasar como fracción decimal (0.75 = 75 %)
new Intl.NumberFormat('es-ES', {
  style: 'percent'
}).format(0.75);
// "75 %"

// Con un decimal
new Intl.NumberFormat('es-ES', {
  style: 'percent',
  minimumFractionDigits: 1,
  maximumFractionDigits: 1
}).format(0.7523);
// "75,2 %"

Error frecuente: el estilo percent multiplica el valor por 100. Si se pasa 75, el resultado es 7.500 %. Si ya tienes el valor como porcentaje (75), debes dividirlo entre 100 primero:

const valorPorcentaje = 75;
new Intl.NumberFormat('es-ES', {
  style: 'percent'
}).format(valorPorcentaje / 100);
// "75 %"

Notación científica

Para aplicaciones científicas o de ingeniería:

new Intl.NumberFormat('es-ES', {
  notation: 'scientific'
}).format(1234567890);
// "1,235E9"

new Intl.NumberFormat('es-ES', {
  notation: 'engineering'
}).format(1234567890);
// "1,235E9"

Notación compacta

Muy útil en paneles de control y estadísticas:

// Configuración regional española
new Intl.NumberFormat('es-ES', {
  notation: 'compact',
  compactDisplay: 'short'
}).format(1200);
// "1,2 mil"

new Intl.NumberFormat('es-ES', {
  notation: 'compact',
  compactDisplay: 'short'
}).format(3500000);
// "3,5 M"

new Intl.NumberFormat('es-ES', {
  notation: 'compact',
  compactDisplay: 'long'
}).format(1200);
// "1,2 miles"

// Configuración regional de EE. UU. para comparar
new Intl.NumberFormat('en-US', {
  notation: 'compact'
}).format(1200);
// "1.2K"

Errores comunes y casos límite

NaN e Infinity:

new Intl.NumberFormat('es-ES').format(NaN);
// "NaN"

new Intl.NumberFormat('es-ES').format(Infinity);
// "+infinito" (algunas locales tienen su propia representación)

Lo mejor es validar los valores antes de formatearlos para no mostrar símbolos técnicos a los usuarios.

Rendimiento: crear una instancia de Intl.NumberFormat tiene un coste. Si formateas muchos números con las mismas opciones, reutiliza la instancia:

// Ineficiente
numeros.forEach(n => new Intl.NumberFormat('es-ES').format(n));

// Eficiente
const formateador = new Intl.NumberFormat('es-ES');
numeros.forEach(n => formateador.format(n));

El método formatToParts(): para aplicar estilos distintos a cada parte del número formateado:

new Intl.NumberFormat('es-ES', {
  style: 'currency',
  currency: 'EUR'
}).formatToParts(1234.56);
// [
//   { type: 'integer', value: '1' },
//   { type: 'group', value: '.' },
//   { type: 'integer', value: '234' },
//   { type: 'decimal', value: ',' },
//   { type: 'fraction', value: '56' },
//   { type: 'literal', value: ' ' },
//   { type: 'currency', value: '€' }
// ]

En componentes React, esto permite dar un color o tamaño distinto al símbolo de la divisa.

Números grandes y BigInt: para enteros muy grandes (más de 2^53), Intl.NumberFormat es compatible con BigInt:

new Intl.NumberFormat('es-ES').format(9007199254740993n);
// "9.007.199.254.740.993"

Limitaciones de Intl.NumberFormat

Siendo honestos, esta API tiene sus límites:

  • Sin análisis (parsing): no hay una API Intl.NumberParse. Convertir "1.234,56" en 1234.56 requiere implementación propia — es sorprendentemente complejo.
  • Sin formatos personalizados: los formatos tipo Excel (#.##0,00) no están soportados. Para eso, bibliotecas como numeral.js son más adecuadas.
  • Formato contable: mostrar negativos entre paréntesis (1.234,56) está parcialmente cubierto con currencySign: 'accounting', pero no en todas las locales.

Para la gran mayoría de aplicaciones web, Intl.NumberFormat cubre perfectamente las necesidades.

La herramienta Number Formatter de ToolBox Hub

Si quieres probar distintas opciones de formato sin escribir código, la herramienta Number Formatter de ToolBox Hub te permite:

  1. Introducir el número a formatear
  2. Seleccionar una configuración regional (más de 30 disponibles)
  3. Elegir un estilo (decimal, currency, percent, scientific)
  4. Para divisas, seleccionar el código de divisa
  5. Definir los decimales mínimos y máximos
  6. Activar o desactivar el separador de miles
  7. Ver el resultado en tiempo real y copiar el código JavaScript correspondiente

Es especialmente útil para verificar cómo queda un número en una región desconocida antes de desplegar.

Herramientas relacionadas

Conclusión

Intl.NumberFormat es una de las APIs mejor diseñadas de la biblioteca estándar de JavaScript. Bajo su aparente sencillez hay un sistema completo para la localización de números.

Puntos clave a recordar:

  • Siempre usar Intl.NumberFormat para números que se muestren a usuarios — nunca manipulación manual de cadenas
  • La divisa y la configuración regional son parámetros independientes
  • El estilo percent multiplica por 100 — pasar una fracción decimal
  • La notación compact en español da "mil" y "M"
  • Reutilizar la misma instancia para formateos repetidos
  • formatToParts() permite estilizar individualmente cada componente del número

Formatear correctamente los números es una muestra de respeto hacia los usuarios de todo el mundo. Con Intl.NumberFormat, además, el código es más sencillo, más fiable y más fácil de mantener.

Preguntas Frecuentes

Compartir

XLinkedIn

Publicaciones relacionadas