分类
Javascript

Vue I18n解决方案

一、背景介绍

系统功能越来越强大,但不支持多国语言,国际化提上议事日程,公司目前前端框架主要采用Vue,经过比较充分地调研,推荐使用Vue I18n + localStorage+ element-ui组件I18n来作为解决该系统多国语言的解决方案。以下是Demo工程最终效果。

二、Why Vue I18n
Vue I18n 是 Vue.js 的国际化插件,具有以下的特性:

  • 开源,Vue.js官方推荐;
  • Github 6.4K Star;
  • 文档丰富;
  • 简单:API简单,使用方便;
  • 强大:除了简单的翻译外,还支持复数,数字,日期时间等本地化处理;
  • 面向组件,你可以在单文件组件上管理。

三、Why localStorage

相比Cookie等浏览器端本地存储,有以下优势:

  • 简单:原生API简单
  • 友好:安全限制少

四、具体实现

1) 导入 Vue 和 VueI18n ,然后调用 Vue.use(VueI18n);

import Vue from "vue";
import VueI18n from "vue-i18n";

Vue.use(VueI18n);

2) 准备翻译的语言环境信息,可使用对象变量的方式,但通常情况下推荐使用全局lang配置文件。Demo工程目前配置了英文和中文两种语言。

lang/en.js

export default {
  app: {
    ACTIVITY_NAME: "Name",
    ACTIVITY_REGION: "Region",
    ...
    ACTIVITY_TIME: "Time",
    TODAY: "Today",
    YESTERDAY: "Yesterday",
    ONE_WEEK_AGO: "One week ago",
    RESET: "RESET",
    SUBMIT: "Submit",
    REQUIRED_ERROR: "{0} is required",
    SUBMIT_FAILED: "Submit failed, do you want to re-enter?"
  }
};

ang/zh-CN.js

export default {
  app: {
    ACTIVITY_NAME: "活动名称",
    ACTIVITY_REGION: "活动区域",
    ...
    ACTIVITY_TIME: "活动时间",
    TODAY: "今天",
    YESTERDAY: "昨天",
    ONE_WEEK_AGO: "一周前",
    RESET: "重置",
    SUBMIT: "提交",
    REQUIRED_ERROR: "{0}不能为空",
    SUBMIT_FAILED: "提交失败, 是否重新输入?"
  }
};

3) 通过选项创建 VueI18n 实例, 并设置Vue 实例i18n选项。

mport i18n from "./i18n";
import App from "./App.vue";

new Vue({
  i18n,
  render: (h) => h(App)
}).$mount("#app");

4) 兼容UI库。本项目UI库使用了element-ui,所以国际化的同时也要将其国际化。本系统中已经实现国际化的element-ui组件有:Datepicker、Select、Pagination、Messagebox、TableTree。完整代码查看这里。element-ui默认不支持 >= 6.x 的 vue-i18n,需要手动处理。

import zhLocale from "element-ui/lib/locale/lang/zh-CN";
import enLocale from "element-ui/lib/locale/lang/en";
import zhBMS from "./lang/zh-CN";
import enBMS from "./lang/en";

Vue.use(VueI18n);

const DEFAULT_LANG = "zh";
const LOCALE_KEY = "LOCALE";

const messages = {
  zh: { ...zhLocale, ...zhBMS },
  en: { ...enLocale, ...enBMS }
};

5) 模块化
该模块提供了一个setup()的方法,给使用者修改当前使用语种的能力。同时,我们在setup里还做了三件事:

  • 将当前语种存到 localStorage中,保存用户的使用习惯;
  • 将给body添加语种相关的class,因为不同语言可能导致排版出现差异,我们需要适配;
  • 将将当前语种存到Vue的全局配置中,以便未来可能的使用;
  • 将i18n绑定到window,这样方便纯JS文件直接用i18n对象。

点击此处查看完整代码。

五、使用案例

1) template模板中使用 $t

<el-form-item
  :label="$t('app.ACTIVITY_REGION')"
  :rules="[
    {
      required: true,
      message: $t('app.REQUIRED_ERROR', [$t('app.ACTIVITY_REGION')]),
    },
  ]"
  prop="region"
>

2) JS中使用 this.$t

this.$refs.ruleForm.validate((valid) => {
  if (valid) {
    this.$confirm(this.$t("app.SUBMIT_FAILED"), {
      type: "warning",
    })
      .then(() => {
        this.resetForm();
      })
      .catch(() => {});
  }
});

3) 模板使用占位或参数
语言环境信息如下

export default {
  app: {
    REQUIRED_ERROR: "{0}不能为空"
  }
};

模板如下:

<el-form-item
  :label="$t('app.ACTIVITY_NAME')"
  :rules="[
    {
      required: true,
      message: $t('app.REQUIRED_ERROR', [$t('app.ACTIVITY_NAME')]),
    },
  ]"
  prop="name"
  class="region-name"
>

4) 使用 element-ui中的语言环境信息

<el-button type="primary" @click="submitForm">
  {{ $t("el.colorpicker.confirm") }}
</el-button>

5) 配合v-for灵活使用

语言环境信息如下:

export default {
  app: {
    REGION_BG: "北京",
    REGION_SH: "上海",
    REGION_GZ: "广州",
    REGION_SZ: "深圳",
  }
}

模板如下:

<el-select v-model="form.region" clearable class="region-select">
    <el-option
      v-for="item in regionOptions"
      :key="item"
      :label="$t('app.REGION_' + item)"
      :value="item"
    />
  </el-select>

6) 更多高级用法
复数、日期时间本地化、数字本地化等,点击此处查看

六、使用案例

  • https://kazupon.github.io/vue-i18n/zh/introduction.html
  • https://element.eleme.cn/#/zh-CN/component/i18n
  • https://panjiachen.github.io/vue-element-admin-site/zh/guide/advanced/i18n.html