不少网站有多语言模式,正好项目里需要多语言切换,简单学习之后,整理成文章,加深记忆。

Vue I18n 是 Vue.js 的国际化插件,格局比较大,具体怎么解释还是不太好说,直接看用法就能明白。简单说一下为什么叫这个名字:internationalization(i+中间的18个字母+n)。

如果你更喜欢看官方文档可以移步下面的官方文档,本文只是基本使用,看本文你也可以学会基本使用
i18n官网: https://kazupon.github.io/vue-i18n/zh/

本文案例环境:

  • "vue": "^2.6.11",
  • "vue-i18n": "^8.23.0",
  • 安装vue-I18n插件
  • //需要使用npm进行安装8.x版本
    npm install vue-i18n@8.23.0
    

    注:如果按照使用时候报一堆错误,找不到变量,可能是i18n版本太高了,与当前VUE版本不兼容,我的项目vue版本是2.6.11,开始我就安装的i18n版本是9.x,一直报错找不到原因,我就试着把i18n版本降低到8.x就不报错了

  • 在项目中配置i18n
    main.js 中引入 vue-i18n
  • import Vue from 'vue' // 先引入vue
    import VueI18n from 'vue-i18n'//引入对应的组件
    Vue.use(VueI18n);//挂载使用i18n的插件
    

    设置本地语言来挂载不同的信息(变量)

    通常语言环境信息 (例如:localemessages 等) 会被设置为 VueI18n 实例的构造函数选项,并且该实例会被作为 i18n 选项设置在 Vue 的根实例上。

    因此你可以全局地在 Vue 的根实例以及任何被组合的组件中使用 $t 或者 $tc 进行翻译。当然面向 Vue 组件的设计,你也可以更方便的分别控制每个组件的语言环境信息。

    main.js 中引入 vue-i18n

    // 为 Vue 的根实例设置语言环境信息
    // 通过选项创建 VueI18n 实例
    const i18n = new VueI18n({
      //基本常见,多语言网页,使用this.$i18n.locale="zh";可以修改对应的语言模式,其处理一般放在一个lang文件下
      //封装处理多个语言, 大小写均可,这就是messages对象里面的key
      locale: 'CN',
      // 首选语言缺少翻译时要使用的语言。如果某个语言环境没有设置变量,就会使用fallbackLocale环境下的对应变量
      fallbackLocale: 'CN',
      //抑制警告
      silentFallbackWarn: true,
      // 语言对照表
      messages: {
        US: {
          msg: {
            hello: 'english'
        CN: {
          msg: {
            hello: '简体'
        HK: {
          msg: {
            hello: '繁體'
        DD: {
          msg: {
            // 在模板里获取DD语言的hello时,会默认使用fallbackLocale环境下的值
      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'  
    new Vue({
      i18n,
    }).$mount('#app')
    
  • locale: 当前语种
  • fallbackLocale: 如果当前语种不存在时,默认设置当前语种
  • messages: 本地语言包('en','zh'...)
  • silentFallbackWarn: 抑制警告,
  • numberFormats: 设置 数字格式化
  • dateTimeFormats: 设置 时间日期格式化
  • 模板中使用:

    //App.vue组件中的使用举例了(由于挂载到了app上面,因此可以在任意组件中使用该地区信息,即:messages)
    //使用形式如下:
    <div>{{ $t("msg.hello") }}</div><!--你好-->
    

    在上面的例子中,如果组件没有语言环境信息,它将回退到全局定义的本地化信息。组件使用根实例中设置的语言 (在上面的例子中:locale: 'CN')。

    注意,在默认情况下,回退到根语言环境会在控制台中生成两个警告:

    [vue-i18n] Value of key 'msg.hellp' is not a string!
    [vue-i18n] Fall back to translate the keypath 'msg.hellp' with root locale.
    

    为避免以上警告 (同时保留那些完全没有翻译给定关键字的警告) 需初始化 VueI18n 实例时设置 silentFallbackWarn: true

    如果你希望在组件语言环境中进行本地化,可以在 i18n 选项中用 sync: falselocale

    包括获取某个模块的语言包;区域语言包合并到全局语言包;

    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作用一样,都是获取语言包中的某条数据,但也有很大的区别

    //locale='en'
    const messages = {
      en: {
        message: {
          GG: hello'
       message: {
          GG: '哈哈{name}'
    //组件中使用1 字符串用法
     <p v-t="'message.GG'"></p>
     hello
     //组件中使用2 对象用法
    <p v-t="{ path: 'message.GG', locale: 'zh', args: { name: 'lsq' } }"></p>
     哈哈lsq
    

    v-t指令总结:
    字符串形式,只能简单的获取当前语种下的非动态文本数据 ,而对象用法支持设置语种,动态文本数据

    v-t指令和$t方法的区别
    $t 是扩展的Vue实例方法。它有以下优点和缺点:

    v-t是一个自定义指令。它有以下优点和缺点:

    v-t不能灵活使用$t,因为它相当复杂。已翻译的内容v-t将插入到 textContent 元素中。

    语言环境变更

    通常,使用 Vue 根实例作为起点,使用 VueI18n 类的 locale 属性作为参考来本地化所有子组件。

    有时你可能希望动态更改语言环境。在这种情况下,你可以更改 VueI18n 实例的 locale 属性的值。

    const i18n = new VueI18n({
      locale: 'CN', // 设置语言环境
    // 创建 Vue 根实例
    new Vue({
      i18n,
    }).$mount('#app')
    // 更改为其它的 locale
    i18n.locale = 'EN'
    

    在模板中修改locale的值

    // 更改为其它的 locale
    this.$i18n.locale = 'EN'
    

    每个组件都包含一个引用为 $i18n 属性的 VueI18n 实例,该实例也可用于更改语言环境。

    对于使用了 sync: false 的组件,语言环境的更改将被忽略。
    在组件内更改 $i18n.locale 不会更新根语言环境。 如果您依靠根语言环境,例如在使用 root fallbacks 时,请使用 $root.$i18n.locale 而不是$i18n.locale

    语言环境信息如下:

    const messages = {
      CN: {
        message: {
          hello: '{msg}简体{name}'  //没看错这里就是字符串,不用`` ,es6的模板编译这样写
    

    模板如下:

    <p>{{ $t("msg.hello", { name: '较瘦', msg: 999 } ) }}</p>
    

    输出如下:

    <p>999简体较瘦</p>
    

    语言环境信息如下:

    const messages = {
      en: {
        message: {
          hello: '{0} world'
    

    模板如下:

    <p>{{ $t('message.hello', ['hello']) }}</p>
    

    输出如下:

    <p>hello world</p>
    

    列表格式也接受类似数组的对象:

    <p>{{ $t('message.hello', {'0': 'hello'}) }}</p>
    

    输出如下:

    <p>hello world</p>
    
  • HTML 格式化
  • 在你的网站上动态插入任意 HTML 可能非常危险,因为它很容易导致 XSS 攻击。仅对可信内容使用 HTML 插值,而不对用户提供的内容使用。我们建议使用组件插值 功能。

    在某些情况下,你可能希望将翻译呈现为 HTML 信息而不是静态字符串。

    const messages = {
      en: {
        message: {
          hello: 'hello <br> world'
    

    模板如下:

    <p v-html="$t('message.hello')"></p>
    

    输出如下 (取代预先格式化的信息)

    <p>hello
    <!--<br> 存在,但呈现为 html 而不是字符串-->
    world</p>
    

    下面就是官方文档翻译了,可以移步官方查看
    下面就是官方文档翻译了,可以移步官方查看
    下面就是官方文档翻译了,可以移步官方查看

    你可以使用复数进行翻译。你必须定义具有管道 | 分隔符的语言环境,并在管道分隔符中定义复数。

    您的模板将需要使用 $tc() 而不是 $t()

    语言环境信息如下:

    const messages = {
      en: {
        car: 'car | cars',
        apple: 'no apples | one apple | {count} apples'
    

    模板如下:

    <p>{{ $tc('car', 1) }}</p>
    <p>{{ $tc('car', 2) }}</p>
    <p>{{ $tc('apple', 0) }}</p>
    <p>{{ $tc('apple', 1) }}</p>
    <p>{{ $tc('apple', 10, { count: 10 }) }}</p>
    

    输出如下:

    <p>car</p>
    <p>cars</p>
    <p>no apples</p>
    <p>one apple</p>
    <p>10 apples</p>
    
  • 通过预定义的参数访问该数字
    你无需明确指定复数的数字。可以通过预定义的命名参数 {count} 和/或 {n} 在语言环境信息中访问该数字。如有必要,你可以覆盖这些预定义的命名参数。
  • 语言环境信息如下:

    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>
    

    $tc总结:
    1、在定义复数时,必要使用|管道符分隔。
    2、当|管道符等于1个时,索引从1开始,最大索引为2;当管道符大于1个时,索引从0开始(类似数组),最大索引为管道符的个数
    3、通过使用$tc("复数",index)获取对应语言文本

    语言环境信息的语法

  • Linked locale messages
  • 如果有一个翻译关键字总是与另一个具有相同的具体文本,你可以链接到它。要链接到另一个翻译关键字,你所要做的就是在其内容前加上一个 @: 符号后跟完整的翻译键名,包括你要链接到的命名空间。

    语言环境信息如下:

    const messages = {
      en: {
        message: {
          the_world: 'the world',
          dio: 'DIO:',
          linked: '@:message.dio @:message.the_world !!!!'
    

    模板如下:

    <p>{{ $t('message.linked') }}</p>
    

    输出如下:

    <p>DIO: the world !!!!</p>
    
  • 格式化链接的语言环境消息
    如果语言区分字符大小写,则可能需要控制链接的语言环境消息的大小写。 链接的消息可以用修饰符 @.modifier:key 格式化。
  • 以下修饰符当前可用。

  • upper: 链接消息中的所有字符均大写
  • lower: 小写链接消息中的所有字符
  • capitalize: 大写链接消息中的第一个字符
  • 语言环境消息如下:

    const messages = {
      en: {
        message: {
          homeAddress: 'Home address',
          missingHomeAddress: 'Please provide @.lower:message.homeAddress'
    <label>{{ $t('message.homeAddress') }}</label>
    <p class="error">{{ $t('message.missingHomeAddress') }}</p>
    

    输出以下内容:

    <label>Home address</label>
    <p class="error">Please provide home address</p>
    

    您可以添加修饰符或覆盖将 modifiers 选项传递给 VueI18n 构造函数的现有修饰符。

    const i18n = new VueI18n({
      locale: 'en',
      modifiers: {
        snakeCase: (str) => str.split(' ').join('-')
      messages: {
        // ...
    
  • 按括号分组
    链接到的语言环境信息的键名也可以形如 @:(message.foo.bar.baz),其中链接到另一段翻译的键名在括号 () 里。
  • 如果链接 @:message.something 后紧跟着一个点 .,则此选项非常有用,因为它本不该成为但却成为了链接的一部分。

    语言环境信息如下:

    const messages = {
      en: {
        message: {
          dio: 'DIO',
          linked: 'There\'s a reason, you lost, @:(message.dio).'
    

    模板如下:

    <p>{{ $t('message.linked') }}</p>
    

    输出如下:

    <p>There's a reason, you lost, DIO.</p>
    vue-i18n 建议在翻译消息时使用基于列表的字符串或命名格式作为语言环境消息。
    

    但是,在某些情况下,由于复杂的语言语法,您确实需要JavaScript的全部编程功能。 因此,您可以使用 message function 来代替基于字符串的消息。

    以下是一个返回简单问候语的消息函数:

    const messages = {
      en: {
        greeting: (ctx) => 'hello!'
    

    使用消息功能非常容易! 您只需使用 $tt 指定消息功能的键:

    <p>{{ $t('greeting') }}</p>
    

    输出如下:

    <p>hello!</p>
    

    消息功能输出消息,该消息具有消息功能的返回值。

    vue-i18n 支持命名格式 作为基于字符串的消息格式。 vue-i18n用$tt插值参数值,并可以将其输出。

    使用 消息上下文 的消息功能可以完成以下操作:

    这是问候的示例:

    const messages = {
      en: {
        greeting: (ctx) => `hello, ${ctx.named('name')}!`
    
    <p>{{ $t('greeting', { name: 'DIO' }) }}</p>
    

    输出如下:

    <p>hello, DIO!</p>
    

    消息上下文具有命名函数。 您需要指定键来解析以 $tt 命名的值。

    列表格式的使用类似于上述命名格式。

    vue-i18n 支持 列表格式 作为基于字符串的消息格式。 vue-i18n用$ t或t插值参数值,并可以将其输出。

    您可以通过使用消息上下文对消息函数执行相同的操作:

    这是问候的示例:

    const messages = {
      en: {
        greeting: (ctx) => `hello, ${ctx.list(0)}!`
    
    <p>{{ $t('greeting', ['DIO']) }}</p>
    

    输出如下:

    <p>hello, DIO!</p>
    

    消息上下文具有列表功能。 您需要指定索引来解析由 $tt 列表指定的值。

    数字格式化

    numberFormats是对象类型,是来设置数字格式化包括货币类型等.

    const messages = {
      en: {
        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')方法,三个参数:

  • 用户传入数字 必传
  • 调用的格式化方案 必传
  • 使用的语种,默认是当前this.$i18n.locale
  • 日期格式化

    dateTimeFormats: 除了对于数字有格式化方案,对于日期时间也是有格式化方案的

    const messages = {
        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> Aug 31, 2018 Fri, Aug 31, 2018, 3:46 PM 2018年8月31日 2018年8月31日周五 下午3:46

    其实这个就和处理数字格式化大同小异了,记住就好。

    最后发现,整理本地化语言包是个力气活啊,复制十个就胳膊疼了。。。

    <template>
        <m-tip>
          {{$t('title')}}
          <m-tips-icon :label="$t('label1')"/>
          <m-tips-icon :label="$t('label2')" icon="bulb" />
        </m-tip>
        <p v-t="'p1'"></p>
        <m-btn-add @click="test" />
        <p v-t="'p2'"></p>
        <m-btn-save />
        <p v-t="'p3'"></p>
        <m-btn-edit />
        <p v-t="'p4'"></p>
        <m-btn-del />
        <p v-t="'p5'"></p>
        <m-btn-search />
        <a-divider></a-divider>
        <p v-t="'p6'"></p>
        <m-btn-print />
        <p v-t="'p7'"></p>
        <m-btn-zip />
        <p v-t="'p8'"></p>
        <m-btn-img />
        <p v-t="'p9'"></p>
        <m-btn-excel />
        <p v-t="'p10'"></p>
        <m-btn-download />
        <a-divider></a-divider>
        <m-btn v-t="'p11'"></m-btn>
        <m-split />
        <m-btn icon="aliyun" v-t="'p12'"></m-btn>
        <m-split />
        <m-btn icon="aliyun" type="danger" v-t="'p13'"></m-btn>
        <m-split />
        <m-btn icon="aliyun" size="large" v-t="'p14'"></m-btn>
        <m-split />
        <m-btn loading v-t="'p14'"></m-btn>
    </template>
    <script>
    export default {
      i18n: require('./i18n'),
      methods: {
        test() {
          this.$msgSucc(this.$t('p15'));
    </script>
    
    //i18n.js
    module.exports = {
      messages: {
        CN: {
          title: '项目中每个页面的按钮通常都是要求风格统一的,封装起来可以有效减少重复代码和开发时间',
          label1: '可以自己进源码修改你要的颜色和图标',
          label2: '换了图标',
          p1: '新增记录',
          p2: '保存',
          p3: '编辑',
          p4: '删除',
          p5: '查询',
          p6: '打印',
          p7: '导出zip',
          p8: '生成图片',
          p9: '导出Excel',
          p10: '下载',
          p11: '依然可以换文本',
          p12: '换图标',
          p13: '换颜色',
          p14: '换大小',
          p15: '点击按钮了',
        HK: {
          title: '項目中每個頁面的按鈕通常都是要求風格統一的,封裝起來可以有效减少重複程式碼和開發時間',
          label1: '可以自己進源碼修改你要的顏色和圖標',
          label2: '換了圖標',
          p1: '新增記錄',
          p2: '保存',
          p3: '編輯',
          p4: '删除',
          p5: '査詢',
          p6: '打印',
          p7: '匯出zip',
          p8: '生成圖片',
          p9: '匯出Excel',
          p10: '下載',
          p11: '依然可以換文字',
          p12: '換圖標',
          p13: '換顏色',
          p14: '換大小',
          p15: '點擊按鈕了',
        US: {
          title: 'The buttons on each page in the project usually require a unified style. Encapsulation can effectively reduce repeated code and development time',
          label1: 'You can enter the source code and modify the colors and icons you want',
          label2: 'Changed the icon',
          p1: 'adding record',
          p2: 'preservation',
          p3: 'edit',
          p4: 'delete',
          p5: 'query',
          p6: 'print',
          p7: 'Export zip',
          p8: 'Generate picture',
          p9: 'Export Excel',
          p10: 'Download',
          p11: 'You can still change text',
          p12: 'Change Icon',
          p13: 'Change color',
          p14: 'Change size',
          p15: 'Click the button',