@i18n-micro/route-strategy 1.1.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,875 @@
1
+ import N from "node:path";
2
+ import { existsSync as E, mkdirSync as B, writeFileSync as U } from "node:fs";
3
+ import { isPrefixAndDefaultStrategy as D, isPrefixStrategy as O } from "@i18n-micro/core";
4
+ function w(l) {
5
+ return l.split("/").map((e) => e.startsWith("[...") && e.endsWith("]") ? `:${e.substring(4, e.length - 1)}(.*)*` : e.startsWith("[") && e.endsWith("]") ? `:${e.substring(1, e.length - 1)}` : e).join("/");
6
+ }
7
+ const R = (l) => {
8
+ if (!l)
9
+ return "";
10
+ const e = N.posix.normalize(l).replace(/\/+$/, "");
11
+ return e === "." ? "" : e;
12
+ }, y = (l) => l.startsWith("/") ? l.slice(1) : l;
13
+ function G(...l) {
14
+ return N.posix.join(...l);
15
+ }
16
+ function q(l) {
17
+ if (!(typeof l > "u"))
18
+ return l.startsWith("/") && l.endsWith("/") ? l?.slice(1, -1) : l;
19
+ }
20
+ function K(l) {
21
+ return !l || !/[\u0080-\uFFFF]/.test(l) ? l : l.split("/").map((e) => !e || e.startsWith(":") || !/[\u0080-\uFFFF]/.test(e) ? e : encodeURI(e)).join("/");
22
+ }
23
+ function A(l, e, t) {
24
+ const a = q(t?.toString()), o = a || (Array.isArray(l) ? l.join("|") : l), s = K(e);
25
+ return R(N.posix.join("/", `:locale(${o})`, s));
26
+ }
27
+ function H(l) {
28
+ const e = K(l);
29
+ return R(e);
30
+ }
31
+ const $ = (l) => l.map((e) => ({ ...e })), J = (l) => !!(l.redirect && !l.file), j = (l, e, t, a = "localized-") => t ? `${a}${l}-${e}` : `${a}${l}`, b = (l, e) => l ?? (e ?? "").replace(/[^a-z0-9]/gi, "-").replace(/^-+|-+$/g, ""), Q = (l, e, t, a) => t && !(l === e.code && !a), X = (l, e, t) => (typeof l == "string" ? l : l.code) === e.code && !t, Y = [
32
+ /^\/sitemap.*\.xml$/,
33
+ /^\/sitemap\.xml$/,
34
+ /^\/robots\.txt$/,
35
+ /^\/favicon\.ico$/,
36
+ /^\/apple-touch-icon.*\.png$/,
37
+ /^\/manifest\.json$/,
38
+ /^\/sw\.js$/,
39
+ /^\/workbox-.*\.js$/,
40
+ /\.(xml|txt|ico|json|js|css|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/
41
+ ];
42
+ function M(l, e) {
43
+ if (/(?:^|\/)__[^/]+/.test(l))
44
+ return !0;
45
+ for (const t of Y)
46
+ if (t.test(l))
47
+ return !0;
48
+ if (e) {
49
+ for (const t of e)
50
+ if (typeof t == "string") {
51
+ if (t.includes("*") || t.includes("?")) {
52
+ if (new RegExp(t.replace(/\*/g, ".*").replace(/\?/g, ".")).test(l)) return !0;
53
+ } else if (l === t || l.startsWith(t))
54
+ return !0;
55
+ } else if (t instanceof RegExp && t.test(l))
56
+ return !0;
57
+ }
58
+ return !1;
59
+ }
60
+ function Z(l, e) {
61
+ const t = l.reduce((o, s) => {
62
+ const i = o.find((r) => r.code === s.code);
63
+ return i ? Object.assign(i, s) : o.push(s), o;
64
+ }, []).filter((o) => !o.disabled), a = t.find((o) => o.code === e) ?? { code: e };
65
+ return { locales: t, defaultLocale: a };
66
+ }
67
+ const ee = (l, e) => l ?? (e ?? "").replace(/[^a-z0-9]/gi, "-").replace(/^-+|-+$/g, "");
68
+ function F(l) {
69
+ return y(l) || "/";
70
+ }
71
+ function S(l, e, t, a = "") {
72
+ const o = {};
73
+ return l.forEach((s) => {
74
+ const i = ee(s.name, s.path), r = R(G(a, s.path ?? "")), n = F(r), d = w(r), c = e[n] || e[d] || e[i];
75
+ if (c)
76
+ typeof c == "object" && (o[n] = c);
77
+ else {
78
+ const h = t[i];
79
+ h && typeof h == "object" && !Array.isArray(h) && (o[n] = h);
80
+ }
81
+ if (s.children?.length) {
82
+ const h = R(G(a, s.path ?? ""));
83
+ Object.assign(o, S(s.children, e, t, h));
84
+ }
85
+ }), o;
86
+ }
87
+ function te(l) {
88
+ const e = {};
89
+ if (!l) return e;
90
+ for (const t in l) {
91
+ const a = w(t), o = l[t];
92
+ if (typeof o == "object") {
93
+ const s = {};
94
+ for (const i in o) {
95
+ const r = o[i];
96
+ r && (s[i] = w(r));
97
+ }
98
+ e[a] = s;
99
+ } else
100
+ e[a] = o;
101
+ }
102
+ return e;
103
+ }
104
+ class ae {
105
+ constructor(e) {
106
+ this.locales = e.locales, this.defaultLocale = this.findLocaleByCode(e.locales, e.defaultLocaleCode) ?? { code: e.defaultLocaleCode }, this.strategy = e.strategy, this.globalLocaleRoutes = te(e.globalLocaleRoutes ?? {}), this.filesLocaleRoutes = e.filesLocaleRoutes ?? {}, this.routeLocales = e.routeLocales ?? {}, this.localizedPaths = S(
107
+ e.pages,
108
+ this.globalLocaleRoutes,
109
+ this.filesLocaleRoutes
110
+ ), this.activeLocaleCodes = this.locales.filter(
111
+ (t) => t.code !== this.defaultLocale.code || D(this.strategy) || O(this.strategy)
112
+ ).map((t) => t.code), this.excludePatterns = e.excludePatterns, this.customRegex = e.customRegex, this.noPrefixRedirect = e.noPrefixRedirect ?? !1, this.localizedRouteNamePrefix = e.localizedRouteNamePrefix ?? "localized-", this.fallbackRedirectComponentPath = e.fallbackRedirectComponentPath, this.rawGlobalLocaleRoutes = e.rawGlobalLocaleRoutes;
113
+ }
114
+ findLocaleByCode(e, t) {
115
+ return e.find((a) => a.code === t);
116
+ }
117
+ /**
118
+ * Returns the list of locale codes allowed for a page (respecting routeLocales).
119
+ */
120
+ getAllowedLocales(e, t) {
121
+ const a = this.routeLocales[e] ?? this.routeLocales[t];
122
+ return a?.length ? a.filter(
123
+ (o) => this.locales.some((s) => s.code === o)
124
+ ) : this.locales.map((o) => o.code);
125
+ }
126
+ /**
127
+ * Returns a custom path for a given locale by original page path, if any.
128
+ */
129
+ getCustomPath(e, t) {
130
+ const a = F(e);
131
+ return this.localizedPaths[a]?.[t];
132
+ }
133
+ /**
134
+ * Returns a map of custom paths (locale → path) for a page by path key or name.
135
+ */
136
+ getCustomPathsForPage(e, t) {
137
+ const a = F(e);
138
+ return this.localizedPaths[a] ?? this.localizedPaths[t];
139
+ }
140
+ hasLocaleRestrictions(e, t) {
141
+ return !!(this.routeLocales[e] ?? this.routeLocales[t]);
142
+ }
143
+ filterLocaleCodesWithoutCustomPaths(e) {
144
+ const t = F(e);
145
+ return this.activeLocaleCodes.filter((a) => !this.localizedPaths[t]?.[a]);
146
+ }
147
+ }
148
+ function z(l, e) {
149
+ const t = (e ?? "").trim();
150
+ return t.startsWith("/") ? R(t) : R(N.posix.join(l || "", t));
151
+ }
152
+ function p(l, e) {
153
+ const { path: t, name: a, children: o, meta: s, alias: i } = e, r = {
154
+ ...l,
155
+ path: t
156
+ };
157
+ return a !== void 0 && (r.name = a), o !== void 0 && (r.children = o), s !== void 0 && (r.meta = { ...l.meta, ...s }), i !== void 0 ? (r.alias = i, r.meta = { ...r.meta, alias: i }) : "alias" in e && (r.alias = void 0, r.meta = { ...r.meta, alias: void 0 }), r;
158
+ }
159
+ function se(l) {
160
+ const e = l.alias, t = l.meta?.alias, a = e ?? t;
161
+ return Array.isArray(a) ? a : [];
162
+ }
163
+ function _(l, e, t, a = "localized-") {
164
+ const o = se(l);
165
+ if (!o.length) return [];
166
+ const s = [];
167
+ for (const i of o) {
168
+ const r = A(e, i, t);
169
+ s.push(
170
+ p(l, {
171
+ path: r,
172
+ name: `${a}${l.name ?? ""}`,
173
+ alias: void 0,
174
+ meta: { alias: void 0 },
175
+ // Important: if the source page has children, the alias route
176
+ // must keep the same children tree so that /alias/child does not 404.
177
+ // createRoute takes care of cloning/adjusting children correctly.
178
+ children: l.children
179
+ })
180
+ );
181
+ }
182
+ return s;
183
+ }
184
+ class k {
185
+ processPage(e, t) {
186
+ if (e.path === void 0)
187
+ throw new Error("page.path is required");
188
+ if (J(e))
189
+ return [e];
190
+ if (e.path && M(e.path, t.excludePatterns))
191
+ return [e];
192
+ const a = e.path ?? "", o = b(e.name, e.path), s = w(a);
193
+ return t.globalLocaleRoutes[o] === !1 || t.globalLocaleRoutes[s] === !1 ? [e] : this.generateVariants(e, t);
194
+ }
195
+ postProcess(e, t) {
196
+ return e;
197
+ }
198
+ /**
199
+ * Recursive localization for children: for a given locale, builds:
200
+ * - parentOriginalPath used for Context lookups,
201
+ * - parentLocalizedPath used for the final path,
202
+ * and returns an array of localized child routes.
203
+ */
204
+ localizeChildren(e, t, a, o, s, i) {
205
+ return e.flatMap((r) => this.localizeChild(r, t, a, o, s, i));
206
+ }
207
+ /**
208
+ * Variant for a single route with :locale(locale1|locale2) — without custom paths.
209
+ * Returns a single child route with a relative path and recursively localized children.
210
+ */
211
+ localizeChildrenAllLocales(e, t, a, o, s) {
212
+ return e.flatMap((i) => this.localizeChildAllLocales(i, t, a, o, s));
213
+ }
214
+ localizeChildAllLocales(e, t, a, o, s) {
215
+ const i = z(a, e.path ?? ""), r = z(t, e.path ?? ""), n = F(r), d = s.localizedPaths[n];
216
+ if (d)
217
+ return o.flatMap((f) => {
218
+ const P = d[f] ?? z(t, e.path ?? "");
219
+ return this.localizeChild(e, P, a, f, s, !0);
220
+ });
221
+ const c = R(e.path ?? ""), h = y(c), u = this.localizeChildrenAllLocales(
222
+ $(e.children ?? []),
223
+ r,
224
+ i,
225
+ o,
226
+ s
227
+ ), m = `${s.localizedRouteNamePrefix}${e.name ?? ""}`;
228
+ return [
229
+ p(e, {
230
+ path: h,
231
+ name: m,
232
+ children: u
233
+ })
234
+ ];
235
+ }
236
+ localizeChild(e, t, a, o, s, i) {
237
+ const r = z(a, e.path ?? ""), n = s.getCustomPath(r, o), d = y(R(n || (e.path ?? ""))), c = n ?? z(t, e.path ?? ""), h = this.localizeChildren(
238
+ $(e.children ?? []),
239
+ c,
240
+ r,
241
+ o,
242
+ s,
243
+ i
244
+ ), u = b(e.name, e.path), m = `${s.localizedRouteNamePrefix}${u}-${o}`;
245
+ return [
246
+ p(e, {
247
+ path: d,
248
+ name: m,
249
+ children: h
250
+ })
251
+ ];
252
+ }
253
+ /**
254
+ * Shared helper for strategies that build prefix-based paths (:locale(...)):
255
+ * - for custom paths, decides whether a prefix is required,
256
+ * - for regular paths, always uses buildFullPath.
257
+ *
258
+ * The logic matches what used to be duplicated in each strategy's buildRoutePath.
259
+ */
260
+ buildRoutePathForLocales(e, t, a, o, s, i, r) {
261
+ if (o) {
262
+ const n = e.includes(r);
263
+ return i || !n ? A(e, a, s) : R(a);
264
+ }
265
+ return A(e, t, s);
266
+ }
267
+ }
268
+ class oe extends k {
269
+ generateVariants(e, t) {
270
+ const a = e.path ?? "", o = b(e.name, e.path), s = t.getAllowedLocales(a, o), i = t.getCustomPathsForPage(a, o), r = $(e.children ?? []), n = [];
271
+ if (n.push(e), i)
272
+ for (const d of s) {
273
+ const c = i[d];
274
+ if (!c) continue;
275
+ const h = R(c), u = R(a);
276
+ if (h === u)
277
+ continue;
278
+ const m = H(c), f = j(o, d, !0), P = this.localizeChildrenForNoPrefix(
279
+ r,
280
+ h,
281
+ a,
282
+ a,
283
+ d,
284
+ t,
285
+ 1
286
+ );
287
+ n.push(
288
+ p(e, {
289
+ path: m,
290
+ name: f,
291
+ children: P,
292
+ alias: [],
293
+ meta: { alias: [] }
294
+ })
295
+ ), t.noPrefixRedirect && d === t.defaultLocale.code && h !== u && (e.redirect = h);
296
+ }
297
+ return n.push(..._(e, s, t.customRegex, t.localizedRouteNamePrefix)), n;
298
+ }
299
+ /**
300
+ * Localizes the children tree for the no_prefix strategy.
301
+ * Mirrors the behavior of the legacy RouteGenerator:
302
+ * - on the first level, custom paths (globalLocaleRoutes/filesLocaleRoutes) are applied;
303
+ * - on deeper levels, path stays as a segment (item, detail, etc.).
304
+ */
305
+ localizeChildrenForNoPrefix(e, t, a, o, s, i, r) {
306
+ return e.map((n) => {
307
+ const d = z(a, n.path ?? "");
308
+ let c, h;
309
+ if (r === 1) {
310
+ const P = i.getCustomPath(d, s);
311
+ if (P) {
312
+ const L = R(P);
313
+ c = y(L), h = L;
314
+ } else {
315
+ const L = R(n.path ?? "");
316
+ c = y(L), h = z(t, n.path ?? "");
317
+ }
318
+ } else {
319
+ const P = R(n.path ?? "");
320
+ c = y(P), h = z(t, n.path ?? "");
321
+ }
322
+ const u = this.localizeChildrenForNoPrefix(
323
+ $(n.children ?? []),
324
+ h,
325
+ d,
326
+ o,
327
+ s,
328
+ i,
329
+ r + 1
330
+ ), m = b(n.name, n.path), f = j(m, s, !0);
331
+ return p(n, {
332
+ path: c,
333
+ name: f,
334
+ children: u
335
+ });
336
+ });
337
+ }
338
+ }
339
+ function le(l) {
340
+ const e = l.alias ?? l.meta?.alias;
341
+ return Array.isArray(e) ? e : [];
342
+ }
343
+ class ie extends k {
344
+ generateVariants(e, t) {
345
+ const a = e.path ?? "", o = b(e.name, e.path), s = t.getAllowedLocales(a, o), i = t.getCustomPathsForPage(a, o), r = $(e.children ?? []), n = [];
346
+ if (i)
347
+ for (const c of s) {
348
+ const h = i[c], u = h ? R(h) : a, m = A(c, u, t.customRegex), f = j(o, c, !!h, t.localizedRouteNamePrefix), P = h ?? a, L = this.localizeChildren(
349
+ r,
350
+ P,
351
+ a,
352
+ c,
353
+ t,
354
+ !0
355
+ );
356
+ n.push(
357
+ p(e, {
358
+ path: m,
359
+ name: f,
360
+ children: L,
361
+ alias: [],
362
+ meta: { alias: [] }
363
+ })
364
+ );
365
+ }
366
+ else {
367
+ const c = A(s, a, t.customRegex), h = j(o, s[0], !1, t.localizedRouteNamePrefix), u = this.localizeChildrenAllLocales(
368
+ r,
369
+ a,
370
+ a,
371
+ s,
372
+ t
373
+ );
374
+ n.push(
375
+ p(e, {
376
+ path: c,
377
+ name: h,
378
+ children: u,
379
+ alias: [],
380
+ meta: { alias: [] }
381
+ })
382
+ );
383
+ }
384
+ const d = le(e);
385
+ if (d.length)
386
+ for (const c of d) {
387
+ const h = A(s, c, t.customRegex);
388
+ n.push(
389
+ p(e, {
390
+ path: h,
391
+ name: `${t.localizedRouteNamePrefix}${e.name ?? ""}`,
392
+ alias: void 0,
393
+ meta: { alias: void 0 }
394
+ })
395
+ );
396
+ }
397
+ return n;
398
+ }
399
+ postProcess(e, t) {
400
+ const a = e.filter((o) => {
401
+ if (o.name === "index" && o.path === "/") return !1;
402
+ const s = o.path ?? "";
403
+ return !!(s && M(s, t.excludePatterns) || t.globalLocaleRoutes[o.name ?? ""] === !1 || /^\/:locale/.test(s) || s === "/");
404
+ });
405
+ return t.fallbackRedirectComponentPath && a.push({
406
+ path: "/:pathMatch(.*)*",
407
+ name: "custom-fallback-route",
408
+ file: t.fallbackRedirectComponentPath,
409
+ meta: {
410
+ globalLocaleRoutes: t.rawGlobalLocaleRoutes ?? t.globalLocaleRoutes
411
+ }
412
+ }), a;
413
+ }
414
+ }
415
+ class re extends k {
416
+ generateVariants(e, t) {
417
+ const a = e.path ?? "", o = b(e.name, e.path), s = t.getAllowedLocales(a, o), i = t.getCustomPathsForPage(a, o), r = $(e.children ?? []), n = [], d = t.defaultLocale.code;
418
+ n.push(e);
419
+ const c = t.locales.filter((u) => s.includes(u.code));
420
+ if (c.length > 0)
421
+ if (i)
422
+ for (const u of c) {
423
+ const m = i[u.code];
424
+ if (m)
425
+ if (u.code === d) {
426
+ const f = this.createLocalizedRoute(
427
+ e,
428
+ [u.code],
429
+ r,
430
+ !0,
431
+ m,
432
+ t.customRegex,
433
+ !1,
434
+ u.code,
435
+ a,
436
+ t
437
+ );
438
+ f && n.push(f);
439
+ const P = this.createLocalizedRoute(
440
+ e,
441
+ [u.code],
442
+ r,
443
+ !0,
444
+ m,
445
+ t.customRegex,
446
+ !0,
447
+ u.code,
448
+ a,
449
+ t
450
+ );
451
+ P && n.push(P);
452
+ } else {
453
+ const f = this.createLocalizedRoute(
454
+ e,
455
+ [u.code],
456
+ r,
457
+ !0,
458
+ m,
459
+ t.customRegex,
460
+ !1,
461
+ u.code,
462
+ a,
463
+ t
464
+ );
465
+ f && n.push(f);
466
+ }
467
+ else {
468
+ const f = this.createLocalizedRoute(
469
+ e,
470
+ [u.code],
471
+ r,
472
+ !1,
473
+ "",
474
+ t.customRegex,
475
+ !1,
476
+ u.code,
477
+ a,
478
+ t
479
+ );
480
+ f && n.push(f);
481
+ }
482
+ }
483
+ else {
484
+ const u = c.map((f) => f.code), m = this.createLocalizedRoute(
485
+ e,
486
+ u,
487
+ r,
488
+ !1,
489
+ "",
490
+ t.customRegex,
491
+ !1,
492
+ !0,
493
+ a,
494
+ t
495
+ );
496
+ m && n.push(m);
497
+ }
498
+ const h = _(e, s, t.customRegex, t.localizedRouteNamePrefix);
499
+ return h.length && n.push(...h), n;
500
+ }
501
+ postProcess(e, t) {
502
+ const a = [], o = [];
503
+ for (const s of e) {
504
+ const i = s.name ?? "";
505
+ typeof i == "string" && i.startsWith(t.localizedRouteNamePrefix) ? o.push(s) : a.push(s);
506
+ }
507
+ return [...a, ...o];
508
+ }
509
+ createLocalizedRoute(e, t, a, o, s = "", i, r = !1, n = !1, d, c) {
510
+ const h = this.buildRoutePathForLocales(
511
+ t,
512
+ e.path ?? "",
513
+ encodeURI(s),
514
+ o,
515
+ i,
516
+ r,
517
+ c.defaultLocale.code
518
+ );
519
+ if (!h || !(o && s) && h === e.path || t.length === 0) return null;
520
+ const m = t[0];
521
+ if (!m) return null;
522
+ const f = d ?? e.path ?? "", P = j(b(e.name ?? "", f), m, o, c.localizedRouteNamePrefix), L = r || m !== c.defaultLocale.code, g = t.length === 1 ? this.localizeChildren(a, h, f, m, c, L) : this.localizeChildrenAllLocales(a, h, f, t, c);
523
+ return p(e, {
524
+ path: h,
525
+ name: P,
526
+ children: g,
527
+ alias: [],
528
+ meta: { alias: [] }
529
+ });
530
+ }
531
+ }
532
+ class ne extends k {
533
+ generateVariants(e, t) {
534
+ const a = e.path ?? "", o = b(e.name, e.path), s = t.getAllowedLocales(a, o), i = t.getCustomPathsForPage(a, o), r = $(e.children ?? []), n = [], d = t.defaultLocale.code;
535
+ if (s.includes(d)) {
536
+ const u = i?.[d], m = u ? R(u) : a, f = u ? { [d]: u } : {}, P = this.createLocalizedChildren(
537
+ r,
538
+ a,
539
+ [d],
540
+ !1,
541
+ !1,
542
+ !1,
543
+ f,
544
+ t
545
+ );
546
+ n.push(
547
+ p(e, {
548
+ path: m,
549
+ name: e.name,
550
+ children: P
551
+ })
552
+ );
553
+ }
554
+ const c = t.locales.filter(
555
+ (u) => s.includes(u.code) && u.code !== d
556
+ );
557
+ if (c.length)
558
+ if (i)
559
+ for (const u of c) {
560
+ const m = i[u.code];
561
+ if (m) {
562
+ const f = this.createLocalizedRoute(
563
+ e,
564
+ [u.code],
565
+ r,
566
+ !0,
567
+ m,
568
+ t.customRegex,
569
+ !1,
570
+ u.code,
571
+ a,
572
+ t
573
+ );
574
+ f && n.push(f);
575
+ } else {
576
+ const f = this.createLocalizedRoute(
577
+ e,
578
+ [u.code],
579
+ r,
580
+ !1,
581
+ "",
582
+ t.customRegex,
583
+ !1,
584
+ u.code,
585
+ a,
586
+ t
587
+ );
588
+ f && n.push(f);
589
+ }
590
+ }
591
+ else {
592
+ const u = c.map((f) => f.code), m = this.createLocalizedRoute(
593
+ e,
594
+ u,
595
+ r,
596
+ !1,
597
+ "",
598
+ t.customRegex,
599
+ !1,
600
+ !0,
601
+ a,
602
+ t
603
+ );
604
+ m && n.push(m);
605
+ }
606
+ const h = _(e, s, t.customRegex, t.localizedRouteNamePrefix);
607
+ return h.length && n.push(...h), n;
608
+ }
609
+ postProcess(e, t) {
610
+ const a = [], o = [];
611
+ for (const i of e) {
612
+ const r = i.name ?? "";
613
+ typeof r == "string" && r.startsWith(t.localizedRouteNamePrefix) ? o.push(i) : a.push(i);
614
+ }
615
+ const s = [...a, ...o];
616
+ return t.fallbackRedirectComponentPath && s.push({
617
+ path: "/:pathMatch(.*)*",
618
+ name: "custom-fallback-route",
619
+ file: t.fallbackRedirectComponentPath,
620
+ meta: {
621
+ globalLocaleRoutes: t.rawGlobalLocaleRoutes ?? t.globalLocaleRoutes
622
+ }
623
+ }), s;
624
+ }
625
+ createLocalizedChildren(e, t, a, o = !0, s = !1, i = !1, r = {}, n) {
626
+ return e.flatMap(
627
+ (d) => this.createLocalizedVariants(
628
+ d,
629
+ t,
630
+ a,
631
+ o,
632
+ s,
633
+ i,
634
+ r,
635
+ n
636
+ )
637
+ );
638
+ }
639
+ createLocalizedVariants(e, t, a, o, s, i = !1, r, n) {
640
+ const d = R(e.path ?? ""), c = z(t, e.path ?? ""), h = F(c), u = n.localizedPaths[h], m = !!u, f = [];
641
+ if (!m) {
642
+ const P = y(d), L = this.createLocalizedChildren(
643
+ $(e.children ?? []),
644
+ z(t, e.path ?? ""),
645
+ a,
646
+ o,
647
+ s,
648
+ i,
649
+ r,
650
+ n
651
+ ), g = this.buildChildRouteName(e.name, i, n);
652
+ return f.push(
653
+ p(e, {
654
+ path: P,
655
+ name: g,
656
+ children: L
657
+ })
658
+ ), f;
659
+ }
660
+ for (const P of a) {
661
+ const L = r?.[P], g = !!L, C = u?.[P];
662
+ let x = R(C || (e.path ?? ""));
663
+ g && L && (C ? x = R(C) : x = z(L, e.path ?? ""));
664
+ const v = Q(
665
+ P,
666
+ n.defaultLocale,
667
+ s,
668
+ !1
669
+ ) ? A(P, x, n.customRegex) : x, T = y(v), W = C ? R(C) : g ? L : z(t, e.path ?? ""), V = this.createLocalizedChildren(
670
+ $(e.children ?? []),
671
+ W,
672
+ [P],
673
+ o,
674
+ s,
675
+ P,
676
+ {
677
+ ...r,
678
+ [P]: W
679
+ },
680
+ n
681
+ ), I = this.buildLocalizedRouteName(
682
+ b(e.name, e.path),
683
+ P,
684
+ o,
685
+ !!u,
686
+ n
687
+ );
688
+ f.push(
689
+ p(e, {
690
+ path: T,
691
+ name: I,
692
+ children: V
693
+ })
694
+ );
695
+ }
696
+ return f;
697
+ }
698
+ buildChildRouteName(e, t, a) {
699
+ return t === !0 ? `${a.localizedRouteNamePrefix}${e}` : typeof t == "string" ? `${a.localizedRouteNamePrefix}${e}-${t}` : e;
700
+ }
701
+ createLocalizedRoute(e, t, a, o, s = "", i, r = !1, n = !1, d, c) {
702
+ const h = this.buildRoutePathForLocales(
703
+ t,
704
+ e.path ?? "",
705
+ encodeURI(s),
706
+ o,
707
+ i,
708
+ r,
709
+ c.defaultLocale.code
710
+ );
711
+ if (!h || h === e.path || t.length === 0) return null;
712
+ const u = t[0];
713
+ if (!u) return null;
714
+ const m = d ?? e.path ?? "", f = j(b(e.name ?? "", m), u, o, c.localizedRouteNamePrefix);
715
+ return p(e, {
716
+ path: h,
717
+ name: f,
718
+ children: this.createLocalizedChildren(
719
+ a,
720
+ m,
721
+ t,
722
+ !0,
723
+ !1,
724
+ n,
725
+ { [u]: s },
726
+ c
727
+ ),
728
+ alias: [],
729
+ meta: { alias: [] }
730
+ });
731
+ }
732
+ buildLocalizedRouteName(e, t, a, o = !1, s) {
733
+ return a ? o ? `${s.localizedRouteNamePrefix}${e}-${t}` : t && !X(t, s.defaultLocale, !1) ? `${s.localizedRouteNamePrefix}${e}-${t}` : `${s.localizedRouteNamePrefix}${e}` : e;
734
+ }
735
+ }
736
+ function ce(l) {
737
+ switch (l) {
738
+ case "no_prefix":
739
+ return new oe();
740
+ case "prefix":
741
+ return new ie();
742
+ case "prefix_and_default":
743
+ return new re();
744
+ case "prefix_except_default":
745
+ return new ne();
746
+ default:
747
+ throw new Error(`Unknown route strategy: ${l}`);
748
+ }
749
+ }
750
+ class de {
751
+ constructor(e) {
752
+ this.localizedPaths = {};
753
+ const {
754
+ locales: t,
755
+ defaultLocaleCode: a,
756
+ strategy: o,
757
+ globalLocaleRoutes: s,
758
+ filesLocaleRoutes: i = {},
759
+ routeLocales: r = {},
760
+ noPrefixRedirect: n,
761
+ excludePatterns: d,
762
+ localizedRouteNamePrefix: c = "localized-",
763
+ customRegexMatcher: h,
764
+ fallbackRedirectComponentPath: u
765
+ } = e, m = Z(t, a);
766
+ this.locales = m.locales, this.defaultLocale = m.defaultLocale, this.strategy = o, this.noPrefixRedirect = n, this.excludePatterns = d, this.localizedRouteNamePrefix = c, this.customRegex = h, this.fallbackRedirectComponentPath = u, this.activeLocaleCodes = this.computeActiveLocaleCodes();
767
+ const f = {};
768
+ for (const P in s) {
769
+ const L = w(P), g = s[P];
770
+ if (typeof g == "object") {
771
+ const C = {};
772
+ for (const x in g) {
773
+ const v = g[x];
774
+ v && (C[x] = w(v));
775
+ }
776
+ f[L] = C;
777
+ } else
778
+ f[L] = g;
779
+ }
780
+ this.globalLocaleRoutes = f, this.rawGlobalLocaleRoutes = s ?? {}, this.filesLocaleRoutes = i ?? {}, this.routeLocales = r ?? {};
781
+ }
782
+ computeActiveLocaleCodes() {
783
+ return this.locales.filter((e) => e.code !== this.defaultLocale.code || D(this.strategy) || O(this.strategy)).map((e) => e.code);
784
+ }
785
+ extendPages(e) {
786
+ const t = new ae({
787
+ locales: this.locales,
788
+ defaultLocaleCode: this.defaultLocale.code,
789
+ strategy: this.strategy,
790
+ globalLocaleRoutes: this.globalLocaleRoutes,
791
+ filesLocaleRoutes: this.filesLocaleRoutes,
792
+ routeLocales: this.routeLocales,
793
+ pages: e,
794
+ excludePatterns: this.excludePatterns,
795
+ customRegex: this.customRegex,
796
+ noPrefixRedirect: this.noPrefixRedirect,
797
+ localizedRouteNamePrefix: this.localizedRouteNamePrefix,
798
+ fallbackRedirectComponentPath: this.fallbackRedirectComponentPath,
799
+ rawGlobalLocaleRoutes: this.rawGlobalLocaleRoutes
800
+ });
801
+ this.localizedPaths = t.localizedPaths;
802
+ const a = ce(this.strategy), o = [...e], s = [];
803
+ for (const r of o)
804
+ s.push(...a.processPage(r, t));
805
+ const i = a.postProcess(s, t);
806
+ e.length = 0, e.push(...i);
807
+ }
808
+ extractLocalizedPaths(e, t = "") {
809
+ return S(
810
+ e,
811
+ this.globalLocaleRoutes,
812
+ this.filesLocaleRoutes,
813
+ t
814
+ );
815
+ }
816
+ /**
817
+ * Creates global and per-page translation JSON files for the current resolved locales.
818
+ */
819
+ ensureTranslationFilesExist(e, t, a, o) {
820
+ this.locales.forEach((s) => {
821
+ const i = N.join(a, t, `${s.code}.json`);
822
+ this.ensureFileExists(i), o || e.forEach((r) => {
823
+ const n = N.join(a, t, "pages", `${r}/${s.code}.json`);
824
+ this.ensureFileExists(n);
825
+ });
826
+ });
827
+ }
828
+ ensureFileExists(e) {
829
+ const t = N.dirname(e);
830
+ E(t) || B(t, { recursive: !0 }), E(e) || U(e, JSON.stringify({}), "utf-8");
831
+ }
832
+ /**
833
+ * Returns the localized path for a given URL and locale,
834
+ * respecting strategy and globalLocaleRoutes (custom paths).
835
+ * Used by nitro:config and prerender so route rules work with custom paths (e.g. /de/ueber-uns).
836
+ */
837
+ resolveLocalizedPath(e, t) {
838
+ const a = w(e), o = y(a) || "/";
839
+ let s;
840
+ const i = this.globalLocaleRoutes[o], r = this.globalLocaleRoutes[a];
841
+ i && typeof i == "object" && !Array.isArray(i) ? s = i[t] : r && typeof r == "object" && !Array.isArray(r) && (s = r[t]);
842
+ const n = !!s, d = s ? R(s) : R(a) || "";
843
+ let c = !1;
844
+ if (this.strategy === "no_prefix" ? c = !1 : this.strategy === "prefix" || this.strategy === "prefix_and_default" ? c = !0 : this.strategy === "prefix_except_default" && (c = t !== this.defaultLocale.code), t === this.defaultLocale.code && !n && (this.strategy === "prefix_except_default" || this.strategy === "no_prefix") && (c = !1), !c)
845
+ return R(d) || "/";
846
+ const h = y(d);
847
+ return h ? R(`/${t}/${h}`) : `/${t}`;
848
+ }
849
+ /**
850
+ * Generates the list of data.json routes for prerender (general + per-page per locale).
851
+ */
852
+ generateDataRoutes(e, t, a) {
853
+ const o = [], s = e.map((i) => i.name).filter((i) => typeof i == "string" && i.length > 0);
854
+ for (const i of this.locales)
855
+ if (o.push(`/${t}/general/${i.code}/data.json`), !a)
856
+ for (const r of s)
857
+ o.push(`/${t}/${r}/${i.code}/data.json`);
858
+ return o;
859
+ }
860
+ }
861
+ export {
862
+ de as RouteGenerator,
863
+ A as buildFullPath,
864
+ H as buildFullPathNoPrefix,
865
+ j as buildRouteName,
866
+ $ as cloneArray,
867
+ S as extractLocalizedPaths,
868
+ M as isInternalPath,
869
+ X as isLocaleDefault,
870
+ J as isPageRedirectOnly,
871
+ R as normalizePath,
872
+ w as normalizeRouteKey,
873
+ y as removeLeadingSlash,
874
+ Q as shouldAddLocalePrefix
875
+ };