¿Cómo formatear listas como A, B y C en JavaScript?

Usa Intl.ListFormat para formatear arrays con conjunciones y separadores específicos del idioma.

Introducción

Cuando muestras una lista de elementos a los usuarios, necesitas unirlos con comas y una conjunción como "y". Diferentes idiomas tienen diferentes convenciones para el formato de listas. El inglés usa comas y "and", el español usa "y", el francés usa "et", y el chino utiliza una puntuación completamente diferente.

La API Intl.ListFormat formatea arrays en cadenas de texto apropiadas para cada localización con los separadores y conjunciones correctos. Esto maneja automáticamente las diferencias culturales en el formato de listas.

El problema con el formato manual de listas

Puedes unir elementos de un array con comas usando el método join().

const fruits = ["apples", "oranges", "bananas"];
const list = fruits.join(", ");
console.log(list);
// "apples, oranges, bananas"

Este enfoque tiene dos problemas. Primero, no añade una conjunción antes del último elemento. Segundo, utiliza puntuación en inglés que no funciona para otros idiomas.

Podrías añadir manualmente "and" antes del último elemento.

const fruits = ["apples", "oranges", "bananas"];
const lastFruit = fruits[fruits.length - 1];
const otherFruits = fruits.slice(0, -1);
const list = otherFruits.join(", ") + ", and " + lastFruit;
console.log(list);
// "apples, oranges, and bananas"

Este código solo funciona para inglés. Los usuarios de español verían "apples, oranges, and bananas" en lugar de "apples, oranges y bananas". Los usuarios franceses verían "and" en lugar de "et". Las reglas de puntuación y conjunción varían según el idioma.

Usando Intl.ListFormat para formatear listas

El constructor Intl.ListFormat crea un formateador que convierte arrays en cadenas de lista apropiadas para cada localización.

const formatter = new Intl.ListFormat("en");
const fruits = ["apples", "oranges", "bananas"];
console.log(formatter.format(fruits));
// "apples, oranges, and bananas"

El formateador utiliza los separadores y conjunciones correctos para la localización especificada. Pasas la localización como primer argumento al constructor.

const enFormatter = new Intl.ListFormat("en");
const esFormatter = new Intl.ListFormat("es");
const frFormatter = new Intl.ListFormat("fr");

const fruits = ["apples", "oranges", "bananas"];

console.log(enFormatter.format(fruits));
// "apples, oranges, and bananas"

console.log(esFormatter.format(fruits));
// "apples, oranges y bananas"

console.log(frFormatter.format(fruits));
// "apples, oranges et bananas"

El formateador aplica automáticamente las reglas de puntuación y conjunción para cada localización.

Formateo de listas con "y"

El comportamiento predeterminado de Intl.ListFormat utiliza la conjunción "y" o su equivalente en otros idiomas. Esto se denomina formateo de conjunción.

const formatter = new Intl.ListFormat("en", { type: "conjunction" });
const items = ["bread", "milk", "eggs"];
console.log(formatter.format(items));
// "bread, milk, and eggs"

La opción type controla qué conector aparece entre los elementos. El valor "conjunction" produce listas que utilizan "y". Este es el valor predeterminado, por lo que puedes omitirlo.

Comprendiendo las opciones de tipo de lista

La opción type acepta tres valores que controlan cómo se conectan los elementos.

El tipo "conjunction" utiliza "y" o su equivalente.

const formatter = new Intl.ListFormat("en", { type: "conjunction" });
console.log(formatter.format(["red", "green", "blue"]));
// "red, green, and blue"

El tipo "disjunction" utiliza "o" o su equivalente.

const formatter = new Intl.ListFormat("en", { type: "disjunction" });
console.log(formatter.format(["red", "green", "blue"]));
// "red, green, or blue"

El tipo "unit" formatea listas de medidas o cantidades sin una conjunción.

const formatter = new Intl.ListFormat("en", { type: "unit" });
console.log(formatter.format(["5 pounds", "12 ounces"]));
// "5 pounds, 12 ounces"

El tipo unit utiliza una puntuación mínima apropiada para datos técnicos o de medición.

Comprendiendo las opciones de estilo

La opción style controla la longitud y formalidad de la salida formateada. Acepta tres valores.

El estilo "long" utiliza palabras completas y puntuación estándar. Este es el predeterminado.

const formatter = new Intl.ListFormat("en", { style: "long" });
console.log(formatter.format(["Alice", "Bob", "Carol"]));
// "Alice, Bob, and Carol"

El estilo "short" utiliza formas abreviadas cuando están disponibles.

const formatter = new Intl.ListFormat("en", { style: "short" });
console.log(formatter.format(["Alice", "Bob", "Carol"]));
// "Alice, Bob, & Carol"

El estilo "narrow" utiliza la forma más compacta posible.

const formatter = new Intl.ListFormat("en", { style: "narrow" });
console.log(formatter.format(["Alice", "Bob", "Carol"]));
// "Alice, Bob, Carol"

El estilo narrow a menudo omite completamente la conjunción. La salida exacta depende del locale.

Cómo los diferentes locales formatean listas

Cada locale tiene sus propias reglas para el formato de listas. El formateador aplica estas reglas automáticamente.

El inglés usa comas e incluye la coma Oxford antes de "and".

const formatter = new Intl.ListFormat("en");
console.log(formatter.format(["coffee", "tea", "juice"]));
// "coffee, tea, and juice"

El español usa comas y la conjunción "y".

const formatter = new Intl.ListFormat("es");
console.log(formatter.format(["café", "té", "jugo"]));
// "café, té y jugo"

El francés usa comas y la conjunción "et".

const formatter = new Intl.ListFormat("fr");
console.log(formatter.format(["café", "thé", "jus"]));
// "café, thé et jus"

El chino usa el carácter 和 para "y" y la coma de enumeración 、 como separador.

const formatter = new Intl.ListFormat("zh");
console.log(formatter.format(["咖啡", "茶", "可乐"]));
// "咖啡、茶和可乐"

El alemán usa comas y la conjunción "und".

const formatter = new Intl.ListFormat("de");
console.log(formatter.format(["Kaffee", "Tee", "Saft"]));
// "Kaffee, Tee und Saft"

El formateador maneja estas diferencias sin requerir que conozcas las reglas para cada idioma.

Obtener partes individuales con formatToParts

El método formatToParts() devuelve un array de objetos que representan cada parte de la lista formateada. Esto es útil cuando necesitas aplicar estilos diferentes a distintas partes.

const formatter = new Intl.ListFormat("en");
const parts = formatter.formatToParts(["red", "green", "blue"]);
console.log(parts);

La salida es un array de objetos con propiedades type y value.

[
  { type: "element", value: "red" },
  { type: "literal", value: ", " },
  { type: "element", value: "green" },
  { type: "literal", value: ", and " },
  { type: "element", value: "blue" }
]

Cada elemento de la lista tiene el tipo "element". Los separadores y conjunciones tienen el tipo "literal". Puedes usar esto para aplicar estilos personalizados.

const formatter = new Intl.ListFormat("en");
const parts = formatter.formatToParts(["red", "green", "blue"]);

const html = parts
  .map((part) => {
    if (part.type === "element") {
      return `<strong>${part.value}</strong>`;
    }
    return part.value;
  })
  .join("");

console.log(html);
// "<strong>red</strong>, <strong>green</strong>, and <strong>blue</strong>"

Este enfoque te da un control preciso sobre el formato mientras mantiene separadores y conjunciones apropiados para cada locale.

Compatibilidad con navegadores

La API Intl.ListFormat está disponible en todos los navegadores modernos. Es compatible desde abril de 2021 en los principales navegadores, incluyendo Chrome, Firefox, Safari y Edge.

Puedes verificar si la API está disponible antes de usarla.

if (typeof Intl.ListFormat !== "undefined") {
  const formatter = new Intl.ListFormat("en");
  console.log(formatter.format(["a", "b", "c"]));
} else {
  console.log("Intl.ListFormat is not supported");
}

Para navegadores más antiguos, necesitas proporcionar una alternativa o usar un polyfill. La alternativa puede usar el método simple join().

function formatList(items, locale) {
  if (typeof Intl.ListFormat !== "undefined") {
    const formatter = new Intl.ListFormat(locale);
    return formatter.format(items);
  }
  return items.join(", ");
}

console.log(formatList(["red", "green", "blue"], "en"));
// "red, green, and blue" (o "red, green, blue" en navegadores más antiguos)

Esto asegura que tu código funcione incluso en navegadores sin soporte para Intl.ListFormat.