Skip to content

1.介绍自定义国际化和ElementPlus组件国际化

国际化i18n分为自定义词库国际化和ElementPlus组件国际化

2.实现两者的步骤

安装 vue-i18n

bash
npm i vue-i18n

创建i18n配置文件i18n.ts:

ts
// i18n.ts
import { App } from 'vue'

import { createI18n } from 'vue-i18n'

const install = (app: App) => {
  const messages = {
    en: {
      // 定义你自己的字典,但是请不要和 `el` 重复,这样会导致 ElementPlus 内部组件的翻译失效.
      message: {
        hello: 'hello world',
      },
      button:{
        default:"button"
      }
    },
    zhCn: {
      // 定义你自己的字典,但是请不要和 `el` 重复,这样会导致 ElementPlus 内部组件的翻译失效.
      message: {
        hello: '你好,世界',
      },
      button:{
        default:"按钮"
      }
    }
  }

  const i18n = createI18n({
    legacy: false,
    globalInjection: true, // 全局模式,可以直接使用 $t 调用 i18n
    locale: 'zhCn', //默认为中文模式
    fallbackLocale: 'en',
    // @ts-ignore
    messages
  })
  app.use(i18n)
}
export default install

注:上面的en和zhCn配置项可以作为单独js文件,然后引入i18n.ts中,能够解耦

在main.js中引入i18n.ts:

js
import { install } from "./i18n"; //{}这样引入就不需要use了,可以直接合并进js代码里面

在App.vue中使用el-config-provider,并书写相关方法实现自定义词库国际化和ElementPlus组件国际化的实现

vue
<!-- TODO: 测试国际化 -->
<script lang="ts">
import { computed, defineComponent, ref } from "vue";
import zhCn from "element-plus/lib/locale/lang/zh-cn";
import en from "element-plus/lib/locale/lang/en";
import HelloWorld from "./components/HelloWorld.vue";

type localType = "zhCn" | "en"; //只有ts里面可以这么写,自定义类型
export default defineComponent({
  components: {
    HelloWorld,
  },
  setup() {
    const local = ref<localType>("zhCn");
    const localLanguage = computed(() => {
      switch (local.value) {
        case "en":
          return en;
        case "zhCn":
          return zhCn;
      }
    });
    return {
      local,
      localLanguage,
    };
  },
  methods: {
    /**
     * 切换语言
     * @param type
     */
    changeLanguage(type: localType): void {
      this.local = type;
      this.$i18n.locale = type; //只有在methods这才能拿到this,setup里面拿不到
    },
  },
});
</script>

<template>
	<!-- TODO: 测试国际化 -->
	<el-config-provider :locale="localLanguage">
    	<HelloWorld @change="changeLanguage" />
    </el-config-provider>
</template>

在HelloWorld.vue中定义按钮,切换中英文,调用外部父组件的方法

vue
<template>
  <!-->在这里用$t调用i18n里面定义的内容,$t就相当于i18n对象</-->
  <el-button>{{ $t("button.default") }}</el-button>
  <el-date-picker v-model="value1" type="date" placeholder="选择日期">
  </el-date-picker>
  <el-dropdown @command="changeLanguage">
    <el-button type="primary">
      切换语言<i class="el-icon-arrow-down el-icon--right" />
    </el-button>
    <template #dropdown>
      <el-dropdown-menu>
        <el-dropdown-item command="zhCn"> 中文 </el-dropdown-item>
        <el-dropdown-item command="en"> 英文 </el-dropdown-item>
      </el-dropdown-menu>
    </template>
  </el-dropdown>
</template>

<script lang="ts">
import { defineComponent } from "vue";

type localType = "zhCn" | "en";

export default defineComponent({
  setup() {
    return {
      value1: "",
    };
  },
  methods: {
    /**
     * 切换语言
     * @param type
     */
    changeLanguage(type: localType): void {
      this.$emit("change", type);
    },
  },
});
</script>

3.目录结构优化解耦

  • 在src下 新建 locales 文件夹

简体中文英文为例

  • 在 locales 文件夹下新建 zh-cn.ts
ts
export default {
  buttons: {
    login: '登录'
  },
  menus: {
    home: '首页'
  }
}
  • 在 locales 文件夹下新建 en.ts
ts
export default {
  buttons: {
    login: 'Login'
  },
  menus: {
    home: 'Home'
  }
}
  • 在 locales 文件夹下新建 index.ts(就相当于之前的i18n.ts)
ts
// i18n.ts
import { App } from 'vue'
import { createI18n } from 'vue-i18n'
import zhCn from './zh-cn'
import en from './en'

const install = (app: App) => {
  const messages = {
    zhCn,
    en
  }

  const i18n = createI18n({
    legacy: false,
    globalInjection: true, // 全局模式,可以直接使用 $t 调用 i18n
    locale: 'zhCn', //默认为中文模式
    fallbackLocale: 'en',
    // @ts-ignore
    messages
  })
  app.use(i18n)
}
export default install

4.如何使用i18n对象

4.1 在 template 中的使用

前提:在main.js中引入了index.ts

js
{{ $t('menus.home') }}

4.2 在 ts 中的使用

但是这个时候要使用的话要改变index.ts写法:

ts
// i18n.ts
import { App } from 'vue'
import { createI18n } from 'vue-i18n'
import zhCn from './zh-cn'
import en from './en'

const i18n = createI18n({
    legacy: false,
    globalInjection: true, // 全局模式,可以直接使用 $t 调用 i18n
    locale: 'zhCn', //默认为中文模式
    fallbackLocale: 'en',
    // @ts-ignore
    messages:{
        zhCn,
        en
    }
})
export default i18n

使用:

js
import i18n from './locales'

i18n.global.t('menus.home')

注意:但是这个时候注册在main.js中需要这样:

js
import i18n from "./i18n";
app.use(i18n);

5.elementPlus优化:使用Pinia进行状态管理

Element Plus 官方提供了一个 Vue 组件 ConfigProvider 用于全局配置国际化的设置

修改 locales 文件夹下的 index.ts

修改这句即可 locale: localStorage.getItem('lang') || 'zhCn',

ts
import { App } from 'vue'
import { createI18n } from 'vue-i18n'
import zhCn from './zh-cn'
import en from './en'

const i18n = createI18n({
    legacy: false,
    globalInjection: true, // 全局模式,可以直接使用 $t 调用 i18n
    locale: localStorage.getItem('lang') || 'zhCn',, //之前默认为中文模式,现在是根据本地存储的值决定默认值,所以可以记住用户的选择,关闭浏览器依然成立,所以用户会越用越好用!
    fallbackLocale: 'en',
    messages:{
        zhCn,
        en
    }
})
export default i18n

修改App.vue

vue
<!-- TODO: 测试国际化 -->
<script lang="ts">
import { computed, defineComponent, ref } from "vue";
import zhCn from "element-plus/lib/locale/lang/zh-cn";
import en from "element-plus/lib/locale/lang/en";
import HelloWorld from "./components/HelloWorld.vue";
import { useAppStoreHook } from '@/store/modules/app' //store存放语言配置,这里的useAppStoreHook函数调用后产生的对象就是store对象了
 
// type localType = "zhCn" | "en"; //只有ts里面可以这么写,自定义类型
export default defineComponent({
  components: {
    HelloWorld,
  },
  setup() {
    // const local = ref<localType>("zhCn");
    const store = useAppStoreHook(); //得到store对象
    const localLanguage = computed(() => {
      switch (store.local) { //这里应该判断的是store存储的值,进行计算属性,监听变化
        case "en":
          return en;
        case "zhCn":
          return zhCn;
      }
    });
    return {
      store,
      localLanguage,
    };
  },
  methods: {
    changeLanguage(type: localType): void { //参数为type,参数类型为localType,返回值类型为void
       //这里写调用修改store存储的值的方法
	  store.local = type;
      this.$i18n.locale = type;
      
      // 原来的:
      // this.local = type;
      // this.$i18n.locale = type; //只有在methods这才能拿到this,setup里面拿不到
    },
  },
});
</script>

<template>
	<!-- TODO: 测试国际化 -->
	<el-config-provider :locale="localLanguage">
    	<HelloWorld @change="changeLanguage"/>
    </el-config-provider>
</template>

在src下面创建store文件夹:

store/modules/app.js

js
// store/modules/app
import { defineStore } from 'pinia'
import { store } from '@/store' //感觉是可有可无的
import i18n from '@/locales'

const useAppStore = defineStore('app', {
  state: () => {
    return {
      locale: localStorage.getItem('lang') || 'zhCn'
    }
  },
  actions: {
    SET_LOCALE(locale: string) { //语言切换
      this.locale = locale
      storageLocal.setItem('lang', locale) //这里可能是localStorage更合适一些?
      i18n.global.locale.value = locale
    }
  }
})

// 一般情况下,下面这些代码不用写,除非想给其传入新的store,否则直接在上面的const useAppStore前面加export即可了
export function useAppStoreHook() {
  //返回store对象
  return useAppStore(store)  //这里传的实参感觉也是可有可无的
}