@i18n-micro/path-strategy 1.0.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/LICENSE +21 -0
- package/README.md +196 -0
- package/dist/base-strategy-B5mBf3XX.cjs +2 -0
- package/dist/base-strategy-B5mBf3XX.cjs.map +1 -0
- package/dist/base-strategy-DVqe8ehd.js +790 -0
- package/dist/base-strategy-DVqe8ehd.js.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +394 -0
- package/dist/index.mjs +45 -0
- package/dist/index.mjs.map +1 -0
- package/dist/no-prefix-strategy.cjs +2 -0
- package/dist/no-prefix-strategy.cjs.map +1 -0
- package/dist/no-prefix-strategy.d.ts +283 -0
- package/dist/no-prefix-strategy.mjs +40 -0
- package/dist/no-prefix-strategy.mjs.map +1 -0
- package/dist/prefix-and-default-strategy.cjs +2 -0
- package/dist/prefix-and-default-strategy.cjs.map +1 -0
- package/dist/prefix-and-default-strategy.d.ts +284 -0
- package/dist/prefix-and-default-strategy.mjs +129 -0
- package/dist/prefix-and-default-strategy.mjs.map +1 -0
- package/dist/prefix-except-default-strategy.cjs +2 -0
- package/dist/prefix-except-default-strategy.cjs.map +1 -0
- package/dist/prefix-except-default-strategy.d.ts +298 -0
- package/dist/prefix-except-default-strategy.mjs +245 -0
- package/dist/prefix-except-default-strategy.mjs.map +1 -0
- package/dist/prefix-strategy.cjs +2 -0
- package/dist/prefix-strategy.cjs.map +1 -0
- package/dist/prefix-strategy.d.ts +277 -0
- package/dist/prefix-strategy.mjs +40 -0
- package/dist/prefix-strategy.mjs.map +1 -0
- package/dist/types.cjs +2 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.ts +108 -0
- package/dist/types.mjs +2 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +84 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# @i18n-micro/path-strategy
|
|
2
|
+
|
|
3
|
+
Path and route strategies for **Nuxt I18n Micro**: locale resolution from URL, link generation, redirects, and SEO attributes (canonical, hreflang). Use this package when you need a single routing strategy at build time so only the chosen implementation is bundled.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
- **Strategies**: `no_prefix`, `prefix`, `prefix_except_default`, `prefix_and_default`
|
|
10
|
+
- **API**: `resolveLocaleFromPath`, `getLocaleFromPath`, `localeRoute`, `switchLocaleRoute`, `getRedirect`, `getSeoAttributes`, `getCanonicalPath`, `getRouteBaseName`
|
|
11
|
+
- **Framework-agnostic**: Works with any router that implements the `RouterAdapter` interface (`hasRoute`, `resolve`); compatible with Vue Router and custom adapters.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Package structure
|
|
16
|
+
|
|
17
|
+
| Folder | Contents |
|
|
18
|
+
|--------|----------|
|
|
19
|
+
| `src/core/` | Types (`types.ts`), normalizer (`getPathWithoutLocale`, `getLocaleFromPath`), resolver, builder (`createLocalizedRouteObject`) |
|
|
20
|
+
| `src/strategies/` | `BasePathStrategy`, `createPathStrategy`, and strategy implementations: `no-prefix`, `prefix`, `prefix-except-default`, `prefix-and-default` |
|
|
21
|
+
| `src/utils/` | Path helpers (`path.ts`), route name helpers (`route-name.ts`: `getRouteBaseName`, `buildLocalizedName`, `isIndexRouteName`) |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm add @i18n-micro/path-strategy @i18n-micro/types
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Peer dependency: `@i18n-micro/types`.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Setup: Using a single strategy via Nuxt alias (build-time)
|
|
36
|
+
|
|
37
|
+
To ship only the selected strategy (no factory, no other implementations), wire a Nuxt alias at build time.
|
|
38
|
+
|
|
39
|
+
### 1. Configure the Nuxt module
|
|
40
|
+
|
|
41
|
+
In your Nuxt module’s `setup()` (or in `nuxt.config`), set the alias to the strategy entry you want:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// src/module.ts (or nuxt.config.ts)
|
|
45
|
+
|
|
46
|
+
import type { Strategies } from '@i18n-micro/types'
|
|
47
|
+
|
|
48
|
+
const strategyEntries: Record<Strategies, string> = {
|
|
49
|
+
no_prefix: '@i18n-micro/path-strategy/no-prefix',
|
|
50
|
+
prefix: '@i18n-micro/path-strategy/prefix',
|
|
51
|
+
prefix_except_default: '@i18n-micro/path-strategy/prefix-except-default',
|
|
52
|
+
prefix_and_default: '@i18n-micro/path-strategy/prefix-and-default',
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const selectedStrategy = strategyEntries[options.strategy] ?? strategyEntries.prefix_except_default
|
|
56
|
+
|
|
57
|
+
nuxt.options.alias['#i18n-strategy'] = selectedStrategy
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 2. Type declarations for `#i18n-strategy`
|
|
61
|
+
|
|
62
|
+
So that TypeScript and your IDE understand the alias, add a generated declaration in `prepare:types`:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { resolve } from 'node:path'
|
|
66
|
+
|
|
67
|
+
nuxt.hook('prepare:types', ({ references }) => {
|
|
68
|
+
nuxt.addTemplate({
|
|
69
|
+
filename: 'i18n-strategy.d.ts',
|
|
70
|
+
getContents: () => `
|
|
71
|
+
import { BasePathStrategy } from '@i18n-micro/path-strategy'
|
|
72
|
+
export class Strategy extends BasePathStrategy {}
|
|
73
|
+
`,
|
|
74
|
+
})
|
|
75
|
+
references.push({ path: resolve(nuxt.options.buildDir, 'i18n-strategy.d.ts') })
|
|
76
|
+
})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
If your setup already resolves types for this alias, you can skip this step.
|
|
80
|
+
|
|
81
|
+
### 3. Use in a plugin or composable
|
|
82
|
+
|
|
83
|
+
Import the strategy only via the alias so the bundler includes just that implementation:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
// runtime/plugins/01.i18n-strategy.ts
|
|
87
|
+
|
|
88
|
+
import { Strategy } from '#i18n-strategy'
|
|
89
|
+
import type { PathStrategyContext } from '@i18n-micro/path-strategy/types'
|
|
90
|
+
|
|
91
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
92
|
+
const context: PathStrategyContext = {
|
|
93
|
+
strategy: useRuntimeConfig().public.i18n.strategy,
|
|
94
|
+
defaultLocale: 'en',
|
|
95
|
+
locales: [/* ... */],
|
|
96
|
+
localizedRouteNamePrefix: 'localized-',
|
|
97
|
+
router: { hasRoute, resolve },
|
|
98
|
+
// optional: globalLocaleRoutes, routeLocales, routesLocaleLinks, noPrefixRedirect, includeDefaultLocaleRoute
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const pathStrategy = new Strategy(context)
|
|
102
|
+
return { provide: { i18nStrategy: pathStrategy } }
|
|
103
|
+
})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Only the selected strategy and the base class are included in the bundle; the other strategies are tree-shaken out.
|
|
107
|
+
|
|
108
|
+
### 4. Package exports
|
|
109
|
+
|
|
110
|
+
| Entry | Contents |
|
|
111
|
+
|-------|----------|
|
|
112
|
+
| `@i18n-micro/path-strategy` | Main entry: types, factory, all strategies, utils (`getRouteBaseName`, `buildLocalizedName`, `isIndexRouteName`) |
|
|
113
|
+
| `@i18n-micro/path-strategy/prefix` | `PrefixPathStrategy` and `Strategy` alias |
|
|
114
|
+
| `@i18n-micro/path-strategy/no-prefix` | `NoPrefixPathStrategy` and `Strategy` |
|
|
115
|
+
| `@i18n-micro/path-strategy/prefix-except-default` | `PrefixExceptDefaultPathStrategy` and `Strategy` |
|
|
116
|
+
| `@i18n-micro/path-strategy/prefix-and-default` | `PrefixAndDefaultPathStrategy` and `Strategy` |
|
|
117
|
+
| `@i18n-micro/path-strategy/types` | Types only (`PathStrategyContext`, `RouteLike`, `ResolvedRouteLike`, `RouterAdapter`, `SeoAttributes`, etc.) |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## API
|
|
122
|
+
|
|
123
|
+
### Factory
|
|
124
|
+
|
|
125
|
+
- **`createPathStrategy(ctx: PathStrategyContext)`** — Returns the strategy instance for `ctx.strategy`. Use for tests or server-side when you don’t use the alias.
|
|
126
|
+
|
|
127
|
+
### Utilities (from main entry)
|
|
128
|
+
|
|
129
|
+
- **`getRouteBaseName(route, options?)`** — Returns the base route name (without localized prefix/suffix). Options: `localizedRouteNamePrefix`, `locales`.
|
|
130
|
+
- **`buildLocalizedName(baseName, localeCode, prefix?)`** — Builds a localized route name (e.g. `about` + `de` + `localized-` → `localized-about-de`).
|
|
131
|
+
- **`isIndexRouteName(name, options?)`** — Returns whether the route name is the index route (e.g. `index`, `localized-index-en`). Options: `localizedRouteNamePrefix`, `locales`.
|
|
132
|
+
|
|
133
|
+
### Strategy interface
|
|
134
|
+
|
|
135
|
+
Each strategy implements:
|
|
136
|
+
|
|
137
|
+
| Method | Description |
|
|
138
|
+
|--------|-------------|
|
|
139
|
+
| `switchLocaleRoute(fromLocale, toLocale, route, options)` | Route (or path string) to navigate to when switching locale. Returns `RouteLike` or `string`. |
|
|
140
|
+
| `localeRoute(targetLocale, routeOrPath, currentRoute?)` | Localized route for the target locale. Always returns `RouteLike` with `path` and `fullPath` set. |
|
|
141
|
+
| `getCanonicalPath(route, targetLocale)` | Custom path for the route in that locale (from `globalLocaleRoutes`), or `null`. |
|
|
142
|
+
| `resolveLocaleFromPath(path)` | Locale code from path (strategy-specific; e.g. `no_prefix` returns `null`). |
|
|
143
|
+
| `getLocaleFromPath(path)` | Parses path and returns first segment if it is a locale code; used for initial state and redirect logic. |
|
|
144
|
+
| `getRedirect(currentPath, targetLocale)` | Path to redirect to, or `null`. Use in middleware: `strategy.getRedirect(to.fullPath, detectedLocale)`. |
|
|
145
|
+
| `getSeoAttributes(currentRoute)` | `{ canonical?, hreflangs? }` for `useHead`. |
|
|
146
|
+
| `getRouteBaseName(route)` | Base name for the route (delegates to `getRouteBaseName` with context). |
|
|
147
|
+
|
|
148
|
+
### Context (`PathStrategyContext`)
|
|
149
|
+
|
|
150
|
+
Import from `@i18n-micro/path-strategy/types`.
|
|
151
|
+
|
|
152
|
+
| Property | Description |
|
|
153
|
+
|----------|-------------|
|
|
154
|
+
| `strategy`, `defaultLocale`, `locales`, `localizedRouteNamePrefix`, `router` | Required. |
|
|
155
|
+
| `globalLocaleRoutes` | `Record<string, Record<string, string> \| false>`: custom path per route/locale; `false` = unlocalized. |
|
|
156
|
+
| `routeLocales` | `Record<string, string[]>`: route path or base name → list of locale codes; limits hreflang entries. |
|
|
157
|
+
| `routesLocaleLinks` | `Record<string, string>`: base name → key for `routeLocales` lookup (e.g. `'products-id'` → `'products'`). |
|
|
158
|
+
| `includeDefaultLocaleRoute` | When set, SEO and links can include the default locale variant. |
|
|
159
|
+
| `noPrefixRedirect` | When `true` (default), `NoPrefixPathStrategy.getRedirect` strips a leading locale segment (e.g. `/en/about` → `/about`). Set to `false` to disable. |
|
|
160
|
+
| `debug` | Enable debug logging. |
|
|
161
|
+
|
|
162
|
+
### Redirect behavior per strategy
|
|
163
|
+
|
|
164
|
+
- **prefix**: root `/` → `/{locale}`; paths without prefix get prefix; wrong prefix is replaced.
|
|
165
|
+
- **prefix_except_default**: default locale with prefix (e.g. `/en/about`) → path without prefix (`/about`); non-default without prefix → add prefix; root with non-default → `/{locale}`.
|
|
166
|
+
- **prefix_and_default**: same as prefix (all locales have prefix in URL).
|
|
167
|
+
- **no_prefix**: paths that start with a locale segment (e.g. `/en/about`) → path without segment (`/about`), unless `noPrefixRedirect` is `false`.
|
|
168
|
+
|
|
169
|
+
### Using getRedirect in middleware
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
const redirectPath = strategy.getRedirect(to.fullPath, detectedLocale)
|
|
173
|
+
if (redirectPath) return navigateTo(redirectPath)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Integration with Nuxt I18n Micro
|
|
179
|
+
|
|
180
|
+
The main Nuxt module (**nuxt-i18n-micro**) integrates path-strategy by default: it generates the strategy from the chosen `strategy` option, creates the instance with runtime config and router, and provides it as `nuxtApp.$i18nStrategy`. The catch-all/fallback component (e.g. `locale-redirect.vue`) calls `strategy.getRedirect(route.fullPath, targetLocale)` and redirects when a path is returned; otherwise it can show 404. No duplicated prefix/custom-path logic when the strategy is provided.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Testing
|
|
185
|
+
|
|
186
|
+
The package is tested with **Jest**. Tests include unit tests for each strategy, `localeRoute`/`switchLocaleRoute`/`getRedirect`/`getSeoAttributes`/`getCanonicalPath`/`getRouteBaseName`, normalizer and path utils, and snapshot tests for documentation and regression.
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
pnpm test
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## License
|
|
195
|
+
|
|
196
|
+
MIT
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const ht=/#/g,ct=/&/g,ut=/\//g,ft=/=/g,Q=/\+/g,Y=/%5e/gi,pt=/%60/gi,dt=/%7b/gi,mt=/%7c/gi,gt=/%7d/gi,Pt=/%20/gi;function Z(a){return encodeURI(""+a).replace(mt,"|")}function yt(a){return Z(a).replace(dt,"{").replace(gt,"}").replace(Y,"^")}function w(a){return Z(typeof a=="string"?a:JSON.stringify(a)).replace(Q,"%2B").replace(Pt,"+").replace(ht,"%23").replace(ct,"%26").replace(pt,"`").replace(Y,"^").replace(ut,"%2F")}function C(a){return w(a).replace(ft,"%3D")}function A(a=""){try{return decodeURIComponent(""+a)}catch{return""+a}}function Rt(a){return A(a.replace(Q," "))}function Lt(a){return A(a.replace(Q," "))}function bt(a=""){const t=Object.create(null);a[0]==="?"&&(a=a.slice(1));for(const e of a.split("&")){const o=e.match(/([^=]+)=?(.*)/)||[];if(o.length<2)continue;const s=Rt(o[1]);if(s==="__proto__"||s==="constructor")continue;const n=Lt(o[2]||"");t[s]===void 0?t[s]=n:Array.isArray(t[s])?t[s].push(n):t[s]=[t[s],n]}return t}function Nt(a,t){return(typeof t=="number"||typeof t=="boolean")&&(t=String(t)),t?Array.isArray(t)?t.map(e=>`${C(a)}=${w(e)}`).join("&"):`${C(a)}=${w(t)}`:C(a)}function xt(a){return Object.keys(a).filter(t=>a[t]!==void 0).map(t=>Nt(t,a[t])).filter(Boolean).join("&")}const zt=/^[\s\w\0+.-]{2,}:([/\\]{1,2})/,vt=/^[\s\w\0+.-]{2,}:([/\\]{2})?/,St=/^([/\\]\s*){2,}[^/\\]/,Bt=/^\.?\//;function W(a,t={}){return typeof t=="boolean"&&(t={acceptRelative:t}),t.strict?zt.test(a):vt.test(a)||(t.acceptRelative?St.test(a):!1)}function Ft(a="",t){return a.endsWith("/")}function v(a="",t){return(Ft(a)?a.slice(0,-1):a)||"/"}function At(a="",t){return a.endsWith("/")?a:a+"/"}function _(a=""){return a.startsWith("/")}function $(a=""){return(_(a)?a.slice(1):a)||"/"}function O(a=""){return _(a)?a:"/"+a}function T(a=""){return a.split("://").map(t=>t.replace(/\/{2,}/g,"/")).join("://")}function Wt(a,t){const e=H(a),o={...bt(e.search),...t};return e.search=xt(o),et(e)}function Ut(a){return!a||a==="/"}function Et(a){return a&&a!=="/"}function I(a,...t){let e=a||"";for(const o of t.filter(s=>Et(s)))if(e){const s=o.replace(Bt,"");e=At(e)+s}else e=o;return e}function _t(a,t){return A(v(a))===A(v(t))}function kt(a,t){if(!t||t==="#")return a;const e=H(a);return e.hash=t===""?"":"#"+yt(t),et(e)}const tt=Symbol.for("ufo:protocolRelative");function H(a="",t){const e=a.match(/^[\s\0]*(blob:|data:|javascript:|vbscript:)(.*)/i);if(e){const[,d,P=""]=e;return{protocol:d.toLowerCase(),pathname:P,href:d+P,auth:"",host:"",search:"",hash:""}}if(!W(a,{acceptRelative:!0}))return U(a);const[,o="",s,n=""]=a.replace(/\\/g,"/").match(/^[\s\0]*([\w+.-]{2,}:)?\/\/([^/@]+@)?(.*)/)||[];let[,r="",l=""]=n.match(/([^#/?]*)(.*)?/)||[];o==="file:"&&(l=l.replace(/\/(?=[A-Za-z]:)/,""));const{pathname:h,search:u,hash:m}=U(l);return{protocol:o.toLowerCase(),auth:s?s.slice(0,Math.max(0,s.length-1)):"",host:r,pathname:h,search:u,hash:m,[tt]:!o}}function U(a=""){const[t="",e="",o=""]=(a.match(/([^#?]*)(\?[^#]*)?(#.*)?/)||[]).splice(1);return{pathname:t,search:e,hash:o}}function et(a){const t=a.pathname||"",e=a.search?(a.search.startsWith("?")?"":"?")+a.search:"",o=a.hash||"",s=a.auth?a.auth+"@":"",n=a.host||"";return(a.protocol||a[tt]?(a.protocol||"")+"//":"")+s+n+t+e+o}const Ct=/\/([^/]+)$/;function wt(a="",t){const{pathname:e}=H(a),o=e.match(Ct);return o?o[1]:void 0}function K(a){return(U(a.startsWith("/")?a:`/${a}`).pathname||"").split("/").filter(Boolean)}const y=a=>Ut(a??"")?"/":O(v(T(a)))||"/";function $t(a){const t=T(a||"/");return v(t)||"/"}function g(...a){const t=a.filter(n=>typeof n=="string"&&n!=="");if(t.length===0)return"/";const[e,...o]=t,s=I(e,...o)||"/";return W(s)?s:O(s)}function D(a){return a&&U(a).pathname||""}function j(a,t,e){let o=Wt(a,t??{});if(e&&e!=="#"){const s=e.startsWith("#")?e.slice(1):e;o=kt(o,s)}return o}function L(a){if(!a)return"";let t="";for(let e=0;e<a.length;e++)t+=a[e]==="-"?"/":a[e];return t}function G(a){if(!a)return"";const t=a.indexOf("-");return t===-1?a:I(a.slice(0,t),a.slice(t+1))}function M(a){if(!a)return"";const t=a.lastIndexOf("-");return t===-1?a:I(a.slice(0,t),a.slice(t+1))}function jt(a){const t=K(a);return t.length>1?t.slice(0,-1).join("-"):""}function qt(a){return wt(a||"/")??""}function E(a,t){const e=a.name?.toString();if(!e)return null;const o=t.localizedRouteNamePrefix||"localized-",s=e.startsWith(o)?e.slice(o.length):e,n=[...t.locales].sort((r,l)=>l.code.length-r.code.length);for(const r of n){const l=`-${r.code}`;if(!s.endsWith(l))continue;const h=s.length-r.code.length-1;if(h>=0&&s[h]==="-")return s.slice(0,-l.length)}return s}function at(a,t,e="localized-"){return`${e}${a}-${t}`}function q(a,t){if(a==null)return!1;const e=String(a).trim();if(e===""||e==="index")return!0;const o=t?.localizedRouteNamePrefix??"localized-",s=t?.localeCodes??[],n=`${o}index-`;if(!e.startsWith(n))return!1;const r=e.slice(n.length);return s.length===0?r.length>=2:s.includes(r)}function V(a,t){const e=D(a),o=y(e);if(o==="/")return{pathWithoutLocale:"/",localeFromPath:null};if(!_(o))return{pathWithoutLocale:o,localeFromPath:null};const s=o.indexOf("/",1),n=s===-1?o.slice(1):o.slice(1,s);if(n&&t.includes(n)){const r=1+n.length,l=o.slice(r);return{pathWithoutLocale:y(l||"/"),localeFromPath:n}}return{pathWithoutLocale:o,localeFromPath:null}}function st(a,t){const e=D(a);if(e==="/"||e===""||!_(e))return null;const o=e.indexOf("/",1),s=o===-1?e.slice(1):e.slice(1,o);return s&&t.includes(s)?s:null}function Qt(a){return a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}class ot{constructor(t){this.ctx=t}resolvePathWithParams(t,e={}){let o=t;for(const s in e){const n=e[s];if(n==null||n==="")continue;const r=Array.isArray(n)?n.join("/"):String(n),l=Qt(s),h=new RegExp(`:${l}\\(\\)|:${l}(?![\\w])|\\[\\.\\.\\.${l}\\]`,"g");o=o.replace(h,r)}return o}analyzeRoute(t){const e=this.ctx.locales.map(n=>n.code),{pathWithoutLocale:o}=V(t.path||"/",e);let s=null;return t.name&&(s=E(t,{locales:this.ctx.locales,localizedRouteNamePrefix:this.ctx.localizedRouteNamePrefix||"localized-"})),{pathWithoutLocale:o,baseRouteName:s}}getPathWithoutLocaleAndBaseName(t){return this.analyzeRoute(t)}getLookupKeys(t,e){const o=[];o.push(t);const s=$(t);if(s!==t&&o.push(s),(t==="/"||s==="")&&o.push(""),e){o.push(`/${e}`),o.push(e);const n=L(e);n&&n!==e&&o.push(n);const r=G(e);r&&o.push(r);const l=M(e);l&&o.push(l)}return o}resolveCustomPath(t,e){const o=this.ctx.globalLocaleRoutes;if(!o||Object.keys(o).length===0)return null;const{pathWithoutLocale:s,baseRouteName:n}=this.analyzeRoute(t),r=this.getLookupKeys(s,n);for(const l of r){const h=o[l];if(h&&typeof h=="object"&&!Array.isArray(h)){const u=h[e];if(typeof u=="string")return this.resolvePathWithParams(u,t.params??{})}}return null}getPathForUnlocalizedRoute(t){const e=this.ctx.globalLocaleRoutes;if(!e)return null;const{pathWithoutLocale:o,baseRouteName:s}=this.analyzeRoute(t),n=this.getLookupKeys(o,s);for(const r of n)if(e[r]===!1){if(s&&(r===s||r===`/${s}`)){const l=L(s);return l?g("/",l):`/${s}`}return o}return null}getPathForUnlocalizedRouteByName(t){const e=this.ctx.globalLocaleRoutes;if(!e)return null;const o=[t,`/${t}`,$(t)];for(const s of o)if(e[s]===!1){const n=L(s.startsWith("/")?s.slice(1):s);return n?g("/",n):s.startsWith("/")?s:`/${s}`}return null}getAllowedLocalesForRoute(t){const e=this.ctx.routeLocales;if(!e||Object.keys(e).length===0)return this.ctx.locales.map(r=>r.code);const{pathWithoutLocale:o,baseRouteName:s}=this.analyzeRoute(t);let n=this.getLookupKeys(o,s);s&&this.ctx.routesLocaleLinks?.[s]&&(n=[this.ctx.routesLocaleLinks[s],...n]);for(const r of n){const l=e[r];if(Array.isArray(l)&&l.length>0)return l.filter(h=>this.ctx.locales.some(u=>u.code===h))}return this.ctx.locales.map(r=>r.code)}getParentPathForNested(t,e){if(t.length<=1)return"/";const o=t.length>1?t.slice(0,-1).join("-"):"",s=this.ctx.globalLocaleRoutes;if(o&&s?.[o]&&typeof s[o]=="object"){const n=s[o];if(n[e])return y(n[e])}return g("/",...t.slice(0,-1))}}class Ot{constructor(t){this.ctx=t,this.resolver=new ot(t)}setRouter(t){this.ctx.router=t}getDefaultLocale(){return this.ctx.defaultLocale}getLocales(){return this.ctx.locales}getStrategy(){return this.ctx.strategy}getLocalizedRouteNamePrefix(){return this.ctx.localizedRouteNamePrefix||"localized-"}getGlobalLocaleRoutes(){return this.ctx.globalLocaleRoutes}getRouteLocales(){return this.ctx.routeLocales}getRoutesLocaleLinks(){return this.ctx.routesLocaleLinks}getNoPrefixRedirect(){return this.ctx.noPrefixRedirect}getBaseRouteName(t,e){return E(t,{locales:[{code:e}],localizedRouteNamePrefix:this.getLocalizedRouteNamePrefix()})}getRouteBaseName(t){return E(t,{locales:this.ctx.locales,localizedRouteNamePrefix:this.getLocalizedRouteNamePrefix()})}resolvePathForLocale(t,e){const o={path:t,name:null,fullPath:t,params:{}},s=this.resolver.resolveCustomPath(o,e);return y(s||t)}buildLocalizedName(t,e){return at(t,e,this.getLocalizedRouteNamePrefix())}getLocaleObject(t){return this.ctx.locales.find(e=>e.code===t)}applyBaseUrl(t,e){if(typeof e=="string"){if(W(e))return e}else if(e.path&&W(e.path))return e;const o=this.getLocaleObject(t);if(!o?.baseUrl)return e;const s=v(o.baseUrl);if(typeof e=="string"){const l=y(e.startsWith("/")?e:`/${e}`);return g(s,l)}const n=y(e.path||""),r=g(s,n);return{...e,path:r,fullPath:r}}preserveQueryAndHash(t,e){if(!e||!e.query&&!e.hash)return t;const o=typeof t=="string"?{path:t}:{...t};e.query&&(o.query={...e.query,...o.query}),!o.hash&&e.hash&&(o.hash=e.hash);const s=o.path??"";return o.fullPath=j(s,o.query,o.hash),o}resolvePathWithParams(t,e={}){return this.resolver.resolvePathWithParams(t,e)}getPathWithoutLocaleAndBaseName(t){return this.resolver.getPathWithoutLocaleAndBaseName(t)}getCustomPathSegment(t,e){return this.resolver.resolveCustomPath(t,e)}getAllowedLocalesForRoute(t){return this.resolver.getAllowedLocalesForRoute(t)}getCanonicalPath(t,e){return null}getPathForUnlocalizedRouteByName(t){return this.resolver.getPathForUnlocalizedRouteByName(t)}tryResolveByLocalizedName(t,e,o){const s=`${this.getLocalizedRouteNamePrefix()}${t}-${e}`,n=this.ctx.router.hasRoute(s);if(this.debugLog("tryResolveByLocalizedName",{routeName:t,targetLocale:e,localizedName:s,hasRoute:n}),!n)return null;const r=this.ctx.router.resolve({name:s,params:o?.params,query:o?.query,hash:o?.hash});return this.debugLog("tryResolveByLocalizedName resolved",{localizedName:s,path:r?.path,fullPath:r?.fullPath}),r?.path?{name:s,path:r.path,fullPath:r.fullPath,params:r.params,query:r.query??o?.query,hash:r.hash??o?.hash}:null}tryResolveByLocalizedNameWithParams(t,e,o,s){const n=`${this.getLocalizedRouteNamePrefix()}${t}-${e}`,r=this.ctx.router.hasRoute(n);if(this.debugLog("tryResolveByLocalizedNameWithParams",{routeName:t,targetLocale:e,params:o,localizedName:n,hasRoute:r}),!r)return null;const l=this.ctx.router.resolve({name:n,params:o,query:s?.query,hash:s?.hash});return this.debugLog("tryResolveByLocalizedNameWithParams resolved",{path:l?.path,fullPath:l?.fullPath}),!l?.path||l.path==="/"?null:{name:n,path:l.path,fullPath:l.fullPath,params:l.params,query:l.query??s?.query,hash:l.hash??s?.hash}}getPathForUnlocalizedRoute(t){return this.resolver.getPathForUnlocalizedRoute(t)}buildPathFromBaseNameAndParams(t,e,o){const s=Object.keys(e).filter(m=>e[m]!==void 0&&e[m]!==null&&e[m]!=="");if(s.length===0)return null;let n;const r=s[0];if(s.length===1&&r!==void 0&&t.endsWith("-"+r))n=g("/",t.slice(0,t.length-r.length-1)+"-:"+r);else{const m=L(t),d=m?m.split("/").filter(Boolean):[t],P=Math.min(s.length,d.length),R=d.slice(0,d.length-P).concat(s.slice(0,P).map(S=>`:${S}`));n=g("/",...R)}const l=this.resolvePathWithParams(n,e),h=this.buildLocalizedPath(l,o,!1),u=this.applyBaseUrl(o,h);return typeof u=="string"?u:u.path??h}getPathWithoutLocale(t){return V(t,this.ctx.locales.map(e=>e.code))}getLocaleFromPath(t){return st(t,this.ctx.locales.map(e=>e.code))}getSeoAttributes(t){const e=this.resolveLocaleFromPath(t.path)??this.ctx.defaultLocale,o=this.getCanonicalPath(t,e)??t.path,s=this.buildFullUrl(e,o),n=this.getAllowedLocalesForRoute(t),l=this.ctx.locales.filter(h=>n.includes(h.code)).map(h=>{const u=this.localeRoute(h.code,t,t),d=(u.path??u.fullPath??"")||"/";return{rel:"alternate",hreflang:h.code,href:this.buildFullUrl(h.code,d)}});return{canonical:s,hreflangs:l}}buildFullUrl(t,e){const o=this.applyBaseUrl(t,e);return typeof o=="string"?o:o.path??e}getSwitchLocaleFallbackWhenNoRoute(t,e){return{...t,name:e}}switchLocaleRoute(t,e,o,s){const n=this.getBaseRouteName(o,t);if(!n)return o;let r=this.buildLocalizedRouteName(n,e);if(!this.ctx.router.hasRoute(r))if(this.ctx.router.hasRoute(n))r=n;else return this.getSwitchLocaleFallbackWhenNoRoute(o,r);const l=s.i18nRouteParams?.[e]||{},h={...o.params||{},...l};delete h.locale;const u={name:r,params:h,query:o.query,hash:o.hash};return this.applyBaseUrl(e,u)}localeRoute(t,e,o){const s=this.normalizeRouteInput(e,o),n=this.resolveLocaleRoute(t,s,o);this.debugLog("localeRoute raw",{rawPath:typeof n=="string"?n:n.path,rawFullPath:typeof n=="string"?n:n.fullPath});const r=this.ensureRouteLike(n,s.kind==="route"?s.sourceRoute:void 0);return this.debugLog("localeRoute after ensureRouteLike",{path:r.path,fullPath:r.fullPath}),r}ensureRouteLike(t,e){if(typeof t=="string"){const n=t,r=e?.query||e?.hash?j(n,e?.query,e?.hash):n;return{path:n,fullPath:r,...e?.query&&{query:e.query},...e?.hash&&{hash:e.hash}}}let o=t.fullPath??t.path??"",s=t.path??o.split("?")[0]?.split("#")[0]??o;if(!s&&!o){const n=t.name?.toString()??e?.name?.toString()??"";q(n,{localizedRouteNamePrefix:this.getLocalizedRouteNamePrefix(),localeCodes:this.ctx.locales.map(r=>r.code)})&&(s="/",o="/")}return{...t,path:s,fullPath:o}}normalizeRouteInput(t,e){if(typeof t=="string")return{kind:"path",path:t};const o=t,s=o.name?.toString()??null;let n;try{n=this.ctx.router.resolve(t),this.debugLog("normalizeRouteInput router.resolve ok",{inputName:s,resolvedPath:n.path,resolvedName:n.name})}catch{n={name:s,path:o.path??"/",fullPath:o.fullPath??o.path??"/",params:o.params??{},query:o.query??{},hash:o.hash??""},this.debugLog("normalizeRouteInput router.resolve catch fallback",{inputName:s,resolvedPath:n.path})}return{kind:"route",inputName:s,sourceRoute:o,resolved:n}}debugLog(...t){}resolveLocaleRoute(t,e,o){if(e.kind==="path"){const i=this.resolvePathForLocale(e.path,t),c=this.buildLocalizedPath(i,t,!1),f=this.applyBaseUrl(t,c);return this.debugLog("branch=path",{targetLocale:t,path:e.path,finalPath:c,out:typeof f=="string"?f:f.path}),f}const{inputName:s,sourceRoute:n,resolved:r}=e,l=n.params&&Object.keys(n.params??{}).length>0,h=this.getRouteBaseName(r)??s??r.name?.toString()??null,u=r.name?.toString();if(this.debugLog("input",{targetLocale:t,inputName:s,resolvedPath:r.path,resolvedName:r.name,params:n.params,hasParams:l,baseName:h}),s){const i=this.getPathForUnlocalizedRouteByName(s);if(i!==null)return this.debugLog("branch=unlocalizedByName",{inputName:s,unlocalizedByName:i}),this.preserveQueryAndHash(i,n)}if(s&&l){const i=this.tryResolveByLocalizedNameWithParams(s,t,n.params??{},n);if(i!==null)return this.debugLog("branch=routeWithParams",{inputName:s,path:i.path,fullPath:i.fullPath}),this.preserveQueryAndHash(this.applyBaseUrl(t,i),n)}if(s&&!l){let i=this.tryResolveByLocalizedName(s,t,n);const c=this.getLocalizedRouteNamePrefix();if(i===null&&h!=null&&h!==s&&s.startsWith(c)&&(i=this.tryResolveByLocalizedName(h,t,n)),i!==null)return this.debugLog("branch=routeByLocalizedName",{inputName:s,path:i.path,fullPath:i.fullPath}),this.preserveQueryAndHash(this.applyBaseUrl(t,i),n)}const m=this.getPathForUnlocalizedRoute(r);if(m!==null){const i=this.buildLocalizedPath(m,t,!1);return this.debugLog("branch=unlocalizedPath",{unlocalizedPath:m,path:i}),this.preserveQueryAndHash(this.applyBaseUrl(t,i),n)}const d=this.getCustomPathSegment(r,t);if(d!==null){const i=r.name?.toString()??s??"",c=i?G(i):"",f=i?M(i):"",p=this.ctx.globalLocaleRoutes,x=c.includes("/")&&p?.[c],N=f.includes("/")&&p?.[f],nt=x||N,rt=N?f:c;let F;if(nt){const k=K(rt),z=k.length>1?k.slice(0,-1).join("-"):"",J=z&&p?.[z]&&typeof p[z]=="object"&&!Array.isArray(p[z])?p[z]:null,lt=J?.[t]?y(J[t]):g("/",...k.slice(0,-1)),it=d.startsWith("/")?d.slice(1):d;F=g(lt,it)}else F=y(d);const X=this.buildLocalizedPath(F,t,!0);return this.debugLog("branch=customSegment",{customSegment:d,pathWithoutLocale:F,finalPath:X}),this.preserveQueryAndHash(this.applyBaseUrl(t,X),n)}const P=h??s;if(this.debugLog("before effectiveBaseName check",{baseName:h,inputName:s,effectiveBaseName:P,resolvedName:r.name?.toString()}),!P)return this.debugLog("branch=noBaseName",{return:"src"}),n;if(!l&&r.path&&r.path!=="/"&&r.name){const{pathWithoutLocale:i,baseRouteName:c}=this.getPathWithoutLocaleAndBaseName(r);if(i&&i!=="/"){const f=c&&i===c?g("/",L(c)):i,p=this.buildLocalizedPath(f,t,!1);return this.debugLog("branch=pathFromResolved",{pathWithoutLocale:i,baseRouteName:c,pathToUse:f,finalPath:p}),this.preserveQueryAndHash(this.applyBaseUrl(t,p),n)}}const R=u===s?P:s??P;this.debugLog("fallback build",{resolvedNameStr:u,inputName:s,baseNameForPath:R,targetLocale:t,hasParams:l});const S=this.buildLocalizedRouteName(R,t),b={...n,name:S,params:{...n.params}};if(l){let i=null;try{const c=this.ctx.router.resolve({name:R,params:n.params});if(c?.path){const f=c.path==="/"?"/":(()=>{const{pathWithoutLocale:N}=this.getPathWithoutLocale(c.path);return N&&N!=="/"?N:c.path})(),p=this.buildLocalizedPath(f,t,!1),x=this.applyBaseUrl(t,p);i=typeof x=="string"?x:x.path??p}}catch{i=this.buildPathFromBaseNameAndParams(R,n.params??{},t)}i&&(b.path=i,b.fullPath=i)}else{const i=q(R)?"/":g("/",L(R)),c=this.buildLocalizedPath(i,t,!1),f=this.applyBaseUrl(t,c),p=typeof f=="string"?f:f.path??c;this.debugLog("fallback !hasParams",{pathWithoutLocale:i,finalPath:c,pathStr:p}),b.path=p,b.fullPath=p}const B=this.preserveQueryAndHash(this.applyBaseUrl(t,b),n);return this.debugLog("branch=fallbackNewRoute return",{baseName:h,targetName:S,hasParams:l,newRoutePath:b.path,outPath:typeof B=="string"?B:B.path}),B}}exports.BasePathStrategy=Ot;exports.RouteResolver=ot;exports.buildLocalizedName=at;exports.buildUrl=j;exports.cleanDoubleSlashes=T;exports.getCleanPath=D;exports.getLocaleFromPath=st;exports.getPathSegments=K;exports.getPathWithoutLocale=V;exports.getRouteBaseName=E;exports.isIndexRouteName=q;exports.isSamePath=_t;exports.joinUrl=g;exports.lastPathSegment=qt;exports.nameKeyFirstSlash=G;exports.nameKeyLastSlash=M;exports.normalizePath=y;exports.normalizePathForCompare=$t;exports.parentKeyFromSlashKey=jt;exports.transformNameKeyToPath=L;exports.withLeadingSlash=O;exports.withoutLeadingSlash=$;
|
|
2
|
+
//# sourceMappingURL=base-strategy-B5mBf3XX.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-strategy-B5mBf3XX.cjs","sources":["../../../node_modules/.pnpm/ufo@1.6.1/node_modules/ufo/dist/index.mjs","../src/utils/path.ts","../src/utils/route-name.ts","../src/core/normalizer.ts","../src/core/resolver.ts","../src/strategies/base-strategy.ts"],"sourcesContent":["const n = /[^\\0-\\x7E]/;\nconst t = /[\\x2E\\u3002\\uFF0E\\uFF61]/g;\nconst o = {\n overflow: \"Overflow Error\",\n \"not-basic\": \"Illegal Input\",\n \"invalid-input\": \"Invalid Input\"\n};\nconst e = Math.floor;\nconst r = String.fromCharCode;\nfunction s(n2) {\n throw new RangeError(o[n2]);\n}\nconst c = function(n2, t2) {\n return n2 + 22 + 75 * (n2 < 26) - ((t2 != 0) << 5);\n};\nconst u = function(n2, t2, o2) {\n let r2 = 0;\n for (n2 = o2 ? e(n2 / 700) : n2 >> 1, n2 += e(n2 / t2); n2 > 455; r2 += 36) {\n n2 = e(n2 / 35);\n }\n return e(r2 + 36 * n2 / (n2 + 38));\n};\nfunction toASCII(o2) {\n return function(n2, o3) {\n const e2 = n2.split(\"@\");\n let r2 = \"\";\n e2.length > 1 && (r2 = e2[0] + \"@\", n2 = e2[1]);\n const s2 = function(n3, t2) {\n const o4 = [];\n let e3 = n3.length;\n for (; e3--; ) {\n o4[e3] = t2(n3[e3]);\n }\n return o4;\n }((n2 = n2.replace(t, \".\")).split(\".\"), o3).join(\".\");\n return r2 + s2;\n }(o2, function(t2) {\n return n.test(t2) ? \"xn--\" + function(n2) {\n const t3 = [];\n const o3 = (n2 = function(n3) {\n const t4 = [];\n let o4 = 0;\n const e2 = n3.length;\n for (; o4 < e2; ) {\n const r2 = n3.charCodeAt(o4++);\n if (r2 >= 55296 && r2 <= 56319 && o4 < e2) {\n const e3 = n3.charCodeAt(o4++);\n (64512 & e3) == 56320 ? t4.push(((1023 & r2) << 10) + (1023 & e3) + 65536) : (t4.push(r2), o4--);\n } else {\n t4.push(r2);\n }\n }\n return t4;\n }(n2)).length;\n let f = 128;\n let i = 0;\n let l = 72;\n for (const o4 of n2) {\n o4 < 128 && t3.push(r(o4));\n }\n const h = t3.length;\n let p = h;\n for (h && t3.push(\"-\"); p < o3; ) {\n let o4 = 2147483647;\n for (const t4 of n2) {\n t4 >= f && t4 < o4 && (o4 = t4);\n }\n const a = p + 1;\n o4 - f > e((2147483647 - i) / a) && s(\"overflow\"), i += (o4 - f) * a, f = o4;\n for (const o5 of n2) {\n if (o5 < f && ++i > 2147483647 && s(\"overflow\"), o5 == f) {\n let n3 = i;\n for (let o6 = 36; ; o6 += 36) {\n const s2 = o6 <= l ? 1 : o6 >= l + 26 ? 26 : o6 - l;\n if (n3 < s2) {\n break;\n }\n const u2 = n3 - s2;\n const f2 = 36 - s2;\n t3.push(r(c(s2 + u2 % f2, 0))), n3 = e(u2 / f2);\n }\n t3.push(r(c(n3, 0))), l = u(i, a, p == h), i = 0, ++p;\n }\n }\n ++i, ++f;\n }\n return t3.join(\"\");\n }(t2) : t2;\n });\n}\n\nconst HASH_RE = /#/g;\nconst AMPERSAND_RE = /&/g;\nconst SLASH_RE = /\\//g;\nconst EQUAL_RE = /=/g;\nconst IM_RE = /\\?/g;\nconst PLUS_RE = /\\+/g;\nconst ENC_CARET_RE = /%5e/gi;\nconst ENC_BACKTICK_RE = /%60/gi;\nconst ENC_CURLY_OPEN_RE = /%7b/gi;\nconst ENC_PIPE_RE = /%7c/gi;\nconst ENC_CURLY_CLOSE_RE = /%7d/gi;\nconst ENC_SPACE_RE = /%20/gi;\nconst ENC_SLASH_RE = /%2f/gi;\nconst ENC_ENC_SLASH_RE = /%252f/gi;\nfunction encode(text) {\n return encodeURI(\"\" + text).replace(ENC_PIPE_RE, \"|\");\n}\nfunction encodeHash(text) {\n return encode(text).replace(ENC_CURLY_OPEN_RE, \"{\").replace(ENC_CURLY_CLOSE_RE, \"}\").replace(ENC_CARET_RE, \"^\");\n}\nfunction encodeQueryValue(input) {\n return encode(typeof input === \"string\" ? input : JSON.stringify(input)).replace(PLUS_RE, \"%2B\").replace(ENC_SPACE_RE, \"+\").replace(HASH_RE, \"%23\").replace(AMPERSAND_RE, \"%26\").replace(ENC_BACKTICK_RE, \"`\").replace(ENC_CARET_RE, \"^\").replace(SLASH_RE, \"%2F\");\n}\nfunction encodeQueryKey(text) {\n return encodeQueryValue(text).replace(EQUAL_RE, \"%3D\");\n}\nfunction encodePath(text) {\n return encode(text).replace(HASH_RE, \"%23\").replace(IM_RE, \"%3F\").replace(ENC_ENC_SLASH_RE, \"%2F\").replace(AMPERSAND_RE, \"%26\").replace(PLUS_RE, \"%2B\");\n}\nfunction encodeParam(text) {\n return encodePath(text).replace(SLASH_RE, \"%2F\");\n}\nfunction decode(text = \"\") {\n try {\n return decodeURIComponent(\"\" + text);\n } catch {\n return \"\" + text;\n }\n}\nfunction decodePath(text) {\n return decode(text.replace(ENC_SLASH_RE, \"%252F\"));\n}\nfunction decodeQueryKey(text) {\n return decode(text.replace(PLUS_RE, \" \"));\n}\nfunction decodeQueryValue(text) {\n return decode(text.replace(PLUS_RE, \" \"));\n}\nfunction encodeHost(name = \"\") {\n return toASCII(name);\n}\n\nfunction parseQuery(parametersString = \"\") {\n const object = /* @__PURE__ */ Object.create(null);\n if (parametersString[0] === \"?\") {\n parametersString = parametersString.slice(1);\n }\n for (const parameter of parametersString.split(\"&\")) {\n const s = parameter.match(/([^=]+)=?(.*)/) || [];\n if (s.length < 2) {\n continue;\n }\n const key = decodeQueryKey(s[1]);\n if (key === \"__proto__\" || key === \"constructor\") {\n continue;\n }\n const value = decodeQueryValue(s[2] || \"\");\n if (object[key] === void 0) {\n object[key] = value;\n } else if (Array.isArray(object[key])) {\n object[key].push(value);\n } else {\n object[key] = [object[key], value];\n }\n }\n return object;\n}\nfunction encodeQueryItem(key, value) {\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n value = String(value);\n }\n if (!value) {\n return encodeQueryKey(key);\n }\n if (Array.isArray(value)) {\n return value.map(\n (_value) => `${encodeQueryKey(key)}=${encodeQueryValue(_value)}`\n ).join(\"&\");\n }\n return `${encodeQueryKey(key)}=${encodeQueryValue(value)}`;\n}\nfunction stringifyQuery(query) {\n return Object.keys(query).filter((k) => query[k] !== void 0).map((k) => encodeQueryItem(k, query[k])).filter(Boolean).join(\"&\");\n}\n\nconst PROTOCOL_STRICT_REGEX = /^[\\s\\w\\0+.-]{2,}:([/\\\\]{1,2})/;\nconst PROTOCOL_REGEX = /^[\\s\\w\\0+.-]{2,}:([/\\\\]{2})?/;\nconst PROTOCOL_RELATIVE_REGEX = /^([/\\\\]\\s*){2,}[^/\\\\]/;\nconst PROTOCOL_SCRIPT_RE = /^[\\s\\0]*(blob|data|javascript|vbscript):$/i;\nconst TRAILING_SLASH_RE = /\\/$|\\/\\?|\\/#/;\nconst JOIN_LEADING_SLASH_RE = /^\\.?\\//;\nfunction isRelative(inputString) {\n return [\"./\", \"../\"].some((string_) => inputString.startsWith(string_));\n}\nfunction hasProtocol(inputString, opts = {}) {\n if (typeof opts === \"boolean\") {\n opts = { acceptRelative: opts };\n }\n if (opts.strict) {\n return PROTOCOL_STRICT_REGEX.test(inputString);\n }\n return PROTOCOL_REGEX.test(inputString) || (opts.acceptRelative ? PROTOCOL_RELATIVE_REGEX.test(inputString) : false);\n}\nfunction isScriptProtocol(protocol) {\n return !!protocol && PROTOCOL_SCRIPT_RE.test(protocol);\n}\nfunction hasTrailingSlash(input = \"\", respectQueryAndFragment) {\n if (!respectQueryAndFragment) {\n return input.endsWith(\"/\");\n }\n return TRAILING_SLASH_RE.test(input);\n}\nfunction withoutTrailingSlash(input = \"\", respectQueryAndFragment) {\n if (!respectQueryAndFragment) {\n return (hasTrailingSlash(input) ? input.slice(0, -1) : input) || \"/\";\n }\n if (!hasTrailingSlash(input, true)) {\n return input || \"/\";\n }\n let path = input;\n let fragment = \"\";\n const fragmentIndex = input.indexOf(\"#\");\n if (fragmentIndex !== -1) {\n path = input.slice(0, fragmentIndex);\n fragment = input.slice(fragmentIndex);\n }\n const [s0, ...s] = path.split(\"?\");\n const cleanPath = s0.endsWith(\"/\") ? s0.slice(0, -1) : s0;\n return (cleanPath || \"/\") + (s.length > 0 ? `?${s.join(\"?\")}` : \"\") + fragment;\n}\nfunction withTrailingSlash(input = \"\", respectQueryAndFragment) {\n if (!respectQueryAndFragment) {\n return input.endsWith(\"/\") ? input : input + \"/\";\n }\n if (hasTrailingSlash(input, true)) {\n return input || \"/\";\n }\n let path = input;\n let fragment = \"\";\n const fragmentIndex = input.indexOf(\"#\");\n if (fragmentIndex !== -1) {\n path = input.slice(0, fragmentIndex);\n fragment = input.slice(fragmentIndex);\n if (!path) {\n return fragment;\n }\n }\n const [s0, ...s] = path.split(\"?\");\n return s0 + \"/\" + (s.length > 0 ? `?${s.join(\"?\")}` : \"\") + fragment;\n}\nfunction hasLeadingSlash(input = \"\") {\n return input.startsWith(\"/\");\n}\nfunction withoutLeadingSlash(input = \"\") {\n return (hasLeadingSlash(input) ? input.slice(1) : input) || \"/\";\n}\nfunction withLeadingSlash(input = \"\") {\n return hasLeadingSlash(input) ? input : \"/\" + input;\n}\nfunction cleanDoubleSlashes(input = \"\") {\n return input.split(\"://\").map((string_) => string_.replace(/\\/{2,}/g, \"/\")).join(\"://\");\n}\nfunction withBase(input, base) {\n if (isEmptyURL(base) || hasProtocol(input)) {\n return input;\n }\n const _base = withoutTrailingSlash(base);\n if (input.startsWith(_base)) {\n return input;\n }\n return joinURL(_base, input);\n}\nfunction withoutBase(input, base) {\n if (isEmptyURL(base)) {\n return input;\n }\n const _base = withoutTrailingSlash(base);\n if (!input.startsWith(_base)) {\n return input;\n }\n const trimmed = input.slice(_base.length);\n return trimmed[0] === \"/\" ? trimmed : \"/\" + trimmed;\n}\nfunction withQuery(input, query) {\n const parsed = parseURL(input);\n const mergedQuery = { ...parseQuery(parsed.search), ...query };\n parsed.search = stringifyQuery(mergedQuery);\n return stringifyParsedURL(parsed);\n}\nfunction filterQuery(input, predicate) {\n if (!input.includes(\"?\")) {\n return input;\n }\n const parsed = parseURL(input);\n const query = parseQuery(parsed.search);\n const filteredQuery = Object.fromEntries(\n Object.entries(query).filter(([key, value]) => predicate(key, value))\n );\n parsed.search = stringifyQuery(filteredQuery);\n return stringifyParsedURL(parsed);\n}\nfunction getQuery(input) {\n return parseQuery(parseURL(input).search);\n}\nfunction isEmptyURL(url) {\n return !url || url === \"/\";\n}\nfunction isNonEmptyURL(url) {\n return url && url !== \"/\";\n}\nfunction joinURL(base, ...input) {\n let url = base || \"\";\n for (const segment of input.filter((url2) => isNonEmptyURL(url2))) {\n if (url) {\n const _segment = segment.replace(JOIN_LEADING_SLASH_RE, \"\");\n url = withTrailingSlash(url) + _segment;\n } else {\n url = segment;\n }\n }\n return url;\n}\nfunction joinRelativeURL(..._input) {\n const JOIN_SEGMENT_SPLIT_RE = /\\/(?!\\/)/;\n const input = _input.filter(Boolean);\n const segments = [];\n let segmentsDepth = 0;\n for (const i of input) {\n if (!i || i === \"/\") {\n continue;\n }\n for (const [sindex, s] of i.split(JOIN_SEGMENT_SPLIT_RE).entries()) {\n if (!s || s === \".\") {\n continue;\n }\n if (s === \"..\") {\n if (segments.length === 1 && hasProtocol(segments[0])) {\n continue;\n }\n segments.pop();\n segmentsDepth--;\n continue;\n }\n if (sindex === 1 && segments[segments.length - 1]?.endsWith(\":/\")) {\n segments[segments.length - 1] += \"/\" + s;\n continue;\n }\n segments.push(s);\n segmentsDepth++;\n }\n }\n let url = segments.join(\"/\");\n if (segmentsDepth >= 0) {\n if (input[0]?.startsWith(\"/\") && !url.startsWith(\"/\")) {\n url = \"/\" + url;\n } else if (input[0]?.startsWith(\"./\") && !url.startsWith(\"./\")) {\n url = \"./\" + url;\n }\n } else {\n url = \"../\".repeat(-1 * segmentsDepth) + url;\n }\n if (input[input.length - 1]?.endsWith(\"/\") && !url.endsWith(\"/\")) {\n url += \"/\";\n }\n return url;\n}\nfunction withHttp(input) {\n return withProtocol(input, \"http://\");\n}\nfunction withHttps(input) {\n return withProtocol(input, \"https://\");\n}\nfunction withoutProtocol(input) {\n return withProtocol(input, \"\");\n}\nfunction withProtocol(input, protocol) {\n let match = input.match(PROTOCOL_REGEX);\n if (!match) {\n match = input.match(/^\\/{2,}/);\n }\n if (!match) {\n return protocol + input;\n }\n return protocol + input.slice(match[0].length);\n}\nfunction normalizeURL(input) {\n const parsed = parseURL(input);\n parsed.pathname = encodePath(decodePath(parsed.pathname));\n parsed.hash = encodeHash(decode(parsed.hash));\n parsed.host = encodeHost(decode(parsed.host));\n parsed.search = stringifyQuery(parseQuery(parsed.search));\n return stringifyParsedURL(parsed);\n}\nfunction resolveURL(base = \"\", ...inputs) {\n if (typeof base !== \"string\") {\n throw new TypeError(\n `URL input should be string received ${typeof base} (${base})`\n );\n }\n const filteredInputs = inputs.filter((input) => isNonEmptyURL(input));\n if (filteredInputs.length === 0) {\n return base;\n }\n const url = parseURL(base);\n for (const inputSegment of filteredInputs) {\n const urlSegment = parseURL(inputSegment);\n if (urlSegment.pathname) {\n url.pathname = withTrailingSlash(url.pathname) + withoutLeadingSlash(urlSegment.pathname);\n }\n if (urlSegment.hash && urlSegment.hash !== \"#\") {\n url.hash = urlSegment.hash;\n }\n if (urlSegment.search && urlSegment.search !== \"?\") {\n if (url.search && url.search !== \"?\") {\n const queryString = stringifyQuery({\n ...parseQuery(url.search),\n ...parseQuery(urlSegment.search)\n });\n url.search = queryString.length > 0 ? \"?\" + queryString : \"\";\n } else {\n url.search = urlSegment.search;\n }\n }\n }\n return stringifyParsedURL(url);\n}\nfunction isSamePath(p1, p2) {\n return decode(withoutTrailingSlash(p1)) === decode(withoutTrailingSlash(p2));\n}\nfunction isEqual(a, b, options = {}) {\n if (!options.trailingSlash) {\n a = withTrailingSlash(a);\n b = withTrailingSlash(b);\n }\n if (!options.leadingSlash) {\n a = withLeadingSlash(a);\n b = withLeadingSlash(b);\n }\n if (!options.encoding) {\n a = decode(a);\n b = decode(b);\n }\n return a === b;\n}\nfunction withFragment(input, hash) {\n if (!hash || hash === \"#\") {\n return input;\n }\n const parsed = parseURL(input);\n parsed.hash = hash === \"\" ? \"\" : \"#\" + encodeHash(hash);\n return stringifyParsedURL(parsed);\n}\nfunction withoutFragment(input) {\n return stringifyParsedURL({ ...parseURL(input), hash: \"\" });\n}\nfunction withoutHost(input) {\n const parsed = parseURL(input);\n return (parsed.pathname || \"/\") + parsed.search + parsed.hash;\n}\n\nconst protocolRelative = Symbol.for(\"ufo:protocolRelative\");\nfunction parseURL(input = \"\", defaultProto) {\n const _specialProtoMatch = input.match(\n /^[\\s\\0]*(blob:|data:|javascript:|vbscript:)(.*)/i\n );\n if (_specialProtoMatch) {\n const [, _proto, _pathname = \"\"] = _specialProtoMatch;\n return {\n protocol: _proto.toLowerCase(),\n pathname: _pathname,\n href: _proto + _pathname,\n auth: \"\",\n host: \"\",\n search: \"\",\n hash: \"\"\n };\n }\n if (!hasProtocol(input, { acceptRelative: true })) {\n return defaultProto ? parseURL(defaultProto + input) : parsePath(input);\n }\n const [, protocol = \"\", auth, hostAndPath = \"\"] = input.replace(/\\\\/g, \"/\").match(/^[\\s\\0]*([\\w+.-]{2,}:)?\\/\\/([^/@]+@)?(.*)/) || [];\n let [, host = \"\", path = \"\"] = hostAndPath.match(/([^#/?]*)(.*)?/) || [];\n if (protocol === \"file:\") {\n path = path.replace(/\\/(?=[A-Za-z]:)/, \"\");\n }\n const { pathname, search, hash } = parsePath(path);\n return {\n protocol: protocol.toLowerCase(),\n auth: auth ? auth.slice(0, Math.max(0, auth.length - 1)) : \"\",\n host,\n pathname,\n search,\n hash,\n [protocolRelative]: !protocol\n };\n}\nfunction parsePath(input = \"\") {\n const [pathname = \"\", search = \"\", hash = \"\"] = (input.match(/([^#?]*)(\\?[^#]*)?(#.*)?/) || []).splice(1);\n return {\n pathname,\n search,\n hash\n };\n}\nfunction parseAuth(input = \"\") {\n const [username, password] = input.split(\":\");\n return {\n username: decode(username),\n password: decode(password)\n };\n}\nfunction parseHost(input = \"\") {\n const [hostname, port] = (input.match(/([^/:]*):?(\\d+)?/) || []).splice(1);\n return {\n hostname: decode(hostname),\n port\n };\n}\nfunction stringifyParsedURL(parsed) {\n const pathname = parsed.pathname || \"\";\n const search = parsed.search ? (parsed.search.startsWith(\"?\") ? \"\" : \"?\") + parsed.search : \"\";\n const hash = parsed.hash || \"\";\n const auth = parsed.auth ? parsed.auth + \"@\" : \"\";\n const host = parsed.host || \"\";\n const proto = parsed.protocol || parsed[protocolRelative] ? (parsed.protocol || \"\") + \"//\" : \"\";\n return proto + auth + host + pathname + search + hash;\n}\nconst FILENAME_STRICT_REGEX = /\\/([^/]+\\.[^/]+)$/;\nconst FILENAME_REGEX = /\\/([^/]+)$/;\nfunction parseFilename(input = \"\", opts) {\n const { pathname } = parseURL(input);\n const matches = opts?.strict ? pathname.match(FILENAME_STRICT_REGEX) : pathname.match(FILENAME_REGEX);\n return matches ? matches[1] : void 0;\n}\n\nclass $URL {\n protocol;\n host;\n auth;\n pathname;\n query = {};\n hash;\n constructor(input = \"\") {\n if (typeof input !== \"string\") {\n throw new TypeError(\n `URL input should be string received ${typeof input} (${input})`\n );\n }\n const parsed = parseURL(input);\n this.protocol = decode(parsed.protocol);\n this.host = decode(parsed.host);\n this.auth = decode(parsed.auth);\n this.pathname = decodePath(parsed.pathname);\n this.query = parseQuery(parsed.search);\n this.hash = decode(parsed.hash);\n }\n get hostname() {\n return parseHost(this.host).hostname;\n }\n get port() {\n return parseHost(this.host).port || \"\";\n }\n get username() {\n return parseAuth(this.auth).username;\n }\n get password() {\n return parseAuth(this.auth).password || \"\";\n }\n get hasProtocol() {\n return this.protocol.length;\n }\n get isAbsolute() {\n return this.hasProtocol || this.pathname[0] === \"/\";\n }\n get search() {\n const q = stringifyQuery(this.query);\n return q.length > 0 ? \"?\" + q : \"\";\n }\n get searchParams() {\n const p = new URLSearchParams();\n for (const name in this.query) {\n const value = this.query[name];\n if (Array.isArray(value)) {\n for (const v of value) {\n p.append(name, v);\n }\n } else {\n p.append(\n name,\n typeof value === \"string\" ? value : JSON.stringify(value)\n );\n }\n }\n return p;\n }\n get origin() {\n return (this.protocol ? this.protocol + \"//\" : \"\") + encodeHost(this.host);\n }\n get fullpath() {\n return encodePath(this.pathname) + this.search + encodeHash(this.hash);\n }\n get encodedAuth() {\n if (!this.auth) {\n return \"\";\n }\n const { username, password } = parseAuth(this.auth);\n return encodeURIComponent(username) + (password ? \":\" + encodeURIComponent(password) : \"\");\n }\n get href() {\n const auth = this.encodedAuth;\n const originWithAuth = (this.protocol ? this.protocol + \"//\" : \"\") + (auth ? auth + \"@\" : \"\") + encodeHost(this.host);\n return this.hasProtocol && this.isAbsolute ? originWithAuth + this.fullpath : this.fullpath;\n }\n append(url) {\n if (url.hasProtocol) {\n throw new Error(\"Cannot append a URL with protocol\");\n }\n Object.assign(this.query, url.query);\n if (url.pathname) {\n this.pathname = withTrailingSlash(this.pathname) + withoutLeadingSlash(url.pathname);\n }\n if (url.hash) {\n this.hash = url.hash;\n }\n }\n toJSON() {\n return this.href;\n }\n toString() {\n return this.href;\n }\n}\nfunction createURL(input) {\n return new $URL(input);\n}\n\nexport { $URL, cleanDoubleSlashes, createURL, decode, decodePath, decodeQueryKey, decodeQueryValue, encode, encodeHash, encodeHost, encodeParam, encodePath, encodeQueryItem, encodeQueryKey, encodeQueryValue, filterQuery, getQuery, hasLeadingSlash, hasProtocol, hasTrailingSlash, isEmptyURL, isEqual, isNonEmptyURL, isRelative, isSamePath, isScriptProtocol, joinRelativeURL, joinURL, normalizeURL, parseAuth, parseFilename, parseHost, parsePath, parseQuery, parseURL, resolveURL, stringifyParsedURL, stringifyQuery, withBase, withFragment, withHttp, withHttps, withLeadingSlash, withProtocol, withQuery, withTrailingSlash, withoutBase, withoutFragment, withoutHost, withoutLeadingSlash, withoutProtocol, withoutTrailingSlash };\n","/**\n * Path utilities: delegate to ufo for URL/paths; custom logic only for route names (kebab/slash).\n */\nimport type { QueryObject } from 'ufo'\nimport {\n joinURL,\n withLeadingSlash,\n withoutTrailingSlash,\n cleanDoubleSlashes,\n withQuery,\n withFragment,\n parsePath,\n parseFilename,\n isEmptyURL,\n hasProtocol,\n} from 'ufo'\n\n/** Path segments without leading/repeated slashes (ufo parsePath.pathname). */\nexport function getPathSegments(pathOrSlashKey: string): string[] {\n const pathname = parsePath(pathOrSlashKey.startsWith('/') ? pathOrSlashKey : `/${pathOrSlashKey}`).pathname || ''\n return pathname.split('/').filter(Boolean)\n}\n\nexport const normalizePath = (p: string): string => {\n if (isEmptyURL(p ?? '')) return '/'\n return withLeadingSlash(withoutTrailingSlash(cleanDoubleSlashes(p))) || '/'\n}\n\n/** Path for comparison: collapse slashes, remove trailing slash, empty -> '/'. */\nexport function normalizePathForCompare(p: string): string {\n const collapsed = cleanDoubleSlashes(p || '/')\n const trimmed = withoutTrailingSlash(collapsed)\n return trimmed || '/'\n}\n\n/**\n * Join URL segments (ufo handles protocols and slashes correctly).\n * For path-style (no protocol) result always has leading slash.\n */\nexport function joinUrl(...segments: (string | undefined | null)[]): string {\n const valid = segments.filter((s): s is string => typeof s === 'string' && s !== '')\n if (valid.length === 0) return '/'\n const [base, ...rest] = valid\n const joined = joinURL(base!, ...rest) || '/'\n if (hasProtocol(joined)) return joined\n return withLeadingSlash(joined)\n}\n\n/**\n * Safely strips query and hash from path (ufo parsePath).\n * /news?id=1#top -> /news\n */\nexport function getCleanPath(path: string | null | undefined): string {\n if (!path) return ''\n const parsed = parsePath(path)\n return parsed.pathname || ''\n}\n\n/**\n * Builds full URL from path, query and hash (ufo withQuery + withFragment).\n */\nexport function buildUrl(path: string, query?: Record<string, unknown>, hash?: string): string {\n let url = withQuery(path, (query ?? {}) as QueryObject)\n if (hash && hash !== '#') {\n const fragment = hash.startsWith('#') ? hash.slice(1) : hash\n url = withFragment(url, fragment)\n }\n return url\n}\n\n/**\n * Parent path. /a/b/c -> /a/b, /a -> /, / -> null\n */\nexport function getParentPath(routePath: string): string | null {\n const segments = getPathSegments(routePath)\n if (segments.length === 0) return null\n if (segments.length <= 1) return '/'\n return joinUrl('/', ...segments.slice(0, -1))\n}\n\n/**\n * kebab -> path key: activity-skiing-locale -> activity/skiing/locale\n */\nexport function transformNameKeyToPath(nameKey: string): string {\n if (!nameKey) return ''\n let out = ''\n for (let i = 0; i < nameKey.length; i++) {\n out += nameKey[i] === '-' ? '/' : nameKey[i]\n }\n return out\n}\n\n/** First hyphen -> slash: activity-skiing-locale -> activity/skiing-locale */\nexport function nameKeyFirstSlash(nameKey: string): string {\n if (!nameKey) return ''\n const idx = nameKey.indexOf('-')\n return idx === -1 ? nameKey : joinURL(nameKey.slice(0, idx), nameKey.slice(idx + 1))\n}\n\n/** Last hyphen -> slash: activity-locale-skiing -> activity-locale/skiing */\nexport function nameKeyLastSlash(nameKey: string): string {\n if (!nameKey) return ''\n const idx = nameKey.lastIndexOf('-')\n return idx === -1 ? nameKey : joinURL(nameKey.slice(0, idx), nameKey.slice(idx + 1))\n}\n\n/** Parent key from slash-key: activity-locale/hiking -> activity-locale; a/b/c -> a-b */\nexport function parentKeyFromSlashKey(keyWithSlash: string): string {\n const segments = getPathSegments(keyWithSlash)\n return segments.length > 1 ? segments.slice(0, -1).join('-') : ''\n}\n\n/** Last path segment: /change-activity/hiking -> hiking (ufo parseFilename). */\nexport function lastPathSegment(path: string): string {\n return parseFilename(path || '/') ?? ''\n}\n","/**\n * Route name utilities: base name, localized name.\n */\nimport type { RouteLike } from '../core/types'\nimport type { Locale } from '@i18n-micro/types'\n\nexport interface GetRouteBaseNameOptions {\n locales: Pick<Locale, 'code'>[]\n localizedRouteNamePrefix?: string\n}\n\n/**\n * Base route name without prefix (localized-) and suffix (-{locale}).\n * Suffix is stripped only when it is a full segment (preceded by hyphen),\n * so names like product-screen are not broken when locale is en.\n */\nexport function getRouteBaseName(route: RouteLike, options: GetRouteBaseNameOptions): string | null {\n const name = route.name?.toString()\n if (!name) return null\n\n const prefix = options.localizedRouteNamePrefix || 'localized-'\n const base = name.startsWith(prefix) ? name.slice(prefix.length) : name\n\n // Sort by length descending: en-US before en — otherwise we strip the wrong suffix\n const sortedLocales = [...options.locales].sort((a, b) => b.code.length - a.code.length)\n\n for (const locale of sortedLocales) {\n const suffix = `-${locale.code}`\n if (!base.endsWith(suffix)) continue\n // Strip only when locale code is a separate segment (preceded by hyphen: ...-en, not ...screen)\n const charBeforeLocale = base.length - locale.code.length - 1\n if (charBeforeLocale >= 0 && base[charBeforeLocale] === '-') {\n return base.slice(0, -suffix.length)\n }\n }\n return base\n}\n\n/** Builds localized name: localized-{baseName}-{locale}. */\nexport function buildLocalizedName(baseName: string, locale: string, prefix = 'localized-'): string {\n return `${prefix}${baseName}-${locale}`\n}\n\nexport interface IsIndexRouteNameOptions {\n localizedRouteNamePrefix?: string\n localeCodes?: string[]\n}\n\n/**\n * Returns true if the given route name or base name refers to the index (root) route.\n * - Base name: 'index' or ''.\n * - Full route name: 'index', or 'localized-index-{locale}' for any locale in localeCodes.\n * Use this instead of ad-hoc checks like (name === 'index' || name.endsWith('-index') || name === 'localized-index-' + defaultLocale).\n */\nexport function isIndexRouteName(\n name: string | null | undefined,\n options?: IsIndexRouteNameOptions,\n): boolean {\n if (name == null) return false\n const s = String(name).trim()\n if (s === '' || s === 'index') return true\n const prefix = options?.localizedRouteNamePrefix ?? 'localized-'\n const localeCodes = options?.localeCodes ?? []\n const localizedIndexPrefix = `${prefix}index-`\n if (!s.startsWith(localizedIndexPrefix)) return false\n const localePart = s.slice(localizedIndexPrefix.length)\n return localeCodes.length === 0 ? localePart.length >= 2 : localeCodes.includes(localePart)\n}\n","/**\n * Path normalization: extract locale from path and pathWithoutLocale (ufo getCleanPath, hasLeadingSlash).\n */\nimport { hasLeadingSlash } from 'ufo'\nimport { getCleanPath, normalizePath } from '../utils/path'\n\nexport interface PathWithoutLocaleResult {\n pathWithoutLocale: string\n localeFromPath: string | null\n}\n\n/**\n * Parses path: if first segment is a known locale, returns path without it and locale code.\n */\nexport function getPathWithoutLocale(path: string, localeCodes: string[]): PathWithoutLocaleResult {\n const clean = getCleanPath(path)\n const normalized = normalizePath(clean)\n\n if (normalized === '/') {\n return { pathWithoutLocale: '/', localeFromPath: null }\n }\n\n if (!hasLeadingSlash(normalized)) {\n return { pathWithoutLocale: normalized, localeFromPath: null }\n }\n\n const nextSlash = normalized.indexOf('/', 1)\n const firstSegment = nextSlash === -1 ? normalized.slice(1) : normalized.slice(1, nextSlash)\n\n if (firstSegment && localeCodes.includes(firstSegment)) {\n const lengthToCut = 1 + firstSegment.length\n const remaining = normalized.slice(lengthToCut)\n return {\n pathWithoutLocale: normalizePath(remaining || '/'),\n localeFromPath: firstSegment,\n }\n }\n\n return { pathWithoutLocale: normalized, localeFromPath: null }\n}\n\n/**\n * Determines locale from first path segment.\n */\nexport function getLocaleFromPath(path: string, localeCodes: string[]): string | null {\n const clean = getCleanPath(path)\n\n if (clean === '/' || clean === '') return null\n\n if (!hasLeadingSlash(clean)) return null\n\n const nextSlash = clean.indexOf('/', 1)\n const segment = nextSlash === -1 ? clean.slice(1) : clean.slice(1, nextSlash)\n if (segment && localeCodes.includes(segment)) {\n return segment\n }\n\n return null\n}\n","/**\n * RouteResolver — single point for resolving custom paths from globalLocaleRoutes.\n * Uses normalizer and route-name utilities; lookup keys in one place (getLookupKeys).\n */\nimport type { PathStrategyContext, ResolvedRouteLike } from './types'\nimport { withoutLeadingSlash } from 'ufo'\nimport {\n joinUrl,\n normalizePath,\n transformNameKeyToPath,\n nameKeyFirstSlash,\n nameKeyLastSlash,\n} from '../utils/path'\nimport { getRouteBaseName } from '../utils/route-name'\nimport { getPathWithoutLocale } from './normalizer'\n\n/** Escapes special regex characters in a string for use in RegExp. */\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\nexport class RouteResolver {\n constructor(private ctx: PathStrategyContext) {}\n\n /**\n * Substitutes params into path template (:key, :key(), [...key]).\n * Uses one combined regex per key to avoid creating multiple RegExp in a loop.\n */\n resolvePathWithParams(path: string, params: Record<string, unknown> = {}): string {\n let resolved = path\n for (const key in params) {\n const value = params[key]\n if (value === undefined || value === null || value === '') continue\n\n const strValue = Array.isArray(value) ? (value as unknown[]).join('/') : String(value)\n const escaped = escapeRegex(key)\n const pattern = new RegExp(\n `:${escaped}\\\\(\\\\)|:${escaped}(?![\\\\w])|\\\\[\\\\.\\\\.\\\\.${escaped}\\\\]`,\n 'g',\n )\n resolved = resolved.replace(pattern, strValue)\n }\n return resolved\n }\n\n /**\n * Analyzes route: path without locale and base name (normalizer + route-name).\n */\n private analyzeRoute(route: ResolvedRouteLike): { pathWithoutLocale: string, baseRouteName: string | null } {\n const localeCodes = this.ctx.locales.map(l => l.code)\n const { pathWithoutLocale } = getPathWithoutLocale(route.path || '/', localeCodes)\n\n let baseRouteName: string | null = null\n if (route.name) {\n baseRouteName = getRouteBaseName(route, {\n locales: this.ctx.locales,\n localizedRouteNamePrefix: this.ctx.localizedRouteNamePrefix || 'localized-',\n })\n }\n\n return { pathWithoutLocale, baseRouteName }\n }\n\n /** Public access to route analysis (for strategies). */\n getPathWithoutLocaleAndBaseName(route: ResolvedRouteLike): { pathWithoutLocale: string, baseRouteName: string | null } {\n return this.analyzeRoute(route)\n }\n\n /**\n * Lookup keys for config (same order for resolveCustomPath, getPathForUnlocalizedRoute, getAllowedLocalesForRoute).\n */\n private getLookupKeys(pathWithoutLocale: string, baseRouteName: string | null): string[] {\n const keys: string[] = []\n\n keys.push(pathWithoutLocale)\n\n const pathKey = withoutLeadingSlash(pathWithoutLocale)\n if (pathKey && pathKey !== pathWithoutLocale) keys.push(pathKey)\n // Support root path lookup: '' as key when path is '/'\n if (pathWithoutLocale === '/' || pathKey === '') keys.push('')\n\n if (baseRouteName) {\n keys.push(`/${baseRouteName}`)\n keys.push(baseRouteName)\n\n const asPath = transformNameKeyToPath(baseRouteName)\n if (asPath && asPath !== baseRouteName) keys.push(asPath)\n\n const firstSlash = nameKeyFirstSlash(baseRouteName)\n if (firstSlash) keys.push(firstSlash)\n\n const lastSlash = nameKeyLastSlash(baseRouteName)\n if (lastSlash) keys.push(lastSlash)\n }\n\n return keys\n }\n\n /**\n * Resolves custom path for targetLocale from globalLocaleRoutes.\n */\n resolveCustomPath(route: ResolvedRouteLike, targetLocale: string): string | null {\n const gr = this.ctx.globalLocaleRoutes\n if (!gr || Object.keys(gr).length === 0) return null\n\n const { pathWithoutLocale, baseRouteName } = this.analyzeRoute(route)\n const keys = this.getLookupKeys(pathWithoutLocale, baseRouteName)\n\n for (const key of keys) {\n const rule = gr[key]\n if (rule && typeof rule === 'object' && !Array.isArray(rule)) {\n const customPath = (rule as Record<string, string>)[targetLocale]\n if (typeof customPath === 'string') {\n return this.resolvePathWithParams(customPath, route.params ?? {})\n }\n }\n }\n\n return null\n }\n\n /**\n * Unlocalized route (globalLocaleRoutes[key] === false) — returns path without locale.\n */\n getPathForUnlocalizedRoute(route: ResolvedRouteLike): string | null {\n const gr = this.ctx.globalLocaleRoutes\n if (!gr) return null\n\n const { pathWithoutLocale, baseRouteName } = this.analyzeRoute(route)\n const keys = this.getLookupKeys(pathWithoutLocale, baseRouteName)\n\n for (const key of keys) {\n if (gr[key] === false) {\n if (baseRouteName && (key === baseRouteName || key === `/${baseRouteName}`)) {\n const pathForm = transformNameKeyToPath(baseRouteName)\n return pathForm ? joinUrl('/', pathForm) : `/${baseRouteName}`\n }\n return pathWithoutLocale\n }\n }\n\n return null\n }\n\n /**\n * Unlocalized by name (when no route object available).\n */\n getPathForUnlocalizedRouteByName(routeName: string): string | null {\n const gr = this.ctx.globalLocaleRoutes\n if (!gr) return null\n\n const keys = [\n routeName,\n `/${routeName}`,\n withoutLeadingSlash(routeName),\n ]\n\n for (const key of keys) {\n if (gr[key] === false) {\n const pathForm = transformNameKeyToPath(key.startsWith('/') ? key.slice(1) : key)\n return pathForm ? joinUrl('/', pathForm) : (key.startsWith('/') ? key : `/${key}`)\n }\n }\n return null\n }\n\n /**\n * Allowed locales for route (routeLocales).\n */\n getAllowedLocalesForRoute(route: ResolvedRouteLike): string[] {\n const rl = this.ctx.routeLocales\n if (!rl || Object.keys(rl).length === 0) {\n return this.ctx.locales.map(l => l.code)\n }\n\n const { pathWithoutLocale, baseRouteName } = this.analyzeRoute(route)\n let keys = this.getLookupKeys(pathWithoutLocale, baseRouteName)\n\n if (baseRouteName && this.ctx.routesLocaleLinks?.[baseRouteName]) {\n const linkedName = this.ctx.routesLocaleLinks[baseRouteName]\n keys = [linkedName, ...keys]\n }\n\n for (const key of keys) {\n const allowed = rl[key]\n if (Array.isArray(allowed) && allowed.length > 0) {\n return allowed.filter(code => this.ctx.locales.some(l => l.code === code))\n }\n }\n\n return this.ctx.locales.map(l => l.code)\n }\n\n /**\n * Parent path for nested route (parent key -> targetLocale path).\n */\n getParentPathForNested(nameSegments: string[], targetLocale: string): string {\n if (nameSegments.length <= 1) return '/'\n\n const parentKey = nameSegments.length > 1 ? nameSegments.slice(0, -1).join('-') : ''\n const gr = this.ctx.globalLocaleRoutes\n\n if (parentKey && gr?.[parentKey] && typeof gr[parentKey] === 'object') {\n const parentRules = gr[parentKey] as Record<string, string>\n if (parentRules[targetLocale]) {\n return normalizePath(parentRules[targetLocale])\n }\n }\n\n return joinUrl('/', ...nameSegments.slice(0, -1))\n }\n}\n","import type { PathStrategyContext, PathStrategy, NormalizedRouteInput, ResolvedRouteLike, RouteLike, SeoAttributes, SwitchLocaleOptions, RouterAdapter } from '../core/types'\nimport type { Locale } from '@i18n-micro/types'\nimport { RouteResolver } from '../core/resolver'\nimport { getPathWithoutLocale as normalizerGetPathWithoutLocale, getLocaleFromPath as normalizerGetLocaleFromPath } from '../core/normalizer'\nimport { getRouteBaseName as utilGetRouteBaseName, buildLocalizedName as utilBuildLocalizedName, isIndexRouteName } from '../utils/route-name'\nimport { withoutTrailingSlash, hasProtocol } from 'ufo'\nimport { buildUrl, getPathSegments, joinUrl, normalizePath, nameKeyFirstSlash, nameKeyLastSlash, transformNameKeyToPath } from '../utils/path'\n\nexport abstract class BasePathStrategy implements PathStrategy {\n protected resolver: RouteResolver\n\n constructor(protected ctx: PathStrategyContext) {\n this.resolver = new RouteResolver(ctx)\n }\n\n setRouter(router: RouterAdapter): void {\n this.ctx.router = router\n }\n\n getDefaultLocale(): string {\n return this.ctx.defaultLocale\n }\n\n getLocales(): Locale[] {\n return this.ctx.locales\n }\n\n getStrategy(): PathStrategyContext['strategy'] {\n return this.ctx.strategy\n }\n\n getLocalizedRouteNamePrefix(): string {\n return this.ctx.localizedRouteNamePrefix || 'localized-'\n }\n\n getGlobalLocaleRoutes(): PathStrategyContext['globalLocaleRoutes'] {\n return this.ctx.globalLocaleRoutes\n }\n\n getRouteLocales(): PathStrategyContext['routeLocales'] {\n return this.ctx.routeLocales\n }\n\n getRoutesLocaleLinks(): PathStrategyContext['routesLocaleLinks'] {\n return this.ctx.routesLocaleLinks\n }\n\n getNoPrefixRedirect(): boolean | undefined {\n return this.ctx.noPrefixRedirect\n }\n\n /** Strips localization prefix/suffix and returns the \"base\" route name for one locale. */\n protected getBaseRouteName(route: RouteLike, locale: string): string | null {\n return utilGetRouteBaseName(route, {\n locales: [{ code: locale }],\n localizedRouteNamePrefix: this.getLocalizedRouteNamePrefix(),\n })\n }\n\n /** Returns the base route name (without localized prefix/suffix) by trying all locales. */\n getRouteBaseName(route: RouteLike): string | null {\n return utilGetRouteBaseName(route, {\n locales: this.ctx.locales,\n localizedRouteNamePrefix: this.getLocalizedRouteNamePrefix(),\n })\n }\n\n /** Resolves target path for a locale, checking globalLocaleRoutes first. */\n protected resolvePathForLocale(path: string, targetLocale: string): string {\n const mockRoute: ResolvedRouteLike = {\n path,\n name: null,\n fullPath: path,\n params: {},\n }\n const customSegment = this.resolver.resolveCustomPath(mockRoute, targetLocale)\n if (customSegment) return normalizePath(customSegment)\n return normalizePath(path)\n }\n\n protected buildLocalizedName(baseName: string, locale: string): string {\n return utilBuildLocalizedName(baseName, locale, this.getLocalizedRouteNamePrefix())\n }\n\n /** Builds path for target locale (strategy decides: with or without prefix). */\n protected abstract buildLocalizedPath(path: string, locale: string, isCustom: boolean): string\n\n /** Builds localized route name for target locale. */\n protected abstract buildLocalizedRouteName(baseName: string, locale: string): string\n\n protected getLocaleObject(code: string): Locale | undefined {\n return this.ctx.locales.find(l => l.code === code)\n }\n\n protected applyBaseUrl(localeCode: string, route: RouteLike | string): RouteLike | string {\n if (typeof route === 'string') {\n if (hasProtocol(route)) return route\n }\n else if (route.path && hasProtocol(route.path)) {\n return route\n }\n\n const locale = this.getLocaleObject(localeCode)\n if (!locale?.baseUrl) {\n return route\n }\n\n const baseUrl = withoutTrailingSlash(locale.baseUrl)\n\n if (typeof route === 'string') {\n const path = normalizePath(route.startsWith('/') ? route : `/${route}`)\n return joinUrl(baseUrl, path)\n }\n\n const resolvedPath = normalizePath(route.path || '')\n const fullPath = joinUrl(baseUrl, resolvedPath)\n return {\n ...route,\n path: fullPath,\n fullPath,\n }\n }\n\n /**\n * Merges target route (strategy result) with query and hash from source route.\n * Returns normalized RouteLike object.\n */\n protected preserveQueryAndHash(\n target: RouteLike | string,\n source?: RouteLike | null,\n ): RouteLike | string {\n if (!source || (!source.query && !source.hash)) {\n return target\n }\n\n const result: RouteLike = typeof target === 'string'\n ? { path: target }\n : { ...target }\n\n if (source.query) {\n result.query = { ...source.query, ...result.query }\n }\n if (!result.hash && source.hash) {\n result.hash = source.hash\n }\n\n const basePath = result.path ?? ''\n result.fullPath = buildUrl(basePath, result.query, result.hash)\n\n return result\n }\n\n protected resolvePathWithParams(path: string, params: Record<string, unknown> = {}): string {\n return this.resolver.resolvePathWithParams(path, params)\n }\n\n protected getPathWithoutLocaleAndBaseName(route: ResolvedRouteLike): { pathWithoutLocale: string, baseRouteName: string | null } {\n return this.resolver.getPathWithoutLocaleAndBaseName(route)\n }\n\n /** Look up custom path segment for targetLocale in globalLocaleRoutes. */\n protected getCustomPathSegment(route: ResolvedRouteLike, targetLocale: string): string | null {\n return this.resolver.resolveCustomPath(route, targetLocale)\n }\n\n protected getAllowedLocalesForRoute(route: ResolvedRouteLike): string[] {\n return this.resolver.getAllowedLocalesForRoute(route)\n }\n\n getCanonicalPath(_route: ResolvedRouteLike, _targetLocale: string): string | null {\n return null\n }\n\n protected getPathForUnlocalizedRouteByName(routeName: string): string | null {\n return this.resolver.getPathForUnlocalizedRouteByName(routeName)\n }\n\n /**\n * Try to resolve route by localized name. Returns RouteLike with query/hash from sourceRoute to preserve them.\n */\n protected tryResolveByLocalizedName(routeName: string, targetLocale: string, sourceRoute?: RouteLike): RouteLike | null {\n const localizedName = `${this.getLocalizedRouteNamePrefix()}${routeName}-${targetLocale}`\n const hasRoute = this.ctx.router.hasRoute(localizedName)\n this.debugLog('tryResolveByLocalizedName', { routeName, targetLocale, localizedName, hasRoute })\n if (!hasRoute) return null\n const resolved = this.ctx.router.resolve({\n name: localizedName,\n params: sourceRoute?.params,\n query: sourceRoute?.query,\n hash: sourceRoute?.hash,\n })\n this.debugLog('tryResolveByLocalizedName resolved', { localizedName, path: resolved?.path, fullPath: resolved?.fullPath })\n if (!resolved?.path) return null\n return {\n name: localizedName,\n path: resolved.path,\n fullPath: resolved.fullPath,\n params: resolved.params,\n query: resolved.query ?? sourceRoute?.query,\n hash: resolved.hash ?? sourceRoute?.hash,\n }\n }\n\n /**\n * Try to resolve route by localized name with params. Returns RouteLike to preserve query/hash.\n */\n protected tryResolveByLocalizedNameWithParams(\n routeName: string,\n targetLocale: string,\n params: Record<string, unknown>,\n sourceRoute?: RouteLike,\n ): RouteLike | null {\n const localizedName = `${this.getLocalizedRouteNamePrefix()}${routeName}-${targetLocale}`\n const hasRoute = this.ctx.router.hasRoute(localizedName)\n this.debugLog('tryResolveByLocalizedNameWithParams', { routeName, targetLocale, params, localizedName, hasRoute })\n if (!hasRoute) return null\n const resolved = this.ctx.router.resolve({\n name: localizedName,\n params,\n query: sourceRoute?.query,\n hash: sourceRoute?.hash,\n })\n this.debugLog('tryResolveByLocalizedNameWithParams resolved', { path: resolved?.path, fullPath: resolved?.fullPath })\n if (!resolved?.path || resolved.path === '/') return null\n return {\n name: localizedName,\n path: resolved.path,\n fullPath: resolved.fullPath,\n params: resolved.params,\n query: resolved.query ?? sourceRoute?.query,\n hash: resolved.hash ?? sourceRoute?.hash,\n }\n }\n\n protected getPathForUnlocalizedRoute(route: ResolvedRouteLike): string | null {\n return this.resolver.getPathForUnlocalizedRoute(route)\n }\n\n /**\n * Builds localized path from baseName + params when router does not have the route.\n * Tries two conventions:\n * 1) Hyphen form (Nuxt test-[id].vue → /test-:id): when single param key equals last baseName segment (e.g. test-id + id → test-:id).\n * 2) Slash form (kebab→slash): path segments from baseName, last N replaced by :paramKey (e.g. test-id → /test/:id).\n */\n protected buildPathFromBaseNameAndParams(\n baseName: string,\n params: Record<string, unknown>,\n targetLocale: string,\n ): string | null {\n const paramKeys = Object.keys(params).filter(k => params[k] !== undefined && params[k] !== null && params[k] !== '')\n if (paramKeys.length === 0) return null\n let pathTemplate: string\n const firstKey = paramKeys[0]\n if (paramKeys.length === 1 && firstKey !== undefined && baseName.endsWith('-' + firstKey)) {\n pathTemplate = joinUrl('/', baseName.slice(0, baseName.length - firstKey.length - 1) + '-:' + firstKey)\n }\n else {\n const pathForm = transformNameKeyToPath(baseName)\n const pathSegments = pathForm ? pathForm.split('/').filter(Boolean) : [baseName]\n const replaceCount = Math.min(paramKeys.length, pathSegments.length)\n const templateSegments = pathSegments.slice(0, pathSegments.length - replaceCount)\n .concat(paramKeys.slice(0, replaceCount).map(k => `:${k}`))\n pathTemplate = joinUrl('/', ...templateSegments)\n }\n const pathWithParams = this.resolvePathWithParams(pathTemplate, params)\n const finalPath = this.buildLocalizedPath(pathWithParams, targetLocale, false)\n const withBase = this.applyBaseUrl(targetLocale, finalPath)\n return typeof withBase === 'string' ? withBase : (withBase as RouteLike).path ?? finalPath\n }\n\n protected getPathWithoutLocale(path: string): { pathWithoutLocale: string, localeFromPath: string | null } {\n return normalizerGetPathWithoutLocale(path, this.ctx.locales.map(l => l.code))\n }\n\n getLocaleFromPath(path: string): string | null {\n return normalizerGetLocaleFromPath(path, this.ctx.locales.map(l => l.code))\n }\n\n abstract resolveLocaleFromPath(path: string): string | null\n\n /**\n * Returns path to redirect to, or null if no redirect needed.\n * Use in middleware: strategy.getRedirect(to.fullPath, detectedLocale)\n */\n abstract getRedirect(currentPath: string, targetLocale: string): string | null\n\n /**\n * Builds SEO attributes (canonical + hreflangs) from current route.\n * Respects routeLocales: only allowed locales for this route get an hreflang entry.\n * routesLocaleLinks is used when resolving the route key for routeLocales lookup.\n */\n getSeoAttributes(currentRoute: ResolvedRouteLike): SeoAttributes {\n const currentLocale = this.resolveLocaleFromPath(currentRoute.path) ?? this.ctx.defaultLocale\n const canonicalPath = this.getCanonicalPath(currentRoute, currentLocale) ?? currentRoute.path\n const canonical = this.buildFullUrl(currentLocale, canonicalPath)\n\n const allowedCodes = this.getAllowedLocalesForRoute(currentRoute)\n const localesToEmit = this.ctx.locales.filter(l => allowedCodes.includes(l.code))\n const hreflangs = localesToEmit.map((locale) => {\n const localized = this.localeRoute(locale.code, currentRoute, currentRoute)\n const pathStr = localized.path ?? localized.fullPath ?? ''\n const normalizedPath = pathStr || '/'\n return {\n rel: 'alternate' as const,\n hreflang: locale.code,\n href: this.buildFullUrl(locale.code, normalizedPath),\n }\n })\n\n return { canonical, hreflangs }\n }\n\n /**\n * Builds full URL (path + optional baseUrl for locale).\n */\n protected buildFullUrl(localeCode: string, path: string): string {\n const result = this.applyBaseUrl(localeCode, path)\n return typeof result === 'string' ? result : (result.path ?? path)\n }\n\n /** When router knows neither targetName nor baseName — what to return (strategy may override). */\n protected getSwitchLocaleFallbackWhenNoRoute(route: ResolvedRouteLike, targetName: string): RouteLike | string {\n return { ...route, name: targetName }\n }\n\n /**\n * Default: baseName → buildLocalizedRouteName → hasRoute → applyBaseUrl; fallback to baseName.\n */\n switchLocaleRoute(\n fromLocale: string,\n toLocale: string,\n route: ResolvedRouteLike,\n options: SwitchLocaleOptions,\n ): RouteLike | string {\n const baseName = this.getBaseRouteName(route, fromLocale)\n if (!baseName) return route\n\n let targetName = this.buildLocalizedRouteName(baseName, toLocale)\n\n if (!this.ctx.router.hasRoute(targetName)) {\n if (this.ctx.router.hasRoute(baseName)) {\n targetName = baseName\n }\n else {\n return this.getSwitchLocaleFallbackWhenNoRoute(route, targetName)\n }\n }\n\n const i18nParams = options.i18nRouteParams?.[toLocale] || {}\n const newParams: Record<string, unknown> = { ...(route.params || {}), ...i18nParams }\n delete (newParams as Record<string, unknown>).locale\n\n const newRoute: RouteLike = {\n name: targetName,\n params: newParams,\n query: route.query,\n hash: route.hash,\n }\n return this.applyBaseUrl(toLocale, newRoute)\n }\n\n /**\n * Template Method: BaseStrategy knows \"how\" (normalize → delegate to strategy).\n * Always returns RouteLike with path and fullPath (never a string).\n */\n localeRoute(\n targetLocale: string,\n routeOrPath: RouteLike | string,\n currentRoute?: ResolvedRouteLike,\n ): RouteLike {\n const normalized = this.normalizeRouteInput(routeOrPath, currentRoute)\n const raw = this.resolveLocaleRoute(targetLocale, normalized, currentRoute)\n this.debugLog('localeRoute raw', { rawPath: typeof raw === 'string' ? raw : (raw as RouteLike).path, rawFullPath: typeof raw === 'string' ? raw : (raw as RouteLike).fullPath })\n const result = this.ensureRouteLike(raw, normalized.kind === 'route' ? normalized.sourceRoute : undefined)\n this.debugLog('localeRoute after ensureRouteLike', { path: result.path, fullPath: result.fullPath })\n return result\n }\n\n /** Normalizes resolveLocaleRoute result into RouteLike (path and fullPath always set). */\n protected ensureRouteLike(value: RouteLike | string, source?: RouteLike | null): RouteLike {\n if (typeof value === 'string') {\n const path = value\n const fullPath = source?.query || source?.hash\n ? buildUrl(path, source?.query, source?.hash)\n : path\n return {\n path,\n fullPath,\n ...(source?.query && { query: source.query }),\n ...(source?.hash && { hash: source.hash }),\n }\n }\n let fullPath = (value.fullPath ?? value.path ?? '')\n let path = (value.path ?? fullPath.split('?')[0]?.split('#')[0] ?? fullPath)\n if (!path && !fullPath) {\n const name = value.name?.toString() ?? source?.name?.toString() ?? ''\n if (isIndexRouteName(name, {\n localizedRouteNamePrefix: this.getLocalizedRouteNamePrefix(),\n localeCodes: this.ctx.locales.map(l => l.code),\n })) {\n path = '/'\n fullPath = '/'\n }\n }\n return { ...value, path, fullPath }\n }\n\n /**\n * Normalizes localeRoute input into a single structure (path string or route with resolved).\n */\n protected normalizeRouteInput(\n routeOrPath: RouteLike | string,\n _currentRoute?: ResolvedRouteLike,\n ): NormalizedRouteInput {\n if (typeof routeOrPath === 'string') {\n return { kind: 'path', path: routeOrPath }\n }\n const sourceRoute = routeOrPath as RouteLike\n const inputName = sourceRoute.name?.toString() ?? null\n let resolved: ResolvedRouteLike\n try {\n resolved = this.ctx.router.resolve(routeOrPath)\n this.debugLog('normalizeRouteInput router.resolve ok', { inputName, resolvedPath: resolved.path, resolvedName: resolved.name })\n }\n catch {\n resolved = {\n name: inputName,\n path: sourceRoute.path ?? '/',\n fullPath: sourceRoute.fullPath ?? sourceRoute.path ?? '/',\n params: sourceRoute.params ?? {},\n query: sourceRoute.query ?? {},\n hash: sourceRoute.hash ?? '',\n } as ResolvedRouteLike\n this.debugLog('normalizeRouteInput router.resolve catch fallback', { inputName, resolvedPath: resolved.path })\n }\n return { kind: 'route', inputName, sourceRoute, resolved }\n }\n\n /** Logging when ctx.debug (for localeRoute debugging). Disabled by default. */\n private debugLog(..._args: unknown[]): void {\n // if (this.ctx.debug) console.log('[i18n:resolveLocaleRoute]', ..._args)\n }\n\n /**\n * Default resolution: uses buildLocalizedPath and buildLocalizedRouteName.\n * Strategies with different logic (e.g. prefix-except-default) override this method.\n */\n protected resolveLocaleRoute(\n targetLocale: string,\n normalized: NormalizedRouteInput,\n _currentRoute?: ResolvedRouteLike,\n ): RouteLike | string {\n if (normalized.kind === 'path') {\n const resolvedPath = this.resolvePathForLocale(normalized.path, targetLocale)\n const finalPath = this.buildLocalizedPath(resolvedPath, targetLocale, false)\n const out = this.applyBaseUrl(targetLocale, finalPath)\n this.debugLog('branch=path', { targetLocale, path: normalized.path, finalPath, out: typeof out === 'string' ? out : (out as RouteLike).path })\n return out\n }\n\n const { inputName, sourceRoute: src, resolved } = normalized\n const hasParams = src.params && Object.keys(src.params ?? {}).length > 0\n const baseName = this.getRouteBaseName(resolved) ?? inputName ?? resolved.name?.toString() ?? null\n const resolvedNameStr = resolved.name?.toString()\n\n this.debugLog('input', { targetLocale, inputName, resolvedPath: resolved.path, resolvedName: resolved.name, params: src.params, hasParams, baseName })\n\n if (inputName) {\n const unlocalizedByName = this.getPathForUnlocalizedRouteByName(inputName)\n if (unlocalizedByName !== null) {\n this.debugLog('branch=unlocalizedByName', { inputName, unlocalizedByName })\n return this.preserveQueryAndHash(unlocalizedByName, src)\n }\n }\n\n if (inputName && hasParams) {\n const routeWithParams = this.tryResolveByLocalizedNameWithParams(\n inputName,\n targetLocale,\n src.params ?? {},\n src,\n )\n if (routeWithParams !== null) {\n this.debugLog('branch=routeWithParams', { inputName, path: routeWithParams.path, fullPath: routeWithParams.fullPath })\n return this.preserveQueryAndHash(this.applyBaseUrl(targetLocale, routeWithParams), src)\n }\n }\n\n // Resolve by inputName first; if not found and inputName looks like a localized name (prefix-base-locale), try baseName.\n // Do not try baseName when user asked for base name 'index' (resolved route may be current page -> baseName 'page').\n if (inputName && !hasParams) {\n let routeByLocalizedName = this.tryResolveByLocalizedName(inputName, targetLocale, src)\n const prefix = this.getLocalizedRouteNamePrefix()\n if (routeByLocalizedName === null && baseName != null && baseName !== inputName && inputName.startsWith(prefix)) {\n routeByLocalizedName = this.tryResolveByLocalizedName(baseName, targetLocale, src)\n }\n if (routeByLocalizedName !== null) {\n this.debugLog('branch=routeByLocalizedName', { inputName, path: routeByLocalizedName.path, fullPath: routeByLocalizedName.fullPath })\n return this.preserveQueryAndHash(this.applyBaseUrl(targetLocale, routeByLocalizedName), src)\n }\n }\n\n const unlocalizedPath = this.getPathForUnlocalizedRoute(resolved)\n if (unlocalizedPath !== null) {\n const path = this.buildLocalizedPath(unlocalizedPath, targetLocale, false)\n this.debugLog('branch=unlocalizedPath', { unlocalizedPath, path })\n return this.preserveQueryAndHash(this.applyBaseUrl(targetLocale, path), src)\n }\n\n const customSegment = this.getCustomPathSegment(resolved, targetLocale)\n if (customSegment !== null) {\n const routeName = resolved.name?.toString() ?? inputName ?? ''\n const keyFirstSlash = routeName ? nameKeyFirstSlash(routeName) : ''\n const keyLastSlash = routeName ? nameKeyLastSlash(routeName) : ''\n const gr = this.ctx.globalLocaleRoutes\n const isNestedFirst = keyFirstSlash.includes('/') && gr?.[keyFirstSlash]\n const isNestedLast = keyLastSlash.includes('/') && gr?.[keyLastSlash]\n const isNested = isNestedFirst || isNestedLast\n const keyWithSlash = isNestedLast ? keyLastSlash : keyFirstSlash\n let pathWithoutLocale: string\n if (isNested) {\n const nameSegments = getPathSegments(keyWithSlash)\n const parentKey = nameSegments.length > 1 ? nameSegments.slice(0, -1).join('-') : ''\n const parentRules = parentKey && gr?.[parentKey] && typeof gr[parentKey] === 'object' && !Array.isArray(gr[parentKey])\n ? (gr[parentKey] as Record<string, string>)\n : null\n const parentPath = parentRules?.[targetLocale]\n ? normalizePath(parentRules[targetLocale])\n : joinUrl('/', ...nameSegments.slice(0, -1))\n const segment = customSegment.startsWith('/') ? customSegment.slice(1) : customSegment\n pathWithoutLocale = joinUrl(parentPath, segment)\n }\n else {\n pathWithoutLocale = normalizePath(customSegment)\n }\n const finalPath = this.buildLocalizedPath(pathWithoutLocale, targetLocale, true)\n this.debugLog('branch=customSegment', { customSegment, pathWithoutLocale, finalPath })\n return this.preserveQueryAndHash(this.applyBaseUrl(targetLocale, finalPath), src)\n }\n\n const effectiveBaseName = baseName ?? inputName\n this.debugLog('before effectiveBaseName check', { baseName, inputName, effectiveBaseName, resolvedName: resolved.name?.toString() })\n if (!effectiveBaseName) {\n this.debugLog('branch=noBaseName', { return: 'src' })\n return src\n }\n\n if (!hasParams && resolved.path && resolved.path !== '/' && resolved.name) {\n const { pathWithoutLocale, baseRouteName } = this.getPathWithoutLocaleAndBaseName(resolved)\n if (pathWithoutLocale && pathWithoutLocale !== '/') {\n const pathToUse = baseRouteName && pathWithoutLocale === baseRouteName\n ? joinUrl('/', transformNameKeyToPath(baseRouteName))\n : pathWithoutLocale\n const finalPath = this.buildLocalizedPath(pathToUse, targetLocale, false)\n this.debugLog('branch=pathFromResolved', { pathWithoutLocale, baseRouteName, pathToUse, finalPath })\n return this.preserveQueryAndHash(this.applyBaseUrl(targetLocale, finalPath), src)\n }\n }\n\n const baseNameForPath = (resolvedNameStr === inputName ? effectiveBaseName : (inputName ?? effectiveBaseName))\n this.debugLog('fallback build', { resolvedNameStr, inputName, baseNameForPath, targetLocale, hasParams })\n const targetName = this.buildLocalizedRouteName(baseNameForPath, targetLocale)\n const newRoute: RouteLike = {\n ...src,\n name: targetName,\n params: { ...src.params },\n }\n if (!hasParams) {\n const pathWithoutLocale = isIndexRouteName(baseNameForPath)\n ? '/'\n : joinUrl('/', transformNameKeyToPath(baseNameForPath))\n const finalPath = this.buildLocalizedPath(pathWithoutLocale, targetLocale, false)\n const withBase = this.applyBaseUrl(targetLocale, finalPath)\n const pathStr = typeof withBase === 'string' ? withBase : (withBase as RouteLike).path ?? finalPath\n this.debugLog('fallback !hasParams', { pathWithoutLocale, finalPath, pathStr })\n newRoute.path = pathStr\n newRoute.fullPath = pathStr\n }\n else {\n let pathStr: string | null = null\n try {\n const resolvedWithParams = this.ctx.router.resolve({ name: baseNameForPath, params: src.params })\n if (resolvedWithParams?.path) {\n const pathToUse = resolvedWithParams.path === '/'\n ? '/'\n : (() => {\n const { pathWithoutLocale } = this.getPathWithoutLocale(resolvedWithParams.path)\n return pathWithoutLocale && pathWithoutLocale !== '/' ? pathWithoutLocale : resolvedWithParams.path\n })()\n const finalPath = this.buildLocalizedPath(pathToUse, targetLocale, false)\n const withBase = this.applyBaseUrl(targetLocale, finalPath)\n pathStr = typeof withBase === 'string' ? withBase : (withBase as RouteLike).path ?? finalPath\n }\n }\n catch {\n // Router does not have baseName route: build path from baseNameForPath + params (path template)\n pathStr = this.buildPathFromBaseNameAndParams(baseNameForPath, src.params ?? {}, targetLocale)\n }\n if (pathStr) {\n newRoute.path = pathStr\n newRoute.fullPath = pathStr\n }\n }\n const out = this.preserveQueryAndHash(this.applyBaseUrl(targetLocale, newRoute), src)\n this.debugLog('branch=fallbackNewRoute return', { baseName, targetName, hasParams, newRoutePath: newRoute.path, outPath: typeof out === 'string' ? out : (out as RouteLike).path })\n return out\n }\n}\n"],"names":["HASH_RE","AMPERSAND_RE","SLASH_RE","EQUAL_RE","PLUS_RE","ENC_CARET_RE","ENC_BACKTICK_RE","ENC_CURLY_OPEN_RE","ENC_PIPE_RE","ENC_CURLY_CLOSE_RE","ENC_SPACE_RE","encode","text","encodeHash","encodeQueryValue","input","encodeQueryKey","decode","decodeQueryKey","decodeQueryValue","parseQuery","parametersString","object","parameter","s","key","value","encodeQueryItem","_value","stringifyQuery","query","k","PROTOCOL_STRICT_REGEX","PROTOCOL_REGEX","PROTOCOL_RELATIVE_REGEX","JOIN_LEADING_SLASH_RE","hasProtocol","inputString","opts","hasTrailingSlash","respectQueryAndFragment","withoutTrailingSlash","withTrailingSlash","hasLeadingSlash","withoutLeadingSlash","withLeadingSlash","cleanDoubleSlashes","string_","withQuery","parsed","parseURL","mergedQuery","stringifyParsedURL","isEmptyURL","url","isNonEmptyURL","joinURL","base","segment","url2","_segment","isSamePath","p1","p2","withFragment","hash","protocolRelative","defaultProto","_specialProtoMatch","_proto","_pathname","parsePath","protocol","auth","hostAndPath","host","path","pathname","search","FILENAME_REGEX","parseFilename","matches","getPathSegments","pathOrSlashKey","normalizePath","p","normalizePathForCompare","collapsed","joinUrl","segments","valid","rest","joined","getCleanPath","buildUrl","fragment","transformNameKeyToPath","nameKey","out","i","nameKeyFirstSlash","idx","nameKeyLastSlash","parentKeyFromSlashKey","keyWithSlash","lastPathSegment","getRouteBaseName","route","options","name","prefix","sortedLocales","a","b","locale","suffix","charBeforeLocale","buildLocalizedName","baseName","isIndexRouteName","localeCodes","localizedIndexPrefix","localePart","getPathWithoutLocale","clean","normalized","nextSlash","firstSegment","lengthToCut","remaining","getLocaleFromPath","escapeRegex","RouteResolver","ctx","params","resolved","strValue","escaped","pattern","l","pathWithoutLocale","baseRouteName","keys","pathKey","asPath","firstSlash","lastSlash","targetLocale","gr","rule","customPath","pathForm","routeName","rl","allowed","code","nameSegments","parentKey","parentRules","BasePathStrategy","router","utilGetRouteBaseName","mockRoute","customSegment","utilBuildLocalizedName","localeCode","baseUrl","resolvedPath","fullPath","target","source","result","basePath","_route","_targetLocale","sourceRoute","localizedName","hasRoute","paramKeys","pathTemplate","firstKey","pathSegments","replaceCount","templateSegments","pathWithParams","finalPath","withBase","normalizerGetPathWithoutLocale","normalizerGetLocaleFromPath","currentRoute","currentLocale","canonicalPath","canonical","allowedCodes","hreflangs","localized","normalizedPath","targetName","fromLocale","toLocale","i18nParams","newParams","newRoute","routeOrPath","raw","_currentRoute","inputName","_args","src","hasParams","resolvedNameStr","unlocalizedByName","routeWithParams","routeByLocalizedName","unlocalizedPath","keyFirstSlash","keyLastSlash","isNestedFirst","isNestedLast","isNested","parentPath","effectiveBaseName","pathToUse","baseNameForPath","pathStr","resolvedWithParams"],"mappings":"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","x_google_ignoreList":[0]}
|