Try   HackMD

VueJS 2.0 教學筆記: i18n 多語套件進階篇

綱要

適用情況

也許你已經熟悉了前面一篇的作法。
但是當我們需要將多語環境的維護擴充為 「由管理員從後台上傳多語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": "日本語" }

設定js-cookie的寫入與讀取的共用方法

每次進入網站就會使用到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)

建立i18N的主程式

由於管理多語的方式不同,部分設定需要在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

調整main.js的設定

與上一篇的做法不同,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:


tags: VueJS i18n