nuxt-i18n-micro 1.23.0 → 1.24.0

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,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
- <link rel="stylesheet" href="/__nuxt-i18n-micro/_nuxt/entry.DjxsrOxm.css">
4
- <link rel="modulepreload" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/CeFL7aT9.js">
3
+ <link rel="stylesheet" href="/__nuxt-i18n-micro/_nuxt/entry.BqOlM4b6.css">
4
+ <link rel="modulepreload" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/mVL4Ag1z.js">
5
5
  <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/B6E6ObS_.js">
6
6
  <link rel="prefetch" as="style" crossorigin href="/__nuxt-i18n-micro/_nuxt/error-404.C_4C5G96.css">
7
- <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/ftQz2Awu.js">
8
- <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/CnNUpwZL.js">
7
+ <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/B3qz2zap.js">
8
+ <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/CtNJ_juG.js">
9
9
  <link rel="prefetch" as="style" crossorigin href="/__nuxt-i18n-micro/_nuxt/error-500.CBAEdpZV.css">
10
- <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/BKcmVa-6.js">
11
- <script type="module" src="/__nuxt-i18n-micro/_nuxt/CeFL7aT9.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__">[{"prerenderedAt":1,"serverRendered":2},1729013281723,false]</script>
12
- <script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-i18n-micro",buildId:"a117c06c-e590-47a0-9b20-040755226f9e",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
10
+ <link rel="prefetch" as="script" crossorigin href="/__nuxt-i18n-micro/_nuxt/CKE-slgQ.js">
11
+ <script type="module" src="/__nuxt-i18n-micro/_nuxt/mVL4Ag1z.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__">[{"prerenderedAt":1,"serverRendered":2},1729146164615,false]</script>
12
+ <script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-i18n-micro",buildId:"6babd624-967d-4b7f-b3a3-4cea27f30fdf",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body></html>
package/dist/module.d.mts CHANGED
@@ -7,6 +7,7 @@ interface Locale {
7
7
  disabled?: boolean;
8
8
  iso?: string;
9
9
  dir?: 'ltr' | 'rtl' | 'auto';
10
+ displayName?: string;
10
11
  }
11
12
  type Getter = (key: string, params?: Record<string, string | number | boolean>, defaultValue?: string) => unknown;
12
13
  type PluralFunc = (key: string, count: number, locale: string, getter: Getter) => string | null;
@@ -29,6 +30,7 @@ interface ModuleOptions {
29
30
  fallbackLocale?: string;
30
31
  localeCookie?: string;
31
32
  globalLocaleRoutes?: GlobalLocaleRoutes;
33
+ customRegexMatcher?: string | RegExp;
32
34
  }
33
35
  interface ModuleOptionsExtend extends ModuleOptions {
34
36
  plural: string;
package/dist/module.d.ts CHANGED
@@ -7,6 +7,7 @@ interface Locale {
7
7
  disabled?: boolean;
8
8
  iso?: string;
9
9
  dir?: 'ltr' | 'rtl' | 'auto';
10
+ displayName?: string;
10
11
  }
11
12
  type Getter = (key: string, params?: Record<string, string | number | boolean>, defaultValue?: string) => unknown;
12
13
  type PluralFunc = (key: string, count: number, locale: string, getter: Getter) => string | null;
@@ -29,6 +30,7 @@ interface ModuleOptions {
29
30
  fallbackLocale?: string;
30
31
  localeCookie?: string;
31
32
  globalLocaleRoutes?: GlobalLocaleRoutes;
33
+ customRegexMatcher?: string | RegExp;
32
34
  }
33
35
  interface ModuleOptionsExtend extends ModuleOptions {
34
36
  plural: string;
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-i18n-micro",
3
3
  "configKey": "i18n",
4
- "version": "1.23.0",
4
+ "version": "1.24.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "0.8.4",
7
7
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -88,51 +88,33 @@ function setupDevToolsUI(options, resolve) {
88
88
  });
89
89
  }
90
90
 
91
- function normalizeLocales(localesArray) {
92
- const localesObject = {};
93
- for (const locale of localesArray) {
94
- localesObject[locale] = {};
95
- }
96
- return localesObject;
97
- }
98
- function extractDefineI18nRouteConfig(content, filePath) {
99
- const match = content.match(/^[ \t]*\$defineI18nRoute\((\{[\s\S]*?\})\)/m);
100
- if (match && match[1]) {
101
- try {
102
- const parsedObject = Function('"use strict";return (' + match[1] + ")")();
103
- if (parsedObject.locales && Array.isArray(parsedObject.locales)) {
104
- parsedObject.locales = normalizeLocales(parsedObject.locales);
105
- }
106
- if (validateDefineI18nRouteConfig(parsedObject)) {
107
- return parsedObject;
108
- } else {
109
- console.error("Invalid defineI18nRoute configuration format:", parsedObject, "in file: ", filePath);
91
+ function extractLocaleRoutes(content, filePath) {
92
+ const defineMatch = content.match(/\$?\bdefineI18nRoute\s*\(\s*\{[\s\S]*?\}\s*\)/);
93
+ if (defineMatch) {
94
+ const localeRoutesMatch = defineMatch[0].match(/localeRoutes:\s*(\{[\s\S]*?\})/);
95
+ if (localeRoutesMatch && localeRoutesMatch[1]) {
96
+ try {
97
+ const parsedLocaleRoutes = Function('"use strict";return (' + localeRoutesMatch[1] + ")")();
98
+ if (typeof parsedLocaleRoutes === "object" && parsedLocaleRoutes !== null) {
99
+ if (validateDefineI18nRouteConfig(parsedLocaleRoutes)) {
100
+ return parsedLocaleRoutes;
101
+ }
102
+ } else {
103
+ console.error("localeRoutes found but it is not a valid object in file:", filePath);
104
+ }
105
+ } catch (error) {
106
+ console.error("Failed to parse localeRoutes:", error, "in file:", filePath);
110
107
  }
111
- } catch (error) {
112
- console.error("Failed to parse defineI18nRoute configuration:", error, "in file: ", filePath);
113
108
  }
114
109
  }
115
110
  return null;
116
111
  }
117
112
  function validateDefineI18nRouteConfig(obj) {
118
- if (typeof obj !== "object" || obj === null)
113
+ if (typeof obj !== "object")
119
114
  return false;
120
- if (obj.locales) {
121
- if (typeof obj.locales !== "object")
115
+ for (const routeKey in obj.localeRoutes) {
116
+ if (typeof obj.localeRoutes[routeKey] !== "string")
122
117
  return false;
123
- for (const localeKey in obj.locales) {
124
- const translations = obj.locales[localeKey];
125
- if (typeof translations !== "object" || translations === null)
126
- return false;
127
- }
128
- }
129
- if (obj.localeRoutes) {
130
- if (typeof obj.localeRoutes !== "object")
131
- return false;
132
- for (const routeKey in obj.localeRoutes) {
133
- if (typeof obj.localeRoutes[routeKey] !== "string")
134
- return false;
135
- }
136
118
  }
137
119
  return true;
138
120
  }
@@ -146,10 +128,16 @@ const isLocaleDefault = (locale, defaultLocale, includeDefaultLocaleRoute) => {
146
128
  const localeCode = typeof locale === "string" ? locale : locale.code;
147
129
  return localeCode === defaultLocale.code && !includeDefaultLocaleRoute;
148
130
  };
149
- const buildFullPath = (locale, basePath) => {
150
- const localeParam = Array.isArray(locale) ? locale.join("|") : locale;
131
+ const buildFullPath = (locale, basePath, customRegex) => {
132
+ const regexString = normalizeRegex(customRegex?.toString());
133
+ const localeParam = Array.isArray(locale) ? regexString ? regexString : locale.join("|") : locale;
151
134
  return normalizePath(path.posix.join("/", `:locale(${localeParam})`, basePath));
152
135
  };
136
+ const normalizeRegex = (toNorm) => {
137
+ if (typeof toNorm === "undefined")
138
+ return void 0;
139
+ return toNorm.startsWith("/") && toNorm.endsWith("/") ? toNorm?.slice(1, -1) : toNorm;
140
+ };
153
141
 
154
142
  class PageManager {
155
143
  locales;
@@ -171,7 +159,7 @@ class PageManager {
171
159
  computeActiveLocaleCodes() {
172
160
  return this.locales.filter((locale) => locale.code !== this.defaultLocale.code || this.includeDefaultLocaleRoute).map((locale) => locale.code);
173
161
  }
174
- extendPages(pages, rootDir) {
162
+ extendPages(pages, rootDir, customRegex) {
175
163
  this.localizedPaths = this.extractLocalizedPaths(pages, rootDir);
176
164
  const additionalRoutes = [];
177
165
  pages.forEach((page) => {
@@ -180,9 +168,9 @@ class PageManager {
180
168
  return;
181
169
  }
182
170
  if (customRoute && typeof customRoute === "object") {
183
- this.addCustomGlobalLocalizedRoutes(page, customRoute, additionalRoutes);
171
+ this.addCustomGlobalLocalizedRoutes(page, customRoute, additionalRoutes, customRegex);
184
172
  } else {
185
- this.localizePage(page, additionalRoutes);
173
+ this.localizePage(page, additionalRoutes, customRegex);
186
174
  }
187
175
  });
188
176
  pages.push(...additionalRoutes);
@@ -196,10 +184,10 @@ class PageManager {
196
184
  if (page.file) {
197
185
  const filePath = path.resolve(rootDir, page.file);
198
186
  const fileContent = readFileSync(filePath, "utf-8");
199
- const i18nRouteConfig = extractDefineI18nRouteConfig(fileContent, filePath);
200
- if (i18nRouteConfig?.localeRoutes) {
187
+ const localeRoutes = extractLocaleRoutes(fileContent, filePath);
188
+ if (localeRoutes) {
201
189
  const normalizedFullPath = normalizePath(path.join(parentPath, page.path));
202
- localizedPaths[normalizedFullPath] = i18nRouteConfig.localeRoutes;
190
+ localizedPaths[normalizedFullPath] = localeRoutes;
203
191
  }
204
192
  }
205
193
  } else if (typeof globalLocalePath === "object") {
@@ -213,7 +201,7 @@ class PageManager {
213
201
  });
214
202
  return localizedPaths;
215
203
  }
216
- addCustomGlobalLocalizedRoutes(page, customRoutePaths, additionalRoutes) {
204
+ addCustomGlobalLocalizedRoutes(page, customRoutePaths, additionalRoutes, customRegex) {
217
205
  this.locales.forEach((locale) => {
218
206
  const customPath = customRoutePaths[locale.code];
219
207
  if (!customPath)
@@ -222,18 +210,18 @@ class PageManager {
222
210
  if (isDefaultLocale) {
223
211
  page.path = normalizePath(customPath);
224
212
  } else {
225
- additionalRoutes.push(this.createLocalizedRoute(page, [locale.code], page.children ?? [], true, customPath));
213
+ additionalRoutes.push(this.createLocalizedRoute(page, [locale.code], page.children ?? [], true, customPath, customRegex));
226
214
  }
227
215
  });
228
216
  }
229
- localizePage(page, additionalRoutes) {
217
+ localizePage(page, additionalRoutes, customRegex) {
230
218
  if (isPageRedirectOnly(page))
231
219
  return;
232
220
  const originalChildren = cloneArray(page.children ?? []);
233
221
  const normalizedFullPath = normalizePath(page.path);
234
222
  const localeCodesWithoutCustomPaths = this.filterLocaleCodesWithoutCustomPaths(normalizedFullPath);
235
223
  if (localeCodesWithoutCustomPaths.length) {
236
- additionalRoutes.push(this.createLocalizedRoute(page, localeCodesWithoutCustomPaths, originalChildren, false));
224
+ additionalRoutes.push(this.createLocalizedRoute(page, localeCodesWithoutCustomPaths, originalChildren, false, "", customRegex));
237
225
  }
238
226
  this.addCustomLocalizedRoutes(page, normalizedFullPath, originalChildren, additionalRoutes);
239
227
  this.adjustRouteForDefaultLocale(page, originalChildren);
@@ -268,7 +256,7 @@ class PageManager {
268
256
  const localizedChildren = this.createLocalizedChildren(originalChildren, parentPath, localeCodes, false);
269
257
  return [...originalChildren, ...localizedChildren];
270
258
  }
271
- addCustomLocalizedRoutes(page, fullPath, originalChildren, additionalRoutes) {
259
+ addCustomLocalizedRoutes(page, fullPath, originalChildren, additionalRoutes, customRegex) {
272
260
  this.locales.forEach((locale) => {
273
261
  const customPath = this.localizedPaths[fullPath]?.[locale.code];
274
262
  if (!customPath)
@@ -277,7 +265,7 @@ class PageManager {
277
265
  if (isDefaultLocale) {
278
266
  page.children = this.createLocalizedChildren(originalChildren, "", [locale.code], false);
279
267
  } else {
280
- additionalRoutes.push(this.createLocalizedRoute(page, [locale.code], originalChildren, true, customPath));
268
+ additionalRoutes.push(this.createLocalizedRoute(page, [locale.code], originalChildren, true, customPath, customRegex));
281
269
  }
282
270
  });
283
271
  }
@@ -291,8 +279,8 @@ class PageManager {
291
279
  const localizedChildren = this.createLocalizedChildren(route.children ?? [], fullPath, localeCodes, modifyName);
292
280
  return localeCodes.map((locale) => this.createLocalizedChildRoute(route, routePath, locale, customLocalePaths, localizedChildren, modifyName, addLocalePrefix));
293
281
  }
294
- createLocalizedRoute(page, localeCodes, originalChildren, isCustom, customPath = "") {
295
- const routePath = this.buildRoutePath(localeCodes, page.path, customPath, isCustom);
282
+ createLocalizedRoute(page, localeCodes, originalChildren, isCustom, customPath = "", customRegex) {
283
+ const routePath = this.buildRoutePath(localeCodes, page.path, customPath, isCustom, customRegex);
296
284
  const routeName = buildRouteName(page.name ?? "", localeCodes[0], isCustom);
297
285
  return {
298
286
  ...page,
@@ -319,11 +307,11 @@ class PageManager {
319
307
  buildLocalizedRouteName(baseName, locale, modifyName) {
320
308
  return modifyName && !isLocaleDefault(locale, this.defaultLocale, this.includeDefaultLocaleRoute) ? `localized-${baseName}-${locale}` : baseName;
321
309
  }
322
- buildRoutePath(localeCodes, originalPath, customPath, isCustom) {
310
+ buildRoutePath(localeCodes, originalPath, customPath, isCustom, customRegex) {
323
311
  if (isCustom) {
324
- return this.includeDefaultLocaleRoute || !localeCodes.includes(this.defaultLocale.code) ? buildFullPath(localeCodes, customPath) : normalizePath(customPath);
312
+ return this.includeDefaultLocaleRoute || !localeCodes.includes(this.defaultLocale.code) ? buildFullPath(localeCodes, customPath, customRegex) : normalizePath(customPath);
325
313
  }
326
- return buildFullPath(localeCodes, originalPath);
314
+ return buildFullPath(localeCodes, originalPath, customRegex);
327
315
  }
328
316
  }
329
317
 
@@ -407,7 +395,8 @@ const module = defineNuxtModule({
407
395
  return forms[1].trim();
408
396
  }
409
397
  return (forms.length > 2 ? forms[2].trim() : forms[forms.length - 1].trim()).replace("{count}", count.toString());
410
- }
398
+ },
399
+ customRegexMatcher: void 0
411
400
  },
412
401
  async setup(options, nuxt) {
413
402
  const isCloudflarePages = nuxt.options.nitro.preset === "cloudflare_pages" || process.env.NITRO_PRESET === "cloudflare-pages";
@@ -439,8 +428,15 @@ const module = defineNuxtModule({
439
428
  baseURL: nuxt.options.app.baseURL,
440
429
  hashMode: nuxt.options?.router?.options?.hashMode ?? false,
441
430
  globalLocaleRoutes: void 0,
442
- apiBaseUrl
431
+ apiBaseUrl,
432
+ customRegexMatcher: options.customRegexMatcher
443
433
  };
434
+ if (typeof options.customRegexMatcher !== "undefined") {
435
+ const localeCodes = localeManager.locales.map((l) => l.code);
436
+ if (!localeCodes.every((code) => code.match(options.customRegexMatcher))) {
437
+ throw new Error("Nuxt-18n-micro: Some locale codes does not match customRegexMatcher");
438
+ }
439
+ }
444
440
  nuxt.options.runtimeConfig.i18nConfig = {
445
441
  rootDir: nuxt.options.rootDir,
446
442
  rootDirs
@@ -483,7 +479,7 @@ const module = defineNuxtModule({
483
479
  if (!options.disableWatcher) {
484
480
  localeManager.ensureTranslationFilesExist(pagesNames, options.translationDir, nuxt.options.rootDir);
485
481
  }
486
- pageManager.extendPages(pages, nuxt.options.rootDir);
482
+ pageManager.extendPages(pages, nuxt.options.rootDir, options.customRegexMatcher);
487
483
  nuxt.options.generate.routes = Array.isArray(nuxt.options.generate.routes) ? nuxt.options.generate.routes : [];
488
484
  const prerenderRoutes = [];
489
485
  localeManager.locales.forEach((locale) => {
@@ -1,7 +1,7 @@
1
1
  import { resolve } from "node:path";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import { defineEventHandler } from "h3";
4
- import { useRuntimeConfig } from "#imports";
4
+ import { useRuntimeConfig, createError } from "#imports";
5
5
  function deepMerge(target, source) {
6
6
  for (const key of Object.keys(source)) {
7
7
  if (key === "__proto__" || key === "constructor") {
@@ -25,7 +25,12 @@ export default defineEventHandler(async (event) => {
25
25
  const { page, locale } = event.context.params;
26
26
  const config = useRuntimeConfig();
27
27
  const { rootDirs } = config.i18nConfig;
28
- const { translationDir, fallbackLocale } = config.public.i18nConfig;
28
+ const { translationDir, fallbackLocale, customRegexMatcher, locales } = config.public.i18nConfig;
29
+ if (customRegexMatcher && locales && !locales.map((l) => l.code).includes(locale)) {
30
+ throw createError({
31
+ statusCode: 404
32
+ });
33
+ }
29
34
  const getTranslationPath = (locale2, page2) => {
30
35
  return page2 === "general" ? `${locale2}.json` : `pages/${page2}/${locale2}.json`;
31
36
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-i18n-micro",
3
- "version": "1.23.0",
3
+ "version": "1.24.0",
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",
@@ -89,7 +89,6 @@
89
89
  },
90
90
  "workspaces": [
91
91
  "client",
92
- "playground",
93
92
  "test/fixtures/**/*"
94
93
  ],
95
94
  "packageManager": "yarn@3.7.0+sha256.7bf0c78a106332886ea4e59641fd819b1af953edcd72c4d93a32b1c71000ee67"