--- title: 'VueJS 教學筆記: i18n 多語套件進階篇' disqus: hackmd --- VueJS 2.0 教學筆記: i18n 多語套件進階篇 === 綱要 [TOC] 適用情況 --- 也許你已經熟悉了[前面一篇](https://hackmd.io/@FortesHuang/r1czhVbhB)的作法。 但是當我們需要將多語環境的維護擴充為 **「由管理員從後台上傳多語CSV檔案」** ,又要抽出一個JSON格式的設定檔來管理API路徑、預設語系等項目時該怎麼做呢? 安裝 i18n 套件和 js-cookie --- `npm install vue-i18n --save` `npm install js-cookie --save` 新增設定檔 --- 在`public`下新增一個`config.json`的檔案: ```json= [ { "LOCALE": "zh_tw" } ] ``` 然後`public`下再新增一個叫做`locale`的目錄,並增加一些JSON格式的語系檔進去: **public/locale/zh_tw.json** ```json= { "header": "Vue i18n 多語管理", "select_language": "選擇語言", "change_language": "切換語言", "please_select": "請選擇", "locale_en": "English", "locale_zh_tw": "繁體中文", "locale_jp": "日文" } ``` **public/locale/en.json** ```json= { "header": "Vue i18n Multi Language", "select_language": "select language", "change_language": "change language", "please_select": "please select", "locale_en": "English", "locale_zh_tw": "Chinese(Traditional)", "locale_jp": "Japenese" } ``` **public/locale/jp.json** ```json= { "header": "Vue i18n 多言語機能", "select_language": "言語選択", "change_language": "言語切替", "please_select": "言語を選んでください", "locale_en": "英語", "locale_zh_tw": "中国語(台湾)", "locale_jp": "日本語" } ``` 設定js-cookie的寫入與讀取的共用方法 --- 每次進入網站就會使用到cookie儲存的慣用語言設定,當語言切換事件被觸發後應該要再一次將所選的語系覆寫原始設定,所以這裡我們先將cookies的存取方法獨立出來作共用,一般會放在`src/utils`中管理: **src/utils/cookies.js** ```javascript= import Cookies from 'js-cookie' // 儲存在cookies時,應以何種名稱為key const languageKey = 'language' // 取得cookies設定中的語言設定項目 export const getLanguage = () => Cookies.get(languageKey) // 語言設定變更時,寫入cookies export const setLanguage = (language) => Cookies.set(languageKey, language) ``` 建立i18N的主程式 --- 由於管理多語的方式不同,部分設定需要在fetch到public中的JSON設定檔後才能取得正確語系資料,主程式中的結構也會有所變更。 在`src`下新增一個目錄`lang`,建立主程式如下: **src/lang/index.js** ```javascript= import Vue from 'vue' import VueI18n, { LocaleMessages } from 'vue-i18n' import * as cookie from '@/utils/cookies' // 由window取設定,稍後我們會在main.js設置一些相關設定 const config = window['config'] Vue.use(VueI18n) // 啟用i18N const i18n = new VueI18n({ locale: '', messages: {}, silentTranslationWarn: true }) // 預設語言 cookie.setLanguage('zh_tw') const loadedLanguages = [] // 取得現在的語言設定 export const getLocale = () => { const cookieLanguage = cookie.getLanguage() // from cookie if (cookieLanguage) { return cookieLanguage } // from default config if (config.LOCALE) { return config.LOCALE } return 'zh_tw' } const locale = getLocale() // 設置語言的事件 const setI18nLanguage = (lang) => { i18n.locale = lang cookie.setLanguage(lang) return lang } export const loadLanguageAsync = async (lang) => { // 如果配置到同樣的語言value時 if (i18n.locale === lang) { return setI18nLanguage(lang) } // 如果已經載入該語言時 if (loadedLanguages.includes(lang)) { return setI18nLanguage(lang) } // 如果沒有載入語言時 const messages = await getMessages(lang) i18n.setLocaleMessage(lang, messages) loadedLanguages.push(lang) return setI18nLanguage(lang) } // Fetch對應的json語言包 const getMessages = async (locale) => { // ElementUI中使用的locale key稍微不同,格式必須正確 const elementUILocMap = { en: 'en', zh_tw: 'zh-TW', jp: 'ja', } let langFile if (locale === 'zh_tw') { langFile = await (await fetch(`locale/zh.json`)).json() } else if (locale === 'en') { langFile = await (await fetch(`locale/en.json`)).json() } else if (locale === 'jp') { langFile = await (await fetch(`locale/jp.json`)).json() } const elLangFile = await import(/* webpackChunkName: "lang-elementui-[request]" */`element-ui/lib/locale/lang/${elementUILocMap[locale]}`) return { ...langFile, ...elLangFile.default} } loadLanguageAsync(locale) export default i18n ``` 調整main.js的設定 --- 與上一篇的做法不同,i18N的Module不是在`main.js`引入。 這邊所引入的`i18n`是指在`src/lang/index.js`的主程式。 **main.js** ```javascript= // 這裡以專案有使用elementUI為例子 import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' // 引入lang模組 import i18n from '@/lang' // 設置一個初始化事件,New Vue以前先取得config const init = async () => { await getConfig() new Vue({ router, store, i18n, render: h => h(App) }).$mount('#app') } init() if (process.env.NODE_ENV === 'development') { // i18n 確認是否有存在既有語言KEY window['k'] = (v) => { const m = i18n.messages['zh_tw'] const m2 = i18n.messages['en'] for (let i in m) { if (m[i] == v) return i if (m2[i] == v) return i } } window['t'] = (v) => { return i18n.t(v) } window['r'] = Vue.$router window['i'] = Vue.$i18n } ``` 接著設置一些測試用的Template: ```htmlmixed= <template> <div class="row vertical" data-inset="1rem"> <h1>{{ $t('header') }}</h1> <br> <el-select v-model="currentLang" @change="onLangChange"> <el-option v-for="(item, i) in languageList" :key="i" :label="item.label" :value="item.value" /> </el-select> <br> </div> </template> ``` ```javascript= import { loadLanguageAsync } from '@/lang' export default { name: 'i18n', data() { return { currentLang: '', languageList: [ { label: '繁體中文', value: 'zh_tw' }, { label: 'English', value: 'en' }, { label: '日文', value: 'jp' } ] } }, methods: { onLangChange(val) { console.log(val) loadLanguageAsync(val) } } } ``` Preview: ![](https://i.imgur.com/EkH6Bwx.png) ![](https://i.imgur.com/vPM5mbx.png) ###### tags: `VueJS` `i18n`