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>
相关推荐
2301_7891695413 分钟前
react crash course 2024 (1)理论概念
前端·react.js·前端框架
GDAL19 分钟前
HTML5中Checkbox标签的深入全面解析
前端·html·html5
Java开发追求者38 分钟前
npm镜像源证书过期的问题解决
前端·npm·node.js·npm镜像源证书过期的问题解决
宝子向前冲1 小时前
React中九大常用Hooks总结
前端·javascript·react.js
小白小白从不日白1 小时前
react 基础语法
前端·react.js
岸边的风1 小时前
前端Excel热成像数据展示及插值算法
前端·算法·excel
不良人龍木木2 小时前
sqlalchemy FastAPI 前端实现数据库增删改查
前端·数据库·fastapi
c1tenj23 小时前
Jedis,SpringDataRedis
前端
Code成立3 小时前
HTML5中IndexedDB前端本地数据库
前端·数据库·html5·indexeddb