ant design vue教程(vue项目国际化(使用vue-i18n))
最近一个优先级高的任务——将之前的vue项目全局国际化 ,时间紧急虽然付出了较多的努力 ,但因为不够细心 ,导致出现单词拼错 、翻译缺漏等错误 ,还有翻译过后因中英文字符长度差异产生的样式问题 ,上线效果并不理想 。这里记录一下vue-i18n国际化语言包处理插件的使用 。
vue-i18n官网文档
安装
npm install vue-i18n --save配置及使用
在src目录新建i18n目录 ,en.js为英文语言包 ,zh.js为中文语言包
en.js文件内容
export default { common: { username: 用户名, password: 密码, save: 保存, edit: 编辑, update: 更新, delete: 删除, forever: 永久, expired: 过期 } }zh.js 文件内容
export default { common: { username: username, password: password, save: Save, edit: Edit, update: Update, delete: Delete, forever: Forever, expired: Expired } }i18n 下index.js文件
import Vue from vue import VueI18n from vue-i18n import Cookies from js-cookie import elementEnLocale from element-ui/lib/locale/lang/en // element-ui lang导入Element的语言包 英文 import elementZhLocale from element-ui/lib/locale/lang/zh-CN// element-ui lang g导入Element的语言包 中文 import enLocale from ./en // 导入项目中用到的英文语言包 import zhLocale from ./zh// 导入项目中用到的中文语言包 Vue.use(VueI18n) const messages = { en: { ...enLocale, ...elementEnLocale }, zh: { ...zhLocale, ...elementZhLocale, }, } const i18n = new VueI18n({ locale: localStorage.getItem(language) || zh, // 设置语种 messages, // 设置全局当地语言包, fallbackLocale: zh, numberFormats:{ //设置 数字本地化 en: { currency: { //添加 $ style: currency, currency: USD } }, zh: { currency: { //添加 ¥ style: currency, currency: JPY, currencyDisplay: symbol } } }, dateTimeFormats:{//设置 日期时间本地化 en: { short: { year: numeric, month: short, day: numeric }, long: { year: numeric, month: short, day: numeric, weekday: short, hour: numeric, minute: numeric } }, zh: { short: { year: numeric, month: short, day: numeric }, long: { year: numeric, month: short, day: numeric, weekday: short, hour: numeric, minute: numeric } } } }) export default i18n在主入口文件main.js中
import Vue from vue import Element from element-ui import element-ui/lib/theme-chalk/index.css //导入配置好的国际化语言包 import i18n from ./i18n // Internationalization Vue.use(Element, { size: medium, // set element-ui default size设置元素默认大小 i18n: (key, value) => i18n.t(key, value)// 在注册Element时设置i18n的处理方法 }) Vue.config.productionTip = false// 生产提示 new Vue({ el: #app, i18n, // 注入 配置好的国际化语言配置 })在vue中注册i18n之后 ,我们便可以在组件中通过this.$i18n获取到我们配置好的这个i18n对象
将导入的VueI18n实例化 ,在new VueI18n()中传入配置信息:
locale 当前语种 fallbackLocale 如果当前语种不存在时 ,默认设置当前语种 messages 本地语言包(en,zh...) numberFormats 设置 数字格式化 dateTimeFormats 设置 时间日期格式化 接下来一一介绍:locale 主要是用来设置语种包 如何切换locale?
//在组件中 import i18n from "@/i18n" //根据项目对应真实路径 i18n.locale="en" // 改变为中文 localStorage.setItem(language,"en")//在localStorage中存入设置messages
一般会将项目中的静态语言分成产品所需要的各个语种,包括中文 ,英文 ,法文等...比如:
message:{ zh: { common: { username: 用户名, password: 密码, save: 保存, edit: 编辑, update: 更新, delete: 删除, forever: 永久, expired: 过期 } }, en: { common: { username: username, password: password, save: Save, edit: Edit, update: Update, delete: Delete, forever: Forever, expired: Expired } } }zh就代表静态语言中文版,en代表静态语言英文版 ,一般就将en,zh单独分成两个模块——en.js, zh.js.这样项目不仅结构变得更简洁明了 ,在维护开发阶段也节省很多时间 。
$t 的使用(格式化)
简单来说就是拿到messages中的某个数据,参数是字符串 ,代表着所要获取的某一条数据
注意:
放在data中的静态数据 国际化需要放到computed中 ,切换时才会有响应式;
当翻译定义在consts 里的某些常量时 ,用 i18n.t 翻译 再用函数返回 , 在页面使用时在computed 中调用函数 ,切换时才会有响应式;
简单使用
//template 需要使用 {{}} 将 name包装起来 {{$t(save)}} // js this.$t(save)[命名格式化]
const messages = { en: { message: { title: hello, {name} } } } //组件中使用 <p>{{ $t(message.title, { name: Kite }) }}</p> //输出 <p>hello, Kite</p>这种叫做命名格式化 ,可以区域格式化信息 。 这种情况下$t的第二参数是一个对象 ,就代表了所有需要动态添加的内容,注意是所有在message中所需要动态添加的变量都在第二个参数中 。
1.未传第二个参数
const message = { en: { message: { title: {a}{b}哈哈 } } } //组件中使用1 <p>{{ $t(message.title) }}</p> //输出 <p>{a}{b}哈哈</p> //组件中使用2, <p>{{ $t(message.title,{a:1,b:2) }}</p> //输出 <p>12哈哈</p>如上述例子中显示 ,如果未传第二个参数 ,那么将会都以按照字符串的形式展示.
2.不同的命名类型
const messages = { en: { message: { title: {a}{b}哈哈 } } } //组件中使用 数值型与字符串类型 1 <p>{{ $t(message.title,{a:1,b:"2") }}</p> //输出 <p>12哈哈</p> //组件中使用2 对象类型 <p>{{ $t(message.title,{a:{},b:"2") }}</p> //输出 <p>[object Object]2哈哈</p> //组件中使用3 数组类型(内含布尔 ,对象类型) <p>{{ $t(message.title,{a:[1,2,3,true,{}],b:"2") }}</p> //输出 <p>123true[object Object]2哈哈</p> object对象类型会直接输出 [object Object] boolean布尔类型会按照字符串输出 true-->"true"/false-->"false" array数组类型中 ,如果每一项都是数值或者字符串那么直接输出,否则按上述情况显示[列表格式]
const message = { en: { message: { sing: {0}{1}{2}忘了想念 } } } // 组件内使用 1 列表格式 <p>{{ $t(message.sing, [我 ,以,为]) }}</p> //输出 <p>我以为忘了想念</p> // 组件内使用 2 类似命名格式的方式 <p>{{ $t(message.sing, { 0:"我",1:以,2:为 }) }}</p> //输出 <p>我以为忘了想念</p>$tc 的使用 (复数)
const messages = { en: { apple: no apples | one apple | {count} apples, banana: no bananas | {n} banana | {n} bananas } }这里必须注意一点:必须定义具有管道 | 分隔符的区域设置 ,并在管道分隔符中定义复数
//在组件内使用 <p>{{ $tc(apple, 10, { count: 10 }) }}</p> <p>{{ $tc(apple, 10) }}</p> <p>{{ $tc(banana, 1, { n: 1 }) }}</p> <p>{{ $tc(banana, 1) }}</p> <p>{{ $tc(banana, 100, { n: too many }) }}</p> //输出 <p>10 apples</p> <p>10 apples</p> <p>1 banana</p> <p>1 banana</p> <p>too many bananas</p>1 、在定义复数时 ,必要使用|管道符分隔 。
2 、当|管道符等于1个时,索引从1开始 ,最大索引为2;当管道符大于1个时 ,索引从0开始(类似数组),最大索引为管道符的个数
3 、通过使用$tc(“复数 ”,index)获取对应语言文本
dateTimeFormats 日期时间格式化
dateTimeFormats:{//设置 日期时间本地化 en: { short: { //显示英文 年月日 year: numeric, month: short, day: numeric }, long: { //显示英文 年月日 星期 小时 分钟 year: numeric, month: short, day: numeric, weekday: short, hour: numeric, minute: numeric } }, zh: { short: { year: numeric, month: short, day: numeric }, long: { year: numeric, month: short, day: numeric, weekday: short, hour: numeric, minute: numeric } } }处理数字有$n方法 ,对于日期时间格式化也有对应的方法——$d
//在组件中使用 <div id="app"> <p>{{ $d(new Date(), short) }}</p> <p>{{ $d(new Date(), long) }}</p> <p>{{ $d(new Date(), short,zh) }}</p> <p>{{ $d(new Date(), long, zh) }}</p> </div> //输出 Jul 31, 2022 Sat, Jul 31, 2022, 5:55 PM 2022年07月23日 2018年07月23日 周六 下午5:55numberFormats 设置数字格式化包括货币类型等.
numberFormats:{ en: { currency: { //添加 $ style: currency, currency: USD } }, zh: { currency: { //添加 ¥ style: currency, currency: JPY, currencyDisplay: symbol } } },$n(数字本地化)
对于数字格式化在组件中如何使用 ,如同$t一样 ,也提供了对应的方法$n.
//组件中使用 <p>{{ $n(100, currency) }}</p> <p>{{ $n(100, currency, zh) }}</p> //输出 <p>$100.00</p> <p>¥100</p>$n(number,path,locale)方法 ,三个参数:
number 用户传入数字 必传 path 调用的格式化方案 必传 locale 使用的语种 ,默认是当前this.$i18n.locale8.10+ 新增:$n 方法返回的结果字符串带有完全格式化的数字 ,该数字只能作为整体使用 。 在需要格式化格式化数字的某些部分(例如小数位)的情况下 ,$n 是不够的 。 在这种情况下 ,<i18n-n> 功能组件将有所帮助 。
有了最少的一组属性 ,<i18n-n> 产生的输出与 $n 相同 ,并包装到已配置的DOM元素中 。
<i18n-n :value="1234" :format="{ key: currency, currency: EUR }"> <span v-slot:currency="slotProps" styles="color: green">{{ slotProps.currency }}</span> <span v-slot:integer="slotProps" styles="font-weight: bold">{{ slotProps.integer }}</span> <span v-slot:group="slotProps" styles="font-weight: bold">{{ slotProps.group }}</span> <span v-slot:fraction="slotProps" styles="font-size: small">{{ slotProps.fraction }}</span> </i18n-n> // 结果 <span> <span styles="color: green">€</span> <span styles="font-weight: bold">1</span> <span styles="font-weight: bold">,</span> <span styles="font-weight: bold">234</span> <span styles="font-size: small">00</span> </span>常用方法
getLocaleMessage
this.i18n.getLocaleMessage(key),这个方法是用来获取全局语言包中某个语种的语言包,比如:
this.i18n.getLocaleMessage(en)//获取英文的语言包 返回的同样是一个对象mergeLocaleMessage
this.i18n.mergeLocaleMessage(key,localeData),这是方法是用来对于 key语种中添加本地语言包,往往在某个子组件中,我们会将某个区域语言包合并到全局对应语种的语言包
this.$i18n.mergeLocaleMessage(zh, local.zh)//向全局中文语言包中补充内容v-t
自定义指令v-t.它和$t作用一样 ,都是获取语言包中的某条数据 ,但也有很大的区别
v-t的使用
//locale=en const messages = { en: { message: { title: hello } }, zh:{ message: { title: 哈哈{name} } } } //组件中使用1 字符串用法 <p v-t="message.title"></p> //输出 hello //组件中使用2 对象用法 <p v-t="{ path: message.title, locale: zh, args: { name: cfz } }"></p> //输出 哈哈cfzv-t和$t的区别
$t 是扩展的Vue实例方法
[优点] 在模板中灵活使用小胡子语法(mustash)语法{{}},也可以在Vue实例中灵活地使用计算道具和方法 。
[缺点] 每次重新渲染时都会执行 ,因此它比较消耗性能 。
v-t是一个自定义指令
[优点] 当翻译一次时 ,由于其使用自定义指令进行缓存 ,因此具有比$t方法更好的性能.
[缺点] v-t不能灵活使用$t ,因为它相当复杂。已翻译的内容v-t将插入到textContent元素中 。
还有一些其他的用法 ,具体的请参考官方文档
插入组件
如果遇到这样的场景 ,如何去处理?
<p>I accept xxx <a href="/term">Terms of Service Agreement</a></p>我的第一反应是分成两个字段 ,a标签不属于翻译的内容 ,只要写成:
<p>{{ $t(xx1) }}<a href="/term">{{ $t(xx2) }}</a></p>看了官网的介绍 ,说这种处理太笨拙了 ,可以通过组件的方式去处理
使用了两个变量存储信息 通过tag来生产标签 ,path来制定标签的内容
// 这里使用了i18n 组件 <i18n path="term" tag="p" for="tos"> <a :href="url" target="_blank">{{ $t(tos) }}</a> </i18n> const messages = { en: { tos: Term of Service, term: I accept xxx {0}. } } new Vue({ el: #app, i18n, data: { url: /term } })更高级的用法 ,可以控制html元素的插入位置,通过place来指定出现在html中的位置 。
<i18n path="info" tag="p"> <span place="limit">{{ changeLimit }}</span> <a place="action" :href="changeUrl">{{ $t(change) }}</a> </i18n> const messages = { en: { info: You can {action} until {limit} minutes from departure., change: change your flight, refund: refund the ticket } } const i18n = new VueI18n({ locale: en, messages }) new Vue({ i18n, data: { changeUrl: /change, refundUrl: /refund, changeLimit: 15, refundLimit: 30 } }).$mount(#app) // result <p> You can <a href="/change">change your flight</a> until <span>15</span> minutes from departure. </p>动态加载语言包
一次加载所有的语言包是没有必要的 ,特别是语言包过的情况下 ,之前我也提出了这个问题,发现官网上是给了解决方式的。
//i18n-setup.js import Vue from vue import VueI18n from vue-i18n import messages from @/i18n // 语言包的地址 ,随项目本身设置修改 import axios from axios // 根据项目中使用api请求模块去设置 ,不一定是axios Vue.use(VueI18n) export const i18n = new VueI18n({ locale: en, // set locale fallbackLocale: en, // 默认语言设置 ,当其他语言没有的情况下 ,使用en作为默认语言 messages // set locale messages }) const loadedLanguages = [en] // our default language that is prelaoded function setI18nLanguage (lang) { i18n.locale = lang axios.defaults.headers.common[Accept-Language] = lang // 设置请求头部 document.querySelector(html).setAttribute(lang, lang) // 根元素增加lang属性 return lang } export function loadLanguageAsync (lang) { if (i18n.locale !== lang) { if (!loadedLanguages.includes(lang)) { return import(/* webpackChunkName: "lang-[request]" */ `@/lang/${lang}`).then(msgs => { i18n.setLocaleMessage(lang, msgs.default) loadedLanguages.push(lang) return setI18nLanguage(lang) }) } return Promise.resolve(setI18nLanguage(lang)) } return Promise.resolve(lang) } // 在vue-router的beforeEach的全局钩子处理 router.beforeEach((to, from, next) => { const lang = to.params.lang loadLanguageAsync(lang).then(() => next()) })创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!