如何在 TanStack Start v1 中实现基于语言环境的路由

使用语言环境段配置路由

问题

在构建多语言应用时,一个最根本的决策会影响后续所有实现:应用如何确定显示哪种语言?如果没有明确的机制,URL /about 就会变得模糊——它可能代表任何语言的内容。用户无法分享特定语言版本的链接,搜索引擎也难以判断每个版本对应的受众。这种不明确会影响用户体验和 SEO,因为无法区分同一内容的不同语言版本。

解决方案

直接在 URL 路径中加入语言标识符,例如 /en/about/fr/about。这样每个路径都唯一对应某种语言,消除了用户和搜索引擎的歧义。通过在路由结构中使用 locale 参数,每个 URL 都能自我描述并便于分享,用户可以收藏或分享自己偏好的语言内容链接,同时也方便搜索引擎正确索引每个语言版本。

步骤

1. 创建语言环境布局路由

使用 {-$locale} 语法定义可选的 locale 参数,以创建灵活的路由模式,使 locale 参数可选。TanStack Start 采用基于文件的路由,路由定义在 src/routes 目录中。

import { createFileRoute, Outlet } from "@tanstack/react-router";

export const Route = createFileRoute("/{-$locale}")({
  component: LocaleLayout,
});

function LocaleLayout() {
  return <Outlet />;
}

该路由既匹配 /about(locale 未定义),也匹配 /en/about(locale 为 "en"),从而支持带或不带语言前缀的 URL。

2. 在 locale 布局下创建子路由

TanStack Router 使用嵌套路由,根据 URL 匹配并渲染正确的组件树。请将路由文件作为 locale 参数的子级创建,以便从 URL 继承 locale。

import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/{-$locale}/about")({
  component: AboutPage,
});

function AboutPage() {
  const { locale } = Route.useParams();
  const currentLocale = locale || "en";

  return (
    <div>
      <h1>About Us</h1>
      <p>Current locale: {currentLocale}</p>
    </div>
  );
}

路由文件结构 {-$locale}/about.tsx 会生成像 /about/en/about 这样的路径,这些路径都会渲染同一个组件,并且可以访问 locale 参数。

3. 在组件中访问 locale 参数

使用 useParams hook 从 URL 读取 locale,并确定显示哪种语言。

import { createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/{-$locale}/products")({
  component: ProductsPage,
});

function ProductsPage() {
  const { locale } = Route.useParams();
  const displayLocale = locale || "en";

  return (
    <div>
      <h1>{displayLocale === "fr" ? "Produits" : "Products"}</h1>
    </div>
  );
}

当 locale 参数未定义时,组件会默认使用基础语言,从而支持应用同时处理本地化和非本地化的 URL。

4. 创建保留 locale 的链接

使用 Link 组件并传递 locale 参数,在页面间跳转时保持当前语言环境。

import { Link, createFileRoute } from "@tanstack/react-router";

export const Route = createFileRoute("/{-$locale}/")({
  component: HomePage,
});

function HomePage() {
  const { locale } = Route.useParams();

  return (
    <nav>
      <Link to="/{-$locale}/about" params={{ locale }}>
        About
      </Link>
      <Link to="/{-$locale}/products" params={{ locale }}>
        Products
      </Link>
    </nav>
  );
}

通过在 params 属性中传递当前 locale,链接会自动生成与用户当前语言环境相匹配的 URL,例如在查看法语版本时会生成 /fr/about