@i18n-micro/utils 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto-detect-path.cjs +1 -0
- package/dist/auto-detect-path.d.cts +16 -0
- package/dist/auto-detect-path.d.ts +16 -0
- package/dist/auto-detect-path.mjs +13 -0
- package/dist/resolve-hreflang.cjs +1 -0
- package/dist/resolve-hreflang.d.cts +22 -0
- package/dist/resolve-hreflang.d.ts +22 -0
- package/dist/resolve-hreflang.mjs +29 -0
- package/dist/split-locale-routes.cjs +1 -0
- package/dist/split-locale-routes.d.cts +36 -0
- package/dist/split-locale-routes.d.ts +36 -0
- package/dist/split-locale-routes.mjs +19 -0
- package/package.json +48 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function i(e,o={}){const t=o.autoDetectPath??"/",r=!e||e===""?"/":e;if(t==="*")return!0;if(t==="no_prefix")return!o.hasLocalePrefix;if(t==="/"||t==="")return r==="/";const c=t.startsWith("/")?t:`/${t}`;return r===c||r===`${c}/`}exports.shouldAttemptLocaleRedirect=i;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether cookie / Accept-Language preference may steer locale redirects (#242).
|
|
3
|
+
*
|
|
4
|
+
* Modes (`ModuleOptions.autoDetectPath`):
|
|
5
|
+
* - `'/'` (default) — only `/`
|
|
6
|
+
* - `'no_prefix'` — any path without a locale prefix
|
|
7
|
+
* - `'*'` — every path (also enables aggressive prefixed-URL rewrites in the plugin)
|
|
8
|
+
* - any other string — exact path match
|
|
9
|
+
*
|
|
10
|
+
* Does not gate strategy / `localeRoutes` canonicalization: when preference is denied on an
|
|
11
|
+
* unprefixed path, the plugin still runs `getClientRedirect` with the default locale.
|
|
12
|
+
*/
|
|
13
|
+
export declare function shouldAttemptLocaleRedirect(path: string, options?: {
|
|
14
|
+
autoDetectPath?: string;
|
|
15
|
+
hasLocalePrefix?: boolean;
|
|
16
|
+
}): boolean;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether cookie / Accept-Language preference may steer locale redirects (#242).
|
|
3
|
+
*
|
|
4
|
+
* Modes (`ModuleOptions.autoDetectPath`):
|
|
5
|
+
* - `'/'` (default) — only `/`
|
|
6
|
+
* - `'no_prefix'` — any path without a locale prefix
|
|
7
|
+
* - `'*'` — every path (also enables aggressive prefixed-URL rewrites in the plugin)
|
|
8
|
+
* - any other string — exact path match
|
|
9
|
+
*
|
|
10
|
+
* Does not gate strategy / `localeRoutes` canonicalization: when preference is denied on an
|
|
11
|
+
* unprefixed path, the plugin still runs `getClientRedirect` with the default locale.
|
|
12
|
+
*/
|
|
13
|
+
export declare function shouldAttemptLocaleRedirect(path: string, options?: {
|
|
14
|
+
autoDetectPath?: string;
|
|
15
|
+
hasLocalePrefix?: boolean;
|
|
16
|
+
}): boolean;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function c(e, n = {}) {
|
|
2
|
+
const t = n.autoDetectPath ?? "/", r = !e || e === "" ? "/" : e;
|
|
3
|
+
if (t === "*") return !0;
|
|
4
|
+
if (t === "no_prefix")
|
|
5
|
+
return !n.hasLocalePrefix;
|
|
6
|
+
if (t === "/" || t === "")
|
|
7
|
+
return r === "/";
|
|
8
|
+
const o = t.startsWith("/") ? t : `/${t}`;
|
|
9
|
+
return r === o || r === `${o}/`;
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
c as shouldAttemptLocaleRedirect
|
|
13
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function l(e){return e.iso?.trim()||String(e.code)}function u(e){const r=e.match(/^([A-Za-z]{2,3})(?:[-_](.+))?$/);return r?{language:r[1],region:r[2]}:{language:e}}function d(e,r={}){const{hreflangBaseLanguage:f=!1}=r;if(!f)return e.map(t=>{const o=String(t.code);return{hreflang:l(t),localeCode:o}});const s=new Map;for(const t of e){const o=String(t.code),a=l(t),{language:n,region:i}=u(a);n&&i&&!s.has(n)&&s.set(n,o),s.set(a,o)}const g=new Set,c=[];for(const t of e){const o=String(t.code),a=l(t),{language:n,region:i}=u(a);n&&i&&s.get(n)===o&&!g.has(n)&&(g.add(n),c.push({hreflang:n,localeCode:o})),g.has(a)||(g.add(a),c.push({hreflang:a,localeCode:o}))}return c}exports.resolveHreflangAlternates=d;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Locale } from '@i18n-micro/types';
|
|
2
|
+
export type HreflangLocaleInput = Pick<Locale, 'code' | 'iso'>;
|
|
3
|
+
export interface ResolveHreflangAlternatesOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Also emit a bare-language `hreflang` derived from `iso` (e.g. `es-ES` → `es`),
|
|
6
|
+
* claimed by the first regional locale in the list for that language.
|
|
7
|
+
* Never derived from routing `code`.
|
|
8
|
+
* @default false
|
|
9
|
+
*/
|
|
10
|
+
hreflangBaseLanguage?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface HreflangAlternate {
|
|
13
|
+
/** Value for the `hreflang` attribute (BCP-47 / `iso || code`). */
|
|
14
|
+
hreflang: string;
|
|
15
|
+
/** Locale `code` whose localized URL should back this tag. */
|
|
16
|
+
localeCode: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve `hreflang` values for SEO alternate links.
|
|
20
|
+
* Uses `iso || code` — never emits routing `code` when `iso` is set (#243).
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveHreflangAlternates(locales: HreflangLocaleInput[], options?: ResolveHreflangAlternatesOptions): HreflangAlternate[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Locale } from '@i18n-micro/types';
|
|
2
|
+
export type HreflangLocaleInput = Pick<Locale, 'code' | 'iso'>;
|
|
3
|
+
export interface ResolveHreflangAlternatesOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Also emit a bare-language `hreflang` derived from `iso` (e.g. `es-ES` → `es`),
|
|
6
|
+
* claimed by the first regional locale in the list for that language.
|
|
7
|
+
* Never derived from routing `code`.
|
|
8
|
+
* @default false
|
|
9
|
+
*/
|
|
10
|
+
hreflangBaseLanguage?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface HreflangAlternate {
|
|
13
|
+
/** Value for the `hreflang` attribute (BCP-47 / `iso || code`). */
|
|
14
|
+
hreflang: string;
|
|
15
|
+
/** Locale `code` whose localized URL should back this tag. */
|
|
16
|
+
localeCode: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve `hreflang` values for SEO alternate links.
|
|
20
|
+
* Uses `iso || code` — never emits routing `code` when `iso` is set (#243).
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveHreflangAlternates(locales: HreflangLocaleInput[], options?: ResolveHreflangAlternatesOptions): HreflangAlternate[];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
function u(n) {
|
|
2
|
+
return n.iso?.trim() || String(n.code);
|
|
3
|
+
}
|
|
4
|
+
function f(n) {
|
|
5
|
+
const r = n.match(/^([A-Za-z]{2,3})(?:[-_](.+))?$/);
|
|
6
|
+
return r ? { language: r[1], region: r[2] } : { language: n };
|
|
7
|
+
}
|
|
8
|
+
function d(n, r = {}) {
|
|
9
|
+
const { hreflangBaseLanguage: l = !1 } = r;
|
|
10
|
+
if (!l)
|
|
11
|
+
return n.map((o) => {
|
|
12
|
+
const t = String(o.code);
|
|
13
|
+
return { hreflang: u(o), localeCode: t };
|
|
14
|
+
});
|
|
15
|
+
const g = /* @__PURE__ */ new Map();
|
|
16
|
+
for (const o of n) {
|
|
17
|
+
const t = String(o.code), a = u(o), { language: e, region: i } = f(a);
|
|
18
|
+
e && i && !g.has(e) && g.set(e, t), g.set(a, t);
|
|
19
|
+
}
|
|
20
|
+
const s = /* @__PURE__ */ new Set(), c = [];
|
|
21
|
+
for (const o of n) {
|
|
22
|
+
const t = String(o.code), a = u(o), { language: e, region: i } = f(a);
|
|
23
|
+
e && i && g.get(e) === t && !s.has(e) && (s.add(e), c.push({ hreflang: e, localeCode: t })), s.has(a) || (s.add(a), c.push({ hreflang: a, localeCode: t }));
|
|
24
|
+
}
|
|
25
|
+
return c;
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
d as resolveHreflangAlternates
|
|
29
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function a(s){const o=[],n={},r=new Set;for(const t of s){const e=t.name?.trim();if(!e)throw new Error("[splitLocaleRoutes] each entry needs a non-empty `name`");if(!t.path)throw new Error(`[splitLocaleRoutes] entry "${e}" needs a \`path\``);if(!t.file)throw new Error(`[splitLocaleRoutes] entry "${e}" needs a \`file\``);if(r.has(e))throw new Error(`[splitLocaleRoutes] duplicate route name "${e}"`);r.add(e),o.push({name:e,path:t.path,file:t.file}),t.paths!==void 0&&(n[e]=t.paths)}return{pages:o,globalLocaleRoutes:n}}exports.splitLocaleRoutes=a;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { GlobalLocaleRoutes, LocaleCode } from '@i18n-micro/types';
|
|
2
|
+
/**
|
|
3
|
+
* One programmatic route entry for {@link splitLocaleRoutes} (#244).
|
|
4
|
+
* Prefer route `name` as the `globalLocaleRoutes` key so shared wrapper SFCs do not collapse.
|
|
5
|
+
*/
|
|
6
|
+
export interface SplitLocaleRouteEntry {
|
|
7
|
+
/** Route name — also the key in `globalLocaleRoutes`. */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Default (unlocalized) path pushed into `pages:extend`. */
|
|
10
|
+
path: string;
|
|
11
|
+
/** Page component / wrapper SFC (Nuxt `file`). */
|
|
12
|
+
file: string;
|
|
13
|
+
/**
|
|
14
|
+
* Custom per-locale paths, or `false` to disable localization for this route.
|
|
15
|
+
* Omitted → route is still pushed to `pages`, but no `globalLocaleRoutes` entry.
|
|
16
|
+
*/
|
|
17
|
+
paths?: Record<LocaleCode, string> | false;
|
|
18
|
+
}
|
|
19
|
+
export interface SplitLocaleRoutePage {
|
|
20
|
+
name: string;
|
|
21
|
+
path: string;
|
|
22
|
+
file: string;
|
|
23
|
+
}
|
|
24
|
+
export interface SplitLocaleRoutesResult {
|
|
25
|
+
/** Pass into `pages:extend`: `pages.push(...pages)`. */
|
|
26
|
+
pages: SplitLocaleRoutePage[];
|
|
27
|
+
/** Merge into `i18n.globalLocaleRoutes` (keyed by route name). */
|
|
28
|
+
globalLocaleRoutes: NonNullable<GlobalLocaleRoutes>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Split one programmatic route registry into Nuxt pages + `globalLocaleRoutes` (#244).
|
|
32
|
+
*
|
|
33
|
+
* Keeps both halves in sync and keys locale paths by route **name** (not file path),
|
|
34
|
+
* so N routes sharing one wrapper SFC do not overwrite each other.
|
|
35
|
+
*/
|
|
36
|
+
export declare function splitLocaleRoutes(entries: readonly SplitLocaleRouteEntry[]): SplitLocaleRoutesResult;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { GlobalLocaleRoutes, LocaleCode } from '@i18n-micro/types';
|
|
2
|
+
/**
|
|
3
|
+
* One programmatic route entry for {@link splitLocaleRoutes} (#244).
|
|
4
|
+
* Prefer route `name` as the `globalLocaleRoutes` key so shared wrapper SFCs do not collapse.
|
|
5
|
+
*/
|
|
6
|
+
export interface SplitLocaleRouteEntry {
|
|
7
|
+
/** Route name — also the key in `globalLocaleRoutes`. */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Default (unlocalized) path pushed into `pages:extend`. */
|
|
10
|
+
path: string;
|
|
11
|
+
/** Page component / wrapper SFC (Nuxt `file`). */
|
|
12
|
+
file: string;
|
|
13
|
+
/**
|
|
14
|
+
* Custom per-locale paths, or `false` to disable localization for this route.
|
|
15
|
+
* Omitted → route is still pushed to `pages`, but no `globalLocaleRoutes` entry.
|
|
16
|
+
*/
|
|
17
|
+
paths?: Record<LocaleCode, string> | false;
|
|
18
|
+
}
|
|
19
|
+
export interface SplitLocaleRoutePage {
|
|
20
|
+
name: string;
|
|
21
|
+
path: string;
|
|
22
|
+
file: string;
|
|
23
|
+
}
|
|
24
|
+
export interface SplitLocaleRoutesResult {
|
|
25
|
+
/** Pass into `pages:extend`: `pages.push(...pages)`. */
|
|
26
|
+
pages: SplitLocaleRoutePage[];
|
|
27
|
+
/** Merge into `i18n.globalLocaleRoutes` (keyed by route name). */
|
|
28
|
+
globalLocaleRoutes: NonNullable<GlobalLocaleRoutes>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Split one programmatic route registry into Nuxt pages + `globalLocaleRoutes` (#244).
|
|
32
|
+
*
|
|
33
|
+
* Keeps both halves in sync and keys locale paths by route **name** (not file path),
|
|
34
|
+
* so N routes sharing one wrapper SFC do not overwrite each other.
|
|
35
|
+
*/
|
|
36
|
+
export declare function splitLocaleRoutes(entries: readonly SplitLocaleRouteEntry[]): SplitLocaleRoutesResult;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function s(a) {
|
|
2
|
+
const o = [], n = {}, r = /* @__PURE__ */ new Set();
|
|
3
|
+
for (const t of a) {
|
|
4
|
+
const e = t.name?.trim();
|
|
5
|
+
if (!e)
|
|
6
|
+
throw new Error("[splitLocaleRoutes] each entry needs a non-empty `name`");
|
|
7
|
+
if (!t.path)
|
|
8
|
+
throw new Error(`[splitLocaleRoutes] entry "${e}" needs a \`path\``);
|
|
9
|
+
if (!t.file)
|
|
10
|
+
throw new Error(`[splitLocaleRoutes] entry "${e}" needs a \`file\``);
|
|
11
|
+
if (r.has(e))
|
|
12
|
+
throw new Error(`[splitLocaleRoutes] duplicate route name "${e}"`);
|
|
13
|
+
r.add(e), o.push({ name: e, path: t.path, file: t.file }), t.paths !== void 0 && (n[e] = t.paths);
|
|
14
|
+
}
|
|
15
|
+
return { pages: o, globalLocaleRoutes: n };
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
s as splitLocaleRoutes
|
|
19
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@i18n-micro/utils",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.13",
|
|
4
4
|
"description": "Framework-agnostic utilities for Nuxt I18n Micro (granular subpath imports).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"i18n",
|
|
@@ -165,6 +165,36 @@
|
|
|
165
165
|
},
|
|
166
166
|
"default": "./dist/resolve-locale.mjs"
|
|
167
167
|
},
|
|
168
|
+
"./auto-detect-path": {
|
|
169
|
+
"production": {
|
|
170
|
+
"types": "./dist/auto-detect-path.d.ts",
|
|
171
|
+
"default": "./dist/auto-detect-path.mjs"
|
|
172
|
+
},
|
|
173
|
+
"import": {
|
|
174
|
+
"types": "./dist/auto-detect-path.d.ts",
|
|
175
|
+
"default": "./dist/auto-detect-path.mjs"
|
|
176
|
+
},
|
|
177
|
+
"require": {
|
|
178
|
+
"types": "./dist/auto-detect-path.d.cts",
|
|
179
|
+
"default": "./dist/auto-detect-path.cjs"
|
|
180
|
+
},
|
|
181
|
+
"default": "./dist/auto-detect-path.mjs"
|
|
182
|
+
},
|
|
183
|
+
"./split-locale-routes": {
|
|
184
|
+
"production": {
|
|
185
|
+
"types": "./dist/split-locale-routes.d.ts",
|
|
186
|
+
"default": "./dist/split-locale-routes.mjs"
|
|
187
|
+
},
|
|
188
|
+
"import": {
|
|
189
|
+
"types": "./dist/split-locale-routes.d.ts",
|
|
190
|
+
"default": "./dist/split-locale-routes.mjs"
|
|
191
|
+
},
|
|
192
|
+
"require": {
|
|
193
|
+
"types": "./dist/split-locale-routes.d.cts",
|
|
194
|
+
"default": "./dist/split-locale-routes.cjs"
|
|
195
|
+
},
|
|
196
|
+
"default": "./dist/split-locale-routes.mjs"
|
|
197
|
+
},
|
|
168
198
|
"./resolve-og-locale": {
|
|
169
199
|
"production": {
|
|
170
200
|
"types": "./dist/resolve-og-locale.d.ts",
|
|
@@ -180,6 +210,21 @@
|
|
|
180
210
|
},
|
|
181
211
|
"default": "./dist/resolve-og-locale.mjs"
|
|
182
212
|
},
|
|
213
|
+
"./resolve-hreflang": {
|
|
214
|
+
"production": {
|
|
215
|
+
"types": "./dist/resolve-hreflang.d.ts",
|
|
216
|
+
"default": "./dist/resolve-hreflang.mjs"
|
|
217
|
+
},
|
|
218
|
+
"import": {
|
|
219
|
+
"types": "./dist/resolve-hreflang.d.ts",
|
|
220
|
+
"default": "./dist/resolve-hreflang.mjs"
|
|
221
|
+
},
|
|
222
|
+
"require": {
|
|
223
|
+
"types": "./dist/resolve-hreflang.d.cts",
|
|
224
|
+
"default": "./dist/resolve-hreflang.cjs"
|
|
225
|
+
},
|
|
226
|
+
"default": "./dist/resolve-hreflang.mjs"
|
|
227
|
+
},
|
|
183
228
|
"./merge-i18n-head": {
|
|
184
229
|
"production": {
|
|
185
230
|
"types": "./dist/merge-i18n-head.d.ts",
|
|
@@ -353,14 +398,14 @@
|
|
|
353
398
|
},
|
|
354
399
|
"dependencies": {
|
|
355
400
|
"globby": "^14.1.0",
|
|
356
|
-
"@i18n-micro/types": "1.2.
|
|
401
|
+
"@i18n-micro/types": "^1.2.10"
|
|
357
402
|
},
|
|
358
403
|
"devDependencies": {
|
|
359
404
|
"publint": "^0.3.17",
|
|
360
405
|
"vite": "^7.3.6",
|
|
361
406
|
"vite-plugin-dts": "^4.5.4",
|
|
362
407
|
"vitest": "^4.1.10",
|
|
363
|
-
"@i18n-micro/test-utils": "1.2.
|
|
408
|
+
"@i18n-micro/test-utils": "^1.2.8"
|
|
364
409
|
},
|
|
365
410
|
"engines": {
|
|
366
411
|
"node": ">=18"
|