Formato de números en JavaScript: Guía completa de Intl.NumberFormat
📷 Antoine Dautry / PexelsFormato 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.
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" en1234.56requiere implementación propia — es sorprendentemente complejo. - Sin formatos personalizados: los formatos tipo Excel (
#.##0,00) no están soportados. Para eso, bibliotecas comonumeral.jsson más adecuadas. - Formato contable: mostrar negativos entre paréntesis
(1.234,56)está parcialmente cubierto concurrencySign: '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:
- Introducir el número a formatear
- Seleccionar una configuración regional (más de 30 disponibles)
- Elegir un estilo (decimal, currency, percent, scientific)
- Para divisas, seleccionar el código de divisa
- Definir los decimales mínimos y máximos
- Activar o desactivar el separador de miles
- 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
- Convertidor de unidades — conversión entre unidades de medida
- Calculadora de porcentajes — cálculo y visualización de porcentajes
- Convertidor de bytes — conversión de tamaños de archivo
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.NumberFormatpara 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
percentmultiplica por 100 — pasar una fracción decimal - La notación
compacten 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.