vue-i18n 多语言插件源码分析

332 阅读2分钟

基础学习资料

官网: What is Vue I18n? | Vue I18n

github: vue-i18n

版本:11.0.0

vue i18n是一个vue的国际化插件,使用它很容易集成一些本地化的功能到我们的vue应用中。

基础使用

import { createAPP } from "vue";
import { createI18n } from "vue-i18n";
const i18n = createI18n({
  locale: 'ja',
  messages: {
    en: {
      message: {
        hello: 'hello world'
      }
    },
    ja: {
      message: {
        hello: 'こんにちは、世界'
      }
    }
  }
})

const app = createApp({
  // something vue options here...
})

app.use(i18n);
app.mount('#app')

前置知识

vue插件

vue中一些扩展性功能(添加全局组件,指令,混入等)使用插件来进行扩展,app.use就是用来按照插件的,插件可以是一个带有install的函数的对象,或者就是一个函数,并且在调用时会接受Vue作为参数;如以下代码中

const app = createApp({
  // something vue options here...
})
// i18n是一个插件,app.use来调用该插件
app.use(i18n);

自定义指令

自定义指令主要是用来重用涉及元素底层DOM访问逻辑;

原理分析

createI18n 创建一个i18n实例

const i18n = createI18n({
  locale: 'ja',
  messages: {
    en: {
      message: {
        hello: 'hello world'
      }
    },
    ja: {
      message: {
        hello: 'こんにちは、世界'
      }
    }
  }
})

createI18n的实现,在vue-i18n-core中,其最后返回一个带有install方法的对象i18n;

install中做了什么事情

  • 创建composer对象
createGlobal => createComposer(options)
  • 全局注册组件;
    ;[Translation.name, 'I18nT'].forEach(name =>
      app.component(name, Translation)
    )
    ;[NumberFormat.name, 'I18nN'].forEach(name =>
      app.component(name, NumberFormat)
    )
    ;[DatetimeFormat.name, 'I18nD'].forEach(name =>
      app.component(name, DatetimeFormat)
    )
  • 全局注册自定义指令
    app.directive('t', vTDirective(i18n))
  • minix 扩展了beforCreate, mounted, unmounted这几个钩子;

$t() 实现是怎么样实现的

创建了createComposer中,定义了$t()方法的实现,并挂载到了global上,所以可以在模版中使用;

// 将$i18n, $t等方法挂载到了global上面,
if (!__legacyMode && __globalInjection) {
        globalReleaseHandler = injectGlobalFields(app, i18n.global as Composer)
}

  const globalExportMethods = !__LITE__
  ? ['t', 'rt', 'd', 'n', 'tm', 'te']
  : ['t']
  // 全局挂载$i18n
  app.config.globalProperties.$i18n = i18n

  // 挂载各个方法;
  globalExportMethods.forEach(method => {
    const desc = Object.getOwnPropertyDescriptor(composer, method)
    if (!desc || !desc.value) {
      throw createI18nError(I18nErrorCodes.UNEXPECTED_ERROR)
    }
    Object.defineProperty(app.config.globalProperties, `$${method}`, desc)
  })

如何做到不刷新页面,切换语言的时候,自动更新;

  • 利用composition API ref, 对locale和message做依赖收集,所以当该两个属性变更的时候,自动更新

  • ref主要是在get该属性的时候做依赖手机,在set修改属性的时候,统一做数据更新