跳到內容

多語系支援與閱讀切換

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 設定裡,兩處保持一致。


如何切換語言

  1. 在頁面頂部導覽列右側找到語言按鈕(顯示目前語言的縮寫,如 ZH);
  2. 點擊按鈕,下拉選單列出全部 10 種語言;
  3. 點擊目標語言(例如 English 或 日本語);
  4. 瀏覽器跳轉到目前這篇文章的目標語言版本,導覽、側邊欄、目錄與內文一起變成目標語言。

多語系切換下拉選單展開時的真實標註效果:① 語言按鈕 ② 語言列表 ③ 目前語言

圖:在《多語系支援與閱讀切換》頁點擊語言按鈕後的實際標註效果。① 頂欄右側的語言切換按鈕;② 展開的下拉選單,列出全部 10 種語言(列表可捲動);③ 目前生效的語言(帶對勾標記)。

多語系切換工作機制示意圖

圖:語言切換的執行流程。建置時每種語言產生一套靜態頁面,點擊語言按鈕即跳轉到對應語言的同一篇文章;個別頁面缺少譯文時自動回退顯示中文。


URL 規則

每種語言的頁面有獨立的 URL 前綴,同一篇文章在不同語言下只有前綴不同:

/canvas/i18n/ → 簡體中文(預設語言,無前綴)
/en/canvas/i18n/ → 英文
/ja/canvas/i18n/ → 日文
/zh-tw/canvas/i18n/ → 繁體中文
  • 語言資訊直接編碼在 URL 裡,切換後的頁面可以直接加入書籤、分享,搜尋引擎也能按語言分別收錄;
  • 頁面內出現的站內連結(導覽、側邊欄、內文中的推薦連結)都會自動帶上目前語言的前綴,讀者在某一語言內連續閱讀時不會跳回中文頁;
  • 每個語言版本都是建置期產生的獨立靜態頁面,頁面的 <html lang> 屬性與語言一致,螢幕閱讀器和翻譯工具可以正確識別。

譯文缺失怎麼辦

系統按「預設語言回退」的策略處理缺失譯文:某篇文件還沒有某語言的譯文時,存取該語言的頁面會顯示預設的簡體中文內容,頁面其餘部分(導覽、側邊欄、介面文字)仍然是目標語言,不會出現 404 錯誤或空白頁。

這一策略的好處是:新增文件時不需要等所有語言的譯文就緒,先發布中文版,譯文補齊後再重新建置即可。


實作原理

多語系能力由 Astro 與 Starlight 的國際化機制承載,建置流程如下:

  1. 內容目錄按語言劃分:預設語言的文件放在 src/content/docs/(簡體中文),其他語言放在 src/content/docs/<語言>/ 下,目錄結構與中文完全對應,例如英文版《多語系支援與閱讀切換》是 src/content/docs/en/canvas/i18n.md;
  2. 建置期產生全部語言頁面:astro build 讀取 astro.config.mjs 中的 locales 設定,為每種語言產生一套完整靜態頁面;
  3. 介面字串按語言渲染:頂欄導覽、搜尋提示、目錄標題等介面文字由各元件呼叫 getTranslation(key, lang) 在建置期直接輸出對應語言,頁面裡沒有執行時替換腳本;
  4. 內文內部連結自動在地化:建置管線中的 rehypeLocalizeInternalLinks 外掛會把譯文內文裡的 /canvas/xxx 內部連結自動加上目前語言前綴;
  5. 全文搜尋按語言隔離:Pagefind 為每種語言建立獨立索引,在英文頁面搜尋只會回傳英文結果。
  6. 內文圖片依語言自動回退:rehypeLocalizeDiagramImages 外掛將譯文內文中的 /images/canvas/<檔名> 改寫為 /images/canvas/<語言>/<檔名>,對應語言的圖片放在 public/images/canvas/<語言>/ 下;沒有同名檔時保留原圖,新增一張圖不必同時備齊 10 種語言;
  7. 提示框與註腳依語言輸出:rehypeLocalizeAsides 與 rehypeLocalizeFootnotes 依原始檔所在語言目錄改寫提示框標題與註腳文字——Starlight 在 remark 階段以檔案絕對路徑推斷語言,而本機建置傳給它的是相對路徑,不處理就會全部回退成中文;
  8. hreflang 與 404 頁:hreflangXDefault() 於建置完成後為每個頁面補一條 hreflang="x-default",指向簡體中文版本;src/pages/404.astro 沿用同一份詞條字典,依瀏覽器語言輸出提示文字,頁面上的語言選單指向各語言首頁。

開發者:如何新增一種語言?

以新增義大利文(Italiano,代碼 it)為例:

  1. 註冊語言路由:在 astro.config.mjs 的 locales 中加入 it: { label: 'Italiano', lang: 'it' };
  2. 補充側邊欄文案:在同一檔案的 SIDEBAR_I18N 中為全部分組與條目補上 it 的翻譯;
  3. 補充介面字串:在 src/utils/i18n.ts 的 SUPPORTED_LANGUAGES 中登記語言清單(代碼、名稱、縮寫、URL 前綴),並在 UI_TRANSLATIONS 中補齊該語言的介面字串;
  4. 翻譯文件內容:新建 src/content/docs/it/ 目錄,按中文版的目錄結構放入譯文。未翻譯的頁面會先回退顯示中文,可以逐步補齊;若需翻譯介面截圖與架構圖,另建 public/images/canvas/it/ 目錄放入同名檔,頁面會自動引用。
  5. 重新建置:執行 pnpm run build,新語言頁面與搜尋索引即產生。建置後執行 node scripts/audit-i18n.mjs 與 node scripts/check-localized-images.mjs 覆核譯文結構與圖片引用,這兩項在 CI 中為必修檢查。

開發者:如何新增或修改介面字串?

新增介面元素時,在 src/utils/i18n.ts 的 UI_TRANSLATIONS 中補充字串:

src/utils/i18n.ts
// 字典按「語言 → 字串鍵」兩層組織,與 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>

字串在建置期渲染為對應語言的靜態文字,沒有執行時開銷。