Как поддерживать локаль в навигационных ссылках в React Router v7
Сохраняйте локаль при внутренней навигации
Проблема
Когда информация о локали кодируется в пути URL, каждая ссылка навигации должна сохранять эту локаль, чтобы поддерживать единообразный пользовательский опыт. Если пользователь просматривает французскую версию вашего сайта и нажимает на ссылку /about, он ожидает остаться на французском языке и перейти на /fr/about. Без ссылок, учитывающих локаль, пользователи попадают на язык по умолчанию в середине сеанса, что нарушает их контекст просмотра и заставляет их вручную переключать язык снова. Это создает трение и подрывает локализованный опыт.
Жесткое кодирование префикса локали в каждую ссылку подвержено ошибкам и делает кодовую базу хрупкой. По мере того как пользователи перемещаются по приложению, активная локаль может изменяться, и ручное обновление сотен ссылок становится неустойчивым.
Решение
Создайте пользовательский компонент Link, который автоматически считывает текущую локаль из URL и добавляет её ко всем внутренним путям навигации. Обернув компонент Link из React Router, вы централизуете обработку локали в одном месте. Обертка извлекает параметр локали из текущего маршрута и гарантирует, что каждый целевой путь включает его, чтобы навигация сохраняла выбор языка пользователя без ручного вмешательства.
Этот подход позволяет сохранять определения ссылок чистыми и независимыми от локали по всему вашему приложению, гарантируя, что контекст локали сохраняется при каждом клике.
Шаги
1. Создайте компонент-обертку Link, учитывающий локаль
Создайте пользовательский компонент, который использует useParams для извлечения текущей локали из URL и оборачивает компонент Link из React Router, чтобы добавлять локаль к целевому пути.
import { Link, useParams } from "react-router";
import type { LinkProps } from "react-router";
export function LocaleLink({ to, ...props }: LinkProps) {
const { locale } = useParams<{ locale: string }>();
const localizedTo =
typeof to === "string"
? `/${locale}${to.startsWith("/") ? to : `/${to}`}`
: {
...to,
pathname: `/${locale}${to.pathname?.startsWith("/") ? to.pathname : `/${to.pathname}`}`,
};
return <Link to={localizedTo} {...props} />;
}
Этот компонент считывает параметр локали из текущего маршрута и автоматически добавляет его к любому пути, переданному в проп to, обрабатывая как строковые, так и объектные формы.
2. Используйте компонент LocaleLink во всем вашем приложении
Замените стандартные компоненты Link на LocaleLink везде, где требуется навигация с сохранением локали.
import { LocaleLink } from "./LocaleLink";
export function Navigation() {
return (
<nav>
<LocaleLink to="/">Главная</LocaleLink>
<LocaleLink to="/about">О нас</LocaleLink>
<LocaleLink to="/products">Продукты</LocaleLink>
</nav>
);
}
Когда пользователь на странице /fr/products нажимает на ссылку "О нас", он переходит на /fr/about. Префикс локали добавляется автоматически, не загромождая определение ссылки.
3. Обработка крайних случаев для абсолютных путей и внешних ссылок
Расширьте обертку, чтобы определить, когда путь уже включает локаль или указывает на внешний URL, избегая двойного добавления префикса или нарушения внешней навигации.
import { Link, useParams } from "react-router";
import type { LinkProps } from "react-router";
export function LocaleLink({ to, ...props }: LinkProps) {
const { locale } = useParams<{ locale: string }>();
if (!locale) {
return <Link to={to} {...props} />;
}
const isExternal =
typeof to === "string" &&
(to.startsWith("http://") || to.startsWith("https://"));
const alreadyLocalized =
typeof to === "string" && to.startsWith(`/${locale}/`);
if (isExternal || alreadyLocalized) {
return <Link to={to} {...props} />;
}
const localizedTo =
typeof to === "string"
? `/${locale}${to.startsWith("/") ? to : `/${to}`}`
: {
...to,
pathname: `/${locale}${to.pathname?.startsWith("/") ? to.pathname : `/${to.pathname}`}`,
};
return <Link to={localizedTo} {...props} />;
}
Это предотвращает двойное добавление префикса, если путь уже начинается с локали, и пропускает внешние URL без изменений, обеспечивая надежную работу компонента во всех сценариях навигации.