# @dts-stn/react-router-i18n-routes 中文文档

规范地址：https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/

版本：1\.0\.1
npm 元数据更新时间：2026-10-18T20:21:21.612Z
中文译文更新时间：2026-11-12T23:48:35.946Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40dts-stn/react-router-i18n-routes
原文对照：https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/?lang=original
项目主页：https://github.com/STN-DTS/react-router-i18n-routes#readme
源码仓库：https://github.com/STN-DTS/react-router-i18n-routes

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：121 kB，19 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=20\.0\.0
- 运行依赖：0 个
- peer 依赖：react \>=18\.0\.0，react-router ^7\.0\.0 \|\| ^8\.0\.0，@react-router/dev ^7\.0\.0 \|\| ^8\.0\.0
- 首次发布：2026-10-18T19:05:22.813Z
- 最新版本发布：2026-10-18T19:11:13.403Z
- 近 30 天下载量：2909（2026-10-13 至 2026-11-11，npm 官方下载统计）
- 已发布版本数：3（近 12 个月 3 个）

## 中文简介

类型安全,为React Routers(帧模式)所翻译的(i18n)路由定义.

## 安装

```sh
npm install @dts-stn/react-router-i18n-routes
```

也可以使用：`pnpm add @dts-stn/react-router-i18n-routes`、`yarn add @dts-stn/react-router-i18n-routes`、`bun add @dts-stn/react-router-i18n-routes`

## README

# @dts-stn/ react-router-i18n-routes (英语)

[![npm version](https://img.shields.io/npm/v/@dts-stn/react-router-i18n-routes)](https://www.npmjs.com/package/@dts-stn/react-router-i18n-routes) [![CI](https://github.com/STN-DTS/react-router-i18n-routes/actions/workflows/ci.yaml/badge.svg)](https://github.com/STN-DTS/react-router-i18n-routes/actions/workflows/ci.yaml) [![types: TypeScript](https://img.shields.io/badge/types-TypeScript-3178c6)](https://www.typescriptlang.org/) [![license: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/STN-DTS/react-router-i18n-routes/blob/main/LICENSE)

**类型安全, 翻译 URL for [反应路由器](https://reactrouter.com/) 框架模式.**

申报每页一次,每种语言都有路径. 您可以得到 React 路由器路由配置, 本地化链接和 重新定向,语言检测,和一个语言切换器. 每个路由文件和语言都是字符串字元类型,所以 断开的链接是编译错误,而不是404.

```ts
const i18nRoutes = defineI18nRoutes([
  {
    id: 'CASE-0001',
    file: 'routes/case.tsx',
    paths: { en: '/en/case/:caseId', fr: '/fr/dossier/:caseId' },
  },
]);

const i18nRouting = createI18nRouting(i18nRoutes);

i18nRouting.getPath('routes/case.tsx', 'fr', { params: { caseId: '42' } }); // '/fr/dossier/42'
i18nRouting.translatePath('/en/case/42', 'fr'); // '/fr/dossier/42'
i18nRouting.getPath('routes/case.tsx', 'de'); // ❌ type error: 'de' is not a supported language
i18nRouting.getPath('routes/cases.tsx', 'en'); // ❌ type error: no such route file
```

## 为什么?

A 类 `/:lang/...` 当只有语言段更改时,前缀就足够了。 许多地点,包括政府驻地 官方语文规则、需要 **完全翻译路径** 相反: `/en/dashboard` 财务报告和审定财务报表 `/fr/tableau-de-bord`进行中 通过手工方式,每个语言登记每一页,保持路径同步,并重复绘图 每一个链接、方向和语言切换。 这个软件包保留了一个路线表,并构建了它以外的一切.

## 特征

-   🗺️ **一个真理的来源.** 每页声明一次,React路由器获得每个语言的一个路由.
-   🔒 **完全输入, 不 `as const`。 。 。 .** 路由文件、身份证和语言被推断为文字结合。 未知的文件, 排版文件,编译时拒绝不支持的语言.
-   🔗 **链接和重定向.** `<I18nLink>` 替换 `<Link>`,以及 `redirect()` 正在建设 `Response`s 用于装载器和 动作,有参数,搜索和散列.
-   🌐 **语言切换.** `<I18nLanguageSwitchLink>` 链接到其它语言的当前页面并保留其 parms,搜索,和散列.
-   🧭 **URL匹配 .** URL 使用 React Router 自身的排名映射回路由和语言, 所以静态片段总是 击败动态的.
-   🗣️ **语言谈判.** 语言来自 URL, 有可选的 `Accept-Language` 倒计时.
-   ✅ **失败的验证.** 重复的ID或文件,缺少翻译,以及启动时抛出的路由ID相撞.
-   🪶 **小而可树.** 仅限无害环境管理, `sideEffects: false`,没有运行时间依赖 超出它的同行,它的工作 与回放18和19以及回放路由器7和8.

## 目录

-   [安装](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-installation)
-   [快开始](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-quick-start)
-   [概念](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-concepts)
-   [食谱](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-recipes)
-   [API 参考](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-api-reference)
-   [行为细节](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-behavior-details)
-   [财务问题](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-faq)
-   [捐款](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-contributing)
-   [许可证](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-license)

## 安装

```sh
npm install @dts-stn/react-router-i18n-routes
# or
pnpm add @dts-stn/react-router-i18n-routes
# or
yarn add @dts-stn/react-router-i18n-routes
```

### 所需资源

| 软件包 | 版本 | 需要时间 |
| --- | --- | --- |
| `react-router` | `^7.0.0 || ^8.0.0` | 所有的东西 |
| `react` | `>=18.0.0` | [`@dts-stn/react-router-i18n-routes/react`](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-dts-stnreact-router-i18n-routesreact) |
| `@react-router/dev` | `^7.0.0 || ^8.0.0` | [`@dts-stn/react-router-i18n-routes/route-config`](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-dts-stnreact-router-i18n-routesroute-config) |

`react` 财务报告和审定财务报表 `@react-router/dev` 是可选的同伴。 只有当您使用需要的切入点时才安装它们 .

软件包是 **仅限无害环境管理** 并且需要20号或以后的节点。 类型推论依赖 [`const` 类型参数](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html#const-type-parameters), (中文(简体) ), 因此,需要TypeScript 5.0或更晚.

### 入境点

| 导入路径 | 目录 | 从 |
| --- | --- | --- |
| `@dts-stn/react-router-i18n-routes` | 路线定义, `createI18nRouting()`类型和错误 | 任何地方(客户端和服务器) |
| `@dts-stn/react-router-i18n-routes/react` | 钩和连接组件 | 反应组件 |
| `@dts-stn/react-router-i18n-routes/route-config` | 转换为 React 路由器路由配置 | `app/routes.ts` |

## 快开始

### 1\. 确定路线

将定义保留在自己的模块中这样 `app/routes.ts`,组件、装载器和动作都可以导入.

```ts
// app/i18n-routes.ts
import type { I18nLanguageOf, I18nRouteFileOf } from '@dts-stn/react-router-i18n-routes';
import { createI18nRouting, defineI18nRoutes } from '@dts-stn/react-router-i18n-routes';

export const i18nRoutes = defineI18nRoutes([
  {
    id: 'HOME-0001',
    file: 'routes/index.tsx',
    paths: { en: '/en/', fr: '/fr/' },
  },
  {
    // A pathless layout route
    file: 'routes/protected/layout.tsx',
    children: [
      {
        id: 'DASH-0001',
        file: 'routes/protected/dashboard.tsx',
        paths: { en: '/en/dashboard', fr: '/fr/tableau-de-bord' },
      },
      {
        id: 'CASE-0001',
        file: 'routes/protected/case.tsx',
        paths: { en: '/en/case/:caseId', fr: '/fr/dossier/:caseId' },
      },
    ],
  },
]);

export const i18nRouting = createI18nRouting(i18nRoutes);

export type I18nRouteFile = I18nRouteFileOf<typeof i18nRoutes>;
// 'routes/index.tsx' | 'routes/protected/dashboard.tsx' | 'routes/protected/case.tsx'

export type Language = I18nLanguageOf<typeof i18nRoutes>;
// 'en' | 'fr'
```

### 2\. 用回放路由器登记路线

```ts
// app/routes.ts
import type { RouteConfig } from '@react-router/dev/routes';
import { route } from '@react-router/dev/routes';

import { toRouteConfigEntries } from '@dts-stn/react-router-i18n-routes/route-config';

import { i18nRoutes } from './i18n-routes';

export default [
  route('/api/health', 'routes/api/health.ts'), // non-translated routes work as usual
  ...toRouteConfigEntries(i18nRoutes),
] satisfies RouteConfig;
```

> \[大 反应路由器的配置加载器不能解决路径的别名, 例如 `~/`,所以导入定义到 `app/routes.ts` 和相对路径.

### 3\. 连接、重新定向和切换语言

```tsx
import {
  I18nLanguageSwitchLink,
  I18nLink,
  useIsCurrentRoute,
  useIsNavigatingTo,
  useLanguage,
} from '@dts-stn/react-router-i18n-routes/react';

import { i18nRouting } from '~/i18n-routes';

export function Navigation() {
  const { alternateLanguage } = useLanguage(i18nRouting);
  const isDashboard = useIsCurrentRoute(i18nRouting, 'routes/protected/dashboard.tsx');
  const isLoadingCase = useIsNavigatingTo(i18nRouting, 'routes/protected/case.tsx', { params: { caseId: '42' } });

  return (
    <nav>
      {/* Links to the current language by default */}
      <I18nLink routing={i18nRouting} file="routes/protected/dashboard.tsx" aria-current={isDashboard ? 'page' : undefined}>
        Dashboard
      </I18nLink>

      {/* Any React Router <Link> prop is forwarded */}
      <I18nLink
        routing={i18nRouting}
        file="routes/protected/case.tsx"
        params={{ caseId: '42' }}
        search="tab=notes"
        prefetch="intent"
      >
        Case 42 {isLoadingCase && '…'}
      </I18nLink>

      {/* The current page in the other language, with the same params, search, and hash */}
      <I18nLanguageSwitchLink routing={i18nRouting}>
        {alternateLanguage === 'fr' ? 'Français' : 'English'}
      </I18nLanguageSwitchLink>
    </nav>
  );
}
```

```ts
// app/routes/protected/layout.tsx
import { i18nRouting } from '~/i18n-routes';

import type { Route } from './+types/layout';

export function loader({ request }: Route.LoaderArgs) {
  if (!isSignedIn(request)) {
    const language = i18nRouting.getLanguage(request) ?? 'en';
    throw i18nRouting.redirect('routes/index.tsx', language);
  }
}
```

就是这样。 每个 `file`, (中文(简体) ), `language`,以及 `params` 以上值的键入 `app/i18n-routes.ts`。 。 。 .

## 概念

### 页路由

一个页面路由有一个 `id`,路径模块 `file`,以及每种语言的路径:

```ts
{ id: 'DASH-0001', file: 'routes/protected/dashboard.tsx', paths: { en: '/en/dashboard', fr: '/fr/tableau-de-bord' } }
```

-   **`file`** 是路由模块,相对于应用程序目录,如: `app/routes.ts`。这也是 **查找密钥**数字 : 链接、重定向和钩子是指其文件中的一页.
-   **`paths`** 使用 React 路由器路径语法:活性区段( R)`:caseId`),可选部分(`:tab?`),和花板 (单位:千美元)`*`)所有作业. 每个页面路径必须声明 **同一套语言**。 。 。 .
-   **`id`** 必须是独一无二的。 React 路由器每个语言获得一条路由,并带有 id `${id}-${LANGUAGE}` (单位:千美元)`DASH-0001-EN`, (中文(简体) ), `DASH-0001-FR`) (中文(简体) ). 把这些身份传递给 `useRouteLoaderData()`,或用 [`getI18nRouteId()`](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-geti18nrouteidid-language)。 。 。 .

### 布局路线

一个布局路线有一个 `file` 财务报告和审定财务报表 `children` 但是没有 `id` 或者说 `paths`。它会变成一个无路径回放路由器 `layout()` 路径 让孩子度过难关 `<Outlet />`,用于认证卫士、共享铬和共享 装载机 布局可以筑巢. 排版不能成为链接目标, 因此将排版文件传递到 `getPath()` 是类型 错误.

### 路径实例

`createI18nRouting(i18nRoutes)` 验证定义一次并返回 [`I18nRouting`](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-i18nrouting) 对象,每个查找和 URL 构建器。 在模块级别创建并导入一次 无论需要什么 反应钩和组件 把它当作他们的第一个论据或 `routing` 道具 (英语).

## 食谱

### 设定 `<html lang>` 在根布局中

```tsx
// app/root.tsx
import type { ReactNode } from 'react';

import { Links, Meta, Scripts, ScrollRestoration } from 'react-router';

import { useCurrentLanguage } from '@dts-stn/react-router-i18n-routes/react';

import { i18nRouting } from '~/i18n-routes';

export function Layout({ children }: { children: ReactNode }) {
  const language = useCurrentLanguage(i18nRouting) ?? 'en';

  return (
    <html lang={language}>
      <head>
        <Meta />
        <Links />
      </head>
      <body>
        {children}
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  );
}
```

### 重定向 `/` 改为客家首选语言

在 i18n 路由旁注册一个平面索引路由,并谈判语言 `Accept-Language` 页眉 :

```ts
// app/routes.ts
export default [index('routes/language-redirect.ts'), ...toRouteConfigEntries(i18nRoutes)] satisfies RouteConfig;
```

```ts
// app/routes/language-redirect.ts
import { i18nRouting } from '~/i18n-routes';

import type { Route } from './+types/language-redirect';

export function loader({ request }: Route.LoaderArgs) {
  // The language of the URL path, then the Accept-Language header, then English
  const language = i18nRouting.getLanguage(request, { acceptLanguage: true }) ?? 'en';
  return i18nRouting.redirect('routes/index.tsx', language);
}
```

### 用正确的语言显示404页

`getLanguage()` 当没有页面路由匹配时, 返回到第一个路径段, 所以一个覆盖所有路由仍然知道 `/fr/page-inexistante` 法语:

```ts
// app/routes.ts
export default [...toRouteConfigEntries(i18nRoutes), route('*', 'routes/not-found.tsx')] satisfies RouteConfig;
```

```tsx
// app/routes/not-found.tsx
export default function NotFound() {
  const language = useCurrentLanguage(i18nRouting) ?? 'en';
  return <h1>{language === 'fr' ? 'Page introuvable' : 'Page not found'}</h1>;
}
```

### 添加 `hreflang` sEO 的替代链接

```tsx
import { useLocation } from 'react-router';

import { i18nRouting } from '~/i18n-routes';

const ORIGIN = 'https://www.example.com';

export function AlternateLinks() {
  const { pathname } = useLocation();

  return i18nRouting.languages.map((language) => {
    const path = i18nRouting.translatePath(pathname, language);
    return path && <link key={language} rel="alternate" hrefLang={language} href={new URL(path, ORIGIN).href} />;
  });
}
```

渲染器 `<AlternateLinks />` 内部 `<head>` 内 `app/root.tsx`。 。 。 .

### 支持三种或三种以上语言

`alternateLanguage` 仅适用于双语应用程序。 更多语言,列表 `alternateLanguages` 并传递每个 `I18nLanguageSwitchLink`数字 :

```tsx
const LANGUAGE_NAMES = { en: 'English', fr: 'Français', es: 'Español' } as const;

export function LanguageMenu() {
  const { alternateLanguages } = useLanguage(i18nRouting);

  return (
    <ul>
      {alternateLanguages.map((language) => (
        <li key={language}>
          <I18nLanguageSwitchLink routing={i18nRouting} language={language}>
            {LANGUAGE_NAMES[language]}
          </I18nLanguageSwitchLink>
        </li>
      ))}
    </ul>
  );
}
```

`I18nLanguageSwitchLink` 套装 `lang` 财务报告和审定财务报表 `hrefLang` 编辑 `<a>`,所以屏幕阅读器宣告每个语言名称 对.

### 切换语言时重新装入文档

如果每个文档都装入过一次翻译( 例如, 服务器上创建的 i18next 实例), 则通过 `reloadDocument` 这样切换语言就可以完成一个完整的页面负载 :

```tsx
<I18nLanguageSwitchLink routing={i18nRouting} reloadDocument>
  Français
</I18nLanguageSwitchLink>
```

### 构建特定应用链接组件

捆绑 `routing` 和默认样式 :

```tsx
import type { I18nLinkProps } from '@dts-stn/react-router-i18n-routes/react';
import { I18nLink } from '@dts-stn/react-router-i18n-routes/react';

import type { i18nRoutes } from '~/i18n-routes';
import { i18nRouting } from '~/i18n-routes';

export function AppLink(props: Omit<I18nLinkProps<typeof i18nRoutes>, 'routing'>) {
  return <I18nLink routing={i18nRouting} className="underline" {...props} />;
}
```

```tsx
<AppLink file="routes/protected/dashboard.tsx">Dashboard</AppLink> // ✅
<AppLink file="routes/protected/dashbord.tsx">Dashboard</AppLink> // ❌ type error
```

用于非链接导航( U)`navigate()`, (中文(简体) ), `<Form action>`, (中文(简体) ), `fetcher.submit()`),使用时 [`useI18nPath()`](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-usei18npathrouting-file-options) 建造道路.

### 处理路由错误

包扔出的每一个错误都是 `I18nRoutingError` 有机器可读 `code`数字 :

```ts
import { I18nRoutingError } from '@dts-stn/react-router-i18n-routes';

try {
  const { route, language, params } = i18nRouting.getRouteByPath(pathname);
} catch (error) {
  if (error instanceof I18nRoutingError && error.code === 'ROUTE_NOT_FOUND') {
    // ...
  }
  throw error;
}
```

这个 `find*` 方法返回 `undefined` 而不是扔, 这往往更简单.

## API 参考

### `@dts-stn/react-router-i18n-routes`

#### `defineI18nRoutes(routes)`

回返 `routes` 不变,按文字键入,无 `as const` 需要帮助。 使用它来声明路由表.

#### `createI18nRouting(routes)`

验证路径并返回一个 [`I18nRouting`](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-i18nrouting) 举个例子 掷出 `I18nRoutingError` 有代码 `INVALID_ROUTES` 如果:

-   两个页面路由共享 an `id` 或一个 `file`, (中文(简体) ),
-   页面路由并非全部声明相同的语言,或者
-   两个路由/语言对生成相同的React Router路由id. 例如,语言 `en` 财务报告和审定财务报表 `EN` 碰撞,这样 执行路由 `PAGE` 使用语言 `fr-CA` 和路线 `PAGE-FR` 使用语言 `ca`,两者均生成 `PAGE-FR-CA`。 。 。 .

#### `I18nRouting`

| 成员 | 回返 | 说明 |
| --- | --- | --- |
| `routes` | `T` | 路线定义. |
| `languages` | `Language[]` | 支持的语言,按声明顺序排列. |
| `getPath(file, language, options?)` | `string` | 本地化,根相通的路径. `options`数字 : `params`, (中文(简体) ), `search` (单位:千美元)`string` 或者说 `URLSearchParams`, (中文(简体) ), `hash`。 。 。 . |
| `redirect(file, language, options?)` | `Response` | 重定向到 `getPath()`。 。 。 . `options.init` 设置状态( 默认) `302`或全数 `ResponseInit`。 。 。 . |
| `translatePath(pathname, language, options?)` | `string | undefined` | 匹配的页面路由在另一种语言中的路径,保留其参数(`/en/case/42` → `/fr/dossier/42`) (中文(简体) ). `options`数字 : `search`, (中文(简体) ), `hash`。 。 。 . |
| `getLanguage(resource, options?)` | `Language | undefined` | 路径名的语言, `URL`,或 `Request`。见 [语言检测](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-language-detection)。 。 。 . |
| `getAlternateLanguages(language)` | `Language[]` | 其他按声明顺序支持语言. |
| `findRouteByPath(pathname)` | `{ route, language, params } | undefined` | 将路径名匹配到页面路由和语言. |
| `getRouteByPath(pathname)` | `{ route, language, params }` | 与 `findRouteByPath()`但抛出 `ROUTE_NOT_FOUND`。 。 。 . |
| `findRouteByFile(file)` | `PageRoute | undefined` | 文件的页面路由 。 接受任意字符串,以便测试未知值. |
| `getRouteByFile(file)` | `PageRoute` | 已知文件的页面路由, 输入为准确路由 。 掷出 `ROUTE_NOT_FOUND`。 。 。 . |

#### `getI18nRouteId(id, language)`

页面路由中的一种语言的回放路由器路由ID: `getI18nRouteId('DASH-0001', 'fr')` → `'DASH-0001-FR'`。 。 。 .

#### `negotiateLanguage(acceptLanguage, languages)`

最佳支持语言 `Accept-Language` 页眉值,或 `undefined`。见 [语言检测](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-language-detection)。 。 。 .

```ts
negotiateLanguage('fr-CA,fr;q=0.9,en;q=0.8', ['en', 'fr']); // 'fr'
```

#### `isI18nPageRoute(value)`, (中文(简体) ), `isI18nLayoutRoute(value)`

为行走路线定义而设的护卫类型.

#### `I18nRoutingError`

包抛出的错误 。 内容 `code` 这是:

| 代码 | 掷出时 |
| --- | --- |
| `INVALID_ROUTES` | `createI18nRouting()` 发现定义不一致. |
| `ROUTE_NOT_FOUND` | 没有页面路由匹配文件或路径名传递到一个 `get*` 方法. |
| `LANGUAGE_NOT_DETERMINED` | `useI18nPath()` 或者说 `I18nLink` 得到没有 `language` 而当前 URL 没有. |

#### 类型

| 类型 | 说明 |
| --- | --- |
| `I18nRoute<L>`, (中文(简体) ), `I18nPageRoute<L>`, (中文(简体) ), `I18nLayoutRoute<L>` | 路由定义类型, 通用于语言联盟 `L`。 。 。 . |
| `I18nPaths<L>` | `{ [language]: path }`。 。 。 . |
| `I18nRouteFileOf<T>` | 页面路由文件在 `typeof routes`。 。 。 . |
| `I18nRouteIdOf<T>` | 页面路由代码的结合. |
| `I18nLanguageOf<T>` | 宣布的语言联盟 _每个_ 页面路由. |
| `I18nPageRouteOf<T>` | 页面路由定义的结合. |
| `I18nPageRouteForFile<T, F>` | 文件的页面路由 `F` (返回类型 `getRouteByFile()`) (中文(简体) ). |
| `I18nRouting<T>`, (中文(简体) ), `I18nRouteMatch<T>` | 路径实例和结果 `findRouteByPath()`。 。 。 . |
| `I18nPathOptions`, (中文(简体) ), `I18nRedirectOptions`, (中文(简体) ), `I18nTranslatePathOptions`, (中文(简体) ), `I18nLanguageOptions` | 联合国 `I18nRouting` 方法。 。 . |
| `I18nRoutingErrorCode` | 错误代码的结合. |

类型帮助者也接受广泛的类型,例如 `I18nRoute<'en' | 'fr'>[]`。对于这些,文件和身份证决心 `string` 和声明的联盟的语言.

### `@dts-stn/react-router-i18n-routes/react`

每个钩子和元件都把路由实例当作它的第一论据(呼克)或 `routing` 道具(组件). 全体人员 他们从React路由器读取当前位置,所以必须在路由器内渲染出.

#### `useLanguage(routing)`

回返 `{ currentLanguage, alternateLanguage, alternateLanguages }` 用于当前位置. `alternateLanguage` 设定 只有另外一种语言,即双语语言.

#### `useCurrentLanguage(routing)`

当前位置的语言,或 `undefined` (单位:千美元)`routing.getLanguage(pathname)`) (中文(简体) ).

#### `useI18nRouteMatch(routing)`

`{ route, language, params }` 用于当前位置,或 `undefined` (单位:千美元)`routing.findRouteByPath(pathname)`) (中文(简体) ).

#### `useI18nPath(routing, file, options?)`

`routing.getPath()`,与 `options.language` 默认为当前语言。 掷出 `LANGUAGE_NOT_DETERMINED` 若为 两者皆无。 用它来 `navigate()`, (中文(简体) ), `<Form action>`,其他需要路径而不是链接的任何东西.

#### `useLanguageSwitchPath(routing, language?)`

当前页 `language` (默认:替代语言),保留其参数,搜索和散列. 回返 `undefined` 在i18n路线之外.

#### `useIsCurrentRoute(routing, file, options?)`

当前位置是否 `file`任何语言的页面路线。 与 `options.params`,匹配的路径的参数 也必须平等。 用它来 `aria-current="page"`。 。 。 .

#### `useIsNavigatingTo(routing, file, options?)`

是否导航到 `file`页面路由正在装入 . `options.language` 默认为当前语言,并且 `options.params` 还比较了匹配路线的参数. 用于待定指标。 需要数据路由器 (框架模式, `createBrowserRouter()`,或 `createMemoryRouter()`) (中文(简体) ).

对于两者 `useIsCurrentRoute()` 财务报告和审定财务报表 `useIsNavigatingTo()`数字 :

-   `file` 也许 `undefined` (结果就是 `false`)),所以你可以从其组件中无条件称呼它们 链接并不总是 i18n 路由.
-   `options.params` 仅比较匹配的路由本身的参数, 这样您就可以通过完整 `useParams()` 对象.

#### `<I18nLink>`

反应路由器 `<Link>` 谁 `to` 道具替换为 `routing`, (中文(简体) ), `file`选择 `language`, (中文(简体) ), `params`, (中文(简体) ), `search`,以及 `hash`。语言默认为当前语言。 每一个 `<Link>` 道具,包括 `ref`, (中文(简体) ), `prefetch`,以及 `viewTransition`页:1.

#### `<I18nLanguageSwitchLink>`

未设置的回放路由器 `<Link>` 改为 [`useLanguageSwitchPath()`](https://npmcn.com/package/%40dts-stn/react-router-i18n-routes/#readme-uselanguageswitchpathrouting-language),与 `lang` 财务报告和审定财务报表 `hrefLang` 设置到目标语言。 内容 `to` 道具替换为 `routing` 和可选 `language`。 所有其他 道具,包括 `ref` 财务报告和审定财务报表 `reloadDocument`页:1 它在i18n路线之外没有任何东西.

### `@dts-stn/react-router-i18n-routes/route-config`

| 导出 | 说明 |
| --- | --- |
| `toRouteConfigEntries(routes)` | 将路由定义转换为 React Router 路由配置条目, 递归式 . |
| `toPageRouteConfigEntries(pageRoute)` | 将一个页面路由转换为每个语言的一个条目,以便在树外注册. |

此切入点仅取决于 `@react-router/dev/routes`,因此从 `app/routes.ts`。 。 。 .

## 行为细节

### 路径匹配

`findRouteByPath()`, (中文(简体) ), `translatePath()`, (中文(简体) ), `getLanguage()`,而钩子与路由器的路径名匹配 `matchRoutes()` 跨越每一页路线和语言。 结果:

-   静态片段胜过动态片段, 动态片段胜过平板, 不管宣布的顺序,
-   随从的鞭打,是被忽视的,
-   %- 编码路径名被解码,以及
-   路径名称与应用程序相对 `basename`。 。 。 .

### 路径生成

`getPath()` 使用响应路由器 `generatePath()`因此:

-   缺少所需的抛出物,
-   接后鞭打被去除(`/en/` → `/en`, (中文(简体) ),
-   结果总是从 `/`,即使没有一条道路被宣布(`en/about` → `/en/about`链接 从未相对于当前 URL 解析,以及
-   静态片段、搜索和散列按申报方式返回(`/fr/à-propos`) (中文(简体) ).

`redirect()` %- encode 非 ASCII 字符 `Location` 页眉 (e)`/fr/%C3%A0-propos`)并留有 逃逸率不变.

### 语言检测

`getLanguage(resource)` 按顺序尝试 :

1.  匹配页面路由的语言,
2.  第一个路径段,如果它是一个支持的语言(`/fr/anything` → `fr`),以及
3.  仅使用 `{ acceptLanguage: true }` (单位:千美元) `Request`,则 `Accept-Language` 标题, 使用 `negotiateLanguage()`。 。 。 .

`negotiateLanguage()` 尝试下行质量顺序的偏好, 链接保持标题顺序 。 确切地说, 大小写不敏感匹配获胜。 要不然就比较初级亚种,所以 `fr-CA` 匹配 `fr` 财务报告和审定财务报表 `fr` 匹配 `fr-CA`。 。 。 . 条目 `q=0`,则 `*` 通配符,以及错误的条目被忽略.

饼干,会话,用户偏好被故意留给应用程序处理. 先读一下,然后回到 `getLanguage()`。 。 。 .

## 财务问题

**它能翻译我的内容吗?** 没有。 它只处理URL. 与任何翻译库(i18next, react-intl,Lingui,.)对等,并传入语言 从 `useCurrentLanguage()` 或者说 `getLanguage()`。 。 。 .

**一个页面能否只用一种语言存在?** 不是作为i18n路由:每个页面路由必须声明每种语言,这保证了语言切换器总是 有目标 使用 React 路由器自行注册的单语页 `route()` 内 `app/routes.ts`。 。 。 .

**我可以用一个 `/:lang/...` 样式而不是翻译路径 ?** 对 道路是简单的线条,所以 `{ en: '/en/about', fr: '/fr/about' }` 和被翻译的子弹一样有效.

**它是否在声明式或数据模式下工作(无 `app/routes.ts`{\\fn黑体\\fs22\\bord1\\shad0\\3aHBE\\4aH00\\fscx67\\fscy66\\2cHFFFFFF\\3cH808080}你觉得呢?** 核心入站和回放钩与任何路由器配合. `/route-config` 专门针对框架模式,以及 `useIsNavigatingTo()` 需要数据路由器。 在其他模式中,从 `i18nRoutes` 与 `getI18nRouteId()`。 。 。 .

**为什么路由识别像 `DASH-0001-EN`? 吗?** 反应路由器每条路由需要独有的ID,每一页成为每条语言的一个路由. 使用您喜欢的任何 ID 方案 大写后缀为后缀.

## 捐款

欢迎提出问题和拉动请求。 见 [捐款额](https://github.com/STN-DTS/react-router-i18n-routes/blob/main/CONTRIBUTING.md) 用于开发设置和发布过程.

## 许可证

[麻省理工学院](https://github.com/STN-DTS/react-router-i18n-routes/blob/main/LICENSE)

## 常见问题

### @dts-stn/react-router-i18n-routes 是什么？

类型安全,为React Routers\(帧模式\)所翻译的\(i18n\)路由定义\.

### 如何安装 @dts-stn/react-router-i18n-routes？

在项目目录运行 npm install @dts-stn/react-router-i18n-routes，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：react-router（^7\.0\.0 \|\| ^8\.0\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @dts-stn/react-router-i18n-routes 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @dts-stn/react-router-i18n-routes 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @dts-stn/react-router-i18n-routes 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=20\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @dts-stn/react-router-i18n-routes 可以商用吗？

@dts-stn/react-router-i18n-routes 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @dts-stn/react-router-i18n-routes 的下载量有多少？

根据 npm 官方下载统计，@dts-stn/react-router-i18n-routes 在 2026/10/13 – 2026/11/11 这 30 天内被下载 2,909 次，日均约 97 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @dts-stn/react-router-i18n-routes 还在维护吗？

最新版本 1\.0\.1 发布于 2026/10/19（25 天前）；至今共发布 3 个版本，其中过去 12 个月发布了 3 个；首次发布于 2026/10/19。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

