Skip to content

Commit f55c356

Browse files
committed
feat: support Vue3 vapor mode
1 parent 72f63b7 commit f55c356

File tree

9 files changed

+317
-195
lines changed

9 files changed

+317
-195
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@
162162
"pnpm": {
163163
"overrides": {
164164
"vite": "^6.0.0",
165-
"vue": "3.5.22"
165+
"vue": "3.6.0-alpha.2"
166166
},
167167
"onlyBuiltDependencies": [
168168
"@parcel/watcher",

packages/vue-i18n-core/src/composer.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import {
3737
isString,
3838
warn
3939
} from '@intlify/shared'
40-
import { computed, getCurrentInstance, ref, shallowRef, watch } from 'vue'
40+
import { computed, ref, shallowRef, watch } from 'vue'
4141
import { I18nErrorCodes, createI18nError } from './errors'
4242
import { VERSION } from './misc'
4343
import {
@@ -49,7 +49,13 @@ import {
4949
SetPluralRulesSymbol,
5050
TranslateVNodeSymbol
5151
} from './symbols'
52-
import { createTextNode, getComponentOptions, getLocaleMessages, handleFlatJson } from './utils'
52+
import {
53+
createTextNode,
54+
getComponentOptions,
55+
getCurrentInstance,
56+
getLocaleMessages,
57+
handleFlatJson
58+
} from './utils'
5359
import { I18nWarnCodes, getWarnMessage } from './warnings'
5460

5561
import type {
@@ -104,6 +110,7 @@ import type { VueDevToolsEmitter } from '@intlify/devtools-types'
104110
import type {
105111
ComponentInternalInstance,
106112
ComputedRef,
113+
GenericComponentInstance,
107114
VNode,
108115
VNodeArrayChildren,
109116
WritableComputedRef
@@ -221,7 +228,7 @@ export type DefaultNumberFormatSchema<
221228
export type MissingHandler = (
222229
locale: Locale,
223230
key: Path,
224-
instance?: ComponentInternalInstance,
231+
instance?: ComponentInternalInstance | GenericComponentInstance,
225232
type?: string
226233
) => string | void
227234

packages/vue-i18n-core/src/devtools.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import type {
1616
Hooks,
1717
InspectedComponentData
1818
} from '@vue/devtools-api'
19-
import type { App, ComponentInternalInstance } from 'vue'
19+
import type { App, ComponentInternalInstance, GenericComponentInstance } from 'vue'
2020
import type { Composer } from './composer'
2121
import type { I18n, I18nInternal } from './i18n'
2222

@@ -83,7 +83,7 @@ export async function enableDevTools(app: App, i18n: _I18n): Promise<boolean> {
8383
}
8484
})
8585

86-
const roots = new Map<App, ComponentInternalInstance>()
86+
const roots = new Map<App, ComponentInternalInstance | GenericComponentInstance>()
8787
api.on.getInspectorState(async payload => {
8888
if (payload.app === app && payload.inspectorId === 'vue-i18n-resource-inspector') {
8989
api.unhighlightElement()
@@ -263,12 +263,16 @@ function registerScope(payload: HookPayloads[Hooks.GET_INSPECTOR_TREE], i18n: _I
263263
}
264264
}
265265

266-
function getComponentInstance(nodeId: string, i18n: _I18n): ComponentInternalInstance | null {
266+
function getComponentInstance(
267+
nodeId: string,
268+
i18n: _I18n
269+
): ComponentInternalInstance | GenericComponentInstance | null {
267270
let instance: ComponentInternalInstance | null = null
268271

269272
if (nodeId !== 'global') {
270273
for (const [component, composer] of i18n.__instances.entries()) {
271274
if (composer.id.toString() === nodeId) {
275+
// @ts-expect-error -- TODO(kazupon): need to fix types
272276
instance = component
273277
break
274278
}

packages/vue-i18n-core/src/i18n.ts

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,24 @@ import {
77
makeSymbol,
88
warn
99
} from '@intlify/shared'
10-
import { effectScope, getCurrentInstance, inject, isRef, onMounted, onUnmounted } from 'vue'
10+
import { effectScope, inject, isRef, onMounted, onUnmounted } from 'vue'
1111
import { createComposer } from './composer'
1212
import { addTimelineEvent, enableDevTools } from './devtools'
1313
import { I18nErrorCodes, createI18nError } from './errors'
1414
import { apply as applyPlugin } from './plugin/next'
1515
import { DisableEmitter, DisposeSymbol, EnableEmitter } from './symbols'
16-
import { adjustI18nResources, getComponentOptions } from './utils'
16+
import { adjustI18nResources, getComponentOptions, getCurrentInstance } from './utils'
1717
import { I18nWarnCodes, getWarnMessage } from './warnings'
1818

1919
import type { FallbackLocale, Locale, LocaleParams, SchemaParams } from '@intlify/core-base'
2020
import type { VueDevToolsEmitter, VueDevToolsEmitterEvents } from '@intlify/devtools-types'
21-
import type { App, ComponentInternalInstance, EffectScope, InjectionKey } from 'vue'
21+
import type {
22+
App,
23+
ComponentInternalInstance,
24+
EffectScope,
25+
GenericComponentInstance,
26+
InjectionKey
27+
} from 'vue'
2228
import type {
2329
Composer,
2430
ComposerInternalOptions,
@@ -136,17 +142,17 @@ export interface I18nInternal<
136142
OptionLocale = Locale
137143
> {
138144
__instances: Map<
139-
ComponentInternalInstance,
145+
ComponentInternalInstance | GenericComponentInstance,
140146
Composer<Messages, DateTimeFormats, NumberFormats, OptionLocale>
141147
>
142148
__getInstance<Instance extends Composer<Messages, DateTimeFormats, NumberFormats, OptionLocale>>(
143-
component: ComponentInternalInstance
149+
component: ComponentInternalInstance | GenericComponentInstance
144150
): Instance | null
145151
__setInstance<Instance extends Composer<Messages, DateTimeFormats, NumberFormats, OptionLocale>>(
146-
component: ComponentInternalInstance,
152+
component: ComponentInternalInstance | GenericComponentInstance,
147153
instance: Instance
148154
): void
149-
__deleteInstance(component: ComponentInternalInstance): void
155+
__deleteInstance(component: ComponentInternalInstance | GenericComponentInstance): void
150156
__composerExtend?: ComposerExtender
151157
}
152158

@@ -488,6 +494,7 @@ export function useI18n<
488494
throw createI18nError(I18nErrorCodes.MUST_BE_CALL_SETUP_TOP)
489495
}
490496
if (
497+
// @ts-expect-error -- TODO(kazupon): need to fix types
491498
!instance.isCE &&
492499
instance.appContext.app != null &&
493500
!instance.appContext.app.__VUE_I18N_SYMBOL__
@@ -556,13 +563,15 @@ function createGlobal(options: I18nOptions): [EffectScope, Composer] {
556563
return [scope, obj]
557564
}
558565

559-
function getI18nInstance(instance: ComponentInternalInstance): I18n {
566+
function getI18nInstance(instance: ComponentInternalInstance | GenericComponentInstance): I18n {
560567
const i18n = inject(
568+
// @ts-expect-error -- TODO(kazupon): need to fix types
561569
!instance.isCE ? instance.appContext.app.__VUE_I18N_SYMBOL__! : I18nInjectionKey
562570
)
563571
/* istanbul ignore if */
564572
if (!i18n) {
565573
throw createI18nError(
574+
// @ts-expect-error -- TODO(kazupon): need to fix types
566575
!instance.isCE ? I18nErrorCodes.UNEXPECTED_ERROR : I18nErrorCodes.NOT_INSTALLED_WITH_PROVIDE
567576
)
568577
}
@@ -588,12 +597,13 @@ function getGlobalComposer(i18n: I18n): Composer {
588597

589598
function getComposer(
590599
i18n: I18n,
591-
target: ComponentInternalInstance,
600+
target: ComponentInternalInstance | GenericComponentInstance,
592601
useComponent = false
593602
): Composer | null {
594603
let composer: Composer | null = null
595604
const root = target.root
596-
let current: ComponentInternalInstance | null = getParentComponentInstance(target, useComponent)
605+
let current: ComponentInternalInstance | GenericComponentInstance | null =
606+
getParentComponentInstance(target, useComponent)
597607
while (current != null) {
598608
const i18nInternal = i18n as unknown as I18nInternal
599609
composer = i18nInternal.__getInstance(current)
@@ -610,7 +620,7 @@ function getComposer(
610620
}
611621

612622
function getParentComponentInstance(
613-
target: ComponentInternalInstance | null,
623+
target: ComponentInternalInstance | GenericComponentInstance | null,
614624
useComponent = false
615625
) {
616626
if (target == null) {
@@ -622,15 +632,17 @@ function getParentComponentInstance(
622632

623633
function setupLifeCycle(
624634
i18n: I18nInternal,
625-
target: ComponentInternalInstance,
635+
target: ComponentInternalInstance | GenericComponentInstance,
626636
composer: Composer
627637
): void {
628638
let emitter: VueDevToolsEmitter | null = null
629639

630640
// eslint-disable-next-line vue-composable/lifecycle-placement -- NOTE(kazupon): not Vue component
631641
onMounted(() => {
632642
// inject composer instance to DOM for intlify-devtools
643+
// @ts-expect-error -- TODO(kazupon): need to fix types
633644
if ((__DEV__ || __FEATURE_PROD_VUE_DEVTOOLS__) && !__NODE_JS__ && target.vnode.el) {
645+
// @ts-expect-error -- TODO(kazupon): need to fix types
634646
target.vnode.el.__VUE_I18N__ = composer
635647
emitter = createEmitter<VueDevToolsEmitterEvents>()
636648
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -649,11 +661,14 @@ function setupLifeCycle(
649661
if (
650662
(__DEV__ || __FEATURE_PROD_VUE_DEVTOOLS__) &&
651663
!__NODE_JS__ &&
664+
// @ts-expect-error -- TODO(kazupon): need to fix types
652665
target.vnode.el &&
666+
// @ts-expect-error -- TODO(kazupon): need to fix types
653667
target.vnode.el.__VUE_I18N__
654668
) {
655669
emitter && emitter.off('*', addTimelineEvent)
656670
_composer[DisableEmitter] && _composer[DisableEmitter]()
671+
// @ts-expect-error -- TODO(kazupon): need to fix types
657672
delete target.vnode.el.__VUE_I18N__
658673
}
659674
i18n.__deleteInstance(target)

packages/vue-i18n-core/src/utils.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,17 @@ import {
1010
isString,
1111
warn
1212
} from '@intlify/shared'
13+
import * as Vue from 'vue'
1314
import { Text, createVNode } from 'vue'
1415
import { I18nWarnCodes, getWarnMessage } from './warnings'
1516

1617
import type { Locale, MessageResolver } from '@intlify/core-base'
17-
import type { ComponentInternalInstance, RendererElement, RendererNode } from 'vue'
18+
import type {
19+
ComponentInternalInstance,
20+
GenericComponentInstance,
21+
RendererElement,
22+
RendererNode
23+
} from 'vue'
1824
import type { Composer, ComposerOptions, CustomBlocks, VueMessageType } from './composer'
1925

2026
type GetLocaleMessagesOptions<Messages = {}> = {
@@ -154,7 +160,9 @@ export function getLocaleMessages<Messages = {}>(
154160
return ret as { [K in keyof Messages]: Messages[K] }
155161
}
156162

157-
export function getComponentOptions(instance: ComponentInternalInstance): any {
163+
export function getComponentOptions(
164+
instance: ComponentInternalInstance | GenericComponentInstance
165+
): any {
158166
return instance.type
159167
}
160168

@@ -205,3 +213,8 @@ export function adjustI18nResources(
205213
export function createTextNode(key: string): any {
206214
return createVNode(Text, null, key, 0)
207215
}
216+
217+
export function getCurrentInstance(): GenericComponentInstance | ComponentInternalInstance | null {
218+
// @ts-ignore -- NOTE(kazupon): for Vue 3.6
219+
return Vue.currentInstance || Vue.getCurrentInstance()
220+
}

packages/vue-i18n-core/test/i18n.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ import {
2323
setDevToolsHook
2424
} from '@intlify/core-base'
2525
import { createEmitter } from '@intlify/shared'
26-
import { defineComponent, defineCustomElement, getCurrentInstance, h, nextTick, ref } from 'vue'
26+
import { defineComponent, defineCustomElement, h, nextTick, ref } from 'vue'
2727
import { errorMessages, I18nErrorCodes } from '../src/errors'
2828
import { createI18n, useI18n } from '../src/i18n'
29+
import { getCurrentInstance } from '../src/utils'
2930
import { pluralRules as _pluralRules, mount, randStr } from './helper'
3031

3132
import type { IntlifyDevToolsEmitterHooks } from '@intlify/devtools-types'

packages/vue-i18n-core/test/issues.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ import {
2121
resolveValue,
2222
setDevToolsHook
2323
} from '@intlify/core-base'
24-
import { defineComponent, getCurrentInstance, nextTick, ref } from 'vue'
24+
import { defineComponent, nextTick, ref } from 'vue'
2525
import { createI18n, useI18n } from '../src/i18n'
26+
import { getCurrentInstance } from '../src/utils'
2627
import { ast } from './fixtures/ast'
2728
import { mount } from './helper'
2829

packages/vue-i18n-core/test/wc.test.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22
* @vitest-environment jsdom
33
*/
44

5-
import { h, provide, nextTick, defineCustomElement, getCurrentInstance } from 'vue'
65
import {
76
compile,
7+
fallbackWithLocaleChain,
8+
registerLocaleFallbacker,
89
registerMessageCompiler,
9-
resolveValue,
1010
registerMessageResolver,
11-
fallbackWithLocaleChain,
12-
registerLocaleFallbacker
11+
resolveValue
1312
} from '@intlify/core-base'
14-
import { createI18n, useI18n, I18nInjectionKey } from '../src/index'
13+
import { defineCustomElement, h, nextTick, provide } from 'vue'
14+
import { createI18n, I18nInjectionKey, useI18n } from '../src/index'
15+
import { getCurrentInstance } from '../src/utils'
1516
import { randStr } from './helper'
1617

17-
import type { VueElement, ComponentOptions } from 'vue'
18+
import type { ComponentOptions, VueElement } from 'vue'
1819

1920
const container = document.createElement('div')
2021
document.body.appendChild(container)

0 commit comments

Comments
 (0)