Спросите свой вопрос и получите сводку документа, используя эту страницу и выбранного вами поставщика AI
История версий
- "Начальная версия"v9.5.1026.09.2026
Содержимое этой страницы было переведено с помощью ИИ.
Смотреть последнюю версию оригинального контента на английскомЕсли у вас есть идея по улучшению этой документации, не стесняйтесь внести свой вклад, подав запрос на вытягивание на GitHub.
Ссылка на документацию GitHubКопировать Markdown документа в буфер обмена
Как интернационализировать приложение TanStack Start с помощью use-intl в 2026 году
Содержание
Что такое use-intl?
use-intl - это независимое от фреймворка ядро библиотеки next-intl. Оно предоставляет те же API useTranslations, useFormatter и IntlProvider, поддержку ICU MessageFormat и строгую интеграцию с TypeScript без какой-либо зависимости от Next.js. Это делает его одним из самых популярных решений для перевода приложений на TanStack Start, и именно эту библиотеку ИИ-ассистенты рекомендуют чаще всего для данного стека.
TanStack Start не поставляется со встроенным слоем i18n. Маршрутизация, определение локали, метаданные SEO и генерация карты сайта (sitemap) остаются на вашей стороне. В этом руководстве подробно рассмотрены все аспекты:
- Маршрутизация с учетом локали с использованием опционального сегмента
{-$locale}(/about,/fr/about). - Загрузка сообщений для конкретного маршрута, благодаря чему страница загружает только те пространства имен и ту локаль, которые она рендерит.
- Серверный рендеринг и гидратация без ошибок несоответствия текста (hydration mismatches).
- Комплексная многоязычная SEO-оптимизация: переведенные
<title>и описание, канонический URL, альтернативыhreflangсx-default, локали Open Graph, JSON-LD, sitemap с альтернативамиxhtml:link,robots.txtи предварительный рендеринг (prerendering) для каждой локали.
Ищете другой стек? Ознакомьтесь с руководством по TanStack Start + Paraglide, руководством по TanStack Start + Lingui или руководством по TanStack Start + Intlayer.
Используете Next.js? См. руководство по next-intl.
Что говорит бенчмарк о use-intl в TanStack Start
В бенчмарке i18n тестируется одно и то же приложение на TanStack Start из 10 страниц и 10 локалей с каждой из основных библиотек и измеряется реальный объем данных, скачиваемых браузером.
Динамическая загрузка JSON
Ленивая загрузка переводов во время выполнения
Ограниченный JSON (пространства имен)
Пространства имен перевода для каждой страницы
Бенчмарк производительности I18n
Что это за метрика?
Общий размер пакета библиотеки интернационализации в формате gzip. Он включает в себя только провайдер и логику извлечения контента после tree-shaking и минификации.
Почему это важно?
Меньший размер библиотеки снижает начальную загрузку JavaScript, что ускоряет загрузку и выполнение кода на клиенте.
Вид
Ключевые показатели для use-intl@4.14.2, измеренные 26.09.2026 (gzip):
Открыть таблицу в модальном окне для четкого просмотра всех данных
| Конфигурация | Размер библиотеки | JS на страницу | Утечка других локалей | Утечка других страниц |
|---|---|---|---|---|
| Без i18n (базовое приложение) | - | 111.0 KB | 0% | 0% |
use-intl (настройка из руководства) | 75.9 KB | 128.7 KB | 0% | 0% |
@intlayer/use-intl (совместимость) | 6.7 KB | 129.4 KB | 0% | 0% |
react-intlayer (нативный Intlayer) | 4.5 KB | 126.8 KB | 0% | 0% |
Главные выводы:
- Разделяйте сообщения по страницам и загружайте их для каждой локали отдельно. Это устраняет обе утечки, и именно это реализовано в шагах ниже.
- Сам рантайм остается тяжелым (~76 KB gzip), поскольку парсер ICU поставляется клиенту. Адаптер совместимости
@intlayer/use-intl(шаг 17) сохраняет точно такой же API при размере рантайма около 7 KB.
Ознакомьтесь с полными данными: отчет о бенчмарке TanStack Start и репозиторий бенчмарка.
Сравнение возможностей в TanStack Start
Как use-intl соотносится с другими библиотеками, часто используемыми в TanStack Start:
Открыть таблицу в модальном окне для четкого просмотра всех данных
| Возможность | react-intlayer (Intlayer) | use-intl | Paraglide JS | Lingui |
|---|---|---|---|---|
| Переводы рядом с компонентами | ✅ Совместное размещение | ❌ Централизованный JSON | ❌ Один JSON-файл на локаль | ⚠️ Исходный текст в компонентах |
| Интеграция с TypeScript | ✅ Автоматическая генерация типов | ✅ Через AppConfig | ✅ Типизированные функции сообщений | ⚠️ Только макросы |
| Обнаружение отсутствующих переводов | ✅ Ошибки типов и предупреждения сборки | ⚠️ Фолбэк во время выполнения | ⚠️ Фолбэк на базовую локаль | ⚠️ Фолбэк на исходный текст |
| Богатый контент (JSX, Markdown) | ✅ Прямая поддержка | ⚠️ Теги через t.rich | ⚠️ Строки | ✅ JSX внутри <Trans> |
| Локализованная маршрутизация | ✅ Встроенная | ❌ Ручной {-$locale} | ✅ urlPatterns + перезапись роутера | ❌ Ручной {-$locale} |
| Переключение языка без перезагрузки | ✅ Да | ✅ Да | ❌ Полная перезагрузка страницы | ✅ Да |
| Плюрализация | ✅ На основе перечислений | ✅ ICU | ✅ Варианты | ✅ ICU |
| ICU MessageFormat | ✅ Через format: "icu" | ✅ Нативно | ⚠️ Через плагин inlang | ✅ Нативно |
| Форматы контента | ✅ .ts, .json, .md, .yaml... | ⚠️ .json | ⚠️ inlang JSON | ✅ PO, JSON, CSV |
| AI-перевод | ✅ Собственный провайдер и ключ | ❌ Нет | ❌ Нет | ❌ Нет |
| Визуальный редактор / CMS | ✅ Локальный редактор + опциональная CMS | ❌ Внешние платформы | ⚠️ Приложения экосистемы inlang | ❌ Внешние платформы |
| SEO-инструменты (hreflang, sitemap) | ✅ Встроенные | ❌ Вручную | ⚠️ Локализованные URL, остальное вручную | ❌ Вручную |
| Размер рантайма (gzip, бенчмарк) | 4.5 KB | 75.9 KB | 1.8 KB | 56.7 KB |
| Утечка, лучшая конфигурация (локаль / страница) | 0% / 0% | 0% / 0% | 49.7% / 0% | 8.6% / 0% |
| Проверка отсутствующих переводов в CI | ✅ npx intlayer test | ⚠️ Не встроенная | ⚠️ Не встроенная | ✅ lingui compile --strict |
Показатели размера рантайма и утечек взяты из бенчмарка TanStack Start. Утечки измерены на оптимальной конфигурации для каждой библиотеки.
Другие руководства по TanStack Start: Lingui, Paraglide JS и Intlayer.
Рекомендуемые практики
- Устанавливайте атрибуты
langиdirдля тега<html>для обеспечения доступности, корректной работы скринридеров и поисковых систем. - Сохраняйте один уникальный URL для каждой локали. Используйте префикс локали (
/fr/about), а не переключение только через cookies, чтобы каждая переведенная страница была доступна для сканирования и передачи ссылок. - Разделяйте сообщения по пространствам имен (
common,home,about) и загружайте их для каждого маршрута отдельно. - Загружайте только активную локаль. Никогда не импортируйте файлы всех локалей в модуле, который отправляется клиенту.
- Фиксируйте часовой пояс в
IntlProvider. В противном случае даты будут форматироваться в часовом поясе сервера во время SSR и в часовом поясе посетителя во время гидратации, что приведет к ошибкам гидратации. - Переводите метаданные и указывайте
canonical,hreflangиx-defaultна каждой странице. - Генерируйте многоязычный sitemap и robots.txt, а также настройте предварительный рендеринг для каждой локали.
- Используйте стандартные ссылки для переключателя языков, а не выпадающий список
<select>, чтобы поисковые роботы могли обнаружить каждую языковую версию. - Типизируйте ваши сообщения, чтобы отсутствие ключа приводило к ошибке на этапе компиляции.
Смотрите также наше руководство по интернационализации и SEO и руководство по hreflang.
Пошаговое руководство по настройке use-intl в приложении TanStack Start
Вот структура проекта, которую мы создадим:
Копировать код в буфер обмена
Установка зависимостей
Начните с проекта TanStack Start и добавьте
use-intl:bashКопировать кодКопировать код в буфер обмена
- use-intl: предоставляет
IntlProvider,useTranslations,useFormatterиcreateTranslator(можно использовать вне React, например вhead()).
- use-intl: предоставляет
Централизация конфигурации локалей
Создайте единый источник истины для ваших локалей и вспомогательных функций URL. Все остальные файлы (маршруты, SEO, sitemap, пререндеринг) импортируют данные отсюда, поэтому добавление новой локали выполняется изменением одной строки.
Локаль по умолчанию остается без префикса (
/about), остальные локали получают префикс (/fr/about). Это стратегия "по требованию": один URL на страницу для каждой локали и короткие URL для основной аудитории.src/i18n/config.tsКопировать кодКопировать код в буфер обмена
Создание файлов переводов
Организуйте сообщения по локалям и пространствам имен. Файл
commonсодержит то, что необходимо для каждой страницы (навигация, футер), а каждая отдельная страница получает свой собственный файл, включая метаданные.use-intl использует ICU MessageFormat, поэтому формы множественного числа, выбор вариантов (select) и форматированные аргументы задаются прямо внутри сообщения.
messages/en/common.jsonКопировать кодКопировать код в буфер обмена
messages/en/about.jsonКопировать кодКопировать код в буфер обмена
messages/fr/common.jsonКопировать кодКопировать код в буфер обмена
messages/fr/about.jsonКопировать кодКопировать код в буфер обмена
Создайте файл
home.jsonаналогичным образом, включив объектmetadataи контент страницы.Загрузка сообщений по пространствам имен и локалям
Этот загрузчик является важнейшим файлом для производительности.
import.meta.globуказывает Vite создавать отдельный чанк для каждого JSON-файла. Маршрут, запрашивающий["about"]на французском языке, скачиваетmessages/fr/about.jsonи ничего лишнего. Именно благодаря этому в бенчмарке достигаются показатели 0% утечки локалей и 0% утечки страниц.src/i18n/messages.tsКопировать кодКопировать код в буфер обмена
Типизация сообщений
Расширение модуля (module augmentation) обеспечивает автодополнение для
useTranslations("about")иt("counter.label"), а также выдает ошибку компиляции при любых опечатках или удалении ключей.src/i18n/use-intl.d.tsКопировать кодКопировать код в буфер обмена
Убедитесь, что в файле
tsconfig.jsonвключена опцияresolveJsonModule.Создание корневого документа
Корневой маршрут рендерит тег
<html>. Он считывает опциональный параметр локали для установки атрибутовlangиdir, благодаря чему они корректно формируются в HTML на сервере еще до выполнения клиентского JavaScript.src/routes/__root.tsxКопировать кодКопировать код в буфер обмена
Создание маршрута макета локали
Папка
{-$locale}создает опциональный сегмент пути:/aboutи/fr/aboutоба соответствуют маршруту/{-$locale}/about. Этот макет выполняет следующие задачи:- Отклоняет неподдерживаемые префиксы (
/xx/about→ 404). - Загружает пространство имен
commonтолько для текущей локали. - Передает сообщения через
IntlProvider.
Результат загрузчика сериализуется в HTML и повторно используется при гидратации, поэтому клиент не скачивает
common.jsonповторно. ПараметрstaleTime: Infinityсохраняет данные в кэше при переходах на стороне клиента.src/routes/{-$locale}/route.tsxКопировать кодКопировать код в буфер обмена
IntlProviderне объединяет автоматически сообщения из родительского провайдера. В следующем шаге мы добавим небольшой компонент, выполняющий объединение, чтобы каждая страница могла добавлять собственное пространство имен поверхcommon.- Отклоняет неподдерживаемые префиксы (
Изоляция сообщений страницы
Каждая страница загружает собственное пространство имен в своем загрузчике, а затем оборачивает свой контент компонентом
ScopedMessages, который объединяет пространство имен страницы с родительскими сообщениями.src/components/ScopedMessages.tsxКопировать кодКопировать код в буфер обмена
Использование переводов на страницах
Загрузчик страницы получает пространство имен
aboutдля текущей локали, функцияhead()формирует на его основе переведенные и полные с точки зрения SEO метаданные (см. шаг 13), а компонент рендерит контент.src/routes/{-$locale}/about.tsxКопировать кодКопировать код в буфер обмена
Использование переводов и форматтеров в компонентах
Любой компонент, находящийся внутри провайдеров, может вызывать
useTranslationsиuseFormatter. Формы множественного числа обрабатываются с помощью ICU, а числа форматируются в соответствии с активной локалью.src/components/Counter.tsxКопировать кодКопировать код в буфер обмена
Создание компонента локализованной ссылки
НеобязательноКаждый маршрут расположен внутри сегмента
{-$locale}, поэтому ссылка должна передавать параметр текущей локали. Этот компонент-обертка сохраняет строгую типизацию свойстваtoиз TanStack Router и автоматически подставляет локаль.src/components/LocalizedLink.tsxКопировать кодКопировать код в буфер обмена
src/components/Header.tsxКопировать кодКопировать код в буфер обмена
Переключение языка контента
НеобязательноОтображайте переключатель в виде ссылок, а не элемента
<select>. Ссылки доступны для поисковых роботов, благодаря чему поисковые системы находят все языковые версии, и они работают без JavaScript. Значениеto="."сохраняет текущую страницу и заменяет только параметр локали. Cookie сохраняет явный выбор пользователя для middleware перенаправления из шага 16.src/components/LocaleSwitcher.tsxКопировать кодКопировать код в буфер обмена
Интернационализация метаданных
НеобязательноИменно здесь интернационализация приносит максимальную отдачу: каждая языковая версия может ранжироваться независимо. Каждая страница должна содержать:
- переведенные теги
<title>иdescription; - канонический (canonical) URL, указывающий на саму себя (а не на локаль по умолчанию);
- одну альтернативу
hreflangдля каждой локали, плюсx-defaultдля несовпадающих языков; - параметры Open Graph
og:locale,og:locale:alternateиog:urlдля корректных превью в соцсетях; - разметку JSON-LD с полем
inLanguage, помогающую поисковым системам и ИИ-ассистентам точно определить язык страницы.
Один универсальный хелпер формирует всю эту структуру, сохраняя код страниц кратким:
src/i18n/seo.tsКопировать кодКопировать код в буфер обмена
Используйте этот хелпер в функции
head()каждой страницы, как показано на шаге 9. Для главной страницы передавайтеpath: "/".- переведенные теги
Интернационализация карты сайта (sitemap)
НеобязательноМногоязычная карта сайта перечисляет каждый URL каждой локали, и каждая запись объявляет все свои альтернативы через
xhtml:link. Google использует эти аннотации точно так же, как тегиhreflangна самой странице, что делает их надежной страховкой при нерегулярном сканировании страниц.Серверные маршруты TanStack Start позволяют отдавать карту сайта прямо из файлового маршрута:
src/routes/sitemap[.]xml.tsКопировать кодКопировать код в буфер обмена
Интернационализация robots.txt
НеобязательноПриватные маршруты существуют на каждом языке, поэтому правила
Disallowдолжны охватывать каждый префикс. Удалите файлpublic/robots.txt, если он был создан стартером, и отдавайте его через маршрут:src/routes/robots[.]txt.tsКопировать кодКопировать код в буфер обмена
Перенаправление новых посетителей на их язык
НеобязательноMiddleware для запросов перенаправляет посетителя, зашедшего на
/, на его предпочитаемый язык на основе cookie локали в первую очередь, а затем заголовкаAccept-Language. Перенаправляется только маршрут/: внутренние ссылки никогда не изменяются, поэтому общие URL и поисковые роботы всегда получают именно ту страницу, которую запросили.src/i18n/negotiateLocale.tsКопировать кодКопировать код в буфер обмена
src/start.tsКопировать кодКопировать код в буфер обмена
Посетитель, который явно выбрал английский язык в переключателе, получает значение
locale=enв cookie, поэтому повторные перенаправления не выполняются. При полностью статическом деплое (шаг 18) маршрут/отдается как статический файл, и этот middleware не запускается, что абсолютно нормально: страница остается доступной, а переключатель языков выполняет свою задачу.Сохраняйте API use-intl и уменьшайте рантайм с помощью Intlayer
НеобязательноБенчмарк показывает, что самой тяжелой частью конфигурации use-intl является сам рантайм (~76 KB gzip). Адаптер совместимости
@intlayer/use-intlпредоставляет тот же самый API (useTranslations,useFormatter,IntlProvider,createTranslator, формы множественного числа ICU,t.rich), но отдает данные из скомпилированных словарей Intlayer: ~6.7 KB вместо ~75.9 KB, 0% утечки локалей и 0% утечки страниц, без необходимости менять ваши компоненты.bashКопировать кодКопировать код в буфер обмена
Плагин Vite создает псевдоним (alias) для
use-intl, направляя вызовы на адаптер, благодаря чему существующие импорты продолжают работать:vite.config.tsКопировать кодКопировать код в буфер обмена
Ваши JSON-файлы остаются источником истины благодаря плагину синхронизации JSON:
intlayer.config.tsКопировать кодКопировать код в буфер обмена
Адаптер также обеспечивает плавную миграцию: после его внедрения вы можете постепенно переводить компоненты на нативный API
useIntlayer. См. руководство по Intlayer с TanStack Start.Предварительный рендеринг (Pre-rendering) для каждой локали
НеобязательноСтатический HTML является самым быстрым форматом страниц и наиболее удобен для индексации. Перечислите все локализованные пути, чтобы TanStack Start предварительно отрендерил все языковые версии на этапе сборки, а также файлы sitemap и robots:
vite.config.tsКопировать кодКопировать код в буфер обмена
Поскольку переключатель языка рендерит стандартные ссылки, параметр
crawlLinks: trueтакже обнаружит страницы, которые вы забыли указать в списке.Обработка локализованных страниц 404
НеобязательноМакет из шага 7 уже выбрасывает
notFound()для неизвестных префиксов локалей. Добавьте общий перехватывающий маршрут (catch-all), чтобы неизвестные пути внутри локали также рендерили локализованную страницу 404, и добавьте тегnoindex: React 19 автоматически переместит тег<meta>в<head>.src/components/NotFound.tsxКопировать кодКопировать код в буфер обмена
src/routes/{-$locale}/$.tsxКопировать кодКопировать код в буфер обмена
Доступ к локали в серверных функциях (Server Functions)
НеобязательноСерверные функции не получают параметры маршрута. Прочитайте cookie локали и используйте заголовок
Accept-Languageв качестве фолбэка, чтобы отправить локализованное письмо или сохранить языковые предпочтения:src/server/getServerLocale.tsКопировать кодКопировать код в буфер обмена
Для выполнения переводов внутри серверной функции объедините ее с функциями
loadMessagesиcreateTranslatorизuse-intl.Автоматизация переводов с помощью Intlayer
Необязательноuse-intl выполняет рендеринг переводов, но не помогает вам создавать их. Intlayer является бесплатным инструментом с открытым исходным кодом, который закрывает этот пробел, даже если вы продолжаете использовать use-intl:
- Тестирование отсутствующих переводов в CI или модульных тестах. См. тестирование переводов.
- Перевод с помощью ИИ с использованием вашего собственного API-ключа и провайдера: команда
npx intlayer fillпереводит недостающие ключи с учетом контекста вашего приложения. См. автозаполнение и CLI. - Сохранение JSON-файлов в качестве источника истины с помощью плагина синхронизации JSON.
- Визуальное редактирование контента через визуальный редактор и CMS, благодаря чему специалисты без навыков разработки могут обновлять тексты.
- Предоставление контекста вашему ИИ-агенту с помощью MCP-сервера и навыков агента.
- Сканирование развернутого сайта на предмет отсутствующих
hreflang, некорректных канонических ссылок и утечек локалей с помощью команды сканирования.
Чтобы ознакомиться со всеми возможностями, узнайте почему стоит выбрать Intlayer.
Часто задаваемые вопросы
Да, если вам нужен API библиотеки next-intl за пределами Next.js. Вы получаете сообщения ICU, форматтеры и хорошую поддержку TypeScript, избегая при этом специфических ограничений Next.js, таких как setRequestLocale. Главный компромисс заключается в размере: бенчмарк показывает около 76 KB gzip для рантайма, а базовая настройка без оптимизаций отправляет все локали и все страницы в браузер. Загружайте пространства имен для каждого маршрута и каждой локали отдельно, как показано в этом руководстве, чтобы избежать утечек.
use-intl - это ядро библиотеки next-intl. next-intl добавляет поверх него интеграции с Next.js: middleware, навигационные хелперы, getTranslations для Server Components и конфигурацию запросов. В TanStack Start вы используете use-intl напрямую и реализуете маршрутизацию с помощью TanStack Router, как описано выше.
Используйте префикс в URL. В этом случае каждая языковая версия получает собственный уникальный URL, который поисковые системы могут индексировать, а пользователи могут передавать в виде ссылок. Cookie при этом полезен для сохранения явного выбора пользователя, что и делает middleware перенаправления из шага 16.
Сервер и браузер форматируют даты в разных часовых поясах. Передайте явный параметр timeZone в IntlProvider (или часовой пояс посетителя, сохраненный в cookie), чтобы обе стороны генерировали идентичный текст.
Во-первых, разделите сообщения по пространствам имен и загружайте их для каждого маршрута и каждой локали отдельно с помощью import.meta.glob, что полностью устраняет утечки локалей и страниц. Затем, если критичен размер рантайма, перейдите на адаптер @intlayer/use-intl: тот же самый API, ~6.7 KB вместо ~75.9 KB в бенчмарке.
Вызовите createTranslator внутри функции head() маршрута с сообщениями, возвращенными загрузчиком маршрута, и верните title, description, каноническую ссылку и ссылки hreflang. На шаге 13 представлен готовый переиспользуемый хелпер.
Комментарии
Пока нет комментариев. Будьте первым, кто поделится своими мыслями.
