August 21, 2019

vue-i18n 雙語網站:vue-router 調整

瀏覽器預設語言


文 / 西打藍 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