# General Translation Knowledge Base: 如何为 TanStack Start 添加 i18n？
URL: https://generaltranslation.com/zh/kb/add-i18n-to-tanstack-start.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: TanStack Start 没有内置 i18n，因此你需要引入一个库，在每个服务端请求中解析区域设置（通常依据 URL 前缀或 cookie），并在渲染前加载消息。Paraglide JS、react-i18next 和 Lingui 负责渲染你提供的译文；General Translation 的实验性库 gt-tanstack-start 还能根据 JSX 中内联编写的文案自动生成译文。
Category: 国际化
Last updated: 2026-10-28
Authors: General Translation Team
Published: 2026-10-28

TanStack Start 没有自带 i18n 层，因此你需要自行补齐三样东西：一个以当前语言渲染文本的库、一套在每个服务端请求中解析当前语言的机制，以及译文本身。Start 会先在服务端渲染完整文档，再在浏览器中进行水合，因此两端必须使用相同的区域设置和消息，否则首屏会以错误的语言呈现，或者水合失败。

## TanStack Start 提供了什么，又把什么留给了你

TanStack Start 是“一个由 TanStack Router 驱动的全栈 React 框架”，支持完整文档的服务器端渲染 (SSR) 、流式传输、服务器函数和请求中间件 ([TanStack Start 概览](https://tanstack.com/start/latest/docs/framework/react/overview)) 。其中有几项正是 i18n 初始化设置所依赖的基础：

* **区域设置 URL。** 像 `/{-$locale}/about` 这样的可选路径参数，只需一个路由文件即可匹配 `/about`、`/es/about` 和 `/fr/about`；也可以改用路由器的 `rewrite` 选项来添加和移除区域设置前缀 ([TanStack Router i18n 指南](https://tanstack.com/router/latest/docs/guide/internationalization-i18n)) 。
* **请求中间件。** 在 `src/start.ts` 中通过 `createStart` 注册的中间件会在每个请求之前运行，SSR 和服务器函数也不例外 ([TanStack Start 中间件](https://tanstack.com/start/latest/docs/framework/react/guide/middleware)) 。国际化库正是在这里读取 URL、cookie 或 `Accept-Language` 请求头。
* **加载器与 `head`。** root 路由的加载器可以在渲染前加载当前区域设置的消息，而每个路由的 `head` 负责设置翻译后的 `<title>` 和 meta 标签。

Start 留给你自行处理的部分包括：消息目录及负责查找消息的运行时、区域设置检测以及用于记住用户选择的 cookie、根布局中的 `<html lang>` 属性、复数与数字格式化、`hreflang` 链接，以及译文本身。TanStack 的 i18n 指南对 Paraglide JS 做了深入介绍 (包括 TanStack Start 的 SSR 初始化设置) ，并附有 Intlayer 和 use-intl 的社区指南链接。此外，TanStack CLI 还为新应用提供了 `paraglide` 插件。

## 可选方案

| 库                                                      | 如何编写文案                                                                                                     | 服务端的区域设置                                                                                                                                 | 译文来源                                                                       |
| ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| [Paraglide JS](https://paraglidejs.com/tanstack-start) | 每个区域设置对应一个 JSON 文件存放消息，编译为 `m.greeting()` 等带类型的函数                                                          | `paraglideMiddleware` 包裹服务端处理函数；策略包括 URL、cookie 和首选语言                                                                                    | 由你自己、译者，或你对这些文件运行的机器翻译命令提供                                                 |
| [react-i18next](https://react.i18next.com/latest/ssr)  | 在 JSON 命名空间中定义键，通过 `t('home.title')` 渲染                                                                    | 其文档未提供 TanStack Start 集成；你需要自行创建按请求的实例，并将 `initialLanguage` 和 `initialI18nStore` 传给客户端                                                   | 由你自己、译者，或 Locize 等翻译管理系统 (TMS) 提供                                          |
| [Lingui](https://lingui.dev/ref/vite-plugin)           | 内联使用 `<Trans>` 宏，提取到 PO 消息目录                                                                               | 其 Vite 插件负责编译消息目录；你需要在服务端和浏览器中激活当前请求的区域设置                                                                                                | 由你自己、译者，或与消息目录同步的服务提供                                                      |
| General Translation (`gt-tanstack-start`，实验性)          | 用 [`<T>`](/docs/react/reference/components/t) 包裹 JSX，用 [`useGT`](/docs/react/reference/hooks/use-gt) 处理字符串 | [`gtMiddleware`](/docs/react/tanstack-start/reference/functions/gt-middleware)：依次检查 URL 前缀 (需主动启用) 、cookie、`Accept-Language`，最后回退到默认区域设置 | 由 [`npx gt translate`](/docs/cli/reference/commands/translate) 生成，并在仪表板中审校 |

如果你想采用 TanStack 官方文档中的初始化设置、带类型的消息函数以及按消息粒度的 tree-shaking，并且已有填充 JSON 文件的途径，请选择 Paraglide JS。如果你要沿用其他应用中的 i18next 消息目录，请选择 react-i18next。如果你的译者习惯使用 PO 文件，请选择 Lingui。如果你希望文案直接内联在组件中，并由此自动生成译文、保持同步更新，请选择 General Translation。 (更详细的对比请参阅 [General Translation 与 Paraglide JS 对比](/kb/general-translation-vs-paraglide)。) 

`gt-tanstack-start` 目前处于实验阶段：General Translation 的文档指出它可能出现破坏性变更，暂不建议用于生产环境。如果现在就需要稳定的 React 初始化设置，请参阅[如何翻译 React 应用？](/kb/translate-react-app)。

## 将 General Translation 添加到 TanStack Start

本教程将为页面添加西班牙语和法语支持，翻译一个服务器函数，然后为每种语言分配独立的 URL。本教程已使用 `npx @tanstack/cli@latest create` 创建的应用 (`@tanstack/react-start` 1.169.4) 、`gt-tanstack-start@11.4.16` 和 `gt@2.26.11` 测试通过。该软件包要求 `@tanstack/react-start` 1.159.0 或更高版本，且仅支持 ESM。

[初始化设置向导](/docs/cli/reference/commands/init) (`npx gt@2.26.11 init`) 所做的更改与步骤 1 至 4 相同：安装该软件包，写入加载器、中间件、路由器调用和 root 路由，并列出所有无法安全修改的内容。你可以检查它生成的差异，也可以按照以下步骤手动操作。

### 1. 安装库和 CLI

```bash
npm install gt-tanstack-start@11.4.16
npm install --save-dev gt@2.26.11
```

`gt-tanstack-start` 导出共享的 React 组件 (例如 [`<T>`](/docs/react/reference/components/t) 和 [`<LocaleSelector>`](/docs/react/reference/components/locale-selector)) 以及服务端辅助函数。`gt` CLI 负责查找源文案并生成翻译文件。

### 2. 设置语言

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": ["es", "fr"],
  "files": {
    "gt": {
      "output": "src/_gt/[locale].json"
    }
  }
}
```

请将输出文件放在 `src/` 目录下，以便 Vite 导入。然后添加一个加载器：

```ts title="src/loadTranslations.ts"
export default async function loadTranslations(locale: string) {
  const translations = await import(`./_gt/${locale}.json`);
  return translations.default;
}
```

### 3. 注册请求中间件

```ts title="src/start.ts"
import { createCsrfMiddleware, createStart } from '@tanstack/react-start';
import { gtMiddleware } from 'gt-tanstack-start';

// 为服务器函数保留 TanStack Start 的 CSRF 防护。
const csrfMiddleware = createCsrfMiddleware({
  filter: ({ handlerType }) => handlerType === 'serverFn',
});

export const startInstance = createStart(() => ({
  requestMiddleware: [csrfMiddleware, gtMiddleware],
}));
```

General Translation 的 [`gtMiddleware`](/docs/react/tanstack-start/reference/functions/gt-middleware) 会为每个请求解析一次区域设置，依次检查区域设置 cookie、`Accept-Language` 和 `defaultLocale`，并将结果保存到 cookie 中。即使多个请求同时渲染，每个请求也会保持各自的区域设置。

### 4. 初始化库并对 root 路由进行水合

在现有的 `src/router.tsx` 中，于模块作用域添加初始化代码：

```tsx title="src/router.tsx"
import { initializeGT } from 'gt-tanstack-start';
import gtConfig from '../gt.config.json';
import loadTranslations from './loadTranslations';

initializeGT({ ...gtConfig, loadTranslations });

// ... 现有的 getRouter() 代码
```

然后在 root 路由中加载区域设置及其译文，并将二者传给 [`<GTProvider>`](/docs/react/reference/components/gt-provider)：

```tsx title="src/routes/__root.tsx"
import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router';
import {
  GTProvider,
  LocaleSelector,
  getLocale,
  getTranslationsSnapshot,
} from 'gt-tanstack-start';

export const Route = createRootRoute({
  // 首次请求时在服务器端运行，因此返回的 HTML 已完成翻译。
  loader: async () => {
    const locale = getLocale();
    return { locale, translations: await getTranslationsSnapshot(locale) };
  },
  shellComponent: RootDocument,
});

function RootDocument({ children }: { children: React.ReactNode }) {
  const { locale, translations } = Route.useLoaderData();
  return (
    <html lang={locale}>
      <head>
        <HeadContent />
      </head>
      <body>
        <GTProvider locale={locale} translations={translations}>
          <LocaleSelector />
          {children}
        </GTProvider>
        <Scripts />
      </body>
    </html>
  );
}
```

[`getLocale`](/docs/react/tanstack-start/reference/functions/get-locale) 在服务器端读取请求的区域设置，在浏览器端则读取 cookie，从而确保两端的渲染结果一致。设置 `lang={locale}` 后，即可替换 starter 模板 shell 中硬编码的 `lang="en"`。

### 5. 标记需要翻译的内容

```tsx title="src/routes/index.tsx"
import { createFileRoute } from '@tanstack/react-router';
import { T, useGT } from 'gt-tanstack-start';

export const Route = createFileRoute('/')({ component: Home });

function Home() {
  const gt = useGT();

  return (
    <main>
      <T>
        <h1>Find your next project</h1>
        <p>Explore projects from teams around the world.</p>
      </T>
      <input type="search" placeholder={gt('Search projects')} aria-label={gt('Search projects')} />
    </main>
  );
}
```

[`<T>`](/docs/react/reference/components/t) 会将标题和段落作为一个整体进行翻译，并将标记结构作为上下文。属性中的字符串则由 [`useGT`](/docs/react/reference/hooks/use-gt) 处理。如果 [`<T>`](/docs/react/reference/components/t) 中包含名称、数量和日期，请使用[变量和格式化组件](/docs/react/guides/formatting-variables)。

### 6. 生成译文

使用 [`npx gt login`](/docs/cli/reference/commands/login) 登录，设置 `GT_PROJECT_ID` (或在 `gt.config.json` 中设置 `projectId`) ，然后运行 [`npx gt translate`](/docs/cli/reference/commands/translate)。该命令会生成 `src/_gt/es.json` 和 `src/_gt/fr.json`。生成译文采用[按用量计费](https://generaltranslation.com/pricing)。

如果想在不注册账户的情况下试用这套初始化设置，请运行 [`npx gt generate`](/docs/cli/reference/commands/generate)。该命令会生成相同的文件，但内容为英文源文本，需要你手动编辑。如果某个区域设置尚无对应文件，则会渲染源文本，并记录一条警告，提示其译文无法加载。

### 7. 运行并切换语言

运行 `npm run dev`，然后在选择器中选择 Español。选择结果会保存到区域设置 cookie 中，页面随即重新加载，服务器会渲染西班牙语内容。在测试应用中，生产环境构建对带有 `Accept-Language: es` 的请求返回了 `<html lang="es">` 以及西班牙语标题和占位符；对未指定语言偏好的请求，则返回了 `<html lang="en">` 和英语内容。

## 在服务器函数和元数据中进行翻译

[`getGT`](/docs/react/tanstack-start/reference/functions/get-gt) 可在服务器函数中根据当前请求的区域设置翻译字符串：

```tsx title="src/routes/account.tsx"
import { createFileRoute } from '@tanstack/react-router';
import { createServerFn } from '@tanstack/react-start';
import { getGT } from 'gt-tanstack-start';

const loadAccount = createServerFn({ method: 'GET' }).handler(async () => {
  const gt = await getGT();
  return { title: gt('Your account') };
});

export const Route = createFileRoute('/account')({
  loader: () => loadAccount(),
  // 翻译后的标题也会用作页面的 <title>。
  head: ({ loaderData }) => ({ meta: [{ title: loaderData?.title }] }),
  component: () => <h1>{Route.useLoaderData().title}</h1>,
});
```

在服务器端，如果在 [`gtMiddleware`](/docs/react/tanstack-start/reference/functions/gt-middleware) 所处理的请求之外 (例如在模块作用域中) 调用这些辅助函数，就会抛出错误。[使用服务器函数](/docs/react/tanstack-start/using-server-functions)中也介绍了词典条目和已注册的消息的用法。

## 为每种语言提供独立的 URL

上述初始化设置会在同一个 URL 下提供所有语言，具体显示哪种语言由 cookie 或浏览器语言决定。搜索引擎对每个 URL 只会索引一种语言，因此[公开页面需要添加前缀](/kb/locale-routing-seo)，例如 `/es/about`。请将路由移到一个可选路径段下，例如 `src/routes/{-$locale}/index.tsx`，并配合使用 `createFileRoute('/{-$locale}/')`，然后启用区域设置路由：

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": ["es", "fr"],
  "localeRouting": true
}
```

随后，中间件会先检查路径，选择器则跳转到带前缀的 URL。在测试应用中，`/es` 和 `/es/account` 渲染为西班牙语，并带有 `<html lang="es">`，而 `/` 渲染为英语。对于回访用户，不带前缀的 URL 仍会根据 cookie 确定语言；此外，你需要自行在每个路由的 `head` 中添加 [`hreflang` 链接](/kb/what-is-hreflang)。 (参见[区域设置路由初始化设置](/docs/react/tanstack-start/setup#locale-routing)。)

## 发布并让译文保持最新

每次构建前先运行翻译，确保新增文案以所有语言同步发布：

```json title="package.json"
{
  "scripts": {
    "build": "gt validate && gt translate && vite build"
  }
}
```

[`gt validate`](/docs/cli/reference/commands/validate) 会在发起任何 API 调用之前进行检查，一旦发现会破坏翻译的内容，就让构建失败。在 CI 中，请设置 `GT_PROJECT_ID`，并将一个具有 **Files &gt; Write** 和 **Translation queue &gt; Enabled** 权限的项目 API 密钥设为 `GT_API_KEY` (参见 [CLI 凭据](/docs/cli/guides/configuring#credentials)) 。之后每次运行只会翻译新增或变更的源内容。

审校人员可以在 General Translation 的[翻译编辑器](/docs/platform/dashboard/guides/reviewing-translations)中编辑任意字符串；直接在 JSON 文件中所做的修改，则可通过 [`npx gt save-local`](/docs/cli/reference/commands/save-local) 同步回去，确保后续运行时得以保留。[上下文分组](/docs/platform/dashboard/guides/defining-context-for-translations)用于存放你的词汇表和自定义提示词，让产品名称和语气在本应用、你的文档以及其他项目中保持一致。General Translation 的 AI 智能体 [Locadex](/docs/platform/locadex/guides/configuring-automations) 支持 TanStack Start 应用，并可通过拉取请求翻译新增文案。

## 常见问题

### TanStack Start 是否内置 i18n？

没有。TanStack Router 提供可选的区域设置路径段和 URL 重写，Start 提供中间件和加载器，但消息、区域设置检测和翻译功能仍需借助库来实现。

### 可以在 TanStack Start 中使用 react-i18next 吗？

可以，把它当作普通的 React 库使用即可。不过 TanStack 并未提供相关文档，react-i18next 的 SSR 指南也只提到了 Next.js、Remix 和 Gatsby 的集成，因此你需要自行接入按请求创建的实例和客户端水合。

### gt-tanstack-start 是否可用于生产环境？

暂不建议：General Translation 目前将其标记为实验性功能。请锁定版本，并在升级前查阅更新日志。

## 要点总结

* TanStack Start 本身没有 i18n 层；它的可选 `/{-$locale}` 路由段、`createStart` 中间件和根加载器正是接入 i18n 的位置。
* 在服务器端按请求解析区域设置，并用相同的消息对客户端进行水合；同时在加载器中设置 `<html lang>`，不要沿用初始模板中硬编码的 `lang="en"`。
* Paraglide JS 是 TanStack 官方文档推荐的库；它与 react-i18next、Lingui 一样，都只负责渲染由你提供的译文。
* General Translation 的实验性库 `gt-tanstack-start` 提供了 [`gtMiddleware`](/docs/react/tanstack-start/reference/functions/gt-middleware)、[`initializeGT`](/docs/react/reference/config#initialize) 和 [`<GTProvider>`](/docs/react/reference/components/gt-provider)，文案以内联方式保留在 [`<T>`](/docs/react/reference/components/t) 中，再由 [`npx gt translate`](/docs/cli/reference/commands/translate) 写入 `src/_gt/[locale].json`。
* 如果每种语言都需要独立且可被搜索引擎索引的 URL，请添加 `"localeRouting": true`，并配合可选的 `{-$locale}` 路由段使用。

## Related questions

- [如何为 Next.js App Router 应用添加 i18n？](https://generaltranslation.com/zh/kb/add-i18n-to-nextjs.mdx): 首先在受支持的 App Router 项目中运行 gt init 来配置 General Translation，然后标记源内容、生成译文并验证语言切换。gt-next 将文案与翻译上下文一同保留在 JSX 中；CLI、仪表板编辑器和 Locadex 负责生成、审校和持续更新。本指南还演示了如何显式配置本地文件。
- [General Translation 与 Paraglide JS：该选哪一个？](https://generaltranslation.com/zh/kb/general-translation-vs-paraglide.mdx): 如果你希望将文案内联在代码中，并结合 React 组件结构、共享术语和仪表板审阅来生成译文，请选择 General Translation。如果你需要编译生成的带类型消息函数，以及按单条消息进行的 tree-shaking，请选择 Paraglide JS。Paraglide 负责渲染你的消息目录；General Translation 则将源文案与译文生成及后续更新衔接起来。
- [React 应用最适合使用哪个国际化库？](https://generaltranslation.com/zh/kb/best-react-i18n-library.mdx): 主流的 React 国际化库有四个：General Translation 的 gt-react、react-i18next、Lingui 和 React Intl。四者都能渲染和格式化译文，但只有 gt-react 还能根据你在 JSX 中内联编写的文案直接生成译文。如果想继续沿用 i18next 的消息目录和插件，请选择 react-i18next；如果需要将文案提取为编译后的消息目录，请选择 Lingui；如果需要 FormatJS 和 ICU MessageFormat，请选择 React Intl。
- [语言重定向与 SEO：URL、cookie 还是 Accept-Language？](https://generaltranslation.com/zh/kb/locale-routing-seo.mdx): 凡是希望被搜索引擎收录的页面，都应由 URL 决定其语言，因为 Googlebot 不会发送 Accept-Language 请求头，而且大多从美国 IP 地址抓取。只有在决定 / 这类中性根路径重定向到哪里时，才应优先参考 cookie 中保存的用户选择，其次是 Accept-Language，并使用临时的 302 或 307 重定向。
- [如何翻译 React 应用？](https://generaltranslation.com/zh/kb/translate-react-app.mdx): 翻译 React 应用，需要先对组件进行国际化，使其以用户的语言渲染，再将每个字符串翻译成你支持的各种语言。General Translation 的 gt-react 在 `<T>` 组件中原地翻译 JSX，npx gt translate 则会为每种语言生成一个文件。

## Previous and next questions

- Previous question: [如何为 Next.js Pages Router 应用添加 i18n？](https://generaltranslation.com/zh/kb/add-i18n-to-nextjs-pages-router.mdx)
- Next question: [如何为多语言网站创建站点地图？](https://generaltranslation.com/zh/kb/multilingual-sitemap.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/zh/kb/sitemap.md) for every article.
