如何在 TanStack Start v1 的导航链接中维护 locale
在内部导航中保持 locale 一致
问题
当 locale 信息被编码在 URL 路径中时,每一个导航链接都必须保留该 locale,以确保用户体验的一致性。如果用户正在 /fr/products 浏览网站的法语版本,点击跳转到 /about 时会进入默认语言,导致会话上下文丢失。将 locale 参数硬编码到每个链接中既繁琐又容易出错,尤其是在应用规模扩大、组件中链接增多时问题更为突出。
如果没有系统化的 locale 感知导航方案,开发者只能在每个 Link 组件中手动传递 locale,或者接受用户在会话中途被意外切换到默认语言。这两种结果都会降低用户体验,并增加维护负担。
解决方案
围绕框架的 Link 创建一个包装组件,自动从 URL 读取当前 locale,并将其注入到每个导航目标的 params 属性中。通过将这部分逻辑集中到一个可复用组件中,所有内部链接都能自动继承 locale 感知行为,无需开发者在每个调用点手动传递 locale 参数。
该方法通过使用路由器的 hooks 读取当前路由参数中的 locale,然后将 locale 合并到目标链接的参数中。包装组件会保留所有 Link 的原有功能,同时确保导航过程中的 locale 连贯性。
步骤
1. 创建一个 locale 感知的 Link 包装组件
构建一个能够读取当前 locale 并自动将其包含到导航参数中的组件。
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,并将其合并到传递给底层 Link 的 params 属性中。展开运算符可确保任何显式传递的参数具有更高优先级。
2. 内部导航请使用 LocaleLink 组件
请在应用中用 LocaleLink 替换标准 Link 组件。
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。locale 参数会在每个链接处自动保留,无需手动处理。
3. 需要时显式处理语言切换
对于语言切换组件,请直接使用标准 Link,以绕过自动 locale 注入。
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>
);
}
语言切换器需要对 locale 参数进行显式控制,因此会使用标准 Link 组件,并显式设置 locale 参数。这样用户可以在保持当前逻辑页面的同时切换语言。