---
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`