Как реализовать маршрутизацию по локали в React Router v7

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

Проблема

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

Решение

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

Шаги

1. Определите маршруты с параметром локали

Настройте маршруты в app/routes.ts, чтобы параметр локали был первым сегментом каждого пути.

import { type RouteConfig, route, index } from "@react-router/dev/routes";

export default [
  route(":locale", "./localized-layout.tsx", [
    index("./home.tsx"),
    route("about", "./about.tsx"),
    route("contact", "./contact.tsx"),
  ]),
] satisfies RouteConfig;

Префикс с двоеточием делает locale динамическим сегментом, который будет извлекаться из URL и передаваться как параметр в компоненты маршрута. Такая конфигурация создаёт маршруты вроде /en, /en/about, /fr/contact, где первый сегмент всегда — локаль.

2. Создайте layout-компонент для извлечения локали

Дочерние маршруты отображаются через компонент Outlet в родительском маршруте. Создайте layout, который извлекает параметр locale и рендерит вложенные маршруты.

import { Outlet, useParams } from "react-router";

export default function LocalizedLayout() {
  const { locale } = useParams();

  return (
    <div>
      <nav>
        <a href={`/${locale}`}>Home</a>
        <a href={`/${locale}/about`}>About</a>
        <a href={`/${locale}/contact`}>Contact</a>
      </nav>
      <Outlet />
    </div>
  );
}

Хук useParams получает значение динамического сегмента из URL. Layout использует этот locale для построения навигационных ссылок и передаёт управление рендерингом дочерним маршрутам через Outlet.

3. Доступ к locale в компонентах страниц

Используйте хук useParams в любом компоненте маршрута, чтобы получить параметр locale.

import { useParams } from "react-router";

export default function About() {
  const { locale } = useParams();

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

Каждый компонент, отображаемый внутри локализованного layout, может извлекать locale из URL. Это значение можно использовать для загрузки нужных переводов, форматирования дат и чисел или других решений, зависящих от локали.

Замените теги anchor на компоненты Link, чтобы включить навигацию с помощью клиентского роутинга.

import { Outlet, useParams, Link } from "react-router";

export default function LocalizedLayout() {
  const { locale } = useParams();

  return (
    <div>
      <nav>
        <Link to={`/${locale}`}>Home</Link>
        <Link to={`/${locale}/about`}>About</Link>
        <Link to={`/${locale}/contact`}>Contact</Link>
      </nav>
      <Outlet />
    </div>
  );
}

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