Nuxt的國際化終極解決方案:I18n+Nuxt Content
出海大潮,國內用得多的Vue和Nuxt也常要面對國際化的問題。
如果是wordpress的話,就簡單了,裝一個插件,配置好Google的翻譯接口,然後系統就會每天將新的內容自動翻譯成各種語言版本。
但對於其它的系統,就不那麼方便了。
程式碼已開源:https://github.com/aigc-projects/nuxt-i18n-starter
一、基本的國際化—I18n
nuxt-i18n
1、什麼是I18n?
I18n是Nuxt國際化的必須的東西。它主要是提供了一套完整的國際化的解決方案,包括國際化路由、和基於國際化路由改變語言的方法。
2、安裝I18n
以下都可以。
yarn add @nuxtjs/i18n # yarn npm i @nuxtjs/i18n # npm pnpm i @nuxtjs/i18n pnpm add @nuxtjs/i18n@next --save-dev
3、設定nuxt.config.ts
modules: [ '@nuxtjs/i18n', ], i18n: { locales: [ { name: "English",code: "en", iso: "en-US", dir: "ltr" }, { name: " español",code: "es", iso: "es-LA", dir: "ltr" }, { name: "En français",code: "fr", iso: "fr-FR", dir: "ltr " }, { name: "العربية",code: "ar", iso: "ar-EG", dir: "rtl" },], defaultLocale: "en", detectBrowserLanguage: false, // 👇 Reference the Vue I18nserLanguage: false, // 👇 Reference the Vue I18nserLanguage: config file vueI18n: "./i18n.config.js", },
4、設定i18n.config.ts
新建i18n.config.ts或i18n.config.js
這個文件是用來配置翻譯字段的。
export default defineI18nConfig(() => ({ legacy: false, // 👇 Add translations messages: { "en": { nav_about: "About", }, "es": { nav_about: "sobre", }, "ar ": { nav_about: "نبذة عنا", }, "fr": { nav_about: "About", }, }, }))
5、連結組件
程式碼
用法
{{ $t('nav_home') }}
6.語言切換組件
程式碼
<!-- components/LangSwitcher.vue -->
<script setup lang="ts">
// Used for type casting
// Used for type casting
import type { LocaleObject } from "@nuxtjs/i18n/dist/runtime/composables";
// Get active locale and supported locales
const { locale, locales } = useI18n()
// Cast to avoid TypeScript errors in template
const supportedLocales = locales.value as Array<LocaleObject>
const router = useRouter()
const switchLocalePath = useSwitchLocalePath()
// When the visitor selects a new locale, route to
// to the new locale's path e.g. /en-CA/foo → /ar-EG/foo
function onLocaleChanged(event: Event) {
const target = event.target as HTMLInputElement
// switchLocalePath('ar-EG') will return Arabic equivalent
// for the *current* URL path e.g. if we're at /en-CA/about,
// switchLocalePath('ar-EG') will return '/ar-EG/about'
router.push({ path: switchLocalePath(target.value) })
}
</script>
<template>
<div>
🌐
<select :value="locale" @change="onLocaleChanged">
<option v-for="loc in supportedLocales" :key="loc.code" :value="loc.code">
{{ loc.name }}
</option>
</select>
</div>
</template>
用法
在頁面或佈局中使用標籤:
7、取得目前的語言
context.app.i18n.locale // where you have access to NuxtContext this.$i18n.locale //in component $i18n.locale // in template
二、文檔內容的國際化
單獨使用I18n完全可以實現全站的國際化。但如果網站有很多文章,那就需要在i18n.config.ts中寫入大量的配置項,相當麻煩。
當然,如果文章內容來自後端資料庫,那麼就不用考慮這個了,只需要將翻譯好的內容存入資料庫,不同的語言頁面取對應語言的文章版本就可以了。
這裡說的是,文章內容不是在後端資料庫,而是放在前端。
對nuxt來說,最好的方法就是使用nuxt content。簡單來說,就是將文章都存在markdown檔案中,然後,開啟某個路由就會載入這個路由對應的頁面和markdown檔案。
因為同樣的頁面,例如首頁,不同的語言,使用的路由是不同的。
比如,預設英語。首頁是www.xxx.com, 西班牙文版就是www.xxx.com/es。
所以www.xxx.com會呼叫pages目錄下的index.vue,並且載入content目錄下的index.md。而,www.xxx.com/es會呼叫pages目錄下的index.vue,並載入content目錄下的es.md文件。
所以,同一篇文章的不同語言的版本,只需要在content目錄下依照路由建造對應版本的翻譯檔案。
1、安裝nuxt content
pnpm add @nuxt/content
2、nuxt.config.ts配置
modules: [ '@nuxt/content' ], content: { // ... options }
3、在頁面呼叫對應翻譯文檔
首頁預設英語,配置西班牙語路由和頁面。
最後的路由是這樣的:
預設首頁(英文):www.xxx.com
西班牙文首頁:www.xxx.com/es
首先,設計content的檔案目錄
//content目錄設計| pages . index.vue content . index.md . es.md
然後,在首頁中需要呼叫文章的部分加標籤
<ContentDoc />
三、國際化路由的最佳實踐
en-US,en表示英語,US表示國家:美國。這是一個標準的語言代碼。路由可以直接這樣來寫:www.xxx.com/en-US
但是,大多時候,我們不需要細分到國家的層次,只需要到語言的層次就夠了。所以,這樣寫,反而是最適合的:www.xxx.com/en
當然,對於中文,就不能這樣了,中文有:zh-CN(簡體中文),zh-HK(香港繁體),zh-TW(台灣繁體)
所以,對於中文,只能這樣:www.xxx.com/zh-cn
四、附錄:國際標準的語言代碼
語言程式碼 | 語言國家 |
---|---|
af | 南非語 |
af-ZA | 南非語 |
ar | 阿拉伯語 |
ar-AE | 阿拉伯語(阿聯酋) |
ar-BH | 阿拉伯語(巴林) |
ar-DZ | 阿拉伯語(阿爾及利亞) |
ar-EG | 阿拉伯語(埃及) |
ar-IQ | 阿拉伯語(伊拉克) |
ar-JO | 阿拉伯語(約旦) |
ar-KW | 阿拉伯語(科威特) |
ar-LB | 阿拉伯語(黎巴嫩) |
ar-LY | 阿拉伯語(利比亞) |
ar-MA | 阿拉伯語(摩洛哥) |
ar-OM | 阿拉伯語(阿曼) |
ar-QA | 阿拉伯語(卡達) |
ar-SA | 阿拉伯語(沙烏地阿拉伯) |
ar-SY | 阿拉伯語(敘利亞) |
ar-TN | 阿拉伯語(突尼斯) |
ar-YE | 阿拉伯語(葉門) |
az | 亞塞拜然語 |
az-AZ | 阿塞拜疆語(拉丁文) |
az-AZ | 亞塞拜然語(西里爾文) |
be | 比利時語 |
be-BY | 比利時語 |
bg | 保加利亞語 |
bg-BG | 保加利亞語 |
bs-BA | 波士尼亞語(拉丁文,波士尼亞與赫塞哥維納) |
ca | 加泰隆語 |
ca-ES | 加泰隆語 |
cs | 捷克語 |
cs-CZ | 捷克語 |
cy | 威爾斯語 |
cy-GB | 威爾斯語 |
da | 丹麥語 |
da-DK | 丹麥語 |
de | 德文 |
de-AT | 德語(奧地利) |
de-CH | 德語(瑞士) |
de-DE | 德語(德) |
de-LI | 德文(列支敦斯登) |
de-LU | 德語(盧森堡) |
dv | 第維埃語 |
dv-MV | 第維埃語 |
el | 希臘文 |
el-GR | 希臘文 |
en | 英語 |
en-AU | 英語(澳洲) |
en-BZ | 英語(伯利茲) |
en-CA | 英語(加拿大) |
en-CB | 英文(加勒比海) |
en-GB | 英語(英國) |
en-IE | 英語(愛爾蘭) |
en-JM | 英文(牙買加) |
en-NZ | 英語(紐西蘭) |
en-PH | 英語(菲律賓) |
en-TT | 英語(特立尼達) |
en-US | 英語(美國) |
en-ZA | 英語(南非) |
en-ZW | 英語(津巴布韋) |
eo | 世界語 |
es | 西班牙語 |
es-AR | 西班牙文(阿根廷) |
es-BO | 西班牙文(玻利維亞) |
es-CL | 西班牙文(智利) |
es-CO | 西班牙文(哥倫比亞) |
es-CR | 西班牙文(哥斯大黎加) |
es-DO | 西班牙文(多明尼加共和國) |
es-EC | 西班牙文(厄瓜多) |
es-ES | 西班牙文(傳統) |
es-ES | 西班牙語(國際) |
es-GT | 西班牙語(危地馬拉) |
es-HN | 西班牙語(洪都拉斯) |
es-MX | 西班牙語(墨西哥) |
es-NI | 西班牙語(尼加拉瓜) |
es-PA | 西班牙文(巴拿馬) |
es-PE | 西班牙語(秘魯) |
es-PR | 西班牙文(波多黎各(美)) |
es-PY | 西班牙語(巴拉圭) |
es-SV | 西班牙文(薩爾瓦多) |
es-UY | 西班牙文(烏拉圭) |
es-VE | 西班牙文(委內瑞拉) |
et | 愛沙尼亞語 |
et-EE | 愛沙尼亞語 |
eu | 巴士克語 |
eu-ES | 巴士克語 |
fa | 法斯語 |
fa-IR | 法斯語 |
fi | 芬蘭語 |
fi-FI | 芬蘭語 |
fo | 法羅語 |
fo-FO | 法羅語 |
fr | 法語 |
fr-BE | 法語(比利時) |
fr-CA | 法文(加拿大) |
fr-CH | 法文(瑞士) |
fr-FR | 法文(法國) |
fr-LU | 法文(盧森堡) |
fr-MC | 法文(摩納哥) |
gl | 加里西亞語 |
gl-ES | 加里西亞語 |
gu | 古吉拉特語 |
gu-IN | 古吉拉特語 |
he | 希伯來文 |
he-IL | 希伯來文 |
hi | 印地語 |
hi-IN | 印地語 |
hr | 克羅埃西亞語 |
hr-BA | 克羅埃西亞語(波士尼亞與赫塞哥維納) |
hr-HR | 克羅埃西亞語 |
hu | 匈牙利語 |
hu-HU | 匈牙利語 |
hy | 亞美尼亞語 |
hy-AM | 亞美尼亞語 |
id | 印尼語 |
id-ID | 印尼語 |
is | 冰島語 |
is-IS | 冰島語 |
it | 義大利語 |
it-CH | 義大利語(瑞士) |
it-IT | 義大利語(義大利) |
ja | 日語 |
ja-JP | 日語 |
ka | 喬治亞語 |
ka-GE | 喬治亞語 |
kk | 哈薩克語 |
kk-KZ | 哈薩克語 |
kn | 卡納拉語 |
kn-IN | 卡納拉語 |
ko | 韓語 |
ko-KR | 韓語 |
kok | 孔卡尼語 |
kok-IN | 孔卡尼語 |
ky | 吉爾吉斯語 |
ky-KG | 吉爾吉斯語(西里爾文) |
lt | 立陶宛語 |
lt-LT | 立陶宛語 |
lv | 拉脫維亞語 |
lv-LV | 拉脫維亞語 |
mi | 毛利語 |
mi-NZ | 毛利語 |
mk | 馬其頓語 |
mk-MK | 馬其頓語(FYROM) |
mn | 蒙古語 |
mn-MN | 蒙古語(西里爾文) |
mr | 馬拉地語 |
mr-IN | 馬拉地語 |
ms | 馬來語 |
ms-BN | 馬來語(汶萊達魯薩蘭) |
ms-MY | 馬來語(馬來西亞) |
mt | 馬爾他語 |
mt-MT | 馬爾他語 |
nb | 挪威語(伯克梅爾) |
nb-NO | 挪威語(伯克梅爾)(挪威) |
nl | 荷蘭語 |
nl-BE | 荷蘭語(比利時) |
nl-NL | 荷蘭語(荷蘭) |
nn-NO | 挪威語(尼諾斯克)(挪威) |
ns | 北梭托語 |
ns-ZA | 北梭托語 |
pa | 旁遮普語 |
pa-IN | 旁遮普語 |
pl | 波蘭語 |
pl-PL | 波蘭語 |
pt | 葡萄牙語 |
pt-BR | 葡萄牙語(巴西) |
pt-PT | 葡萄牙語(葡萄牙) |
qu | 克丘亞語 |
qu-BO | 克丘亞語(玻利維亞) |
qu-EC | 克丘亞語(厄瓜多) |
qu-PE | 克丘亞語(秘魯) |
ro | 羅馬尼亞語 |
ro-RO | 羅馬尼亞語 |
ru | 俄文 |
ru-RU | 俄文 |
sa | 梵文 |
sa-IN | 梵文 |
se | 北薩摩斯語 |
se-FI | 北薩摩斯語(芬蘭) |
se-FI | 斯科特薩摩斯語(芬蘭) |
se-FI | 伊薩薩摩斯語(芬蘭) |
se-NO | 北薩摩斯語(挪威) |
se-NO | 律勒歐薩摩斯語(挪威) |
se-NO | 南薩摩斯語(挪威) |
se-SE | 北薩摩斯語(瑞典) |
se-SE | 律勒歐薩摩斯語(瑞典) |
se-SE | 南薩摩斯語(瑞典) |
sk | 斯洛伐克語 |
sk-SK | 斯洛伐克語 |
sl | 斯洛維尼亞語 |
sl-SI | 斯洛維尼亞語 |
sq | 阿爾巴尼亞語 |
sq-AL | 阿爾巴尼亞語 |
sr-BA | 塞爾維亞語(拉丁文,波士尼亞與赫塞哥維納) |
sr-BA | 塞爾維亞語(西里爾文,波士尼亞和黑塞哥維那) |
sr-SP | 塞爾維亞(拉丁) |
sr-SP | 塞爾維亞(西里爾文) |
sv | 瑞典語 |
sv-FI | 瑞典語(芬蘭) |
sv-SE | 瑞典語 |
sw | 斯瓦希里語 |
sw-KE | 斯瓦希里語 |
syr | 敘利亞語 |
syr-SY | 敘利亞語 |
ta | 泰米爾語 |
ta-IN | 泰米爾語 |
te | 泰盧固語 |
te-IN | 泰盧固語 |
th | 泰語 |
th-TH | 泰語 |
tl | 塔加路語 |
tl-PH | 塔加路語(菲律賓) |
tn | 茨瓦納語 |
tn-ZA | 茨瓦納語 |
tr | 土耳其語 |
tr-TR | 土耳其語 |
ts | 宗加語 |
tt | 韃靼語 |
tt-RU | 韃靼語 |
uk | 烏克蘭語 |
uk-UA | 烏克蘭語 |
ur | 烏都語 |
ur-PK | 烏都語 |
uz | 烏茲別克語 |
uz-UZ | 烏茲別克語(拉丁文) |
uz-UZ | 烏茲別克語(西里爾文) |
vi | 越南語 |
vi-VN | 越南語 |
xh | 班圖語 |
xh-ZA | 班圖語 |
zh | 中文 |
zh-CN | 中文(簡體) |
zh-HK | 中文(香港) |
zh-MO | 中文(澳門) |
zh-SG | 中文(新加坡) |
zh-TW | 中文(繁體) |
zu | 祖魯語 |
zu-ZA | 祖魯語 |