[vue]簡單實做多國語系

  • 5150
  • 0
  • vue
  • 2017-07-12

[vue]簡單實做多國語系,使用web api的資源檔做為多國語系的來源

前言

有關於.net如何實做多國語系,可以從筆者上一篇文章了解一下(https://dotblogs.com.tw/kinanson/2017/07/11/082615),雖然這篇的後端語言是使用c#,但其實不管是什麼後端語言都一樣,只要最後回傳的是object的key and value的結構,前端都能類似的完成相關需求,筆者在angular或vue都曾經看過有人問多國語系實做問題,但其實在vue.js只要後端定義好多國語系的規則,前端其實根本不需要使用任何第三方的package就能實做多國語系了啊,接下來就示例一下筆者如何在vue.js實做多國語系吧。

導覽

  1. web api部份
  2. vue的部份
  3. 增加下拉選項,切換多國語系
  4. 為server端增加快取機制
  5. 結論

web api部份

我目前在資源檔已定義了如下的一些key

接著我們在定義一個controller為多國語系直接吐出json供前端調用

TranslateController

    public class TranslateController : ApiController
    {
        public IHttpActionResult Get()
        {
            var resources = GetResources(HttpContext.Current.Request.UserLanguages[0]);
            return Ok(resources);
        }

        private Dictionary<string, string> GetResources(string lang)
        {
            var resources = new Dictionary<string, string>();
            var resourceSet = Resource.ResourceManager.GetResourceSet(new CultureInfo(lang), true, true);
            IDictionaryEnumerator enumerator = resourceSet.GetEnumerator();
            while (enumerator.MoveNext())
            {
                resources.Add(enumerator.Key.ToString(), enumerator.Value.ToString());
            }

            return resources;
        }
    }

接下來先簡單使用swagger,測試多國語系是否能正確回傳json物件

vue的部份

再來就是vue的部份了,因為多國語系是全局的,有很多種方式可以實現,你也可以存在sessionStorage裡面,而筆者則是直接保存在vuex的state裡面,以下則為程式碼示例

stores/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    dictionarys: {}
  },
  actions: {
    async getDictionarys({ commit }) {
      let result = await axios.get('http://localhost:64508/api/translate/get')
      commit('getDictionarys', result.data)
    }
  },
  mutations: {
    getDictionarys(state, data) {
      state.dictionarys = data
    }
  },
  getters: {
    dictionarys: state => state.dictionarys
  },
  strict: process.env.NODE_ENV === 'development'
})

component的部份

<template>
  <div>
    <a href="#" :title="dictionarys.Edit" @click="click">{{dictionarys.Edit}}</a>
    <br>
    {{dictionarys.Create}}
  </div>
</template>

<script>
import { mapActions, mapGetters } from 'vuex'
export default {
  name: 'translate',
  methods: {
    ...mapActions([
      'getDictionarys'
    ]),
    click () {
      alert(this.dictionarys.CompanyName)
    }
  },
  computed: {
    ...mapGetters([
      'dictionarys'
    ])
  },
  created () {
    this.getDictionarys()
  }
}
</script>

<style>

</style>

接著來看一下畫面的結果吧

增加下拉選項,切換多國語系

這樣子確實是已經顯示出後端回傳的多國語系了,但是我們如何切換成別種語系版本呢?簡單使用一個下拉式選單來示例一下

stores/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    dictionarys: {}
  },
  actions: {
    async getDictionarys({ commit }, lang) { // 增加傳入語系
      let result = await axios.get('http://localhost:64508/api/translate/get',
       { headers: { 'Accept-Language': lang } })// 新增可以改變語系的header
      commit('getDictionarys', result.data)
    }
  },
  mutations: {
    getDictionarys(state, data) {
      state.dictionarys = data
    }
  },
  getters: {
    dictionarys: state => state.dictionarys
  },
  strict: process.env.NODE_ENV === 'development'
})

component

<template>
  <div>
    <select v-model="lang" @change="changeLang">
      <option value="zh-TW">繁中</option>
      <option value="zh-CN">簡中</option>
      <option value="en-US">英文</option>
    </select>
    <a href="#" :title="dictionarys.Edit" @click="click">{{dictionarys.Edit}}</a>
    {{dictionarys.Create}}
  </div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
export default {
  name: 'translate',
  data () {
    return {
      lang: 'zh-TW'
    }
  },
  methods: {
    ...mapActions([
      'getDictionarys'
    ]),
    changeLang () {
      // 增加傳入語系
      this.getDictionarys(this.lang)
    },
    click () {
      alert(this.dictionarys.CompanyName)
    }
  },
  computed: {
    ...mapGetters([
      'dictionarys'
    ])
  },
  created () {
    this.getDictionarys(this.lang)
  }
}
</script>
<style>

</style>

接下來再看一下畫面示例

為server端增加快取機制

雖然多國語系都完成了,不過我們每次換頁或重整,就重新的跟web api要一次,這不是一件好事,那我們簡單來改造一下,為web api加上快取吧,因為我們要以傳入的語系當做快取條件,所以我把TranslateController改成要傳入參數,而不是去取Header的方式,並加入要求server和client都得快取的方式,如果對快取這個attribute不熟的話,想了解可以看筆者之前文章(https://dotblogs.com.tw/kinanson/2017/05/09/222747)

    public class TranslateController : ApiController
    { 
        [CacheOutput(ServerTimeSpan = 120, ClientTimeSpan = 120)]
        public IHttpActionResult Get(string lang)
        {
            var resources = GetResources(lang);
            return Ok(resources);
        }

        private Dictionary<string, string> GetResources(string lang)
        {
            var resources = new Dictionary<string, string>();
            var resourceSet = Resource.ResourceManager.GetResourceSet(new CultureInfo(lang), true, true);
            IDictionaryEnumerator enumerator = resourceSet.GetEnumerator();
            while (enumerator.MoveNext())
            {
                resources.Add(enumerator.Key.ToString(), enumerator.Value.ToString());
            }

            return resources;
        }
    }

接著把vuex的傳入改成參數,而不是原本的修改Header的方式

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    dictionarys: {}
  },
  actions: {
    async getDictionarys({ commit }, lang) {
      let result = await axios.get(`http://localhost:64508/api/translate/get?lang=${lang}`)// 修改為傳入參數
      commit('getDictionarys', result.data)
    }
  },
  mutations: {
    getDictionarys(state, data) {
      state.dictionarys = data
    }
  },
  getters: {
    dictionarys: state => state.dictionarys
  },
  strict: process.env.NODE_ENV === 'development'
})

最後再來看一下結果示例

第一次傳入繁中語系,是從伺服器來的

接著切換到英文或簡體語系,第一次一樣還是從伺服器來的

但如果我們之後切換這三種語系就都會cache在client端

結論

從此範例我們可以看到,其實要完成多國語系的需求並不會很困難,而且我們又實做了伺服器端的快取,只是用很簡單的技術來快取,什麼redis等等的快取機制都不需要用到,而且資源檔這種變動不大的部份,實際上儲存在各台ap上面就足夠了,還不需要存到一個快取中心給不同ap共用,不過因為我們在client也快取了,所以一旦我們就算重新上版伺服器的部份,client的快取還是會保留起來,並不會馬上去跟伺服器要最新的多國語系資料,就請讀者自行評估快取策略囉。