初識ABP vNext(6):vue+ABP實現國際化

xhznl發表於2020-08-26

Tips:本篇已加入系列文章閱讀目錄,可點選檢視更多相關文章。

前言

上一篇介紹了ABP擴充套件實體,並且在前端部分新增了身份認證管理和租戶管理的選單,在實現這兩個功能模組前,先來解決一下介面文字國際化的問題。

開始

國際化(簡稱 I18N),本地化(簡稱 L10N);這兩者的目的都是用於讓你的應用程式支援多個國家和區域的語言,它們看起來很相似,但是有一些細微的區別,本文不對此進行深入探討,有興趣的可以自行搜尋。ABP後端支援的是本地化,而vue-element-admin支援的是國際化,使用vue-i18n實現;本文預設它兩者是一回事。

前面的章節中,已經大概分析了vue+ABP國際化的實現思路。我們可以在後端實現國際化,然後vue從後端獲取國際化文字,展示到介面中;另一種方式是直接在前端部分實現國際化。在前端實現就很簡單,直接在vue-element-admin的src\lang\目錄下配置相應的文字,然後介面使用i18n的$t()方法渲染就可以了,這個不多做介紹。本文只探討第一種實現方式。

語言選項

首先,語言選項列表需要根據後端配置得到。

在後端修改支援的語言型別,這裡就只支援中文和英文2種吧,其他的註釋掉。

src\Xhznl.HelloAbp.HttpApi.Host\HelloAbpHttpApiHostModule.cs:

請求abp/application-configuration介面:

此時返回的localization.languages屬性只有2個語言了,然後只需要把這個資料繫結到介面上就好了。語言切換用的是一個公共元件 src\components\LangSelect\index.vue:

<template>
  <el-dropdown
    trigger="click"
    class="international"
    @command="handleSetLanguage"
  >
    <div>
      <svg-icon class-name="international-icon" icon-class="language" />
    </div>
    <el-dropdown-menu slot="dropdown">
      <el-dropdown-item
        v-for="item in languages"
        :key="item.cultureName"
        :disabled="language === item.cultureName"
        :command="item.cultureName"
      >
        {{ item.displayName }}
      </el-dropdown-item>
    </el-dropdown-menu>
  </el-dropdown>
</template>

<script>
export default {
  data() {
    return {
      languages: this.$store.getters.abpConfig.localization.languages
    };
  },
  computed: {
    language() {
      return this.$store.getters.language;
    }
  },
  methods: {
    handleSetLanguage(lang) {
      //this.$i18n.locale = lang
      this.$store.dispatch("app/setLanguage", lang);
      this.$store.dispatch("app/applicationConfiguration").then(() => {
        this.$message({
          message: "Switch Language Success",
          type: "success"
        });
      });
    }
  }
};
</script>

語言切換

語言切換時,需要再次呼叫app/applicationConfiguration介面,更新本地化文字。

src\utils\request.js:

// request interceptor
service.interceptors.request.use(
  config => {
    // do something before request is sent
    config.headers['accept-language'] = store.getters.language

    if (store.getters.token) {
      config.headers['authorization'] = 'Bearer ' + getToken()
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)

src\store\modules\app.js:

const actions = {
  。。。。。。
    
  applicationConfiguration({ commit }) {
    return new Promise((resolve, reject) => {
      applicationConfiguration()
        .then(response => {
          const data = response;
          commit("SET_ABPCONFIG", data);

          const language = data.localization.currentCulture.cultureName;
          const values = data.localization.values;
          setLocale(language, values);

          resolve(data);
        })
        .catch(error => {
          reject(error);
        });
    });
  }
};

src\lang\index.js:

import Vue from "vue";
import VueI18n from "vue-i18n";
import Cookies from "js-cookie";
import elementEnLocale from "element-ui/lib/locale/lang/en"; // element-ui lang
import elementZhLocale from "element-ui/lib/locale/lang/zh-CN"; // element-ui lang

Vue.use(VueI18n);

const messages = {
  en: {
    ...elementEnLocale
  },
  "zh-Hans": {
    ...elementZhLocale
  }
};

export function getLanguage() {
  const chooseLanguage = Cookies.get("language");
  if (chooseLanguage) return chooseLanguage;

  // if has not choose language
  const language = (
    navigator.language || navigator.browserLanguage
  ).toLowerCase();
  const locales = Object.keys(messages);
  for (const locale of locales) {
    if (language.indexOf(locale) > -1) {
      return locale;
    }
  }
  return "en";
}
export function setLocale(language, values) {
  i18n.mergeLocaleMessage(language, values);
  i18n.locale = language;
}
const i18n = new VueI18n({
  // set locale
  // options: en | zh | es
  locale: getLanguage(),
  // set locale messages
  messages
});

export default i18n;

將後端返回的文字設定到vue-i18n中,就可以使用了。這跟直接在前端做國際化有一點區別就是,後者的文字資訊是寫在前端,vue-i18n可以直接使用。而這裡只是把文字資訊改到後端,從後端獲取後再設定到i18n中,本質是一樣的。

修改後端的配置文字:

src\Xhznl.HelloAbp.Domain.Shared\Localization\HelloAbp\zh-Hans.json:

src\Xhznl.HelloAbp.Domain.Shared\Localization\HelloAbp\en.json:

localization.values返回:

接下來只需要把介面上對應的文字使用vue-i18n的$t()方法渲染就好了,比如:

前端需要改動的地方比較多,但都是類似的修改。。。直接看效果:

注意

因為app/applicationConfiguration介面只有在重新整理頁面、登入、退出、切換語言等操作的時候才會去呼叫,所以不用擔心請求頻繁。

其實上面有一部分本地化文字還是放在了前端:ElementUI自帶的文字。因為ABP的本地化json格式只能有一級,key/value:

文字只能寫在texts屬性中,key/value形式,不支援多層級。

而vue-i18n是支援多層級的:

所以ElementUI的這部分文字還是放在前端了。

最後

本篇關於vue+ABP實現國際化就介紹完了。。。其實還是有點繁瑣的,要配置的比較多,不知道有沒有更好的方法,歡迎評論交流。。。

相關文章