¿Cómo formatear listas de medidas con unidades?
Muestra múltiples medidas como 5 km, 10 km, 15 km con formato de lista apropiado según la configuración regional utilizando las APIs Intl de JavaScript
Introducción
Las aplicaciones que muestran mediciones a menudo necesitan mostrar múltiples valores juntos. Una aplicación de fitness podría mostrar tiempos parciales como "5 km, 10 km, 15 km". Una aplicación meteorológica podría mostrar temperaturas a lo largo de la semana como "20°C, 22°C, 25°C, 23°C". Una receta podría enumerar cantidades de ingredientes como "2 tazas, 1 cucharada, 3 cucharaditas".
Estas listas combinan dos desafíos de internacionalización. Primero, cada medición necesita un formato de unidad apropiado para el idioma local. Segundo, la lista en sí necesita puntuación y separadores adecuados para el idioma de destino. El inglés utiliza comas y a veces conjunciones como "and". Otros idiomas utilizan diferentes separadores y siguen diferentes reglas gramaticales.
JavaScript proporciona dos APIs para resolver este problema. Intl.NumberFormat formatea mediciones individuales con unidades. Intl.ListFormat combina múltiples valores en una lista gramaticalmente correcta. Esta lección explica cómo usar ambas APIs juntas para formatear listas de mediciones que coincidan con las expectativas del usuario en cualquier idioma.
Las listas de mediciones requieren dos pasos de formateo
Cuando formateas una lista de mediciones, no puedes omitir ninguno de los pasos de formateo. Si formateas la lista sin formatear las mediciones, obtienes separadores apropiados para el idioma pero una visualización incorrecta de las unidades. Si formateas las mediciones sin formatear la lista, obtienes unidades correctas pero separadores incorrectos.
const distances = [5, 10, 15];
// Incorrecto: lista formateada pero no las mediciones
console.log(distances.join(', '));
// Resultado: "5, 10, 15" (faltan unidades)
// Incorrecto: mediciones formateadas pero no la lista
const formatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer'
});
console.log(distances.map(d => formatter.format(d)).join(', '));
// Resultado: "5 km, 10 km, 15 km" (la coma codificada podría ser incorrecta para algunos idiomas)
El enfoque correcto formatea primero las mediciones, luego formatea el array resultante de cadenas como una lista.
const distances = [5, 10, 15];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer'
});
const formattedMeasurements = distances.map(d => numberFormatter.format(d));
// Resultado: ["5 km", "10 km", "15 km"]
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedMeasurements));
// Resultado: "5 km, 10 km, 15 km"
Este patrón funciona para cualquier tipo de medición y cualquier idioma. Formateas cada medición con su unidad, luego formateas el array de cadenas formateadas como una lista.
Usar type unit para listas de medidas
El constructor Intl.ListFormat acepta una opción type que controla cómo se combinan los elementos de la lista. La opción type: 'unit' formatea las listas siguiendo las convenciones para datos técnicos y científicos.
const measurements = ['5 km', '10 km', '15 km'];
const unitList = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(unitList.format(measurements));
// Resultado: "5 km, 10 km, 15 km"
Las listas con type: 'unit' omiten conjunciones como "y" o "o". Utilizan separadores simples entre elementos. Esto coincide con la forma en que normalmente se escriben las medidas en contextos técnicos.
Compara esto con type: 'conjunction', que añade "y" antes del último elemento.
const measurements = ['5 km', '10 km', '15 km'];
const conjunctionList = new Intl.ListFormat('en-US', {
type: 'conjunction'
});
console.log(conjunctionList.format(measurements));
// Resultado: "5 km, 10 km, and 15 km"
La forma de conjunción se lee naturalmente en prosa pero parece incorrecta en contextos técnicos. Cuando muestres múltiples medidas, usa type: 'unit' para seguir las convenciones estándar de escritura científica y técnica.
Formatear medidas de distancia en listas
Las medidas de distancia utilizan identificadores de unidad como kilometer, meter, mile y foot. Después de formatear cada distancia con su unidad, combínalas en una lista.
const distances = [5, 10, 15, 20];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// Resultado: "5 km, 10 km, 15 km, 20 km"
El mismo patrón funciona para millas.
const distances = [3, 6, 9];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'mile'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// Resultado: "3 mi, 6 mi, 9 mi"
Puedes formatear distancias con decimales configurando opciones de formato de números.
const distances = [5.2, 10.7, 15.3];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer',
maximumFractionDigits: 1
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// Resultado: "5.2 km, 10.7 km, 15.3 km"
El formateador de números maneja el redondeo y los decimales antes de que el formateador de listas combine los valores.
Formatear mediciones de peso en listas
Las mediciones de peso siguen el mismo patrón utilizando identificadores de unidad como kilogram, pound, ounce y gram.
const weights = [50, 75, 100];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilogram'
});
const formattedWeights = weights.map(w => numberFormatter.format(w));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedWeights));
// Output: "50 kg, 75 kg, 100 kg"
Puedes mostrar el peso en libras en su lugar.
const weights = [110, 165, 220];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'pound'
});
const formattedWeights = weights.map(w => numberFormatter.format(w));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedWeights));
// Output: "110 lb, 165 lb, 220 lb"
El formateador de números utiliza automáticamente la abreviatura correcta para cada unidad.
Formatear mediciones de temperatura en listas
Las mediciones de temperatura utilizan identificadores de unidad como celsius y fahrenheit.
const temperatures = [20, 22, 25, 23, 21];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'celsius'
});
const formattedTemperatures = temperatures.map(t => numberFormatter.format(t));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedTemperatures));
// Output: "20°C, 22°C, 25°C, 23°C, 21°C"
Los formateadores de temperatura incluyen automáticamente símbolos de grado en la salida.
Fahrenheit funciona de la misma manera.
const temperatures = [68, 72, 77, 73, 70];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'fahrenheit'
});
const formattedTemperatures = temperatures.map(t => numberFormatter.format(t));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedTemperatures));
// Output: "68°F, 72°F, 77°F, 73°F, 70°F"
El patrón permanece idéntico en los diferentes tipos de medición. Solo cambia el identificador de unidad.
Formatear mediciones de volumen en listas
Las mediciones de volumen utilizan identificadores de unidad como liter, gallon, milliliter y fluid-ounce.
const volumes = [1, 2, 3];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'liter'
});
const formattedVolumes = volumes.map(v => numberFormatter.format(v));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedVolumes));
// Output: "1 L, 2 L, 3 L"
Las mediciones de volumen funcionan con valores decimales.
const volumes = [0.5, 1.5, 2.5];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'liter',
maximumFractionDigits: 1
});
const formattedVolumes = volumes.map(v => numberFormatter.format(v));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedVolumes));
// Output: "0.5 L, 1.5 L, 2.5 L"
El formateador de números maneja la precisión decimal antes de que el formateador de listas procese los valores.
Formatear mediciones de velocidad en listas
Las mediciones de velocidad utilizan unidades compuestas como kilometer-per-hour y mile-per-hour.
const speeds = [50, 75, 100];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer-per-hour'
});
const formattedSpeeds = speeds.map(s => numberFormatter.format(s));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedSpeeds));
// Output: "50 km/h, 75 km/h, 100 km/h"
Las millas por hora funcionan de la misma manera.
const speeds = [30, 45, 60];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'mile-per-hour'
});
const formattedSpeeds = speeds.map(s => numberFormatter.format(s));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedSpeeds));
// Output: "30 mph, 45 mph, 60 mph"
Las unidades compuestas se formatean automáticamente con las abreviaturas y separadores correctos.
La configuración regional determina el formato del separador de lista
El parámetro de configuración regional controla cómo se separan y puntúan los elementos de la lista. Diferentes idiomas utilizan diferentes convenciones para el formato de listas.
const distances = [5, 10, 15];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const enList = new Intl.ListFormat('en-US', {
type: 'unit'
});
const frList = new Intl.ListFormat('fr-FR', {
type: 'unit'
});
const deList = new Intl.ListFormat('de-DE', {
type: 'unit'
});
console.log(enList.format(formattedDistances));
// Output: "5 km, 10 km, 15 km"
console.log(frList.format(formattedDistances));
// Output: "5 km, 10 km, 15 km"
console.log(deList.format(formattedDistances));
// Output: "5 km, 10 km, 15 km"
Aunque las abreviaturas de kilómetro permanecen similares en estas configuraciones regionales, los espacios y las convenciones de separadores pueden variar. La API Intl.ListFormat maneja estas reglas de formato específicas de la configuración regional automáticamente.
Algunos idiomas utilizan diferentes separadores o patrones de puntuación para las listas. La API garantiza que tus listas sigan las convenciones correctas para cada configuración regional sin que necesites conocer las reglas específicas.
Hacer coincidir la configuración regional de números con la de listas
Al formatear listas de medidas, utiliza la misma configuración regional tanto para el formateador de números como para el formateador de listas. Esto garantiza un formato coherente en toda la salida.
const distances = [1000, 2000, 3000];
const locale = 'de-DE';
const numberFormatter = new Intl.NumberFormat(locale, {
style: 'unit',
unit: 'meter'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat(locale, {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// Salida: "1.000 m, 2.000 m, 3.000 m"
El formato alemán utiliza puntos como separadores de miles. Tanto el formateador de números como el formateador de listas utilizan las convenciones alemanas porque comparten la misma configuración regional.
Utilizar diferentes configuraciones regionales para el formato de números y listas crea una salida inconsistente.
const distances = [1000, 2000, 3000];
const numberFormatter = new Intl.NumberFormat('de-DE', {
style: 'unit',
unit: 'meter'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// Salida: "1.000 m, 2.000 m, 3.000 m"
Esto crea un formato mixto donde los números utilizan convenciones alemanas pero la lista utiliza convenciones inglesas. Siempre utiliza la misma configuración regional para ambos formateadores.
Controlar el estilo de visualización de listas
La opción style controla cuán detallado aparece el formato de la lista. La opción acepta tres valores: "long", "short" y "narrow".
const measurements = ['5 km', '10 km', '15 km'];
const longList = new Intl.ListFormat('en-US', {
type: 'unit',
style: 'long'
});
const shortList = new Intl.ListFormat('en-US', {
type: 'unit',
style: 'short'
});
const narrowList = new Intl.ListFormat('en-US', {
type: 'unit',
style: 'narrow'
});
console.log(longList.format(measurements));
// Salida: "5 km, 10 km, 15 km"
console.log(shortList.format(measurements));
// Salida: "5 km, 10 km, 15 km"
console.log(narrowList.format(measurements));
// Salida: "5 km 10 km 15 km"
Los estilos long y short producen una salida similar para listas de unidades en inglés. El estilo narrow utiliza un espaciado mínimo y omite los separadores entre elementos.
Diferentes configuraciones regionales muestran más variación entre estilos. La configuración regional determina el formato exacto para cada nivel de estilo.
Combinar con nombres de unidades largos
Puedes formatear medidas con nombres completos de unidades en lugar de abreviaturas configurando unitDisplay: 'long' en el formateador de números.
const distances = [5, 10, 15];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer',
unitDisplay: 'long'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// Output: "5 kilometers, 10 kilometers, 15 kilometers"
El formateador de números maneja automáticamente las formas singulares y plurales. El formateador de listas combina las cadenas formateadas independientemente de si utilizan abreviaturas o nombres completos.
const distances = [1, 5];
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer',
unitDisplay: 'long'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// Output: "1 kilometer, 5 kilometers"
El formateador de números usa "kilometer" para 1 y "kilometers" para 5. El formateador de listas los combina con separadores apropiados.
Reutilizar formateadores para un mejor rendimiento
La creación de instancias de Intl.NumberFormat e Intl.ListFormat implica cargar datos de localización y procesar opciones. Cuando formateas múltiples listas de medidas, crea los formateadores una vez y reutilízalos.
const numberFormatter = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'kilometer'
});
const listFormatter = new Intl.ListFormat('en-US', {
type: 'unit'
});
const distanceLists = [
[5, 10, 15],
[20, 25, 30],
[35, 40, 45]
];
distanceLists.forEach(distances => {
const formattedDistances = distances.map(d => numberFormatter.format(d));
console.log(listFormatter.format(formattedDistances));
});
// Output:
// "5 km, 10 km, 15 km"
// "20 km, 25 km, 30 km"
// "35 km, 40 km, 45 km"
Este patrón crea cada formateador una sola vez y lo utiliza múltiples veces. La diferencia de rendimiento se vuelve significativa cuando se formatean muchas listas.
Crear una función de formato reutilizable
Puedes encapsular el patrón de formato de dos pasos en una función reutilizable.
function formatMeasurementList(values, locale, unit) {
const numberFormatter = new Intl.NumberFormat(locale, {
style: 'unit',
unit: unit
});
const formattedValues = values.map(v => numberFormatter.format(v));
const listFormatter = new Intl.ListFormat(locale, {
type: 'unit'
});
return listFormatter.format(formattedValues);
}
console.log(formatMeasurementList([5, 10, 15], 'en-US', 'kilometer'));
// Salida: "5 km, 10 km, 15 km"
console.log(formatMeasurementList([50, 75, 100], 'en-US', 'kilogram'));
// Salida: "50 kg, 75 kg, 100 kg"
console.log(formatMeasurementList([20, 22, 25], 'en-US', 'celsius'));
// Salida: "20°C, 22°C, 25°C"
Esta función maneja cualquier tipo de medida y localización. Puedes extenderla para aceptar opciones de formato adicionales.
function formatMeasurementList(values, locale, unit, options = {}) {
const numberFormatter = new Intl.NumberFormat(locale, {
style: 'unit',
unit: unit,
...options
});
const formattedValues = values.map(v => numberFormatter.format(v));
const listFormatter = new Intl.ListFormat(locale, {
type: 'unit'
});
return listFormatter.format(formattedValues);
}
console.log(formatMeasurementList(
[5.123, 10.789, 15.456],
'en-US',
'kilometer',
{ maximumFractionDigits: 1 }
));
// Salida: "5.1 km, 10.8 km, 15.5 km"
console.log(formatMeasurementList(
[1, 5, 10],
'en-US',
'kilometer',
{ unitDisplay: 'long' }
));
// Salida: "1 kilometer, 5 kilometers, 10 kilometers"
La función pasa opciones adicionales al formateador de números, permitiendo controlar los decimales, la visualización de unidades y otras configuraciones de formato.
Formatear listas para la localización del usuario
En lugar de codificar una localización específica, puedes utilizar las preferencias de idioma del navegador del usuario. La propiedad navigator.language devuelve la localización preferida del usuario.
const userLocale = navigator.language;
const distances = [5, 10, 15];
const numberFormatter = new Intl.NumberFormat(userLocale, {
style: 'unit',
unit: 'kilometer'
});
const formattedDistances = distances.map(d => numberFormatter.format(d));
const listFormatter = new Intl.ListFormat(userLocale, {
type: 'unit'
});
console.log(listFormatter.format(formattedDistances));
// La salida varía según la localización del usuario
Este enfoque muestra listas de medidas de acuerdo con las expectativas de formato de cada usuario. Diferentes usuarios ven los mismos datos formateados según las convenciones de su localización.
Mostrar listas de medidas en aplicaciones
Puedes usar este patrón en cualquier lugar donde muestres múltiples medidas a los usuarios. Esto incluye aplicaciones de fitness que muestran tiempos parciales, aplicaciones meteorológicas que muestran pronósticos de temperatura, aplicaciones de recetas que muestran cantidades de ingredientes y aplicaciones científicas que muestran datos experimentales.
const splitTimes = [5, 10, 15, 20];
const numberFormatter = new Intl.NumberFormat(navigator.language, {
style: 'unit',
unit: 'kilometer',
maximumFractionDigits: 1
});
const formattedTimes = splitTimes.map(t => numberFormatter.format(t));
const listFormatter = new Intl.ListFormat(navigator.language, {
type: 'unit'
});
const result = listFormatter.format(formattedTimes);
document.getElementById('split-times').textContent = result;
// Muestra: "5 km, 10 km, 15 km, 20 km" (o equivalente según la configuración regional)
Las cadenas formateadas funcionan como cualquier otro valor de cadena. Puedes insertarlas en contenido de texto, atributos o cualquier contexto donde muestres información a los usuarios.