Skip to content

Commit

Permalink
fix: exntending for Composer and VueI18n (#1237)
Browse files Browse the repository at this point in the history
* fix: exntending for Composer and VueI18n

* fix: lint warnings
  • Loading branch information
kazupon authored Nov 20, 2022
1 parent 702783a commit 125c94b
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 2 deletions.
22 changes: 22 additions & 0 deletions packages/vue-i18n-core/src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,14 @@ export interface I18n<
dispose(): void
}

/**
* @internal
*/
type ExtendHooks = {
__composerExtend?: (composer: Composer) => void
__vueI18nExtend?: (vueI18n: VueI18n) => void
}

/**
* I18n interface for internal usage
*
Expand Down Expand Up @@ -272,6 +280,8 @@ export interface I18nInternal<
instance: Instance
): void
__deleteInstance(component: ComponentInternalInstance): void
__composerExtend?: Required<ExtendHooks>['__composerExtend']
__vueI18nExtend?: Required<ExtendHooks>['__vueI18nExtend']
}

/**
Expand Down Expand Up @@ -541,6 +551,15 @@ export function createI18n(options: any = {}, VueI18nLegacy?: any): any {
app.__VUE_I18N_SYMBOL__ = symbol
app.provide(app.__VUE_I18N_SYMBOL__, i18n as unknown as I18n)

// set composer & vuei18n extend hook options from plugin options
if (isPlainObject(options[0])) {
const opts = options[0] as ExtendHooks
;(i18n as unknown as I18nInternal).__composerExtend =
opts.__composerExtend
;(i18n as unknown as I18nInternal).__vueI18nExtend =
opts.__vueI18nExtend
}

// global method and properties injection for Composition API
if (!__legacyMode && __globalInjection) {
injectGlobalFields(app, i18n.global as Composer)
Expand Down Expand Up @@ -838,6 +857,9 @@ export function useI18n<
}

composer = createComposer(composerOptions, _legacyVueI18n) as Composer
if (i18nInternal.__composerExtend) {
i18nInternal.__composerExtend(composer)
}
setupLifeCycle(i18nInternal, instance, composer)

i18nInternal.__setInstance(instance, composer)
Expand Down
5 changes: 5 additions & 0 deletions packages/vue-i18n-core/src/mixins/next.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ export function defineMixin(
this.$i18n.n(...args)
this.$tm = (key: Path): LocaleMessageValue<VueMessageType> | {} =>
this.$i18n.tm(key)

// extend vue-i18n legacy APIs
if (i18n.__vueI18nExtend) {
i18n.__vueI18nExtend(this.$i18n)
}
},

mounted(): void {
Expand Down
21 changes: 19 additions & 2 deletions packages/vue-i18n-core/test/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@ import {
import { compile } from '@vue/compiler-dom'
import * as runtimeDom from 'vue'
import { I18n } from '../src/i18n'
import { isBoolean, assign } from '@intlify/shared'
import { isBoolean, isPlainObject, assign } from '@intlify/shared'

import type { I18nPluginOptions } from '../src/plugin/types'

export interface MountOptions {
propsData: Record<string, any> // eslint-disable-line @typescript-eslint/no-explicit-any
provide: Record<string | symbol, any> // eslint-disable-line @typescript-eslint/no-explicit-any
components: ComponentOptions['components']
slots: Record<string, string>
installI18n: boolean
pluginOptions?: I18nPluginOptions
}

interface Wrapper {
Expand Down Expand Up @@ -85,6 +88,20 @@ export function mount(
const installI18n = isBoolean(options.installI18n)
? options.installI18n
: true

const pluginOptions: I18nPluginOptions = isPlainObject(options.pluginOptions)
? options.pluginOptions
: {
globalInstall: true,
useI18nComponentName: false
}
if (pluginOptions.globalInstall == null) {
pluginOptions.globalInstall = true
}
if (pluginOptions.useI18nComponentName == null) {
pluginOptions.useI18nComponentName = false
}

return new Promise((resolve, reject) => {
// NOTE: only supports props as an object
const propsData = reactive(
Expand Down Expand Up @@ -156,7 +173,7 @@ export function mount(
}
}

installI18n && app.use(i18n)
installI18n && app.use(i18n, pluginOptions)

const rootEl = document.createElement('div')
document.body.appendChild(rootEl)
Expand Down
57 changes: 57 additions & 0 deletions packages/vue-i18n-core/test/i18n.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import {
h,
ref,
defineComponent,
defineCustomElement,
nextTick,
Expand Down Expand Up @@ -32,6 +33,7 @@ import {
} from '@intlify/devtools-if'

import type { I18n } from '../src/i18n'
import type { VueI18n } from '../src/legacy'
import type { App } from 'vue'

const container = document.createElement('div')
Expand Down Expand Up @@ -1360,3 +1362,58 @@ describe('release global scope', () => {
expect(error).not.toEqual(errorMessages[I18nErrorCodes.UNEXPECTED_ERROR])
})
})

describe('Composer & VueI18n extend hooking', () => {
test('composition', async () => {
const composerExtendSpy = jest
.fn()
.mockImplementation((composer: Composer) => {
;(composer as any).foo = ref('hello world')
})
const vueI18nExtendSpy = jest.fn()
const i18n = createI18n({
legacy: false
})

const App = defineComponent({
setup() {
// @ts-ignore
const { foo } = useI18n({
useScope: 'local'
})
return { foo }
},
template: '<p>{{ foo }}</p>'
})
const { html } = await mount(App, i18n, {
pluginOptions: {
__composerExtend: composerExtendSpy,
__vueI18nExtend: vueI18nExtendSpy
} as any
})
expect(composerExtendSpy).toHaveBeenCalled()
expect(html()).toBe('<p>hello world</p>')
expect(vueI18nExtendSpy).not.toHaveBeenCalled()
})

test('legacy', async () => {
const composerExtendSpy = jest.fn()
const vueI18nExtendSpy = jest
.fn()
.mockImplementation((vueI18n: VueI18n) => {
;(vueI18n as any).foo = 'hello world'
})
const i18n = createI18n({ legacy: true })

const App = defineComponent({ template: '<p>{{ $i18n.foo }}</p>' })
const { html } = await mount(App, i18n, {
pluginOptions: {
__composerExtend: composerExtendSpy,
__vueI18nExtend: vueI18nExtendSpy
} as any
})
expect(composerExtendSpy).not.toHaveBeenCalled()
expect(vueI18nExtendSpy).toHaveBeenCalled()
expect(html()).toBe('<p>hello world</p>')
})
})

0 comments on commit 125c94b

Please sign in to comment.