Skip to content

Commit 7608dda

Browse files
committed
fix & improvements
1 parent 382b97f commit 7608dda

File tree

6 files changed

+86
-85
lines changed

6 files changed

+86
-85
lines changed

src/app/src/i18n.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import { createI18n, type LocaleMessages, type VueMessageType } from 'vue-i18n'
22

3-
const defaultLocale = navigator.language.split('-')[0] || 'en'
4-
53
type StudioMessages = Record<string, LocaleMessages<VueMessageType>>
64

7-
export function createStudioI18n(messages: Record<string, unknown>) {
5+
export function createStudioI18n(locale: string, messages: Record<string, unknown>) {
86
return createI18n({
97
legacy: false,
10-
locale: defaultLocale,
8+
locale,
119
fallbackLocale: 'en',
1210
messages: messages as StudioMessages,
1311
globalInjection: true, // to be able to use $t() in templates

src/app/src/main.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
import type { VueElementConstructor } from 'vue'
22
import { defineCustomElement } from 'vue'
33
import { createRouter, createMemoryHistory } from 'vue-router'
4-
54
// @ts-expect-error -- inline css
65
import styles from './assets/css/main.css?inline'
7-
86
import { createHead } from '@unhead/vue/client'
97
import { generateColors, tailwindColors } from './utils/colors'
108
import { refineTailwindStyles } from './utils/styles.ts'
11-
9+
import { createStudioI18n } from './i18n'
1210
import App from './app.vue'
1311
import Content from './pages/content.vue'
1412
import Media from './pages/media.vue'
1513
import Review from './pages/review.vue'
1614
import Success from './pages/success.vue'
1715
import Error from './pages/error.vue'
18-
import { createStudioI18n } from './i18n'
1916

2017
if (typeof window !== 'undefined' && 'customElements' in window) {
2118
const NuxtStudio = defineCustomElement(
@@ -56,13 +53,12 @@ if (typeof window !== 'undefined' && 'customElements' in window) {
5653
})
5754

5855
app.use(router)
59-
// Read messages from window (set by our new Nuxt plugin)
60-
// @ts-expect-error - We are defining this global variable
61-
const messages = window.__NUXT_STUDIO_I18N_MESSAGES__ || {}
62-
// Create the i18n instance dynamically
63-
const i18n = createStudioI18n(messages)
64-
app.use(i18n) // Use the new instance
65-
// app._context.provides.usehead = true
56+
57+
// @ts-expect-error - Global variable defined in plugin
58+
const i18n = createStudioI18n(window.__NUXT_STUDIO_DEFAULT_LOCALE__, window.__NUXT_STUDIO_I18N_MESSAGES__)
59+
60+
app.use(i18n)
61+
6662
app.use({
6763
install() {
6864
const head = createHead({

src/module/src/i18n.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { addPlugin, addTemplate, createResolver } from '@nuxt/kit'
2+
import { resolve, basename, join } from 'node:path'
3+
import { promises as fsp } from 'node:fs'
4+
import { defu } from 'defu'
5+
import type { Nuxt } from '@nuxt/schema'
6+
7+
const resolver = createResolver(import.meta.url)
8+
9+
interface I18nOptions {
10+
defaultLocale?: string
11+
translations?: Record<string, unknown>
12+
}
13+
14+
async function loadLocaleFiles(localesPath: string): Promise<Record<string, unknown>> {
15+
const messages: Record<string, unknown> = {}
16+
17+
try {
18+
const files = await fsp.readdir(localesPath)
19+
const jsonFiles = files.filter(file => file.endsWith('.json'))
20+
21+
for (const file of jsonFiles) {
22+
const lang = basename(file, '.json')
23+
const filePath = join(localesPath, file)
24+
const content = await fsp.readFile(filePath, 'utf-8')
25+
messages[lang] = JSON.parse(content)
26+
}
27+
}
28+
catch {
29+
// Directory doesn't exist or can't be read
30+
}
31+
32+
return messages
33+
}
34+
35+
export async function setupI18n(
36+
nuxt: Nuxt,
37+
options: I18nOptions,
38+
) {
39+
// Load default locale files from the module
40+
const defaultLocalesPath = resolver.resolve('./locales')
41+
const defaultMessages = await loadLocaleFiles(defaultLocalesPath)
42+
43+
// Load user locale files from project
44+
const userLocalesPath = resolve(nuxt.options.srcDir, 'locales/studio')
45+
const userMessages = await loadLocaleFiles(userLocalesPath)
46+
47+
const optionsMessages = options.translations || {}
48+
// @ts-expect-error - nuxt.options.appConfig.studio is not fully typed
49+
const appConfigMessages = nuxt.options.appConfig.studio?.i18n?.translations || {}
50+
51+
const defaultLocale = options.defaultLocale || 'en'
52+
const finalMessages = defu(
53+
optionsMessages, // 1. Highest priority (nuxt.config options)
54+
appConfigMessages, // 2. Priority (app.config)
55+
userMessages, // 3. Priority (locales/studio user folder)
56+
defaultMessages, // 4. Default translations (module)
57+
)
58+
59+
addTemplate({
60+
filename: 'studio-i18n-plugin.client.mjs',
61+
getContents: () => {
62+
return `
63+
export default defineNuxtPlugin(() => {
64+
window.__NUXT_STUDIO_I18N_MESSAGES__ = ${JSON.stringify(finalMessages)}
65+
window.__NUXT_STUDIO_DEFAULT_LOCALE__ = '${defaultLocale}'
66+
})
67+
`
68+
},
69+
})
70+
71+
addPlugin(resolve(nuxt.options.buildDir, 'studio-i18n-plugin.client.mjs'))
72+
}
File renamed without changes.
File renamed without changes.

src/module/src/module.ts

Lines changed: 5 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
import { defineNuxtModule, createResolver, addPlugin, extendViteConfig, useLogger, addServerHandler, addTemplate, addVitePlugin } from '@nuxt/kit'
1+
import { defineNuxtModule, createResolver, addPlugin, extendViteConfig, useLogger, addServerHandler, addTemplate } from '@nuxt/kit'
22
import { createHash } from 'node:crypto'
33
import { defu } from 'defu'
4-
import { resolve, basename } from 'node:path'
5-
import { promises as fsp } from 'node:fs'
6-
import { globby } from 'globby'
4+
import { resolve } from 'node:path'
75
import fsDriver from 'unstorage/drivers/fs'
86
import { createStorage } from 'unstorage'
9-
import type { Plugin } from 'vite'
107
import { getAssetsStorageDevTemplate, getAssetsStorageTemplate } from './templates'
118
import { version } from '../../../package.json'
129
import { setupDevMode } from './dev'
10+
import { setupI18n } from './i18n'
1311

1412
interface ModuleOptions {
1513
/**
@@ -135,71 +133,6 @@ export default defineNuxtModule<ModuleOptions>({
135133
const resolver = createResolver(import.meta.url)
136134
const runtime = (...args: string[]) => resolver.resolve('./runtime', ...args)
137135

138-
const defaultLocalesPath = resolver.resolve('../../app/src/locales')
139-
const defaultLocaleFiles = await globby(`${defaultLocalesPath}/*.json`)
140-
const defaultMessages: Record<string, unknown> = {}
141-
for (const file of defaultLocaleFiles) {
142-
const lang = basename(file, '.json')
143-
defaultMessages[lang] = JSON.parse(await fsp.readFile(file, 'utf-8'))
144-
}
145-
146-
const userLocalesPath = resolve(nuxt.options.srcDir, 'locales/studio')
147-
const userLocaleFiles = await globby(`${userLocalesPath}/*.json`)
148-
const userMessages: Record<string, unknown> = {}
149-
for (const file of userLocaleFiles) {
150-
const lang = basename(file, '.json')
151-
userMessages[lang] = JSON.parse(await fsp.readFile(file, 'utf-8'))
152-
}
153-
154-
const optionsMessages = options.i18n?.translations || {}
155-
// @ts-expect-error - nuxt.options.appConfig.studio is not fully typed
156-
const appConfigMessages = nuxt.options.appConfig.studio?.i18n?.translations || {}
157-
158-
const finalMessages = defu(
159-
optionsMessages, // 1. Highest priority (nuxt.config options)
160-
appConfigMessages, // 2. Priority (app.config)
161-
userMessages, // 3. Priority (locales/studio folder)
162-
defaultMessages, // 4. Default translations (module)
163-
)
164-
165-
// --- VITE PLUGIN ---
166-
const virtualModuleName = 'virtual:studio-i18n-messages'
167-
const resolvedVirtualModuleId = '\0' + virtualModuleName
168-
169-
addVitePlugin({
170-
name: 'nuxt-studio-i18n-virtual-module',
171-
resolveId(id) {
172-
if (id === virtualModuleName) {
173-
return resolvedVirtualModuleId
174-
}
175-
},
176-
load(id) {
177-
if (id === resolvedVirtualModuleId) {
178-
return `export default ${JSON.stringify(finalMessages)}`
179-
}
180-
},
181-
} as Plugin)
182-
183-
addTemplate({
184-
filename: 'studio-i18n-plugin.client.mjs',
185-
getContents: () => {
186-
const defaultLocale = options.i18n?.defaultLocale || 'en'
187-
188-
return `
189-
import messages from 'virtual:studio-i18n-messages'
190-
191-
export default defineNuxtPlugin(() => {
192-
// @ts-ignore
193-
window.__NUXT_STUDIO_I18N_MESSAGES__ = messages
194-
// @ts-ignore
195-
window.__NUXT_STUDIO_DEFAULT_LOCALE__ = '${defaultLocale}'
196-
})
197-
`
198-
},
199-
})
200-
201-
addPlugin(resolve(nuxt.options.buildDir, 'studio-i18n-plugin.client.mjs'))
202-
203136
if (nuxt.options.dev === false || options.development?.sync === false) {
204137
options.dev = false
205138
}
@@ -279,6 +212,8 @@ export default defineNuxtModule<ModuleOptions>({
279212
: getAssetsStorageTemplate(assetsStorage, nuxt),
280213
})
281214

215+
await setupI18n(nuxt, options.i18n!)
216+
282217
if (options.dev) {
283218
setupDevMode(nuxt, runtime, assetsStorage)
284219
}

0 commit comments

Comments
 (0)