---
title: "多语言"
description: "组织多语言内容、路由、界面文案、搜索范围和 SEO 多语言链接。"
---

> Documentation Index
> Fetch the complete documentation index at: https://svedocs.pwp.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# 多语言

多语言站点不只是换掉几条界面文案。svedocs 会为每个页面记录所属语言，让路由、导航、搜索结果、Ask AI 引用、HTML 语言属性和 SEO 多语言链接保持一致。

## 配置语言

```ts title="svedocs.config.ts"
import { defineConfig } from 'svedocs/config';

export default defineConfig({
  site: {
    name: 'Acme Docs',
    url: 'https://docs.acme.com'
  },
  i18n: {
    defaultLocale: 'en-US',
    prefixDefaultLocale: false,
    locales: [
      {
        code: 'en-US',
        label: 'English',
        path: 'en',
        hreflang: 'en-US',
        dir: 'ltr'
      },
      {
        code: 'zh-Hans',
        label: '中文',
        path: 'zh',
        hreflang: 'zh-CN',
        dir: 'ltr'
      },
      {
        code: 'ar',
        label: 'العربية',
        path: 'ar',
        hreflang: 'ar',
        dir: 'rtl'
      }
    ]
  }
});
```

这些字段分别表示内部标识、公开 URL 和标准语言标签：

| 字段 | 作用 |
| --- | --- |
| `code` | 稳定的内部标识，会写入页面、搜索记录和 AI 过滤条件。 |
| `label` | 语言切换器显示的名称，建议使用该语言自己的写法。 |
| `path` | 用于发现内容和生成路由的单个目录名和 URL 路径段，默认等于 `code`。 |
| `hreflang` | SEO 元数据和文档 `lang` 属性使用的 BCP 47 语言标签，默认等于 `code`。 |
| `dir` | 文档方向，可选 `ltr` 或 `rtl`，默认是 `ltr`。 |

把 `code` 和 `path` 分开后，可以用 `zh-Hans` 作为稳定标识，同时提供更短的 `/zh` 路由。以后即使公开 URL 发生变化，搜索过滤条件和已存数据也不必跟着修改。

svedocs 会在发现内容前检查语言配置。以下情况会直接报错：`code`、`path` 或语言标签重复，`defaultLocale` 指向未配置的语言，路径为空、包含多段或不适合放入 URL，路径与 `/docs` 冲突，以及 `messages` 使用了未配置的语言。重复检查不区分大小写，因此不会受到宿主文件系统影响。

## 组织内容

在两个内容根目录下，都使用语言的 `path` 作为第一层目录：

```txt
content/
├── docs/
│   ├── en/
│   │   ├── index.md
│   │   └── guides/deploy.md
│   ├── zh/
│   │   ├── index.md
│   │   └── guides/deploy.md
│   └── ar/
│       ├── index.md
│       └── guides/deploy.md
└── pages/
    ├── en/index.md
    ├── zh/index.md
    └── ar/index.md
```

当 `defaultLocale: 'en-US'` 且 `prefixDefaultLocale: false` 时，路由映射如下：

| 源文件 | 路由 | 语言代码 | 翻译分组 |
| --- | --- | --- | --- |
| `content/docs/en/index.md` | `/docs` | `en-US` | `/docs` |
| `content/docs/zh/index.md` | `/docs/zh` | `zh-Hans` | `/docs` |
| `content/docs/ar/guides/deploy.md` | `/docs/ar/guides/deploy` | `ar` | `/docs/guides/deploy` |
| `content/pages/en/index.md` | `/` | `en-US` | `/` |
| `content/pages/zh/index.md` | `/zh` | `zh-Hans` | `/` |

如果要求每个公开 URL 都带语言路径，设置 `prefixDefaultLocale: true`。上面的英文路由会变成 `/docs/en` 和 `/en`。

默认语言文件也可以直接放在 `content/docs` 和 `content/pages` 下。根目录文件与默认语言目录二选一，不要同时维护，否则对应文件会生成重复路由。使用彼此镜像的语言目录更容易比对，也方便日后调整 URL 前缀策略。

除了正文，也要翻译 frontmatter。标题、描述、`navTitle`、关键词和有意义的图片替代文本都会出现在导航、搜索或页面元数据中。各语言目录里的对应文件应保持相同的相对路径，这样 svedocs 才能把它们识别为同一页面的不同译本。

## 本地化站点外壳

`i18n.messages` 可以按语言覆盖默认主题文案。没有提供的值会使用英文基础文案。

```ts title="svedocs.config.ts"
export default defineConfig({
  theme: {
    nav: [
      { label: 'Docs', labelKey: 'nav.docs', href: '/docs' },
      { label: 'Guides', labelKey: 'nav.guides', href: '/docs/guides' }
    ],
    home: {
      primaryAction: {
        label: 'Read the guides',
        labelKey: 'home.readGuides',
        href: '/docs/guides'
      }
    }
  },
  i18n: {
    defaultLocale: 'en',
    locales: ['en', 'zh'],
    messages: {
      en: {
        'nav.guides': 'Guides',
        'home.readGuides': 'Read the guides'
      },
      zh: {
        'nav.guides': '指南',
        'home.readGuides': '阅读指南',
        'search.placeholder': '搜索文档',
        'ask.label': '问 AI'
      }
    }
  }
});
```

内建文案键覆盖导航、搜索、Ask AI、目录、文章操作、代码工具、首页卡片、错误页和渲染错误。项目也可以添加自定义键。导航、社交链接、页脚和首页操作项都支持 `labelKey`；`brand.labelKey`、`home.kickerKey` 和 `home.visual.altKey` 的用法相同。普通文本字段仍然是默认值，在没有对应翻译时显示。

自定义组件可以从 `SvedocsThemeContext` 同时读取内部语言代码和 HTML 语言标签：

```svelte
<script lang="ts">
  import type { SvedocsThemeContext } from 'svedocs/theme/types';

  export let context: SvedocsThemeContext;
</script>

<p lang={context.languageTag} dir={context.locale?.dir ?? 'ltr'}>
  {context.t('home.readGuides')}
</p>
```

过滤条件和持久化状态使用 `context.localeCode`；HTML 属性和按语言格式化数据时使用 `context.languageTag`。

## 自动匹配多语言链接

对于品牌、顶部导航、社交链接、页脚、首页操作和 Markdown 正文中的站内链接，svedocs 会查找当前语言下的对应页面。因此中文页面上的 `/docs/guides` 配置链接，在译文存在时会变成 `/docs/zh/guides`。

语言切换器使用相同的页面映射。如果当前页面没有某种语言的译文，对应选项会被禁用，不会让用户误以为译文存在。其他站内链接会在当前语言内容缺失时指向默认语言页面。用户直接请求缺少译文的本地化 URL 时，edge 构建会返回临时 HTTP 307 重定向；static 和 SPA 构建会为每个可确定的兜底路径预渲染等效的跳转文档，因此即使静态主机本身不返回 307，浏览器仍会进入默认语言的 canonical 页面。默认语言页面也不存在时仍返回 404。

镜像文件之间的相对 Markdown 链接会被解析为实际生成的路由，链接中的 `.md`、`.mdx` 或 `.svx` 扩展名也会被正确处理：

```md
继续阅读[部署指南](../guides/deploy.md)。
```

不带语言的绝对链接 `/docs/guides/deploy` 也会按相同规则本地化。明确写出的语言路由（例如 `/docs/zh/guides/deploy`）会尊重作者指定的语言；query 和标题 fragment 会完整保留。

自定义 Svelte 或主题组件可以使用 `LocalizedLink`，在浏览器端复用同一套规则：

```svelte
<script lang="ts">
  import { LocalizedLink } from 'svedocs/theme';
  import type { SvedocsThemeContext } from 'svedocs/theme/types';

  export let context: SvedocsThemeContext;
</script>

<LocalizedLink {context} href="/docs/guides/deploy">部署</LocalizedLink>
```

## 搜索与 Ask AI

页面和章节搜索记录都会带上 `metadata.locale = code`。使用默认的 `scope: 'current'` 时，搜索与 Ask AI 请求会包含当前语言代码，不会混入其他语言的结果。只有确实需要跨语言结果时，才把服务的 `scope` 设为 `all`。

托管索引必须把 `locale` 保留为可过滤字段。内建的 Algolia、Typesense、Cloudflare AI Search 和本地适配器都会自动传递这个过滤条件。

## SEO 与文档语言

设置 `site.url` 后，svedocs 才能生成绝对 canonical URL 和对应的多语言 URL。每组翻译会生成：

- 当前路由的 canonical URL。
- 只指向真实存在翻译的双向 `hreflang` 链接。
- 翻译存在时，指向默认语言页面的 `x-default`。
- 站点地图中使用相同映射的多语言链接。
- Open Graph 当前语言和真实存在的其他语言。
- JSON-LD `inLanguage`。
- 来自 `languageTag` 的 `<html lang>` 和来自 `dir` 的 `<html dir>`。

缺失的译文不会出现在 Open Graph 或 `hreflang` 多语言声明中。自定义根布局应调用 `createPageMetadata(config, page, pages)`，以便根据完整页面列表生成 Open Graph 的语言映射。

## 检查翻译覆盖率

可以在项目里启用检查，也可以通过 CLI 临时开启：

```ts title="svedocs.config.ts"
export default defineConfig({
  checks: {
    translations: true
  }
});
```

```sh
svedocs check --translations
svedocs check --translations --strict
```

检查会按相对路径匹配公开文档和独立页面，并报告缺少哪种已配置语言。隐藏页面不参与检查；使用 `--strict` 时，警告也会让命令失败。

每次新增、重命名或删除译文后都应运行检查。发布前还应至少测试每种语言的一个路由、语言切换器中的一个缺失译文，以及一个对应语言的 404 路由。

Source: https://svedocs.pwp.sh/docs/zh/configuration/i18n
