@i18n-micro/astro 1.3.25 → 2.0.1
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 +1 -1
- package/README.md +8 -64
- package/dist/auto-middleware.d.ts +1 -0
- package/dist/client/core.d.cts +86 -0
- package/dist/client/core.d.ts +71 -8
- package/dist/client/index.d.cts +2 -6
- package/dist/client/index.d.ts +2 -6
- package/dist/client/index.js +1 -6
- package/dist/client/preact.d.ts +12 -23
- package/dist/client/preact.js +13 -37
- package/dist/client/react.d.ts +14 -21
- package/dist/client/react.js +12 -37
- package/dist/client/svelte.d.ts +14 -14
- package/dist/client/svelte.js +17 -47
- package/dist/client/vue.d.ts +15 -15
- package/dist/client/vue.js +37 -2
- package/dist/composer.d.cts +16 -0
- package/dist/composer.d.ts +10 -30
- package/dist/core-CgrgdmGy.cjs +1 -0
- package/dist/core-DTAcn2yF.js +72 -0
- package/dist/env.d.ts +8 -2
- package/dist/index.cjs +11 -3
- package/dist/index.d.cts +10 -13
- package/dist/index.d.ts +10 -13
- package/dist/index.mjs +171 -482
- package/dist/integration.d.cts +26 -0
- package/dist/integration.d.ts +14 -15
- package/dist/middleware-BT3OA5YL.cjs +1 -0
- package/dist/middleware-Ch8E0iV_.js +257 -0
- package/dist/middleware.d.cts +34 -0
- package/dist/middleware.d.ts +17 -8
- package/dist/middleware.js +23 -0
- package/dist/node.d.ts +26 -0
- package/dist/node.js +22 -0
- package/dist/request.d.ts +69 -0
- package/dist/router/adapter.d.cts +9 -0
- package/dist/router/adapter.d.ts +5 -4
- package/dist/router/types.d.cts +66 -0
- package/dist/router/types.d.ts +3 -2
- package/dist/utils.d.cts +112 -0
- package/dist/utils.d.ts +39 -35
- package/dist/virtual.d.ts +21 -0
- package/package.json +28 -15
- package/src/auto-middleware.ts +26 -0
- package/src/client/core.ts +124 -59
- package/src/client/index.ts +2 -11
- package/src/client/preact.tsx +12 -127
- package/src/client/react.tsx +11 -123
- package/src/client/svelte.ts +6 -69
- package/src/client/vue.ts +22 -77
- package/src/components/i18n-link.astro +2 -59
- package/src/components/i18n-switcher.astro +46 -149
- package/src/components/i18n-t.astro +6 -54
- package/src/composer.ts +25 -115
- package/src/env.d.ts +7 -0
- package/src/index.ts +1 -6
- package/src/integration.ts +113 -52
- package/src/middleware.ts +174 -120
- package/src/node.ts +51 -0
- package/src/request.ts +177 -0
- package/src/router/adapter.ts +47 -149
- package/src/router/types.ts +3 -2
- package/src/utils.ts +149 -323
- package/src/virtual.d.ts +21 -0
- package/dist/components/index.d.cts +0 -0
- package/dist/components/index.d.ts +0 -0
- package/dist/core-DwkpOV-H.cjs +0 -1
- package/dist/core-VSnkGRWR.js +0 -28
- package/dist/load-translations.d.ts +0 -43
- package/dist/routing-context.d.ts +0 -4
- package/dist/vue-BNiEwZr2.cjs +0 -5
- package/dist/vue-CWHjIOiS.js +0 -1724
- package/src/components/index.ts +0 -11
- package/src/load-translations.ts +0 -106
- package/src/routing-context.ts +0 -23
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Locale } from '@i18n-micro/types';
|
|
2
|
+
import { AstroIntegration } from 'astro';
|
|
3
|
+
import { AstroI18n, AstroI18nOptions } from './composer.cjs';
|
|
4
|
+
export interface I18nIntegrationOptions {
|
|
5
|
+
locale: string;
|
|
6
|
+
fallbackLocale?: string;
|
|
7
|
+
locales?: Locale[];
|
|
8
|
+
missingWarn?: boolean;
|
|
9
|
+
localeCookie?: string | null;
|
|
10
|
+
autoDetect?: boolean;
|
|
11
|
+
/** `/` also redirects when nothing prefers another locale: see `createI18nMiddleware`. */
|
|
12
|
+
redirectToDefault?: boolean;
|
|
13
|
+
/** Bundled into the server at build time, relative to the project root. */
|
|
14
|
+
translationDir?: string;
|
|
15
|
+
/** Page files (`pages/about/de.json`) count as root translations. */
|
|
16
|
+
disablePageLocales?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* `false`: no middleware from the integration. Write `src/middleware.ts` with `createI18nMiddleware`
|
|
19
|
+
* for what cannot cross from the Astro config to the server bundle: `plural`, `missingHandler`, a strategy.
|
|
20
|
+
*/
|
|
21
|
+
middleware?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** Astro integration for i18n-micro: publishes the config and dictionaries, and installs the middleware. */
|
|
24
|
+
export declare function i18nIntegration(options: I18nIntegrationOptions): AstroIntegration;
|
|
25
|
+
/** Create an i18n instance (for a `src/middleware.ts` of your own). */
|
|
26
|
+
export declare function createI18n(options: AstroI18nOptions): AstroI18n;
|
package/dist/integration.d.ts
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
import { Locale
|
|
1
|
+
import { Locale } from '@i18n-micro/types';
|
|
2
2
|
import { AstroIntegration } from 'astro';
|
|
3
|
-
import { AstroI18n, AstroI18nOptions } from './composer';
|
|
4
|
-
|
|
5
|
-
export interface I18nIntegrationOptions extends Omit<ModuleOptions, 'plural'> {
|
|
3
|
+
import { AstroI18n, AstroI18nOptions } from './composer.js';
|
|
4
|
+
export interface I18nIntegrationOptions {
|
|
6
5
|
locale: string;
|
|
7
6
|
fallbackLocale?: string;
|
|
8
7
|
locales?: Locale[];
|
|
9
|
-
messages?: Record<string, Record<string, unknown>>;
|
|
10
|
-
plural?: PluralFunc;
|
|
11
8
|
missingWarn?: boolean;
|
|
12
|
-
missingHandler?: (locale: string, key: string, routeName: string) => void;
|
|
13
9
|
localeCookie?: string | null;
|
|
14
10
|
autoDetect?: boolean;
|
|
11
|
+
/** `/` also redirects when nothing prefers another locale: see `createI18nMiddleware`. */
|
|
15
12
|
redirectToDefault?: boolean;
|
|
13
|
+
/** Bundled into the server at build time, relative to the project root. */
|
|
16
14
|
translationDir?: string;
|
|
17
|
-
|
|
15
|
+
/** Page files (`pages/about/de.json`) count as root translations. */
|
|
16
|
+
disablePageLocales?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* `false`: no middleware from the integration. Write `src/middleware.ts` with `createI18nMiddleware`
|
|
19
|
+
* for what cannot cross from the Astro config to the server bundle: `plural`, `missingHandler`, a strategy.
|
|
20
|
+
*/
|
|
21
|
+
middleware?: boolean;
|
|
18
22
|
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Astro Integration for i18n-micro
|
|
22
|
-
*/
|
|
23
|
+
/** Astro integration for i18n-micro: publishes the config and dictionaries, and installs the middleware. */
|
|
23
24
|
export declare function i18nIntegration(options: I18nIntegrationOptions): AstroIntegration;
|
|
24
|
-
/**
|
|
25
|
-
* Create i18n instance (for manual setup)
|
|
26
|
-
*/
|
|
25
|
+
/** Create an i18n instance (for a `src/middleware.ts` of your own). */
|
|
27
26
|
export declare function createI18n(options: AstroI18nOptions): AstroI18n;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let e=require("@i18n-micro/core"),t=require("@i18n-micro/runtime"),n=require("@i18n-micro/utils/active-locales"),r=require("@i18n-micro/utils/app-path"),i=require("@i18n-micro/utils/cookie"),a=require("@i18n-micro/utils/resolve-locale");var o=class extends t.I18n{constructor(e){super(e);let t=e.parent;this.initialMessages=t?.initialMessages??{...e.messages},this.initialRouteMessages=t?.initialRouteMessages??Object.fromEntries(Object.entries(e.routeMessages??{}).map(([e,t])=>[e,{...t}]))}keepMessages(e,t){this.initialMessages={...this.initialMessages,...e};let n={...this.initialRouteMessages};for(let[e,r]of Object.entries(t))n[e]={...n[e],...r};this.initialRouteMessages=n}getLocaleIso(){return this.localeIso}getRouteTranslations(e,t){return this.helper.getCache(e,t)??null}mergeTranslations(e,t,n){this.addRouteTranslations(e,t,n)}clearCache(){super.clearCache(),this.loadMessages(this.initialMessages,this.initialRouteMessages)}},s=e=>(0,r.trimTrailingSlashes)(e??``);function c(e,t){return t?e===`/`?t:`${t}${e}`:e}function l(e,t){try{return e.request.headers.get(t)}catch{return null}}function u(e){let t=e.isPrerendered?null:l(e,`referer`);if(!t)return null;try{return new URL(t)}catch{return null}}function d(e,t){let n=l(e,`sec-fetch-site`);return n?n===`same-origin`:t.host===e.url.host}function f(e){let t=u(e);return t&&new URL(t.pathname+t.search,e.url)}var p=e=>e?.startsWith(`/_server-islands/`)===!0||e?.startsWith(`/_actions/`)===!0;function m(e,t){let{routePattern:n,params:r}=e;if(!n)return;let i=/^\/\[([^\].]+)\]/.exec(n),a=i?r?.[i[1]]:void 0;if(!a)return n;let o=n.slice(i[0].length);return t.includes(a)?`/${a}${o}`:i[1]===`locale`?o||`/`:n}function h(e,{defaultLocale:t,locales:n,strategy:r}){let i=(0,a.localeFromPath)(e,n);if(i)return i;let o=r.getLocaleFromPath?.(e,t,n)??null;return o!==t&&o!==null&&n.includes(o)?o:null}function g(e,t){let{strategy:n,locales:i,defaultLocale:a,base:o}=t,s=p(e.routePattern),c=s&&f(e)||e.url,l=(0,r.withoutAppBaseURL)(c.pathname,o),u=h(l,t),d=s?void 0:m(e,i);return{url:c,partOfPage:s,path:l,urlLocale:u,locale:u??a,route:n.getRouteName(l,i,d)}}function _(e,t,n){let i=u(e);return!i||!d(e,i)?!1:(h((0,r.withoutAppBaseURL)(i.pathname,n.base),n)??n.defaultLocale)!==t.locale}function v(e,t){let n=e.request.method??`GET`;return!t.partOfPage&&!e.isPrerendered&&(n===`GET`||n===`HEAD`)}function y(e,t){return!t.ok||!t.headers.get(`content-type`)?.startsWith(`text/html`)?!1:!`${l(e,`sec-purpose`)} ${l(e,`purpose`)}`.includes(`prefetch`)}var b=/^[a-z][a-z\d+.-]*:/i;function x(t,n,i){if(t===``||t[0]===`#`||t[0]===`?`)return t;let a=(0,e.externalLinkHref)(t)??(b.test(t)?t:void 0);if(a)return a;let{strategy:o,codes:s,defaultLocale:l,base:u,from:d=`/`}=i,f=(0,e.pathEnd)(t),p=f===-1?t:t.slice(0,f),m=(0,e.withoutDots)(p[0]===`/`?(0,r.withoutAppBaseURL)(p,u):`${(0,r.trimTrailingSlashes)(d)}/${p}`),h=o.localizePath(m,n,s,l);return`${c(h+(p.length>1&&p.endsWith(`/`)&&!h.endsWith(`/`)?`/`:``),u)}${f===-1?``:t.slice(f)}`}var S=/\[(?:\.\.\.)?([^\]]+)\]/g;function C(t,n){let r=(0,e.pathSegments)((0,e.urlPath)(t));return r[0]!==void 0&&n.includes(r[0])&&r.shift(),r}var w=t=>t.slice((0,e.urlPath)(t).length);function T(e,t=[]){let n=C(e,t);if(n.length===0)return`index`;let r=n.join(`-`);return r.includes(`[`)?r.replace(S,`$1`):r}var E=(e,t=[])=>`/${C(e,t).join(`/`)}${w(e)}`;function D(e,t,n=[],r){let i=C(e,n);return t!==r&&i.unshift(t),`/${i.join(`/`)}${w(e)}`}function O(e,t,n){let i=e.map(e=>e.code),o=()=>n?.()??(typeof window<`u`?new URL(window.location.href):null);return{getCurrentPath:()=>o()?.pathname??`/`,getRouteName:(e,t=[],n)=>T(n??e,t),getLocaleFromPath:(e,t=`en`,n=[])=>(0,a.localeFromPath)(`/${(0,r.trimLeadingSlashes)(e)}`,n)??t,switchLocalePath:D,localizePath:D,removeLocaleFromPath:E,resolvePath:(e,n)=>D(typeof e==`string`?e:e.path||`/`,n,i,t),getRoute:()=>{let e=o();return e?{fullPath:e.pathname+e.search,query:Object.fromEntries(e.searchParams)}:{fullPath:`/`,query:{}}},push:e=>{typeof window<`u`&&(window.location.href=e.path)},replace:e=>{typeof window<`u`&&window.location.replace(e.path)}}}var k=`i18n-locale`;function A(e,t){if(t===null)return null;try{return e.get(t)?.value??null}catch{return null}}function j(e,t,n){let r=O(t,n);if(!e)return r;let i=e,a={};for(let[t,n]of Object.entries(r)){let r=i[t];a[t]=typeof r==`function`?r.bind(e):n}return a}function M(e,t,{cookies:n,headers:r,localeCookie:i,autoDetect:o}){return(0,a.resolveLocale)({defaultLocale:t.defaultLocale,validLocales:t.locales,autoDetectLanguage:o,url:h(e,t),cookie:o?A(n,i):null,acceptLanguage:o?l({request:{headers:r}},`accept-language`):null})}function N(e,t,n,r,i,a=k,o,s=!0){return M(e,{defaultLocale:r,locales:i,strategy:j(o,i.map(e=>({code:e})),r)},{cookies:t,headers:n,localeCookie:a,autoDetect:s})}var P=!1;function F(){P||(P=!0,console.warn("[i18n-micro] i18nIntegration already installs the middleware: pass `middleware: false` to it to use your own createI18nMiddleware."))}function I(e){let{i18n:t,defaultLocale:r,localeObjects:a,autoDetect:o=!0}=e,l=e.localeCookie===void 0?k:e.localeCookie,u=a??e.locales.map(e=>({code:e})),d=s(e.base),f={defaultLocale:r,base:d,locales:(0,n.getEnabledLocaleCodes)(u).filter(t=>e.locales.includes(t)),strategy:j(e.routingStrategy,u,r)},p={path:d||`/`,maxAge:i.DEFAULT_COOKIE_MAX_AGE,sameSite:`lax`},m=l===null?`Accept-Language`:`Cookie, Accept-Language`,h=async(n,r)=>{if(n.locals.locale&&n.locals.i18n)return n.locals.i18nHandler&&n.locals.i18nHandler!==h&&F(),r();let i=g(n,f),{path:a,url:s,locale:b,partOfPage:x}=i,S=v(n,i),C=S&&_(n,i,f),w=S&&a===`/`,T=o&&w&&!C?M(a,f,{cookies:n.cookies,headers:n.request.headers,localeCookie:l,autoDetect:!0}):b,E=[x||C?`Referer`:``,o&&w?m:``].filter(Boolean).join(`, `)||null,D=T!==b||w&&e.redirectToDefault?R(T,f):a;if(D!==a)return z(n.redirect(c(D,d)+s.search,302),E);Object.assign(n.locals,L(t,i,f,u,h));let O=await r();return C&&l!==null&&y(n,O)&&n.cookies.set(l,b,p),z(O,E)};return h}function L(e,t,n,r,i){let{url:a,path:o,locale:s,route:c}=t,l=e.fork(s);l.setRoute(c);let u=Object.create(n.strategy);return u.getCurrentPath=()=>o,u.getRoute=()=>({fullPath:o+a.search,query:Object.fromEntries(a.searchParams)}),{i18n:l,locale:s,defaultLocale:n.defaultLocale,locales:r,currentUrl:a,routingStrategy:u,i18nBase:n.base,i18nHandler:i}}function R(e,{strategy:t,defaultLocale:n}){let r=t.resolvePath(`/`,e);return(typeof r==`string`?r:r.path)||(e===n?`/`:`/${e}`)}function z(e,t){if(t===null)return e;try{e.headers.append(`Vary`,t)}catch{}return e}Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return I}});
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { externalLinkHref as e, pathEnd as t, pathSegments as n, urlPath as r, withoutDots as i } from "@i18n-micro/core";
|
|
2
|
+
import { I18n as a } from "@i18n-micro/runtime";
|
|
3
|
+
import { getEnabledLocaleCodes as o } from "@i18n-micro/utils/active-locales";
|
|
4
|
+
import { trimLeadingSlashes as s, trimTrailingSlashes as c, withoutAppBaseURL as l } from "@i18n-micro/utils/app-path";
|
|
5
|
+
import { DEFAULT_COOKIE_MAX_AGE as u } from "@i18n-micro/utils/cookie";
|
|
6
|
+
import { localeFromPath as d, resolveLocale as f } from "@i18n-micro/utils/resolve-locale";
|
|
7
|
+
// src/composer.ts
|
|
8
|
+
var p = class extends a {
|
|
9
|
+
constructor(e) {
|
|
10
|
+
super(e);
|
|
11
|
+
let t = e.parent;
|
|
12
|
+
this.initialMessages = t?.initialMessages ?? { ...e.messages }, this.initialRouteMessages = t?.initialRouteMessages ?? Object.fromEntries(Object.entries(e.routeMessages ?? {}).map(([e, t]) => [e, { ...t }]));
|
|
13
|
+
}
|
|
14
|
+
keepMessages(e, t) {
|
|
15
|
+
this.initialMessages = {
|
|
16
|
+
...this.initialMessages,
|
|
17
|
+
...e
|
|
18
|
+
};
|
|
19
|
+
let n = { ...this.initialRouteMessages };
|
|
20
|
+
for (let [e, r] of Object.entries(t)) n[e] = {
|
|
21
|
+
...n[e],
|
|
22
|
+
...r
|
|
23
|
+
};
|
|
24
|
+
this.initialRouteMessages = n;
|
|
25
|
+
}
|
|
26
|
+
getLocaleIso() {
|
|
27
|
+
return this.localeIso;
|
|
28
|
+
}
|
|
29
|
+
getRouteTranslations(e, t) {
|
|
30
|
+
return this.helper.getCache(e, t) ?? null;
|
|
31
|
+
}
|
|
32
|
+
mergeTranslations(e, t, n) {
|
|
33
|
+
this.addRouteTranslations(e, t, n);
|
|
34
|
+
}
|
|
35
|
+
clearCache() {
|
|
36
|
+
super.clearCache(), this.loadMessages(this.initialMessages, this.initialRouteMessages);
|
|
37
|
+
}
|
|
38
|
+
}, m = (e) => c(e ?? "");
|
|
39
|
+
function h(e, t) {
|
|
40
|
+
return t ? e === "/" ? t : `${t}${e}` : e;
|
|
41
|
+
}
|
|
42
|
+
function g(e, t) {
|
|
43
|
+
try {
|
|
44
|
+
return e.request.headers.get(t);
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function _(e) {
|
|
50
|
+
let t = e.isPrerendered ? null : g(e, "referer");
|
|
51
|
+
if (!t) return null;
|
|
52
|
+
try {
|
|
53
|
+
return new URL(t);
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function v(e, t) {
|
|
59
|
+
let n = g(e, "sec-fetch-site");
|
|
60
|
+
return n ? n === "same-origin" : t.host === e.url.host;
|
|
61
|
+
}
|
|
62
|
+
function y(e) {
|
|
63
|
+
let t = _(e);
|
|
64
|
+
return t && new URL(t.pathname + t.search, e.url);
|
|
65
|
+
}
|
|
66
|
+
var b = (e) => e?.startsWith("/_server-islands/") === !0 || e?.startsWith("/_actions/") === !0;
|
|
67
|
+
function x(e, t) {
|
|
68
|
+
let { routePattern: n, params: r } = e;
|
|
69
|
+
if (!n) return;
|
|
70
|
+
let i = /^\/\[([^\].]+)\]/.exec(n), a = i ? r?.[i[1]] : void 0;
|
|
71
|
+
if (!a) return n;
|
|
72
|
+
let o = n.slice(i[0].length);
|
|
73
|
+
return t.includes(a) ? `/${a}${o}` : i[1] === "locale" ? o || "/" : n;
|
|
74
|
+
}
|
|
75
|
+
function S(e, { defaultLocale: t, locales: n, strategy: r }) {
|
|
76
|
+
let i = d(e, n);
|
|
77
|
+
if (i) return i;
|
|
78
|
+
let a = r.getLocaleFromPath?.(e, t, n) ?? null;
|
|
79
|
+
return a !== t && a !== null && n.includes(a) ? a : null;
|
|
80
|
+
}
|
|
81
|
+
function C(e, t) {
|
|
82
|
+
let { strategy: n, locales: r, defaultLocale: i, base: a } = t, o = b(e.routePattern), s = o && y(e) || e.url, c = l(s.pathname, a), u = S(c, t), d = o ? void 0 : x(e, r);
|
|
83
|
+
return {
|
|
84
|
+
url: s,
|
|
85
|
+
partOfPage: o,
|
|
86
|
+
path: c,
|
|
87
|
+
urlLocale: u,
|
|
88
|
+
locale: u ?? i,
|
|
89
|
+
route: n.getRouteName(c, r, d)
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function w(e, t, n) {
|
|
93
|
+
let r = _(e);
|
|
94
|
+
return !r || !v(e, r) ? !1 : (S(l(r.pathname, n.base), n) ?? n.defaultLocale) !== t.locale;
|
|
95
|
+
}
|
|
96
|
+
function T(e, t) {
|
|
97
|
+
let n = e.request.method ?? "GET";
|
|
98
|
+
return !t.partOfPage && !e.isPrerendered && (n === "GET" || n === "HEAD");
|
|
99
|
+
}
|
|
100
|
+
function E(e, t) {
|
|
101
|
+
return !t.ok || !t.headers.get("content-type")?.startsWith("text/html") ? !1 : !`${g(e, "sec-purpose")} ${g(e, "purpose")}`.includes("prefetch");
|
|
102
|
+
}
|
|
103
|
+
var D = /^[a-z][a-z\d+.-]*:/i;
|
|
104
|
+
function O(n, r, a) {
|
|
105
|
+
if (n === "" || n[0] === "#" || n[0] === "?") return n;
|
|
106
|
+
let o = e(n) ?? (D.test(n) ? n : void 0);
|
|
107
|
+
if (o) return o;
|
|
108
|
+
let { strategy: s, codes: u, defaultLocale: d, base: f, from: p = "/" } = a, m = t(n), g = m === -1 ? n : n.slice(0, m), _ = i(g[0] === "/" ? l(g, f) : `${c(p)}/${g}`), v = s.localizePath(_, r, u, d);
|
|
109
|
+
return `${h(v + (g.length > 1 && g.endsWith("/") && !v.endsWith("/") ? "/" : ""), f)}${m === -1 ? "" : n.slice(m)}`;
|
|
110
|
+
}
|
|
111
|
+
// src/router/adapter.ts
|
|
112
|
+
var k = /\[(?:\.\.\.)?([^\]]+)\]/g;
|
|
113
|
+
function A(e, t) {
|
|
114
|
+
let i = n(r(e));
|
|
115
|
+
return i[0] !== void 0 && t.includes(i[0]) && i.shift(), i;
|
|
116
|
+
}
|
|
117
|
+
var j = (e) => e.slice(r(e).length);
|
|
118
|
+
function M(e, t = []) {
|
|
119
|
+
let n = A(e, t);
|
|
120
|
+
if (n.length === 0) return "index";
|
|
121
|
+
let r = n.join("-");
|
|
122
|
+
return r.includes("[") ? r.replace(k, "$1") : r;
|
|
123
|
+
}
|
|
124
|
+
var N = (e, t = []) => `/${A(e, t).join("/")}${j(e)}`;
|
|
125
|
+
function P(e, t, n = [], r) {
|
|
126
|
+
let i = A(e, n);
|
|
127
|
+
return t !== r && i.unshift(t), `/${i.join("/")}${j(e)}`;
|
|
128
|
+
}
|
|
129
|
+
function F(e, t, n) {
|
|
130
|
+
let r = e.map((e) => e.code), i = () => n?.() ?? (typeof window < "u" ? new URL(window.location.href) : null);
|
|
131
|
+
return {
|
|
132
|
+
getCurrentPath: () => i()?.pathname ?? "/",
|
|
133
|
+
getRouteName: (e, t = [], n) => M(n ?? e, t),
|
|
134
|
+
getLocaleFromPath: (e, t = "en", n = []) => d(`/${s(e)}`, n) ?? t,
|
|
135
|
+
switchLocalePath: P,
|
|
136
|
+
localizePath: P,
|
|
137
|
+
removeLocaleFromPath: N,
|
|
138
|
+
resolvePath: (e, n) => P(typeof e == "string" ? e : e.path || "/", n, r, t),
|
|
139
|
+
getRoute: () => {
|
|
140
|
+
let e = i();
|
|
141
|
+
return e ? {
|
|
142
|
+
fullPath: e.pathname + e.search,
|
|
143
|
+
query: Object.fromEntries(e.searchParams)
|
|
144
|
+
} : {
|
|
145
|
+
fullPath: "/",
|
|
146
|
+
query: {}
|
|
147
|
+
};
|
|
148
|
+
},
|
|
149
|
+
push: (e) => {
|
|
150
|
+
typeof window < "u" && (window.location.href = e.path);
|
|
151
|
+
},
|
|
152
|
+
replace: (e) => {
|
|
153
|
+
typeof window < "u" && window.location.replace(e.path);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
// src/middleware.ts
|
|
158
|
+
var I = "i18n-locale";
|
|
159
|
+
function L(e, t) {
|
|
160
|
+
if (t === null) return null;
|
|
161
|
+
try {
|
|
162
|
+
return e.get(t)?.value ?? null;
|
|
163
|
+
} catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function R(e, t, n) {
|
|
168
|
+
let r = F(t, n);
|
|
169
|
+
if (!e) return r;
|
|
170
|
+
let i = e, a = {};
|
|
171
|
+
for (let [t, n] of Object.entries(r)) {
|
|
172
|
+
let r = i[t];
|
|
173
|
+
a[t] = typeof r == "function" ? r.bind(e) : n;
|
|
174
|
+
}
|
|
175
|
+
return a;
|
|
176
|
+
}
|
|
177
|
+
function z(e, t, { cookies: n, headers: r, localeCookie: i, autoDetect: a }) {
|
|
178
|
+
return f({
|
|
179
|
+
defaultLocale: t.defaultLocale,
|
|
180
|
+
validLocales: t.locales,
|
|
181
|
+
autoDetectLanguage: a,
|
|
182
|
+
url: S(e, t),
|
|
183
|
+
cookie: a ? L(n, i) : null,
|
|
184
|
+
acceptLanguage: a ? g({ request: { headers: r } }, "accept-language") : null
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
function B(e, t, n, r, i, a = I, o, s = !0) {
|
|
188
|
+
return z(e, {
|
|
189
|
+
defaultLocale: r,
|
|
190
|
+
locales: i,
|
|
191
|
+
strategy: R(o, i.map((e) => ({ code: e })), r)
|
|
192
|
+
}, {
|
|
193
|
+
cookies: t,
|
|
194
|
+
headers: n,
|
|
195
|
+
localeCookie: a,
|
|
196
|
+
autoDetect: s
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
var V = !1;
|
|
200
|
+
function H() {
|
|
201
|
+
V || (V = !0, console.warn("[i18n-micro] i18nIntegration already installs the middleware: pass `middleware: false` to it to use your own createI18nMiddleware."));
|
|
202
|
+
}
|
|
203
|
+
function U(e) {
|
|
204
|
+
let { i18n: t, defaultLocale: n, localeObjects: r, autoDetect: i = !0 } = e, a = e.localeCookie === void 0 ? I : e.localeCookie, s = r ?? e.locales.map((e) => ({ code: e })), c = m(e.base), l = {
|
|
205
|
+
defaultLocale: n,
|
|
206
|
+
base: c,
|
|
207
|
+
locales: o(s).filter((t) => e.locales.includes(t)),
|
|
208
|
+
strategy: R(e.routingStrategy, s, n)
|
|
209
|
+
}, d = {
|
|
210
|
+
path: c || "/",
|
|
211
|
+
maxAge: u,
|
|
212
|
+
sameSite: "lax"
|
|
213
|
+
}, f = a === null ? "Accept-Language" : "Cookie, Accept-Language", p = async (n, r) => {
|
|
214
|
+
if (n.locals.locale && n.locals.i18n) return n.locals.i18nHandler && n.locals.i18nHandler !== p && H(), r();
|
|
215
|
+
let o = C(n, l), { path: u, url: m, locale: g, partOfPage: _ } = o, v = T(n, o), y = v && w(n, o, l), b = v && u === "/", x = i && b && !y ? z(u, l, {
|
|
216
|
+
cookies: n.cookies,
|
|
217
|
+
headers: n.request.headers,
|
|
218
|
+
localeCookie: a,
|
|
219
|
+
autoDetect: !0
|
|
220
|
+
}) : g, S = [_ || y ? "Referer" : "", i && b ? f : ""].filter(Boolean).join(", ") || null, D = x !== g || b && e.redirectToDefault ? G(x, l) : u;
|
|
221
|
+
if (D !== u) return K(n.redirect(h(D, c) + m.search, 302), S);
|
|
222
|
+
Object.assign(n.locals, W(t, o, l, s, p));
|
|
223
|
+
let O = await r();
|
|
224
|
+
return y && a !== null && E(n, O) && n.cookies.set(a, g, d), K(O, S);
|
|
225
|
+
};
|
|
226
|
+
return p;
|
|
227
|
+
}
|
|
228
|
+
function W(e, t, n, r, i) {
|
|
229
|
+
let { url: a, path: o, locale: s, route: c } = t, l = e.fork(s);
|
|
230
|
+
l.setRoute(c);
|
|
231
|
+
let u = Object.create(n.strategy);
|
|
232
|
+
return u.getCurrentPath = () => o, u.getRoute = () => ({
|
|
233
|
+
fullPath: o + a.search,
|
|
234
|
+
query: Object.fromEntries(a.searchParams)
|
|
235
|
+
}), {
|
|
236
|
+
i18n: l,
|
|
237
|
+
locale: s,
|
|
238
|
+
defaultLocale: n.defaultLocale,
|
|
239
|
+
locales: r,
|
|
240
|
+
currentUrl: a,
|
|
241
|
+
routingStrategy: u,
|
|
242
|
+
i18nBase: n.base,
|
|
243
|
+
i18nHandler: i
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function G(e, { strategy: t, defaultLocale: n }) {
|
|
247
|
+
let r = t.resolvePath("/", e);
|
|
248
|
+
return (typeof r == "string" ? r : r.path) || (e === n ? "/" : `/${e}`);
|
|
249
|
+
}
|
|
250
|
+
function K(e, t) {
|
|
251
|
+
if (t === null) return e;
|
|
252
|
+
try {
|
|
253
|
+
e.headers.append("Vary", t);
|
|
254
|
+
} catch {}
|
|
255
|
+
return e;
|
|
256
|
+
}
|
|
257
|
+
export { h as a, O as i, B as n, p as o, F as r, U as t };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Locale } from '@i18n-micro/types';
|
|
2
|
+
import { MiddlewareHandler } from 'astro';
|
|
3
|
+
import { AstroI18n } from './composer.cjs';
|
|
4
|
+
import { I18nRoutingStrategy } from './router/types.cjs';
|
|
5
|
+
export interface I18nMiddlewareOptions {
|
|
6
|
+
i18n: AstroI18n;
|
|
7
|
+
defaultLocale: string;
|
|
8
|
+
locales: string[];
|
|
9
|
+
localeObjects?: Locale[];
|
|
10
|
+
/** `/` redirects to the locale the cookie / Accept-Language prefer (default `true`); pages keep the URL's locale. */
|
|
11
|
+
autoDetect?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* `/` also redirects when nothing prefers another locale: to the home `routingStrategy` resolves
|
|
14
|
+
* for the default locale (default `false`). Without one `/` stays: it is the default locale's page.
|
|
15
|
+
*/
|
|
16
|
+
redirectToDefault?: boolean;
|
|
17
|
+
routingStrategy?: I18nRoutingStrategy;
|
|
18
|
+
/** Cookie holding the visitor's locale (default `'i18n-locale'`); `null` disables it. */
|
|
19
|
+
localeCookie?: string | null;
|
|
20
|
+
/** Astro's `base`, `config.base` of the virtual config. */
|
|
21
|
+
base?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare const DEFAULT_ASTRO_LOCALE_COOKIE = "i18n-locale";
|
|
24
|
+
/**
|
|
25
|
+
* Locale a visitor prefers: URL prefix → cookie → Accept-Language → default, the one precedence of
|
|
26
|
+
* `resolveLocale`. An explicit prefix always wins; `autoDetect: false` leaves only the URL.
|
|
27
|
+
*/
|
|
28
|
+
export declare function detectLocale(pathname: string, cookies: {
|
|
29
|
+
get: (name: string) => {
|
|
30
|
+
value: string;
|
|
31
|
+
} | undefined;
|
|
32
|
+
}, headers: Headers, defaultLocale: string, locales: string[], localeCookie?: string | null, routingStrategy?: I18nRoutingStrategy | null, autoDetect?: boolean): string;
|
|
33
|
+
/** Create Astro middleware for i18n locale detection */
|
|
34
|
+
export declare function createI18nMiddleware(options: I18nMiddlewareOptions): MiddlewareHandler;
|
package/dist/middleware.d.ts
CHANGED
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
import { Locale } from '@i18n-micro/types';
|
|
2
2
|
import { MiddlewareHandler } from 'astro';
|
|
3
|
-
import { AstroI18n } from './composer';
|
|
4
|
-
import { I18nRoutingStrategy } from './router/types';
|
|
3
|
+
import { AstroI18n } from './composer.js';
|
|
4
|
+
import { I18nRoutingStrategy } from './router/types.js';
|
|
5
5
|
export interface I18nMiddlewareOptions {
|
|
6
6
|
i18n: AstroI18n;
|
|
7
7
|
defaultLocale: string;
|
|
8
8
|
locales: string[];
|
|
9
9
|
localeObjects?: Locale[];
|
|
10
|
+
/** `/` redirects to the locale the cookie / Accept-Language prefer (default `true`); pages keep the URL's locale. */
|
|
10
11
|
autoDetect?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* `/` also redirects when nothing prefers another locale: to the home `routingStrategy` resolves
|
|
14
|
+
* for the default locale (default `false`). Without one `/` stays: it is the default locale's page.
|
|
15
|
+
*/
|
|
11
16
|
redirectToDefault?: boolean;
|
|
12
17
|
routingStrategy?: I18nRoutingStrategy;
|
|
18
|
+
/** Cookie holding the visitor's locale (default `'i18n-locale'`); `null` disables it. */
|
|
19
|
+
localeCookie?: string | null;
|
|
20
|
+
/** Astro's `base`, `config.base` of the virtual config. */
|
|
21
|
+
base?: string;
|
|
13
22
|
}
|
|
23
|
+
export declare const DEFAULT_ASTRO_LOCALE_COOKIE = "i18n-locale";
|
|
14
24
|
/**
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
export declare function createI18nMiddleware(options: I18nMiddlewareOptions): MiddlewareHandler;
|
|
18
|
-
/**
|
|
19
|
-
* Detect locale from request
|
|
25
|
+
* Locale a visitor prefers: URL prefix → cookie → Accept-Language → default, the one precedence of
|
|
26
|
+
* `resolveLocale`. An explicit prefix always wins; `autoDetect: false` leaves only the URL.
|
|
20
27
|
*/
|
|
21
28
|
export declare function detectLocale(pathname: string, cookies: {
|
|
22
29
|
get: (name: string) => {
|
|
23
30
|
value: string;
|
|
24
31
|
} | undefined;
|
|
25
|
-
}, headers: Headers, defaultLocale: string, locales: string[], localeCookie?: string | null, routingStrategy?: I18nRoutingStrategy | null): string;
|
|
32
|
+
}, headers: Headers, defaultLocale: string, locales: string[], localeCookie?: string | null, routingStrategy?: I18nRoutingStrategy | null, autoDetect?: boolean): string;
|
|
33
|
+
/** Create Astro middleware for i18n locale detection */
|
|
34
|
+
export declare function createI18nMiddleware(options: I18nMiddlewareOptions): MiddlewareHandler;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { o as e, t } from "./middleware-Ch8E0iV_.js";
|
|
2
|
+
import { localeIsoMap as n } from "@i18n-micro/core";
|
|
3
|
+
import { config as r } from "virtual:i18n-micro/config";
|
|
4
|
+
import { messages as i } from "virtual:i18n-micro/messages";
|
|
5
|
+
// src/auto-middleware.ts
|
|
6
|
+
var a = new e({
|
|
7
|
+
locale: r.defaultLocale,
|
|
8
|
+
fallbackLocale: r.fallbackLocale,
|
|
9
|
+
missingWarn: r.missingWarn,
|
|
10
|
+
localeIso: n(r.locales),
|
|
11
|
+
messages: i.root,
|
|
12
|
+
routeMessages: i.routes
|
|
13
|
+
}), o = t({
|
|
14
|
+
i18n: a,
|
|
15
|
+
defaultLocale: r.defaultLocale,
|
|
16
|
+
locales: r.localeCodes,
|
|
17
|
+
localeObjects: r.locales,
|
|
18
|
+
autoDetect: r.autoDetect,
|
|
19
|
+
redirectToDefault: r.redirectToDefault,
|
|
20
|
+
localeCookie: r.localeCookie,
|
|
21
|
+
base: r.base
|
|
22
|
+
});
|
|
23
|
+
export { o as onRequest };
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Translations } from '@i18n-micro/types';
|
|
2
|
+
import { TranslationFileBuckets } from '@i18n-micro/utils/parse-path';
|
|
3
|
+
export interface LoadTranslationsOptions {
|
|
4
|
+
translationDir: string;
|
|
5
|
+
rootDir?: string;
|
|
6
|
+
disablePageLocales?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface LoadedTranslations extends TranslationFileBuckets<Translations> {
|
|
9
|
+
}
|
|
10
|
+
/** Load all translations from a directory: flat (`en.json`) and nested (`pages/home/en.json`). */
|
|
11
|
+
export declare function loadTranslationsFromDir(options: LoadTranslationsOptions): LoadedTranslations;
|
|
12
|
+
/** The directory's dictionaries and the files they came from, for the integration's build. */
|
|
13
|
+
export declare function readTranslationDir(options: {
|
|
14
|
+
translationDir: string;
|
|
15
|
+
rootDir: URL;
|
|
16
|
+
disablePageLocales?: boolean;
|
|
17
|
+
}): {
|
|
18
|
+
messages: TranslationFileBuckets<Translations>;
|
|
19
|
+
files: string[];
|
|
20
|
+
};
|
|
21
|
+
/** Load a directory into an instance, replacing the chunks it finds. */
|
|
22
|
+
export declare function loadTranslationsIntoI18n(i18n: {
|
|
23
|
+
addTranslations: (locale: string, translations: Translations, merge?: boolean) => void;
|
|
24
|
+
addRouteTranslations: (locale: string, routeName: string, translations: Translations, merge?: boolean) => void;
|
|
25
|
+
keepMessages?: (messages: Record<string, Translations>, routeMessages: Record<string, Record<string, Translations>>) => void;
|
|
26
|
+
}, options: LoadTranslationsOptions): void;
|
package/dist/node.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { resolve as e } from "node:path";
|
|
2
|
+
import { fileURLToPath as t } from "node:url";
|
|
3
|
+
import { listTranslationFiles as n, loadTranslationDir as r, loadTranslationFiles as i } from "@i18n-micro/utils/load-dir";
|
|
4
|
+
// src/node.ts
|
|
5
|
+
function a(t) {
|
|
6
|
+
let { translationDir: n, rootDir: i = process.cwd(), disablePageLocales: a = !1 } = t;
|
|
7
|
+
return r(e(i, n), a);
|
|
8
|
+
}
|
|
9
|
+
function o(r) {
|
|
10
|
+
let a = e(t(r.rootDir), r.translationDir), o = n(a);
|
|
11
|
+
return {
|
|
12
|
+
messages: i(o, r.disablePageLocales),
|
|
13
|
+
files: [a, ...o.map((e) => e.absolutePath)]
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function s(e, t) {
|
|
17
|
+
let { root: n, routes: r } = a(t);
|
|
18
|
+
for (let [t, r] of Object.entries(n)) e.addTranslations(t, r, !1);
|
|
19
|
+
for (let [t, n] of Object.entries(r)) for (let [r, i] of Object.entries(n)) e.addRouteTranslations(r, t, i, !1);
|
|
20
|
+
e.keepMessages?.(n, r);
|
|
21
|
+
}
|
|
22
|
+
export { a as loadTranslationsFromDir, s as loadTranslationsIntoI18n, o as readTranslationDir };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { I18nRoutingStrategy } from './router/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The one request model. Everything below works on the page's path without Astro's `base`:
|
|
4
|
+
* the middleware strips it once, every URL that goes out gets it back from {@link withBase}.
|
|
5
|
+
*/
|
|
6
|
+
export interface I18nRouting {
|
|
7
|
+
defaultLocale: string;
|
|
8
|
+
/** Codes of the locales in service: a disabled one is neither a URL's locale nor a redirect target. */
|
|
9
|
+
locales: string[];
|
|
10
|
+
/** `''` or `/docs`, no trailing slash. */
|
|
11
|
+
base: string;
|
|
12
|
+
strategy: I18nRoutingStrategy;
|
|
13
|
+
}
|
|
14
|
+
/** The parts of an Astro context a request is read from: also a mock in tests. */
|
|
15
|
+
export interface RequestContext {
|
|
16
|
+
url: URL;
|
|
17
|
+
params?: Record<string, string | undefined>;
|
|
18
|
+
routePattern?: string;
|
|
19
|
+
isPrerendered?: boolean;
|
|
20
|
+
request: {
|
|
21
|
+
headers: Headers;
|
|
22
|
+
method?: string;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export interface I18nRequest {
|
|
26
|
+
/** The page this request is for: another URL than `context.url` for a server island or action. */
|
|
27
|
+
url: URL;
|
|
28
|
+
/** A server island or action: it belongs to the page in `url`, and is no page view itself. */
|
|
29
|
+
partOfPage: boolean;
|
|
30
|
+
/** `url.pathname` without `base`. */
|
|
31
|
+
path: string;
|
|
32
|
+
/** The locale `url` names, `null` for an unprefixed URL. */
|
|
33
|
+
urlLocale: string | null;
|
|
34
|
+
/** The URL's locale, else the default one: an unprefixed URL is the default locale's page. */
|
|
35
|
+
locale: string;
|
|
36
|
+
route: string;
|
|
37
|
+
}
|
|
38
|
+
export declare const normalizeBase: (base: string | undefined) => string;
|
|
39
|
+
/** `path`, which has no `base`, as a URL of the site. */
|
|
40
|
+
export declare function withBase(path: string, base: string): string;
|
|
41
|
+
/** A request header, or null where there is none (static prerendering). */
|
|
42
|
+
export declare function header(context: Pick<RequestContext, 'request'>, name: string): string | null;
|
|
43
|
+
/**
|
|
44
|
+
* Locale a path names: its prefix, or what the strategy reads from it when that is not the default
|
|
45
|
+
* (a strategy's `getLocaleFromPath` answers the default for a URL without a locale).
|
|
46
|
+
*/
|
|
47
|
+
export declare function localeOfPath(path: string, { defaultLocale, locales, strategy }: Omit<I18nRouting, 'base'>): string | null;
|
|
48
|
+
export declare function resolveRequest(context: RequestContext, routing: I18nRouting): I18nRequest;
|
|
49
|
+
/** Whether the visitor comes from a page of this site in another locale. */
|
|
50
|
+
export declare function isSwitch(context: RequestContext, request: I18nRequest, routing: I18nRouting): boolean;
|
|
51
|
+
/** A document may be asked for by this request: an island, an action or a form post is no landing. */
|
|
52
|
+
export declare function asksForPage(context: RequestContext, request: I18nRequest): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* The visitor did see this response as a page: no endpoint, image, 404 or redirect, and not a
|
|
55
|
+
* prefetch of a link they may never follow.
|
|
56
|
+
* ponytail: a `fetch` of an HTML fragment from a page of another locale still counts; `<ClientRouter>`
|
|
57
|
+
* navigates by `fetch` too, and the two look the same from here.
|
|
58
|
+
*/
|
|
59
|
+
export declare function isPageView(context: RequestContext, response: Response): boolean;
|
|
60
|
+
export interface HrefContext extends Pick<I18nRouting, 'base' | 'defaultLocale' | 'strategy'> {
|
|
61
|
+
codes: string[];
|
|
62
|
+
/** What a relative `href` resolves against: the page's path. */
|
|
63
|
+
from?: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* `href` as a link to `locale`. What leaves the app, and a bare `#hash` or `?query`, stays as
|
|
67
|
+
* written; a route is localized and keeps its query, hash and trailing slash.
|
|
68
|
+
*/
|
|
69
|
+
export declare function localizeHref(href: string, locale: string, context: HrefContext): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Locale } from '@i18n-micro/types';
|
|
2
|
+
import { I18nRoutingStrategy } from './types.cjs';
|
|
3
|
+
/** `/en/blog/post` → `blog-post`, `/blog/[slug]` → `blog-slug`, `/` → `index`. */
|
|
4
|
+
export declare function routeNameFromPath(path: string, locales?: readonly string[]): string;
|
|
5
|
+
/**
|
|
6
|
+
* Prefix-except-default routing over plain paths. Paths here never carry Astro's `base`: the
|
|
7
|
+
* middleware strips it from what comes in and adds it to what goes out.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createAstroRouterAdapter(locales: Locale[], defaultLocale: string, getCurrentUrl?: () => URL): I18nRoutingStrategy;
|
package/dist/router/adapter.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Locale } from '@i18n-micro/types';
|
|
2
|
-
import { I18nRoutingStrategy } from './types';
|
|
2
|
+
import { I18nRoutingStrategy } from './types.js';
|
|
3
|
+
/** `/en/blog/post` → `blog-post`, `/blog/[slug]` → `blog-slug`, `/` → `index`. */
|
|
4
|
+
export declare function routeNameFromPath(path: string, locales?: readonly string[]): string;
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Uses standard Astro APIs: Astro.url, context.url
|
|
6
|
+
* Prefix-except-default routing over plain paths. Paths here never carry Astro's `base`: the
|
|
7
|
+
* middleware strips it from what comes in and adds it to what goes out.
|
|
7
8
|
*/
|
|
8
9
|
export declare function createAstroRouterAdapter(locales: Locale[], defaultLocale: string, getCurrentUrl?: () => URL): I18nRoutingStrategy;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routing strategy interface for i18n in Astro
|
|
3
|
+
* Implement this interface to integrate with any routing logic
|
|
4
|
+
* Matches Vue/Solid/React package interface for consistency
|
|
5
|
+
* Adapted for Astro SSR context (push/replace are optional)
|
|
6
|
+
*/
|
|
7
|
+
export interface I18nRoutingStrategy {
|
|
8
|
+
/**
|
|
9
|
+
* Returns current path (without locale prefix if needed, or full path)
|
|
10
|
+
* Used for determining active classes in links
|
|
11
|
+
*/
|
|
12
|
+
getCurrentPath: () => string;
|
|
13
|
+
/**
|
|
14
|
+
* Generate path for specific locale
|
|
15
|
+
*/
|
|
16
|
+
resolvePath?: (to: string | {
|
|
17
|
+
path?: string;
|
|
18
|
+
}, locale: string) => string | {
|
|
19
|
+
path?: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Get route name from path (e.g., /en/about -> about)
|
|
23
|
+
* Used in middleware to set route name. `routePattern` is the page's pattern (`/blog/[slug]`), with
|
|
24
|
+
* a `[locale]` param already replaced by its value: use it to give every URL of a page one name.
|
|
25
|
+
*/
|
|
26
|
+
getRouteName?: (path: string, locales: string[], routePattern?: string) => string;
|
|
27
|
+
/**
|
|
28
|
+
* Get locale from path
|
|
29
|
+
* Checks if first segment is a locale code
|
|
30
|
+
*/
|
|
31
|
+
getLocaleFromPath?: (path: string, defaultLocale: string, locales: string[]) => string;
|
|
32
|
+
/**
|
|
33
|
+
* Switch locale in path
|
|
34
|
+
* Replaces or adds locale prefix to path
|
|
35
|
+
*/
|
|
36
|
+
switchLocalePath?: (path: string, newLocale: string, locales: string[], defaultLocale?: string) => string;
|
|
37
|
+
/**
|
|
38
|
+
* Localize path with locale prefix
|
|
39
|
+
*/
|
|
40
|
+
localizePath?: (path: string, locale: string, locales: string[], defaultLocale?: string) => string;
|
|
41
|
+
/**
|
|
42
|
+
* Remove locale from path
|
|
43
|
+
*/
|
|
44
|
+
removeLocaleFromPath?: (path: string, locales: string[]) => string;
|
|
45
|
+
/**
|
|
46
|
+
* (Optional) Function to navigate to another route/locale
|
|
47
|
+
* Not used in SSR, but can be used in client-side islands
|
|
48
|
+
*/
|
|
49
|
+
push?: (target: {
|
|
50
|
+
path: string;
|
|
51
|
+
}) => void;
|
|
52
|
+
/**
|
|
53
|
+
* (Optional) Function to replace current route
|
|
54
|
+
* Not used in SSR, but can be used in client-side islands
|
|
55
|
+
*/
|
|
56
|
+
replace?: (target: {
|
|
57
|
+
path: string;
|
|
58
|
+
}) => void;
|
|
59
|
+
/**
|
|
60
|
+
* (Optional) Get current route object for SEO/Meta tags
|
|
61
|
+
*/
|
|
62
|
+
getRoute?: () => {
|
|
63
|
+
fullPath: string;
|
|
64
|
+
query: Record<string, unknown>;
|
|
65
|
+
};
|
|
66
|
+
}
|