如何在 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,并将其合并到传递给底层 Linkparams 属性中。扩展运算符确保任何显式提供的参数具有优先权。

在整个应用程序中,将标准的 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 参数。这允许用户在保持相同逻辑页面的同时切换语言。