Vite2+Vue3学习笔记(四):引入Vue-i18n并实现按钮切换页面语言
新手小白Vue3学习笔记第四篇,在项目中使用Vue-i18n,实现按钮实时切换页面及组件内部语言。
目录
1)在Element Plus容器布局的例子基础上修改下拉菜单,增加单选按钮组和头像:
3)修改单选按钮组和下拉菜单文本,渲染en_US.js中自定义的文本:
4)添加change事件监听单选按钮组,实现点击按钮切换自定义国际化文件的功能:
参考链接
vue3.0配置vue-i18n - 易函123 - 博客园
vue3国际化如何使用vue-i18n以及解决切换语言不刷新的问题 - baifangzi - 博客园
前言
本人职场小白,公司让学习Vite和Vue3并搭建项目Demo,借这个机会自己尝试写写博客,主要目的是搭项目,所以原理性的知识没有过多阐述,写博客时也根据步骤复现了,对于新手直接跟着操作就可以把项目搭起来,少走了很多弯路,希望对大家有帮助。
文中参考链接都有附上,参考时可以看看,如果有任何错误或意见也欢迎大家指点。
项目码云Gitea地址
Vite-Demo: 使用vite2.0及vue3.0并集成Element Plus,开发后台管理系统demo。https://gitee.com/YG-CST/vite-demo
其他文章
Vite2+Vue3学习笔记(一):Vue3.0项目搭建及配置过程_YGいくこさん的博客-CSDN博客
Vite2+Vue3学习笔记(二):引入Vue-Router_YGいくこさん的博客-CSDN博客
Vite2+Vue3学习笔记(三):引入Axios并调用后端接口_YGいくこさん的博客-CSDN博客
四、引入Vue-i18n并实现按钮切换语言
1.安装vue-i18n
npm i vue-i18n@next --save
-
package.json
{
"name": "test-demo-1",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"dependencies": {
"axios": "^0.24.0",
"element-plus": "^1.2.0-beta.3",
"sass": "^1.43.5",
"scss": "^0.2.4",
"vue": "^3.2.16",
"vue-i18n": "^9.2.0-beta.20",
"vue-router": "^4.0.12"
},
"devDependencies": {
"@vitejs/plugin-vue": "^1.9.3",
"vite": "^2.6.4"
}
}
2.准备语言文件
-
src/lang/zh_CN.js
自定义中文文本。
const zh_CN = {
nav: {
chi: '简体中文',
eng: '英语',
personalCenter: '个人中心',
logout: '退出登录',
},
};
export default zh_CN;
-
src/lang/en_US.js
自定义英文文本。
const en_US = {
nav: {
chi: 'CN',
eng: 'EN',
personalCenter: 'Personal Center',
logout: 'Sign Out',
},
};
export default en_US;
3.配置文件
-
src/lang/index.js
import { createI18n } from 'vue-i18n';
// 自定义国际化文件
import zh_CN from './zh_CN';
import en_US from './en_US';
const i18n = createI18n({
legacy: false, // Composition API 模式
globalInjection: true, // 全局注册 $t方法
// 默认语言
locale: 'zh_CN',
// 语言库
messages: {
zh_CN: zh_CN,
en_US: en_US
}
});
// 将i18n暴露出去,在main.js中引入挂载
export default i18n;
4.全局配置
-
src/main.js
// 引入Vue-i18n
import i18n from './lang'
app.use(i18n);
5.修改首页src/components/Main.vue
1)在Element Plus容器布局的例子基础上修改下拉菜单,增加单选按钮组和头像:
官网:Container 布局容器 | Element Plus
<template>
<el-container style="border: 1px solid #eee">
<el-aside width="200px" style="background-color: rgb(238, 241, 246)">
<el-menu :default-openeds="['1', '3']" style="height: 100%">
......
</el-menu>
</el-aside>
<el-container>
<el-header class="flex-center-flex-end">
<el-radio-group
v-model="toggle_locale"
size="mini"
border
style="margin-right: 20px"
>
<el-radio-button label="简体中文"></el-radio-button>
<el-radio-button label="英语"></el-radio-button>
</el-radio-group>
<el-dropdown>
<el-avatar
src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
></el-avatar>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item>退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-header>
<el-main>
......
</el-main>
</el-container>
</el-container>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import { Message, Menu, Setting } from "@element-plus/icons";
export default defineComponent({
components: {
Message,
Setting,
"icon-menu": Menu,
},
setup() {
return {
toggle_locale: ref("简体中文"), //和el-radio-button的label保持一致
};
},
});
</script>
<style>
.el-header {
background-color: #b3c0d1;
color: var(--el-text-color-primary);
line-height: 60px;
}
.el-aside {
color: var(--el-text-color-primary);
}
.flex-center-flex-end {
display: flex;
align-items: center;
justify-content: flex-end;
}
</style>
2)在setup()中使用vue-i18n:
<script lang="ts">
import { defineComponent, ref } from "vue";
import { useI18n } from "vue-i18n";
export default defineComponent({
setup() {
// i18n
const { locale } = useI18n(); // vue-i18n提供了一个钩子函数 useI18n(),暴露出locale属性用于切换语言
locale.value = "en_US"; // 要切换的语言
const chi = useI18n().t("nav.chi");
const eng = useI18n().t("nav.eng");
let myLocale = useI18n().locale.value; // 记录自定义国际化文件的locale值,为【后续和Element Plus国际化文件的locale区分开】做准备
// 切换按钮组选中值
const toggle_locale = myLocale === "en_US" ? ref(chi) : ref(eng);
return {
// i18n
chi,
eng,
toggle_locale,
};
},
});
</script>
3)修改单选按钮组和下拉菜单文本,渲染en_US.js中自定义的文本:
<el-header class="flex-center-flex-end">
<el-radio-group
v-model="toggle_locale"
size="mini"
border
style="margin-right: 20px"
>
<el-radio-button :label="chi">{{ $t("nav.chi") }}</el-radio-button>
<el-radio-button :label="eng">{{ $t("nav.eng") }}</el-radio-button>
</el-radio-group>
<el-dropdown>
<el-avatar
src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
></el-avatar>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>{{ $t("nav.personalCenter") }}</el-dropdown-item>
<el-dropdown-item>{{ $t("nav.logout") }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-header>
4)添加change事件监听单选按钮组,实现点击按钮切换自定义国际化文件的功能:
- <template>
<el-radio-group
v-model="toggle_locale"
size="mini"
border
style="margin-right: 20px"
@change="changeLanguage"
>
<el-radio-button :label="chi">{{ $t("nav.chi") }}</el-radio-button>
<el-radio-button :label="eng">{{ $t("nav.eng") }}</el-radio-button>
</el-radio-group>
- <script> - setup()
按钮切换后把当前语言环境记录到localStorage中,用户刷新页面时根据localStorage的是否有值渲染当前页面的文本(※处)。
// i18n
const { locale } = useI18n(); // vue-i18n提供了一个钩子函数 useI18n(),暴露出locale属性用于切换语言
locale.value = localStorage.getItem("locale") || "zh_CN"; // 要切换的语言 ——※
const chi = useI18n().t("nav.chi");
const eng = useI18n().t("nav.eng");
let myLocale = useI18n().locale.value;
const changeLanguage = (e) => {
if (e == chi) {
myLocale = "zh_CN";
locale.value = "zh_CN";
} else if (e == eng) {
myLocale = "en_US";
locale.value = "en_US";
}
localStorage.setItem("locale", myLocale); // ——※
};
// 定义方法集合,整体return出去
let methods = {
// 切换语言
changeLanguage,
};
return {
// i18n
chi,
eng,
toggle_locale,
...methods,
};
到这里就可以实现按钮切换页面语言了,但其实还没结束......
引入Element Plus的取色器组件(随便一个组件都可以),会发现切换按钮时,只有通过{{t("")}}或者userI18n().t()两种方式渲染的文本会变化,组件内部文本是不会切换语言的,所以需要配置Element Plus组件国际化。
6. 配置Element Plus组件国际化
参考官方文档:
国际化全局配置:国际化 | Element Plus
使用Config Provider全局配置:全局配置 | Element Plus
-
src/main.js
全局配置,判断当前localStorage的值并初始化:
// Element Plus全局配置国际化
import zhCn from "element-plus/lib/locale/lang/zh-cn";
import en from "element-plus/lib/locale/lang/en";
// app.use(ElementPlus);
app.use(ElementPlus, {
// locale: zhCn,
locale: localStorage.getItem('locale') == 'zh_CN' ? zhCn : en,
});
app.mount('#app');
-
src/components/Main.vue
-
<template>
把el-container包裹在el-config-provider中:
<template>
<el-config-provider :locale="elLocale">
<el-container>
......
</el-container>
</el-config-provider>
</template>
- <script>
修改※处。
注意:要删除<script>标签后面的【lang="ts"】,否则会报错。
<script>
// ElementPlus组件国际化
import { ElConfigProvider } from "element-plus";
import zhCn from "element-plus/lib/locale/lang/zh-cn";
import en from "element-plus/lib/locale/lang/en";
export default defineComponent({
components: {
ElConfigProvider,
},
setup() {
// i18n
// 自定义国际化
const { locale } = useI18n(); // vue-i18n提供了一个钩子函数 useI18n(),暴露出locale属性用于切换语言
locale.value = localStorage.getItem("locale") || "zh_CN"; // 要切换的语言
const chi = useI18n().t("nav.chi");
const eng = useI18n().t("nav.eng");
let myLocale = useI18n().locale.value;
// Element Plus组件国际化
const elLocale_zh = ref(zhCn);
const elLocale_en = ref(en);
let elLocale = localStorage.getItem("locale") == "zh_CN" ? elLocale_zh : elLocale_en;
// 切换按钮组选中值
const toggle_locale = myLocale === "zh_CN" ? ref(chi) : ref(eng);
// 单选按钮组监听事件
const changeLanguage = (e) => {
if (e == chi) {
myLocale = "zh_CN";
locale.value = "zh_CN";
// 组件国际化
const temp = elLocale_zh.value;
elLocale_zh.value = elLocale_en.value;
elLocale_en.value = temp;
} else if (e == eng) {
myLocale = "en_US";
locale.value = "en_US";
// 组件国际化
const temp = elLocale_en.value;
elLocale_en.value = elLocale_zh.value;
elLocale_zh.value = temp;
}
localStorage.setItem("locale", myLocale);
};
let methods = {
// 切换语言
changeLanguage,
};
return {
// i18n
chi,
eng,
toggle_locale,
colorPicker: ref("#409EFF"),
elLocale,
...methods,
};
},
});
</script>
7.折腾系列之添加退出登录事件
-
<template>
<el-dropdown-menu>
<el-dropdown-item>{{ $t("nav.personalCenter") }}</el-dropdown-item>
<el-dropdown-item @click="logout">{{ $t("nav.logout") }}</el-dropdown-item>
</el-dropdown-menu>
-
<script> - setup()
// 退出登录
const logout = () => {
localStorage.removeItem("Token");
window.location.href = "/login";
};
let methods = {
// 退出登录
logout,
// 切换语言
changeLanguage,
};
8.折腾系列之替换首页el-main
-
src/views/AppList.vue
<template>
<el-table :data="tableData">
<el-table-column prop="date" label="Date" width="140"> </el-table-column>
<el-table-column prop="name" label="Name" width="120"> </el-table-column>
<el-table-column prop="address" label="Address"> </el-table-column>
</el-table>
</template>
<script>
import { defineComponent, ref } from "vue";
export default defineComponent({
components: {},
setup() {
// 表格数据
const item = {
date: "2016-05-02",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
};
const tableData = ref(Array(20).fill(item));
let methods = {};
return {
// 表格数据
tableData,
...methods,
};
},
});
</script>
<style></style>
-
src/components/Main.vue
<el-main>
<router-view></router-view>
</el-main>
-
src/router/index.js
import { createRouter, createWebHistory } from "vue-router";
const routerHistory = createWebHistory();
const router = createRouter({
history: routerHistory,
routes: [{
path: "/login",
name: "login",
component: () =>
import ("../components/Login.vue")
}, {
path: "/", // 父级路径
name: "main",
component: () =>
import ("../components/Main.vue"),
children: [{
path: "/", // 空路径路由的路径与父级路径保持一致,否则会显示Main.vue,没有渲染router-view
redirect: "/appList"
}, // 定义空路径,用户访问localhost:5000时跳转至首页
{
path: "/appList",
name: "appList",
component: () =>
import ("../views/AppList.vue")
}
]
}, {
path: "/:pathMatch(.*)*",
name: "notFound",
component: () =>
import ("../components/NotFound.vue")
}]
});
// 路由守卫
router.beforeEach((to) => {
let token = localStorage.getItem('Token');
if (token && to.path === '/login')
return "/appList";
else if (!token && to.path !== '/login')
return "/login";
});
export default router;
2022年04月13日更新:
感谢评论区涩谷同学提出的问题,测试后发现了问题,代码更新记录请戳链接:
<!-- Main.vue -->
<el-dropdown>
{{ $t("label.test") }}
{{ testRefreshData1 }}
</el-dropdown>
// Main.vue
/**
* 测试更新自定义data是否需要刷新
* 解析:确实需要手动刷新页面才会更新,个人理解是国际化相关配置文件只在页面加载时重新引入,而setup中的响应式数据是热更新的,只要lang文件夹下的文件内容没有改变,就不会重新引入,所以需要手动刷新使页面重新import相关文件。
* 测试:修改zh_CN中的label.test文本时页面是自动刷新的,所以按钮切换无效。
* 结论:如果确实需要按钮切换更新页面文本,建议:
* 1.要么自己在template中使用{{t()}},这个可以实现无刷新按钮切换;
* 2.要么就在setup中监测自定义data的改变,一改变就强制刷新页面【不推荐,用户体验不好】。
*/
const testRefreshData1 = reactive(useI18n().t("label.test"));
return {
testRefreshData1,
}
// 国际化配置文件
const zh_CN = {
nav: {
chi: '简体中文',
eng: '英语',
personalCenter: '个人中心',
logout: '退出登录',
},
label: {
test: '测试刷新更新文本'
}
};
export default zh_CN;
const en_US = {
nav: {
chi: 'CN',
eng: 'EN',
personalCenter: 'Personal Center',
logout: 'Sign Out',
},
label: {
test: 'Test Refresh Update Text'
}
};
export default en_US;
如果解释不对请大神们指出,谢谢~
更多推荐
所有评论(0)