@i18n-micro/astro 1.3.12 → 1.3.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/README.md CHANGED
@@ -58,6 +58,23 @@ const { t, locale } = useI18n(Astro)
58
58
  </html>
59
59
  ```
60
60
 
61
+ ### 3. Locale-prefixed URLs (`/[locale]/*`)
62
+
63
+ When using `createAstroRouterAdapter`, add rewrite stubs under `src/pages/[locale]/`:
64
+
65
+ ```astro
66
+ ---
67
+ import { prepareLocaleRewrite } from '@i18n-micro/astro'
68
+
69
+ const rewriteTarget = prepareLocaleRewrite(Astro)
70
+ if (rewriteTarget instanceof Response) return rewriteTarget
71
+
72
+ return Astro.rewrite(rewriteTarget)
73
+ ---
74
+ ```
75
+
76
+ See the [full Astro integration guide](https://s00d.github.io/nuxt-i18n-micro/integrations/astro-package.html#locale-prefixed-routes-locale) for routing layout and typecheck notes.
77
+
61
78
  ## Resources
62
79
 
63
80
  - **Repository**: [https://github.com/s00d/nuxt-i18n-micro](https://github.com/s00d/nuxt-i18n-micro)
File without changes
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=require("@i18n-micro/core"),G=require("node:async_hooks"),R=require("node:fs"),$=require("node:path"),M=require("@i18n-micro/utils/parse-path"),V=require("@i18n-micro/utils/accept-language");class v extends j.BaseI18n{constructor(e){const r=e._storage||{translations:new Map};if(super({storage:r,plural:e.plural,missingWarn:e.missingWarn,missingHandler:e.missingHandler,numberFormats:e.numberFormats,datetimeFormats:e.datetimeFormats}),this.initialMessages={},this.storage=r,this._locale=e.locale,this._fallbackLocale=e.fallbackLocale||e.locale,this._currentRoute="index",e.messages){this.initialMessages={...e.messages};for(const[l,c]of Object.entries(e.messages))this.helper.loadTranslations(l,c)}}cloneStorage(e){const r=new Map;for(const[l,c]of e.translations)r.set(l,{...c});return{translations:r}}clone(e){const r=this.cloneStorage(this.storage);return new v({locale:e||this._locale,fallbackLocale:this._fallbackLocale,plural:this.pluralFunc,missingWarn:this.missingWarn,missingHandler:this.missingHandler,numberFormats:this.formatter.getNumberFormats(),datetimeFormats:this.formatter.getDateTimeFormats(),_storage:r})}get locale(){return this._locale}set locale(e){this._locale=e}get fallbackLocale(){return this._fallbackLocale}set fallbackLocale(e){this._fallbackLocale=e}setRoute(e){this._currentRoute=e}getLocale(){return this._locale}getFallbackLocale(){return this._fallbackLocale}getRoute(){return this._currentRoute}getRouteTranslations(e,r){const l=`${e}:${r}`;return this.storage.translations.get(l)??null}addTranslations(e,r,l=!0){super.loadTranslationsCore(e,r,l)}addRouteTranslations(e,r,l,c=!0){super.loadRouteTranslationsCore(e,r,l,c)}mergeTranslations(e,r,l){this.helper.mergeTranslation(e,r,l,!0)}clearCache(){const e={...this.initialMessages};if(super.clearCache(),Object.keys(e).length>0)for(const[r,l]of Object.entries(e))this.helper.loadTranslations(r,l)}}let q=null;const W=new G.AsyncLocalStorage;function _(){const t=W.getStore();return t!==void 0?t:q}function U(t){q=t}function H(t,e){return W.run(t,e)}function J(t){const{locale:e,fallbackLocale:r,translationDir:l,routingStrategy:c}=t;return U(c||null),{name:"@i18n-micro/astro",hooks:{"astro:config:setup":u=>{const{updateConfig:i}=u,o="virtual:i18n-micro/config",s=`\0${o}`,a={defaultLocale:e,fallbackLocale:r||e,locales:t.locales||[],localeCodes:(t.locales||[]).map(n=>n.code),translationDir:l||null,autoDetect:t.autoDetect??!0,redirectToDefault:t.redirectToDefault??!1,localeCookie:t.localeCookie===null?null:t.localeCookie||"i18n-locale",missingWarn:t.missingWarn??!1};i({vite:{plugins:[{name:"vite-plugin-i18n-micro-config",resolveId(n){if(n===o)return s},load(n){if(n===s)return`export const config = ${JSON.stringify(a)}`}}]}})},"astro:config:done":u=>{const{injectTypes:i}=u;i({filename:"i18n-micro-env.d.ts",content:`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=require("@i18n-micro/core"),J=require("node:async_hooks"),R=require("node:fs"),$=require("node:path"),M=require("@i18n-micro/utils/parse-path"),Z=require("@i18n-micro/utils/accept-language");class v extends j.BaseI18n{constructor(t){const a=t._storage||{translations:new Map};if(super({storage:a,plural:t.plural,missingWarn:t.missingWarn,missingHandler:t.missingHandler,numberFormats:t.numberFormats,datetimeFormats:t.datetimeFormats}),this.initialMessages={},this.storage=a,this._locale=t.locale,this._fallbackLocale=t.fallbackLocale||t.locale,this._currentRoute="index",t.messages){this.initialMessages={...t.messages};for(const[r,c]of Object.entries(t.messages))this.helper.loadTranslations(r,c)}}cloneStorage(t){const a=new Map;for(const[r,c]of t.translations)a.set(r,{...c});return{translations:a}}clone(t){const a=this.cloneStorage(this.storage);return new v({locale:t||this._locale,fallbackLocale:this._fallbackLocale,plural:this.pluralFunc,missingWarn:this.missingWarn,missingHandler:this.missingHandler,numberFormats:this.formatter.getNumberFormats(),datetimeFormats:this.formatter.getDateTimeFormats(),_storage:a})}get locale(){return this._locale}set locale(t){this._locale=t}get fallbackLocale(){return this._fallbackLocale}set fallbackLocale(t){this._fallbackLocale=t}setRoute(t){this._currentRoute=t}getLocale(){return this._locale}getFallbackLocale(){return this._fallbackLocale}getRoute(){return this._currentRoute}getRouteTranslations(t,a){const r=`${t}:${a}`;return this.storage.translations.get(r)??null}addTranslations(t,a,r=!0){super.loadTranslationsCore(t,a,r)}addRouteTranslations(t,a,r,c=!0){super.loadRouteTranslationsCore(t,a,r,c)}mergeTranslations(t,a,r){this.helper.mergeTranslation(t,a,r,!0)}clearCache(){const t={...this.initialMessages};if(super.clearCache(),Object.keys(t).length>0)for(const[a,r]of Object.entries(t))this.helper.loadTranslations(a,r)}}let q=null;const W=new J.AsyncLocalStorage;function C(){const e=W.getStore();return e!==void 0?e:q}function U(e){q=e}function H(e,t){return W.run(e,t)}function K(e){const{locale:t,fallbackLocale:a,translationDir:r,routingStrategy:c}=e;return U(c||null),{name:"@i18n-micro/astro",hooks:{"astro:config:setup":u=>{const{updateConfig:i}=u,o="virtual:i18n-micro/config",s=`\0${o}`,l={defaultLocale:t,fallbackLocale:a||t,locales:e.locales||[],localeCodes:(e.locales||[]).map(n=>n.code),translationDir:r||null,autoDetect:e.autoDetect??!0,redirectToDefault:e.redirectToDefault??!1,localeCookie:e.localeCookie===null?null:e.localeCookie||"i18n-locale",missingWarn:e.missingWarn??!1};i({vite:{plugins:[{name:"vite-plugin-i18n-micro-config",resolveId(n){if(n===o)return s},load(n){if(n===s)return`export const config = ${JSON.stringify(l)}`}}]}})},"astro:config:done":u=>{const{injectTypes:i}=u;i({filename:"i18n-micro-env.d.ts",content:`
2
2
  /// <reference types="@i18n-micro/astro/env" />
3
3
 
4
4
  declare module 'virtual:i18n-micro/config' {
@@ -14,4 +14,4 @@
14
14
  missingWarn: boolean | null;
15
15
  }
16
16
  }
17
- `})}}}}function Z(t){return new v(t)}function z(t,e){if(R.existsSync(t))for(const r of R.readdirSync(t)){const l=$.join(t,r);if(R.statSync(l).isDirectory()){z(l,e);continue}r.endsWith(".json")&&e(l)}}function E(t){const{translationDir:e,rootDir:r=process.cwd(),disablePageLocales:l=!1}=t,c=$.resolve(r,e);if(!R.existsSync(c))return console.warn(`[i18n] Translation directory not found: ${c}`),{root:{},routes:{}};const u={root:{},routes:{}};return z(c,i=>{const o=$.relative(c,i).split($.sep).join("/");try{const s=R.readFileSync(i,"utf-8"),a=JSON.parse(s);M.storeLoadedTranslationFile(u,o,a,l)}catch(s){console.error(`[i18n] Failed to load translation file: ${i}`,s)}}),u}function K(t,e){const{root:r,routes:l}=E(e);for(const[c,u]of Object.entries(r))t.addTranslations(c,u,!1);for(const[c,u]of Object.entries(l))for(const[i,o]of Object.entries(u))t.addRouteTranslations(i,c,M.mergeRouteTranslationsWithRoot(r[i],o),!1)}function Q(t){const{i18n:e,defaultLocale:r,locales:l,localeObjects:c,autoDetect:u=!0,redirectToDefault:i=!1,routingStrategy:o}=t,s=o||_();return async(a,n)=>{if(a.locals.locale&&a.locals.i18n)return n();const f=a.url,d=f.pathname;if(!s){const w=e.clone(r),g=d==="/"||d===""?"index":d.split("/").filter(Boolean).join("-");return w.setRoute(g),a.locals.i18n=w,a.locals.locale=r,a.locals.defaultLocale=r,a.locals.locales=c||l.map(L=>({code:L})),a.locals.currentUrl=f,n()}const h={...s,getCurrentPath:()=>d,getRoute:()=>({fullPath:f.pathname+f.search,query:Object.fromEntries(f.searchParams)})},m=d.split("/").filter(Boolean)[0],P=m!==void 0&&l.includes(m);let S;P&&m?S=m:h.getLocaleFromPath?S=h.getLocaleFromPath(d,r,l):S=r;const y=e.clone(S),T=h.getRouteName?h.getRouteName(d,l):"index";return y.setRoute(T),a.locals.i18n=y,a.locals.locale=S,a.locals.defaultLocale=r,a.locals.locales=c||l.map(w=>({code:w})),a.locals.currentUrl=f,a.locals.routingStrategy=h,H(h,()=>n())}}function X(t,e,r,l,c,u="i18n-locale",i){const o=i??_();let s=l;if(o?.getLocaleFromPath)s=o.getLocaleFromPath(t,l,c);else{const n=t.split("/").filter(Boolean)[0];n&&c.includes(n)&&(s=n)}if(u!==null&&s===l&&e.get(u)){const a=e.get(u)?.value;a&&c.includes(a)&&(s=a)}if(s===l)try{const a=V.detectLocaleFromAcceptLanguage(r.get("accept-language")??void 0,c);a&&(s=a)}catch{}return s}function Y(t,e,r){const l=t.map(n=>n.code),c=(n,f=[])=>{const d=n.replace(/^\//,"").replace(/\/$/,"");if(!d)return"index";const h=d.split("/").filter(Boolean),p=h[0];return p&&f.includes(p)&&h.shift(),h.length===0?"index":h.join("-")},u=(n,f="en",d=[])=>{const p=n.split("/").filter(Boolean)[0];return p&&d.includes(p)?p:f},i=(n,f,d=[],h)=>{const p=n.split("/").filter(Boolean),m=p[0];return m&&d.includes(m)&&p.shift(),(f!==h||h===void 0)&&p.unshift(f),`/${p.join("/")}`},o=(n,f,d=[],h)=>{const m=(n.replace(/^\//,"").replace(/\/$/,"")||"").split("/").filter(Boolean),P=m[0];return P&&d.includes(P)&&m.shift(),(f!==h||h===void 0)&&m.unshift(f),`/${m.join("/")}`};return{getCurrentPath:()=>r?r().pathname:typeof window<"u"?window.location.pathname:"/",getRouteName:c,getLocaleFromPath:u,switchLocalePath:i,localizePath:o,removeLocaleFromPath:(n,f=[])=>{const d=n.split("/").filter(Boolean),h=d[0];return h&&f.includes(h)&&d.shift(),`/${d.join("/")}`},resolvePath:(n,f)=>{const d=typeof n=="string"?n:n.path||"/";return o(d,f,l,e)},getRoute:()=>{if(r){const n=r();return{fullPath:n.pathname+n.search,query:Object.fromEntries(n.searchParams)}}if(typeof window<"u"){const n=new URL(window.location.href);return{fullPath:n.pathname+n.search,query:Object.fromEntries(n.searchParams)}}return{fullPath:"/",query:{}}},push:n=>{typeof window<"u"&&(window.location.href=n.path)},replace:n=>{typeof window<"u"&&window.location.replace(n.path)}}}function D(t){return t.iso?.trim()||String(t.code)}function N(t){const e=t.match(/^([A-Za-z]{2,3})(?:[-_](.+))?$/);return e?{language:e[1],region:e[2]}:{language:t}}function ee(t,e={}){const{hreflangBaseLanguage:r=!1}=e;if(!r)return t.map(i=>{const o=String(i.code);return{hreflang:D(i),localeCode:o}});const l=new Map;for(const i of t){const o=String(i.code),s=D(i),{language:a,region:n}=N(s);a&&n&&!l.has(a)&&l.set(a,o),l.set(s,o)}const c=new Set,u=[];for(const i of t){const o=String(i.code),s=D(i),{language:a,region:n}=N(s);a&&n&&l.get(a)===o&&!c.has(a)&&(c.add(a),u.push({hreflang:a,localeCode:o})),c.has(s)||(c.add(s),u.push({hreflang:s,localeCode:o}))}return u}function I(t){const e=t.og?.trim();if(e)return e;const r=t.iso?.trim();if(!r)return null;const l=r.indexOf("_");if(l>0){const u=r.slice(0,l),i=r.slice(l+1);if(u.length>=2&&i.length===2)return`${u.toLowerCase()}_${i.toUpperCase()}`}const c=r.indexOf("-");if(c>0){const u=r.slice(0,c),i=r.slice(c+1);if(u.length>=2&&i.length===2&&/^[A-Za-z]{2}$/.test(i))return`${u.toLowerCase()}_${i.toUpperCase()}`}return null}function A(t,e={}){if(I(t)!==null||e.missingWarn===!1||process.env.NODE_ENV==="production")return;const r=e.tag??"og:locale",l=String(t.code??"unknown"),c=t.iso?`, iso: '${t.iso}'`:"";console.warn(`[i18n] Cannot derive ${r} for locale '${l}'${c}. Set locale.og (e.g. 'en_US') or use iso with a 2-letter region (e.g. 'en-US').`)}function O(t){const e=t.locals.i18n;if(!e)throw new Error("i18n instance not found. Make sure i18n middleware is configured.");return e}function F(t){return t.locals.locale||"en"}function k(t){return t.locals.defaultLocale||"en"}function C(t){return t.locals.locales||[]}function x(t){return t.locals.routingStrategy||null}function te(t){const e=O(t),r=F(t),l=k(t),c=C(t),u=c.map(o=>o.code),i=x(t);return{locale:r,defaultLocale:l,locales:c,t:(o,s,a,n)=>e.t(o,s,a,n),ts:(o,s,a,n)=>e.ts(o,s,a,n),tc:(o,s,a)=>e.tc(o,s,a),tn:e.tn.bind(e),td:e.td.bind(e),tdr:e.tdr.bind(e),has:(o,s)=>e.has(o,s),getRoute:()=>e.getRoute(),getRouteName:o=>{const s=o||t.url.pathname;if(i?.getRouteName)return i.getRouteName(s,u);const a=s.replace(/^\//,"").replace(/\/$/,"");if(!a)return"index";const n=a.split("/").filter(Boolean),f=n[0];return f&&u.includes(f)&&n.shift(),n.length===0?"index":n.join("-")},getLocaleFromPath:o=>{const s=o||t.url.pathname;if(i?.getLocaleFromPath)return i.getLocaleFromPath(s,l,u);const n=s.split("/").filter(Boolean)[0];return n&&u.includes(n)?n:l},switchLocalePath:o=>{if(i?.switchLocalePath)return i.switchLocalePath(t.url.pathname,o,u,l);const s=t.url.pathname.split("/").filter(Boolean),a=s[0];return a&&u.includes(a)&&s.shift(),o!==l&&s.unshift(o),`/${s.join("/")}`},localizePath:(o,s)=>{if(i?.localizePath)return i.localizePath(o,s||r,u,l);const n=(o.replace(/^\//,"").replace(/\/$/,"")||"").split("/").filter(Boolean),f=n[0];return f&&u.includes(f)&&n.shift(),s&&s!==l&&n.unshift(s),`/${n.join("/")}`},getI18n:()=>e,getBasePath:o=>{const n=(o||t.url).pathname.split("/").filter(Boolean),f=n[0];return f&&u.includes(f)&&n.shift(),n.length>0?`/${n.join("/")}`:"/"},addTranslations:(o,s,a=!0)=>{e.addTranslations(o,s,a)},addRouteTranslations:(o,s,a,n=!0)=>{e.addRouteTranslations(o,s,a,n)},mergeTranslations:(o,s,a)=>{e.mergeTranslations(o,s,a)},clearCache:()=>{e.clearCache()}}}function ne(t,e={}){const{baseUrl:r="/",addDirAttribute:l=!0,addSeoAttributes:c=!0,hreflangBaseLanguage:u=!1}=e,i=F(t),o=k(t),a=C(t).filter(g=>!g.disabled),n=a.filter(g=>g.seo!==!1),f=a.find(g=>g.code===i);if(!f)return{htmlAttrs:{},link:[],meta:[]};const d=f.iso||i,h=I(f),p=f.dir||"auto",m={htmlAttrs:{lang:d,...l?{dir:p}:{}},link:[],meta:[]};if(!c)return m;const P=`${r}${t.url.pathname}`;m.link.push({rel:"canonical",href:P});const S=x(t),y=a.map(g=>g.code),T=new Map;for(const g of n){let L=t.url.pathname;if(S?.switchLocalePath)L=S.switchLocalePath(t.url.pathname,g.code,y,o);else{const b=t.url.pathname.split("/").filter(Boolean),B=b[0];B&&y.includes(B)&&b.shift(),g.code!==o&&b.unshift(g.code),L=`/${b.join("/")}`}T.set(String(g.code),`${r}${L}`)}for(const{hreflang:g,localeCode:L}of ee(n,{hreflangBaseLanguage:u})){const b=T.get(L);b&&m.link.push({rel:"alternate",href:b,hreflang:g})}if(a.find(g=>g.code===o)?.seo!==!1){let g=t.url.pathname;if(S?.switchLocalePath)g=S.switchLocalePath(t.url.pathname,o,y,o);else{const L=t.url.pathname.split("/").filter(Boolean),b=L[0];b&&y.includes(b)&&L.shift(),g=`/${L.join("/")}`}m.link.push({rel:"alternate",href:`${r}${g}`,hreflang:"x-default"})}h?m.meta.push({property:"og:locale",content:h}):A(f,{tag:"og:locale"}),m.meta.push({property:"og:url",content:P});for(const g of n){if(g.code===i)continue;const L=I(g);if(!L){A(g,{tag:"og:locale:alternate"});continue}m.meta.push({property:"og:locale:alternate",content:L})}return m}function oe(t,e,r){const l=e.split(".");let c=t;for(let i=0;i<l.length-1;i++){const o=l[i];c[o]||(c[o]={}),c=c[o]}const u=l[l.length-1];u!==void 0&&(c[u]=r)}function ae(t,e){const r=O(t),l=F(t),c=k(t),u=r.getRoute(),i={};if(e&&e.length>0){const o={};for(const s of e){const a=r.t(s,void 0,void 0,u);a!=null&&a!==s&&oe(o,s,a)}Object.keys(o).length>0&&(i[u]=o)}else{const o=r.getRouteTranslations(l,u);o&&(i[u]=o)}return{locale:l,fallbackLocale:c,currentRoute:u,translations:i}}Object.defineProperty(exports,"FormatService",{enumerable:!0,get:()=>j.FormatService});Object.defineProperty(exports,"defaultPlural",{enumerable:!0,get:()=>j.defaultPlural});Object.defineProperty(exports,"interpolate",{enumerable:!0,get:()=>j.interpolate});exports.AstroI18n=v;exports.createAstroRouterAdapter=Y;exports.createI18n=Z;exports.createI18nMiddleware=Q;exports.detectLocale=X;exports.getDefaultLocale=k;exports.getGlobalRoutingStrategy=_;exports.getI18n=O;exports.getI18nProps=ae;exports.getLocale=F;exports.getLocales=C;exports.i18nIntegration=J;exports.loadTranslationsFromDir=E;exports.loadTranslationsIntoI18n=K;exports.runWithRoutingStrategy=H;exports.setGlobalRoutingStrategy=U;exports.useI18n=te;exports.useLocaleHead=ne;
17
+ `})}}}}function Q(e){return new v(e)}function z(e,t){if(R.existsSync(e))for(const a of R.readdirSync(e)){const r=$.join(e,a);if(R.statSync(r).isDirectory()){z(r,t);continue}a.endsWith(".json")&&t(r)}}function E(e){const{translationDir:t,rootDir:a=process.cwd(),disablePageLocales:r=!1}=e,c=$.resolve(a,t);if(!R.existsSync(c))return console.warn(`[i18n] Translation directory not found: ${c}`),{root:{},routes:{}};const u={root:{},routes:{}};return z(c,i=>{const o=$.relative(c,i).split($.sep).join("/");try{const s=R.readFileSync(i,"utf-8"),l=JSON.parse(s);M.storeLoadedTranslationFile(u,o,l,r)}catch(s){console.error(`[i18n] Failed to load translation file: ${i}`,s)}}),u}function X(e,t){const{root:a,routes:r}=E(t);for(const[c,u]of Object.entries(a))e.addTranslations(c,u,!1);for(const[c,u]of Object.entries(r))for(const[i,o]of Object.entries(u))e.addRouteTranslations(i,c,M.mergeRouteTranslationsWithRoot(a[i],o),!1)}function Y(e){const{i18n:t,defaultLocale:a,locales:r,localeObjects:c,autoDetect:u=!0,redirectToDefault:i=!1,routingStrategy:o}=e,s=o||C();return async(l,n)=>{if(l.locals.locale&&l.locals.i18n)return n();const f=l.url,d=f.pathname;if(!s){const w=t.clone(a),g=d==="/"||d===""?"index":d.split("/").filter(Boolean).join("-");return w.setRoute(g),l.locals.i18n=w,l.locals.locale=a,l.locals.defaultLocale=a,l.locals.locales=c||r.map(L=>({code:L})),l.locals.currentUrl=f,n()}const h={...s,getCurrentPath:()=>d,getRoute:()=>({fullPath:f.pathname+f.search,query:Object.fromEntries(f.searchParams)})},m=d.split("/").filter(Boolean)[0],b=m!==void 0&&r.includes(m);let P;b&&m?P=m:h.getLocaleFromPath?P=h.getLocaleFromPath(d,a,r):P=a;const y=t.clone(P),T=h.getRouteName?h.getRouteName(d,r):"index";return y.setRoute(T),l.locals.i18n=y,l.locals.locale=P,l.locals.defaultLocale=a,l.locals.locales=c||r.map(w=>({code:w})),l.locals.currentUrl=f,l.locals.routingStrategy=h,H(h,()=>n())}}function ee(e,t,a,r,c,u="i18n-locale",i){const o=i??C();let s=r;if(o?.getLocaleFromPath)s=o.getLocaleFromPath(e,r,c);else{const n=e.split("/").filter(Boolean)[0];n&&c.includes(n)&&(s=n)}if(u!==null&&s===r&&t.get(u)){const l=t.get(u)?.value;l&&c.includes(l)&&(s=l)}if(s===r)try{const l=Z.detectLocaleFromAcceptLanguage(a.get("accept-language")??void 0,c);l&&(s=l)}catch{}return s}function te(e,t,a){const r=e.map(n=>n.code),c=(n,f=[])=>{const d=n.replace(/^\//,"").replace(/\/$/,"");if(!d)return"index";const h=d.split("/").filter(Boolean),p=h[0];return p&&f.includes(p)&&h.shift(),h.length===0?"index":h.join("-")},u=(n,f="en",d=[])=>{const p=n.split("/").filter(Boolean)[0];return p&&d.includes(p)?p:f},i=(n,f,d=[],h)=>{const p=n.split("/").filter(Boolean),m=p[0];return m&&d.includes(m)&&p.shift(),(f!==h||h===void 0)&&p.unshift(f),`/${p.join("/")}`},o=(n,f,d=[],h)=>{const m=(n.replace(/^\//,"").replace(/\/$/,"")||"").split("/").filter(Boolean),b=m[0];return b&&d.includes(b)&&m.shift(),(f!==h||h===void 0)&&m.unshift(f),`/${m.join("/")}`};return{getCurrentPath:()=>a?a().pathname:typeof window<"u"?window.location.pathname:"/",getRouteName:c,getLocaleFromPath:u,switchLocalePath:i,localizePath:o,removeLocaleFromPath:(n,f=[])=>{const d=n.split("/").filter(Boolean),h=d[0];return h&&f.includes(h)&&d.shift(),`/${d.join("/")}`},resolvePath:(n,f)=>{const d=typeof n=="string"?n:n.path||"/";return o(d,f,r,t)},getRoute:()=>{if(a){const n=a();return{fullPath:n.pathname+n.search,query:Object.fromEntries(n.searchParams)}}if(typeof window<"u"){const n=new URL(window.location.href);return{fullPath:n.pathname+n.search,query:Object.fromEntries(n.searchParams)}}return{fullPath:"/",query:{}}},push:n=>{typeof window<"u"&&(window.location.href=n.path)},replace:n=>{typeof window<"u"&&window.location.replace(n.path)}}}function I(e){return e.iso?.trim()||String(e.code)}function N(e){const t=e.match(/^([A-Za-z]{2,3})(?:[-_](.+))?$/);return t?{language:t[1],region:t[2]}:{language:e}}function ne(e,t={}){const{hreflangBaseLanguage:a=!1}=t;if(!a)return e.map(i=>{const o=String(i.code);return{hreflang:I(i),localeCode:o}});const r=new Map;for(const i of e){const o=String(i.code),s=I(i),{language:l,region:n}=N(s);l&&n&&!r.has(l)&&r.set(l,o),r.set(s,o)}const c=new Set,u=[];for(const i of e){const o=String(i.code),s=I(i),{language:l,region:n}=N(s);l&&n&&r.get(l)===o&&!c.has(l)&&(c.add(l),u.push({hreflang:l,localeCode:o})),c.has(s)||(c.add(s),u.push({hreflang:s,localeCode:o}))}return u}function _(e){const t=e.og?.trim();if(t)return t;const a=e.iso?.trim();if(!a)return null;const r=a.indexOf("_");if(r>0){const u=a.slice(0,r),i=a.slice(r+1);if(u.length>=2&&i.length===2)return`${u.toLowerCase()}_${i.toUpperCase()}`}const c=a.indexOf("-");if(c>0){const u=a.slice(0,c),i=a.slice(c+1);if(u.length>=2&&i.length===2&&/^[A-Za-z]{2}$/.test(i))return`${u.toLowerCase()}_${i.toUpperCase()}`}return null}function A(e,t={}){if(_(e)!==null||t.missingWarn===!1||process.env.NODE_ENV==="production")return;const a=t.tag??"og:locale",r=String(e.code??"unknown"),c=e.iso?`, iso: '${e.iso}'`:"";console.warn(`[i18n] Cannot derive ${a} for locale '${r}'${c}. Set locale.og (e.g. 'en_US') or use iso with a 2-letter region (e.g. 'en-US').`)}function O(e){const t=e.locals.i18n;if(!t)throw new Error("i18n instance not found. Make sure i18n middleware is configured.");return t}function F(e){return e.locals.locale||"en"}function k(e){return e.locals.defaultLocale||"en"}function D(e){return e.locals.locales||[]}function x(e){return e.locals.routingStrategy||null}function G(e){const t=O(e),a=F(e),r=k(e),c=D(e),u=c.map(o=>o.code),i=x(e);return{locale:a,defaultLocale:r,locales:c,t:(o,s,l,n)=>t.t(o,s,l,n),ts:(o,s,l,n)=>t.ts(o,s,l,n),tc:(o,s,l)=>t.tc(o,s,l),tn:t.tn.bind(t),td:t.td.bind(t),tdr:t.tdr.bind(t),has:(o,s)=>t.has(o,s),getRoute:()=>t.getRoute(),getRouteName:o=>{const s=o||e.url.pathname;if(i?.getRouteName)return i.getRouteName(s,u);const l=s.replace(/^\//,"").replace(/\/$/,"");if(!l)return"index";const n=l.split("/").filter(Boolean),f=n[0];return f&&u.includes(f)&&n.shift(),n.length===0?"index":n.join("-")},getLocaleFromPath:o=>{const s=o||e.url.pathname;if(i?.getLocaleFromPath)return i.getLocaleFromPath(s,r,u);const n=s.split("/").filter(Boolean)[0];return n&&u.includes(n)?n:r},switchLocalePath:o=>{if(i?.switchLocalePath)return i.switchLocalePath(e.url.pathname,o,u,r);const s=e.url.pathname.split("/").filter(Boolean),l=s[0];return l&&u.includes(l)&&s.shift(),o!==r&&s.unshift(o),`/${s.join("/")}`},localizePath:(o,s)=>{if(i?.localizePath)return i.localizePath(o,s||a,u,r);const n=(o.replace(/^\//,"").replace(/\/$/,"")||"").split("/").filter(Boolean),f=n[0];return f&&u.includes(f)&&n.shift(),s&&s!==r&&n.unshift(s),`/${n.join("/")}`},getI18n:()=>t,getBasePath:o=>{const n=(o||e.url).pathname.split("/").filter(Boolean),f=n[0];return f&&u.includes(f)&&n.shift(),n.length>0?`/${n.join("/")}`:"/"},addTranslations:(o,s,l=!0)=>{t.addTranslations(o,s,l)},addRouteTranslations:(o,s,l,n=!0)=>{t.addRouteTranslations(o,s,l,n)},mergeTranslations:(o,s,l)=>{t.mergeTranslations(o,s,l)},clearCache:()=>{t.clearCache()}}}function V(e){const t=e.locals.currentUrl??e.url;return G(e).getBasePath(t)}function oe(e){const{locale:t}=e.params,a=D(e).map(c=>c.code);if(!t||!a.includes(t))return new Response(null,{status:404});const r=e.locals.i18n;return r&&(r.locale=t,e.locals.locale=t),V(e)}function ae(e,t={}){const{baseUrl:a="/",addDirAttribute:r=!0,addSeoAttributes:c=!0,hreflangBaseLanguage:u=!1}=t,i=F(e),o=k(e),l=D(e).filter(g=>!g.disabled),n=l.filter(g=>g.seo!==!1),f=l.find(g=>g.code===i);if(!f)return{htmlAttrs:{},link:[],meta:[]};const d=f.iso||i,h=_(f),p=f.dir||"auto",m={htmlAttrs:{lang:d,...r?{dir:p}:{}},link:[],meta:[]};if(!c)return m;const b=`${a}${e.url.pathname}`;m.link.push({rel:"canonical",href:b});const P=x(e),y=l.map(g=>g.code),T=new Map;for(const g of n){let L=e.url.pathname;if(P?.switchLocalePath)L=P.switchLocalePath(e.url.pathname,g.code,y,o);else{const S=e.url.pathname.split("/").filter(Boolean),B=S[0];B&&y.includes(B)&&S.shift(),g.code!==o&&S.unshift(g.code),L=`/${S.join("/")}`}T.set(String(g.code),`${a}${L}`)}for(const{hreflang:g,localeCode:L}of ne(n,{hreflangBaseLanguage:u})){const S=T.get(L);S&&m.link.push({rel:"alternate",href:S,hreflang:g})}if(l.find(g=>g.code===o)?.seo!==!1){let g=e.url.pathname;if(P?.switchLocalePath)g=P.switchLocalePath(e.url.pathname,o,y,o);else{const L=e.url.pathname.split("/").filter(Boolean),S=L[0];S&&y.includes(S)&&L.shift(),g=`/${L.join("/")}`}m.link.push({rel:"alternate",href:`${a}${g}`,hreflang:"x-default"})}h?m.meta.push({property:"og:locale",content:h}):A(f,{tag:"og:locale"}),m.meta.push({property:"og:url",content:b});for(const g of n){if(g.code===i)continue;const L=_(g);if(!L){A(g,{tag:"og:locale:alternate"});continue}m.meta.push({property:"og:locale:alternate",content:L})}return m}function re(e,t,a){const r=t.split(".");let c=e;for(let i=0;i<r.length-1;i++){const o=r[i];c[o]||(c[o]={}),c=c[o]}const u=r[r.length-1];u!==void 0&&(c[u]=a)}function le(e,t){const a=O(e),r=F(e),c=k(e),u=a.getRoute(),i={};if(t&&t.length>0){const o={};for(const s of t){const l=a.t(s,void 0,void 0,u);l!=null&&l!==s&&re(o,s,l)}Object.keys(o).length>0&&(i[u]=o)}else{const o=a.getRouteTranslations(r,u);o&&(i[u]=o)}return{locale:r,fallbackLocale:c,currentRoute:u,translations:i}}Object.defineProperty(exports,"FormatService",{enumerable:!0,get:()=>j.FormatService});Object.defineProperty(exports,"defaultPlural",{enumerable:!0,get:()=>j.defaultPlural});Object.defineProperty(exports,"interpolate",{enumerable:!0,get:()=>j.interpolate});exports.AstroI18n=v;exports.createAstroRouterAdapter=te;exports.createI18n=Q;exports.createI18nMiddleware=Y;exports.detectLocale=ee;exports.getDefaultLocale=k;exports.getGlobalRoutingStrategy=C;exports.getI18n=O;exports.getI18nProps=le;exports.getLocale=F;exports.getLocaleRewritePath=V;exports.getLocales=D;exports.i18nIntegration=K;exports.loadTranslationsFromDir=E;exports.loadTranslationsIntoI18n=X;exports.prepareLocaleRewrite=oe;exports.runWithRoutingStrategy=H;exports.setGlobalRoutingStrategy=U;exports.useI18n=G;exports.useLocaleHead=ae;
package/dist/index.d.cts CHANGED
@@ -11,4 +11,4 @@ export { createI18nMiddleware, detectLocale } from './middleware';
11
11
  export { createAstroRouterAdapter } from './router/adapter';
12
12
  export type { I18nRoutingStrategy } from './router/types';
13
13
  export type { I18nClientProps, LocaleHeadOptions, LocaleHeadResult } from './utils';
14
- export { getDefaultLocale, getI18n, getI18nProps, getLocale, getLocales, useI18n, useLocaleHead } from './utils';
14
+ export { getDefaultLocale, getI18n, getI18nProps, getLocale, getLocaleRewritePath, getLocales, prepareLocaleRewrite, useI18n, useLocaleHead, } from './utils';
package/dist/index.d.ts CHANGED
@@ -11,4 +11,4 @@ export { createI18nMiddleware, detectLocale } from './middleware';
11
11
  export { createAstroRouterAdapter } from './router/adapter';
12
12
  export type { I18nRoutingStrategy } from './router/types';
13
13
  export type { I18nClientProps, LocaleHeadOptions, LocaleHeadResult } from './utils';
14
- export { getDefaultLocale, getI18n, getI18nProps, getLocale, getLocales, useI18n, useLocaleHead } from './utils';
14
+ export { getDefaultLocale, getI18n, getI18nProps, getLocale, getLocaleRewritePath, getLocales, prepareLocaleRewrite, useI18n, useLocaleHead, } from './utils';
package/dist/index.mjs CHANGED
@@ -1,61 +1,61 @@
1
1
  import { BaseI18n as U } from "@i18n-micro/core";
2
- import { FormatService as be, defaultPlural as ye, interpolate as we } from "@i18n-micro/core";
2
+ import { FormatService as we, defaultPlural as Re, interpolate as Te } from "@i18n-micro/core";
3
3
  import { AsyncLocalStorage as q } from "node:async_hooks";
4
- import { existsSync as _, readdirSync as z, statSync as E, readFileSync as H } from "node:fs";
4
+ import { existsSync as B, readdirSync as z, statSync as E, readFileSync as H } from "node:fs";
5
5
  import { resolve as x, join as V, relative as G, sep as J } from "node:path";
6
6
  import { mergeRouteTranslationsWithRoot as Z, storeLoadedTranslationFile as K } from "@i18n-micro/utils/parse-path";
7
7
  import { detectLocaleFromAcceptLanguage as Q } from "@i18n-micro/utils/accept-language";
8
8
  class v extends U {
9
- constructor(e) {
10
- const r = e._storage || {
9
+ constructor(t) {
10
+ const a = t._storage || {
11
11
  translations: /* @__PURE__ */ new Map()
12
12
  };
13
13
  if (super({
14
- storage: r,
15
- plural: e.plural,
16
- missingWarn: e.missingWarn,
17
- missingHandler: e.missingHandler,
18
- numberFormats: e.numberFormats,
19
- datetimeFormats: e.datetimeFormats
20
- }), this.initialMessages = {}, this.storage = r, this._locale = e.locale, this._fallbackLocale = e.fallbackLocale || e.locale, this._currentRoute = "index", e.messages) {
21
- this.initialMessages = { ...e.messages };
22
- for (const [l, c] of Object.entries(e.messages))
23
- this.helper.loadTranslations(l, c);
14
+ storage: a,
15
+ plural: t.plural,
16
+ missingWarn: t.missingWarn,
17
+ missingHandler: t.missingHandler,
18
+ numberFormats: t.numberFormats,
19
+ datetimeFormats: t.datetimeFormats
20
+ }), this.initialMessages = {}, this.storage = a, this._locale = t.locale, this._fallbackLocale = t.fallbackLocale || t.locale, this._currentRoute = "index", t.messages) {
21
+ this.initialMessages = { ...t.messages };
22
+ for (const [l, i] of Object.entries(t.messages))
23
+ this.helper.loadTranslations(l, i);
24
24
  }
25
25
  }
26
- cloneStorage(e) {
27
- const r = /* @__PURE__ */ new Map();
28
- for (const [l, c] of e.translations)
29
- r.set(l, { ...c });
30
- return { translations: r };
26
+ cloneStorage(t) {
27
+ const a = /* @__PURE__ */ new Map();
28
+ for (const [l, i] of t.translations)
29
+ a.set(l, { ...i });
30
+ return { translations: a };
31
31
  }
32
- clone(e) {
33
- const r = this.cloneStorage(this.storage);
32
+ clone(t) {
33
+ const a = this.cloneStorage(this.storage);
34
34
  return new v({
35
- locale: e || this._locale,
35
+ locale: t || this._locale,
36
36
  fallbackLocale: this._fallbackLocale,
37
37
  plural: this.pluralFunc,
38
38
  missingWarn: this.missingWarn,
39
39
  missingHandler: this.missingHandler,
40
40
  numberFormats: this.formatter.getNumberFormats(),
41
41
  datetimeFormats: this.formatter.getDateTimeFormats(),
42
- _storage: r
42
+ _storage: a
43
43
  });
44
44
  }
45
45
  get locale() {
46
46
  return this._locale;
47
47
  }
48
- set locale(e) {
49
- this._locale = e;
48
+ set locale(t) {
49
+ this._locale = t;
50
50
  }
51
51
  get fallbackLocale() {
52
52
  return this._fallbackLocale;
53
53
  }
54
- set fallbackLocale(e) {
55
- this._fallbackLocale = e;
54
+ set fallbackLocale(t) {
55
+ this._fallbackLocale = t;
56
56
  }
57
- setRoute(e) {
58
- this._currentRoute = e;
57
+ setRoute(t) {
58
+ this._currentRoute = t;
59
59
  }
60
60
  getLocale() {
61
61
  return this._locale;
@@ -66,57 +66,57 @@ class v extends U {
66
66
  getRoute() {
67
67
  return this._currentRoute;
68
68
  }
69
- getRouteTranslations(e, r) {
70
- const l = `${e}:${r}`;
69
+ getRouteTranslations(t, a) {
70
+ const l = `${t}:${a}`;
71
71
  return this.storage.translations.get(l) ?? null;
72
72
  }
73
- addTranslations(e, r, l = !0) {
74
- super.loadTranslationsCore(e, r, l);
73
+ addTranslations(t, a, l = !0) {
74
+ super.loadTranslationsCore(t, a, l);
75
75
  }
76
- addRouteTranslations(e, r, l, c = !0) {
77
- super.loadRouteTranslationsCore(e, r, l, c);
76
+ addRouteTranslations(t, a, l, i = !0) {
77
+ super.loadRouteTranslationsCore(t, a, l, i);
78
78
  }
79
- mergeTranslations(e, r, l) {
80
- this.helper.mergeTranslation(e, r, l, !0);
79
+ mergeTranslations(t, a, l) {
80
+ this.helper.mergeTranslation(t, a, l, !0);
81
81
  }
82
82
  clearCache() {
83
- const e = { ...this.initialMessages };
84
- if (super.clearCache(), Object.keys(e).length > 0)
85
- for (const [r, l] of Object.entries(e))
86
- this.helper.loadTranslations(r, l);
83
+ const t = { ...this.initialMessages };
84
+ if (super.clearCache(), Object.keys(t).length > 0)
85
+ for (const [a, l] of Object.entries(t))
86
+ this.helper.loadTranslations(a, l);
87
87
  }
88
88
  }
89
- let B = null;
90
- const O = new q();
91
- function I() {
92
- const t = O.getStore();
93
- return t !== void 0 ? t : B;
89
+ let O = null;
90
+ const I = new q();
91
+ function N() {
92
+ const e = I.getStore();
93
+ return e !== void 0 ? e : O;
94
94
  }
95
- function X(t) {
96
- B = t;
95
+ function X(e) {
96
+ O = e;
97
97
  }
98
- function Y(t, e) {
99
- return O.run(t, e);
98
+ function Y(e, t) {
99
+ return I.run(e, t);
100
100
  }
101
- function ce(t) {
102
- const { locale: e, fallbackLocale: r, translationDir: l, routingStrategy: c } = t;
103
- return X(c || null), {
101
+ function fe(e) {
102
+ const { locale: t, fallbackLocale: a, translationDir: l, routingStrategy: i } = e;
103
+ return X(i || null), {
104
104
  name: "@i18n-micro/astro",
105
105
  hooks: {
106
106
  // 1. Vite setup (virtual module) happens here
107
107
  "astro:config:setup": (u) => {
108
- const { updateConfig: i } = u, o = "virtual:i18n-micro/config", s = `\0${o}`, a = {
109
- defaultLocale: e,
110
- fallbackLocale: r || e,
111
- locales: t.locales || [],
112
- localeCodes: (t.locales || []).map((n) => n.code),
108
+ const { updateConfig: c } = u, o = "virtual:i18n-micro/config", s = `\0${o}`, r = {
109
+ defaultLocale: t,
110
+ fallbackLocale: a || t,
111
+ locales: e.locales || [],
112
+ localeCodes: (e.locales || []).map((n) => n.code),
113
113
  translationDir: l || null,
114
- autoDetect: t.autoDetect ?? !0,
115
- redirectToDefault: t.redirectToDefault ?? !1,
116
- localeCookie: t.localeCookie === null ? null : t.localeCookie || "i18n-locale",
117
- missingWarn: t.missingWarn ?? !1
114
+ autoDetect: e.autoDetect ?? !0,
115
+ redirectToDefault: e.redirectToDefault ?? !1,
116
+ localeCookie: e.localeCookie === null ? null : e.localeCookie || "i18n-locale",
117
+ missingWarn: e.missingWarn ?? !1
118
118
  };
119
- i({
119
+ c({
120
120
  vite: {
121
121
  plugins: [
122
122
  {
@@ -127,7 +127,7 @@ function ce(t) {
127
127
  },
128
128
  load(n) {
129
129
  if (n === s)
130
- return `export const config = ${JSON.stringify(a)}`;
130
+ return `export const config = ${JSON.stringify(r)}`;
131
131
  }
132
132
  }
133
133
  ]
@@ -136,8 +136,8 @@ function ce(t) {
136
136
  },
137
137
  // 2. Type injection happens here (per Astro documentation)
138
138
  "astro:config:done": (u) => {
139
- const { injectTypes: i } = u;
140
- i({
139
+ const { injectTypes: c } = u;
140
+ c({
141
141
  filename: "i18n-micro-env.d.ts",
142
142
  content: `
143
143
  /// <reference types="@i18n-micro/astro/env" />
@@ -161,61 +161,61 @@ function ce(t) {
161
161
  }
162
162
  };
163
163
  }
164
- function ue(t) {
165
- return new v(t);
164
+ function ge(e) {
165
+ return new v(e);
166
166
  }
167
- function N(t, e) {
168
- if (_(t))
169
- for (const r of z(t)) {
170
- const l = V(t, r);
167
+ function M(e, t) {
168
+ if (B(e))
169
+ for (const a of z(e)) {
170
+ const l = V(e, a);
171
171
  if (E(l).isDirectory()) {
172
- N(l, e);
172
+ M(l, t);
173
173
  continue;
174
174
  }
175
- r.endsWith(".json") && e(l);
175
+ a.endsWith(".json") && t(l);
176
176
  }
177
177
  }
178
- function ee(t) {
179
- const { translationDir: e, rootDir: r = process.cwd(), disablePageLocales: l = !1 } = t, c = x(r, e);
180
- if (!_(c))
181
- return console.warn(`[i18n] Translation directory not found: ${c}`), { root: {}, routes: {} };
178
+ function ee(e) {
179
+ const { translationDir: t, rootDir: a = process.cwd(), disablePageLocales: l = !1 } = e, i = x(a, t);
180
+ if (!B(i))
181
+ return console.warn(`[i18n] Translation directory not found: ${i}`), { root: {}, routes: {} };
182
182
  const u = { root: {}, routes: {} };
183
- return N(c, (i) => {
184
- const o = G(c, i).split(J).join("/");
183
+ return M(i, (c) => {
184
+ const o = G(i, c).split(J).join("/");
185
185
  try {
186
- const s = H(i, "utf-8"), a = JSON.parse(s);
187
- K(u, o, a, l);
186
+ const s = H(c, "utf-8"), r = JSON.parse(s);
187
+ K(u, o, r, l);
188
188
  } catch (s) {
189
- console.error(`[i18n] Failed to load translation file: ${i}`, s);
189
+ console.error(`[i18n] Failed to load translation file: ${c}`, s);
190
190
  }
191
191
  }), u;
192
192
  }
193
- function fe(t, e) {
194
- const { root: r, routes: l } = ee(e);
195
- for (const [c, u] of Object.entries(r))
196
- t.addTranslations(c, u, !1);
197
- for (const [c, u] of Object.entries(l))
198
- for (const [i, o] of Object.entries(u))
199
- t.addRouteTranslations(i, c, Z(r[i], o), !1);
193
+ function he(e, t) {
194
+ const { root: a, routes: l } = ee(t);
195
+ for (const [i, u] of Object.entries(a))
196
+ e.addTranslations(i, u, !1);
197
+ for (const [i, u] of Object.entries(l))
198
+ for (const [c, o] of Object.entries(u))
199
+ e.addRouteTranslations(c, i, Z(a[c], o), !1);
200
200
  }
201
- function ge(t) {
201
+ function de(e) {
202
202
  const {
203
- i18n: e,
203
+ i18n: t,
204
204
  // This is the global singleton with cache
205
- defaultLocale: r,
205
+ defaultLocale: a,
206
206
  locales: l,
207
- localeObjects: c,
207
+ localeObjects: i,
208
208
  autoDetect: u = !0,
209
- redirectToDefault: i = !1,
209
+ redirectToDefault: c = !1,
210
210
  routingStrategy: o
211
- } = t, s = o || I();
212
- return async (a, n) => {
213
- if (a.locals.locale && a.locals.i18n)
211
+ } = e, s = o || N();
212
+ return async (r, n) => {
213
+ if (r.locals.locale && r.locals.i18n)
214
214
  return n();
215
- const f = a.url, h = f.pathname;
215
+ const f = r.url, h = f.pathname;
216
216
  if (!s) {
217
- const w = e.clone(r), g = h === "/" || h === "" ? "index" : h.split("/").filter(Boolean).join("-");
218
- return w.setRoute(g), a.locals.i18n = w, a.locals.locale = r, a.locals.defaultLocale = r, a.locals.locales = c || l.map((L) => ({ code: L })), a.locals.currentUrl = f, n();
217
+ const w = t.clone(a), g = h === "/" || h === "" ? "index" : h.split("/").filter(Boolean).join("-");
218
+ return w.setRoute(g), r.locals.i18n = w, r.locals.locale = a, r.locals.defaultLocale = a, r.locals.locales = i || l.map((L) => ({ code: L })), r.locals.currentUrl = f, n();
219
219
  }
220
220
  const d = {
221
221
  ...s,
@@ -226,34 +226,34 @@ function ge(t) {
226
226
  })
227
227
  }, m = h.split("/").filter(Boolean)[0], b = m !== void 0 && l.includes(m);
228
228
  let S;
229
- b && m ? S = m : d.getLocaleFromPath ? S = d.getLocaleFromPath(h, r, l) : S = r;
230
- const y = e.clone(S), R = d.getRouteName ? d.getRouteName(h, l) : "index";
231
- return y.setRoute(R), a.locals.i18n = y, a.locals.locale = S, a.locals.defaultLocale = r, a.locals.locales = c || l.map((w) => ({ code: w })), a.locals.currentUrl = f, a.locals.routingStrategy = d, Y(d, () => n());
229
+ b && m ? S = m : d.getLocaleFromPath ? S = d.getLocaleFromPath(h, a, l) : S = a;
230
+ const y = t.clone(S), R = d.getRouteName ? d.getRouteName(h, l) : "index";
231
+ return y.setRoute(R), r.locals.i18n = y, r.locals.locale = S, r.locals.defaultLocale = a, r.locals.locales = i || l.map((w) => ({ code: w })), r.locals.currentUrl = f, r.locals.routingStrategy = d, Y(d, () => n());
232
232
  };
233
233
  }
234
- function he(t, e, r, l, c, u = "i18n-locale", i) {
235
- const o = i ?? I();
234
+ function me(e, t, a, l, i, u = "i18n-locale", c) {
235
+ const o = c ?? N();
236
236
  let s = l;
237
237
  if (o?.getLocaleFromPath)
238
- s = o.getLocaleFromPath(t, l, c);
238
+ s = o.getLocaleFromPath(e, l, i);
239
239
  else {
240
- const n = t.split("/").filter(Boolean)[0];
241
- n && c.includes(n) && (s = n);
240
+ const n = e.split("/").filter(Boolean)[0];
241
+ n && i.includes(n) && (s = n);
242
242
  }
243
- if (u !== null && s === l && e.get(u)) {
244
- const a = e.get(u)?.value;
245
- a && c.includes(a) && (s = a);
243
+ if (u !== null && s === l && t.get(u)) {
244
+ const r = t.get(u)?.value;
245
+ r && i.includes(r) && (s = r);
246
246
  }
247
247
  if (s === l)
248
248
  try {
249
- const a = Q(r.get("accept-language") ?? void 0, c);
250
- a && (s = a);
249
+ const r = Q(a.get("accept-language") ?? void 0, i);
250
+ r && (s = r);
251
251
  } catch {
252
252
  }
253
253
  return s;
254
254
  }
255
- function de(t, e, r) {
256
- const l = t.map((n) => n.code), c = (n, f = []) => {
255
+ function pe(e, t, a) {
256
+ const l = e.map((n) => n.code), i = (n, f = []) => {
257
257
  const h = n.replace(/^\//, "").replace(/\/$/, "");
258
258
  if (!h)
259
259
  return "index";
@@ -262,7 +262,7 @@ function de(t, e, r) {
262
262
  }, u = (n, f = "en", h = []) => {
263
263
  const p = n.split("/").filter(Boolean)[0];
264
264
  return p && h.includes(p) ? p : f;
265
- }, i = (n, f, h = [], d) => {
265
+ }, c = (n, f, h = [], d) => {
266
266
  const p = n.split("/").filter(Boolean), m = p[0];
267
267
  return m && h.includes(m) && p.shift(), (f !== d || d === void 0) && p.unshift(f), `/${p.join("/")}`;
268
268
  }, o = (n, f, h = [], d) => {
@@ -270,10 +270,10 @@ function de(t, e, r) {
270
270
  return b && h.includes(b) && m.shift(), (f !== d || d === void 0) && m.unshift(f), `/${m.join("/")}`;
271
271
  };
272
272
  return {
273
- getCurrentPath: () => r ? r().pathname : typeof window < "u" ? window.location.pathname : "/",
274
- getRouteName: c,
273
+ getCurrentPath: () => a ? a().pathname : typeof window < "u" ? window.location.pathname : "/",
274
+ getRouteName: i,
275
275
  getLocaleFromPath: u,
276
- switchLocalePath: i,
276
+ switchLocalePath: c,
277
277
  localizePath: o,
278
278
  removeLocaleFromPath: (n, f = []) => {
279
279
  const h = n.split("/").filter(Boolean), d = h[0];
@@ -281,11 +281,11 @@ function de(t, e, r) {
281
281
  },
282
282
  resolvePath: (n, f) => {
283
283
  const h = typeof n == "string" ? n : n.path || "/";
284
- return o(h, f, l, e);
284
+ return o(h, f, l, t);
285
285
  },
286
286
  getRoute: () => {
287
- if (r) {
288
- const n = r();
287
+ if (a) {
288
+ const n = a();
289
289
  return {
290
290
  fullPath: n.pathname + n.search,
291
291
  query: Object.fromEntries(n.searchParams)
@@ -312,149 +312,160 @@ function de(t, e, r) {
312
312
  }
313
313
  };
314
314
  }
315
- function T(t) {
316
- return t.iso?.trim() || String(t.code);
315
+ function T(e) {
316
+ return e.iso?.trim() || String(e.code);
317
317
  }
318
- function D(t) {
319
- const e = t.match(/^([A-Za-z]{2,3})(?:[-_](.+))?$/);
320
- return e ? { language: e[1], region: e[2] } : { language: t };
318
+ function C(e) {
319
+ const t = e.match(/^([A-Za-z]{2,3})(?:[-_](.+))?$/);
320
+ return t ? { language: t[1], region: t[2] } : { language: e };
321
321
  }
322
- function te(t, e = {}) {
323
- const { hreflangBaseLanguage: r = !1 } = e;
324
- if (!r)
325
- return t.map((i) => {
326
- const o = String(i.code);
327
- return { hreflang: T(i), localeCode: o };
322
+ function te(e, t = {}) {
323
+ const { hreflangBaseLanguage: a = !1 } = t;
324
+ if (!a)
325
+ return e.map((c) => {
326
+ const o = String(c.code);
327
+ return { hreflang: T(c), localeCode: o };
328
328
  });
329
329
  const l = /* @__PURE__ */ new Map();
330
- for (const i of t) {
331
- const o = String(i.code), s = T(i), { language: a, region: n } = D(s);
332
- a && n && !l.has(a) && l.set(a, o), l.set(s, o);
330
+ for (const c of e) {
331
+ const o = String(c.code), s = T(c), { language: r, region: n } = C(s);
332
+ r && n && !l.has(r) && l.set(r, o), l.set(s, o);
333
333
  }
334
- const c = /* @__PURE__ */ new Set(), u = [];
335
- for (const i of t) {
336
- const o = String(i.code), s = T(i), { language: a, region: n } = D(s);
337
- a && n && l.get(a) === o && !c.has(a) && (c.add(a), u.push({ hreflang: a, localeCode: o })), c.has(s) || (c.add(s), u.push({ hreflang: s, localeCode: o }));
334
+ const i = /* @__PURE__ */ new Set(), u = [];
335
+ for (const c of e) {
336
+ const o = String(c.code), s = T(c), { language: r, region: n } = C(s);
337
+ r && n && l.get(r) === o && !i.has(r) && (i.add(r), u.push({ hreflang: r, localeCode: o })), i.has(s) || (i.add(s), u.push({ hreflang: s, localeCode: o }));
338
338
  }
339
339
  return u;
340
340
  }
341
- function $(t) {
342
- const e = t.og?.trim();
343
- if (e) return e;
344
- const r = t.iso?.trim();
345
- if (!r) return null;
346
- const l = r.indexOf("_");
341
+ function $(e) {
342
+ const t = e.og?.trim();
343
+ if (t) return t;
344
+ const a = e.iso?.trim();
345
+ if (!a) return null;
346
+ const l = a.indexOf("_");
347
347
  if (l > 0) {
348
- const u = r.slice(0, l), i = r.slice(l + 1);
349
- if (u.length >= 2 && i.length === 2)
350
- return `${u.toLowerCase()}_${i.toUpperCase()}`;
348
+ const u = a.slice(0, l), c = a.slice(l + 1);
349
+ if (u.length >= 2 && c.length === 2)
350
+ return `${u.toLowerCase()}_${c.toUpperCase()}`;
351
351
  }
352
- const c = r.indexOf("-");
353
- if (c > 0) {
354
- const u = r.slice(0, c), i = r.slice(c + 1);
355
- if (u.length >= 2 && i.length === 2 && /^[A-Za-z]{2}$/.test(i))
356
- return `${u.toLowerCase()}_${i.toUpperCase()}`;
352
+ const i = a.indexOf("-");
353
+ if (i > 0) {
354
+ const u = a.slice(0, i), c = a.slice(i + 1);
355
+ if (u.length >= 2 && c.length === 2 && /^[A-Za-z]{2}$/.test(c))
356
+ return `${u.toLowerCase()}_${c.toUpperCase()}`;
357
357
  }
358
358
  return null;
359
359
  }
360
- function C(t, e = {}) {
361
- if ($(t) !== null || e.missingWarn === !1 || process.env.NODE_ENV === "production") return;
362
- const r = e.tag ?? "og:locale", l = String(t.code ?? "unknown"), c = t.iso ? `, iso: '${t.iso}'` : "";
360
+ function _(e, t = {}) {
361
+ if ($(e) !== null || t.missingWarn === !1 || process.env.NODE_ENV === "production") return;
362
+ const a = t.tag ?? "og:locale", l = String(e.code ?? "unknown"), i = e.iso ? `, iso: '${e.iso}'` : "";
363
363
  console.warn(
364
- `[i18n] Cannot derive ${r} for locale '${l}'${c}. Set locale.og (e.g. 'en_US') or use iso with a 2-letter region (e.g. 'en-US').`
364
+ `[i18n] Cannot derive ${a} for locale '${l}'${i}. Set locale.og (e.g. 'en_US') or use iso with a 2-letter region (e.g. 'en-US').`
365
365
  );
366
366
  }
367
- function M(t) {
368
- const e = t.locals.i18n;
369
- if (!e)
367
+ function A(e) {
368
+ const t = e.locals.i18n;
369
+ if (!t)
370
370
  throw new Error("i18n instance not found. Make sure i18n middleware is configured.");
371
- return e;
371
+ return t;
372
372
  }
373
- function j(t) {
374
- return t.locals.locale || "en";
373
+ function j(e) {
374
+ return e.locals.locale || "en";
375
375
  }
376
- function k(t) {
377
- return t.locals.defaultLocale || "en";
376
+ function k(e) {
377
+ return e.locals.defaultLocale || "en";
378
378
  }
379
- function A(t) {
380
- return t.locals.locales || [];
379
+ function F(e) {
380
+ return e.locals.locales || [];
381
381
  }
382
- function W(t) {
383
- return t.locals.routingStrategy || null;
382
+ function W(e) {
383
+ return e.locals.routingStrategy || null;
384
384
  }
385
- function me(t) {
386
- const e = M(t), r = j(t), l = k(t), c = A(t), u = c.map((o) => o.code), i = W(t);
385
+ function ne(e) {
386
+ const t = A(e), a = j(e), l = k(e), i = F(e), u = i.map((o) => o.code), c = W(e);
387
387
  return {
388
388
  // Current locale
389
- locale: r,
389
+ locale: a,
390
390
  defaultLocale: l,
391
- locales: c,
391
+ locales: i,
392
392
  // Translation methods
393
- t: (o, s, a, n) => e.t(o, s, a, n),
394
- ts: (o, s, a, n) => e.ts(o, s, a, n),
395
- tc: (o, s, a) => e.tc(o, s, a),
396
- tn: e.tn.bind(e),
397
- td: e.td.bind(e),
398
- tdr: e.tdr.bind(e),
399
- has: (o, s) => e.has(o, s),
393
+ t: (o, s, r, n) => t.t(o, s, r, n),
394
+ ts: (o, s, r, n) => t.ts(o, s, r, n),
395
+ tc: (o, s, r) => t.tc(o, s, r),
396
+ tn: t.tn.bind(t),
397
+ td: t.td.bind(t),
398
+ tdr: t.tdr.bind(t),
399
+ has: (o, s) => t.has(o, s),
400
400
  // Route management
401
- getRoute: () => e.getRoute(),
401
+ getRoute: () => t.getRoute(),
402
402
  getRouteName: (o) => {
403
- const s = o || t.url.pathname;
404
- if (i?.getRouteName)
405
- return i.getRouteName(s, u);
406
- const a = s.replace(/^\//, "").replace(/\/$/, "");
407
- if (!a) return "index";
408
- const n = a.split("/").filter(Boolean), f = n[0];
403
+ const s = o || e.url.pathname;
404
+ if (c?.getRouteName)
405
+ return c.getRouteName(s, u);
406
+ const r = s.replace(/^\//, "").replace(/\/$/, "");
407
+ if (!r) return "index";
408
+ const n = r.split("/").filter(Boolean), f = n[0];
409
409
  return f && u.includes(f) && n.shift(), n.length === 0 ? "index" : n.join("-");
410
410
  },
411
411
  getLocaleFromPath: (o) => {
412
- const s = o || t.url.pathname;
413
- if (i?.getLocaleFromPath)
414
- return i.getLocaleFromPath(s, l, u);
412
+ const s = o || e.url.pathname;
413
+ if (c?.getLocaleFromPath)
414
+ return c.getLocaleFromPath(s, l, u);
415
415
  const n = s.split("/").filter(Boolean)[0];
416
416
  return n && u.includes(n) ? n : l;
417
417
  },
418
418
  // Path utilities
419
419
  switchLocalePath: (o) => {
420
- if (i?.switchLocalePath)
421
- return i.switchLocalePath(t.url.pathname, o, u, l);
422
- const s = t.url.pathname.split("/").filter(Boolean), a = s[0];
423
- return a && u.includes(a) && s.shift(), o !== l && s.unshift(o), `/${s.join("/")}`;
420
+ if (c?.switchLocalePath)
421
+ return c.switchLocalePath(e.url.pathname, o, u, l);
422
+ const s = e.url.pathname.split("/").filter(Boolean), r = s[0];
423
+ return r && u.includes(r) && s.shift(), o !== l && s.unshift(o), `/${s.join("/")}`;
424
424
  },
425
425
  localizePath: (o, s) => {
426
- if (i?.localizePath)
427
- return i.localizePath(o, s || r, u, l);
426
+ if (c?.localizePath)
427
+ return c.localizePath(o, s || a, u, l);
428
428
  const n = (o.replace(/^\//, "").replace(/\/$/, "") || "").split("/").filter(Boolean), f = n[0];
429
429
  return f && u.includes(f) && n.shift(), s && s !== l && n.unshift(s), `/${n.join("/")}`;
430
430
  },
431
431
  // Get i18n instance
432
- getI18n: () => e,
432
+ getI18n: () => t,
433
433
  // Get base path without locale (for rewrite)
434
434
  getBasePath: (o) => {
435
- const n = (o || t.url).pathname.split("/").filter(Boolean), f = n[0];
435
+ const n = (o || e.url).pathname.split("/").filter(Boolean), f = n[0];
436
436
  return f && u.includes(f) && n.shift(), n.length > 0 ? `/${n.join("/")}` : "/";
437
437
  },
438
438
  // Translation management
439
- addTranslations: (o, s, a = !0) => {
440
- e.addTranslations(o, s, a);
439
+ addTranslations: (o, s, r = !0) => {
440
+ t.addTranslations(o, s, r);
441
441
  },
442
- addRouteTranslations: (o, s, a, n = !0) => {
443
- e.addRouteTranslations(o, s, a, n);
442
+ addRouteTranslations: (o, s, r, n = !0) => {
443
+ t.addRouteTranslations(o, s, r, n);
444
444
  },
445
- mergeTranslations: (o, s, a) => {
446
- e.mergeTranslations(o, s, a);
445
+ mergeTranslations: (o, s, r) => {
446
+ t.mergeTranslations(o, s, r);
447
447
  },
448
448
  clearCache: () => {
449
- e.clearCache();
449
+ t.clearCache();
450
450
  }
451
451
  };
452
452
  }
453
- function pe(t, e = {}) {
454
- const { baseUrl: r = "/", addDirAttribute: l = !0, addSeoAttributes: c = !0, hreflangBaseLanguage: u = !1 } = e, i = j(t), o = k(t), a = A(t).filter((g) => !g.disabled), n = a.filter((g) => g.seo !== !1), f = a.find((g) => g.code === i);
453
+ function oe(e) {
454
+ const t = e.locals.currentUrl ?? e.url;
455
+ return ne(e).getBasePath(t);
456
+ }
457
+ function Le(e) {
458
+ const { locale: t } = e.params, a = F(e).map((i) => i.code);
459
+ if (!t || !a.includes(t))
460
+ return new Response(null, { status: 404 });
461
+ const l = e.locals.i18n;
462
+ return l && (l.locale = t, e.locals.locale = t), oe(e);
463
+ }
464
+ function Se(e, t = {}) {
465
+ const { baseUrl: a = "/", addDirAttribute: l = !0, addSeoAttributes: i = !0, hreflangBaseLanguage: u = !1 } = t, c = j(e), o = k(e), r = F(e).filter((g) => !g.disabled), n = r.filter((g) => g.seo !== !1), f = r.find((g) => g.code === c);
455
466
  if (!f)
456
467
  return { htmlAttrs: {}, link: [], meta: [] };
457
- const h = f.iso || i, d = $(f), p = f.dir || "auto", m = {
468
+ const h = f.iso || c, d = $(f), p = f.dir || "auto", m = {
458
469
  htmlAttrs: {
459
470
  lang: h,
460
471
  ...l ? { dir: p } : {}
@@ -462,23 +473,23 @@ function pe(t, e = {}) {
462
473
  link: [],
463
474
  meta: []
464
475
  };
465
- if (!c)
476
+ if (!i)
466
477
  return m;
467
- const b = `${r}${t.url.pathname}`;
478
+ const b = `${a}${e.url.pathname}`;
468
479
  m.link.push({
469
480
  rel: "canonical",
470
481
  href: b
471
482
  });
472
- const S = W(t), y = a.map((g) => g.code), R = /* @__PURE__ */ new Map();
483
+ const S = W(e), y = r.map((g) => g.code), R = /* @__PURE__ */ new Map();
473
484
  for (const g of n) {
474
- let L = t.url.pathname;
485
+ let L = e.url.pathname;
475
486
  if (S?.switchLocalePath)
476
- L = S.switchLocalePath(t.url.pathname, g.code, y, o);
487
+ L = S.switchLocalePath(e.url.pathname, g.code, y, o);
477
488
  else {
478
- const P = t.url.pathname.split("/").filter(Boolean), F = P[0];
479
- F && y.includes(F) && P.shift(), g.code !== o && P.unshift(g.code), L = `/${P.join("/")}`;
489
+ const P = e.url.pathname.split("/").filter(Boolean), D = P[0];
490
+ D && y.includes(D) && P.shift(), g.code !== o && P.unshift(g.code), L = `/${P.join("/")}`;
480
491
  }
481
- R.set(String(g.code), `${r}${L}`);
492
+ R.set(String(g.code), `${a}${L}`);
482
493
  }
483
494
  for (const { hreflang: g, localeCode: L } of te(n, { hreflangBaseLanguage: u })) {
484
495
  const P = R.get(L);
@@ -488,32 +499,32 @@ function pe(t, e = {}) {
488
499
  hreflang: g
489
500
  });
490
501
  }
491
- if (a.find((g) => g.code === o)?.seo !== !1) {
492
- let g = t.url.pathname;
502
+ if (r.find((g) => g.code === o)?.seo !== !1) {
503
+ let g = e.url.pathname;
493
504
  if (S?.switchLocalePath)
494
- g = S.switchLocalePath(t.url.pathname, o, y, o);
505
+ g = S.switchLocalePath(e.url.pathname, o, y, o);
495
506
  else {
496
- const L = t.url.pathname.split("/").filter(Boolean), P = L[0];
507
+ const L = e.url.pathname.split("/").filter(Boolean), P = L[0];
497
508
  P && y.includes(P) && L.shift(), g = `/${L.join("/")}`;
498
509
  }
499
510
  m.link.push({
500
511
  rel: "alternate",
501
- href: `${r}${g}`,
512
+ href: `${a}${g}`,
502
513
  hreflang: "x-default"
503
514
  });
504
515
  }
505
516
  d ? m.meta.push({
506
517
  property: "og:locale",
507
518
  content: d
508
- }) : C(f, { tag: "og:locale" }), m.meta.push({
519
+ }) : _(f, { tag: "og:locale" }), m.meta.push({
509
520
  property: "og:url",
510
521
  content: b
511
522
  });
512
523
  for (const g of n) {
513
- if (g.code === i) continue;
524
+ if (g.code === c) continue;
514
525
  const L = $(g);
515
526
  if (!L) {
516
- C(g, { tag: "og:locale:alternate" });
527
+ _(g, { tag: "og:locale:alternate" });
517
528
  continue;
518
529
  }
519
530
  m.meta.push({
@@ -523,56 +534,58 @@ function pe(t, e = {}) {
523
534
  }
524
535
  return m;
525
536
  }
526
- function ne(t, e, r) {
527
- const l = e.split(".");
528
- let c = t;
529
- for (let i = 0; i < l.length - 1; i++) {
530
- const o = l[i];
531
- c[o] || (c[o] = {}), c = c[o];
537
+ function ae(e, t, a) {
538
+ const l = t.split(".");
539
+ let i = e;
540
+ for (let c = 0; c < l.length - 1; c++) {
541
+ const o = l[c];
542
+ i[o] || (i[o] = {}), i = i[o];
532
543
  }
533
544
  const u = l[l.length - 1];
534
- u !== void 0 && (c[u] = r);
545
+ u !== void 0 && (i[u] = a);
535
546
  }
536
- function Le(t, e) {
537
- const r = M(t), l = j(t), c = k(t), u = r.getRoute(), i = {};
538
- if (e && e.length > 0) {
547
+ function Pe(e, t) {
548
+ const a = A(e), l = j(e), i = k(e), u = a.getRoute(), c = {};
549
+ if (t && t.length > 0) {
539
550
  const o = {};
540
- for (const s of e) {
541
- const a = r.t(s, void 0, void 0, u);
542
- a != null && a !== s && ne(o, s, a);
551
+ for (const s of t) {
552
+ const r = a.t(s, void 0, void 0, u);
553
+ r != null && r !== s && ae(o, s, r);
543
554
  }
544
- Object.keys(o).length > 0 && (i[u] = o);
555
+ Object.keys(o).length > 0 && (c[u] = o);
545
556
  } else {
546
- const o = r.getRouteTranslations(l, u);
547
- o && (i[u] = o);
557
+ const o = a.getRouteTranslations(l, u);
558
+ o && (c[u] = o);
548
559
  }
549
560
  return {
550
561
  locale: l,
551
- fallbackLocale: c,
562
+ fallbackLocale: i,
552
563
  currentRoute: u,
553
- translations: i
564
+ translations: c
554
565
  };
555
566
  }
556
567
  export {
557
568
  v as AstroI18n,
558
- be as FormatService,
559
- de as createAstroRouterAdapter,
560
- ue as createI18n,
561
- ge as createI18nMiddleware,
562
- ye as defaultPlural,
563
- he as detectLocale,
569
+ we as FormatService,
570
+ pe as createAstroRouterAdapter,
571
+ ge as createI18n,
572
+ de as createI18nMiddleware,
573
+ Re as defaultPlural,
574
+ me as detectLocale,
564
575
  k as getDefaultLocale,
565
- I as getGlobalRoutingStrategy,
566
- M as getI18n,
567
- Le as getI18nProps,
576
+ N as getGlobalRoutingStrategy,
577
+ A as getI18n,
578
+ Pe as getI18nProps,
568
579
  j as getLocale,
569
- A as getLocales,
570
- ce as i18nIntegration,
571
- we as interpolate,
580
+ oe as getLocaleRewritePath,
581
+ F as getLocales,
582
+ fe as i18nIntegration,
583
+ Te as interpolate,
572
584
  ee as loadTranslationsFromDir,
573
- fe as loadTranslationsIntoI18n,
585
+ he as loadTranslationsIntoI18n,
586
+ Le as prepareLocaleRewrite,
574
587
  Y as runWithRoutingStrategy,
575
588
  X as setGlobalRoutingStrategy,
576
- me as useI18n,
577
- pe as useLocaleHead
589
+ ne as useI18n,
590
+ Se as useLocaleHead
578
591
  };
package/dist/utils.d.ts CHANGED
@@ -52,6 +52,15 @@ export declare function useI18n(astro: AstroGlobal): {
52
52
  mergeTranslations: (locale: string, routeName: string, translations: Record<string, unknown>) => void;
53
53
  clearCache: () => void;
54
54
  };
55
+ /**
56
+ * Strip locale prefix from the current URL for `Astro.rewrite()` on `/[locale]/*` routes.
57
+ */
58
+ export declare function getLocaleRewritePath(astro: AstroGlobal): string;
59
+ /**
60
+ * Validate `:locale`, sync i18n/locals, and return the base path for `Astro.rewrite()`.
61
+ * Returns a `Response` when the locale param is invalid.
62
+ */
63
+ export declare function prepareLocaleRewrite(astro: AstroGlobal): Response | string;
55
64
  /**
56
65
  * Generate locale head meta tags for SEO
57
66
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@i18n-micro/astro",
3
- "version": "1.3.12",
3
+ "version": "1.3.13",
4
4
  "description": "Astro integration for i18n-micro — translations, routing, and islands.",
5
5
  "keywords": [
6
6
  "astro",
@@ -43,6 +43,9 @@
43
43
  "./env": {
44
44
  "types": "./dist/env.d.ts"
45
45
  },
46
+ "./astro-shim": {
47
+ "types": "./dist/env.d.ts"
48
+ },
46
49
  "./components/i18n-t.astro": "./src/components/i18n-t.astro",
47
50
  "./components/i18n-link.astro": "./src/components/i18n-link.astro",
48
51
  "./components/i18n-switcher.astro": "./src/components/i18n-switcher.astro",
@@ -77,10 +80,10 @@
77
80
  "access": "public"
78
81
  },
79
82
  "dependencies": {
80
- "@i18n-micro/core": "^1.3.14",
81
- "@i18n-micro/types": "^1.2.11",
82
- "@i18n-micro/node": "^1.2.8",
83
- "@i18n-micro/utils": "^1.0.14"
83
+ "@i18n-micro/core": "^1.3.15",
84
+ "@i18n-micro/node": "^1.2.9",
85
+ "@i18n-micro/utils": "^1.0.15",
86
+ "@i18n-micro/types": "^1.2.12"
84
87
  },
85
88
  "devDependencies": {
86
89
  "astro": "^5.0.0 || ^6.0.0 || ^7.0.0",
@@ -123,6 +126,6 @@
123
126
  "dev": "cd playground && astro dev",
124
127
  "test": "vitest run",
125
128
  "test:dist": "vitest run --config vitest.dist.config.ts",
126
- "typecheck": "tsc --noEmit"
129
+ "typecheck": "tsc --noEmit && pnpm --dir playground typecheck"
127
130
  }
128
131
  }
@@ -0,0 +1 @@
1
+ import './env'
package/src/index.ts CHANGED
@@ -20,5 +20,15 @@ export { createAstroRouterAdapter } from './router/adapter'
20
20
  export type { I18nRoutingStrategy } from './router/types'
21
21
  export type { I18nClientProps, LocaleHeadOptions, LocaleHeadResult } from './utils'
22
22
  // Utilities
23
- export { getDefaultLocale, getI18n, getI18nProps, getLocale, getLocales, useI18n, useLocaleHead } from './utils'
23
+ export {
24
+ getDefaultLocale,
25
+ getI18n,
26
+ getI18nProps,
27
+ getLocale,
28
+ getLocaleRewritePath,
29
+ getLocales,
30
+ prepareLocaleRewrite,
31
+ useI18n,
32
+ useLocaleHead,
33
+ } from './utils'
24
34
  // It's loaded directly by Astro via entrypoint in integration config
package/src/utils.ts CHANGED
@@ -181,6 +181,35 @@ export function useI18n(astro: AstroGlobal) {
181
181
  }
182
182
  }
183
183
 
184
+ /**
185
+ * Strip locale prefix from the current URL for `Astro.rewrite()` on `/[locale]/*` routes.
186
+ */
187
+ export function getLocaleRewritePath(astro: AstroGlobal): string {
188
+ const url = astro.locals.currentUrl ?? astro.url
189
+ return useI18n(astro).getBasePath(url)
190
+ }
191
+
192
+ /**
193
+ * Validate `:locale`, sync i18n/locals, and return the base path for `Astro.rewrite()`.
194
+ * Returns a `Response` when the locale param is invalid.
195
+ */
196
+ export function prepareLocaleRewrite(astro: AstroGlobal): Response | string {
197
+ const { locale } = astro.params
198
+ const localeCodes = getLocales(astro).map((entry) => entry.code)
199
+
200
+ if (!locale || !localeCodes.includes(locale)) {
201
+ return new Response(null, { status: 404 })
202
+ }
203
+
204
+ const i18n = astro.locals.i18n
205
+ if (i18n) {
206
+ i18n.locale = locale
207
+ astro.locals.locale = locale
208
+ }
209
+
210
+ return getLocaleRewritePath(astro)
211
+ }
212
+
184
213
  /**
185
214
  * Generate locale head meta tags for SEO
186
215
  */