How do I format arrays with locale-specific separators in JavaScript?
Use Intl.ListFormat to automatically apply the correct commas, spaces, and punctuation for any language.
Introduction
When you convert an array into a readable string, you need to separate the items with commas or other punctuation. Different languages use different separators. English uses commas and spaces, Japanese uses the enumeration comma 、, and Arabic uses different punctuation and word order.
The Intl.ListFormat API converts arrays into strings with locale-appropriate separators. This ensures your lists look natural to users in every language.
Why array separators differ by locale
You might assume all languages use commas to separate list items. This is not true.
English separates items with a comma and space.
// English: "red, green, blue"
Japanese uses the enumeration comma 、 with no spaces.
// Japanese: "赤、緑、青"
Chinese uses the same enumeration comma 、 character.
// Chinese: "红、绿、蓝"
Arabic uses a different comma character، and reads right to left.
// Arabic: "أحمر، أخضر، أزرق"
These differences are automatic in Intl.ListFormat. You do not need to know the punctuation rules for each language.
The problem with join()
The Array.prototype.join() method converts arrays to strings using a separator you specify.
const colors = ["red", "green", "blue"];
console.log(colors.join(", "));
// "red, green, blue"
This hardcodes English punctuation. The comma and space separator does not work for other languages.
const colors = ["赤", "緑", "青"];
console.log(colors.join(", "));
// "赤, 緑, 青" (wrong - should use 、 instead of ,)
You cannot manually switch separators based on locale because you would need to maintain a mapping of every language to its punctuation rules. This mapping would be incomplete and hard to maintain.
Using Intl.ListFormat for locale-aware separators
The Intl.ListFormat constructor creates a formatter that applies the correct separators for any locale.
const formatter = new Intl.ListFormat("en");
const colors = ["red", "green", "blue"];
console.log(formatter.format(colors));
// "red, green, and blue"
The formatter automatically uses the right punctuation for the specified locale. You pass the locale code as the first argument.
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(["أحمر", "أخضر", "أزرق"]));
// "أحمر، أخضر، أزرق"
The browser provides the punctuation rules. You do not maintain any locale-specific code.
How separators change across languages
The formatter applies different separators based on the locale. These examples show how the same array formats differently.
English uses a comma, space, and the word "and".
const formatter = new Intl.ListFormat("en");
console.log(formatter.format(["apple", "orange", "banana"]));
// "apple, orange, and banana"
Spanish uses a comma, space, and the word "y".
const formatter = new Intl.ListFormat("es");
console.log(formatter.format(["manzana", "naranja", "plátano"]));
// "manzana, naranja y plátano"
French uses a comma, space, and the word "et".
const formatter = new Intl.ListFormat("fr");
console.log(formatter.format(["pomme", "orange", "banane"]));
// "pomme, orange et banane"
German uses a comma, space, and the word "und".
const formatter = new Intl.ListFormat("de");
console.log(formatter.format(["Apfel", "Orange", "Banane"]));
// "Apfel, Orange und Banane"
Japanese uses the enumeration comma 、 and the character 、.
const formatter = new Intl.ListFormat("ja");
console.log(formatter.format(["りんご", "オレンジ", "バナナ"]));
// "りんご、オレンジ、バナナ"
Chinese uses the enumeration comma 、 and the word 和.
const formatter = new Intl.ListFormat("zh");
console.log(formatter.format(["苹果", "橙子", "香蕉"]));
// "苹果、橙子和香蕉"
Korean uses a comma and the particle 및.
const formatter = new Intl.ListFormat("ko");
console.log(formatter.format(["사과", "오렌지", "바나나"]));
// "사과, 오렌지 및 바나나"
The formatter handles all these differences automatically. You write the same code for every language.
Using the user's locale
You can detect the user's preferred locale from their browser settings and use it to format lists.
const userLocale = navigator.language;
const formatter = new Intl.ListFormat(userLocale);
const items = ["first", "second", "third"];
console.log(formatter.format(items));
This ensures the list uses separators that match the user's expectations. A user with French browser settings sees French punctuation. A user with Japanese settings sees Japanese punctuation.
Formatting arrays without conjunctions
The default Intl.ListFormat behavior adds a conjunction like "and" before the last item. You can disable this by using the unit type.
const formatter = new Intl.ListFormat("en", { type: "unit" });
console.log(formatter.format(["5 km", "12 minutes", "100 calories"]));
// "5 km, 12 minutes, 100 calories"
The unit type uses only separators without adding connecting words. This is useful for technical lists, measurements, or data where conjunctions are not appropriate.
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"
Even without conjunctions, the separator punctuation still follows locale rules.
Creating reusable formatters
You can create a formatter once and reuse it for multiple arrays. This is more efficient than creating a new formatter for each 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"
The same formatter works for arrays of any length. It applies the correct separators and conjunctions based on how many items are in the array.
Handling empty arrays
When you format an empty array, the formatter returns an empty string.
const formatter = new Intl.ListFormat("en");
console.log(formatter.format([]));
// ""
You should check for empty arrays before formatting if you need different behavior.
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"
This gives you control over how empty arrays appear to users.
Browser support
The Intl.ListFormat API is available in all modern browsers. It has been supported since April 2021 across Chrome, Firefox, Safari, and Edge.
You can check if the API exists before using it.
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");
}
For older browsers, you can fall back to the join() method. This provides basic formatting without locale-specific separators.
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)
This ensures your code works across all browsers while providing the best experience in modern ones.