本文主要梳理vue2项目实现全项目格式化,在导航栏中切换,页面中所有的组件的默认语言随之切换,搭配vue-i18n插件
文章目录
基础准备
引入插件vue-i18n
安装插件
npm i vue-i18n
【注】安装过程中报错
npm ERR! Cannot read properties of null (reading ‘matches‘)
解决方案:
先清除npm缓存:
npm cache clean --force
再使用pnpm进行安装(未安装的话就npm i pnpm一下即可)
pnpm i vue-i18n
或者在package.json文件中直接添加 “vue-i18n”: “^8.27.1”,版本,在进行重新进行npm install一下也可以
实现示例流程
1. 创建国际化文件
在src文件目录下创建i18n文件夹,文件夹下创建:element、locales、change-language.vue、index.js四个文件
1.1 element文件夹
创建两个文件:en.js,zh-CN.js,
主要用于存放elementUI组件,一些相对固定的文本描述翻译
【en.js】
// 英语
exports.default = {
el: {
colorpicker: {
confirm: 'OK',
clear: 'Clear'
},
datepicker: {
now: 'Now',
today: 'Today',
cancel: 'Cancel',
clear: 'Clear',
confirm: 'OK',
selectDate: 'Select date',
selectTime: 'Select time',
startDate: 'Start Date',
startTime: 'Start Time',
endDate: 'End Date',
endTime: 'End Time',
prevYear: 'Previous Year',
nextYear: 'Next Year',
prevMonth: 'Previous Month',
nextMonth: 'Next Month',
year: 'year',
month1: 'January',
month2: 'February',
month3: 'March',
month4: 'April',
month5: 'May',
month6: 'June',
month7: 'July',
month8: 'August',
month9: 'September',
month10: 'October',
month11: 'November',
month12: 'December',
week: 'week',
weeks: {
sun: 'Sun',
mon: 'Mon',
tue: 'Tue',
wed: 'Wed',
thu: 'Thu',
fri: 'Fri',
sat: 'Sat'
},
months: {
jan: 'Jan',
feb: 'Feb',
mar: 'Mar',
apr: 'Apr',
may: 'May',
jun: 'Jun',
jul: 'Jul',
aug: 'Aug',
sep: 'Sep',
oct: 'Oct',
nov: 'Nov',
dec: 'Dec'
}
},
select: {
loading: 'Loading',
noMatch: 'No matching data',
noData: 'No data',
placeholder: 'Select'
},
cascader: {
noMatch: 'No matching data',
loading: 'Loading',
placeholder: 'Select',
noData: 'No data'
},
pagination: {
goto: 'Go to',
pagesize: '/page',
total: 'Total {total}',
pageClassifier: ''
},
messagebox: {
title: 'Message',
confirm: 'OK',
cancel: 'Cancel',
error: 'Illegal input'
},
upload: {
deleteTip: 'press delete to remove',
delete: 'Delete',
preview: 'Preview',
continue: 'Continue'
},
table: {
emptyText: 'No Data',
confirmFilter: 'Confirm',
resetFilter: 'Reset',
clearFilter: 'All',
sumText: 'Sum'
},
tree: {
emptyText: 'No Data'
},
transfer: {
noMatch: 'No matching data',
noData: 'No data',
titles: ['List 1', 'List 2'], // to be translated
filterPlaceholder: 'Enter keyword', // to be translated
noCheckedFormat: '{total} items', // to be translated
hasCheckedFormat: '{checked}/{total} checked' // to be translated
},
image: {
error: 'FAILED'
},
pageHeader: {
title: 'Back' // to be translated
},
popconfirm: {
confirmButtonText: 'Yes',
cancelButtonText: 'No'
},
empty: {
description: 'No Data'
}
},
};
【zh-CN.js】
// 中文
exports.default = {
el: {
colorpicker: {
confirm: '确定',
clear: '清空'
},
datepicker: {
now: '此刻',
today: '今天',
cancel: '取消',
clear: '清空',
confirm: '确定',
selectDate: '选择日期',
selectTime: '选择时间',
startDate: '开始日期',
startTime: '开始时间',
endDate: '结束日期',
endTime: '结束时间',
prevYear: '前一年',
nextYear: '后一年',
prevMonth: '上个月',
nextMonth: '下个月',
year: '年',
month1: '1 月',
month2: '2 月',
month3: '3 月',
month4: '4 月',
month5: '5 月',
month6: '6 月',
month7: '7 月',
month8: '8 月',
month9: '9 月',
month10: '10 月',
month11: '11 月',
month12: '12 月',
// week: '周次',
weeks: {
sun: '日',
mon: '一',
tue: '二',
wed: '三',
thu: '四',
fri: '五',
sat: '六'
},
months: {
jan: '一月',
feb: '二月',
mar: '三月',
apr: '四月',
may: '五月',
jun: '六月',
jul: '七月',
aug: '八月',
sep: '九月',
oct: '十月',
nov: '十一月',
dec: '十二月'
}
},
select: {
loading: '加载中',
noMatch: '无匹配数据',
noData: '无数据',
placeholder: '请选择'
},
cascader: {
noMatch: '无匹配数据',
loading: '加载中',
placeholder: '请选择',
noData: '暂无数据'
},
pagination: {
goto: '前往',
pagesize: '条/页',
total: '共 {total} 条',
pageClassifier: '页'
},
messagebox: {
title: '提示',
confirm: '确定',
cancel: '取消',
error: '输入的数据不合法!'
},
upload: {
deleteTip: '按 delete 键可删除',
delete: '删除',
preview: '查看图片',
continue: '继续上传'
},
table: {
emptyText: '暂无数据',
confirmFilter: '筛选',
resetFilter: '重置',
clearFilter: '全部',
sumText: '合计'
},
tree: {
emptyText: '暂无数据'
},
transfer: {
noMatch: '无匹配数据',
noData: '无数据',
titles: ['列表 1', '列表 2'],
filterPlaceholder: '请输入搜索内容',
noCheckedFormat: '共 {total} 项',
hasCheckedFormat: '已选 {checked}/{total} 项'
},
image: {
error: '加载失败'
},
pageHeader: {
title: '返回'
},
popconfirm: {
confirmButtonText: '确定',
cancelButtonText: '取消'
},
empty: {
description: '暂无数据'
}
},
};
1.2 locales文件夹
创建两个文件:en.js,zh-CN.js,
主要用于存放页面中所需要的除了elementUI自带其他的页面文本描述元素
【en.js】
export default {
Language: 'English',
system: {
homePage: {
title1: 'title1',
title2: 'title2',
description1: 'Last 7 days',
description2: 'Nearly six months',
}
}
};
【zh-CN.js】
export default {
Language: '中文',
system: {
homePage: {
title1: '标题1',
title2: '标题2',
description1: '近7日',
description2: '近6个月',
}
}
};
1.3 index.js
文本集成文件,用于导入到入口文件main.js中,基本结构就是将两个element和locales文件集成导入,为了实现全局控制使用了本地储存localStorage来进行全局控制切换值,默认中文
import Vue from 'vue';
import VueI18n from 'vue-i18n';
Vue.use(VueI18n);
// 各个国家的key
const localeKeys = ['en', 'zh-CN'];
// 各个国家语言包
const messages = {};
for (const key of localeKeys) {
const langObj = require(`./locales/${key}`).default;
const langElement = require(`./element/${key}`);
messages[key] = {
...langObj,
...langElement ? langElement.default : {}
};
}
export default new VueI18n({
locale: localStorage.getItem('change-language') || 'zh-CN',
messages,
silentTranslationWarn: true // 忽略翻译警告
});
解析:
-
locale属性:用于控制语言的标识,默认中文,此处使用了localStorage本地储存,方便全局且页面刷新都可以保持选中值
-
messages属性:切换文本的主要内容值,当locale的属性切换,所对应的语言的文本展示
-
silentTranslationWarn:是否忽略翻译警告
1.4 change-language.vue 切换组件
封装国际化语言切换组件,方便调用使用
<template>
<el-dropdown @command="handle"
style="cursor: pointer;">
<span class="el-dropdown-link">
{{$t('Language')}}<i class="el-icon-caret-bottom el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="(item, index) of list"
:key="index"
:disabled="$t('Language') == item.name"
:command="item.key">{{item.name}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
export default {
name: 'change-language',
data() {
return {
list: [
{ key: 'en', name: 'English' }, // 英语
{ key: 'zh-CN', name: '中文' }, // 中文
],
}
},
methods: {
handle(value) {
this.$i18n.locale = value
localStorage.setItem('change-language', value)
location.reload()
},
},
}
</script>
<style scoped lang="scss">
</style>
2. 全局引入(main.js)
在入口文件main.js文件中进行引入,方便全局使用,
import i18n from './i18n';
Vue.use(Element, {
i18n: (key, value) => i18n.t(key, value),
});
new Vue({
el: '#app',
router,
store,
i18n,
render: h => h(App)
});
3. 在导航栏navbar.vue组件切换逻辑
直接在导航栏引入封装组件
引入:
<ChangeLanguage />
import ChangeLanguage from '@/i18n/change-language'
export default {
components: {
ChangeLanguage,
},
}
效果:
4. 在首页示例展示效果
示例组件:
直接使用$t函数直接双向绑定
<template>
<div class="newMain-container homePage">
示例代码:
<br>
我是title1===:{{ $t('system.homePage.title1') }}
<br>
我是title2===:{{ $t('system.homePage.title2') }}
<br>
我是description1===:<el-button type="primary">{{ $t('system.homePage.description1') }}</el-button>
<br>
我是description2===:<el-button type="primary">{{ $t('system.homePage.description2') }}</el-button>
</div>
</template>
效果: