Как реализовать маршрутизацию по локали в TanStack Start v1

Настройка маршрутизации с сегментами локали

Проблема

При создании многоязычного приложения один ключевой вопрос определяет всё остальное: как приложение узнает, на каком языке показывать контент? Без явного механизма URL /about становится неоднозначным — он может вести на контент на любом языке. Пользователи не могут делиться ссылками на определённые языковые версии, а поисковым системам сложно понять, какая версия предназначена для какой аудитории. Такая неоднозначность создаёт проблемы и для пользовательского опыта, и для SEO, ведь нет чёткого способа различать языковые варианты одного и того же контента.

Решение

Добавьте идентификатор языка прямо в путь URL, например, /en/about или /fr/about. Это делает каждый путь уникальным для определённого языка, устраняя неоднозначность как для пользователей, так и для поисковых систем. Используя параметр локали в структуре маршрута, каждый URL становится самодокументируемым и удобным для обмена: пользователи могут сохранять или делиться ссылками на контент на нужном языке, а поисковые системы смогут корректно индексировать каждую языковую версию.

Шаги

1. Создайте маршрут с layout для локали

Определите необязательный параметр локали с помощью синтаксиса {-$locale}, чтобы создавать гибкие шаблоны маршрутов, где параметр локали не обязателен. В TanStack Start используется файловая маршрутизация, где маршруты определяются в директории src/routes.

import { createFileRoute, Outlet } from "@tanstack/react-router";

export const Route = createFileRoute("/{-$locale}")({
  component: LocaleLayout,
});

function LocaleLayout() {
  return <Outlet />;
}

Этот маршрут подходит как для /about (локаль не указана), так и для /en/about (локаль — «en»), что позволяет поддерживать URL-адреса с префиксом локали и без него.

2. Создайте дочерние маршруты внутри макета локали

TanStack Router использует вложенные маршруты, чтобы сопоставлять URL с нужным деревом компонентов для отображения. Создайте файлы маршрутов как дочерние для параметра локали, чтобы наследовать локаль из URL.

import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/{-$locale}/about")({
  component: AboutPage,
});

function AboutPage() {
  const { locale } = Route.useParams();
  const currentLocale = locale || "en";

  return (
    <div>
      <h1>About Us</h1>
      <p>Current locale: {currentLocale}</p>
    </div>
  );
}

Структура файлов маршрутов {-$locale}/about.tsx создаёт пути вроде /about и /en/about, которые оба отображают один и тот же компонент с доступом к параметру локали.

3. Получите доступ к параметру локали в компонентах

Используйте хук useParams, чтобы считать локаль из URL и определить, какой язык показывать.

import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/{-$locale}/products")({
  component: ProductsPage,
});

function ProductsPage() {
  const { locale } = Route.useParams();
  const displayLocale = locale || "en";

  return (
    <div>
      <h1>{displayLocale === "fr" ? "Produits" : "Products"}</h1>
    </div>
  );
}

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

4. Создайте ссылки с сохранением локали

Используйте компонент Link с параметром локали, чтобы переходить между страницами, сохраняя текущий язык.

import { Link, createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/{-$locale}/")({
  component: HomePage,
});

function HomePage() {
  const { locale } = Route.useParams();

  return (
    <nav>
      <Link to="/{-$locale}/about" params={{ locale }}>
        About
      </Link>
      <Link to="/{-$locale}/products" params={{ locale }}>
        Products
      </Link>
    </nav>
  );
}

Передавая текущую локаль в пропс params, ссылки автоматически формируют URL, соответствующие языковому контексту пользователя, например /fr/about при просмотре французской версии.