Vue项目中i18n配置多语言(国际化)--配合ElementUi库
要求:
- vscode安装i18n Ally插件
- npm i element-ui -S
- node_modules→element-ui→lib→locale→lang(文件夹下找到对应的语言包.js,转成JSON格式,复制到相应位置)
src文件夹中创建语言包文件夹
├─src ---------页面文件夹(开发代码目录)
│ ├─lang ---------语言包文件夹
│ ├─├─locale ---------存放多语言文件夹和相关配置
│ ├─├─├─en-GB.json ---------多语言英文
│ ├─├─├─zh-CN.json ---------多语言中文
│ ├─├─i18n-setup.js ---------i18n相关配置
en-GB.json
对象里面有两个key:
el是element-ui库的英文(key-value),其他ui库类似
lang是自己代码里面的英文(key-value)
{
"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": "",
"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"],
"filterPlaceholder": "Enter keyword",
"noCheckedFormat": "{total} items",
"hasCheckedFormat": "{checked}/{total} checked"
},
"image": { "error": "FAILED" },
"pageHeader": { "title": "Back" },
"popconfirm": { "confirmButtonText": "Yes", "cancelButtonText": "No" },
"empty": { "description": "No Data" }
},
"lang": {
"mypage": {
"t1": "A bottle of human samples",
"t2": "I can't be described in one sentence",
"t3": "Came and said nothing",
"t4": "pick me",
"t5": "Please choose",
"t6": "Do not change your motto at will",
"t7":"choose date"
}
}
}
zh-CN.json
同en-GB类似
{
"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 月",
"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": "暂无数据" }
},
"lang": {
"mypage": {
"t1": "一瓶人间小样",
"t2": "一句话简介不了我",
"t3": "来过什么话都没有留下",
"t4": "点我",
"t5": "请选择",
"t6": "座右铭岂不随意更改",
"t7":"选择日期"
}
}
}
i18n-setup.js
语言优先级:url参数设置的 > Cookie保存的 > 浏览器默认的
- SYS_LANG(浏览器默认语言)
- SUPPORT_LANGUAGE(当前支持的语言)
- COOKIES_LANG(Cookies里保存的语言)
- LINK_LANG(URL里设置的语言)
- DEFAULT_LANGUAGE(默认语言)
- CURRENT_LANG(入口文件直接拿取当前语言环境, .vue 文件内部用 this.$i18n.locale 来获取即可
import Vue from 'vue';
import Cookies from 'js-cookie';
import VueI18n from 'vue-i18n';
import ElementLocal from 'element-ui/lib/locale' // 引入Element-ui语言包
Vue.use(VueI18n);
// 浏览器默认语言
let SYS_LANG = navigator.language || navigator.userLanguage;
// 兼容zh-cn模式
SYS_LANG = SYS_LANG.toLowerCase().split('-')[1] ? SYS_LANG.toLowerCase().split('-')[0] + '-' + SYS_LANG.toUpperCase().split('-')[1] : SYS_LANG;
// 当前支持的语言
const SUPPORT_LANGUAGE = ['zh-CN', 'en-GB'];
// Cookies里保存的语言
const COOKIES_LANG = !Cookies.get('my_language') || Cookies.get('my_language') == 'undefined' ? '' : Cookies.get('my_language');
// URL里设置的语言,例如: www.xxx.com/page/xxx.html#/?my-lang=zh-CN(无关参数位置)
const LINK_LANG = location.hash.indexOf('my-lang') != -1 ? location.hash.split('?')[1].split('my-lang')[1].split('=')[1].split('&')[0] : '';
// 上述所有的 语言参数 都为空值的话,则需要提供一个默认的语言。(英语。20210812 确定)
const DEFAULT_LANGUAGE = 'en-GB';
// 当前语言环境, 优先级: url参数设置的 > Cookie保存的 > 浏览器默认的
// 输出这个参数, 可以在项目main.js入口文件处获取当前语言环境, .vue 文件内部就用 this.$i18n.locale 来获取即可
let CURRENT_LANG = LINK_LANG || COOKIES_LANG || SYS_LANG || DEFAULT_LANGUAGE;// 同上规则设置语言优先级顺序
// 兼容之前的链接方式
CURRENT_LANG = CURRENT_LANG == 'en' ? 'en-GB' : CURRENT_LANG;
CURRENT_LANG = CURRENT_LANG == 'zh' ? 'zh-CN' : CURRENT_LANG;
// 实例化i18n
export const i18n = new VueI18n({
locale: CURRENT_LANG, // 设置当前语言环境
fallbackLocale: DEFAULT_LANGUAGE, // 回滚设置
messages: {}, // 设置语言环境包
silentTranslationWarn: true
});
ElementLocal.i18n((key, value) => i18n.t(key, value)); // 兼容 element-ui i18n函数
// 改变语言环境
function setI18nLanguage(lang) {
Cookies.set('my_language', lang, {
expires: 7,
path: '/'
}); // 添加到cookie
i18n.locale = lang; // 切换语言环境
document.querySelector('html').setAttribute('lang', lang); // html标签加lang属性备用
document.querySelector('body').setAttribute('id', lang == 'zh-CN' ? 'zh-CN' : 'en-GB'); // 给body标签加id
return lang;
}
// 更新本地缓存,并返回对应的语言包
const updataLocalStorage = (lang, langMessage) => {
// 如果有传入语言包, 就直接更新 localStorage,这里就是针对后端请求有返回,就保存
// 如果是后端请求返回语言包(下面会做补充),这里不需要后端,存本地也是行的
if (!!langMessage) {
localStorage.setItem(lang, JSON.stringify(langMessage));
return Promise.resolve(langMessage);
}
// 如果本地不存在语言
if (!localStorage.getItem(lang)) {
return import(`@/lang/locale/${lang}.json`).then((messages) => {
localStorage.setItem(lang, JSON.stringify(messages));
return messages
})
}
// 如果本地存在
return Promise.resolve(JSON.parse(localStorage.getItem(lang)));
};
// 异步加载语言包
export async function loadLanguageAsync(_lang, message) {
// 语言环境优先级: 需要设置的 > url参数设置的 > Cookie保存的 > 浏览器默认的
let lang = _lang || CURRENT_LANG;
lang = SUPPORT_LANGUAGE.includes(lang) ? lang : DEFAULT_LANGUAGE; // 还没有支持的语言就直接用默认的语言
// updateMetaInfo(lang); // 更新 html页面的 meta信息(可根据自己的情况去写逻辑更新,这里就不在做详细说明)
const langMessage = await updataLocalStorage(lang, message); // 先获取本地缓存直接使用,后面再根据后端的请求是否要更新
// console.log(langMessage)
i18n.setLocaleMessage(lang, Object.assign({}, langMessage));
return setI18nLanguage(lang);
}
i18n.loadLanguageAsync = loadLanguageAsync;
补充1:取本地语言包或者后端接口返回语言包处理方法(与后端沟通看需要传的参数)
// 请求语言包
async getTranslation(item) {
try {
let res = await axios.get('/base/i18n/v1/translation.php', {
params: {
l:'zh-CN',// 当前什么语言,可变的,根据自己需求,这里暂时写死为zh-CN
m: 'pc',// 什么端,PC或h5
}
});
if (Array.isArray(res.data)) return;
// 设置版本
localStorage.setItem(this.lang + '-version', item['last_translation_pair_id']);
// 请求成功,缓存
this.$i18n.loadLanguageAsync(this.lang, res.data);
} catch (error) {
}
},
main.js中使用
import Vue from 'vue'
import App from './App'
import router from './router'
// 按需导入elementUI库
import { Button, Select, Option,Message,Tabs,TabPane,DatePicker} from 'element-ui';
// i18n
import { i18n } from './lang/i18n-setup';
Vue.component(Button.name, Button);
Vue.component(Select.name, Select);
Vue.component(Option.name, Option);
Vue.component(Message.name, Message);
Vue.component(Tabs.name, Tabs);
Vue.component(TabPane.name, TabPane);
Vue.component(DatePicker.name, DatePicker);
Vue.prototype.$message=Message
// i18n项目中的使用方法
i18n.loadLanguageAsync().then(() => {
new Vue({
el: '#app',
router,
store,
i18n,
components: { App },
template: '<App/>'
})
})
补充:下面的写法,只会让当前页面只有英文和你传的语言包
// i18n项目中的使用方法
i18n.loadLanguageAsync('en-GB',{语言包}).then(() => {
new Vue({
el: '#app',
router,
store,
i18n,
components: { App },
template: '<App/>'
})
})
.vue文件夹中使用
template中:使用多语言:$t('lang.mypage.t5')翻译为:请选择
<template>
<div>
<el-select v-model="language" :placeholder="$t('lang.mypage.t5')" @change="change">
<el-option v-for="item in options":key="item.value":label="item.label":value="item.value">
</el-option>
</el-select>
</div>
</template>
script中
<script>
export default {
created() {
// console.log(this.$i18n.locale, "语言包");
},
data() {
return {
language: "",
options: [
{
value: "zh-CN",
label: "中文"
},
{
value: "en-GB",
label: "English"
}
],// 暂时只有中文英文,这是elementui中的下拉切换语言用
};
},
methods: {
async change(val) {
if (this.$i18n.locale === val) return;// 如果是当前语言直接return
await this.$i18n.loadLanguageAsync(val);// 不是当前语言,切换语言
},
}
};
</script>