vue项目国际化(使用vue-i18n)

Posted kite吖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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.jszh.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: 'ab哈哈'
    
  

//组件中使用1
<p> $t('message.title') </p>
//输出
<p>ab哈哈</p>

//组件中使用2, 
<p> $t('message.title',a:1,b:2) </p>
//输出
<p>12哈哈</p>

如上述例子中显示,如果未传第二个参数,那么将会都以按照字符串的形式展示.


2.不同的命名类型

const messages = 
  en: 
    message: 
      title: 'ab哈哈'
    
  

//组件中使用  数值型与字符串类型 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: '012忘了想念'
    
  

// 组件内使用 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:55

numberFormats  设置数字格式化包括货币类型等.

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.locale

8.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>
 //输出
 哈哈cfz

v-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())
)

vue项目中使用vue-i18n国际化

参考技术A 在src/目录下新建lang文件夹
lang/文件中有en.js,index.js,zh.js
例如en.js

zh.js

index.js

在main.js中引入

在组件中的使用
在模板中使用<p> $t("route.home") </p>
在有的项目中需要循环侧边栏导航,所以写了一个工具方法

在组件中使用时,引入这个工具方法

请参考
vue-i18n

这是不用vue时,js的前端国际化
一般会新建一个文件存放语言信息
i18n/language_en.properties

i18n/language_zh.properties

html文件

参考 jquery-i18n-properties

以上是关于vue项目国际化(使用vue-i18n)的主要内容,如果未能解决你的问题,请参考以下文章

vue-i18n 怎么用在data属性上

前端框架Vue.js——vue-i18n ,vue项目中如何实现国际化

vue项目国际化(多语言)

vue项目国际化(使用vue-i18n)

Vue国际化处理 vue-i18n 以及项目自动切换中英文

使用vue-i18n实现项目的国际化 以及iview的国际化