¿Cómo formateo 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 usa puntuación completamente diferente.

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

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, usa puntuación inglesa 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 españoles 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.

Usar Intl.ListFormat para formatear listas

El constructor Intl.ListFormat crea un formateador que convierte arrays en cadenas de lista apropiadas para el idioma.

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

El formateador usa los separadores y la conjunción correctos para el idioma especificado. Pasas el idioma 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 idioma.

Formatear listas con "y"

El comportamiento predeterminado de Intl.ListFormat usa la conjunción "and" o su equivalente en otros idiomas. Esto se llama formato 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 usan "y". Este es el valor predeterminado, por lo que puedes omitirlo.

Comprender las opciones de tipo de lista

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

El tipo "conjunction" usa "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" usa "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 usa puntuación mínima apropiada para datos técnicos o de medición.

Comprender las opciones de estilo

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

El estilo "long" usa 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" usa 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" usa 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 la conjunción por completo. La salida exacta depende de la configuración regional.

Cómo diferentes configuraciones regionales formatean listas

Cada configuración regional 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 de 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 a diferentes partes por separado.

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

La salida es un array de objetos con las 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 mantienes separadores y conjunciones apropiados para cada configuración regional.

Compatibilidad con navegadores

La API Intl.ListFormat está disponible en todos los navegadores modernos. Ha sido 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" (or "red, green, blue" in older browsers)

Esto asegura que tu código funcione incluso en navegadores sin compatibilidad con Intl.ListFormat.