1+ import { mkdtempSync , rmSync , writeFileSync } from 'node:fs'
2+ import { tmpdir } from 'node:os'
3+ import { join } from 'node:path'
14import { afterEach , describe , expect , it , vi } from 'vitest'
25import { withI18nMicro , warnLocaleMismatch , type VitePressUserConfigLike } from '../src/with-i18n-micro'
36import { messagesFromGlob } from '../src/messages-from-glob'
@@ -84,6 +87,73 @@ describe('withI18nMicro', () => {
8487 expect ( String ( warn . mock . calls [ 0 ] ?. [ 0 ] ) ) . toContain ( '"de"' )
8588 expect ( String ( warn . mock . calls [ 0 ] ?. [ 0 ] ) ) . not . toContain ( '"root"' )
8689 } )
90+
91+ it ( 'loads root from disk when only routeMessages are inline' , ( ) => {
92+ const dir = mkdtempSync ( join ( tmpdir ( ) , 'i18n-vp-inline-' ) )
93+ try {
94+ writeFileSync ( join ( dir , 'en.json' ) , JSON . stringify ( { fromDisk : true } ) )
95+ const result = withI18nMicro (
96+ { } as VitePressUserConfigLike ,
97+ {
98+ locale : 'en' ,
99+ locales : [ { code : 'en' } ] ,
100+ translationDir : dir ,
101+ routeMessages : { home : { en : { page : 'inline' } } } ,
102+ warnOnLocaleMismatch : false ,
103+ } ,
104+ )
105+ const plugins = ( result . vite ?. plugins ?? [ ] ) as Array < {
106+ name : string
107+ configResolved ?: ( c : { root : string } ) => void
108+ load ?: ( id : string ) => string | undefined
109+ resolveId ?: ( id : string ) => string | undefined
110+ configureServer ?: ( server : unknown ) => void
111+ } >
112+ const plugin = plugins . find ( ( p ) => p . name === 'vite-plugin-i18n-micro-vitepress' ) !
113+ plugin . configResolved ?.( { root : dir } )
114+ const id = plugin . resolveId ! ( 'virtual:i18n-micro/messages' ) !
115+ const src = plugin . load ! ( id ) !
116+ expect ( src ) . toContain ( '"fromDisk":true' )
117+ expect ( src ) . toContain ( '"page":"inline"' )
118+ plugin . configureServer ?.( {
119+ watcher : { add : vi . fn ( ) , on : vi . fn ( ) } ,
120+ moduleGraph : { getModuleById : ( ) => undefined } ,
121+ ws : { send : vi . fn ( ) } ,
122+ } )
123+ }
124+ finally {
125+ rmSync ( dir , { recursive : true , force : true } )
126+ }
127+ } )
128+
129+ it ( 'skips disk watchers when messages and routeMessages are both inline' , ( ) => {
130+ const result = withI18nMicro (
131+ { } as VitePressUserConfigLike ,
132+ {
133+ locale : 'en' ,
134+ locales : [ { code : 'en' } ] ,
135+ messages : { en : { a : '1' } } ,
136+ routeMessages : { home : { en : { b : '2' } } } ,
137+ warnOnLocaleMismatch : false ,
138+ } ,
139+ )
140+ const plugins = ( result . vite ?. plugins ?? [ ] ) as Array < {
141+ name : string
142+ configResolved ?: ( c : { root : string } ) => void
143+ configureServer ?: ( server : { watcher : { add : ReturnType < typeof vi . fn > } } ) => void
144+ load ?: ( id : string ) => string | undefined
145+ resolveId ?: ( id : string ) => string | undefined
146+ } >
147+ const plugin = plugins . find ( ( p ) => p . name === 'vite-plugin-i18n-micro-vitepress' ) !
148+ plugin . configResolved ?.( { root : process . cwd ( ) } )
149+ const add = vi . fn ( )
150+ plugin . configureServer ?.( { watcher : { add } } )
151+ expect ( add ) . not . toHaveBeenCalled ( )
152+ const id = plugin . resolveId ! ( 'virtual:i18n-micro/messages' ) !
153+ const src = plugin . load ! ( id ) !
154+ expect ( src ) . toContain ( '"a":"1"' )
155+ expect ( src ) . toContain ( '"b":"2"' )
156+ } )
87157} )
88158
89159describe ( 'messagesFromGlob' , ( ) => {
@@ -96,6 +166,20 @@ describe('messagesFromGlob', () => {
96166 expect ( messages . fr ) . toEqual ( { default : 'Defaut' , hello : 'Bonjour' } )
97167 } )
98168
169+ it ( 'keeps a one-key dictionary whose default value is a string' , ( ) => {
170+ const messages = messagesFromGlob ( {
171+ '/x/en.json' : { default : 'Default' } ,
172+ } )
173+ expect ( messages . en ) . toEqual ( { default : 'Default' } )
174+ } )
175+
176+ it ( 'keeps an __esModule-only object as a dictionary' , ( ) => {
177+ const messages = messagesFromGlob ( {
178+ '/x/en.json' : { __esModule : true } as unknown as { default : never } ,
179+ } )
180+ expect ( messages . en ) . toEqual ( { __esModule : true } )
181+ } )
182+
99183 it ( 'unwraps Vite module namespaces' , ( ) => {
100184 const messages = messagesFromGlob ( {
101185 '/x/de.json' : { default : { hello : 'Hallo' } } ,
@@ -195,4 +279,35 @@ describe('createVitePressI18n', () => {
195279 expect ( userHook ) . toHaveBeenCalled ( )
196280 expect ( i18n . getLocale ( ) ) . toBe ( 'fr' )
197281 } )
282+
283+ it ( 'installs the plugin on every Vue app' , ( ) => {
284+ const { enhanceApp } = createVitePressI18n ( {
285+ locale : 'en' ,
286+ defaultLocale : 'en' ,
287+ locales : [ { code : 'en' } , { code : 'fr' } ] ,
288+ messages : { en : { hi : 'Hi' } , fr : { hi : 'Salut' } } ,
289+ syncWithVitePress : false ,
290+ } )
291+
292+ const makeApp = ( ) => ( {
293+ use : vi . fn ( ) ,
294+ provide : vi . fn ( ) ,
295+ config : { globalProperties : { } as Record < string , unknown > } ,
296+ component : vi . fn ( ) ,
297+ } )
298+
299+ const makeRouter = ( path : string ) => ( {
300+ route : { path } ,
301+ go : vi . fn ( ) ,
302+ onAfterRouteChange : undefined as ( ( to : string ) => unknown ) | undefined ,
303+ } )
304+
305+ const app1 = makeApp ( )
306+ const app2 = makeApp ( )
307+ enhanceApp ( { app : app1 as never , router : makeRouter ( '/' ) as never } )
308+ enhanceApp ( { app : app2 as never , router : makeRouter ( '/fr/' ) as never } )
309+
310+ expect ( app1 . use ) . toHaveBeenCalledTimes ( 1 )
311+ expect ( app2 . use ) . toHaveBeenCalledTimes ( 1 )
312+ } )
198313} )
0 commit comments