文 / 西打藍 Siddharam
前言
公司某專案是用 vue,最近需要弄成雙語,目前評估後認為,手作和 vue-i18n 差別不大,最後可能會用手作。但還是紀錄一下 vue-i18n 如何實現雙語,非常簡單。
比較需要額外處理的,包含 vue-router 的調整,以及不重新刷頁面的話,從 API return 回來的資料需要抓另一種語言的版本。此次教學會特別說明前者,而後者我可能會以 watch 來解決,就不多談。
vue-i18n 使用
專案結構:
src -
/lang/CHS.json
/CHT.json
/plugins/i18n.js
/router/index.js
/page/Home/index.vue
/components/layout/Header.vue
main.js
語系 json 檔案:
// CHT.json
// 繁體
{
"test": "測試",
"language": "CHT"
}
// CHS.json
// 簡體
{
"test": "测试",
"language": "CHS"
}
其實 vue-i18n 也可以直接寫在 main.js 裡,但我還是把它拉出一層,比較直觀些:
// i18n.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import CHS from '../lang/CHS.json' // 存放簡體
import CHT from '../lang/CHT.json' // 存放繁體
// i18n
Vue.use(VueI18n)
let browserLanguage = window.navigator.language
// 先塞入瀏覽器預設語言在 i18n
if (browserLanguage.toLowerCase() === 'zh-cn') {
browserLanguage = 'CHS'
} else if (browserLanguage.toLowerCase() === 'zh-tw') {
browserLanguage = 'CHT'
} else {
browserLanguage = 'CHS'
}
// 存放語系 json
const messages = {
CHS: CHS,
CHT: CHT
}
export const i18n = new VueI18n({
locale: browserLanguage, // set locale
fallbackLocale: browserLanguage,
messages // set locale messages
})
掛載 i18n 在 main.js。
// i18n.js
// 引入
import { i18n } from './plugins/i18n'
...
...
new Vue({
el: '#app',
store,
router,
i18n,
components: { App },
template: '< App/>'
})
做到這一步,就能在靜態頁面去塞入語系文字了:
// Home/index.vue
// 首頁
<h1>{{ $t("test") }}</h1>
// 如果你的瀏覽器語系是繁體的話,它就會返回:
<h1>測試</h1>
如果要轉換語系的話,只要更新 $i18n.locale 就好:
// layout/Header.vue
<template>
<header class="header-component">
<router-link :to="'/' + $i18n.locale" class="header-logo-link">
<img class="header-logo" src="@/assets/synergies-logo.png" alt="logo">
</router-link>
<div class="header-language">
<a @click="changeLanuage('CHS')" href="javascript:void(0)" class="header-link active">简</a>
<span class="divider">|</span>
<a @click="changeLanuage('CHT')" href="javascript:void(0)" class="header-link">繁</a>
</div>
</header>
</template>
<script>
export default {
name: 'Header',
data () {
return {
currentLanguage: ''
}
},
methods: {
changeLanuage (lang) {
this.$i18n.locale = lang
let currentPage = window.location.href.split('/').pop()
if (currentPage === 'CHS' || currentPage === 'CHT') {
currentPage = ''
}
this.$router.push({path: `/${lang}/${currentPage}`})
},
mounted () {
this.currentLanguage = this.$i18n.locale
}
}
}
</script>
vue-router 設定
我這邊做的,是要讓以下網址做好簡繁語系切換:
www.test/CHS/question
www.test/CHT/question
如果是以下網址,則會去抓瀏覽器預設語言,在決定顯示 CHS 或是 CHT:
www.test/1231231
www.test/index.html
// router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import { i18n } from '../plugins/i18n'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/:lang',
component: {
template: ' '
},
beforeEnter (to, from, next) {
const lang = to.params.lang
// 如果 URL 非 CHS、CHT 則導至瀏覽器預設語言
if (!['CHS', 'CHT'].includes(lang)) {
return next(i18n.locale)
}
// 如果 URL 有語系,則置換 i18n 語言
if (i18n.locale !== lang) {
i18n.locale = lang
}
return next()
},
children: [
{
path: '/',
name: 'Home',
component: () => import('@/pages/Home/Index')
},
{
path: 'question',
name: 'Question',
component: () => import('@/pages/Question/Index')
}
]
}
]
})
上面要注意的是 children question path 的路徑,不能有 /,不然會和首頁衝突。而 beforeEnter 可以想成在點入 URL 之前,針對路徑執行的函式。而 next 會決定最後進入的路徑。
如果最後進入 next 的路徑和 to.params.lang 衝突的話,則會顯示錯誤。
結語
在 vue-router 這段的設定,其實還有很多種方法,例如每種語系就給它塞入顯示的 component;或者用動態 id 的方式,來處理 CHS、CHT 的路徑。但都沒有現在這個寫法來的彈性。未來新增語系也很方便,不太需要額外的程式碼做處理。
相信做完一次,更熟悉的反而不是 vue-i18n,而是 vue-router,哈。
閱讀量次
聯絡與合作
訂閱電子報,領「我當前 10+ 以上收入源有哪些」一文。
有文字採訪、網站開發,或是諮詢需求,皆可至個人網站參考作品,並聯繫 IG。
或是想分享心情、聊聊天、交朋友,可以來秘密通道找我唷。
Email: frank@siddharam.com