mnfst 0.5.42 → 0.5.43
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/manifest.router.js +83 -1
- package/package.json +1 -1
package/dist/manifest.router.js
CHANGED
|
@@ -228,6 +228,82 @@ function shouldSkipStickyLocaleForLogicalSegments(segments) {
|
|
|
228
228
|
return STICKY_LOCALE_STATIC_FILE_EXT.has(ext);
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
// manifest.prerender.localeRouteExclude → JSON array in meta; logical path prefixes (after locale).
|
|
232
|
+
function parseLocaleRouteExcludePatterns() {
|
|
233
|
+
const meta = document.querySelector('meta[name="manifest:locale-route-exclude"]');
|
|
234
|
+
const raw = meta?.getAttribute('content') || '';
|
|
235
|
+
if (raw.trim().startsWith('[')) {
|
|
236
|
+
try {
|
|
237
|
+
const parsed = JSON.parse(raw.replace(/"/g, '"'));
|
|
238
|
+
if (Array.isArray(parsed)) {
|
|
239
|
+
return parsed.map((s) => String(s).trim()).filter(Boolean);
|
|
240
|
+
}
|
|
241
|
+
} catch {
|
|
242
|
+
/* fall through */
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const legacy = document.querySelector('meta[name="manifest:locale-sticky-exclude"]');
|
|
246
|
+
const legacyRaw = legacy?.getAttribute('content') || '';
|
|
247
|
+
if (!legacyRaw.trim()) return [];
|
|
248
|
+
return legacyRaw.split(',').map((s) => s.trim().replace(/^\/+/, '').split('/')[0]).filter(Boolean);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function logicalPathMatchesLocaleRouteExclude(segments, patterns) {
|
|
252
|
+
if (!patterns.length || !segments.length) return false;
|
|
253
|
+
const lower = segments.map((s) => s.toLowerCase());
|
|
254
|
+
for (const pattern of patterns) {
|
|
255
|
+
const p = String(pattern)
|
|
256
|
+
.trim()
|
|
257
|
+
.replace(/^\/+/, '')
|
|
258
|
+
.split('/')
|
|
259
|
+
.filter(Boolean)
|
|
260
|
+
.map((x) => x.toLowerCase());
|
|
261
|
+
if (p.length === 0) continue;
|
|
262
|
+
if (lower.length < p.length) continue;
|
|
263
|
+
let match = true;
|
|
264
|
+
for (let i = 0; i < p.length; i++) {
|
|
265
|
+
if (lower[i] !== p[i]) {
|
|
266
|
+
match = false;
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if (match) return true;
|
|
271
|
+
}
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// /fr/legal/terms → /legal/terms when patterns include "legal" or "legal/terms" (prefix match).
|
|
276
|
+
function normalizeRedundantLocalePrefixInUrl() {
|
|
277
|
+
if (!isPrerenderedStaticBuild()) return false;
|
|
278
|
+
const codes = getLocalizationCodesFromManifest();
|
|
279
|
+
const patterns = parseLocaleRouteExcludePatterns();
|
|
280
|
+
if (!codes.length || !patterns.length) return false;
|
|
281
|
+
|
|
282
|
+
const segs = logicalSegmentsFromPathname(window.location.pathname);
|
|
283
|
+
if (segs.length < 2) return false;
|
|
284
|
+
if (!codes.includes(segs[0])) return false;
|
|
285
|
+
const rest = segs.slice(1);
|
|
286
|
+
if (!logicalPathMatchesLocaleRouteExclude(rest, patterns)) return false;
|
|
287
|
+
|
|
288
|
+
const newLogical = '/' + rest.join('/');
|
|
289
|
+
const base = getBasePath();
|
|
290
|
+
let newPathname = base ? base.replace(/\/+$/, '') + newLogical : newLogical;
|
|
291
|
+
newPathname = newPathname.replace(/\/{2,}/g, '/');
|
|
292
|
+
if (!newPathname.startsWith('/')) newPathname = '/' + newPathname;
|
|
293
|
+
if (newPathname === window.location.pathname) return false;
|
|
294
|
+
|
|
295
|
+
const prevLogical = pathnameToLogical(window.location.pathname);
|
|
296
|
+
const u = new URL(window.location.href);
|
|
297
|
+
u.pathname = newPathname;
|
|
298
|
+
history.replaceState(null, '', u.toString());
|
|
299
|
+
currentRoute = pathnameToLogical(newPathname);
|
|
300
|
+
const np = currentRoute === '/' ? '/' : String(currentRoute).replace(/^\/|\/$/g, '');
|
|
301
|
+
window.dispatchEvent(new CustomEvent('manifest:route-change', {
|
|
302
|
+
detail: { from: prevLogical, to: currentRoute, normalizedPath: np }
|
|
303
|
+
}));
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
|
|
231
307
|
// When the URL already has a locale prefix (e.g. /zh/pricing), keep it for same-origin links
|
|
232
308
|
// that omit the prefix (/articles → /zh/articles). No-op on default-locale URLs (/pricing).
|
|
233
309
|
function applyStickyLocaleToPathname(absolutePathname) {
|
|
@@ -242,6 +318,12 @@ function applyStickyLocaleToPathname(absolutePathname) {
|
|
|
242
318
|
if (targetSegs.length && codes.includes(targetSegs[0])) {
|
|
243
319
|
return absolutePathname;
|
|
244
320
|
}
|
|
321
|
+
|
|
322
|
+
const routeEx = parseLocaleRouteExcludePatterns();
|
|
323
|
+
if (routeEx.length && logicalPathMatchesLocaleRouteExclude(targetSegs, routeEx)) {
|
|
324
|
+
return absolutePathname;
|
|
325
|
+
}
|
|
326
|
+
|
|
245
327
|
if (shouldSkipStickyLocaleForLogicalSegments(targetSegs)) {
|
|
246
328
|
return absolutePathname;
|
|
247
329
|
}
|
|
@@ -489,8 +571,8 @@ function interceptLinkClicks() {
|
|
|
489
571
|
|
|
490
572
|
// Initialize navigation
|
|
491
573
|
function initializeNavigation() {
|
|
492
|
-
// Set initial route (logical path for matching)
|
|
493
574
|
currentRoute = pathnameToLogical(window.location.pathname);
|
|
575
|
+
normalizeRedundantLocalePrefixInUrl();
|
|
494
576
|
|
|
495
577
|
// In prerendered/static output, use default browser navigation (no SPA interception)
|
|
496
578
|
if (!isPrerenderedStaticBuild()) {
|