8
8
shallowRef ,
9
9
isRef ,
10
10
ref ,
11
- computed
11
+ computed ,
12
+ effectScope
12
13
} from 'vue'
13
14
import {
14
15
inBrowser ,
@@ -47,7 +48,7 @@ import {
47
48
adjustI18nResources
48
49
} from './utils'
49
50
50
- import type { ComponentInternalInstance , App } from 'vue'
51
+ import type { ComponentInternalInstance , App , EffectScope } from 'vue'
51
52
import type {
52
53
Locale ,
53
54
Path ,
@@ -234,6 +235,10 @@ export interface I18n<
234
235
* @param options - An install options
235
236
*/
236
237
install ( app : App , ...options : unknown [ ] ) : void
238
+ /**
239
+ * Release global scope resource
240
+ */
241
+ dispose ( ) : void
237
242
}
238
243
239
244
/**
@@ -492,7 +497,11 @@ export function createI18n(options: any = {}, VueI18nLegacy?: any): any {
492
497
? ! ! options . allowComposition
493
498
: true
494
499
const __instances = new Map < ComponentInternalInstance , VueI18n | Composer > ( )
495
- const __global = createGlobal ( options , __legacyMode , VueI18nLegacy )
500
+ const [ globalScope , __global ] = createGlobal (
501
+ options ,
502
+ __legacyMode ,
503
+ VueI18nLegacy
504
+ )
496
505
const symbol : InjectionKey < I18n > | string = /* #__PURE__*/ makeSymbol (
497
506
__DEV__ ? 'vue-i18n' : ''
498
507
)
@@ -559,6 +568,13 @@ export function createI18n(options: any = {}, VueI18nLegacy?: any): any {
559
568
)
560
569
}
561
570
571
+ // release global scope
572
+ const unmountApp = app . unmount
573
+ app . unmount = ( ) => {
574
+ i18n . dispose ( )
575
+ unmountApp ( )
576
+ }
577
+
562
578
// setup vue-devtools plugin
563
579
if ( ( __DEV__ || __FEATURE_PROD_VUE_DEVTOOLS__ ) && ! __NODE_JS__ ) {
564
580
const ret = await enableDevTools ( app , i18n as _I18n )
@@ -584,6 +600,9 @@ export function createI18n(options: any = {}, VueI18nLegacy?: any): any {
584
600
get global ( ) {
585
601
return __global
586
602
} ,
603
+ dispose ( ) : void {
604
+ globalScope . stop ( )
605
+ } ,
587
606
// @internal
588
607
__instances,
589
608
// @internal
@@ -598,6 +617,7 @@ export function createI18n(options: any = {}, VueI18nLegacy?: any): any {
598
617
// extend legacy VueI18n instance
599
618
600
619
const i18n = ( __global as any ) [ LegacyInstanceSymbol ] // eslint-disable-line @typescript-eslint/no-explicit-any
620
+ let _localeWatcher : Function | null = null
601
621
Object . defineProperty ( i18n , 'global' , {
602
622
get ( ) {
603
623
return __global
@@ -631,11 +651,21 @@ export function createI18n(options: any = {}, VueI18nLegacy?: any): any {
631
651
__FEATURE_FULL_INSTALL__ && applyBridge ( Vue , ...options )
632
652
633
653
if ( ! __legacyMode && __globalInjection ) {
634
- injectGlobalFieldsForBridge ( Vue , i18n , __global as Composer )
654
+ _localeWatcher = injectGlobalFieldsForBridge (
655
+ Vue ,
656
+ i18n ,
657
+ __global as Composer
658
+ )
635
659
}
636
660
Vue . mixin ( defineMixinBridge ( i18n , _legacyVueI18n ) )
637
661
}
638
662
} )
663
+ Object . defineProperty ( i18n , 'dispose' , {
664
+ value : ( ) : void => {
665
+ _localeWatcher && _localeWatcher ( )
666
+ globalScope . stop ( )
667
+ }
668
+ } )
639
669
const methodMap = {
640
670
__getInstance,
641
671
__setInstance,
@@ -861,16 +891,26 @@ function createGlobal(
861
891
options : I18nOptions ,
862
892
legacyMode : boolean ,
863
893
VueI18nLegacy : any // eslint-disable-line @typescript-eslint/no-explicit-any
864
- ) : VueI18n | Composer {
894
+ ) : [ EffectScope , VueI18n | Composer ] {
895
+ const scope = effectScope ( )
865
896
if ( ! __BRIDGE__ ) {
866
- return ! __LITE__ && __FEATURE_LEGACY_API__ && legacyMode
867
- ? createVueI18n ( options , VueI18nLegacy )
868
- : createComposer ( options , VueI18nLegacy )
897
+ const obj =
898
+ ! __LITE__ && __FEATURE_LEGACY_API__ && legacyMode
899
+ ? scope . run ( ( ) => createVueI18n ( options , VueI18nLegacy ) )
900
+ : scope . run ( ( ) => createComposer ( options , VueI18nLegacy ) )
901
+ if ( obj == null ) {
902
+ throw createI18nError ( I18nErrorCodes . UNEXPECTED_ERROR )
903
+ }
904
+ return [ scope , obj ]
869
905
} else {
870
906
if ( ! isLegacyVueI18n ( VueI18nLegacy ) ) {
871
907
throw createI18nError ( I18nErrorCodes . NOT_COMPATIBLE_LEGACY_VUE_I18N )
872
908
}
873
- return createComposer ( options , VueI18nLegacy )
909
+ const obj = scope . run ( ( ) => createComposer ( options , VueI18nLegacy ) )
910
+ if ( obj == null ) {
911
+ throw createI18nError ( I18nErrorCodes . UNEXPECTED_ERROR )
912
+ }
913
+ return [ scope , obj ]
874
914
}
875
915
}
876
916
@@ -1578,11 +1618,11 @@ function injectGlobalFieldsForBridge(
1578
1618
Vue : any , // eslint-disable-line @typescript-eslint/no-explicit-any
1579
1619
i18n : any , // eslint-disable-line @typescript-eslint/no-explicit-any
1580
1620
composer : Composer
1581
- ) : void {
1621
+ ) : Function {
1582
1622
// The composition mode in vue-i18n-bridge is `$18n` is the VueI18n instance.
1583
1623
// so we need to tell composer to change the locale.
1584
1624
// If we don't do, things like `$t` that are injected will not be reacted.
1585
- i18n . watchLocale ( composer )
1625
+ const watcher = i18n . watchLocale ( composer ) as Function
1586
1626
1587
1627
// define fowardcompatible vue-i18n-next inject fields with `globalInjection`
1588
1628
Vue . prototype . $t = function ( ...args : unknown [ ] ) {
@@ -1596,4 +1636,6 @@ function injectGlobalFieldsForBridge(
1596
1636
Vue . prototype . $n = function ( ...args : unknown [ ] ) {
1597
1637
return Reflect . apply ( composer . n , composer , [ ...args ] )
1598
1638
}
1639
+
1640
+ return watcher
1599
1641
}
0 commit comments