
在 NextJS 中使用 i18n 的指南
目前專案在 NextJS App router, SSG/ISR 環境中 使用到 i18n, 此篇紀錄設定
安裝需求
在專案中安裝以下套件:
- i18next:核心國際化框架
- react-i18next:React 綁定
- i18next-browser-languagedetector:用於檢測瀏覽器語言
- i18next-resources-to-backend:用於動態加載翻譯資源
- react-cookie:用於管理語言偏好設置的 cookie
Installation
npm install i18next react-i18next i18next-browser-languagedetector i18next-resources-to-backend react-cookie
配置步驟
1. 路徑和文件夾設置
在 app 文件夾中設置動態路由文件夾 [lng]。所有其他路徑(文件夾)將存儲在此文件夾下。
app ├── [lng] │ └── 所有路徑文件夾 └── i18n ├── locales ├── client.ts // Client Component 的配置和 useTranslation 函數 ├── index.ts // Server Component 的配置和 useTranslation 函數 ├── setting.ts └── lang.ts // 從 URL 獲取當前語言
2. 建立 i18n 配置文件
client.ts : 建立Client Component i18n 設置的配置文件
"use client"; import { useEffect, useState } from "react"; import i18next from "i18next"; import { initReactI18next, useTranslation as useTranslationOrg, } from "react-i18next"; import { useCookies } from "react-cookie"; import resourcesToBackend from "i18next-resources-to-backend"; import LanguageDetector from "i18next-browser-languagedetector"; import { getOptions, languages, cookieName } from "./setting"; // 檢查代碼是否在Server端運行 const runsOnServerSide = typeof window === "undefined"; // 初始化 i18next i18next .use(initReactI18next) // 將 i18n 傳遞給 react-i18next .use(LanguageDetector) // 使用語言檢測器 .use( resourcesToBackend( (lng: string, ns: string) => import(`./locales/${lng}/${ns}.json`) ) ) // 動態加載翻譯 .init({ ...getOptions(), lng: undefined, // 讓Client檢測語言 detection: { order: ["path", "htmlTag", "cookie", "navigator"], }, preload: runsOnServerSide ? languages : [], // 在Server端預加載所有語言 }); // 自定義 useTranslation hook export function useTranslation(lng?: string, ns?: string, options?: {}) { const [cookies, setCookie] = useCookies([cookieName]); const ret = useTranslationOrg(ns, options); const { i18n } = ret; if (runsOnServerSide && lng && i18n.resolvedLanguage !== lng) { i18n.changeLanguage(lng); } else { // Client語言處理 const [activeLng, setActiveLng] = useState(i18n.resolvedLanguage); // 當解析的語言變更時更新活動語言 useEffect(() => { if (activeLng === i18n.resolvedLanguage) return; setActiveLng(i18n.resolvedLanguage); }, [activeLng, i18n.resolvedLanguage]); // 當 lng prop 變更時改變語言 useEffect(() => { if (!lng || i18n.resolvedLanguage === lng) return; i18n.changeLanguage(lng); }, [lng, i18n]); // 當語言變更時更新 cookie useEffect(() => { if (cookies.i18next === lng) return; setCookie(cookieName, lng, { path: "/" }); }, [lng, cookies.i18next, setCookie]); } return { ...ret }; }
3. index.ts : 建立Server Component i18n 設置的配置文件
// 默認語言 export const fallbackLng = "en"; // 支持的語言 export const languages = [fallbackLng, "zh-Hant"]; // 存儲語言偏好的 cookie 名稱 export const cookieName = 'i18next' // 默認命名空間 export const defaultNS = "translation"; // 獲取 i18next 選項的函數 export function getOptions(lng = fallbackLng, ns = defaultNS) { return { debug: true, supportedLngs: languages, fallbackLng, lng, fallbackNS: defaultNS, defaultNS, ns, }; }
4. 建立翻譯文件
在 app/i18n/locales/ 目錄下為每種語言建立翻譯文件,例如:
- app/i18n/locales/en/common.json
- app/i18n/locales/zh/common.json
5. 使用翻譯
在Client Component 中:
"use client"; import { useTranslation } from "../i18n/client"; import { CurrentLang } from "../i18n/lang"; export default function ClientComponent() { const lang = CurrentLang(); // 獲取當前語言 const { t } = useTranslation(lang, "common"); return <h1>{t('welcome')}</h1>; // 使用翻譯 }
在Server端 Component 中:
import { useTranslation } from "../i18n"; export default async function ServerComponent({ params: { lng } }) { const { t } = await useTranslation(lng, "common"); return <h1>{t('welcome')}</h1>; // 使用翻譯 }
注意事項
- 確保在 next.config.js 中正確配置了 i18n 設置。
- 對於動態路由,確保在 app/[lng] 文件夾中正確處理語言設置。
- 獲取當前語言設置:可以從 params 傳下來,若無法從 params 傳下來,則使用 CurrentLang() 函數來獲取當前語言設置。
- 在Client Component 和Server端 Component 中使用不同的 useTranslation 導入方式。
- Client和Server端的 i18next 配置略有不同,需要注意區分使用。