Vue实现国际化与国际化原理深究(前端国际化通用解决方案)

文章目录

国际化实现原理

我们有一个变量 msg ,但是这个 msg 有且只能有两个值:

  1. hello world
  2. 你好世界

要求:根据需要切换 msg 的值

js 实现:

  1. 定义 msg 值的数据源

定义一个对象【messages】,属性是 locale 为语言比如 zh、en 等,value 是一个对象(key、value 的形式),比如定义一个 msg 属性,里面就是对应的值。

  1. 定义切换变量【定义locale】

  2. 定义赋值函数 t 【参数为 key,返回messages[locale][key]】

  3. 为 msg 赋值 【调用 t 函数,传递 key,比如 zh】

html 复制代码
<script>
  // 1. 定义 msg 值的数据源
  const messages = {
    en: {
      msg: 'hello world'
    },
    zh: {
      msg: '你好世界'
    }
  }
  // 2. 定义切换变量
  let locale = 'en'
  // 3. 定义赋值函数
  function t(key) {
    return messages[locale][key]
  }
  // 4. 为 msg 赋值 
  let msg = t('msg')
  console.log(msg);
  // 修改 locale, 重新执行 t 方法,获取不同语言环境下的值

</script>

总结:

  1. 通过一个变量来 控制 语言环境【locale】
  2. 所有语言环境下的数据源要 预先 定义好
  3. 通过一个方法来获取 当前语言指定属性 的值 (如上t函数)
  4. 该值即为国际化下展示值

基于 vue-i18n V9 的国际化实现方案分析

使用 vue-i18n 进行实现(V9 版本)
vue-i18n 的使用可以分为四个部分:

  1. 创建 messages 数据源
  2. 创建 locale 语言变量
  3. 初始化 i18n 实例
  4. 注册 i18n 实例 (注册到Vue实例上 )

1、 安装

npm install vue-i18n@next

2、 创建 i18n/index.js 文件

创建 messages 数据源 (对象)

javascript 复制代码
const messages = {
  en: {
    msg: {
      test: 'hello world'
    }
  },
  zh: {
    msg: {
      test: '你好世界'
    }
  }
}

3、创建 locale 语言变量 (默认英文)
const locale = 'en'

4、初始化 i18n 实例

lang/index.js

javascript 复制代码
import { createI18n } from 'vue-i18n'

const i18n = createI18n({
  // 使用 Composition API 模式,则需要将其设置为false
  legacy: false,
  // 全局注入 $t 函数
  globalInjection: true,
  locale,
  messages
})

export default i18n; // 方便其他js文件使用,可以import导入

5、把 i18n 注册到 vue 实例

javascript 复制代码
export default i18n

6、在 main.js 中导入

javascript 复制代码
// i18n (PS:导入放到 APP.vue 导入之前,因为后面我们会在 app.vue 中使用国际化内容)
import i18n from '@/i18n'
...
app.use(i18n)

项目中完成国际化分成以下几步进行

  1. 封装 langSelect 组件用于修改 locale
  2. 导入 el-locale 语言包
    1. 语言包分为两种
      1. elementUI 语言包
      2. 自定义的语言(比如一些特殊名称等等)
  3. 创建自定义语言包

封装 langSelect 组件

国际化最终会在全局做国际化的内容修改,因此应当把国际化保存到vuex中,还有对应的本地缓存中。

首先在 vuex 中创建国际化相关的变量

javascript 复制代码
import { LANG } from '@/constant' // 常量
import { getItem, setItem } from '@/utils/storage'
export default {
  namespaced: true,
  state: () => ({
    ...
    language: getItem(LANG) || 'zh' // 优先从本地缓存获取
  }),
  mutations: {
    ...
    /**
     * 设置国际化
     */
    setLanguage(state, lang) {
      setItem(LANG, lang) // 保存本地缓存
      state.language = lang  // 设置新值
    }
  },
  actions: {}
}

使用el-dropdown组件

如果当前语言是中文,选型中已经选择的"中文"是灰色的不能点击的。

html 复制代码
<template>
  <el-dropdown
    trigger="click" // 点击事件
    class="international"
    @command="handleSetLanguage" // 点击事件回调方法,当用户选择下拉菜单中的选项时,触发 handleSetLanguage 方法,该方法根据用户选择的语言进行处理。
    >el-dropdown上会有提示
    <div> // 实现鼠标移入到el-dropdown上会有提示
      <el-tooltip content="国际化" :effect="effect"> // effect实现对应样式,tooltip的样式
        <svg-icon icon="language" />
      </el-tooltip>
    </div>
    <template #dropdown> // 具名插槽,允许你自定义其下拉菜单的内容
      <el-dropdown-menu>
        // 实现当前是啥语言,对应选项置灰不能点击
        <el-dropdown-item :disabled="language === 'zh'" command="zh">
          中文
        </el-dropdown-item>
        <el-dropdown-item :disabled="language === 'en'" command="en">
          English
        </el-dropdown-item>
      </el-dropdown-menu>
    </template>
  </el-dropdown>
</template>

<script setup>
  import { useI18n } from 'vue-i18n'
  import { defineProps, computed } from 'vue'
  import { useStore } from 'vuex'
  import { ElMessage } from 'element-plus'

  defineProps({ // 接收父组件的props
    // tooltip的样式
    effect: {
      type: String,
      default: 'dark',
      validator: function(value) { // 只有两个值
        // 这个值必须匹配下列字符串中的一个
        return ['dark', 'light'].indexOf(value) !== -1
      }
    }
  })

  const store = useStore()
  const language = computed(() => store.getters.language) // 获取到当前中英文的状态

  // 切换语言的方法
  const i18n = useI18n()
  const handleSetLanguage = lang => { // 根据el-dropdown-item的command属性
    // 切换i18n的locale
    i18n.locale.value = lang
    // 修改vuex保存的language
    store.commit('app/setLanguage', lang)
    // 对应的提示
    ElMessage.success('更新成功')
  }
</script>

具名插槽在组件内部是这样定义的, 在组件内部,el-dropdown 可能像这样定义了 dropdown 插槽:

html 复制代码
<slot name="dropdown"></slot>

navbar 中导入 LangSelect 使用

html 复制代码
<template>
  <div class="navbar">
    ...
    <div class="right-menu">
      <lang-select class="right-menu-item hover-effect" />
      <!-- 头像 -->
      ...
    </div>
  </div>
</template>

<script setup>
import LangSelect from '@/components/LangSelect'
...
</script>

<style lang="scss" scoped>
.navbar {
  ...

  .right-menu {
    ...

    ::v-deep .right-menu-item {
      display: inline-block;
      padding: 0 18px 0 0;
      font-size: 24px;
      color: #5a5e66;
      vertical-align: text-bottom;

      &.hover-effect {
        cursor: pointer;
      }
    }

    ...
}
</style>

element-plus 国际化处理(旧版本)

那么对于语言包来说,我们整个项目中会分成两部分:

  1. element-plus 语言包:用来处理 element 组件的国际化功能
  2. 自定义语言包:用来处理 element 组件的国际化功能

目前最新版本的element-plus 支持 vue-i18n 功能,以前是不支持的,需要自己单独处理。【暂时不管】

plugins/index 中导入 element 的中文、英文语言包:

javascript 复制代码
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import en from 'element-plus/lib/locale/lang/en'

注册 element 时,根据当前语言选择使用哪种语言包

javascript 复制代码
import store from '@/store'

export default app => {
  app.use(ElementPlus, {
    locale: store.getters.language === 'en' ? en : zhCn
  })
}

自定义语言包国际化处理

自定义语言包我们使用了 commonJS 导出了一个对象,这个对象就是所有的 自定义语言对象
中文语言包

javascript 复制代码
export default {
  login: {
    title: '用户登录',
    loginBtn: '登录',
    usernameRule: '用户名为必填项',
    passwordRule: '密码不能少于6位',
    desc: `
    测试权限账号:<br />
    提供三种权限账号:<br />
    1. 超级管理员账号: super-admin <br />
    2. 管理员账号:admin <br />
    3. 测试可配置账号:test <br />
    密码统一为:123456 <br />
    <br />
    导入用户账号:<br />
    可使用导入的用户名登录 <br />
    密码统一为:123456  <br />
    <b>注意:导入用户区分中英文库!!!!</b>
    `
  },
  route: {
    profile: '个人中心',
    chart: '数据可视化', // ...

英文语言包

javascript 复制代码
export default {
  login: {
    title: 'User Login',
    loginBtn: 'Login',
    usernameRule: 'Username is required',
    passwordRule: 'Password cannot be less than 6 digits',
    desc: `
    Test authority account:<br />
     Provide three kinds of authority accounts:<br />
     1. Super administrator account: super-admin <br />
     2. Administrator account: admin <br />
     3. Test configurable account: test <br />
     The uniform password is: 123456 <br />
     <br />
     Import user account:<br />
     You can log in with the imported username <br />
     The password is unified as: 123456 <br />
     <b>Note: Import user-discriminatory Chinese and English libraries! ! ! ! </b>
    `
  },
  route: {
    profile: 'Profile',
    chart: 'chart',

lang/index 中,导入语言包

javascript 复制代码
import mZhLocale from './lang/zh'
import mEnLocale from './lang/en'

const messages = {
  en: {
    msg: {
      ...mEnLocale
    }
  },
  zh: {
    msg: {
      ...mZhLocale
    }
  }
}

处理项目国际化内容

在 Vue 的模版中使用国际化:

html 复制代码
<div class="title-container">
  <h3 class="title">{{ $t('msg.login.title') }}</h3>
  <lang-select class="lang-select" effect="light"></lang-select>
</div>

在 Vue 的 js 代码中使用的话【组件中使用 i18n】:

javascript 复制代码
// 验证规则
const i18n = useI18n()
const loginRules = ref({
  username: [
    {
      required: true,
      trigger: 'blur',
      message: computed(() => {
        return i18n.t('msg.login.usernameRule')
      })
    }
  ],

在 js 代码中直接导入即可

code\src\views\login\rules.js

javascript 复制代码
import i18n from '@/i18n'
export const validatePassword = () => {
  return (rule, value, callback) => {
    if (value.length < 6) {
      callback(new Error(i18n.global.t('msg.login.passwordRule')))
    } else {
      callback()
    }
  }
}

国际化缓存处理(刷新页面后国际化丢失)

问题:切换英文后,没有保留,所以刷新页面后又变成默认中文的界面了。

我们希望在 刷新页面后,当前的国际化选择可以被保留 ,所以想要实现这个功能,那么就需要进行 国际化的缓存处理

此处的缓存,我们依然通过两个方面进行:

  1. **vuex**** 缓存**
  2. **LocalStorage**** 缓存**

**i18n/index** 中,创建 **getLanguage** 方法:(之前已经缓存过了,这里只需要读取即可)

javascript 复制代码
import store from '@/store'
/**
 * 返回当前 lang
 */
function getLanguage() {
  return store && store.getters && store.getters.language
}

修改 createI18nlocalegetLanguage()

javascript 复制代码
const i18n = createI18n({
  ...
  locale: getLanguage()
})

国际化方案总结

国际化是前端项目中的一个非常常见的功能,那么在前端项目中实现国际化主要依靠的就是 vue-i18n 这个第三方的包。

i18n 的使用,整体来说就分为这么四步:

  1. 创建 messages 数据源
  2. 创建 locale 语言变量
  3. 初始化 i18n 实例
  4. 注册 i18n 实例

核心的内容其实就是 数据源的部分,但是大家需要注意,如果你的项目中使用了 第三方组件库 ,那么不要忘记 第三方组件库的数据源 需要 单独 进行处理!

关于 element-plus 国际化问题更新

现在 element-plus 已经提供了 国际化的处理方案,我们可以直接通过 el-config-provider 组件中的 locale 属性来指定当前国际化环境。

html 复制代码
<template>
  <el-config-provider :locale="zhCn">
    <app />
  </el-config-provider>
</template>

<script setup lang="ts">
  import { ElConfigProvider } from 'element-plus'
  import zhCn from 'element-plus/es/locale/lang/zh-cn'
</script>

code\src\App.vue

html 复制代码
<template>
  <el-config-provider :locale="store.getters.language === 'en' ? en : zhCn">
    <router-view />
  </el-config-provider>
</template>

<script setup>
  // ......
  import zhCn from 'element-plus/lib/locale/lang/zh-cn'
  import en from 'element-plus/lib/locale/lang/en'
  // ......
</script>
相关推荐
小华同学ai9 分钟前
ShowDoc:Star12.3k,福利项目,个人小团队的在线文档“简单、易用、轻量化”还专门针对API文档、技术文档做了优化
前端·程序员·github
一雨方知深秋10 分钟前
智慧商城:封装getters实现动态统计 + 全选反选功能
开发语言·javascript·vue2·foreach·find·every
海威的技术博客12 分钟前
关于JS中的this指向问题
开发语言·javascript·ecmascript
王解26 分钟前
Vue CLI 脚手架创建项目流程详解 (2)
前端·javascript·vue.js
刘大浪30 分钟前
vue.js滑动到顶便锁定位置
前端·javascript·vue.js
小金刚®36 分钟前
构建简洁之美:我的第一个前端页面
前端
ordinary901 小时前
指令-v-for的key
前端·javascript·vue.js
rpa_top1 小时前
RPA 助力电商:自动化商品信息上传,节省人力资源 —— 以影刀 RPA 为例【rpa.top】
大数据·前端·人工智能·自动化·rpa
新时代农民工--小明1 小时前
前端自动化部署更新,自动化打包部署
运维·前端·自动化
前端Hardy1 小时前
HTML&CSS:酷炫的3D开关控件
前端·javascript·css·3d·html