跳到正文
svedocs

多语言

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

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

配置语言

TypeScriptsvedocs.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
hreflangSEO 元数据和文档 lang 属性使用的 BCP 47 语言标签,默认等于 code
dir文档方向,可选 ltrrtl,默认是 ltr

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

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

组织内容

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

Text
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/docsen-US/docs
content/docs/zh/index.md/docs/zhzh-Hans/docs
content/docs/ar/guides/deploy.md/docs/ar/guides/deployar/docs/guides/deploy
content/pages/en/index.md/en-US/
content/pages/zh/index.md/zhzh-Hans/

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

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

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

本地化站点外壳

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

TypeScriptsvedocs.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、目录、文章操作、代码工具、首页卡片、错误页和渲染错误。项目也可以添加自定义键。导航、社交链接、页脚和首页操作项都支持 labelKeybrand.labelKeyhome.kickerKeyhome.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 扩展名也会被正确处理:

Markdown
继续阅读[部署指南](../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 临时开启:

TypeScriptsvedocs.config.ts
export default defineConfig({ checks: { translations: true }});
Shell
svedocs check --translationssvedocs check --translations --strict

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

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