國際化(i18n):
用 next-intl 讓你的網站說多國語言
next-intl 路由配置、訊息格式化、複數規則、日期貨幣本地化 — 打造真正的多語言 Next.js 應用
Section 1:i18n 不只是「翻譯文字」
很多人以為國際化(Internationalization,縮寫 i18n)只是把字串換成別的語言,但這只是最基礎的一層。真正讓用戶感覺「這個產品是為我打造的」,需要處理五個不同的層面——每一個都有各自的複雜度,也都有對應的工具。
文字翻譯
hello → 你好 → こんにちは
最基礎的層面,把 UI 上的文字對應到不同語言的版本。
複數規則
1 apple vs 2 apples
英文有 singular/plural 兩種,阿拉伯文竟然有 6 種複數形式!每種語言規則不同。
日期格式
2026/05/07 vs May 7, 2026 vs 07.05.2026
台灣、美國、德國對日期的書寫順序和分隔符號都有不同慣例。
貨幣格式
NT$1,500 vs $1,500.00 vs ¥1,500
貨幣符號的位置、小數點符號(. 還是 ,)、千分位分隔符號都因地而異。
文字方向
LTR vs RTL
英文從左到右(LTR),阿拉伯文和希伯來文從右到左(RTL),整個版面配置都需要翻轉。
時區與地域
UTC+8 vs UTC-5 vs ...
顯示時間時需要考量用戶所在時區,同一個時間戳在不同地區呈現不同時間。
next-intl vs 其他方案比較
react-i18next(最多人用)
✓ 生態最大,社群資源豐富
✓ 支援眾多框架
✗ Next.js 整合需要額外配置
✗ 沒有原生 App Router 支援
✗ Server Component 中使用較複雜
next-intl(最適合 Next.js)
✓ 原生支援 App Router
✓ Server Component 直接可用
✓ TypeScript 型別安全
✓ 效能好(Server-side 翻譯)
✓ 翻譯 key 輸入錯誤時 TS 報錯
為什麼 Server-side 翻譯更好?
傳統 Client-side i18n 需要在瀏覽器下載語言包後才能渲染,用戶會先看到未翻譯的內容(FOUC)。next-intl 讓翻譯在伺服器端就完成,HTML 到瀏覽器時已經是正確語言,載入速度更快、SEO 更好。
Section 2:專案設定與目錄結構
next-intl 的核心概念是把所有路由包在 [locale] 動態路段下。這個 locale 參數由 Middleware 自動偵測並注入,你的 Page 元件不需要手動處理語言偵測邏輯。
目錄結構
重要:所有需要多語言的 Page 都必須移動到 app/[locale]/ 目錄下。原本放在 app/ 根目錄的 Page 需要整個搬移,這是 next-intl App Router 整合的必要結構。
localePrefix: 'as-needed' 的 URL 結果
Section 3:訊息檔案設計與使用
翻譯訊息以 JSON 格式存在 messages/ 目錄中,每個語言一個檔案。JSON 結構支援巢狀命名空間(namespace),讓你依功能或頁面分組管理翻譯 key。
在 Server Component 與 Client Component 中使用
Server Component 優勢
- • 翻譯包不會被打包進 JS bundle
- • 沒有語言包的載入延遲
- • SEO 直接拿到翻譯後的 HTML
- • 不需要 Suspense 包裹
Client Component 注意事項
- • 需要在父層 Server Component 中提供翻譯
- • 透過 NextIntlClientProvider 傳遞
- • 可以只傳對應 namespace 的翻譯,節省 bundle 大小
- • 動態語言切換在 Client Component 中直接生效
Section 4:複數規則與格式化
next-intl 使用 ICU(International Components for Unicode)訊息格式,這是業界標準的多語言訊息格式,支援插值、複數、選擇等複雜的本地化需求。理解 ICU 格式是用好 next-intl 的關鍵。
複數規則(各語言不同)
各語言的複數複雜度
日期、時間、貨幣格式化
Section 5:語言切換器與 SEO 配置
語言切換器(Locale Switcher)讓用戶手動切換語言。實作的關鍵是:切換語言後,應該停在同一個頁面,只是換成新語言的版本,而不是跳回首頁。next-intl 提供了 useRouter 的擴充版本來處理這件事。
SEO 多語言 Meta 設定(hreflang)
hreflang 是告訴 Google「這個頁面有其他語言版本」的標準方式。設定正確的 hreflang 能讓 Google 對不同語言的用戶顯示對應版本的頁面,提升搜尋排名和用戶體驗。
hreflang 常見錯誤
- • hreflang 必須是雙向的:zh-TW 版本要指向 en,en 版本也要指向 zh-TW。
- • 每個語言版本都要包含指向自己的 hreflang(self-referencing)。
- • x-default 通常指向你的預設語言或語言選擇頁面。
- • 語言代碼要用標準 BCP 47 格式(zh-TW 而非 zh_TW)。
Section 6:TypeScript 型別安全 + 最佳實踐
next-intl 最強大的功能之一是完整的 TypeScript 型別安全。透過一個型別宣告,讓 TypeScript 知道你的翻譯 JSON 結構,之後只要打錯任何 key 名稱,編譯期就會報錯,完全避免「翻譯 key 不存在導致顯示空白」的 Bug。
翻譯 Key 命名最佳實踐
好的結構:按功能/頁面分組
✗ 不好的結構:一層扁平
常見陷阱與解法
問題:翻譯不同步(英文新增了 key 但中文忘記加)
解法:使用 i18n Ally(VS Code 擴充套件)或 CI 中加入翻譯完整性檢查腳本,確保所有語言的 key 一致。
問題:硬編碼字串混入 JSX(忘了用 t())
解法:設定 ESLint 規則 i18next/no-literal-string,讓 Linter 提醒你有字串沒有透過翻譯函式。
問題:翻譯包太大,影響 Client Component 效能
解法:在 NextIntlClientProvider 中只傳入該 Component 需要的 namespace,而不是整個翻譯包。
問題:RTL(右到左)語言版面跑版
解法:在 <html> 標籤加上 dir={locale === "ar" || locale === "he" ? "rtl" : "ltr"},並使用 Tailwind 的 rtl: 前綴處理鏡像版面。
i18n 不是最後才加的功能
很多專案會在「需要國際化了」的時候才開始加 i18n,結果發現要重構的地方滿坑滿谷。正確做法是:從第一天起就用 t() 來輸出文字,即使初期只有一種語言也這樣做。等到真的需要多語言支援時,只需要新增翻譯檔,而不是重構整個 UI。
上一篇
EP.34 Next.js Middleware
Middleware · Edge Runtime · Rate Limiting
下一篇
EP.36
Coming Soon