Как сохранять локаль в навигационных ссылках в 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. Оператор spread гарантирует, что любые явно переданные параметры будут иметь приоритет.

Замените стандартные компоненты 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>Products</h1>
      <nav>
        <LocaleLink to="/{-$locale}/about">About</LocaleLink>
        <LocaleLink to="/{-$locale}/contact">Contact</LocaleLink>
        <LocaleLink to="/{-$locale}/products/$id" params={{ id: "123" }}>
          Product 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. Это позволяет пользователям менять язык, оставаясь на той же логической странице.