nuxt-i18n-micro 1.12.2 → 1.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{i as o,r as u,g as f,h as d,j as v,k as l,l as i,m as h,n as m}from"./DD0NUamG.js";function U(t,a={}){const e=a.head||o();if(e)return e.ssr?e.push(t,a):p(e,t,a)}function p(t,a,e={}){const s=u(!1),n=u({});f(()=>{n.value=s.value?{}:d(a)});const r=t.push(n.value,e);return v(n,c=>{r.patch(c)}),m()&&(l(()=>{r.dispose()}),i(()=>{s.value=!0}),h(()=>{s.value=!1})),r}export{U as u};
1
+ import{i as o,r as u,g as f,h as d,j as v,k as l,l as i,m as h,n as m}from"./D1fvHJQV.js";function U(t,a={}){const e=a.head||o();if(e)return e.ssr?e.push(t,a):p(e,t,a)}function p(t,a,e={}){const s=u(!1),n=u({});f(()=>{n.value=s.value?{}:d(a)});const r=t.push(n.value,e);return v(n,c=>{r.patch(c)}),m()&&(l(()=>{r.dispose()}),i(()=>{s.value=!0}),h(()=>{s.value=!1})),r}export{U as u};
@@ -1 +1 @@
1
- import{u as o}from"./IYJk2P0o.js";import{_ as a,o as s,c as i,a as e,t as r,p as u,f as l}from"./DD0NUamG.js";const c=t=>(u("data-v-b63e9691"),t=t(),l(),t),d={class:"font-sans antialiased bg-white dark:bg-black text-black dark:text-white grid min-h-screen place-content-center overflow-hidden"},p=c(()=>e("div",{class:"fixed -bottom-1/2 left-0 right-0 h-1/2 spotlight"},null,-1)),h={class:"max-w-520px text-center"},b=["textContent"],g=["textContent"],f={__name:"error-500",props:{appName:{type:String,default:"Nuxt"},version:{type:String,default:""},statusCode:{type:Number,default:500},statusMessage:{type:String,default:"Server error"},description:{type:String,default:"This page is temporarily unavailable."}},setup(t){const n=t;return o({title:`${n.statusCode} - ${n.statusMessage} | ${n.appName}`,script:[],style:[{children:'*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:var(--un-default-border-color, #e5e7eb)}:before,:after{--un-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}h1{font-size:inherit;font-weight:inherit}h1,p{margin:0}*,:before,:after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }'}]}),(m,x)=>(s(),i("div",d,[p,e("div",h,[e("h1",{class:"text-8xl sm:text-10xl font-medium mb-8",textContent:r(t.statusCode)},null,8,b),e("p",{class:"text-xl px-8 sm:px-0 sm:text-4xl font-light mb-16 leading-tight",textContent:r(t.description)},null,8,g)])]))}},w=a(f,[["__scopeId","data-v-b63e9691"]]);export{w as default};
1
+ import{u as o}from"./DxMn4SAe.js";import{_ as a,o as s,c as i,a as e,t as r,p as u,f as l}from"./D1fvHJQV.js";const c=t=>(u("data-v-b63e9691"),t=t(),l(),t),d={class:"font-sans antialiased bg-white dark:bg-black text-black dark:text-white grid min-h-screen place-content-center overflow-hidden"},p=c(()=>e("div",{class:"fixed -bottom-1/2 left-0 right-0 h-1/2 spotlight"},null,-1)),h={class:"max-w-520px text-center"},b=["textContent"],g=["textContent"],f={__name:"error-500",props:{appName:{type:String,default:"Nuxt"},version:{type:String,default:""},statusCode:{type:Number,default:500},statusMessage:{type:String,default:"Server error"},description:{type:String,default:"This page is temporarily unavailable."}},setup(t){const n=t;return o({title:`${n.statusCode} - ${n.statusMessage} | ${n.appName}`,script:[],style:[{children:'*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:var(--un-default-border-color, #e5e7eb)}:before,:after{--un-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}h1{font-size:inherit;font-weight:inherit}h1,p{margin:0}*,:before,:after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / .5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: }'}]}),(m,x)=>(s(),i("div",d,[p,e("div",h,[e("h1",{class:"text-8xl sm:text-10xl font-medium mb-8",textContent:r(t.statusCode)},null,8,b),e("p",{class:"text-xl px-8 sm:px-0 sm:text-4xl font-light mb-16 leading-tight",textContent:r(t.description)},null,8,g)])]))}},w=a(f,[["__scopeId","data-v-b63e9691"]]);export{w as default};
@@ -1 +1 @@
1
- {"id":"ebef9bab-73b3-451c-9eee-7e9b779ac677","timestamp":1725188700332}
1
+ {"id":"e3198b53-a0ca-4886-aad7-085d6bae4a55","timestamp":1725274464836}
@@ -0,0 +1 @@
1
+ {"id":"e3198b53-a0ca-4886-aad7-085d6bae4a55","timestamp":1725274464836,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}
@@ -1,12 +1,12 @@
1
1
  <!DOCTYPE html><html data-capo=""><head><meta charset="utf-8">
2
2
  <meta name="viewport" content="width=device-width, initial-scale=1">
3
3
  <link rel="stylesheet" href="/__nuxt-i18n-micro/_nuxt/entry.DjxsrOxm.css">
4
- <link rel="modulepreload" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/DD0NUamG.js">
4
+ <link rel="modulepreload" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/D1fvHJQV.js">
5
5
  <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/B6E6ObS_.js">
6
6
  <link rel="prefetch" as="style" href="/__nuxt-i18n-micro/_nuxt/error-404.D-AvUzLt.css">
7
- <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/BMM8J4-o.js">
8
- <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/IYJk2P0o.js">
7
+ <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/BpNRGTHy.js">
8
+ <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/DxMn4SAe.js">
9
9
  <link rel="prefetch" as="style" href="/__nuxt-i18n-micro/_nuxt/error-500.21ZDxC33.css">
10
- <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/RtVXrbos.js">
11
- <script type="module" src="/__nuxt-i18n-micro/_nuxt/DD0NUamG.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"serverRendered":1},false]</script>
12
- <script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-i18n-micro",buildId:"ebef9bab-73b3-451c-9eee-7e9b779ac677",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
10
+ <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/DzdJBprQ.js">
11
+ <script type="module" src="/__nuxt-i18n-micro/_nuxt/D1fvHJQV.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"serverRendered":1},false]</script>
12
+ <script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-i18n-micro",buildId:"e3198b53-a0ca-4886-aad7-085d6bae4a55",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
package/dist/module.d.mts CHANGED
@@ -23,11 +23,12 @@ interface ModuleOptions {
23
23
  }
24
24
  interface ModuleOptionsExtend extends ModuleOptions {
25
25
  rootDir: string;
26
- pluralString: string;
26
+ plural: string;
27
27
  rootDirs: string[];
28
28
  dateBuild: number;
29
29
  baseURL: string;
30
30
  }
31
+
31
32
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
32
33
 
33
34
  interface ModuleHooks {
@@ -51,4 +52,4 @@ declare module '@nuxt/schema' {
51
52
  }
52
53
  }
53
54
 
54
- export { type Locale, type ModuleHooks, type ModuleOptions, type ModuleOptionsExtend, _default as default };
55
+ export { type ModuleHooks, _default as default };
package/dist/module.d.ts CHANGED
@@ -23,11 +23,12 @@ interface ModuleOptions {
23
23
  }
24
24
  interface ModuleOptionsExtend extends ModuleOptions {
25
25
  rootDir: string;
26
- pluralString: string;
26
+ plural: string;
27
27
  rootDirs: string[];
28
28
  dateBuild: number;
29
29
  baseURL: string;
30
30
  }
31
+
31
32
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
32
33
 
33
34
  interface ModuleHooks {
@@ -51,4 +52,4 @@ declare module '@nuxt/schema' {
51
52
  }
52
53
  }
53
54
 
54
- export { type Locale, type ModuleHooks, type ModuleOptions, type ModuleOptionsExtend, _default as default };
55
+ export { type ModuleHooks, _default as default };
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-i18n-micro",
3
3
  "configKey": "i18n",
4
- "version": "1.12.2",
4
+ "version": "1.12.3",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "0.8.3",
7
7
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import path from 'node:path';
2
+ import { useNuxt, defineNuxtModule, createResolver, addPlugin, addImportsDir, addServerHandler, addComponentsDir, extendPages } from '@nuxt/kit';
3
+ import { watch } from 'chokidar';
2
4
  import * as fs from 'node:fs';
3
5
  import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
4
- import { useNuxt, defineNuxtModule, createResolver, addPlugin, addImportsDir, addServerHandler, addComponentsDir, extendPages, addPrerenderRoutes } from '@nuxt/kit';
5
- import { watch } from 'chokidar';
6
6
  import { onDevToolsInitialized, extendServerRpc } from '@nuxt/devtools-kit';
7
7
 
8
8
  const DEVTOOLS_UI_PORT = 3030;
@@ -88,6 +88,248 @@ function setupDevToolsUI(options, resolve) {
88
88
  });
89
89
  }
90
90
 
91
+ function extractDefineI18nRouteConfig(content, filePath) {
92
+ const match = content.match(/^[ \t]*\$defineI18nRoute\((\{[\s\S]*?\})\)/m);
93
+ if (match && match[1]) {
94
+ try {
95
+ const parsedObject = Function('"use strict";return (' + match[1] + ")")();
96
+ if (validateDefineI18nRouteConfig(parsedObject)) {
97
+ return parsedObject;
98
+ } else {
99
+ console.error("Invalid defineI18nRoute configuration format:", parsedObject, "in file: ", filePath);
100
+ }
101
+ } catch (error) {
102
+ console.error("Failed to parse defineI18nRoute configuration:", error, "in file: ", filePath);
103
+ }
104
+ }
105
+ return null;
106
+ }
107
+ function validateDefineI18nRouteConfig(obj) {
108
+ if (typeof obj !== "object" || obj === null)
109
+ return false;
110
+ if (obj.locales) {
111
+ if (typeof obj.locales !== "object")
112
+ return false;
113
+ for (const localeKey in obj.locales) {
114
+ const translations = obj.locales[localeKey];
115
+ if (typeof translations !== "object" || translations === null)
116
+ return false;
117
+ }
118
+ }
119
+ if (obj.localeRoutes) {
120
+ if (typeof obj.localeRoutes !== "object")
121
+ return false;
122
+ for (const routeKey in obj.localeRoutes) {
123
+ if (typeof obj.localeRoutes[routeKey] !== "string")
124
+ return false;
125
+ }
126
+ }
127
+ return true;
128
+ }
129
+ const normalizePath = (routePath) => path.posix.normalize(routePath).replace(/\/+$/, "");
130
+ const cloneArray = (array) => [...array];
131
+ const isPageRedirectOnly = (page) => !!(page.redirect && !page.file);
132
+ const removeLeadingSlash = (routePath) => routePath.startsWith("/") ? routePath.slice(1) : routePath;
133
+ const buildRouteName = (baseName, localeCode, isCustom) => isCustom ? `localized-${baseName}-${localeCode}` : `localized-${baseName}`;
134
+ const shouldAddLocalePrefix = (locale, defaultLocale, addLocalePrefix, includeDefaultLocaleRoute) => addLocalePrefix && !(locale === defaultLocale.code && !includeDefaultLocaleRoute);
135
+ const isLocaleDefault = (locale, defaultLocale, includeDefaultLocaleRoute) => {
136
+ const localeCode = typeof locale === "string" ? locale : locale.code;
137
+ return localeCode === defaultLocale.code && !includeDefaultLocaleRoute;
138
+ };
139
+ const buildFullPath = (locale, basePath) => {
140
+ const localeParam = Array.isArray(locale) ? locale.join("|") : locale;
141
+ return normalizePath(path.join(`/:locale(${localeParam})`, basePath));
142
+ };
143
+
144
+ class PageManager {
145
+ locales;
146
+ defaultLocale;
147
+ includeDefaultLocaleRoute;
148
+ localizedPaths = {};
149
+ activeLocaleCodes;
150
+ constructor(locales, defaultLocaleCode, includeDefaultLocaleRoute) {
151
+ this.locales = locales;
152
+ this.defaultLocale = this.findDefaultLocale(defaultLocaleCode);
153
+ this.includeDefaultLocaleRoute = includeDefaultLocaleRoute;
154
+ this.activeLocaleCodes = this.calculateActiveLocaleCodes();
155
+ }
156
+ findDefaultLocale(defaultLocaleCode) {
157
+ return this.locales.find((locale) => locale.code === defaultLocaleCode) || { code: defaultLocaleCode };
158
+ }
159
+ extendPages(pages, options, rootDir) {
160
+ this.localizedPaths = this.extractLocalizedPaths(pages, rootDir);
161
+ const additionalRoutes = [];
162
+ pages.forEach((page) => this.localizePage(page, additionalRoutes));
163
+ pages.push(...additionalRoutes);
164
+ }
165
+ calculateActiveLocaleCodes() {
166
+ return this.locales.filter((locale) => locale.code !== this.defaultLocale.code || this.includeDefaultLocaleRoute).map((locale) => locale.code);
167
+ }
168
+ extractLocalizedPaths(pages, rootDir, parentPath = "") {
169
+ const localizedPaths = {};
170
+ pages.forEach((page) => {
171
+ if (page.file) {
172
+ const filePath = path.resolve(rootDir, page.file);
173
+ const fileContent = readFileSync(filePath, "utf-8");
174
+ const i18nRouteConfig = extractDefineI18nRouteConfig(fileContent, filePath);
175
+ if (i18nRouteConfig?.localeRoutes) {
176
+ const normalizedFullPath = normalizePath(path.join(parentPath, page.path));
177
+ localizedPaths[normalizedFullPath] = i18nRouteConfig.localeRoutes;
178
+ }
179
+ }
180
+ if (page.children?.length) {
181
+ const parentFullPath = normalizePath(path.join(parentPath, page.path));
182
+ Object.assign(localizedPaths, this.extractLocalizedPaths(page.children, rootDir, parentFullPath));
183
+ }
184
+ });
185
+ return localizedPaths;
186
+ }
187
+ localizePage(page, additionalRoutes) {
188
+ if (isPageRedirectOnly(page))
189
+ return;
190
+ const originalChildren = cloneArray(page.children ?? []);
191
+ const normalizedFullPath = normalizePath(page.path);
192
+ const localeCodesWithoutCustomPaths = this.filterLocaleCodesWithoutCustomPaths(normalizedFullPath);
193
+ if (localeCodesWithoutCustomPaths.length) {
194
+ additionalRoutes.push(this.createLocalizedRoute(page, localeCodesWithoutCustomPaths, originalChildren, false));
195
+ }
196
+ this.addCustomLocalizedRoutes(page, normalizedFullPath, originalChildren, additionalRoutes);
197
+ this.adjustRouteForDefaultLocale(page, originalChildren);
198
+ }
199
+ filterLocaleCodesWithoutCustomPaths(fullPath) {
200
+ return this.activeLocaleCodes.filter((code) => !this.localizedPaths[fullPath]?.[code]);
201
+ }
202
+ adjustRouteForDefaultLocale(page, originalChildren) {
203
+ const defaultLocalePath = this.localizedPaths[page.path]?.[this.defaultLocale.code];
204
+ if (defaultLocalePath) {
205
+ page.path = normalizePath(defaultLocalePath);
206
+ }
207
+ const currentChildren = page.children ? [...page.children] : [];
208
+ if (originalChildren.length) {
209
+ const newName = normalizePath(path.join("/", page.name ?? ""));
210
+ const localizedChildren = this.mergeChildren(originalChildren, newName, [this.defaultLocale.code]);
211
+ const childrenMap = new Map(currentChildren.map((child) => [child.name, child]));
212
+ localizedChildren.forEach((localizedChild) => {
213
+ if (childrenMap.has(localizedChild.name)) {
214
+ const existingChild = childrenMap.get(localizedChild.name);
215
+ if (existingChild) {
216
+ Object.assign(existingChild, localizedChild);
217
+ }
218
+ } else {
219
+ currentChildren.push(localizedChild);
220
+ }
221
+ });
222
+ page.children = currentChildren;
223
+ }
224
+ }
225
+ mergeChildren(originalChildren, parentPath, localeCodes) {
226
+ const localizedChildren = this.createLocalizedChildren(originalChildren, parentPath, localeCodes, false);
227
+ return [...originalChildren, ...localizedChildren];
228
+ }
229
+ addCustomLocalizedRoutes(page, fullPath, originalChildren, additionalRoutes) {
230
+ this.locales.forEach((locale) => {
231
+ const customPath = this.localizedPaths[fullPath]?.[locale.code];
232
+ if (!customPath)
233
+ return;
234
+ const isDefaultLocale = isLocaleDefault(locale, this.defaultLocale, this.includeDefaultLocaleRoute);
235
+ if (isDefaultLocale) {
236
+ page.children = this.createLocalizedChildren(originalChildren, "", [locale.code], false);
237
+ } else {
238
+ additionalRoutes.push(this.createLocalizedRoute(page, [locale.code], originalChildren, true, customPath));
239
+ }
240
+ });
241
+ }
242
+ createLocalizedChildren(routes, parentPath, localeCodes, modifyName = true, addLocalePrefix = false) {
243
+ return routes.flatMap((route) => this.createLocalizedVariants(route, parentPath, localeCodes, modifyName, addLocalePrefix));
244
+ }
245
+ createLocalizedVariants(route, parentPath, localeCodes, modifyName, addLocalePrefix) {
246
+ const routePath = normalizePath(route.path);
247
+ const fullPath = normalizePath(path.join(parentPath, routePath));
248
+ const customLocalePaths = this.localizedPaths[fullPath];
249
+ const localizedChildren = this.createLocalizedChildren(route.children ?? [], fullPath, localeCodes, modifyName);
250
+ return localeCodes.map((locale) => this.createLocalizedChildRoute(route, routePath, locale, customLocalePaths, localizedChildren, modifyName, addLocalePrefix));
251
+ }
252
+ createLocalizedRoute(page, localeCodes, originalChildren, isCustom, customPath = "") {
253
+ const routePath = this.buildRoutePath(localeCodes, page.path, customPath, isCustom);
254
+ const routeName = buildRouteName(page.name ?? "", localeCodes[0], isCustom);
255
+ return {
256
+ ...page,
257
+ children: this.createLocalizedChildren(originalChildren, page.path, localeCodes, true),
258
+ path: routePath,
259
+ name: routeName
260
+ };
261
+ }
262
+ createLocalizedChildRoute(route, routePath, locale, customLocalePaths, children, modifyName, addLocalePrefix) {
263
+ const finalPath = this.buildLocalizedRoutePath(routePath, locale, customLocalePaths, addLocalePrefix);
264
+ const routeName = this.buildLocalizedRouteName(route.name ?? "", locale, modifyName);
265
+ return {
266
+ ...route,
267
+ name: routeName,
268
+ path: removeLeadingSlash(finalPath),
269
+ children
270
+ };
271
+ }
272
+ buildLocalizedRoutePath(routePath, locale, customLocalePaths, addLocalePrefix) {
273
+ const basePath = customLocalePaths?.[locale] || routePath;
274
+ const normalizedBasePath = normalizePath(basePath);
275
+ return shouldAddLocalePrefix(locale, this.defaultLocale, addLocalePrefix, this.includeDefaultLocaleRoute) ? buildFullPath(locale, normalizedBasePath) : normalizedBasePath;
276
+ }
277
+ buildLocalizedRouteName(baseName, locale, modifyName) {
278
+ return modifyName && !isLocaleDefault(locale, this.defaultLocale, this.includeDefaultLocaleRoute) ? `localized-${baseName}-${locale}` : baseName;
279
+ }
280
+ buildRoutePath(localeCodes, originalPath, customPath, isCustom) {
281
+ if (isCustom) {
282
+ return this.includeDefaultLocaleRoute || !localeCodes.includes(this.defaultLocale.code) ? buildFullPath(localeCodes, customPath) : normalizePath(customPath);
283
+ }
284
+ return buildFullPath(localeCodes, originalPath);
285
+ }
286
+ }
287
+
288
+ class LocaleManager {
289
+ locales;
290
+ options;
291
+ rootDirs;
292
+ defaultLocale;
293
+ constructor(options, rootDirs) {
294
+ this.options = options;
295
+ this.rootDirs = rootDirs;
296
+ this.locales = this.mergeLocales(options.locales ?? []);
297
+ this.defaultLocale = options.defaultLocale ?? "en";
298
+ }
299
+ mergeLocales(locales) {
300
+ return locales.reduce((acc, locale) => {
301
+ const existingLocale = acc.find((l) => l.code === locale.code);
302
+ if (existingLocale) {
303
+ Object.assign(existingLocale, locale);
304
+ } else {
305
+ acc.push(locale);
306
+ }
307
+ return acc;
308
+ }, []).filter((locale) => !locale.disabled);
309
+ }
310
+ ensureTranslationFilesExist(pagesNames, translationDir, rootDir) {
311
+ this.locales.forEach((locale) => {
312
+ const globalFilePath = path.join(rootDir, translationDir, `${locale.code}.json`);
313
+ this.ensureFileExists(globalFilePath);
314
+ if (!this.options.disablePageLocales) {
315
+ pagesNames.forEach((name) => {
316
+ const pageFilePath = path.join(rootDir, translationDir, "pages", `${name}/${locale.code}.json`);
317
+ this.ensureFileExists(pageFilePath);
318
+ });
319
+ }
320
+ });
321
+ }
322
+ ensureFileExists(filePath) {
323
+ const fileDir = path.dirname(filePath);
324
+ if (!existsSync(fileDir)) {
325
+ mkdirSync(fileDir, { recursive: true });
326
+ }
327
+ if (!existsSync(filePath)) {
328
+ writeFileSync(filePath, JSON.stringify({}), "utf-8");
329
+ }
330
+ }
331
+ }
332
+
91
333
  const module = defineNuxtModule({
92
334
  meta: {
93
335
  name: "nuxt-i18n-micro",
@@ -119,20 +361,13 @@ const module = defineNuxtModule({
119
361
  async setup(options, nuxt) {
120
362
  const resolver = createResolver(import.meta.url);
121
363
  const rootDirs = nuxt.options._layers.map((layer) => layer.config.rootDir).reverse();
122
- const locales = (options.locales ?? []).reduce((acc, locale) => {
123
- const existingLocale = acc.find((l) => l.code === locale.code);
124
- if (existingLocale) {
125
- Object.assign(existingLocale, locale);
126
- } else {
127
- acc.push(locale);
128
- }
129
- return acc;
130
- }, []).filter((locale) => !locale.disabled);
364
+ const localeManager = new LocaleManager(options, rootDirs);
365
+ const pageManager = new PageManager(localeManager.locales, options.defaultLocale, options.includeDefaultLocaleRoute);
131
366
  nuxt.options.runtimeConfig.public.i18nConfig = {
132
367
  rootDir: nuxt.options.rootDir,
133
368
  rootDirs,
134
369
  plural: options.plural,
135
- locales: locales ?? [],
370
+ locales: localeManager.locales ?? [],
136
371
  meta: options.meta ?? true,
137
372
  metaBaseUrl: options.metaBaseUrl ?? void 0,
138
373
  define: options.define ?? true,
@@ -184,153 +419,18 @@ const module = defineNuxtModule({
184
419
  pathPrefix: false,
185
420
  extensions: ["vue"]
186
421
  });
187
- const localeRegex = locales.filter((locale) => locale.code !== options.defaultLocale || options.includeDefaultLocaleRoute).map((locale) => locale.code);
188
- const pagesDir = path.resolve(nuxt.options.rootDir, options.translationDir, "pages");
189
422
  extendPages((pages) => {
190
- const customPaths = {};
191
- function extractCustomPaths(pages2, parentPath = "") {
192
- for (const page of pages2) {
193
- if (page.file) {
194
- const filePath = path.resolve(nuxt.options.rootDir, page.file);
195
- const fileContent = readFileSync(filePath, "utf-8");
196
- const i18nRouteConfig = extractDefineI18nRouteConfig(fileContent, filePath);
197
- if (i18nRouteConfig && i18nRouteConfig.localeRoutes) {
198
- const fullPath = parentPath ? `${parentPath}/${page.path}` : page.path;
199
- customPaths[fullPath] = i18nRouteConfig.localeRoutes;
200
- }
201
- }
202
- if (page.children && page.children.length > 0) {
203
- const fullParentName = parentPath ? `${parentPath}/${page.path}` : page.path;
204
- extractCustomPaths(page.children, fullParentName);
205
- }
206
- }
207
- }
208
- extractCustomPaths(pages);
209
- const pagesNames = pages.map((page) => page.name).filter((name) => name && (!options.routesLocaleLinks || !options.routesLocaleLinks[name]));
210
- function ensureFileExists(filePath) {
211
- const fileDir = path.dirname(filePath);
212
- if (!existsSync(fileDir)) {
213
- mkdirSync(fileDir, { recursive: true });
214
- }
215
- if (!existsSync(filePath)) {
216
- writeFileSync(filePath, JSON.stringify({}), "utf-8");
217
- }
218
- }
219
423
  if (!options.disableWatcher) {
220
- locales.forEach((locale) => {
221
- const globalFilePath = path.join(nuxt.options.rootDir, options.translationDir, `${locale.code}.json`);
222
- ensureFileExists(globalFilePath);
223
- if (!options.disablePageLocales) {
224
- pagesNames.forEach((name) => {
225
- const pageFilePath = path.join(pagesDir, `${name}/${locale.code}.json`);
226
- ensureFileExists(pageFilePath);
227
- });
228
- }
229
- });
230
- }
231
- const newRoutes = [];
232
- for (let i = 0; i < pages.length; i++) {
233
- let localizeChildren = function(routes, parentPath = "", currentLocales = [], modifyName = true, addLocalePrefix = false) {
234
- return routes.flatMap((route) => {
235
- const routePath = route.path.startsWith("/") ? route.path.slice(1) : route.path;
236
- const customLocalePaths = customPaths[`${parentPath}/${routePath}`];
237
- const localizedChildren = route.children ? localizeChildren(route.children, "", currentLocales, modifyName, false) : [];
238
- return currentLocales.map((locale) => {
239
- let path2 = customLocalePaths && customLocalePaths[locale] ? customLocalePaths[locale] : routePath;
240
- if (path2.startsWith("/")) {
241
- path2 = path2.slice(1);
242
- }
243
- const isDefault = locale === options.defaultLocale && !options.includeDefaultLocaleRoute;
244
- const routeName = modifyName && !isDefault ? `localized-${route.name}-${locale}` : route.name;
245
- const finalPath = addLocalePrefix && !isDefault ? `/:locale(${locale})/${path2}` : path2;
246
- return {
247
- ...route,
248
- name: routeName,
249
- path: finalPath,
250
- children: localizedChildren
251
- // Use localized children
252
- };
253
- });
254
- });
255
- };
256
- const page = pages[i];
257
- if (page.redirect && !page.file) {
258
- continue;
259
- }
260
- let modLocaleRegex = localeRegex;
261
- locales.forEach((locale) => {
262
- if (customPaths[page.path] && customPaths[page.path][locale.code]) {
263
- modLocaleRegex = modLocaleRegex.filter((locale2) => {
264
- return !customPaths[page.path][locale2];
265
- });
266
- }
267
- });
268
- const children = [...page.children ?? []];
269
- if (modLocaleRegex.length) {
270
- const newRoute = {
271
- file: page.file,
272
- meta: { ...page.meta },
273
- alias: page.alias,
274
- redirect: page.redirect,
275
- children: page.children ? localizeChildren(children, page.path, modLocaleRegex) : [],
276
- mode: page.mode,
277
- path: `/:locale(${modLocaleRegex.join("|")})${page.path}`,
278
- name: `localized-${page.name}`
279
- };
280
- newRoutes.push(newRoute);
281
- }
282
- if (customPaths[page.path]) {
283
- locales.forEach((locale) => {
284
- if (customPaths[page.path][locale.code]) {
285
- if (locale.code === options.defaultLocale && !options.includeDefaultLocaleRoute) {
286
- if (page.children) {
287
- page.children = localizeChildren(children, `/${page.name}`, [locale.code], false, false);
288
- }
289
- } else {
290
- const newRoute = {
291
- file: page.file,
292
- meta: { ...page.meta },
293
- alias: page.alias,
294
- redirect: page.redirect,
295
- children: page.children ? localizeChildren(children, page.path, [locale.code], true, false) : [],
296
- mode: page.mode,
297
- path: `/:locale(${locale.code})${customPaths[page.path][locale.code]}`,
298
- // Use custom path for the locale
299
- name: `localized-${page.name}-${locale.code}`
300
- };
301
- newRoutes.push(newRoute);
302
- }
303
- }
304
- });
305
- }
306
- if (!options.includeDefaultLocaleRoute) {
307
- if (customPaths[page.path]) {
308
- page.path = customPaths[page.path][options.defaultLocale] ?? page.path;
309
- }
310
- if (page.children?.length) {
311
- page.children = [
312
- ...children,
313
- ...localizeChildren(children, `/${page.name}`, locales.filter((locale) => locale.code === options.defaultLocale).map((locale) => locale.code), false)
314
- ];
315
- }
316
- }
424
+ const pagesNames = pages.map((page) => page.name).filter((name) => name !== void 0 && (!options.routesLocaleLinks || !options.routesLocaleLinks[name]));
425
+ localeManager.ensureTranslationFilesExist(pagesNames, options.translationDir, nuxt.options.rootDir);
317
426
  }
318
- pages.push(...newRoutes);
319
- nuxt.options.generate.routes = Array.isArray(nuxt.options.generate.routes) ? nuxt.options.generate.routes : [];
320
- locales.forEach((locale) => {
321
- if (!options.disablePageLocales) {
322
- pagesNames.forEach((name) => {
323
- addPrerenderRoutes(`/_locales/${name}/${locale.code}/data.json`);
324
- });
325
- }
326
- addPrerenderRoutes(`/_locales/general/${locale.code}/data.json`);
327
- });
427
+ pageManager.extendPages(pages, options, nuxt.options.rootDir);
328
428
  });
329
429
  nuxt.hook("nitro:config", (nitroConfig) => {
330
430
  const routes = nitroConfig.prerender?.routes || [];
331
431
  nuxt.options.generate.routes = Array.isArray(nuxt.options.generate.routes) ? nuxt.options.generate.routes : [];
332
432
  const pages = nuxt.options.generate.routes || [];
333
- locales.forEach((locale) => {
433
+ localeManager.locales.forEach((locale) => {
334
434
  if (locale.code !== options.defaultLocale || options.includeDefaultLocaleRoute) {
335
435
  pages.forEach((page) => {
336
436
  routes.push(`/${locale.code}${page}`);
@@ -377,44 +477,5 @@ const module = defineNuxtModule({
377
477
  }
378
478
  }
379
479
  });
380
- function extractDefineI18nRouteConfig(content, path2) {
381
- const match = content.match(/^[ \t]*\$defineI18nRoute\((\{[\s\S]*?\})\)/m);
382
- if (match && match[1]) {
383
- try {
384
- const parsedObject = Function('"use strict";return (' + match[1] + ")")();
385
- const configObject = parsedObject;
386
- if (validateDefineI18nRouteConfig(configObject)) {
387
- return configObject;
388
- } else {
389
- console.error("Invalid defineI18nRoute configuration format:", configObject, "in file: ", path2);
390
- }
391
- } catch (error) {
392
- console.error("Failed to parse defineI18nRoute configuration:", error, "in file: ", path2);
393
- }
394
- }
395
- return null;
396
- }
397
- function validateDefineI18nRouteConfig(obj) {
398
- if (typeof obj !== "object" || obj === null)
399
- return false;
400
- if (obj.locales) {
401
- if (typeof obj.locales !== "object")
402
- return false;
403
- for (const localeKey in obj.locales) {
404
- const translations = obj.locales[localeKey];
405
- if (typeof translations !== "object" || translations === null)
406
- return false;
407
- }
408
- }
409
- if (obj.localeRoutes) {
410
- if (typeof obj.localeRoutes !== "object")
411
- return false;
412
- for (const routeKey in obj.localeRoutes) {
413
- if (typeof obj.localeRoutes[routeKey] !== "string")
414
- return false;
415
- }
416
- }
417
- return true;
418
- }
419
480
 
420
481
  export { module as default };
@@ -9,7 +9,7 @@ interface PluralTranslations {
9
9
  }
10
10
  declare const _default: import("#app").Plugin<{
11
11
  getLocale: () => string;
12
- getLocales: () => Locale[];
12
+ getLocales: () => any;
13
13
  t: (key: string, params?: Record<string, string | number | boolean>, defaultValue?: string) => unknown;
14
14
  tc: (key: string, count: number, defaultValue?: string) => string;
15
15
  tn: (value: number, options?: Intl.NumberFormatOptions) => string;
@@ -20,7 +20,7 @@ declare const _default: import("#app").Plugin<{
20
20
  localeRoute: (to: RouteLocationRaw, locale?: string) => RouteLocationRaw;
21
21
  }> & import("#app").ObjectPlugin<{
22
22
  getLocale: () => string;
23
- getLocales: () => Locale[];
23
+ getLocales: () => any;
24
24
  t: (key: string, params?: Record<string, string | number | boolean>, defaultValue?: string) => unknown;
25
25
  tc: (key: string, count: number, defaultValue?: string) => string;
26
26
  tn: (value: number, options?: Intl.NumberFormatOptions) => string;
package/dist/types.d.mts CHANGED
@@ -1,4 +1,6 @@
1
- import type { ModuleHooks } from './module.js'
1
+ import type { NuxtModule } from '@nuxt/schema'
2
+
3
+ import type { default as Module, ModuleHooks } from './module.js'
2
4
 
3
5
  declare module '@nuxt/schema' {
4
6
  interface NuxtHooks extends ModuleHooks {}
@@ -8,4 +10,6 @@ declare module 'nuxt/schema' {
8
10
  interface NuxtHooks extends ModuleHooks {}
9
11
  }
10
12
 
11
- export { type Locale, type ModuleHooks, type ModuleOptions, type ModuleOptionsExtend, default } from './module.js'
13
+ export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<O> : Record<string, any>
14
+
15
+ export { type ModuleHooks, default } from './module.js'
package/dist/types.d.ts CHANGED
@@ -1,4 +1,6 @@
1
- import type { ModuleHooks } from './module'
1
+ import type { NuxtModule } from '@nuxt/schema'
2
+
3
+ import type { default as Module, ModuleHooks } from './module'
2
4
 
3
5
  declare module '@nuxt/schema' {
4
6
  interface NuxtHooks extends ModuleHooks {}
@@ -8,4 +10,6 @@ declare module 'nuxt/schema' {
8
10
  interface NuxtHooks extends ModuleHooks {}
9
11
  }
10
12
 
11
- export { type Locale, type ModuleHooks, type ModuleOptions, type ModuleOptionsExtend, default } from './module'
13
+ export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<O> : Record<string, any>
14
+
15
+ export { type ModuleHooks, default } from './module'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-i18n-micro",
3
- "version": "1.12.2",
3
+ "version": "1.12.3",
4
4
  "description": "Nuxt I18n Micro is a lightweight, high-performance internationalization module for Nuxt, designed to handle multi-language support with minimal overhead, fast build times, and efficient runtime performance.",
5
5
  "repository": "s00d/nuxt-i18n-micro",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- {"id":"ebef9bab-73b3-451c-9eee-7e9b779ac677","timestamp":1725188700332,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}