Функция Intl.Collator в JavaScript предоставляет стандартный механизм сортировки строк с учетом локали. Однако по умолчанию она использует базовые правила Unicode, которые часто не соответствуют ожиданиям пользователей на конкретных языках (например, русские буквы «ё» и «е», пробелы после знаков препинания). Для корректной работы необходимо явно указывать регион (locale) и настраивать чувствительность к регистру. Без этих настроек сортировка будет работать по латинскому алфавиту или игнорировать специфические символы, что приведет к ошибкам в списках товаров, контактах и результатах поиска.

Как работает Intl.Collator и почему локализация требует настройки

Объект Intl.Collator создает объект, который определяет порядок сортировки строк. Он принимает два основных аргумента: код региона (locale) и объект опций.

Если не указать locale или использовать пустую строку, функция использует базовые правила Unicode. Это означает, что символы будут сортироваться по их кодовым точкам в таблице Unicode. Для русского языка это часто приводит к тому, что «ё» стоит после всех букв «е», а пробелы могут обрабатываться не так, как ожидается пользователем.

Указание locale (например, 'ru-RU') активирует правила конкретного региона. Это включает в себя специфические правила сортировки, такие как игнорирование пробелов после знаков препинания или правильное позиционирование букв с диакритическими знаками.

Важно понимать, что Intl.Collator не заменяет собой логику бизнес-правилов. Он отвечает только за лексикографический порядок символов согласно правилам выбранного региона.

Шаг 1: Определение региона (locale) для сортировки

Первым шагом является выбор правильного кода региона. Для русского языка стандартным выбором является 'ru-RU'. Этот код указывает на использование правил Российской Федерации.

Можно также использовать 'ru' без суффикса страны, но 'ru-RU' предпочтительнее для строгого соответствия стандартам.

Пример создания объекта сортировки:

const collator = new Intl.Collator('ru-RU', { sensitivity: 'base' });

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

Проверка работы:

const names = ['Иванов', 'Петров', 'Сидоров'];

names.sort((a, b) => collator.compare(a, b));

Результатом будет правильный порядок: Иванов, Петров, Сидоров. Если бы мы использовали английский регион ('en-US'), то символы «И», «П», «С» могли бы быть отсортированы иначе в зависимости от версии библиотеки или реализации Unicode.

Шаг 2: Настройка чувствительности к регистру и акцентам

Опция sensitivity определяет, учитывает ли сортировка регистр букв (верхний/нижний) и диакритические знаки.

Значение 'base' игнорирует регистр и диакритические знаки. Это полезно для поиска или сортировки, где «Иванов» и «иванов» должны стоять рядом, а «Иванов» с «ё» — рядом с «Иванов» без «ё».

Значение 'accent' учитывает диакритические знаки, но игнорирует регистр. Это важно для языков, где «е» и «ё» считаются разными буквами (например, в русском языке «ё» часто стоит после «е» или отдельно).

Значение 'case' учитывает регистр, но игнорирует диакритические знаки.

Значение 'variant' учитывает все различия, включая регистр и диакритические знаки. Это наиболее строгий режим.

Для большинства задач с именами на русском языке рекомендуется использовать 'base', если нужно объединить «е» и «ё», или 'accent', если важно разделять их.

Пример:

const collatorBase = new Intl.Collator('ru-RU', { sensitivity: 'base' });

const namesMixed = ['Иванов', 'иванов', 'ИВАНОВ'];

namesMixed.sort((a, b) => collatorBase.compare(a, b)); // Все варианты будут отсортированы вместе

const collatorAccent = new Intl.Collator('ru-RU', { sensitivity: 'accent' });

const namesWithYo = ['Иванов', 'Иванёв'];

namesWithYo.sort((a, b) => collatorAccent.compare(a, b)); // «Иванёв» будет после «Иванов»

Шаг 3: Обработка специфических правил сортировки (например, «ё» или пробелы)

В русском языке буква «ё» исторически и в некоторых стандартах считается отдельной буквой, которая должна стоять после всех букв «е», но перед другими буквами.

Стандартные правила Unicode для 'ru-RU' обычно соблюдают это требование. Однако при работе с пользовательским контентом важно убедиться, что сортировка работает корректно.

Пробелы после знаков препинания: в некоторых локализованных правилах пробелы после точек или запятых игнорируются при сравнении. Это позволяет сортировать «Иванов.» и «Иванов» как равные или с учетом только текста без пробела.

Если требуется строгое соблюдение всех символов, включая пробелы, можно использовать режим 'variant' или не указывать опцию sensitivity (что использует настройки по умолчанию для региона).

Пример:

const namesWithPunctuation = ['Иванов.', 'Иванов', 'Иванов,'];

const collatorStrict = new Intl.Collator('ru-RU', { sensitivity: 'variant' });

namesWithPunctuation.sort((a, b) => collatorStrict.compare(a, b)); // Сортировка будет учитывать знаки препинания и пробелы

Шаг 4: Интеграция с формами ввода и валидацией

При работе с формами ввода (например, поиск по базе клиентов) сортировка должна применяться к результатам поиска, а не к данным формы напрямую.

Валидация данных в форме не зависит от Intl.Collator, но сортировка результатов поиска должна использовать настроенный объект collator.

Пример реализации поиска и сортировки:

const searchInput = document.getElementById('search-input');

const resultsContainer = document.getElementById('results-container');

const collator = new Intl.Collator('ru-RU', { sensitivity: 'base' });

function filterAndSortNames(names, query) {

const filtered = names.filter(name => name.toLowerCase().includes(query));

return filtered.sort((a, b) => collator.compare(a, b));

}

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

Важно: не сортируйте данные на сервере перед отправкой. Сортировку выполняйте на стороне клиента после фильтрации, используя Intl.Collator.

Шаг 5: Оптимизация производительности при работе с большими массивами

Intl.Collator не требует создания нового объекта для каждой сортировки. Объект можно создать один раз и использовать многократно.

Для больших массивов данных (например, тысячи имен) создание одного объекта collator значительно ускоряет процесс.

Пример:

const collator = new Intl.Collator('ru-RU', { sensitivity: 'base' });

const largeArray = […]; // Массив из 10 000+ элементов

largeArray.sort((a, b) => collator.compare(a, b));

Избегайте создания нового объекта collator внутри цикла или функции, если он не меняется.

Если сортировка выполняется в реальном времени (например, при вводе текста), используйте debounce для отложенного вызова сортировки, чтобы избежать лишних вычислений.

Шаг 6: Обработка ошибок и невалидных аргументов Intl.Collator

Intl.Collator может抛出 ошибку, если указан неверный код региона (например, 'ru-XX', где XX — несуществующая страна).

Всегда проверяйте корректность кода региона перед созданием объекта.

Пример обработки ошибок:

try {

const collator = new Intl.Collator('ru-RU');

} catch (e) {

console.error('Неверный код региона:', e.message);

// Фоллбэк на базовую сортировку или другой регион

}

Шаг 7: Адаптация под мобильные устройства и разные браузеры

Intl.Collator поддерживается всеми современными браузерами, включая мобильные (Chrome, Safari, Firefox).

На старых версиях Internet Explorer эта функция отсутствует. Для таких случаев необходимо использовать полифиллы или библиотеки типа polyfill-intl-localematcher.

В современных проектах (React, Vue, Angular) Intl.Collator работает стабильно на всех мобильных устройствах.

Если проект поддерживает старые браузеры, добавьте проверку перед использованием:

if ('Intl' in window && 'Collator' in Intl) {

// Использовать Intl.Collator

} else {

// Использовать fallback-сортировку (например, String.prototype.localeCompare)

}

Шаг 8: Тестирование на реальных данных пользователя

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

Используйте тестовые данные, включающие имена с «ё», разные регистры, знаки препинания и пробелы.

Пример тестового набора:

const testNames = ['Иванов', 'Иванёв', 'иванов', 'ИВАНОВ', 'Петров.', 'Сидоров,'];

const collator = new Intl.Collator('ru-RU', { sensitivity: 'base' });

testNames.sort((a, b) => collator.compare(a, b));

Проверьте результат вручную и убедитесь, что он соответствует ожиданиям пользователей.

Если сортировка не работает как ожидается, проверьте код региона и настройки sensitivity.

Вопросы и ответы

Можно ли использовать Intl.Collator для других языков?

Да, Intl.Collator поддерживает множество регионов (например, 'en-US', 'de-DE', 'fr-FR'). Просто измените код региона в конструкторе.

Как отсортировать массив без создания объекта collator?

Можно использовать метод String.prototype.localeCompare с указанием locale: array.sort((a, b) => a.localeCompare(b, 'ru-RU', { sensitivity: 'base' }));. Однако создание объекта collator предпочтительнее для производительности.

Что делать, если Intl.Collator не поддерживается браузером?

Используйте полифиллы или библиотеки типа polyfill-intl-localematcher. Также можно использовать fallback-сортировку через String.prototype.localeCompare.

const collator = new Intl.Collator('ru-RU', { sensitivity: 'base' });

const names = ['Иванов', 'Петров', 'Сидоров'];
names.sort((a, b) => collator.compare(a, b));