Форматирование массивов элементов

В международных интерфейсах массивы элементов почти никогда не отображаются через фиксированные разделители вроде запятой. Разные языки используют собственные правила перечисления: различаются союзы, порядок знаков препинания, наличие серийной запятой и даже формы соединительных слов в зависимости от длины списка.

Библиотека Globalize опирается на данные CLDR (Unicode Common Locale Data Repository), где для каждой локали определены шаблоны форматирования списков. Эти шаблоны описывают, как должны соединяться элементы массива в текстовую строку.

Ключевая задача форматирования списков:

  • корректное соединение элементов массива;
  • учёт локальных правил пунктуации;
  • поддержка списков разной длины;
  • автоматический выбор шаблона по количеству элементов.

Модель представления списков в CLDR

CLDR различает несколько типов списков:

  • standard — обычные перечисления;
  • or — альтернативы;
  • unit — единицы измерения и составные выражения.

Каждый тип списка имеет собственные правила соединения элементов.

Пример логики:

  • 2 элемента → специальный шаблон для пары
  • 3+ элементов → шаблон с последовательным объединением

Подготовка Globalize для работы со списками

Globalize требует загрузки CLDR-данных, включая раздел listPatterns.

import Globalize from "globalize";

// предполагается, что CLDR данные уже загружены:
// cldr/supplemental/listPatterns.json
// cldr/main/{locale}/listPatterns.json

Globalize.locale("en");

Без данных listPatterns форматирование списков работать не будет, так как библиотека не содержит встроенных локализаций.


Базовое форматирование массива

Для преобразования массива в строку используется метод:

Globalize.formatList(array, options);

Пример:

const g = Globalize("en");

g.formatList(["apples", "bananas", "oranges"]);

Результат:

apples, bananas, and oranges

Для локали с другими правилами результат будет отличаться.


Поведение в разных локалях

Английская локаль

Globalize.locale("en");

Globalize.formatList(["A", "B", "C"]);

Результат:

A, B, and C

Используется серийная запятая (Oxford comma).


Немецкая локаль

Globalize.locale("de");

Globalize.formatList(["A", "B", "C"]);

Результат:

A, B und C

Особенность: отсутствие запятой перед союзом.


Французская локаль

Globalize.locale("fr");

Globalize.formatList(["A", "B", "C"]);

Результат:

A, B et C

Типы списков и их различия

Standard list

Используется для обычных перечислений.

g.formatList(["HTML", "CSS", "JavaScript"], { type: "standard" });

OR list

Используется для альтернативных вариантов.

g.formatList(["light", "dark"], { type: "or" });

Результат может выглядеть как:

light or dark

В других локалях:

light ou dark
light oder dark

Unit list

Используется для комбинирования единиц измерения.

g.formatList(["10 kg", "200 g"], { type: "unit" });

Этот тип часто исключает союзы и использует более компактное соединение.


Внутренние правила формирования строки

CLDR описывает список через набор шаблонов:

  • pair — для двух элементов;
  • start — начало списка;
  • middle — промежуточные элементы;
  • end — завершение списка.

Пример структуры:

{0}, {1}
{0}, {1}
{0}, and {1}

Globalize выбирает шаблон в зависимости от длины массива.


Работа с массивами разной длины

Один элемент

Globalize.formatList(["A"]);

Результат:

A

Шаблоны не применяются.


Два элемента

Globalize.formatList(["A", "B"]);

Используется шаблон pair:

A and B

Три и более элементов

Globalize.formatList(["A", "B", "C", "D"]);

Результат:

A, B, C, and D

Настройка поведения через параметры

Метод formatList принимает опции:

Globalize.formatList(array, {
  type: "standard"
});

Основные параметры:

  • type — тип списка (standard, or, unit)

Использование с динамическими данными

Форматирование списков часто применяется к результатам API или пользовательским данным.

const users = ["Anna", "Ivan", "Sara", "John"];

Globalize.formatList(users);

При изменении локали формат автоматически адаптируется:

Globalize.locale("ru");

Globalize.formatList(users);

Результат:

Anna, Ivan, Sara и John

Вложенные структуры и преобразования

Перед форматированием часто требуется нормализация данных:

const items = response.data.map(item => item.title);

Globalize.formatList(items);

Если элементы содержат сложные строки, Globalize не изменяет их содержимое, а только соединяет.


Поведение при пустых и некорректных значениях

Пустой массив

Globalize.formatList([]);

Результат:

""

Массив с null/undefined

Globalize.formatList(["A", null, "C"]);

Поведение зависит от предварительной очистки данных; Globalize не фильтрует значения автоматически.


Производительность форматирования

Форматирование списков опирается на заранее загруженные CLDR-шаблоны. Это означает:

  • отсутствует динамическое вычисление правил;
  • операции сводятся к подстановке строк;
  • производительность стабильна даже при больших объёмах вызовов.

При частом использовании рекомендуется:

  • кешировать экземпляр Globalize;
  • избегать повторной загрузки CLDR;
  • минимизировать создание новых массивов на горячих участках кода.

Интеграция с другими форматами Globalize

Форматирование списков часто комбинируется с другими возможностями:

Форматирование дат

const dates = [
  Globalize.formatDate(new Date(2024, 0, 1)),
  Globalize.formatDate(new Date(2024, 0, 2))
];

Globalize.formatList(dates);

Форматирование чисел

const numbers = [
  Globalize.formatNumber(1000),
  Globalize.formatNumber(2000)
];

Globalize.formatList(numbers);

Влияние локали на структуру списка

Локаль влияет не только на союзы, но и на:

  • наличие запятых;
  • порядок слов;
  • пробелы вокруг разделителей;
  • использование специальных символов.

Например, в некоторых азиатских локалях список может быть оформлен без союзов вообще.


Особенности использования в UI-компонентах

При работе с интерфейсами форматирование списков применяется для:

  • отображения выбранных фильтров;
  • вывода тегов;
  • формирования строк описаний;
  • генерации человекочитаемых списков событий.

Типичный пример:

const filters = ["React", "TypeScript", "GraphQL"];

label.textContent = Globalize.formatList(filters);

Ограничения механизма

  • отсутствие встроенной очистки данных;
  • зависимость от корректно загруженных CLDR ресурсов;
  • невозможность кастомизации шаблонов без изменения данных локали;
  • фиксированная модель типов списков.

Поведение при смене локали в рантайме

const g = Globalize("en");

g.formatList(["A", "B"]);

Globalize.locale("ja");

g.formatList(["A", "B"]);

Результат изменится автоматически в зависимости от активной локали, если экземпляр Globalize использует глобальный locale state.