IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 【vue-element-admin】4.x 添加 i18n 国际化多语言切换 -> 正文阅读

[JavaScript知识库]【vue-element-admin】4.x 添加 i18n 国际化多语言切换

花裤衩前辈的vue-element-admin模块在4.x的大版本中去除了对i18n国际化的支持,本次因项目需要,在一个基于 vue-element-admin V4.2.1 版本模板开发的项目中,需要加入中英文切换的支持,此处添加参考了 vue-element-admin 模板早期支持国际化版本的语言切换组件,具体步骤如下。

安装 vue-i18n 插件

npm install --save vue-i18n

安装后 package.json 中如下:
在这里插入图片描述
node_modules中,如下:
在这里插入图片描述

添加自定义配置

创建 src/lang/index.js,其中 elementEnLocale elementZhLocale 是 Element UI 自带的多语言配置,enLocale zhLocale 是自定义的中英文配置,与 src/lang/index.js 在同一目录下。

// 进行多语言支持配置
import Vue from 'vue' // 引入Vue
import VueI18n from 'vue-i18n' // 引入国际化的插件包
import Cookies from 'js-cookie' // 引入 Cookies 保存当前默认语言选项

import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui 英文包
import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'// element-ui 中文包

// 自定义的中英文配置
import enLocale from './en'
import zhLocale from './zh'


Vue.use(VueI18n); // 全局注册国际化包

// 创建国际化插件的实例
const i18n = new VueI18n({
  // 指定语言类型 zh表示中文  en表示英文 set locale 设置默认初始化的语言 i18n
  locale: Cookies.get('language') || 'zh',
  // 将将elementUI语言包 和自定义语言包 加入到插件语言数据里 set locale messages
  messages: {
    // 英文环境下的语言数据
    en: {
      ...enLocale,
      ...elementEnLocale
    },
    // 中文环境下的语言数据
    zh: {
      ...zhLocale,
      ...elementZhLocale
    }
  }
});

export default i18n

en.js示例

export default {
  route:{
    dashboard: 'Dashboard',
  },
  // 登录页
  loginPage:{
    username: 'Username',
    password: 'Password',
    login:'Login',
  }
}

zh.js示例

export default {
  route: {
    dashboard: '首页',
  },
  loginPage:{
    username: '请输入用户名',
    password: '请输入密码',
    login:'登录',
  }
}

在 main.js 中挂载 i18n 插件

import i18n from "@/lang/i18n";
Vue.use(Element, {
  // set element-ui default size
  size: Cookies.get('size') || 'medium',
  // 配置elementUI 语言转换关系
  i18n: (key, value) => i18n.t(key, value)
});

new Vue({
  el: '#app',
  router,
  store,
  i18n,
  render: h => h(App)
});

修改模板(组件)渲染

当我们引入VueI18n语言插件之后,每个组件实例都拥有了一个$t()方法,这个方法可以帮助我们进行语言转换,可以根据当前的语言类型,使用传入的key去寻找当前key对应的文本。
$t('属性名')来访问配置文件(en.js和ch.js)对象里的属性。这里的$?t()是引入了i18n之后,自动挂载在vue实例上的功能。

vuex组件 的store模块添加封装方法

src/store/modules/app.js 中添加以下内容

import Cookies from 'js-cookie'

const state = {
  // ...其他配置项省略...
  // set locale 设置默认初始化的语言 i18n
  language: Cookies.get('language') || 'zh'
}

const mutations = {
   // ...其他配置项省略...
  SET_LANGUAGE: (state, language) => {
    state.language = language
    Cookies.set('language', language)
  }
}

const actions = {
  // ...其他配置项省略...
  setLanguage({ commit }, language) {
    commit('SET_LANGUAGE', language)
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

注意: app.js 的属性中中配置了命名空间 namespaced: true ,其他组件在通过 this.$store.dispatch() 方法调用时,要在 action 方法名之前加上 前缀路径 app/ ,不然会报错 unknown action type:XXX(未知的操作类型:)

src/store/getters.js 中添加以下内容

const getters = {
  sidebar: state => state.app.sidebar,
  size: state => state.app.size,
  language: state => state.app.language,
  // ...其他配置项省略...
}
export default getters

添加实现中英文切换的封装组件

组件名:LangSelect

<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 command="zh" :disabled="language==='zh'">中文</el-dropdown-item>
      <el-dropdown-item command="en" :disabled="language==='en'">English</el-dropdown-item>
    </el-dropdown-menu>
  </el-dropdown>
</template>

<script>
  export default {
    name: "LangSelect",
    computed: {
      language() {
        return this.$store.getters.language
      }
    },
    methods: {
      handleSetLanguage(lang) {
        this.$i18n.locale = lang
        this.$store.dispatch('app/setLanguage', lang)
        this.$message.success('switch language success')
        // 重新刷新页面更改语言
        location.reload()
      }
    }
  }
</script>

<style scoped>
  .international-icon {
    font-size: 20px;
    cursor: pointer;
    vertical-align: -5px!important;
  }
</style>

登录页面添加中英文切换组件

登录页位置 src/views/login/index.vue,添加中英文切换后,登录页面全局代码

<template>
  <div class="fullscreen" :style="'background-color: red;background: url('+loginImgJpgUrl+') ;background-size: cover'">
    <!--左上角logo-->
    <div class="login-logo" :style="'background: url('+loginLogoImgPngUrl+') no-repeat 10px center'"></div>

    <div class="login-box" :style="'background: url('+loginImgPngUrl+') no-repeat center'">

      <el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on"
               label-position="left" style="display: block;">
        <div class="m-list-group" style="">
          <el-form-item prop="username">
            <el-input ref="usernameRef" v-model="loginForm.username"
                      :placeholder="$t('loginPage.username')" name="username" type="text"
                      tabindex="1" autocomplete="on" style="width: 280px;margin-left: 412px">
              <template slot="prepend">
                <svg-icon style="height: 18px;width: 15px;" color="green" icon-class="user"></svg-icon>
              </template>
            </el-input>
          </el-form-item>
          <el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="bottom" manual
                      style="width: 280px;margin-left: 412px">
            <el-form-item prop="password">
              <el-input ref="passwordRef" :key="passwordType" v-model="loginForm.password" :type="passwordType"
                        :placeholder="$t('loginPage.password')"
                        name="password" tabindex="2" autocomplete="on"
                        @keyup.native="checkCapslock"
                        @blur="capsTooltip = false"
                        @keyup.enter.native="handleLogin"
              >
                <template slot="prepend">
                  <svg-icon style="height: 18px;width: 15px;" color="green" icon-class="password"></svg-icon>
                </template>
                <template slot="suffix">
                  <div style="color: black;margin-top: 8px;margin-right: 5px" @click="showPwd">
                    <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"></svg-icon>
                  </div>
                </template>
              </el-input>
            </el-form-item>
          </el-tooltip>
          <el-form-item>
            <el-button :loading="loading" type="primary" style="width: 200px;margin-left: 422px;margin-top: 40px"
                       @click.native.prevent="handleLogin">{{$t('loginPage.login')}}
            </el-button>
            <lang-select class="set-language"></lang-select>
          </el-form-item>
        </div>
      </el-form>
    </div>

    <!--密码修改对话框-->
    <user-update-pwd
      ref="UserUpdatePwdRef"
      :first-login="ifFirstLogin"
    ></user-update-pwd>
  </div>
</template>

<script>
  import {validUsername} from '@/utils/validate'
  import UserUpdatePwd from "@/components/UpdatePwd/UserUpdatePwd";
  import LangSelect from '@/components/LangSelect'

  export default {
    name: 'Login',
    components: {
      UserUpdatePwd,
      LangSelect
    },
    data() {
      // 用户名校验
      const validateUsername = (rule, value, callback) => {
        if (!validUsername(value)) {
          callback(new Error('Please enter the correct user name'))
        } else {
          callback()
        }
      }
      // 密码校验
      const validatePassword = (rule, value, callback) => {
        if (value.length < 1) {
          callback(new Error('The password can not be less than 1 digits'))
        } else {
          callback()
        }
      }
      return {
        loginImgJpgUrl: require('./components/login.jpg'),
        loginImgPngUrl: require('./components/login.png'),
        loginLogoImgPngUrl: require('./components/logo.png'),

        // 当前登录账户是否是首次登录
        ifFirstLogin: false,

        // 登录表单
        loginForm: {
          username: '',
          password: ''
        },
        loginRules: {
          username: [{required: true, trigger: 'blur', validator: validateUsername}],
          password: [{required: true, trigger: 'blur', validator: validatePassword}]
        },
        passwordType: 'password',
        capsTooltip: false,
        loading: false,
        redirect: undefined,
        otherQuery: {}
      }
    },
    watch: {
      $route: {
        handler: function (route) {
          const query = route.query
          if (query) {
            this.redirect = query.redirect
            this.otherQuery = this.getOtherQuery(query)
          }
        },
        immediate: true
      }
    },
    created() {
      // window.addEventListener('storage', this.afterQRScan)
    },
    mounted() {
      if (this.loginForm.username === '') {
        this.$refs.usernameRef.focus()
      } else if (this.loginForm.password === '') {
        this.$refs.passwordRef.focus()
      }
    },
    destroyed() {
      // window.removeEventListener('storage', this.afterQRScan)
    },
    methods: {
      checkCapslock(e) {
        // console.log('KeyboardEvent-----', e)
        const {key} = e
        this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z')
      },
      showPwd() {
        if (this.passwordType === 'password') {
          this.passwordType = ''
        } else {
          this.passwordType = 'password'
        }
        this.$nextTick(() => {
          this.$refs.passwordRef.focus()
        })
      },
      handleLogin() {
        this.$refs.loginFormRef.validate(valid => {
          if (valid) {
            this.loading = true
            // 调用vuex的 store 中的 对应的action
            this.$store.dispatch('user/login', this.loginForm)
                .then(res => {
                  // 此处的返回值没有用到,可以不返回
                  console.log('login.vue--user/login--:', res)
                  // console.log('this.redirect---', this.redirect)
                  // console.log('this.otherQuery---', this.otherQuery)
                  let account = res.account
                  this.ifFirstLogin = res.ifFirstLogin
                  if (this.ifFirstLogin) {
                    this.$refs.UserUpdatePwdRef.showDialog(account)
                  } else {
                    let ifNotifyUpdatePwd = res.ifNotifyUpdatePwd
                    if (ifNotifyUpdatePwd) {
                      // this.$message.warning('账户长时间未修改密码,请定时更新,确保账户安全!')
                      this.$notify({
                        title: '密码更新提示',
                        dangerouslyUseHTMLString: true,
                        message: '账户' + '<span style="color: red;font-weight: bolder">' + '长时间未修改密码' + '</span>' + ',请定时更新,确保账户安全!',
                        type: 'warning',
                        offset: 100,
                        duration: 30000 // 单位:毫秒,从显示到关闭的时间间隔
                      })
                    }
                    this.$router.push({path: this.redirect || '/', query: this.otherQuery})
                    this.loading = false
                  }

                }).catch(error => {
              this.loading = false
            })
          } else {
            console.log('error submit!!')
            return false
          }
        })
      },
      getOtherQuery(query) {
        return Object.keys(query).reduce((acc, cur) => {
          if (cur !== 'redirect') {
            acc[cur] = query[cur]
          }
          return acc
        }, {})
      }
    }
  }
</script>

<style lang="scss">
  .fullscreen {
    position: absolute;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .m-list-group {
    border-radius: 3px;
    padding: 0;
    margin: 120px 0 20px;
  }

  .set-language {
    /*color: #e3e3e3;*/
    /*position: absolute;*/
    /*top: 5px;*/
    left: 30px;
    /*right: 0px;*/
  }

  .login-box {
    float: right;
    position: relative;
    width: 720px;
    height: 420px;
    margin: 0 auto;
    padding: 0px 15px;
  }

  .login-logo {
    position: absolute;
    width: 80px;
    height: 35px;
    top: 80px;
    left: 120px;
  }

  .login-box .m-input {
    padding: 10px;
    border: none;
    outline: none;
    box-sizing: border-box;
  }

  .login-box .m-btn {
    border-radius: 5px;
    font-size: 15px;
    height: 35px;
    color: #fff;
    background-color: #256ddb;
    display: inline-block;
    text-align: center;
    cursor: pointer;
    outline: none;
    border: 1px solid #256ddb;
    box-sizing: border-box;
    text-decoration: none;
  }

  .login-box .m-btn:hover {
    background-color: #1e4bae;
  }

  .login-box .m-btn:active {
    opacity: 0.8;
  }

  @media (max-width: 768px) {
    .login-box {
      width: auto;
    }
  }
</style>

至此,登录页面添加中英文切换组件完成, 可正常替换,全局的自定义中英文对照文档zh.jsen.js需要一点点的完善。原理是将设置的语言种类存储在浏览器的Cookies中作为全局配置参数,每次渲染页面之前i18n插件从浏览器Cookies中获取此配置参数,转换成对应是语言。
同理登录之后,导航栏的右上角页也需要添加一个中英文切换组件,此处就不再赘述了。

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 18:27:19  更:2022-04-22 18:29:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:30:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码