綱要
也許你已經熟悉了前面一篇的作法。
但是當我們需要將多語環境的維護擴充為 「由管理員從後台上傳多語CSV檔案」 ,又要抽出一個JSON格式的設定檔來管理API路徑、預設語系等項目時該怎麼做呢?
npm install vue-i18n --save
npm install js-cookie --save
在public
下新增一個config.json
的檔案:
[
{
"LOCALE": "zh_tw"
}
]
然後public
下再新增一個叫做locale
的目錄,並增加一些JSON格式的語系檔進去:
public/locale/zh_tw.json
{
"header": "Vue i18n 多語管理",
"select_language": "選擇語言",
"change_language": "切換語言",
"please_select": "請選擇",
"locale_en": "English",
"locale_zh_tw": "繁體中文",
"locale_jp": "日文"
}
public/locale/en.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
{
"header": "Vue i18n 多言語機能",
"select_language": "言語選択",
"change_language": "言語切替",
"please_select": "言語を選んでください",
"locale_en": "英語",
"locale_zh_tw": "中国語(台湾)",
"locale_jp": "日本語"
}
每次進入網站就會使用到cookie儲存的慣用語言設定,當語言切換事件被觸發後應該要再一次將所選的語系覆寫原始設定,所以這裡我們先將cookies的存取方法獨立出來作共用,一般會放在src/utils
中管理:
src/utils/cookies.js
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)
由於管理多語的方式不同,部分設定需要在fetch到public中的JSON設定檔後才能取得正確語系資料,主程式中的結構也會有所變更。
在src
下新增一個目錄lang
,建立主程式如下:
src/lang/index.js
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
與上一篇的做法不同,i18N的Module不是在main.js
引入。
這邊所引入的i18n
是指在src/lang/index.js
的主程式。
main.js
// 這裡以專案有使用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:
<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>
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:
VueJS
i18n