不知道為什麼,實作多國語系這部分一直都很吸引我。
一直沒有機會去做做看,卻在這個寫文靈感極度枯竭的時候忽然想起來。
爬文之後發現用 Vue I18n 真的很方便,在此紀錄一下。
官網
Vue I18n
CDN 用法
首先介紹 CDN 的用法。
基本設定
將 vue-i18n.js 引用在 <body> 的最後;也要引用 vue 。
1 2 <script src ="https://unpkg.com/vue/dist/vue.js" > </script > <script src ="https://unpkg.com/vue-i18n/dist/vue-i18n.js" > </script >
接著來設定各國語言的內容,設定值第一層的 key 是語系名稱, value 就是這個語系的內容。
可以依據語意來安排結構,像是「 header 的 title 」。
每個語系都有同樣結構的 key ,如果不相同的話,切換到該語系可能就會找不到詞彙。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 const messages = { en: { header: { title: "Website" }, main: { image: { text: "fake image" , font: "lobster" } } }, tw: { header: { title: "網站" }, main: { image: { text: "假圖" , font: "noto" } } }, jp: { header: { title: "サイト" }, main: { image: { text: "フェイク" , font: "noto" } } } };
再來就將設定值作為 VueI18n 實體的參數。
1 2 3 4 5 6 7 8 9 10 const i18n = new VueI18n({ locale: 'tw' , messages: messages }); const i18n = new VueI18n({ locale: 'tw' , messages });
然後將 VueI18n 實體 放入 Vue 實體中。
1 2 3 4 5 6 7 8 9 let app = new Vue({ el: "#app" , i18n: i18n }); let app = new Vue({ el: "#app" , i18n });
這樣就設定完成了。
使用
直接使用
在 HTML 中以 $t(“header.title”) 這樣的格式來取得內容。
1 <h1 class ="h1" > {{ $t("header.title") }}</h1 >
在字串裡面的用法也一樣。
1 <img class ="img" :src ="`https://fakeimg.pl/460x200/?text=${$t('main.image.text')}&font=${$t('main.image.font')}`" >
在 JavaScript 中則是例如:
想切換語系的話就直接更改 locale 。
1 this .$i18n.locale = 'jp' ;
帶入參數
設定值的字串是可以帶參數的,例如句子中帶有稱呼的時候:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const messages = { en: { main: { greeting: "{name}, Hi!" , }, tw: { main: { greeting: "{name},你好!" , }, jp: { main: { greeting: "{name}さん、こんにちは" , } } };
用物件的方式帶入參數。
1 <h2 class ="h2" > {{$t("main.greeting", {name: "Lynn"})}}</h2 >
帶入數量
有些語言的後綴可能會隨著數量不同而改變,這時就可以設定不同數量時的表示法。
參數的帶入方式同上,而不同數量的說法以 | 分開。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const messages = { en: { main: { sheep: "no sheep | 1 sheep | {value} sheeps" } }, tw: { main: { sheep: "沒有綿羊 | 1 隻綿羊 | {value} 隻綿羊" } }, jp: { main: { sheep: "羊がいない | 羊 1 匹 | 羊 {value} 匹" } } }
使用方式則如下:
1 2 3 4 // 要小心這邊用的是 $tc <li > {{ $tc("main.sheep", 0 , { value: 0 }) }}</li > <li > {{ $tc("main.sheep", 1 , { value: 1 }) }}</li > <li > {{ $tc("main.sheep", 2 , { value: 2 }) }}</li >
另外如果遇到其它複數規則的語言,可以參考文件:自定義複數
範例
這是用以上的內容寫的範例。
See the Pen
Vue I18n CDN by Lynn (@clhuang224 )
on CodePen .
Vue Cli 用法
Vue Cli 3.x 以上的版本可以直接用指令讓 Cli 將 I18n 設定好。
或者可以自行安裝。
用 Cli 加入模組的話,會有幾個要回答的問題。
1 2 3 4 5 6 7 8 ? The locale of project localization. zh-TW ? The fallback locale of project localization. zh-TW ? The directory where store localization messages of project. It`s stored under `src` directory. locales ? Enable locale messages in Single file components ? Yes
設定好以後,專案中會產生或更動一些檔案:
1 2 3 4 5 6 7 8 9 10 11 src ├── .env ├── i18n.js ├── main.js ├── locales | └── zh-TW.json ├── components | └── HelloI18n.vue ├── vue.config.js ├── package.json └── package-lock.json
.env
.env 宣告了兩個環境變數給其他檔案使用,如果要更改預設地區跟 fallback 地區就可以來這邊改。
1 2 VUE_APP_I18N_LOCALE=zh-TW VUE_APP_I18N_FALLBACK_LOCALE=zh-TW
i18n.js
i18n.js 比較長一點,但就是在設定基本的內容,跟 Vue router 的設定檔案類似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import Vue from "vue" ;import VueI18n from "vue-i18n" ;Vue.use(VueI18n); function loadLocaleMessages ( ) { const locales = require .context( "./locales" , true , /[A-Za-z0-9 -_,\s]+\.json$/i ); const messages = {}; locales.keys().forEach(key => { const matched = key.match(/([A-Za-z0-9-_]+)\./i ); if (matched && matched.length > 1 ) { const locale = matched[1 ]; messages[locale] = locales(key); } }); return messages; } export default new VueI18n({ locale: process.env.VUE_APP_I18N_LOCALE || "en" , fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || "en" , messages: loadLocaleMessages() });
話說中間比對檔名的部分我有點不懂為什麼是這樣子的規則,所以做了一個小實驗。
首先在 src/locales 新增幾個檔案:
jp .json
tw .json
tw,.json
tw,copy.json
tw,tw.json
tw.json
再加上 console.log() 。
1 2 3 4 5 6 7 8 9 10 locales.keys().forEach(key => { console .log("Filename: " , key); const matched = key.match(/([A-Za-z0-9-_]+)\./i ); console .log("matched: " , matched); if (matched && matched.length > 1 ) { const locale = matched[1 ]; messages[locale] = locales(key); console .log("messages: " , messages); } });
最後跑出來結果是這樣:
可以觀察到的規則是:
不接受空白鍵或逗號結尾的檔名
有空白鍵或逗號隔開時,會選擇符號前的文字作為 key
key 重複時不會被覆蓋
所以基本上取名只要用大小寫英數字、橫線及底線就可以
main.js
main.js 的部分就是把 VueI18n 放入 Vue 實體中。
1 2 3 4 5 6 7 8 9 10 import Vue from "vue" ;import App from "./App.vue" ;import i18n from "./i18n" ; Vue.config.productionTip = false ; new Vue({ i18n, render: h => h(App) }).$mount("#app" );
locales/__.json
預設的語系檔案。
1 2 3 { "message" : "hello i18n !!" }
components/HelloI18n.vue
示範元件內使用 標籤的檔案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <template> <p>{{ $t("hello") }}</p> </template> <script> export default { name: "HelloI18n" }; </script> <i18n> { "en": { "hello": "Hello i18n in SFC!" } } </i18n>
vue.config.js
i18n 相關的專案設定。
1 2 3 4 5 6 7 8 9 10 module .exports = { pluginOptions: { i18n: { locale: "zh-TW" , fallbackLocale: "zh-TW" , localeDir: "locales" , enableInSFC: true } } };
結語
以上大概就是有關 Vue I18n 的內容,感謝閱讀到這裡:)
參考資料