神马?还不会国际化???

295 阅读3分钟

vue3+element plus+vue-i18操作步骤

首先安装vue-i18n

npm install vue-i18n

或者

yarn add vue-i18n

如果配置文件没问题,报错vue-i18n的问题,大概是依赖的问题,vue-i18n更新最新

npm install vue-i18n@latest

或者

yarn add vue-i18n@latest

在vscode上安装i18n-ally插件

如图:

Pasted image 20240820142415.png

vscode的setting关于i18n-ally的配置

"i18n-ally.localesPaths": ["src/locales"],// 指定翻译文件存放的路径
"i18n-ally.keystyle": "nested",// 设置键的样式为嵌套(例如:foo.bar)
"i18n-ally.translate.engines": ["google","google-cn","deepl"],// 指定翻译时使用的引擎,可以使用 Google、Google-CN 或 DeepL
"i18n-ally.namespace": true,// 启用命名空间,这样可以将翻译按模块分组
"i18n-ally.enabledParsers": ["js","json"],// 指定允许的解析器,支持 js 和 json 文件
"i18n-ally.sortKeys": true,// 启用键排序,翻译键会按字母顺序排序
"i18n-ally.sourceLanguage": "zh-CN",// 设置源语言为中文(简体)
"i18n-ally.displayLanguage": "zh-CN",// 设置显示语言为中文(简体)
"i18n-ally.extract.keygenStyle": "camelCase",// 提取键名的风格为驼峰式(例如:fooBar)
"i18n-ally.enabledFrameworks": ["vue","react"],// 启用的框架,支持 Vue 和 React

项目文件目录

如图:

Pasted image 20240820143317.png

其中 en.jsonzh-Cn.json 为翻译原件,index.js 则是我们需要配置的i18n参数文件

import { createI18n } from 'vue-i18n';

import { useStorage } from '@vueuse/core';

// 自定义语言文件

import zhCN from '@/locales/zh-CN.json';

import en from '@/locales/en.json';

import ele_zhCN from 'element-plus/es/locale/lang/zh-cn';

import ele_en from 'element-plus/es/locale/lang/en';

const messages = {

  zhCN: {

    ...zhCN,

    ...ele_zhCN,

  },

  en: {

    ...en,

    ...ele_en,

  },

};

const getLanguage = () => {

  const language = useStorage('language', 'en');

  if (language.value) {

    return language.value;

  }

  return 'en';

};

// // const language = (navigator.language || 'zhCN').toLocaleLowerCase(); // 这是获取浏览器的语言

const i18n = createI18n({

  legacy: true, // 是否使用 composition API 模式

  // locale: localStorage.getItem('locales') || language.split('-')[0] || 'zhCN', // 首先从缓存里拿,没有的话就用浏览器语言, "zhCN",

  locale: getLanguage(),

  globalInjection: true, //允许全局使用$t()函数

  fallbackLocale: 'zhCN', // 设置备用语言

  messages,

});

export default i18n;

接着我们需要在主文件 main.js 引入

import i18n from './locales/index'; //国际化
app.use(i18n);

Pasted image 20240820144238.png

切换语言按钮

Pasted image 20240820144749.png

<template>

  <el-dropdown trigger="click" @command="handleLanguageChange">

    <div class="lang-select--style">

      <svg-icon icon-class="language" />

    </div>

    <template #dropdown>

      <el-dropdown-menu>

        <el-dropdown-item :disabled="appStore.language === 'zhCN'" command="zhCN"> 中文 </el-dropdown-item>

        <el-dropdown-item :disabled="appStore.language === 'en'" command="en"> English </el-dropdown-item>

      </el-dropdown-menu>

    </template>

  </el-dropdown>

</template>

  

<script setup>

import { useI18n } from 'vue-i18n';

import SvgIcon from '@/components/SvgIcon/index.vue';

import useAppStore from '@/store/modules/app';

  

const appStore = useAppStore();

const { locale } = useI18n();

const { proxy } = getCurrentInstance();

  

const message = {

  zhCN: '切换语言成功!',

  en: 'Switch Language Successful!',

}

const handleLanguageChange = (lang) => {

  locale.value = lang;

  appStore.changeLanguage(lang);

  proxy.$modal.msgSuccess(message[lang]);

}

</script>

  

<style lang="scss" scoped>

.lang-select--style {

  font-size: 18px;

  line-height: 50px;

}

</style>

这里做了语言的缓存以及状态管理,主要是为了解决后续切换语言,刷新浏览器,页面语言被还原了

Pasted image 20240820145323.png

const useAppStore = defineStore('app', {

  state: () => ({
  
    language: useStorage('language', 'en'),
  }),

  actions: {

    changeLanguage(val) {

      this.language = val;

    },

  },

});

最终

Pasted image 20240820145621.png

<template>

  <el-config-provider :locale="language === 'en' ? en : zhCN">

    <router-view v-if="isActive" />

  </el-config-provider>

</template>

  

<script setup>

import useSettingsStore from '@/store/modules/settings'

import { handleThemeStyle } from '@/utils/theme'

import i18n from "./locales";

import useAppStore from '@/store/modules/app';

import { watch } from 'vue';

const appStore = useAppStore();

const language = computed(() => appStore.language)

const zhCN = i18n.global.messages.zhCN

const en = i18n.global.messages.en

const isActive = ref(false)//用来解决el-form的校验在切换中英文后,还是原语言

//刷新页面

function reload() {

  isActive.value = false

  nextTick(() => {

    isActive.value = true

  })

}

//监听语言的切换,切换后刷新页面

watch(() => appStore.language, (newVal, oldVal) => {

  if (newVal !== oldVal) {

    reload()

  }

  // console.log("🚀 ~ language:", language.value)

}, { immediate: true })

  

onMounted(() => {

  nextTick(() => {

    // 初始化主题样式

    handleThemeStyle(useSettingsStore().theme)

  })

})

</script>

这里遇到一个问题,在 el-form 校验时,切换语言,发现还是前一个语言的校验,所以这里给 router-view 加上了 isActive 控制,相当于手动刷新

总结

问题

  1. i18n-ally插件的setting一定要配置对,不然不起作用
  2. 项目目录的语言包尽量用 .json 格式
  3. 切换语言一定要做缓存和状态管理
  4. 表单校验报错信息切换语言并不生效

补充

import i18n from '@/locales/index';

/**

 * 获取国际化路由,如果不存在则原生返回

 * @param title 路由名称

 * @returns {string}

 */

export const translateRouteTitle = (title) => {

  // 遍历对象,查找对应的key

  for (const key in i18n.global.messages.zhCN.sideBar) {

    if (i18n.global.messages.zhCN.sideBar[key] === title) {

      return key;

    }

  }

};

这里是国际化路由的方法,应为路由返回的是中文,这里我拿中文去匹配对应的key值,应为我们在翻译时,用的是对应的key

$t('form.name')//标签属性内部的中文

{{$t('form.name')}} //内容

t('form.name') //vue文件的<script></script>使用需要引用
import { useI18n } from 'vue-i18n'
const { t } = useI18n()

//在.js文件中使用
import i18n from '@/locales';
i18n.global.t('form.name')