【Vue3+Element Plus】从0-1搭建后台管理系统(05)-多语言国际化vue I18n
什么是 Vue I18n?
Vue I18n 是 Vue.js 的国际化插件。它可以轻松地将一些本地化功能集成到您的 Vue.js 应用程序中。
安装vue-i18n
npm install vue-i18n@9
引入i18n并创建实例对象
在src/
创建locales
文件夹,在该目录下创建index.ts
以及两个语言包zh.ts
和en.ts
文件:
locales/en.ts:
export default {
common: {
home: 'home',
about: 'about',
signIn: 'sign in',
signUp: 'sign up'
},
route: {
doshboard: 'Doshboard',
workbench: 'Workbench',
...
},
...
}
locales/zh.ts:
export default {
common: {
home: '首页',
about: '关于',
signIn: '登录',
signUp: '注册'
},
route: {
doshboard: '仪表盘',
workbench: '工作台',
...
},
...
}
locales/index.ts:
import type { App } from 'vue'
import { createI18n } from 'vue-i18n'
// 导入语言
import en from './en'
import zh from './zh'
/** 获取浏览器界面语言,默认语言。 navigator.language: zh-CN
* 我们只需要它的前缀:zh,所以使用replace将zh后面的替换为空
*/
let currentLanguage = navigator.language.replace(/-[A-Za-z]*/, '')
console.log(currentLanguage)
/** 从本地缓存localStorage中获取语言环境 */
const locales = localStorage.getItem('locales')
/** 如果本地缓存中记录了语言环境,则使用本地缓存记录的语言环境 */
if (locales !== null) {
currentLanguage = JSON.parse(locales)?.locale
}
/** 创建i18n实例对象 */
const i18n = createI18n({
locale: currentLanguage,
legacy: false, // 防止组件引入i18n,vite脚手架报错
messages: {
zh,
en
}
})
/**
* 安装i8n
* @param app vue实例对象
*/
export const setupI18n = (app: App): void => {
app.use(i18n)
}
/** Nav.vue头部导航栏中英文切换下拉菜单使用 */
export const langs = [
{ key: 'zh', title: '中文' },
{ key: 'en', title: 'English' }
]
main.ts中引入安装i18n:
import { createApp } from 'vue'
/** 导入安装i18n函数 */
import { setupI18n } from './locales'
/** 创建vue实例对象 */
const app = createApp(App)
/** 安装i18n国际化语言 */
setupI18n(app)
在layout/index.vue组件中测试使用:
直接在组件的模板中的插值表达式中使用i18n提供的$t()
函数渲染不同语言包下对应的中英文,我们只需要传入一个类似获取对象属性值的字符串(在messages中有的)给$t()
,就可以渲染不同语言包下对应的内容。
<el-main>
<span class="text-3xl font-bold underline dark:text-white"> {{ $t('common.main') }} </span>
</el-main>
因为我的浏览器默认语言是中文,所以使用的是中文的语言包。
效果:
渲染已有语言列表
基础的准备我们已经做好了,那么接下来就是将我们现有的语言在语言切换下拉菜单中渲染出来。
在我们做准备的时候,在src/lacales/index.ts
中向外暴露了下面这个对象:
/** Nav.vue头部导航栏中英文切换下拉菜单使用 */
export const langs = [
{ key: 'zh', title: '中文' },
{ key: 'en', title: 'English' }
]
现在我们在layout/Header/components/Language.vue
组件中将它引入进来并对中英文切换下拉菜单进行渲染:
<template>
<!-- 中英文切换 -->
<el-dropdown trigger="click">
<span class="el-dropdown-link">中文</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="lang in langs" :key="lang.key">{{ lang.title }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<script setup lang="ts">
/** 导入已有的语言列表 */
import { langs } from '@/locales'
defineOptions({
name: 'Language'
})
</script>
实现中英文切换功能
将现有语言列表进行渲染完成以后,接下来就是要对中英文切换功能的实现了。
因为中英文切换是影响到全局的,所以得将中英文切换的状态,存放到状态管理pinia
中。
具体步骤如下:
-
在
src/store/modules
目录下新建index.ts
文件: -
定义
locales
仓库:/** 导入定义store的函数,类型 */ import { defineStore, type Store } from 'pinia' /** 导入pinia实例对象 */ import { store } from '../index.ts' /** 定义locales仓库 */ const useLocalesStore = defineStore( 'locales', () => { /** 返回数据 */ return {} } ) /** * 在 setup() 外部使用 useLocalesStore * 详情见:https://pinia.vuejs.org/zh/ssr/ */ const useLocalesStoreHook = (): Store => { return useLocalesStore(store) }
-
初始化一个当前语言状态
export const useLocalesStore = defineStore( 'locales', () => { // 当前语言 const locale = ref(i18n.global.locale.value) return { locale } } )
这里
locale
的初始值取i18n初始化时的值,因为i18n初始化时的值是当前浏览器的语言或者是本地缓存中记录的,这样我们一进入后台就可以得到当前的语言。 -
设置当前语言的方法
/** setLocale函数的lang参数的类型 */ type lang = 'zh' | 'en' export const useLocalesStore = defineStore( 'locales', () => { // 当前语言 const locale = ref(i18n.global.locale.value) /** * 设置当前语言 * @param lang 设置成的语言 */ function setLocale(lang: lang): void { /** 改变当前所处语言环境的状态,刷新的时候i18n会取这个值作为当前的语言环境 */ locale.value = lang /** 点击的时候立马修改语言(切换语言) */ i18n.global.locale.value = lang } return { locale, setLocale } } )
-
在
layout/Header/components/Language.vue
中引入locales
仓库并使用仓库中的locale属性
和setLocale方法
:<template> <!-- 中英文切换 --> <el-dropdown trigger="click" @command="changeLanguage"> <span class="el-dropdown-link">中文</span> <template #dropdown> <el-dropdown-menu> <el-dropdown-item v-for="lang in langs" :key="lang.key" :command="lang.key"> {{ lang.title }} </el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> </template> <script setup lang="ts"> /** 导入已有的语言列表 */ import { langs } from '@/locales' /** 导入locales仓库 */ import { useLocalesStore } from '@/store/modules/locales' defineOptions({ name: 'Language' }) /** 初始化locales仓库 */ const localesStore = useLocalesStore() /** 切换当前语言环境 */ const changeLanguage = (locale: any): void => { localesStore.setLocale(locale) } </script> <style lang="scss" scoped></style>
绑定
el-dronpdown
的command
事件,从事件处理函数中获取到点击的el-dropdown-item
绑定的command
的值传给locales
仓库的setLocale
函数,从而改变当前的语言环境。效果:
从上图发现一个问题,就是不管当我们切换英文或者是中文也好,头部语言下拉菜单一直显示的都是我们写死的“中文”,所以接下来我们要把它换成是动态的。
头部语言动态显示
初始化一个currentLocales
变量用来动态展示头部语言动态显示,初始值为现有语言列表中的当前语言环境:
<!-- 中英文切换 -->
<el-dropdown trigger="click" @command="changeLanguage">
<span class="el-dropdown-link">{{ currentLocale }}</span>
...
</el-dropdown>
<script setup lang="ts">
import { ref } from 'vue'
/** 导入解构pinia状态保持响应式的函数 */
import { storeToRefs } from 'pinia'
/** 导入已有的语言列表 */
import { langs } from '@/locales'
/** 导入locales仓库 */
import { useLocalesStore } from '@/store/modules/locales'
defineOptions({
name: 'Language'
})
/** 初始化locales仓库 */
const localesStore = useLocalesStore()
/** 从localesStore仓库中解构属性,并保持响应式 */
const { locale: curLocale } = storeToRefs(localesStore)
/** 头部导航栏语言下拉菜单显示的当前语言环境 */
const currentLocale = ref(langs.find((locale) => locale.key === curLocale.value)?.title ?? '')
/** 切换当前语言环境 */
const changeLanguage = (locale: any): void => {
/** 当切换语言环境的时候,同时切换显示的当前语言 */
currentLocale.value = locale.title
...
}
</script>
效果:
以为这就彻底完成了吗?那就有点和我一样草率了,试着刷新看看~是不是发现了什么?
对的,刷新又变回以前的语言环境了。这时候我们就得将修改的语言环境记录到本地缓存中啦!!
本地持久化
当我们将语言设置为English后,如果刷新页面的话,语言环境又会回到中文。所以我们需要做一点操作来保持国际化状态。
这里采用的是Pinia搭配localStorage来完成保持国际化状态。
所以使用到pinia的持久化插件pinia-plugin-persistedstate
-
安装:
npm install pinia-plugin-persistedstate
-
将插件添加到pinia实例中:
import { createPinia } from 'pinia' /** 导入pinia持久化插件 */ import piniaPluginpersistedState from 'pinia-plugin-persistedstate' import { type App } from 'vue' /** 向外暴露pinia实例,方便再setup语法糖意外的地方使用store */ export const store = createPinia() /** 在pinia的实例上添加持久化插件 */ store.use(piniaPluginpersistedState) /** * 在vue实例对象上注册pinia * @param app vue实例对象 */ export function setupStore(app: App): void { app.use(store) }
-
用法:
- Option Store:
import { defineStore } from 'pinia' export const useStore = defineStore('main', { state: () => { return { someState: 'hello pinia', } }, persist: true, })
- Setup Store:
import { defineStore } from 'pinia' export const useStore = defineStore( 'main', () => { const someState = ref('hello pinia') return { someState } }, { persist: true, }, )
- Option Store:
-
在
store/modules/locales.ts
中使用:... /** 创建 locales Store */ export const useLocalesStore = defineStore( 'locales', () => { ... }, // 本地持久化缓存 { persist: true } ) ...
-
效果: