多語系支援與閱讀切換
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>字串在建置期渲染為對應語言的靜態文字,沒有執行時開銷。