# General Translation React SDKs (gt-react, gt-next, gt-react-native): React Router 快速入门
URL: https://generaltranslation.com/zh/docs/react/react-router-quickstart.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: 将 General Translation 添加到 React Router 框架应用（包括 Shopify Hydrogen 店面）中，并翻译你的第一批内容。

在 React Router 框架模式下，`gt-react` 通过根路由运行。你需要在 `app/root.tsx` 中初始化该库，在根加载器中解析每位访问者的区域设置，并在根 `Layout` 中渲染 [`GTProvider`](/docs/react/reference/components/gt-provider)。

本快速入门适用于使用 `@react-router/dev` 构建的应用。如果你是在 Vite 单页应用中以库的形式使用 React Router，请参阅 [React SPA 快速入门](/docs/react/react-spa-quickstart)。

在应用根目录下运行 [`npx gt@latest init`](/docs/cli/reference/commands/init) 即可自动完成初始化。该向导会安装 `gt-react`，创建配置文件和翻译加载器，并配置由 create-react-router 或 Hydrogen 模板生成的 `app/root.tsx`。对于其他根文件，向导不会做任何改动，而是列出需要手动执行的操作；本指南将介绍如何手动完成同样的初始化。

*注意：此初始化要求 `gt-react` 11.1.3 或更高版本，且应用需在每次请求时进行渲染。不支持 SPA 模式 (`ssr: false`) 、预渲染以及 RSC 框架模式。*

## 快速入门 [#quickstart]

### 1. 安装软件包

`gt-react` 是为应用提供翻译功能的库，`gt` 则是用于生成翻译的 CLI。

<Tabs items={['npm', 'yarn', 'bun', 'pnpm']}>
  <Tab value="npm">
    ```bash
    npm install gt-react && npm install gt --save-dev
    ```
  </Tab>

  <Tab value="yarn">
    ```bash
    yarn add gt-react && yarn add --dev gt
    ```
  </Tab>

  <Tab value="bun">
    ```bash
    bun add gt-react && bun add --dev gt
    ```
  </Tab>

  <Tab value="pnpm">
    ```bash
    pnpm add gt-react && pnpm add --save-dev gt
    ```
  </Tab>
</Tabs>

### 2. 创建 `gt.config.json`

在项目根目录中创建 `gt.config.json` 文件。该文件用于声明源语言、目标语言区域，以及翻译文件的输出位置。

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

* `defaultLocale` — 应用的源语言，即编写应用时使用的语言。
* `locales` — 需要翻译成的目标语言。可从[支持的语言区域](/docs/platform/dashboard/reference/supported-locales)中选择。
* `files.gt.output` — CLI 写入翻译文件的位置。请将翻译文件放在 `app/` 目录下，以便 Vite 将其与服务器端和客户端代码一起打包。

### 3. 创建翻译加载器

创建 `app/loadTranslations.ts`。当根加载器发出请求时，该文件会导入对应区域设置的翻译文件。

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

然后为每个目标区域设置创建一个内容为 `{}` 的空文件，例如 `app/_gt/es.json` 和 `app/_gt/ja.json`；[`gt init`](/docs/cli/reference/commands/init) 会自动为你创建这些文件。如果某个区域设置没有对应的翻译文件，则会以你的默认语言渲染。

### 4. 配置根路由

在 `app/root.tsx` 的模块作用域中调用一次 [`initializeGT`](/docs/react/reference/config#initialize)，在根加载器中返回区域设置和译文快照，并用 [`GTProvider`](/docs/react/reference/components/gt-provider) 包裹 `Layout` 的内容。将高亮的代码行添加到现有的根文件中：

```tsx title="app/root.tsx"
import {
  Links,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
  useRouteLoaderData, // [!code ++]
} from 'react-router';
import { GTProvider, getTranslationsSnapshot, initializeGT, parseLocale } from 'gt-react'; // [!code ++]

import type { Route } from './+types/root';
import gtConfig from '../gt.config.json'; // [!code ++]
import loadTranslations from './loadTranslations'; // [!code ++]
import './app.css';

initializeGT({ ...gtConfig, loadTranslations }); // [!code ++]

// [!code ++:11]
// 错误页面没有 loader 数据。因此在此跳过 GTProvider，以免它
// 用默认值覆盖访问者已保存的区域设置。
function RootGTProvider({ children }: { children: React.ReactNode }) {
  const data = useRouteLoaderData<typeof loader>('root');
  if (!data) return <>{children}</>;
  return (
    <GTProvider locale={data.locale} translations={data.translations}>
      {children}
    </GTProvider>
  );
}

// [!code ++:4]
export async function loader({ request }: Route.LoaderArgs) {
  const locale = parseLocale(request);
  return { locale, translations: await getTranslationsSnapshot(locale) };
}

export function Layout({ children }: { children: React.ReactNode }) {
  const locale = useRouteLoaderData<typeof loader>('root')?.locale ?? gtConfig.defaultLocale; // [!code ++]
  return (
    // [!code ++]
    <html lang={locale}>
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <Meta />
        <Links />
      </head>
      <body>
        {/* [!code ++] */}
        <RootGTProvider>
          {children}
          <ScrollRestoration />
        {/* [!code ++] */}
        </RootGTProvider>
        <Scripts />
      </body>
    </html>
  );
}

export default function App() {
  return <Outlet />;
}
```

`parseLocale` 会先读取区域设置 cookie，再读取 `Accept-Language` 标头，最后回退到 `defaultLocale`。如果你的根路由已有 `loader`，请在其返回的对象中添加 `locale` 和 `translations`。

*注意：缺少根加载器数据的错误页面 (例如直接访问的 404 页面或根加载器出错时) 会在没有 [`GTProvider`](/docs/react/reference/components/gt-provider) 的情况下渲染。在这些页面中，翻译组件和 hooks (例如 [`<T>`](/docs/react/reference/components/t) 和 [`useLocale`](/docs/react/reference/hooks/use-locale)) 会抛出错误，导致错误页面变为服务器端错误，因此请勿对根路由的 `ErrorBoundary` 进行翻译。*

### 5. 标记待翻译内容

使用 [`<T>`](/docs/react/reference/components/t) 组件包裹 JSX，即可原地翻译；对于 `aria-label` 值等普通字符串，请使用 [`useGT`](/docs/react/reference/hooks/use-gt)。再添加一个 [`<LocaleSelector>`](/docs/react/reference/components/locale-selector)，方便访问者切换语言。

```tsx title="app/routes/home.tsx"
import { LocaleSelector, T, useGT } from 'gt-react';

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

  return (
    <main>
      <LocaleSelector />
      <T>
        <h1>Welcome to my app</h1>
        <p>This content is translated automatically.</p>
      </T>
      <input aria-label={gt('Email address')} />
    </main>
  );
}
```

当访问者选择语言后，[`<LocaleSelector>`](/docs/react/reference/components/locale-selector) 会将所选语言保存到区域设置 cookie 中并重新加载页面，使根加载器按新的区域设置进行渲染。

### 6. 生成译文

使用 [`gt login`](/docs/cli/reference/commands/login) 登录，在 `gt.config.json` 中设置现有项目的 [`projectId`](/docs/cli/reference/config#project-id) (或在环境变量中设置 `GT_PROJECT_ID`) ，然后执行翻译：

```bash
npx gt login
GT_PROJECT_ID=your-project-id npx gt translate
```

登录后不会自动选择项目。如果你还没有项目，可以在[控制台](/docs/platform/dashboard/get-started)中创建，也可以运行 [`gt init`](/docs/cli/reference/commands/init) 并启用开发时实时翻译，在此过程中选择或创建项目。

启动开发服务器并切换语言，即可查看翻译效果。将该命令添加到现有构建脚本的最前面，确保生产环境构建始终包含最新翻译：

```json title="package.json"
{
  "scripts": {
    "build": "npx gt translate && react-router build"
  }
}
```

如需从 CDN 加载译文而非将其打包到应用中，请运行 [`npx gt configure --storage cdn`](/docs/cli/reference/commands/configure)。该命令会列出需要在 `app/root.tsx` 中做出的修改。

如果你会缓存文档响应 (例如在 CDN 或反向代理上) ，请按区域设置区分缓存，以免访问者收到其他语言的页面。你可以在文档响应中发送 `Vary: Cookie, Accept-Language`，或者不让共享缓存存储这些响应。

<Callout type="info">
  **注意：** 在 CI 中，请通过密钥设置提供一个单独限定作用域的 `GT_API_KEY`，以及相同的项目 ID。 (参见 [CLI 凭据](/docs/cli/guides/configuring#credentials)。) 
</Callout>

## Shopify Hydrogen [#hydrogen]

Hydrogen 店面属于 React Router 框架应用，因此步骤完全相同。保留 Hydrogen 自带的构建命令，只需在其前面加上翻译生成命令：

```json title="package.json"
{
  "scripts": {
    "build": "npx gt translate && shopify hydrogen build --codegen"
  }
}
```

`gt-react` 负责翻译店面代码中的文本，例如导航、按钮和页面文案。商品标题、描述及其他店铺内容来自 Shopify，这些内容请在 Shopify 中翻译。

## 故障排除 [#troubleshooting]

<Accordions>
  <Accordion title="gt init 未修改 app/root.tsx">
    向导只会编辑结构与 create-react-router 或 Hydrogen 起始模板一致、且尚未调用 [`initializeGT`](/docs/react/reference/config#initialize) 的根文件。请按照[步骤 4](#quickstart) 手动完成修改。
  </Accordion>

  <Accordion title="gt init 在修改前就已停止">
    修复方法取决于停止的原因：

    * **SPA 模式、预渲染或 RSC 框架模式：** 此方案会在每次请求时于根加载器中读取每位访问者的区域设置，因此无论使用向导还是手动配置，均不支持这些模式。
    * **`gt-react` 的版本范围允许低于 11.1.3 的版本：** 请升级 `gt-react`，然后重新运行 `npx gt@latest init`。
    * **`appDirectory` 不是 `app`，或向导无法读取 `react-router.config`：** 如果应用在每次请求时渲染，请运行 `npx gt@latest init --no-react-setup`，完成除源代码之外的全部设置，然后按照步骤 2 至 4 操作，并将 `app/` 替换为你的应用目录 (`files.gt.output` 中也需一并替换) 。
  </Accordion>

  <Accordion title="使用选择器时语言没有切换">
    请确认 cookie 已启用、该区域设置已添加到 `gt.config.json` 中，且选择器在 `RootGTProvider` 内部渲染。如果 `<html lang>` 已变化但文本未变，请运行 [`npx gt translate`](/docs/cli/reference/commands/translate) 来填充 `app/_gt/[locale].json`。
  </Accordion>
</Accordions>

## Next steps

- /docs/react/guides/translating-jsx
- /docs/react/guides/translating-strings
- /docs/react/guides/managing-locales
- /docs/react/guides/storing-translations

## Sitemap

See the full [sitemap](https://generaltranslation.com/sitemap.md) for all pages.
