diff --git a/specs/fixtures/issues/2094/app.vue b/specs/fixtures/issues/2094/app.vue new file mode 100644 index 000000000..2b1be0907 --- /dev/null +++ b/specs/fixtures/issues/2094/app.vue @@ -0,0 +1,5 @@ + diff --git a/specs/fixtures/issues/2094/i18n.config.ts b/specs/fixtures/issues/2094/i18n.config.ts new file mode 100644 index 000000000..b40ff88ed --- /dev/null +++ b/specs/fixtures/issues/2094/i18n.config.ts @@ -0,0 +1,13 @@ +const config = defineI18nConfig(() => { + return { + legacy: false, + locale: 'ja', + messages: { + ja: { + big: 'こんにちは,'.repeat(10) + } + } + } +}) + +export default config diff --git a/specs/fixtures/issues/2094/nuxt.config.ts b/specs/fixtures/issues/2094/nuxt.config.ts new file mode 100644 index 000000000..b11432890 --- /dev/null +++ b/specs/fixtures/issues/2094/nuxt.config.ts @@ -0,0 +1,15 @@ +// https://nuxt.com/docs/api/configuration/nuxt-config +export default defineNuxtConfig({ + modules: ['@nuxtjs/i18n'], + + i18n: { + defaultLocale: 'ja', + locales: [ + { + code: 'ja', + iso: 'ja-JP', + name: 'Japanese' + } + ] + } +}) diff --git a/specs/fixtures/issues/2094/package.json b/specs/fixtures/issues/2094/package.json new file mode 100644 index 000000000..e98685246 --- /dev/null +++ b/specs/fixtures/issues/2094/package.json @@ -0,0 +1,15 @@ +{ + "name": "nuxt3-test-issues-2000", + "private": true, + "type": "module", + "scripts": { + "build": "nuxt build", + "dev": "nuxt dev", + "generate": "nuxt generate", + "start": "node .output/server/index.mjs" + }, + "devDependencies": { + "@nuxtjs/i18n": "latest", + "nuxt": "latest" + } +} diff --git a/specs/fixtures/issues/2094/pages/index.vue b/specs/fixtures/issues/2094/pages/index.vue new file mode 100644 index 000000000..f5f42e238 --- /dev/null +++ b/specs/fixtures/issues/2094/pages/index.vue @@ -0,0 +1,9 @@ + + + diff --git a/specs/issues/2094.spec.ts b/specs/issues/2094.spec.ts new file mode 100644 index 000000000..fa638867c --- /dev/null +++ b/specs/issues/2094.spec.ts @@ -0,0 +1,17 @@ +import { test, describe, expect } from 'vitest' +import { fileURLToPath } from 'node:url' +import { setup } from '../utils' +import { getText, renderPage } from '../helper' + +describe('#2094', async () => { + await setup({ + rootDir: fileURLToPath(new URL(`../fixtures/issues/2094`, import.meta.url)), + browser: true + }) + + test('vue-i18n messages are loaded from config exported as variable', async () => { + const { page } = await renderPage('/') + + expect(await getText(page, '#render')).toEqual('こんにちは,'.repeat(10)) + }) +}) diff --git a/src/utils.ts b/src/utils.ts index 808176ada..dac1ff194 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -12,7 +12,7 @@ import { NUXT_I18N_MODULE_ID, TS_EXTENSIONS, EXECUTABLE_EXTENSIONS, NULL_HASH } import type { NuxtI18nOptions, LocaleInfo, VueI18nConfigPathInfo, LocaleType, LocaleFile, LocaleObject } from './types' import type { Nuxt, NuxtConfigLayer } from '@nuxt/schema' -import type { File } from '@babel/types' +import type { File, Identifier } from '@babel/types' export function formatMessage(message: string) { return `[${NUXT_I18N_MODULE_ID}]: ${message}` @@ -150,27 +150,64 @@ function parseCode(code: string, path: string) { function scanProgram(program: File['program'] /*, calleeName: string*/) { let ret: false | 'object' | 'function' | 'arrow-function' = false + let variableDeclaration: Identifier | undefined + for (const node of program.body) { - if (node.type === 'ExportDefaultDeclaration') { - if (node.declaration.type === 'ObjectExpression') { - ret = 'object' + if (node.type !== 'ExportDefaultDeclaration') continue + + if (node.declaration.type === 'ObjectExpression') { + ret = 'object' + break + } + + if (node.declaration.type === 'Identifier') { + variableDeclaration = node.declaration + break + } + + if (node.declaration.type === 'CallExpression' && node.declaration.callee.type === 'Identifier') { + const [fnNode] = node.declaration.arguments + if (fnNode.type === 'FunctionExpression') { + ret = 'function' break - } else if ( - node.declaration.type === 'CallExpression' && - node.declaration.callee.type === 'Identifier' // && - // node.declaration.callee.name === calleeName - ) { - const [fnNode] = node.declaration.arguments - if (fnNode.type === 'FunctionExpression') { - ret = 'function' - break - } else if (fnNode.type === 'ArrowFunctionExpression') { - ret = 'arrow-function' + } + + if (fnNode.type === 'ArrowFunctionExpression') { + ret = 'arrow-function' + break + } + } + } + + if (variableDeclaration) { + for (const node of program.body) { + if (node.type !== 'VariableDeclaration') continue + for (const decl of node.declarations) { + if (decl.type !== 'VariableDeclarator') continue + if (decl.init == null) continue + if ('name' in decl.id === false || decl.id.name !== variableDeclaration!.name) continue + + if (decl.init.type === 'ObjectExpression') { + ret = 'object' break } + + if (decl.init.type === 'CallExpression' && decl.init.callee.type === 'Identifier') { + const [fnNode] = decl.init.arguments + if (fnNode.type === 'FunctionExpression') { + ret = 'function' + break + } + + if (fnNode.type === 'ArrowFunctionExpression') { + ret = 'arrow-function' + break + } + } } } } + return ret }