Reporting a bug?
Under Vite 8 (non-Rolldown), @intlify/unplugin-vue-i18n's configResolved patch of vite:json does not apply correctly. Locale JSON files are compiled by unplugin-vue-i18n's own transform to var resource = { ... }; export { resource as default }; and are then handed back to Vite's built-in vite:json plugin, which calls JSON.parse on the JS output and throws:
Failed loading locale (en): Unexpected token 'c', "const reso"... is not valid JSON
Affected versions: @intlify/unplugin-vue-i18n v11.0.7 (latest latest dist-tag at the time of this report). Does not reproduce under Vite 7.x.
Suspected source: https://github.com/intlify/bundle-tools/blob/v11.0.7/packages/unplugin-vue-i18n/src/core/resource.ts#L182-L193
In configResolved, the plugin does:
const isRolldownVite = !!(await getViteModule()).rolldownVersion
if (!isRolldownVite) {
const jsonPlugin = getVitePlugin(config, 'vite:json')
// ... patches vite:json to skip i18n locale files
}
Under Vite 8, vite:json's transform is now an ObjectHook ({ handler, filter, ... }) rather than a plain function. The current patch overwrites jsonPlugin.transform with a plain function, and on Vite 8 the ObjectHook's handler is still what gets invoked, so the patch is effectively a no-op — locale JSON files flow through vite:json, which tries to JSON.parse the already-compiled JS output from unplugin-vue-i18n's enforce: 'pre' transform.
This bug has also been reported downstream at nuxt-modules/i18n#3953, where maintainer @BobbieGoede requested a minimal upstream repro (comment). Independent reporters on the downstream issue include @floki1250 and @benlavalley, the latter confirming that the patch posted by @ysya (which preserves the ObjectHook shape) fixes it on a 77k-line locale bundle. I have also applied the same patch as a workaround on a Nuxt 4 production app (~2k lines × 23 locales) and it resolves the warning cleanly.
Expected behavior
Under Vite 8, locale JSON files matched by include should be compiled by @intlify/unplugin-vue-i18n and returned as valid i18n message objects, the same as under Vite 7. vite:json should not re-process unplugin-vue-i18n's output.
Reproduction
StackBlitz: https://stackblitz.com/~/github.com/mendrinos/mtkankzl
Steps:
- Open the StackBlitz link (no sign-in required to view).
- Wait for the WebContainer to run
npm install && npm run dev.
- Observe the dev-server terminal — the
Failed to load messages for locale "en": Unexpected token 'c', "const reso"... warning fires on the first SSR request.
Stack trace (from the StackBlitz terminal, identical to what a real-world Nuxt 4 app emits on Vite 8):
WARN Failed to load messages for locale "en" Failed loading locale (en): Unexpected token 'c', "const reso"... is not valid JSON
at getLocaleMessages (node_modules/@nuxtjs/i18n/dist/runtime/shared/messages.js:36:11)
at async Object.callAsync (node_modules/unctx/dist/index.mjs:91:16)
at async getLocaleMessagesMergedCached (node_modules/@nuxtjs/i18n/dist/runtime/shared/messages.js:52:20)
at async loadMessagesFromClient (node_modules/@nuxtjs/i18n/dist/runtime/context.js:68:19)
at async Object.loadMessages (node_modules/@nuxtjs/i18n/dist/runtime/context.js:139:50)
at async loadAndSetLocale (node_modules/@nuxtjs/i18n/dist/runtime/utils.js:148:3)
The repro is intentionally minimal: one Nuxt module (@nuxtjs/i18n), one dumb index.vue calling t('common.save'), and two synthetic locale JSON files (~50 KB each). No other Nuxt modules, no middleware, no plugins, no custom server routes. Bisected down from a real production Nuxt 4 app.
Issue Package
unplugin-vue-i18n
System Info
System:
OS: macOS 26.4.1
CPU: (10) arm64 Apple M1 Pro
Shell: 5.9 - /bin/zsh
Binaries:
Node: 23.11.0
npm: 11.4.2
bun: 1.3.12
Browsers:
Chrome: 147.0.7727.101
Firefox: 149.0
Safari: 26.4
npmPackages:
@nuxtjs/i18n: 10.2.4
@intlify/unplugin-vue-i18n: 11.0.7 (transitive, via @nuxtjs/i18n)
nuxt: 4.4.2
vite: 8.0.8
vue: 3.5.32
vue-i18n: 11.3.2
StackBlitz reproduction runs the same versions inside a WebContainer (Node 22.22.0 + npm, no Bun) and reproduces the bug identically.
Additional context
Confirmed workaround (credit @ysya, from the downstream thread) — a pre Vite plugin that wraps vite:json's transform.handler to skip i18n/locales/*.json, leaving unplugin-vue-i18n's own transform to produce the final JS module. Adding this to nuxt.config.ts resolves the warning on a large production app:
// nuxt.config.ts — workaround until bundle-tools ships a fix
{
name: 'i18n-json-vite8-fix',
enforce: 'pre',
configResolved(config) {
const jsonPlugin = config.plugins.find(p => p.name === 'vite:json')
if (!jsonPlugin?.transform) return
const transform = jsonPlugin.transform
const original = typeof transform === 'function' ? transform : transform.handler
if (typeof original !== 'function') return
const patched = function (this: unknown, code: string, id: string, ...args: unknown[]) {
if (/i18n\/locales\/.*\.json$/.test(id)) return
return (original as (...a: unknown[]) => unknown).call(this, code, id, ...args)
}
if (typeof transform === 'function') jsonPlugin.transform = patched as typeof jsonPlugin.transform
else transform.handler = patched as typeof transform.handler
},
}
Validations
Reporting a bug?
Under Vite 8 (non-Rolldown),
@intlify/unplugin-vue-i18n'sconfigResolvedpatch ofvite:jsondoes not apply correctly. Locale JSON files are compiled by unplugin-vue-i18n's own transform tovar resource = { ... }; export { resource as default };and are then handed back to Vite's built-invite:jsonplugin, which callsJSON.parseon the JS output and throws:Affected versions:
@intlify/unplugin-vue-i18nv11.0.7 (latestlatestdist-tag at the time of this report). Does not reproduce under Vite 7.x.Suspected source: https://github.com/intlify/bundle-tools/blob/v11.0.7/packages/unplugin-vue-i18n/src/core/resource.ts#L182-L193
In
configResolved, the plugin does:Under Vite 8,
vite:json'stransformis now anObjectHook({ handler, filter, ... }) rather than a plain function. The current patch overwritesjsonPlugin.transformwith a plain function, and on Vite 8 the ObjectHook'shandleris still what gets invoked, so the patch is effectively a no-op — locale JSON files flow throughvite:json, which tries toJSON.parsethe already-compiled JS output from unplugin-vue-i18n'senforce: 'pre'transform.This bug has also been reported downstream at nuxt-modules/i18n#3953, where maintainer @BobbieGoede requested a minimal upstream repro (comment). Independent reporters on the downstream issue include @floki1250 and @benlavalley, the latter confirming that the patch posted by @ysya (which preserves the ObjectHook shape) fixes it on a 77k-line locale bundle. I have also applied the same patch as a workaround on a Nuxt 4 production app (~2k lines × 23 locales) and it resolves the warning cleanly.
Expected behavior
Under Vite 8, locale JSON files matched by
includeshould be compiled by@intlify/unplugin-vue-i18nand returned as valid i18n message objects, the same as under Vite 7.vite:jsonshould not re-process unplugin-vue-i18n's output.Reproduction
StackBlitz: https://stackblitz.com/~/github.com/mendrinos/mtkankzl
Steps:
npm install && npm run dev.Failed to load messages for locale "en": Unexpected token 'c', "const reso"...warning fires on the first SSR request.Stack trace (from the StackBlitz terminal, identical to what a real-world Nuxt 4 app emits on Vite 8):
The repro is intentionally minimal: one Nuxt module (
@nuxtjs/i18n), one dumbindex.vuecallingt('common.save'), and two synthetic locale JSON files (~50 KB each). No other Nuxt modules, no middleware, no plugins, no custom server routes. Bisected down from a real production Nuxt 4 app.Issue Package
unplugin-vue-i18n
System Info
System: OS: macOS 26.4.1 CPU: (10) arm64 Apple M1 Pro Shell: 5.9 - /bin/zsh Binaries: Node: 23.11.0 npm: 11.4.2 bun: 1.3.12 Browsers: Chrome: 147.0.7727.101 Firefox: 149.0 Safari: 26.4 npmPackages: @nuxtjs/i18n: 10.2.4 @intlify/unplugin-vue-i18n: 11.0.7 (transitive, via @nuxtjs/i18n) nuxt: 4.4.2 vite: 8.0.8 vue: 3.5.32 vue-i18n: 11.3.2StackBlitz reproduction runs the same versions inside a WebContainer (Node 22.22.0 + npm, no Bun) and reproduces the bug identically.
Additional context
Confirmed workaround (credit @ysya, from the downstream thread) — a
preVite plugin that wrapsvite:json'stransform.handlerto skipi18n/locales/*.json, leaving unplugin-vue-i18n's own transform to produce the final JS module. Adding this tonuxt.config.tsresolves the warning on a large production app:Validations