國際化
國際化(i18n)
星羅內建中英雙語 UI 支援,採用 prefixDefaultLocale: false 路由策略,預設語言無 URL 前綴。
路由策略
Astro 的 i18n 設定(見 astro.config.ts):
tsi18n: { locales: ["zh-cn", "en"], defaultLocale: "zh-cn", routing: { prefixDefaultLocale: false }, }
關鍵:prefixDefaultLocale: false 不會自動生成在地化頁面副本,需手動維護 [locale]/ 鏡像路由。
星羅的落地方式:
- 根目錄頁面 = 預設語言(
zh-cn),URL 無前綴,如/posts/welcome/ src/pages/[locale]/下鏡像全部頁面,getStaticPaths用getLocaleParams()僅生成非預設語言,如/en/posts/welcome/- 鏡像頁面同樣是薄包裝,渲染邏輯複用同一 View 元件
/ → 首頁(zh-cn) /en/ → 首頁(en) /posts/welcome/ → 文章(zh-cn) /en/posts/welcome/ → 文章(en)
locale 解析
View 元件內部使用 Astro.currentLocale 自動解析:
- 根目錄頁 →
zh-cn [locale]段頁 →en(或其他非預設語言)
無需在元件層判斷路徑,useTranslations(locale) 直接取得對應語言文案。
i18n 模組結構
| 檔案 | 職責 |
|---|---|
index.ts | import.meta.glob("./lang/*.ts", {eager:true}) 載入語言;匯出 DEFAULT_LOCALE、LOCALES、useTranslations(locale)、tplStr |
types.ts | UIStrings 完整介面(所有需在地化的字串) |
routing.ts | getLocalePrefix、withLocale(path, locale)、parseLocaleFromPath(pathname) |
staticPaths.ts | NON_DEFAULT_LOCALES、getLocaleParams() |
format.ts | tplStr(template, vars) — {{key}} 佔位符替換 |
lang/zh-cn.ts | 簡體中文(預設語言) |
lang/en.ts | 英文 |
UIStrings 結構
UIStrings 介面定義所有需在地化的介面字串,分組組織:
nav:導航(home/posts/tags/about/archives/search/rss)post:文章(日期、分享、標籤、返回、編輯、目錄、程式碼複製、圖片燈箱等)pagination:分頁home:首頁(社交連結、精選、最新)archives:歸檔(計數、月份)footer:頁尾(版權)pages:各頁面標題與描述a11y:無障礙標籤languageSwitcher:語言切換器notFound:404comments:評論區
模板字串
帶佔位符的文案用 {{key}},配合 tplStr 替換:
tsimport { tplStr } from "@/i18n"; // archives.postCount = "{{count}} 篇" tplStr(t.archives.postCount, { count: 5 }); // "5 篇"
SEO 多語言宣告
Layout.astro 的 head 輸出:
- 各語言
<link rel="alternate" hreflang="..." href="..."> x-default指向預設語言- sitemap 整合啟用 i18n 設定,自動生成 hreflang
- 非預設語言文章的 canonical 指向預設語言原文(避免重複內容判定,詳見 SEO)
新增語言
以新增日語 ja 為例:
astro.config.ts的i18n.locales與 sitemapi18n.locales新增"ja"與"ja-JP"對應src/i18n/lang/建立ja.ts,匯出完整的UIStrings(可複製en.ts翻譯)src/i18n/staticPaths.ts的NON_DEFAULT_LOCALES自動包含ja(基於LOCALES計算)src/pages/[locale]/鏡像頁面自動生成ja版本(getLocaleParams已覆蓋)- 語言切換器:在
zh-cn.ts與en.ts的languageSwitcher.names新增"ja": "日本語"
內容級翻譯
星羅支援文章內容的多語言翻譯,透過 locale 與 translationKey 兩個 frontmatter 欄位實作。
基本用法
- 預設語言文章放在
src/content/posts/<slug>.md,設定translationKey作為分組標識:
yaml# src/content/posts/welcome.md --- title: "歡迎來到星羅" locale: zh-cn translationKey: welcome-to-xingluo tags: [公告, Astro] ---
- 譯文放在語言子目錄
src/content/posts/en/<slug>.md,使用相同的translationKey:
yaml# src/content/posts/en/welcome.md --- title: "Welcome to Xingluo" locale: en translationKey: welcome-to-xingluo tags: [announcement, Astro] ---
目錄結構
src/content/posts/ ├── welcome.md # 預設語言(zh-cn) ├── en/ │ └── welcome.md # 英文譯文 ├── ja/ │ └── welcome.md # 日文譯文 └── another-post.md # 獨立文章(未設定 translationKey)
- 語言子目錄名需與
astro.config.ts的i18n.locales中的語言代碼一致 - 語言子目錄會被路由層過濾,不進入 URL slug(如
/posts/welcome/而非/posts/en/welcome/) - 無
translationKey的文章各自獨立,不在任何語言間關聯
路由行為
| 場景 | 行為 |
|---|---|
預設語言存取 zh-cn 文章 | 渲染預設語言原文 |
| 非預設語言存取有譯文的文章 | 渲染對應語言的譯文 |
| 非預設語言存取無譯文的文章 | 回退渲染預設語言原文(內容一致,non-duplicate canonical 保障 SEO) |
列表去重
列表頁(首頁、文章列表、標籤、歸檔、RSS)使用 getPostsForLocale 按語言選取代表文章:每組譯文只顯示一條對應語言的卡片,避免同主題譯文重複出現。
canonical 與 SEO
- 有獨立譯文:canonical 指向譯文自身 URL,搜尋引擎可獨立索引
- 無譯文(回退):canonical 指向預設語言原文,避免重複內容懲罰
- hreflang 宣告覆蓋全部語言,搜尋引擎理解各語言版本關係
詳見 SEO。