¿Cómo formateo arrays con separadores específicos de la configuración regional en JavaScript?

Usa Intl.ListFormat para aplicar automáticamente las comas, espacios y puntuación correctos para cualquier idioma.

Introducción

Cuando conviertes un array en una cadena legible, necesitas separar los elementos con comas u otra puntuación. Diferentes idiomas usan diferentes separadores. El inglés usa comas y espacios, el japonés usa la coma de enumeración 、, y el árabe usa diferente puntuación y orden de palabras.

La API Intl.ListFormat convierte arrays en cadenas con separadores apropiados para la configuración regional. Esto garantiza que tus listas se vean naturales para los usuarios en cada idioma.

Por qué los separadores de arrays difieren según la configuración regional

Podrías asumir que todos los idiomas usan comas para separar elementos de lista. Esto no es cierto.

El inglés separa elementos con una coma y un espacio.

// English: "red, green, blue"

El japonés usa la coma de enumeración 、 sin espacios.

// Japanese: "赤、緑、青"

El chino usa el mismo carácter de coma de enumeración 、.

// Chinese: "红、绿、蓝"

El árabe usa un carácter de coma diferente، y se lee de derecha a izquierda.

// Arabic: "أحمر، أخضر، أزرق"

Estas diferencias son automáticas en Intl.ListFormat. No necesitas conocer las reglas de puntuación para cada idioma.

El problema con join()

El método Array.prototype.join() convierte arrays en cadenas usando un separador que especificas.

const colors = ["red", "green", "blue"];
console.log(colors.join(", "));
// "red, green, blue"

Esto codifica de forma fija la puntuación del inglés. El separador de coma y espacio no funciona para otros idiomas.

const colors = ["赤", "緑", "青"];
console.log(colors.join(", "));
// "赤, 緑, 青" (wrong - should use 、 instead of ,)

No puedes cambiar manualmente los separadores según la configuración regional porque necesitarías mantener un mapeo de cada idioma a sus reglas de puntuación. Este mapeo sería incompleto y difícil de mantener.

Usar Intl.ListFormat para separadores conscientes de la configuración regional

El constructor Intl.ListFormat crea un formateador que aplica los separadores correctos para cualquier configuración regional.

const formatter = new Intl.ListFormat("en");
const colors = ["red", "green", "blue"];
console.log(formatter.format(colors));
// "red, green, and blue"

El formateador utiliza automáticamente la puntuación correcta para la configuración regional especificada. Se pasa el código de configuración regional como primer argumento.

const enFormatter = new Intl.ListFormat("en");
const jaFormatter = new Intl.ListFormat("ja");
const arFormatter = new Intl.ListFormat("ar");

const colors = ["red", "green", "blue"];

console.log(enFormatter.format(colors));
// "red, green, and blue"

console.log(jaFormatter.format(["赤", "緑", "青"]));
// "赤、緑、青"

console.log(arFormatter.format(["أحمر", "أخضر", "أزرق"]));
// "أحمر، أخضر، أزرق"

El navegador proporciona las reglas de puntuación. No es necesario mantener ningún código específico de configuración regional.

Cómo cambian los separadores entre idiomas

El formateador aplica diferentes separadores según la configuración regional. Estos ejemplos muestran cómo el mismo array se formatea de manera diferente.

El inglés utiliza una coma, un espacio y la palabra "and".

const formatter = new Intl.ListFormat("en");
console.log(formatter.format(["apple", "orange", "banana"]));
// "apple, orange, and banana"

El español utiliza una coma, un espacio y la palabra "y".

const formatter = new Intl.ListFormat("es");
console.log(formatter.format(["manzana", "naranja", "plátano"]));
// "manzana, naranja y plátano"

El francés utiliza una coma, un espacio y la palabra "et".

const formatter = new Intl.ListFormat("fr");
console.log(formatter.format(["pomme", "orange", "banane"]));
// "pomme, orange et banane"

El alemán utiliza una coma, un espacio y la palabra "und".

const formatter = new Intl.ListFormat("de");
console.log(formatter.format(["Apfel", "Orange", "Banane"]));
// "Apfel, Orange und Banane"

El japonés utiliza la coma de enumeración 、 y el carácter 、.

const formatter = new Intl.ListFormat("ja");
console.log(formatter.format(["りんご", "オレンジ", "バナナ"]));
// "りんご、オレンジ、バナナ"

El chino utiliza la coma de enumeración 、 y la palabra 和.

const formatter = new Intl.ListFormat("zh");
console.log(formatter.format(["苹果", "橙子", "香蕉"]));
// "苹果、橙子和香蕉"

El coreano utiliza una coma y la partícula 및.

const formatter = new Intl.ListFormat("ko");
console.log(formatter.format(["사과", "오렌지", "바나나"]));
// "사과, 오렌지 및 바나나"

El formateador gestiona todas estas diferencias automáticamente. Se escribe el mismo código para todos los idiomas.

Uso de la configuración regional del usuario

Se puede detectar la configuración regional preferida del usuario desde la configuración de su navegador y utilizarla para formatear listas.

const userLocale = navigator.language;
const formatter = new Intl.ListFormat(userLocale);
const items = ["first", "second", "third"];
console.log(formatter.format(items));

Esto garantiza que la lista utilice separadores que coincidan con las expectativas del usuario. Un usuario con configuración de navegador en francés verá puntuación francesa. Un usuario con configuración en japonés verá puntuación japonesa.

Formatear arrays sin conjunciones

El comportamiento predeterminado de Intl.ListFormat añade una conjunción como "y" antes del último elemento. Puedes desactivar esto usando el tipo unit.

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

El tipo unit usa solo separadores sin añadir palabras de conexión. Esto es útil para listas técnicas, mediciones o datos donde las conjunciones no son apropiadas.

const enFormatter = new Intl.ListFormat("en", { type: "unit" });
const jaFormatter = new Intl.ListFormat("ja", { type: "unit" });

console.log(enFormatter.format(["Item A", "Item B", "Item C"]));
// "Item A, Item B, Item C"

console.log(jaFormatter.format(["項目A", "項目B", "項目C"]));
// "項目A、項目B、項目C"

Incluso sin conjunciones, la puntuación de separación sigue las reglas de la configuración regional.

Crear formateadores reutilizables

Puedes crear un formateador una vez y reutilizarlo para múltiples arrays. Esto es más eficiente que crear un nuevo formateador para cada array.

const formatter = new Intl.ListFormat("en");

console.log(formatter.format(["red", "green"]));
// "red and green"

console.log(formatter.format(["a", "b", "c", "d"]));
// "a, b, c, and d"

console.log(formatter.format(["one"]));
// "one"

El mismo formateador funciona para arrays de cualquier longitud. Aplica los separadores y conjunciones correctos según cuántos elementos haya en el array.

Manejar arrays vacíos

Cuando formateas un array vacío, el formateador devuelve una cadena vacía.

const formatter = new Intl.ListFormat("en");
console.log(formatter.format([]));
// ""

Debes verificar si hay arrays vacíos antes de formatear si necesitas un comportamiento diferente.

function formatList(items, locale) {
  if (items.length === 0) {
    return "No items";
  }
  const formatter = new Intl.ListFormat(locale);
  return formatter.format(items);
}

console.log(formatList([], "en"));
// "No items"

console.log(formatList(["apple"], "en"));
// "apple"

Esto te da control sobre cómo aparecen los arrays vacíos a los usuarios.

Compatibilidad con navegadores

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

Puedes verificar si la API existe 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, puedes recurrir al método join(). Esto proporciona formato básico sin separadores específicos de la configuración regional.

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 garantiza que tu código funcione en todos los navegadores mientras proporciona la mejor experiencia en los modernos.