多语言支持与阅读切换
EpoCanvas Docs 内置了完整的内容级多语言:导航栏、侧边栏、搜索提示等界面文字,以及每一篇文档的正文,都提供 10 种语言的独立版本。读者在页面右上角选择语言后,会跳转到同一篇文章的目标语言版本,正文与界面一起切换。
支持的语言列表
站点目前提供 10 种语言,其中简体中文是默认语言:
| 语言 | 语言名称 | URL 前缀 | 界面缩写 |
|---|---|---|---|
| 简体中文 | 简体中文(默认) | 无前缀 | ZH |
| 繁體中文 | 繁體中文 | /zh-tw/ | TW |
| English | 英语 | /en/ | EN |
| 日本語 | 日语 | /ja/ | JA |
| 한국어 | 韩语 | /ko/ | KO |
| Español | 西班牙语 | /es/ | ES |
| Français | 法语 | /fr/ | FR |
| Deutsch | 德语 | /de/ | DE |
| Русский | 俄语 | /ru/ | RU |
| Português | 葡萄牙语 | /pt/ | PT |
语言清单定义在 src/utils/i18n.ts 的 SUPPORTED_LANGUAGES 中,语言路由注册在 astro.config.mjs 的 locales 配置里,两处保持一致。
如何切换语言
- 在页面顶部导航栏右侧找到语言按钮(显示当前语言的缩写,如
ZH); - 点击按钮,下拉菜单列出全部 10 种语言;
- 点击目标语言(例如
English或日本語); - 浏览器跳转到当前这篇文章的目标语言版本,导航、侧边栏、目录与正文一起变成目标语言。

图:在《多语言支持与阅读切换》页点击语言按钮后的实际标注效果。① 顶栏右侧的语言切换按钮;② 展开的下拉菜单,列出全部 10 种语言(列表可滚动);③ 当前生效的语言(带对勾标记)。
图:语言切换的执行流程。构建时每种语言生成一套静态页面,点击语言按钮即跳转到对应语言的同一篇文章;个别页面缺少译文时自动回退显示中文。
URL 规则
每种语言的页面有独立的 URL 前缀,同一篇文章在不同语言下只有前缀不同:
/canvas/i18n/ → 简体中文(默认语言,无前缀)/en/canvas/i18n/ → 英文/ja/canvas/i18n/ → 日文/zh-tw/canvas/i18n/ → 繁体中文- 语言信息直接编码在 URL 里,切换后的页面可以直接收藏、分享,搜索引擎也能按语言分别收录;
- 页面内出现的站内链接(导航、侧边栏、正文中的推荐链接)都会自动带上当前语言的前缀,读者在某一语言内连续阅读时不会跳回中文页;
- 每个语言版本都是构建期生成的独立静态页面,页面的
<html lang>属性与语言一致,屏幕阅读器和翻译工具可以正确识别。
译文缺失怎么办
系统按”默认语言兜底”的策略处理缺失译文:某篇文档还没有某语言的译文时,访问该语言的页面会显示默认的简体中文内容,页面其余部分(导航、侧边栏、界面文字)仍然是目标语言,不会出现 404 报错或空白页。
这一策略的好处是:新增文档时不需要等所有语言的译文就绪,先发布中文版,译文补齐后再重新构建即可。
实现原理
多语言能力由 Astro 与 Starlight 的国际化机制承载,构建流程如下:
- 内容目录按语言划分:默认语言的文档放在
src/content/docs/(简体中文),其他语言放在src/content/docs/<语言>/下,目录结构与中文完全对应,例如英文版《多语言支持与阅读切换》是src/content/docs/en/canvas/i18n.md; - 构建期生成全部语言页面:
astro build读取astro.config.mjs中的locales配置,为每种语言生成一套完整静态页面; - 界面词条按语言渲染:顶栏导航、搜索提示、目录标题等界面文字由各组件调用
getTranslation(key, lang)在构建期直接输出对应语言,页面里没有运行时替换脚本; - 正文内链自动本地化:构建管线中的
rehypeLocalizeInternalLinks插件会把译文正文里的/canvas/xxx内链自动加上当前语言前缀; - 全文搜索按语言隔离:Pagefind 为每种语言建立独立索引,在英文页面搜索只会返回英文结果。
- 正文图片按语言自动回退:
rehypeLocalizeDiagramImages插件把译文正文里的/images/canvas/<文件名>改写为/images/canvas/<语言>/<文件名>,对应语言的图片放在public/images/canvas/<语言>/下;没有同名文件时保留原图,新增一张图不必同时配齐 10 种语言; - 提示框与脚注按语言输出:
rehypeLocalizeAsides与rehypeLocalizeFootnotes按源文件所在语言目录改写提示框标题和脚注文案——Starlight 在 remark 阶段按文件绝对路径推断语言,本机构建传给它的是相对路径,不处理就会全部回落成中文; - hreflang 与 404 页:
hreflangXDefault()在构建完成后为每个页面补一条hreflang="x-default",指向简体中文版本;src/pages/404.astro复用同一份词条字典按浏览器语言输出提示文案,页面上的语言菜单指向各语言首页。
开发者:如何新增一种语言?
以新增意大利语(Italiano,代码 it)为例:
- 注册语言路由:在
astro.config.mjs的locales中加入it: { label: 'Italiano', lang: 'it' }; - 补充侧边栏文案:在同一文件的
SIDEBAR_I18N中为全部分组与条目补上it的翻译; - 补充界面词条:在
src/utils/i18n.ts的SUPPORTED_LANGUAGES中登记语言清单(代码、名称、缩写、URL 前缀),并在UI_TRANSLATIONS中补齐该语言的界面词条; - 翻译文档内容:新建
src/content/docs/it/目录,按中文版的目录结构放入译文。未翻译的页面会先回退显示中文,可以逐步补齐;如需翻译界面截图与架构图,另建public/images/canvas/it/目录放入同名文件,页面会自动引用。 - 重新构建:运行
pnpm run build,新语言页面与搜索索引即生成。构建后运行node scripts/audit-i18n.mjs和node scripts/check-localized-images.mjs复核译文结构与图片引用,这两项在 CI 中是必过检查。
开发者:如何新增或修改界面词条?
新增界面元素时,在 src/utils/i18n.ts 的 UI_TRANSLATIONS 中补充词条:
// 字典按「语言 → 词条键」两级组织,与 getTranslation 的读取顺序一致export const UI_TRANSLATIONS: Record<string, Record<string, string>> = { // 第一步:在默认语言 zh-CN 里加词条(缺失时界面回退显示键名) 'zh-CN': { 'nav.plugins': '插件生态', // ...其余已有词条 }, // 第二步:给其它语言补同一键名的翻译,没补的语言自动回退中文 en: { 'nav.plugins': 'Plugins', }, ja: { 'nav.plugins': 'プラグイン', },};然后在组件中调用 getTranslation 并传入当前语言:
---import { getLangFromLocale, getTranslation } from '../../utils/i18n';const lang = getLangFromLocale(Astro.currentLocale);---
<a href={localizedHref('/plugins/', lang)}>{getTranslation('nav.plugins', lang)}</a>词条在构建期渲染为对应语言的静态文字,没有运行时开销。