Как поддерживать локаль в навигационных ссылках в TanStack Start v1

Сохраняйте локаль при внутренней навигации

Проблема

Когда информация о локали кодируется в пути URL, каждая навигационная ссылка должна сохранять эту локаль, чтобы поддерживать единообразный пользовательский опыт. Если пользователь просматривает французскую версию сайта по адресу /fr/products, нажатие на ссылку /about переводит его на язык по умолчанию, нарушая контекст его сессии. Жёсткое кодирование параметров локали в каждую ссылку является повторяющимся и подверженным ошибкам процессом, особенно по мере роста приложения и добавления большего количества ссылок в компоненты.

Без системного подхода к навигации с учётом локали разработчики сталкиваются с выбором: вручную передавать локаль через каждый компонент Link или смириться с тем, что пользователи неожиданно переключаются на язык по умолчанию в середине сессии. Оба варианта ухудшают пользовательский опыт и увеличивают нагрузку на обслуживание.

Решение

Создайте обёрточный компонент вокруг Link фреймворка, который автоматически считывает текущую локаль из URL и добавляет её в проп params каждой навигационной цели. Централизуя эту логику в одном многократно используемом компоненте, все внутренние ссылки наследуют поведение с учётом локали без необходимости вручную передавать параметры локали в каждом месте вызова.

Этот подход работает за счёт считывания активной локали из параметров маршрута с использованием хуков маршрутизатора, а затем добавления этой локали в параметры целевой ссылки. Обёртка сохраняет всю остальную функциональность Link, обеспечивая при этом непрерывность локали при навигации.

Шаги

Создайте компонент, который считывает текущую локаль и автоматически включает её в параметры навигации.

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

type LocaleLinkProps = LinkProps & {
  to: string;
};

export function LocaleLink(props: LocaleLinkProps) {
  const params = useParams({ strict: false });
  const currentLocale = params.locale;

  const enhancedParams = {
    ...props.params,
    ...(currentLocale && { locale: currentLocale }),
  };

  return <Link {...props} params={enhancedParams} />;
}

Этот компонент использует useParams с strict: false для доступа к параметрам из любого маршрута в приложении, извлекает текущую locale и добавляет её в проп params, передаваемый базовому Link. Оператор распространения гарантирует, что любые явно указанные параметры имеют приоритет.

Замените стандартные компоненты Link на LocaleLink по всему вашему приложению.

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

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

function ProductsPage() {
  return (
    <div>
      <h1>Продукты</h1>
      <nav>
        <LocaleLink to="/{-$locale}/about">О нас</LocaleLink>
        <LocaleLink to="/{-$locale}/contact">Контакты</LocaleLink>
        <LocaleLink to="/{-$locale}/products/$id" params={{ id: "123" }}>
          Продукт 123
        </LocaleLink>
      </nav>
    </div>
  );
}

Когда пользователь посещает /fr/products, все компоненты LocaleLink автоматически перенаправляют на /fr/about, /fr/contact и /fr/products/123. Параметр локали сохраняется без необходимости ручного вмешательства в каждом месте ссылки.

3. Явно обрабатывайте переключение локали, когда это необходимо

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

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

export function LanguageSwitcher() {
  const params = useParams({ strict: false });
  const currentPath = window.location.pathname.replace(/^\/(en|fr|es)/, "");

  return (
    <div>
      <Link to={`/{-$locale}${currentPath}`} params={{ locale: "en" }}>
        English
      </Link>
      <Link to={`/{-$locale}${currentPath}`} params={{ locale: "fr" }}>
        Français
      </Link>
      <Link to={`/{-$locale}${currentPath}`} params={{ locale: "es" }}>
        Español
      </Link>
    </div>
  );
}

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