Vue 自定义插件内使用 vue-i18n 实现国际化

15天前

为了将一些业务提取出来,减少项目复杂程度,因此使用自定义插件的方式来实现。

自定义插件

<!-- plugin.vue -->
<template>
  <div>
   {{ $t('plugin') }}
  </div>
</template>
<!-- index.js -->
import Vue from 'vue'
import Plugin from './plugin.vue'

const PluginConstructor = Vue.extend(Plugin)

const plugin = function () {
  if (Vue.prototype.$isServer) return

  const instance = new PluginConstructor()
  instance.$mount()
  document.body.appendChild(instance.$el)

  return instance
}

const install = (Vue) => {
  Vue.prototype.$plugin = plugin
}

export default {
  install
}
<!-- main.js -->
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import Plugin from './index.js'

const i18n = new VueI18n({
  locale: 'en',
  messages: {}
})

Vue.use(Plugin)

new Vue({
  i18n,
  render: h => h(App)
}).$mount('#root')

但是在其他地方调用 this.$plugin() 时报错:

Vue-i18n "TypeError: Cannot read property '_t' of undefined"

在翻阅了官方的文档之后也没有关于这个问题的解答,查看源码之后发现出现问题的代码在:

if (!Vue.prototype.hasOwnProperty('$i18n')) {
  // $FlowFixMe
  Object.defineProperty(Vue.prototype, '$i18n', {
    get: function get () { return this._i18n }
  });
}

var i18n = this.$i18n;
return i18n._t.apply(i18n, [ key, i18n.locale, i18n._getMessages(), this ].concat( values ))

也就是 Vue.prototype.$i18n 未定义,但是直接重定义 $i18n 不可行,只能重定义 Vue.prototype._i18n

解决方案

<!-- index.js -->
import Vue from 'vue'
import Plugin from './plugin.vue'

let _i18n = null

export function RewriteLocale (i18n) {
  _i18n = i18n
}

const PluginConstructor = Vue.extend(Plugin)

const plugin = function () {
  if (Vue.prototype.$isServer) return

  const instance = new PluginConstructor()
  instance.$mount()
  document.body.appendChild(instance.$el)

  return instance
}

const install = (Vue) => {
  Vue.prototype._i18n = _i18n
  Vue.prototype.$plugin = plugin
}

export default {
  install
}
<!-- main.js -->
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import Plugin, { RewriteLocale } from './index.js'

const i18n = new VueI18n({
  locale: 'en',
  messages: {}
})

RewriteLocale(i18n)
Vue.use(Plugin)

new Vue({
  i18n,
  render: h => h(App)
}).$mount('#root')

评论(0)