API Intl.NumberFormat
Formatea números para cualquier locale con la API de internacionalización integrada en JavaScript
Introducción
Considera mostrar el número 1234567.89 en tu aplicación. Usar toString() produce "1234567.89", que es difícil de leer y asume que todos usan puntos para los decimales y leen los números de izquierda a derecha. Los estadounidenses esperan "1,234,567.89", los alemanes esperan "1.234.567,89", y los usuarios en India esperan "12,34,567.89" con diferentes reglas de agrupación.
La API Intl.NumberFormat resuelve esto formateando números según las convenciones específicas de cada localización. Maneja separadores de miles, puntos decimales, agrupación de dígitos, símbolos de moneda, signos de porcentaje, unidades de medida y sistemas de numeración. Esto elimina la necesidad de manipulación manual de cadenas o bibliotecas de terceros.
Esta guía explica cómo usar Intl.NumberFormat para formatear números correctamente para usuarios de todo el mundo, comenzando con el uso básico y progresando a características avanzadas como formato de moneda, notación compacta y modos de redondeo personalizados.
Formatear un número con configuración predeterminada
Crea un formateador llamando a new Intl.NumberFormat() con una cadena de localización, luego llama a su método format() con un número.
const formatter = new Intl.NumberFormat('en-US');
formatter.format(1234567.89);
// "1,234,567.89"
El formateador añade separadores de miles y formatea el punto decimal según la localización. Sin especificar una localización, el formateador usa la localización predeterminada del entorno de ejecución, típicamente basada en la configuración del sistema del usuario.
const formatter = new Intl.NumberFormat('de-DE');
formatter.format(1234567.89);
// "1.234.567,89"
Las convenciones alemanas usan puntos para separadores de miles y comas para puntos decimales, al contrario de las convenciones estadounidenses. El formateador maneja estas diferencias automáticamente.
Entender los códigos de localización
Un código de localización identifica un idioma y opcionalmente una región, escrito como idioma-REGIÓN. El idioma usa un código ISO 639-1 de dos letras como en o es. La región usa un código ISO 3166-1 de dos letras como US o MX.
new Intl.NumberFormat('en-US').format(1234.56);
// "1,234.56" (inglés americano)
new Intl.NumberFormat('en-GB').format(1234.56);
// "1,234.56" (inglés británico)
new Intl.NumberFormat('es-ES').format(1234.56);
// "1234,56" (español europeo)
new Intl.NumberFormat('es-MX').format(1234.56);
// "1,234.56" (español mexicano)
Ambas variantes del inglés usan el mismo formato, pero las variantes del español difieren. El español europeo omite los separadores de miles para números de cuatro dígitos y usa comas para los decimales, mientras que el español mexicano sigue las convenciones estadounidenses.
Elige las localizaciones basándote en las ubicaciones de tus usuarios o preferencias de idioma. Las aplicaciones típicamente determinan la localización a partir de la configuración del usuario, el idioma del navegador o la geolocalización IP.
Elige un estilo de formato
La opción style determina la categoría de formato. Pasa un objeto de opciones como segundo argumento al constructor.
new Intl.NumberFormat('en-US', {
style: 'decimal'
}).format(1234.56);
// "1,234.56"
El estilo decimal es el predeterminado. Los otros estilos son currency, percent y unit.
Formatear moneda con símbolos y códigos
El estilo currency requiere una opción currency con un código de moneda ISO 4217.
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(1234.56);
// "$1,234.56"
El formateador añade el símbolo del dólar y formatea a dos decimales por defecto, el estándar para la mayoría de las monedas. Diferentes locales posicionan el símbolo de manera diferente.
new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR'
}).format(1234.56);
// "1.234,56 €"
El formato alemán coloca el símbolo del euro después de la cantidad con un espacio. La opción currency determina qué moneda mostrar, no qué convenciones de formato seguir. El locale determina las convenciones de formato, mientras que la moneda determina el símbolo.
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'EUR'
}).format(1234.56);
// "€1,234.56"
Las convenciones de formato americanas con el símbolo del euro producen un signo de euro antes de la cantidad, siguiendo las convenciones de colocación americanas en lugar de las europeas.
Controlar el formato de visualización de moneda
La opción currencyDisplay cambia cómo aparece la moneda en la cadena formateada.
const amount = 1234.56;
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
currencyDisplay: 'symbol'
}).format(amount);
// "$1,234.56"
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
currencyDisplay: 'code'
}).format(amount);
// "USD 1,234.56"
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
currencyDisplay: 'name'
}).format(amount);
// "1,234.56 US dollars"
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
currencyDisplay: 'narrowSymbol'
}).format(amount);
// "$1,234.56"
La opción symbol es la predeterminada y muestra el símbolo de moneda como $ o €. La opción code muestra el código de moneda de tres letras. La opción name escribe el nombre completo de la moneda. La opción narrowSymbol utiliza un símbolo de moneda estrecho del locale, que puede ser ambiguo pero ahorra espacio.
La diferencia entre symbol y narrowSymbol se hace evidente con monedas que comparten símbolos.
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'CAD',
currencyDisplay: 'symbol'
}).format(100);
// "CA$100.00"
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'CAD',
currencyDisplay: 'narrowSymbol'
}).format(100);
// "$100.00"
Los dólares canadienses se muestran como CA$ con la opción symbol para distinguirlos de los dólares estadounidenses, pero se muestran simplemente como $ con narrowSymbol.
Formatear cantidades monetarias negativas con notación contable
La opción currencySign controla cómo aparecen las cantidades negativas.
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
currencySign: 'standard'
}).format(-1234.56);
// "-$1,234.56"
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
currencySign: 'accounting'
}).format(-1234.56);
// "($1,234.56)"
La opción standard es la predeterminada y utiliza un signo menos. La opción accounting envuelve las cantidades negativas entre paréntesis, siguiendo las convenciones contables. Esto hace que los números negativos sean visualmente más distinguibles en los informes financieros.
Formatear porcentajes
El estilo percent multiplica el número por 100 y añade un signo de porcentaje.
new Intl.NumberFormat('en-US', {
style: 'percent'
}).format(0.1234);
// "12%"
new Intl.NumberFormat('en-US', {
style: 'percent'
}).format(0.1256);
// "13%"
El formateador redondea al entero más cercano por defecto. Controla los decimales con opciones de dígitos.
new Intl.NumberFormat('en-US', {
style: 'percent',
minimumFractionDigits: 2
}).format(0.1234);
// "12.34%"
Pasa la forma decimal del porcentaje, no la forma multiplicada. El formateador se encarga de la multiplicación.
Formatear medidas con unidades
El estilo unit requiere una opción unit con un identificador de unidad.
new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer-per-hour'
}).format(100);
// "100 km/h"
new Intl.NumberFormat('en-GB', {
style: 'unit',
unit: 'mile-per-hour'
}).format(100);
// "100 mph"
Las unidades disponibles incluyen medidas de longitud (meter, kilometer, mile), duraciones de tiempo (second, minute, hour), almacenamiento digital (byte, kilobyte, megabyte), temperaturas (celsius, fahrenheit), y muchas otras. Las unidades compuestas como kilometer-per-hour combinan unidades simples con guiones.
La opción unitDisplay controla el formato de la unidad.
const distance = 1234.5;
new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer',
unitDisplay: 'long'
}).format(distance);
// "1,234.5 kilometers"
new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer',
unitDisplay: 'short'
}).format(distance);
// "1,234.5 km"
new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer',
unitDisplay: 'narrow'
}).format(distance);
// "1,234.5km"
La opción long escribe el nombre completo de la unidad. La opción short utiliza abreviaturas. La opción narrow utiliza la forma más compacta, que puede ser ambigua.
Mostrar números grandes con notación compacta
La opción notation cambia cómo se expresan los números. El valor compact utiliza formas cortas específicas del idioma para números grandes.
new Intl.NumberFormat('en-US', {
notation: 'compact'
}).format(1234567);
// "1.2M"
new Intl.NumberFormat('en-US', {
notation: 'compact'
}).format(987654321);
// "988M"
La notación compacta redondea a un decimal por defecto y añade sufijos como K para miles, M para millones y B para miles de millones. Este formato aparece en contadores de seguidores en redes sociales, contadores de visualizaciones de videos y paneles de análisis.
La opción compactDisplay controla la longitud del sufijo.
new Intl.NumberFormat('en-US', {
notation: 'compact',
compactDisplay: 'short'
}).format(1234567);
// "1.2M"
new Intl.NumberFormat('en-US', {
notation: 'compact',
compactDisplay: 'long'
}).format(1234567);
// "1.2 million"
La opción short es la predeterminada y utiliza símbolos. La opción long escribe la palabra de magnitud completa. Diferentes idiomas utilizan diferentes sufijos.
new Intl.NumberFormat('zh-CN', {
notation: 'compact'
}).format(123456789);
// "1.2亿"
El chino usa 亿 para cientos de millones, reflejando el sistema de agrupación numérica del idioma.
Expresar números muy grandes o pequeños en notación científica
La notación scientific expresa números como un coeficiente multiplicado por una potencia de diez.
new Intl.NumberFormat('en-US', {
notation: 'scientific'
}).format(123456789);
// "1.235E8"
new Intl.NumberFormat('en-US', {
notation: 'scientific'
}).format(0.00000123);
// "1.23E-6"
Este formato funciona bien para números muy grandes (distancias astronómicas, recuentos moleculares) y números muy pequeños (masas de partículas, mediciones a nanoescala). El exponente siempre aparece como un múltiplo de uno.
Usar notación de ingeniería para aplicaciones técnicas
La notación engineering es similar a la notación científica pero limita los exponentes a múltiplos de tres.
new Intl.NumberFormat('en-US', {
notation: 'engineering'
}).format(123456789);
// "123.457E6"
new Intl.NumberFormat('en-US', {
notation: 'engineering'
}).format(1234);
// "1.234E3"
La notación de ingeniería se alinea con los prefijos de unidades SI (kilo, mega, giga), convirtiéndola en estándar en contextos de ingeniería y física. El coeficiente varía de 1 a 999.
Controlar los decimales con dígitos fraccionarios
Las opciones minimumFractionDigits y maximumFractionDigits controlan cuántos dígitos aparecen después del punto decimal.
new Intl.NumberFormat('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}).format(1234.5);
// "1,234.50"
new Intl.NumberFormat('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}).format(1234.567);
// "1,234.57"
El mínimo asegura que aparezcan ceros finales cuando sea necesario. El máximo redondea decimales más largos. Los formateadores de moneda tienen por defecto dos decimales. Los formateadores decimales tienen por defecto un mínimo de cero y un máximo de tres.
new Intl.NumberFormat('en-US', {
minimumFractionDigits: 0,
maximumFractionDigits: 0
}).format(1234.567);
// "1,235"
Establecer ambos a cero redondea al entero más cercano.
Controlar la precisión general con dígitos significativos
Las opciones minimumSignificantDigits y maximumSignificantDigits controlan la precisión total independientemente de la posición del punto decimal.
new Intl.NumberFormat('en-US', {
minimumSignificantDigits: 3,
maximumSignificantDigits: 3
}).format(1234.567);
// "1,230"
new Intl.NumberFormat('en-US', {
minimumSignificantDigits: 3,
maximumSignificantDigits: 3
}).format(0.001234);
// "0.00123"
Los dígitos significativos cuentan todos los dígitos excepto los ceros iniciales. El primer ejemplo redondea a tres dígitos, produciendo 1230. El segundo ejemplo mantiene tres dígitos después de los ceros iniciales, produciendo 0.00123.
Las opciones de dígitos significativos anulan las opciones de dígitos fraccionarios cuando se especifican ambas.
Elegir una estrategia de redondeo con modos de redondeo
La opción roundingMode determina cómo se redondean los números cuando es necesario truncarlos.
const value = 1.5;
new Intl.NumberFormat('en-US', {
maximumFractionDigits: 0,
roundingMode: 'halfExpand'
}).format(value);
// "2"
new Intl.NumberFormat('en-US', {
maximumFractionDigits: 0,
roundingMode: 'halfTrunc'
}).format(value);
// "1"
El modo halfExpand es el predeterminado y redondea 0.5 alejándose de cero, una estrategia de redondeo común enseñada en las escuelas. El modo halfTrunc redondea 0.5 hacia cero.
Otros modos incluyen:
ceil: Siempre redondea hacia el infinito positivofloor: Siempre redondea hacia el infinito negativoexpand: Siempre redondea alejándose de cerotrunc: Siempre redondea hacia cerohalfCeil: Redondea 0.5 hacia el infinito positivohalfFloor: Redondea 0.5 hacia el infinito negativohalfEven: Redondea 0.5 hacia el número par más cercano
const prices = [1.5, 2.5, 3.5];
prices.map(price =>
new Intl.NumberFormat('en-US', {
maximumFractionDigits: 0,
roundingMode: 'halfEven'
}).format(price)
);
// ["2", "2", "4"]
El modo halfEven, también llamado redondeo bancario, reduce el sesgo de redondeo en cálculos repetidos. Al redondear 0.5, elige el número par más cercano. Esto produce 2 tanto para 1.5 como para 2.5, pero 4 para 3.5.
Las aplicaciones financieras usan ceil para redondear cargos hacia arriba y floor para redondear reembolsos hacia abajo. Las aplicaciones estadísticas usan halfEven para minimizar errores acumulativos de redondeo.
Controlar los separadores de miles con opciones de agrupación
La opción useGrouping controla si aparecen los separadores de miles.
new Intl.NumberFormat('en-US', {
useGrouping: true
}).format(123456);
// "123,456"
new Intl.NumberFormat('en-US', {
useGrouping: false
}).format(123456);
// "123456"
El valor true es el predeterminado. El valor false elimina todos los separadores. Los valores de tipo string proporcionan un control más preciso.
new Intl.NumberFormat('en-US', {
useGrouping: 'always'
}).format(1234);
// "1,234"
new Intl.NumberFormat('en-US', {
useGrouping: 'min2'
}).format(1234);
// "1234"
El valor always utiliza separadores en todos los casos. El valor min2 omite los separadores para números de cuatro dígitos. El valor auto sigue las preferencias del idioma, que normalmente coinciden con el comportamiento de min2.
La notación compacta utiliza min2 por defecto porque los números compactos raramente necesitan separadores internos.
Mostrar signos explícitamente con opciones de visualización de signos
La opción signDisplay controla cuándo aparecen los signos positivos y negativos.
new Intl.NumberFormat('en-US', {
signDisplay: 'auto'
}).format(100);
// "100"
new Intl.NumberFormat('en-US', {
signDisplay: 'always'
}).format(100);
// "+100"
El valor auto es el predeterminado y muestra signos negativos para números negativos pero no signos positivos para números positivos. El valor always muestra ambos.
new Intl.NumberFormat('en-US', {
signDisplay: 'exceptZero'
}).format(0);
// "0"
new Intl.NumberFormat('en-US', {
signDisplay: 'always'
}).format(0);
// "+0"
El valor exceptZero omite los signos para valores cero incluso con el comportamiento always. Esto evita mostrar confusamente +0 y -0.
new Intl.NumberFormat('en-US', {
signDisplay: 'never'
}).format(-100);
// "100"
El valor never elimina los signos por completo, mostrando solo el valor absoluto.
Las aplicaciones financieras utilizan always para resaltar las ganancias con signos positivos. Las visualizaciones de temperatura utilizan exceptZero para evitar mostrar +0° o -0°.
Dividir la salida formateada en partes
El método formatToParts() devuelve un array de objetos que representan cada componente de la cadena formateada.
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).formatToParts(1234.56);
Esto devuelve:
[
{ type: 'currency', value: '$' },
{ type: 'integer', value: '1' },
{ type: 'group', value: ',' },
{ type: 'integer', value: '234' },
{ type: 'decimal', value: '.' },
{ type: 'fraction', value: '56' }
]
Cada objeto tiene un type que identifica el componente y un value que contiene la cadena. El type puede ser currency, integer, group, decimal, fraction, literal, minusSign, plusSign, percentSign, u otros.
Esto permite aplicar estilos personalizados a componentes individuales.
const parts = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).formatToParts(1234.56);
const formatted = parts.map(part => {
if (part.type === 'currency') {
return `<span class="currency">${part.value}</span>`;
}
if (part.type === 'integer') {
return `<span class="integer">${part.value}</span>`;
}
return part.value;
}).join('');
// <span class="currency">$</span><span class="integer">1</span>,<span class="integer">234</span>.56
Esto produce HTML con componentes estilizados. El mismo enfoque funciona para aplicar diferentes colores a cantidades negativas, agrandar símbolos de moneda o animar dígitos individuales.
Formatear rangos de números
El método formatRange() formatea dos números como un rango.
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).formatRange(100, 200);
// "$100.00 – $200.00"
El formateador utiliza un separador de rango específico del idioma (un guion medio en español) e incluye ambos símbolos de moneda. Si los valores se formatean a la misma cadena, el formateador devuelve un único valor con una tilde.
new Intl.NumberFormat('en-US', {
notation: 'compact'
}).formatRange(1200, 1800);
// "~1K"
Tanto 1200 como 1800 se formatean como 1K en notación compacta, por lo que el formateador muestra aproximadamente 1K.
El método formatRangeToParts() devuelve las partes del rango.
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).formatRangeToParts(100, 200);
Esto devuelve:
[
{ type: 'currency', value: '$', source: 'startRange' },
{ type: 'integer', value: '100', source: 'startRange' },
{ type: 'decimal', value: '.', source: 'startRange' },
{ type: 'fraction', value: '00', source: 'startRange' },
{ type: 'literal', value: ' – ', source: 'shared' },
{ type: 'currency', value: '$', source: 'endRange' },
{ type: 'integer', value: '200', source: 'endRange' },
{ type: 'decimal', value: '.', source: 'endRange' },
{ type: 'fraction', value: '00', source: 'endRange' }
]
La propiedad source identifica si la parte proviene del valor inicial, valor final o separador de rango.
Los rangos de precios, rangos de fechas y rangos de medidas utilizan este método para un formateo adecuado y sensible al idioma.
Inspeccionar opciones resueltas
El método resolvedOptions() devuelve un objeto que muestra las opciones reales utilizadas por el formateador.
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
formatter.resolvedOptions();
Esto devuelve:
{
locale: 'en-US',
numberingSystem: 'latn',
style: 'currency',
currency: 'USD',
currencyDisplay: 'symbol',
currencySign: 'standard',
minimumIntegerDigits: 1,
minimumFractionDigits: 2,
maximumFractionDigits: 2,
useGrouping: 'auto',
notation: 'standard',
signDisplay: 'auto',
roundingMode: 'halfExpand'
}
El objeto incluye opciones establecidas explícitamente y valores predeterminados. El locale puede diferir del locale solicitado si el sistema resolvió a un locale diferente pero compatible. El numberingSystem muestra qué caracteres de dígitos utiliza el formateador.
Este método ayuda a depurar formateos inesperados al revelar todas las configuraciones activas.
Reutilizar formateadores para un mejor rendimiento
Crear una instancia de NumberFormat implica cargar datos de locale y procesar opciones. Reutiliza las instancias cuando formatees múltiples valores con la misma configuración.
// Ineficiente: crea un nuevo formateador para cada valor
prices.map(price =>
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(price)
);
// Eficiente: crea el formateador una sola vez
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
prices.map(price => formatter.format(price));
El segundo enfoque es significativamente más rápido cuando se formatean muchos valores. Crea formateadores fuera de bucles y funciones de renderizado de componentes.
Los motores de JavaScript modernos almacenan en caché las instancias de NumberFormat internamente, pero la reutilización explícita proporciona mejor rendimiento y código más claro.
Comprobar la compatibilidad del navegador
La API Intl.NumberFormat es compatible con todos los navegadores modernos. Chrome, Firefox, Safari y Edge han soportado la API básica desde 2016. Las funciones avanzadas como formatRange(), formatRangeToParts() y las opciones extendidas de roundingMode obtuvieron soporte más recientemente, pero ahora están disponibles en las versiones actuales de los navegadores.
Comprueba la compatibilidad usando:
if (typeof Intl !== 'undefined' && Intl.NumberFormat) {
// NumberFormat es compatible
const formatter = new Intl.NumberFormat('en-US');
}
Comprueba funciones específicas:
const formatter = new Intl.NumberFormat('en-US');
if (typeof formatter.formatRange === 'function') {
// formatRange es compatible
}
Las aplicaciones que requieren soporte para navegadores más antiguos pueden usar polyfills como @formatjs/intl-numberformat, pero la mayoría de las aplicaciones modernas pueden usar la API nativa sin alternativas.
Cuándo usar NumberFormat
Utiliza Intl.NumberFormat para:
- Mostrar números a los usuarios en cualquier contexto de interfaz
- Formatear cantidades monetarias en aplicaciones de comercio electrónico
- Mostrar porcentajes en paneles de análisis
- Mostrar recuentos de seguidores, visualizaciones y otras métricas sociales
- Formatear mediciones y valores científicos
- Desarrollar aplicaciones internacionalizadas que soporten múltiples locales
No utilices Intl.NumberFormat para:
- Cálculos internos o procesamiento de datos
- Almacenar valores en bases de datos
- Serializar datos para APIs
- Analizar la entrada del usuario para convertirla en números
NumberFormat es una herramienta de capa de presentación. Mantén los valores numéricos sin formato en cálculos y almacenamiento, aplicando el formato solo cuando muestres valores a los usuarios.