vue-i18n 实现国际化,支持切换不同语言

这篇具有很好参考价值的文章主要介绍了vue-i18n 实现国际化,支持切换不同语言。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

需求:后台管理系统,可以实现语言切换

实现过程:用的i18n来实现的语言切换,网上能看到好多模板,根据自己的需求,修改一下即可使用,大概都是差不多的,因为涉及到后端,所以要跟后端协商一致决定去写,我的设计思路是跟着后端设计更改的,如下:

1.语言是后端接口返回的,不是前端写死的(eg:中文、English),由于我的切换语言,设计到了两个地方,一个是登录页面,一个是登录之后的页面,后端不能给一个接口,要区分两个接口给前端,所以关于这个需求,前端自己加了判断(如果你们后端给一个接口,则可忽略我写的判断)

2.根据自己选择的哪一种语言,需要通过接口传给后端,后端会将其存到某个用户表里,这个接口也是两个,也需写判断

3.如果用户是从来没有选择过语言的用户,则前端需要规定默认语言,且要与后端的默认语言保持一致,于是和后端协商一致决定,其默认语言是后端返回的语言的第一个

4.如果后端有选择是哪个语言,我们将其传给了后端,后端讲其存入了用户表,用户登录之后,会在用户接口里,返回给我们,我们将其存 localStorage,这时候,就算用户再次退出到登录页面,我们就可以将用户默认语言做一个判断,判断存入localStorage的language是否有值,如果有值,则登录页面的语言取localStorage的language,如果没有,则还是取后端语言接口返回的第一个值,这样,就可以把用户已经选择过的语言,在登录页面也能进行判断用户习惯

文档: vue-i18n

一.安装vue-i18n 

npm install vue-i18n

二.在mian.js引入

//i18n
import i18n from "@/lang";
Vue.use(Element,{
  size:Cookies.get('size') || 'small',
  i18n:(key,value)=>i18n.t(key,value)
})
new Vue({
  el: '#app',
  router,
  store,
  i18n,
  render: h => h(App)
})

三.在src下创建一个lang文件夹,其中包括en.js、zh.js、index.js文件

1.src/lang/en.js

export default {
  login: {
    username:'username',//用户名
    password:'password',//密码
    code:'code',//验证码
    login:'login',//登录
    logging: 'logging...',//登录...
    storage:'remember the password',//记住密码
  },
  home:{
    welcome:'Welcome to use',//欢迎使用
  },
  route:{
    homepage:'Home page',//首页
    profile:'Profile',//个人中心
    系统管理:"system manage",//系统管理
    系统监控:'system monitor',
    系统工具:"system tools",
    创建运单:"create waybill",
    批量运单:'waybill batch',
    运单管理:"waybill manage",
    审核管理:'audits manage',
    充值管理:'recharge manage',
    失败订单详情:'failed order details',
    运费管理:'freight manage',
    账单管理:'bill manage',
    仓库管理:'warehouse manage',
    用户管理:'user query',
    角色管理:'user query',
    菜单管理:'menu manage',
    部门管理:'dept manage',
    岗位管理:'position manage',
    字典管理:'dictionary manage',
    参数设置:'parameter settings',
    通知公告:'notice announcent',
    日志管理:'log manage',
    操作日志:'operation log',
    登录日志:'login log',
    在线用户:'online users',
    定时任务:'scheduled tasks',
    数据监控:'data monitor',
    服务监控:'service monitor',
    运单审核:'audits order',
    充值审核:'audits recharge',
    客户充值:'customer recharge',
    我的充值:'my recharge',
    基础运费:'basic freight',
    其他附加费:'other surcharges',
    燃油附加费:'fuel surcharge',
    旺季附加费:'peak surcharge',
    全部账单:'bill whole',
    我的账单:'bill my',
    订单详情:'order details',
    仓库配置:'warehouse configuration',
    基础成本价:'basic cost',
    其他成本价:'other cost',
    旺季成本价:'peak cost',
    查询:'query',
    新增:'add',
    修改:'alter',
    导入:'import',
    导出:'export',
    删除:'remove',
    重置密码:'reset passwords',
    仓库:'warehouse',
    批量强退:'batch forcing',
    单条强退:'single strong back',
    众拓网通官网:'Zhongtuo Netcom official website',
    下载失败订单:'download failed order',
    下载面单:'download sheet',
    客户查询:'customer query',
    已取消导出:'export cancelled',
    取消审核中导出:'export cancel audit',
    审核:'audit',
    审核平账:'audit and balance accounts',
    审核平账明细:'review the balance of accounts details',
    充值:'top up',
    充值记录:'recharge record',
    消费记录:'expense calendar',
    补交凭证:'resubmit documents',
    回显:'echo',
    审核明细:'audit detail',
    充值明细:'top-up details',
    失败订单详情查询:'failed order details query',
    复制:'copy',
    基础运费列表:'base freight list',
    客户列表:'customer list',
  },
}

 2.src/lang/zh.js

export default {
  login: {
    username:'用户名',//用户名
    password:'密码',//密码
    code:'验证码',//验证码
    login:'登录',//登录
    logging: '登录...',//登录...
    storage:'记住密码',//记住密码
  },
  home:{
    welcome:'欢迎使用',//欢迎使用
  },
  route:{
    homepage:'首页',//首页
    profile:'个人中心',//个人中心
    系统管理:"系统管理",//系统管理
    系统监控:'系统监控',
    系统工具:"系统工具",
    创建运单:"创建运单",
    批量运单:'批量运单',
    运单管理:"运单管理",
    审核管理:'审核管理',
    充值管理:'充值管理',
    失败订单详情:'失败订单详情',
    运费管理:'运费管理',
    账单管理:'账单管理',
    仓库管理:'仓库管理',
    用户管理:'用户管理',
    角色管理:'角色管理',
    菜单管理:'菜单管理',
    部门管理:'部门管理',
    岗位管理:'岗位管理',
    字典管理:'字典管理',
    参数设置:'参数设置',
    通知公告:'通知公告',
    日志管理:'日志管理',
    操作日志:'操作日志',
    登录日志:'登录日志',
    在线用户:'在线用户',
    定时任务:'定时任务',
    数据监控:'数据监控',
    服务监控:'服务监控',
    运单审核:'运单审核',
    充值审核:'充值审核',
    客户充值:'客户充值',
    我的充值:'我的充值',
    基础运费:'基础运费',
    其他附加费:'其他附加费',
    燃油附加费:'燃油附加费',
    旺季附加费:'旺季附加费',
    全部账单:'全部账单',
    我的账单:'我的账单',
    订单详情:'订单详情',
    仓库配置:'仓库配置',
    基础成本价:'基础成本价',
    其他成本价:'其他成本价',
    旺季成本价:'旺季成本价',
    查询:'查询',
    新增:'新增',
    修改:'修改',
    导入:'导入',
    导出:'导出',
    删除:'删除',
    重置密码:'重置密码',
    仓库:'仓库',
    批量强退:'批量强退',
    单条强退:'单条强退',
    众拓网通官网:'众拓网通官网',
    下载失败订单:'下载失败订单',
    下载面单:'下载面单',
    客户查询:'客户查询',
    已取消导出:'已取消导出',
    取消审核中导出:'取消审核中导出',
    审核:'审核',
    审核平账:'审核平账',
    审核平账明细:'审核平账明细',
    充值:'充值',
    充值记录:'充值记录',
    消费记录:'消费记录',
    补交凭证:'补交凭证s',
    回显:'回显',
    审核明细:'审核明细',
    充值明细:'充值明细',
    失败订单详情查询:'失败订单详情查询',
    复制:'复制',
    基础运费列表:'基础运费列表',
    客户列表:'客户列表',
  },
}

  3.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
import enLocale from './en'
import zhLocale from './zh'

Vue.use(VueI18n)

const messages = {
  en: {
    ...enLocale,
    ...elementEnLocale
  },
  zh: {
    ...zhLocale,
    ...elementZhLocale
  }
}
export function getLanguage() {
  const chooseLanguage = Cookies.get('language')
  if (chooseLanguage) return chooseLanguage
  return 'en'
}
const i18n = new VueI18n({
  locale: getLanguage(),
  messages
})

export default i18n

三.在src/components下创建到LangSelect/index.vue文件(语言切换组件)

<script src="../../api/login.js"></script>
<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 languagelist"  :disabled="$i18n.locale===item.language" :command={languageId:item.languageId,language:item.language}>
        {{item.name}}
      </el-dropdown-item>
    </el-dropdown-menu>
  </el-dropdown>
</template>

<script>
import {checkLanguage, languagelist} from "@/api/menu";
import item from "@/layout/components/Sidebar/Item.vue";
import {languagelistt,checkLanguagee} from '@/api/login'

export default {
  props:{
    //标记他是那个页面过来的,是logo页面,还是登录之后的主页面
    orientation:{
      type:Number,
      default:0
    }
  },
  data(){
    return{
      languagelist:[],
      lang:null,
    }
  },
  computed: {
    item() {
      return item
    },
    language() {
      return this.$store.getters.language
    }
  },
  created() {
    this.getlanguelist()
  },
  methods: {
    //这个是获取后端返回的语言接口
    getlanguelist(){
      //login页面语言接口,接口有两个,但是接口性质是一样的,都是返回语言接口,只不过是一个在登录页面的,一个是登录之后主页面的(如果你们后端返回一个接口,九不用去写这个判断了)
      if(this.orientation==1){
        languagelistt().then((res)=>{
          this.languagelist=res.data
          //拿取user接口存的language,如果有就拿user存的language,如果没有就取后端接口返回的第一个
          const language=localStorage.getItem('language') ||res.data[0].language
          this.$store.dispatch('app/setLanguage', language)
          this.$i18n.locale=language
        })
      }else {
        //主页面语言接口
        languagelist().then((res)=>{
          this.languagelist=res.data
          const language=localStorage.getItem('language')
          this.$store.dispatch('app/setLanguage', language)
          this.$i18n.locale=localStorage.getItem('language')
        })
      }
    },
    handleSetLanguage(lang) {//点击切换事件
      this.$i18n.locale = lang.language
      this.$store.dispatch('app/setLanguage', lang.language)
      this.checkLanguage(lang.languageId)
      this.$message({
        message: 'Switch Language Success',
        type: 'success'
      })
    },
    //传给后端,后端标记是什么语言
    checkLanguage(item){
      //login页面
      if(this.orientation==1){
        checkLanguagee(item).then((res)=>{
          // 传值给前端,前端再把获取到的值,传到login接口里面
          this.$emit("languageid",res.data.languageId)
        })
      }else {
        //主页面
        checkLanguage(item).then((res)=>{
          this.updatePermission()
        })
      }
    },
  }
}
</script>

四.在src/store/modules/app.js 里将language存入vuex和cookie

import Cookies from 'js-cookie'
import { getLanguage } from '@/lang/index'

const state = {
  sidebar: {
    opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
    withoutAnimation: false,
    hide: false
  },
  device: 'desktop',
  language: getLanguage(),
  size: Cookies.get('size') || 'medium'
}

const mutations = {
  TOGGLE_SIDEBAR: state => {
    if (state.sidebar.hide) {
      return false;
    }
    state.sidebar.opened = !state.sidebar.opened
    state.sidebar.withoutAnimation = false
    if (state.sidebar.opened) {
      Cookies.set('sidebarStatus', 1)
    } else {
      Cookies.set('sidebarStatus', 0)
    }
  },
  CLOSE_SIDEBAR: (state, withoutAnimation) => {
    Cookies.set('sidebarStatus', 0)
    state.sidebar.opened = false
    state.sidebar.withoutAnimation = withoutAnimation
  },
  TOGGLE_DEVICE: (state, device) => {
    state.device = device
  },
//语言
  SET_LANGUAGE: (state, language) => {
    state.language = language
    Cookies.set('language', language)
  },
  SET_SIZE: (state, size) => {
    state.size = size
    Cookies.set('size', size)
  },
  SET_SIDEBAR_HIDE: (state, status) => {
    state.sidebar.hide = status
  }
}

const actions = {
  toggleSideBar({ commit }) {
    commit('TOGGLE_SIDEBAR')
  },
  closeSideBar({ commit }, { withoutAnimation }) {
    commit('CLOSE_SIDEBAR', withoutAnimation)
  },
  toggleDevice({ commit }, device) {
    commit('TOGGLE_DEVICE', device)
  },
//语言
  setLanguage({ commit }, language) {
    commit('SET_LANGUAGE', language)
  },
  setSize({ commit }, size) {
    commit('SET_SIZE', size)
  },
  toggleSideBarHide({ commit }, status) {
    commit('SET_SIDEBAR_HIDE', status)
  }
}

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

五.src/modules/user.js,将后端用户信息接口返回的language存入localStorage里

import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'

const user = {
  state: {
    token: getToken(),
    name: '',
    avatar: '',
    roles: [],
    permissions: [],
  },

  mutations: {
    SET_TOKEN: (state, token) => {
      state.token = token
    },
    SET_NAME: (state, name) => {
      state.name = name
    },
    SET_AVATAR: (state, avatar) => {
      state.avatar = avatar
    },
    SET_ROLES: (state, roles) => {
      state.roles = roles
    },
    SET_PERMISSIONS: (state, permissions) => {
      state.permissions = permissions
    },
  },

  actions: {
    // 登录
    Login({ commit }, userInfo) {
      const username = userInfo.username.trim()
      const password = userInfo.password
      const code = userInfo.code
      const uuid = userInfo.uuid
      //语言
      const languageId=userInfo.languageId
      return new Promise((resolve, reject) => {
        login(username, password, code, uuid,languageId).then(res => {
          setToken(res.token)
          commit('SET_TOKEN', res.token)
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    },

    // 获取用户信息
    GetInfo({ commit, state }) {
      return new Promise((resolve, reject) => {
        getInfo(state.token).then(res => {
          const user = res.user
          const avatar = user.avatar == "" ? require("@/assets/image/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
          if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
            commit('SET_ROLES', res.roles)
            commit('SET_PERMISSIONS', res.permissions)
            sessionStorage.setItem('infoCustomers',JSON.stringify(res.customers))
            sessionStorage.setItem('infouser',JSON.stringify(res.user.roles))
            //注:用户已进入页面,调用到用户接口,将用户接口里面的语言存储到localStorage,可以方便用户在登录页面的时候判断语言是中文还是英文(登录页面语言应与user接口保持一直)
            localStorage.setItem('language',JSON.stringify(res.user.language.language).replace(/\"/g, ""))
          } else {
            commit('SET_ROLES', ['ROLE_DEFAULT'])
          }
          commit('SET_NAME', user.userName)
          commit('SET_AVATAR', avatar)
          resolve(res)
        }).catch(error => {
          reject(error)
        })
      })
    },

    // 退出系统
    LogOut({ commit, state }) {
      return new Promise((resolve, reject) => {
        logout(state.token).then(() => {
          commit('SET_TOKEN', '')
          commit('SET_ROLES', [])
          commit('SET_PERMISSIONS', [])
          removeToken()
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    },

    // 前端 登出
    FedLogOut({ commit }) {
      return new Promise(resolve => {
        commit('SET_TOKEN', '')
        removeToken()
        resolve()
      })
    }
  }
}

export default user

 六.登录页面

 效果图:

1.en:

vue-i18n 实现国际化,支持切换不同语言,vue.js,javascript,前端

2.English:

 vue-i18n 实现国际化,支持切换不同语言,vue.js,javascript,前端

<template>
  <div class="login">
    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
      <div class="titlebox">
        <h3 class="title">{{setName}}</h3>
        <lang-select class="set-language"  @languageid="handlelanguage" :orientation='orientation'/>
      </div>
      <el-form-item prop="username">
        <el-input v-model="loginForm.username" type="text" auto-complete="off" :placeholder="$t('login.username')">
          <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
        </el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input
          v-model="loginForm.password"
          type="password"
          auto-complete="off"
          :placeholder="$t('login.password')"
          @keyup.enter.native="handleLogin"
        >
          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
        </el-input>
      </el-form-item>
      <el-form-item prop="code">
        <el-input
          v-model="loginForm.code"
          auto-complete="off"
          :placeholder="$t('login.code')"
          style="width: 63%"
          @keyup.enter.native="handleLogin"
        >
          <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
        </el-input>
        <div class="login-code">
          <img :src="codeUrl" @click="getCode" class="login-code-img"/>
        </div>
      </el-form-item>
      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">{{$t('login.storage')}}</el-checkbox>
      <el-form-item style="width:100%;">
        <el-button
          :loading="loading"
          size="medium"
          type="primary"
          style="width:100%;"
          @click.native.prevent="handleLogin"
        >
          <span v-if="!loading">{{$t('login.login')}}</span>
          <span v-else>{{$t('login.logging')}}</span>
        </el-button>
      </el-form-item>
    </el-form>
    <!--  底部  -->
    <div class="el-login-footer">
      <span>Copyright © 2021-2022 xxx All Rights Reserved 增值电信业务经营许可证:<a
        href="http://beian.miit.gov.cn" target="_blank">xxxxx</a></span>
    </div>
  </div>
</template>

<script>
import {getCodeImg, login} from "@/api/login";
import Cookies from "js-cookie";
import {decrypt, encrypt} from '@/utils/jsencrypt'
import langSelect from "@/components/LangSelect/index.vue";
import {config} from "@/api/menu";
import {mapGetters, mapState} from "vuex";

export default {
  name: "Login",
  components:{
    langSelect
  },
  data() {
    return {
      orientation:1,
      codeUrl: "",
      cookiePassword: "",
      loginForm: {
        username: "admin",
        password: "",
        rememberMe: false,
        code: "",
        uuid: "",
        languageId:"",
      },
      loginRules: {
        username: [
          { required: true, trigger: "blur", message: this.$t('rules.rulesusername') }
        ],
        password: [
          { required: true, trigger: "blur", message: this.$t('rules.rulespassword')  }
        ],
        code: [{ required: true, trigger: "change", message: this.$t('rules.rulescode') }]
      },
      loading: false,
      redirect: undefined,
      title:"",
    };
  },
  watch: {
    $route: {
      handler: function(route) {
        this.redirect = route.query && route.query.redirect;
      },
      immediate: true
    },
    //监听语言的改变,实时改变校验
    language(newVal, oldVal){
      this.loginRules={
        username: [
          { required: true, trigger: "blur", message: this.$t('rules.rulesusername') }
        ],
          password: [
          { required: true, trigger: "blur", message: this.$t('rules.rulespassword')  }
        ],
          code: [{ required: true, trigger: "change", message: this.$t('rules.rulescode') }]
      }
    }
  },
  created() {
    this.getCode();
    this.getCookie();
    this.getproject()
  },
  computed:{
    ...mapGetters(['getSetName']),
    setName() {
      return this.getSetName || this.title
    },
    ...mapState({
      language: state => state.app.language
    })
  },
  methods: {
    //获取项目名字接口
    getproject(){
      config().then((res)=>{
        this.title=res.msg
      })
    },
    login,
    handlelanguage(name){
      this.loginForm.languageId=name
    },
    //获取验证码
    getCode() {
      getCodeImg().then(res => {
        this.codeUrl = "data:image/gif;base64," + res.img;
        this.loginForm.uuid = res.uuid;
      });
    },
    getCookie() {
      const username = Cookies.get("username");
      const password = Cookies.get("password");
      const rememberMe = Cookies.get('rememberMe')
      this.loginForm = {
        username: username === undefined ? this.loginForm.username : username,
        password: password === undefined ? this.loginForm.password : decrypt(password),
        rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
      };
    },
    handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true;
          if (this.loginForm.rememberMe) {
            Cookies.set("username", this.loginForm.username, { expires: 30 });
            Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
            Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
          } else {
            Cookies.remove("username");
            Cookies.remove("password");
            Cookies.remove('rememberMe');
          }
          this.$store
            .dispatch("Login", this.loginForm)
            .then(() => {
              this.$router.push({ path: this.redirect || "/" });
            })
            .catch(() => {
              this.loading = false;
              this.getCode();
            });
        }
      });
    }
  }
};
</script>

  七.在utils里面新建一个i18n.js

export function generateTitle(title) {
  const hasKey = this.$te('route.' + title)
  if (hasKey) {
    // $t :this method from vue-i18n, inject in @/lang/index.js
    const translatedTitle = this.$t('route.' + title)
    return translatedTitle
  }
  return title
}

 七.根据语言的切换,面包屑的语言也随之更新,src/components/Breadcrumb文件里

1.zh: 

 vue-i18n 实现国际化,支持切换不同语言,vue.js,javascript,前端

2.en: 

vue-i18n 实现国际化,支持切换不同语言,vue.js,javascript,前端 

<template>
<!--  这个是上面的面包屑-->
  <el-breadcrumb class="app-breadcrumb" separator="/">
    <transition-group name="breadcrumb">
      <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
        <span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">
<!--          {{ $t(`route.${item.meta.title}`) }}-->
          {{generateTitle(item.meta.title)}}
        </span>
        <a v-else @click.prevent="handleLink(item)">
<!--          {{ $t(`route.${item.meta.title}`)}}-->
          {{generateTitle(item.meta.title)}}
        </a>
      </el-breadcrumb-item>
    </transition-group>
  </el-breadcrumb>
</template>

<script>
import pathToRegexp from 'path-to-regexp'
import { generateTitle } from '@/utils/i18n'
export default {
  inject:['reload'],
  data() {
    return {
      levelList: null
    }
  },
  watch: {
    $route(route) {
      // if you go to the redirect page, do not update the breadcrumbs
      if (route.path.startsWith('/redirect/')) {
        return
      }
      this.getBreadcrumb()
    },
  },
  created() {
    this.getBreadcrumb()
  },

  methods: {
    generateTitle,
    getBreadcrumb() {
      // only show routes with meta.title
      let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
      const first = matched[0]
      if (!this.isDashboard(first)) {
        matched = [{ path: '/index', meta: { title: 'homepage' }}].concat(matched)
      }
      this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
    },
    isDashboard(route) {
      const name = route && route.name
      if (!name) {
        return false
      }
      return name.trim() === 'Home page'
    },
    pathCompile(path) {
      const { params } = this.$route
      var toPath = pathToRegexp.compile(path)
      return toPath(params)
    },
    handleLink(item) {
      const { redirect, path } = item
      if (redirect) {
        this.$router.push(redirect)
        return
      }
      this.$router.push(this.pathCompile(path))
    }
  }
}
</script>

<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
  display: inline-block;
  font-size: 14px;
  line-height: 50px;
  margin-left: 8px;

  .no-redirect {
    color: #97a8be;
    cursor: text;
  }
}
</style>

八.src\layout\components\Sidebar\SidebarItem.vue文件

1.zh                                                                                  

vue-i18n 实现国际化,支持切换不同语言,vue.js,javascript,前端

2.en

vue-i18n 实现国际化,支持切换不同语言,vue.js,javascript,前端

我用的是若依后台管理系统框架,对于路由是后端接口返回的,所以,路由语言切换只有两种实现方式 ,后端接口返回,缺点,每次新增修改路由,后端都要在数据库里面新增、修改两种语言,较为麻烦,所以路由的语言切换就纯前端进行控制。

<template>
  <div v-if="!item.hidden">
    <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
      <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
        <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
          <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="generateTitle(onlyOneChild.meta.title)" />
        </el-menu-item>
      </app-link>
    </template>

    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
      <template slot="title">
        <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="generateTitle(item.meta.title)" />
      </template>
      <sidebar-item
        v-for="child in item.children"
        :key="child.path"
        :is-nest="true"
        :item="child"
        :base-path="resolvePath(child.path)"
        class="nest-menu"
      />
    </el-submenu>
  </div>
</template>

<script>
import path from 'path'
import { generateTitle } from '@/utils/i18n'
import { isExternal } from '@/utils/validate'
import Item from './Item'
import AppLink from './Link'
import FixiOSBug from './FixiOSBug'

export default {
  name: 'SidebarItem',
  components: { Item, AppLink },
  mixins: [FixiOSBug],
  props: {
    // route object
    item: {
      type: Object,
      required: true
    },
    isNest: {
      type: Boolean,
      default: false
    },
    basePath: {
      type: String,
      default: ''
    }
  },
  data() {
    this.onlyOneChild = null
    return {}
  },
  methods: {
    hasOneShowingChild(children = [], parent) {
      const showingChildren = children.filter(item => {
        if (item.hidden) {
          return false
        } else {
          // Temp set(will be used if only has one showing child)
          this.onlyOneChild = item
          return true
        }
      })

      // When there is only one child router, the child router is displayed by default
      if (showingChildren.length === 1) {
        return true
      }

      // Show parent if there are no child router to display
      if (showingChildren.length === 0) {
        this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
        return true
      }

      return false
    },
    resolvePath(routePath) {
      if (isExternal(routePath)) {
        return routePath
      }
      if (isExternal(this.basePath)) {
        return this.basePath
      }
      return path.resolve(this.basePath, routePath)
    },
    generateTitle
  }
}
</script>

 需要注意的是,对于首页,是前端写的路由,其余的页面路由都是后端接口返回的,所以在前端,针对首页,需要改的是router/index.js

vue-i18n 实现国际化,支持切换不同语言,vue.js,javascript,前端

九.菜单管理,和路由同理,都是后端接口返回,接口返回的语言切换,纯前端处理

1.zh

vue-i18n 实现国际化,支持切换不同语言,vue.js,javascript,前端

2.en 

vue-i18n 实现国际化,支持切换不同语言,vue.js,javascript,前端

 

<script>
  computed: {
    ...mapState({
      language: state => state.app.language
    })
  },
  watch:{
    language(newVal, oldVal){
      this.getList()
    }
  },
methods:{
     getList() {
        this.loading = true;
        listMenu(this.queryParams).then(response => {
          this.menuList = this.handleTree(response.data, "menuId").map(item=>{
            const newItem= {
              ...item,
              menuName:this.$t(`route.${item.menuName}`)
            }
            if (newItem.children && newItem.children.length > 0) {
              newItem.children = this.translateChildren(newItem.children);
            }
            return newItem;
          });
          this.loading = false;
        });
      },
    translateChildren(children) {
      return children.map(item => {
        const newItem = {
          ...item,
          menuName: this.$t(`route.${item.menuName}`),
        };
        if (newItem.children && newItem.children.length > 0) {
          newItem.children = this.translateChildren(newItem.children);
        }
        return newItem;
      });
    },
}
</script>

 十.样式处理,可能中文的长度很短,英文长度很长,样式就会错乱,对于这种情况进行处理

  <el-dialog :title="title" :visible.sync="open" width="850px" append-to-body>
      <el-form ref="form" :model="form" :rules="rules" :label-width="getLabelWidth()">
        <el-row>
          <el-col :span="12">
<!--            公告标题-->
            <el-form-item :label="$t('notice.announcementtitle')" prop="noticeTitle" >
              <el-input v-model="form.noticeTitle" :placeholder="$t('notice.titleipt')" 
              style="width: 260px"/>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">{{$t('operation.confirm')}}</el-button>
        <el-button @click="cancel">{{$t('operation.cancel')}}</el-button>
      </div>
    </el-dialog>
getLabelWidth(){
      let labelWidth = '80px';
      if(this.language=='en'){
        labelWidth = '150px';
      }
      return labelWidth;
    },

十一.对于校验的地方,语言切换之后,并不会再次触发校验的语言切换 ,关于这个点,我是进行了监听,语言是否改变,如果语言改变了,我就再次触发校验,缺点,每次切换语言就会出发校验,并不是,我点击了某个提交按钮,进行的校验触发,例如我上面写的登录页面上的校验

vue-i18n 实现国际化,支持切换不同语言,vue.js,javascript,前端

 以上就是整个实现过程啦,可能有点地方忘记写了,等想到了,再进行完善文章来源地址https://www.toymoban.com/news/detail-518912.html

到了这里,关于vue-i18n 实现国际化,支持切换不同语言的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue3中,国际化插件vue-i18n使用记录,配合VSCode自动化翻译插件i18n Ally

    说明文档: vue-i18n 版本说明: vue: 3.0.0+ vue-i18n: 9.x版 src 目录下新建目录 lang ,存放 i18n 的配置。 新建目录名称: lang (语言)、 locales (语系设定)、 i18n ,这些名称都可被VSCode图标插件( vscode-icons )检测到并美化。 lang 目录下,新建 index.js 文件,引入 vue-i18n 。 语言的配置信

    2024年02月12日
    浏览(42)
  • vue-i18n国际化多语言与多套UI组件库使用(Element Plus、Ant Design Vue、Naive UI)

    demo源码:Vue3 UI Lang 因调研需要,需在同一个项目中集成好几种UI组件库的多语言实现,查看各种组件库的表现情况,以便选定组件库。 注意:这只在调研过程中会如此,实际开发项目中极少存在一个项目中集成多个UI组件库的情况。 本demo实际试验阿拉伯语、法语、葡萄牙语

    2024年02月08日
    浏览(53)
  • 用i18n 实现vue2+element UI的国际化多语言切换详细步骤及代码

    这个地方要注意自己的vue版本和i1n8的匹配程度,如果是vue2点几,记得安装i18n的@8版本,不然会自动安装的最新版本,后面会报错哦,查询了下资料,好像最新版本是适配的vue3。 在src下面新建i18n文件夹,然后在里面新建index.js,里面的内容如下 新建i18n文件夹里面新建config文

    2024年02月14日
    浏览(46)
  • 微信小程序-切换语言(国际化i18n)的方法封装

    最近做的一个小程序的项目, 涉及到了 多语言的切换 , 就想到了之前vue用的多语言插件i18n, 就尝试着在微信开放社区搜了一下, 没有具体的实现, 但是提供了大致的实现思路, 如下: 又结合了很多大佬的分享经验, 试着去封装了一个微信的i18n方法 首先, 我们需要明确一下需要实

    2024年02月05日
    浏览(47)
  • SpringBoot 国际化(i18n) 支持中文键(KEY)的解决方法

    前言: 项目中要解决“中英文”切换的问题,想法是输入key例如“你好”,然后去国际化文件找对应的中文key,然后进行输出,如果没有定义这个key,则输出“你好”。但是中文key在properties文件中会已unicode编码输出,使用中文key时获取不到对应的value。 解决方法: 重构$.

    2024年02月16日
    浏览(44)
  • Vue - i18n 国际化的使用

    参考网址: 使用: https://huaweicloud.csdn.net/638f133edacf622b8df8eb26.html?spm=1001.2101.3001.6650.1utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Eactivity-1-125181861-blog-123845480.235%5Ev38%5Epc_relevant_anti_t3_basedepth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Ea

    2024年02月11日
    浏览(60)
  • SpringBoot+Vue前后端分离项目国际化支持

    i18n.js文件 language.en_US.js文件 language.zh_CN.js文件 messages_en_US.properties文件 messages_zh_CN.properties文件

    2024年02月04日
    浏览(58)
  • i18n(国际化)代码简单实现

    各个国家都有各个国家的语言,如果网站需要让全世界的人使用,那就需要进行国际化功能开发 国际化我知道的一共有两种,其中一种是不同国家不同网站,也就是说页面风格都不一样。另外一种是网站都是一样的,只是里面的文字不同罢了。第一种没啥好说了,毕竟都是两

    2024年02月07日
    浏览(59)
  • 如何在Vue3中配置国际化语言i18n

    1. 安装 vue-i18n 2. 创建一个i8n的配置文件 如:i18nConfig.js 3. 新建语言文件 zh-CN.js 和 en-US.js zh-CN.js 文件 en-US.js 文件 CONFIG.js 文件 4. 在 main.js 里面全局配置 通过上面四步即可配置完毕 下面说一下如何使用,分三种情况 在 .vue 组件中的 template 使用 在 .vue 组件中的 script 中使用 在

    2024年02月09日
    浏览(56)
  • 微信小程序配置实现中英文国际化语言切换

    目录 1,在根目录新建文件夹和js文件 2. 在main.js中设置全局语言状态(默认设置为中文) 3. 页面添加  语言切换按钮(登录页面) 4. 在需要显示的页面导入使用 根目录新建一个locales.js文件, 通用的一些函数可以放在此文件该文件夹下 ,如下图所示 配置中英文字段,字段要一

    2024年02月12日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包