[Lv3] Nuxt 3 多語系 (i18n) 與 SEO 最佳實踐
在 SSR 架構下實作多語系(Internationalization),不只是翻譯文字,更涉及路由策略、SEO 標籤(hreflang)、狀態管理與 Hydration 一致性。
1. 面試回答主軸
- 路由策略:使用
@nuxtjs/i18n的 URL 前綴策略(如/en/about,/jp/about)來區分語系,這對 SEO 最友善。 - SEO 標籤:確保自動生成正確的
<link rel="alternate" hreflang="..." />與 Canonical URL,避免重複內容懲罰。 - 狀態管理:在 SSR 階段正確偵測使用者語系(Cookie/Header),並確保 Client 端 Hydration 時語 系一致。
2. Nuxt 3 i18n 實作策略
2.1 為什麼選擇 @nuxtjs/i18n?
官方模組 @nuxtjs/i18n 是基於 vue-i18n,專為 Nuxt 優化。它解決了手動實作 i18n 常遇到的痛點:
- 自動產生帶語系前綴的路由 (Auto-generated routes)。
- 自動處理 SEO Meta Tags (hreflang, og:locale)。
- 支援 Lazy Loading 語言包(優化 Bundle Size)。
2.2 安裝與配置
npm install @nuxtjs/i18n
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
locales: [
{ code: 'en', iso: 'en-US', file: 'en.json', name: 'English' },
{ code: 'tw', iso: 'zh-TW', file: 'tw.json', name: '繁體中文' },
],
defaultLocale: 'tw',
lazy: true, // 啟用 Lazy Loading
langDir: 'locales', // 語言檔目錄
strategy: 'prefix_and_default', // 關鍵路由策略
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected',
redirectOn: 'root', // 只在根路徑偵測並轉導
},
},
});
2.3 路由策略 (Routing Strategy)
這是 SEO 的關鍵。@nuxtjs/i18n 提供幾種策略:
-
prefix_except_default (推薦):
- 預設語系 (tw) 不加前綴:
example.com/about - 其他語系 (en) 加前綴:
example.com/en/about - 優點:URL 乾淨,權重集中。
- 預設語系 (tw) 不加前綴:
-
prefix_and_default:
- 所有語系都加前綴:
example.com/tw/about,example.com/en/about - 優點:結構統一,容易處理重導向。
- 所有語系都加前綴:
-
no_prefix (不推薦用於 SEO):
- 所 有語系網址一樣,靠 Cookie 切換。
- 缺點:搜尋引擎無法索引不同語言的版本。
3. SEO 關鍵實作
3.1 hreflang 標籤
搜尋引擎需要知道「這個頁面有哪些語言版本」。@nuxtjs/i18n 會自動在 <head> 生成:
<link rel="alternate" href="https://example.com/about" hreflang="zh-TW" />
<link rel="alternate" href="https://example.com/en/about" hreflang="en-US" />
<link rel="alternate" href="https://example.com/about" hreflang="x-default" />
注意: 必須在 nuxt.config.ts 設定 baseUrl,否則 hreflang 會產生相對路徑(無效)。
export default defineNuxtConfig({
i18n: {
baseUrl: 'https://example.com', // 必須設定!
},
});
3.2 Canonical URL
確保每個語言版本的頁面都有指向自己的 Canonical URL,避免被視為重複內容。
3.3 動態內容翻譯 (API)
後端 API 也需要支援多語系。通常會在請求時帶上 Accept-Language header。
// composables/useApi.ts
export const useApi = (url: string) => {
const { locale } = useI18n();
return useFetch(url, {
headers: {
'Accept-Language': locale.value, // 傳送當前語系給後端
},
});
};
4. 常見挑戰與解法
4.1 Hydration Mismatch
問題: Server 端偵測到英文,渲染英文 HTML;Client 端瀏覽器預設是中文,Vue i18n 初始為中文,導致畫面閃爍或 Hydration Error。
解法:
- 使用
detectBrowserLanguage設定,讓 Client 端初始化時尊重 URL 或 Cookie 的設定,而不是瀏覽器設定。 - 確保 Server 與 Client 的
defaultLocale設定一致。