如何在 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 连贯性。

步骤

构建一个能够读取当前 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} />;
}

该组件结合使用 useParamsstrict: false,可从应用内任意路由访问参数,提取当前 locale,并将其合并到传递给底层 Linkparams 属性中。展开运算符可确保任何显式传递的参数具有更高优先级。

请在应用中用 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 参数。这样用户可以在保持当前逻辑页面的同时切换语言。