1.前言
最后修改时间2022.8.15
本篇文章主要介绍如何在vite-vue3-ts项目中使用vue-i18n,并且对i18n的懒加载进行优化,达到路由层面,废话不多说直接开冲.
2.开冲前准备
技术栈有
1.vue-i18n
2.pinia(可不需要)
3.vue-router
安装:
我vite版本//3.0.9
pnpm i vue-router //4.0.16
pnpm i pinia //2.0.14
pnpm i vue-i18n //9.2.2
不需要区分放在哪个环境,所以不用后面声明放哪里 基本都是最新版本
3.开冲
怎么搭建项目和使用vue-router我就不写了,这边的区域以后来探索吧
首先在src文件下新创建一个locals文件夹
一级文件夹为国家文件夹和index.ts
二级文件夹为语言文件夹
最后三级文件就是以路由为单位的文件啦
文件夹下层级示例
-locals
-index.ts
-{国家}
-{语言}
-{路由}
-en
-home.ts
-zh
-home.ts
-{国家}
-{国家}
4.index.ts
直接上代码我注释的比较详细了
import { nextTick, reactive } from "vue";
import { createI18n } from "vue-i18n";
import type { VueI18n, Composer } from 'vue-i18n';
//pinia
import { mainStore } from "@/store";
// 预装语言
const obj = reactive<any>({
store: 0,
country: ''
})
// 实例化 // 防止加载过快未挂载上报错
nextTick(() => {
obj.store = mainStore();
})
// i18n实例
export const i18n = createI18n({
// 关闭未使用函数组件显示HTML片段警告(警告为你的v-html需要使用函数组件)
warnHtmlMessage: false,
// 开启全局注入(template模板可以使用$t)
globalInjection: true,
messages: {
// 设置语言环境信息
// 按需加载不能提前设置语言
}
})
// 修改i18n语言(注:repeat为自调用传参,忽略即可)
const setLanguage = (lang: string, repeat?: 0 | 1) => {
// 第一次直接设置语言
if (!repeat) {
if (i18n.mode === 'legacy') (i18n.global as unknown as VueI18n).locale = lang
else (i18n.global as unknown as Composer).locale.value = lang
}
// pinia挂没挂载上都返回lang
if (obj.store !== 0) {
obj.store.language = lang
return lang
}
//pinia 没挂载上,反复调用方法直到挂载上
if (obj.store === 0) {
setLanguage(lang, 1)
return lang
}
return lang
}
// 增加
const add = ({ lang, name, value }: { lang: string, name: string, value: object }): void => {
let obj: any = i18n.global.getLocaleMessage(lang);
obj[name] = value;
i18n.global.setLocaleMessage(lang, obj);
}
// 查询
const inquire = ({ lang, name }: { lang: string, name: string }): 0 | 1 => {
let obj: any = i18n.global.getLocaleMessage(lang);
if (obj[name]) return 1;
return 0;
}
// 导出修改语言方法
export const loadLanguageAsync = async (lang: string, country: string, routerStr: string) => {
let str = routerStr, newLang = lang;
// 修改首页路由传参
if (routerStr === '' || routerStr === ':lang') str = 'home';
// (某些国家)没有某语言直接重置为en
if (country === 'xx') newLang = 'en';
// 如果国家不一样,语言配置全部清空,并更改国家
if (obj.country !== country) {
let arr = i18n.global.availableLocales;
if (arr.length) for (let i = 0, length = arr.length; i < length; i++) i18n.global.setLocaleMessage(arr[i], {});
obj.country = country;
}
// 如果修改语言
if (i18n.global.locale !== newLang) {
// 修改i18n配置语言
setLanguage(newLang);
// 装上默认加载的语言配置
let arr = ['global', 'home'];(有什么路由需要默认装上的可以放进这个数组,前提是名字和文件一致)
for (let i = 0, length = arr.length; i < length; i++) {
// 没有
if (!inquire({ lang: newLang, name: arr[i] })) {
let res = await import(/* @vite-ignore */ `../locals/${country}/${newLang}/${arr[i]}.ts`);
add({ lang: newLang, name: arr[i], value: res.default })
}
}
}
// 查询到当前路由没有语言配置
if (!inquire({ lang: newLang, name: str })) {
let res = await import(/* @vite-ignore */ `../locals/${country}/${newLang}/${str}.ts`);
add({ lang: newLang, name: str, value: res.default })
}
}
这里说一下,为什么要用pinia,因为方便呗
还有为什么有国家的区分?
如果项目和商品挂钩,免不了需要区分货币,有些时候货币单位又不得不在文本里,所以要区分国家,不需要的可以试着自己修改哈
:lang是啥?
这个是vue-router给写法,代表这里是个变量,本来是用来表示当前语言的,但是路由截取后出来变成字符串了
为什么首页不判断'/',因为哪怕用户手动输入'/',也会被重置掉
5.文本配置
其实配置是一样的,但我还是发出来
home.ts
export default {
home: 'xxx'
}
注意,你的路由名字必须有能匹配的文件名否则出问题别来找我
6. main.ts
来main.ts配置一下
import { createApp } from 'vue';
import App from '@/App.vue';
import { createPinia } from 'pinia';
import { mainStore } from "@/store";
import router from '@/router';
// 多语言配置
import { i18n, loadLanguageAsync } from '@/locals';
// 挂载
app.use(pinia).use(router).use(i18n).mount('#app');
// 路由守卫
router.beforeEach((to, from, next) => {
// 截获配置语言的路由名称
// let routerStr = "", routerIndex = 0;
// if (to.matched.length >= 2) routerIndex = 1;
// let routerStrArr = to.matched[routerIndex].path.split(/\//);
// routerStr = routerStrArr[routerStrArr.length - 1];
// 懒加载语言配置
loadLanguageAsync(lang, country, routerStr).then(() => {
// app.config.globalProperties.$root = {
// country,
// locale: lang
// }
next()
}).catch((err) => {
next()
});
});
这里后期我注释了一些代码,意思是别抄我的,因为需求不一样,我的路由层级是这样的,可以这样去取路由名
7.页面使用
home.vue
<template>
<div>
{{$t('home.home')}}
{{t('home.home')}}
<div v-html="$t('home.home')" />
<div v-html="t('home.home')" />
</div>
</template>
<script setup lang="ts">
// i18n
import { useI18n } from 'vue-i18n'
// 解构
const { t } = useI18n()
</script>
各两种基本写法
$t 是全局使用的,但只能在模板里
t是引入解构出来的,模板和脚本都可以
8.最后
我不太会写文章,只是把实现的功能以大家能最快cv的形式写出来,抱歉了各位
要是有不明白的评论区说,我看看我知不知道或者能不能解决
还有这个功能没有打过包,还需要大家自己配置咯