Локализация через Intl API обычно кажется безобидной, пока не сталкиваешься с расхождениями между сервером и клиентом. В production на SSR React, Next.js или Remix race condition по локали между серверным рендерингом и гидратацией — частая причина трудновоспроизводимых багов, особенно в приложениях с мультиязычностью и SEO.
Race condition по локали
Сервер получает локаль из хедера Accept-Language, а клиент — из navigator.language. Если на сервере сформировали
Intl.ListFormat('de').format(['a', 'b', 'c']) (немецкий "a, b und c"), а гидратация пошла с английским "a, b, and c", React выдаёт warning о несовпадении. Фиксируй локаль глобально до гидратации, например через Intl.DateTimeFormat.supportedLocalesOf и ручной выбор.Локаль по умолчанию — ловушка
new Intl.DateTimeFormat() в Node.js без аргументов использует en-US. На клиенте с русской локалью браузер выдаёт DD.MM.YYYY. Разница в форматировании — гарантированный hydration mismatch. Всегда передавай локаль явно: new Intl.DateTimeFormat('ru-RU'). Иначе Типичная ошибка: мокинг только одного API
В тестах часто мокают только
DateTimeFormat, забывая ListFormat. Это приводит к тому, что список "1, 2, 3" сервер превратит в "1, 2 und 3", а клиент — в "1, 2, and 3". Мокай оба API сразу через jest.mock('intl', () => ({ ... })) или вообще выноси локализацию в отдельный слой, который заменяется целиком.Практический совет: кешируй инстансы
Каждый
new Intl.DateTimeFormat('ru') создаёт объект с внутренним состоянием. На SSR с сотнями запросов GC не успевает, появляются лаги. Используй кеш: const cache = new Map(); cache.get(locale) || cache.set(locale, new Intl.DateTimeFormat(locale)).get(locale). Это снижает нагрузку на память и ускоряет рендеринг.Предупреждение: порядок слов ломает гидратацию
Intl.ListFormat('ja').format(['x', 'y', 'z']) даёт японский формат с иероглифом-разделителем. Сравнивать строки на сервере и клиенте без учёта локали — сразу mismatch. Проверяй, что локаль одинакова, иначе hydration failed.Вывод: Явная локализация, кеширование инстансов и одновременный мокинг Intl.ListFormat и Intl.DateTimeFormat — ключевые практики для надёжной локализации в SSR и тестах.