@i18n-micro/astro 1.3.0 → 1.3.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/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=require("@i18n-micro/core"),b=require("node:fs"),I=require("node:path");class w extends j.BaseI18n{constructor(e){const s=e._storage||{translations:new Map};if(super({storage:s,plural:e.plural,missingWarn:e.missingWarn,missingHandler:e.missingHandler}),this.initialMessages={},this.storage=s,this._locale=e.locale,this._fallbackLocale=e.fallbackLocale||e.locale,this._currentRoute="index",e.messages){this.initialMessages={...e.messages};for(const[o,i]of Object.entries(e.messages))this.helper.loadTranslations(o,i)}}cloneStorage(e){const s=new Map;for(const[o,i]of e.translations)s.set(o,{...i});return{translations:s}}clone(e){const s=this.cloneStorage(this.storage);return new w({locale:e||this._locale,fallbackLocale:this._fallbackLocale,plural:this.pluralFunc,missingWarn:this.missingWarn,missingHandler:this.missingHandler,_storage:s})}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,s){const o=`${e}:${s}`;return this.storage.translations.get(o)??null}addTranslations(e,s,o=!0){super.loadTranslationsCore(e,s,o)}addRouteTranslations(e,s,o,i=!0){super.loadRouteTranslationsCore(e,s,o,i)}mergeTranslations(e,s,o){this.helper.mergeTranslation(e,s,o,!0)}clearCache(){const e={...this.initialMessages};if(super.clearCache(),Object.keys(e).length>0)for(const[s,o]of Object.entries(e))this.helper.loadTranslations(s,o)}}let $=null;function D(){return $}function C(n){const{locale:e,fallbackLocale:s,translationDir:o,routingStrategy:i}=n;return $=i||null,{name:"@i18n-micro/astro",hooks:{"astro:config:setup":c=>{const{updateConfig:f}=c,t="virtual:i18n-micro/config",l=`\0${t}`,r={defaultLocale:e,fallbackLocale:s||e,locales:n.locales||[],localeCodes:(n.locales||[]).map(a=>a.code),translationDir:o||null,autoDetect:n.autoDetect??!0,redirectToDefault:n.redirectToDefault??!1,localeCookie:n.localeCookie===null?null:n.localeCookie||"i18n-locale",missingWarn:n.missingWarn??!1};f({vite:{plugins:[{name:"vite-plugin-i18n-micro-config",resolveId(a){if(a===t)return l},load(a){if(a===l)return`export const config = ${JSON.stringify(r)}`}}]}})},"astro:config:done":c=>{const{injectTypes:f}=c;f({filename:"i18n-micro-env.d.ts",content:`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const w=require("@i18n-micro/core"),S=require("node:fs"),k=require("node:path");class j extends w.BaseI18n{constructor(e){const s=e._storage||{translations:new Map};if(super({storage:s,plural:e.plural,missingWarn:e.missingWarn,missingHandler:e.missingHandler}),this.initialMessages={},this.storage=s,this._locale=e.locale,this._fallbackLocale=e.fallbackLocale||e.locale,this._currentRoute="index",e.messages){this.initialMessages={...e.messages};for(const[a,i]of Object.entries(e.messages))this.helper.loadTranslations(a,i)}}cloneStorage(e){const s=new Map;for(const[a,i]of e.translations)s.set(a,{...i});return{translations:s}}clone(e){const s=this.cloneStorage(this.storage);return new j({locale:e||this._locale,fallbackLocale:this._fallbackLocale,plural:this.pluralFunc,missingWarn:this.missingWarn,missingHandler:this.missingHandler,_storage:s})}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,s){const a=`${e}:${s}`;return this.storage.translations.get(a)??null}addTranslations(e,s,a=!0){super.loadTranslationsCore(e,s,a)}addRouteTranslations(e,s,a,i=!0){super.loadRouteTranslationsCore(e,s,a,i)}mergeTranslations(e,s,a){this.helper.mergeTranslation(e,s,a,!0)}clearCache(){const e={...this.initialMessages};if(super.clearCache(),Object.keys(e).length>0)for(const[s,a]of Object.entries(e))this.helper.loadTranslations(s,a)}}let I=null;function D(){return I}function C(t){const{locale:e,fallbackLocale:s,translationDir:a,routingStrategy:i}=t;return I=i||null,{name:"@i18n-micro/astro",hooks:{"astro:config:setup":c=>{const{updateConfig:u}=c,n="virtual:i18n-micro/config",l=`\0${n}`,r={defaultLocale:e,fallbackLocale:s||e,locales:t.locales||[],localeCodes:(t.locales||[]).map(o=>o.code),translationDir:a||null,autoDetect:t.autoDetect??!0,redirectToDefault:t.redirectToDefault??!1,localeCookie:t.localeCookie===null?null:t.localeCookie||"i18n-locale",missingWarn:t.missingWarn??!1};u({vite:{plugins:[{name:"vite-plugin-i18n-micro-config",resolveId(o){if(o===n)return l},load(o){if(o===l)return`export const config = ${JSON.stringify(r)}`}}]}})},"astro:config:done":c=>{const{injectTypes:u}=c;u({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 N(n){return new w(n)}function F(n){const{translationDir:e,rootDir:s=process.cwd(),disablePageLocales:o=!1}=n,i=I.resolve(s,e);if(!b.existsSync(i))return console.warn(`[i18n] Translation directory not found: ${i}`),{root:{},routes:{}};const c={},f={},t=(l,r="")=>{if(!b.existsSync(l))return;const a=b.readdirSync(l);for(const u of a){const h=I.join(l,u);if(b.statSync(h).isDirectory())u==="pages"&&!o?t(h,""):r||o?t(h,r):t(h,u);else if(u.endsWith(".json")){const m=u.replace(".json","");try{const g=b.readFileSync(h,"utf-8"),p=JSON.parse(g);r&&!o?(f[r]||(f[r]={}),f[r][m]=p):c[m]=p}catch(g){console.error(`[i18n] Failed to load translation file: ${h}`,g)}}}};return t(i),{root:c,routes:f}}function q(n,e){const{root:s,routes:o}=F(e);for(const[i,c]of Object.entries(s))n.addTranslations(i,c,!1);for(const[i,c]of Object.entries(o))for(const[f,t]of Object.entries(c)){const l=s[f]||{};n.addRouteTranslations(f,i,{...l,...t},!1)}}function M(n){const{i18n:e,defaultLocale:s,locales:o,localeObjects:i,autoDetect:c=!0,redirectToDefault:f=!1,routingStrategy:t}=n,l=t||D();return async(r,a)=>{if(r.locals.locale&&r.locals.i18n)return a();const u=r.url,h=u.pathname;if(!l){const S=e.clone(s),O=h==="/"||h===""?"index":h.split("/").filter(Boolean).join("-");return S.setRoute(O),r.locals.i18n=S,r.locals.locale=s,r.locals.defaultLocale=s,r.locals.locales=i||o.map(_=>({code:_})),r.locals.currentUrl=u,a()}const d={...l,getCurrentPath:()=>h,getRoute:()=>({fullPath:u.pathname+u.search,query:Object.fromEntries(u.searchParams)})},g=h.split("/").filter(Boolean)[0],p=g!==void 0&&o.includes(g);let P;p&&g?P=g:d.getLocaleFromPath?P=d.getLocaleFromPath(h,s,o):P=s;const L=e.clone(P),y=d.getRouteName?d.getRouteName(h,o):"index";return L.setRoute(y),r.locals.i18n=L,r.locals.locale=P,r.locals.defaultLocale=s,r.locals.locales=i||o.map(S=>({code:S})),r.locals.currentUrl=u,r.locals.routingStrategy=d,a()}}function A(n){const e=[],s=n.split(",");for(const o of s){const[i,c="1.0"]=o.trim().split(";q=");if(Number.parseFloat(c)>0&&i){const t=i.split("-")[0]?.toLowerCase();t&&(e.push(t),i!==t&&e.push(i.toLowerCase()))}}return e}function W(n,e,s,o,i,c="i18n-locale"){const f=D();let t=o;if(f?.getLocaleFromPath)t=f.getLocaleFromPath(n,o,i);else{const r=n.split("/").filter(Boolean)[0];r&&i.includes(r)&&(t=r)}if(c!==null&&t===o&&e.get(c)){const l=e.get(c)?.value;l&&i.includes(l)&&(t=l)}if(t===o)try{const l=s.get("accept-language");if(l){const r=A(l);for(const a of r)if(i.includes(a)){t=a;break}}}catch{}return t}function z(n,e,s){const o=n.map(a=>a.code),i=(a,u=[])=>{const h=a.replace(/^\//,"").replace(/\/$/,"");if(!h)return"index";const d=h.split("/").filter(Boolean),m=d[0];return m&&u.includes(m)&&d.shift(),d.length===0?"index":d.join("-")},c=(a,u="en",h=[])=>{const m=a.split("/").filter(Boolean)[0];return m&&h.includes(m)?m:u},f=(a,u,h=[],d)=>{const m=a.split("/").filter(Boolean),g=m[0];return g&&h.includes(g)&&m.shift(),(u!==d||d===void 0)&&m.unshift(u),`/${m.join("/")}`},t=(a,u,h=[],d)=>{const g=(a.replace(/^\//,"").replace(/\/$/,"")||"").split("/").filter(Boolean),p=g[0];return p&&h.includes(p)&&g.shift(),(u!==d||d===void 0)&&g.unshift(u),`/${g.join("/")}`};return{getCurrentPath:()=>s?s().pathname:typeof window<"u"?window.location.pathname:"/",getRouteName:i,getLocaleFromPath:c,switchLocalePath:f,localizePath:t,removeLocaleFromPath:(a,u=[])=>{const h=a.split("/").filter(Boolean),d=h[0];return d&&u.includes(d)&&h.shift(),`/${h.join("/")}`},resolvePath:(a,u)=>{const h=typeof a=="string"?a:a.path||"/";return t(h,u,o,e)},getRoute:()=>{if(s){const a=s();return{fullPath:a.pathname+a.search,query:Object.fromEntries(a.searchParams)}}if(typeof window<"u"){const a=new URL(window.location.href);return{fullPath:a.pathname+a.search,query:Object.fromEntries(a.searchParams)}}return{fullPath:"/",query:{}}},push:a=>{typeof window<"u"&&(window.location.href=a.path)},replace:a=>{typeof window<"u"&&window.location.replace(a.path)}}}function H(n,e=[]){const s=n.replace(/^\//,"").replace(/\/$/,"");if(!s)return"index";const o=s.split("/").filter(Boolean),i=o[0];return i&&e.includes(i)&&o.shift(),o.length===0?"index":o.join("-")}function U(n,e="en",s=[]){const i=n.split("/").filter(Boolean)[0];return i&&s.includes(i)?i:e}function E(n,e,s=[],o){const i=n.split("/").filter(Boolean),c=i[0];return c&&s.includes(c)&&i.shift(),(e!==o||o===void 0)&&i.unshift(e),`/${i.join("/")}`}function J(n,e,s=[],o){const c=(n.replace(/^\//,"").replace(/\/$/,"")||"").split("/").filter(Boolean),f=c[0];return f&&s.includes(f)&&c.shift(),(e!==o||o===void 0)&&c.unshift(e),`/${c.join("/")}`}function V(n,e=[]){const s=n.split("/").filter(Boolean),o=s[0];return o&&e.includes(o)&&s.shift(),`/${s.join("/")}`}function v(n){const e=n.locals.i18n;if(!e)throw new Error("i18n instance not found. Make sure i18n middleware is configured.");return e}function R(n){return n.locals.locale||"en"}function T(n){return n.locals.defaultLocale||"en"}function k(n){return n.locals.locales||[]}function B(n){return n.locals.routingStrategy||null}function G(n){const e=v(n),s=R(n),o=T(n),i=k(n),c=i.map(t=>t.code),f=B(n);return{locale:s,defaultLocale:o,locales:i,t:(t,l,r,a)=>e.t(t,l,r,a),ts:(t,l,r,a)=>e.ts(t,l,r,a),tc:(t,l,r)=>e.tc(t,l,r),tn:(t,l)=>e.tn(t,l),td:(t,l)=>e.td(t,l),tdr:(t,l)=>e.tdr(t,l),has:(t,l)=>e.has(t,l),getRoute:()=>e.getRoute(),getRouteName:t=>{const l=t||n.url.pathname;if(f?.getRouteName)return f.getRouteName(l,c);const r=l.replace(/^\//,"").replace(/\/$/,"");if(!r)return"index";const a=r.split("/").filter(Boolean),u=a[0];return u&&c.includes(u)&&a.shift(),a.length===0?"index":a.join("-")},getLocaleFromPath:t=>{const l=t||n.url.pathname;if(f?.getLocaleFromPath)return f.getLocaleFromPath(l,o,c);const a=l.split("/").filter(Boolean)[0];return a&&c.includes(a)?a:o},switchLocalePath:t=>{if(f?.switchLocalePath)return f.switchLocalePath(n.url.pathname,t,c,o);const l=n.url.pathname.split("/").filter(Boolean),r=l[0];return r&&c.includes(r)&&l.shift(),t!==o&&l.unshift(t),`/${l.join("/")}`},localizePath:(t,l)=>{if(f?.localizePath)return f.localizePath(t,l||s,c,o);const a=(t.replace(/^\//,"").replace(/\/$/,"")||"").split("/").filter(Boolean),u=a[0];return u&&c.includes(u)&&a.shift(),l&&l!==o&&a.unshift(l),`/${a.join("/")}`},getI18n:()=>e,getBasePath:t=>{const a=(t||n.url).pathname.split("/").filter(Boolean),u=a[0];return u&&c.includes(u)&&a.shift(),a.length>0?`/${a.join("/")}`:"/"},addTranslations:(t,l,r=!0)=>{e.addTranslations(t,l,r)},addRouteTranslations:(t,l,r,a=!0)=>{e.addRouteTranslations(t,l,r,a)},mergeTranslations:(t,l,r)=>{e.mergeTranslations(t,l,r)},clearCache:()=>{e.clearCache()}}}function K(n,e={}){const{baseUrl:s="/",addDirAttribute:o=!0,addSeoAttributes:i=!0}=e,c=R(n),f=T(n),t=k(n),l=t.find(g=>g.code===c);if(!l)return{htmlAttrs:{},link:[],meta:[]};const r=l.iso||c,a=l.dir||"auto",u={htmlAttrs:{lang:r,...o?{dir:a}:{}},link:[],meta:[]};if(!i)return u;const h=`${s}${n.url.pathname}`;u.link.push({rel:"canonical",href:h});const d=B(n),m=t.map(g=>g.code);for(const g of t){if(g.code===c)continue;let p=n.url.pathname;if(d?.switchLocalePath)p=d.switchLocalePath(n.url.pathname,g.code,m,f);else{const L=n.url.pathname.split("/").filter(Boolean),y=L[0];y&&m.includes(y)&&L.shift(),g.code!==f&&L.unshift(g.code),p=`/${L.join("/")}`}const P=`${s}${p}`;u.link.push({rel:"alternate",href:P,hreflang:g.code}),g.iso&&g.iso!==g.code&&u.link.push({rel:"alternate",href:P,hreflang:g.iso})}u.meta.push({property:"og:locale",content:r}),u.meta.push({property:"og:url",content:h});for(const g of t)g.code!==c&&u.meta.push({property:"og:locale:alternate",content:g.iso||g.code});return u}function Q(n,e,s){const o=e.split(".");let i=n;for(let f=0;f<o.length-1;f++){const t=o[f];i[t]||(i[t]={}),i=i[t]}const c=o[o.length-1];c!==void 0&&(i[c]=s)}function X(n,e){const s=v(n),o=R(n),i=T(n),c=s.getRoute(),f={};if(e&&e.length>0){const t={};for(const l of e){const r=s.t(l,void 0,void 0,c);r!=null&&r!==l&&Q(t,l,r)}Object.keys(t).length>0&&(f[c]=t)}else{const t=s.getRouteTranslations(o,c);t&&(f[c]=t)}return{locale:o,fallbackLocale:i,currentRoute:c,translations:f}}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=w;exports.createAstroRouterAdapter=z;exports.createI18n=N;exports.createI18nMiddleware=M;exports.detectLocale=W;exports.getDefaultLocale=T;exports.getI18n=v;exports.getI18nProps=X;exports.getLocale=R;exports.getLocaleFromPath=U;exports.getLocales=k;exports.getRouteName=H;exports.i18nIntegration=C;exports.loadTranslationsFromDir=F;exports.loadTranslationsIntoI18n=q;exports.localizePath=J;exports.removeLocaleFromPath=V;exports.switchLocalePath=E;exports.useI18n=G;exports.useLocaleHead=K;
17
+ `})}}}}function N(t){return new j(t)}function F(t){const{translationDir:e,rootDir:s=process.cwd(),disablePageLocales:a=!1}=t,i=k.resolve(s,e);if(!S.existsSync(i))return console.warn(`[i18n] Translation directory not found: ${i}`),{root:{},routes:{}};const c={},u={},n=(l,r="")=>{if(!S.existsSync(l))return;const o=S.readdirSync(l);for(const g of o){const f=k.join(l,g);if(S.statSync(f).isDirectory())g==="pages"&&!a?n(f,""):r||a?n(f,r):n(f,g);else if(g.endsWith(".json")){const m=g.replace(".json","");try{const p=S.readFileSync(f,"utf-8"),h=JSON.parse(p);r&&!a?(u[r]||(u[r]={}),u[r][m]=h):c[m]=h}catch(p){console.error(`[i18n] Failed to load translation file: ${f}`,p)}}}};return n(i),{root:c,routes:u}}function q(t,e){const{root:s,routes:a}=F(e);for(const[i,c]of Object.entries(s))t.addTranslations(i,c,!1);for(const[i,c]of Object.entries(a))for(const[u,n]of Object.entries(c)){const l=s[u]||{};t.addRouteTranslations(u,i,{...l,...n},!1)}}function M(t){const{i18n:e,defaultLocale:s,locales:a,localeObjects:i,autoDetect:c=!0,redirectToDefault:u=!1,routingStrategy:n}=t,l=n||D();return async(r,o)=>{if(r.locals.locale&&r.locals.i18n)return o();const g=r.url,f=g.pathname;if(!l){const b=e.clone(s),O=f==="/"||f===""?"index":f.split("/").filter(Boolean).join("-");return b.setRoute(O),r.locals.i18n=b,r.locals.locale=s,r.locals.defaultLocale=s,r.locals.locales=i||a.map(_=>({code:_})),r.locals.currentUrl=g,o()}const d={...l,getCurrentPath:()=>f,getRoute:()=>({fullPath:g.pathname+g.search,query:Object.fromEntries(g.searchParams)})},p=f.split("/").filter(Boolean)[0],h=p!==void 0&&a.includes(p);let P;h&&p?P=p:d.getLocaleFromPath?P=d.getLocaleFromPath(f,s,a):P=s;const L=e.clone(P),y=d.getRouteName?d.getRouteName(f,a):"index";return L.setRoute(y),r.locals.i18n=L,r.locals.locale=P,r.locals.defaultLocale=s,r.locals.locales=i||a.map(b=>({code:b})),r.locals.currentUrl=g,r.locals.routingStrategy=d,o()}}function A(t){const e=[],s=t.split(",");for(const a of s){const[i,c="1.0"]=a.trim().split(";q=");if(Number.parseFloat(c)>0&&i){const n=i.split("-")[0]?.toLowerCase();n&&(e.push(n),i!==n&&e.push(i.toLowerCase()))}}return e}function W(t,e,s,a,i,c="i18n-locale"){const u=D();let n=a;if(u?.getLocaleFromPath)n=u.getLocaleFromPath(t,a,i);else{const r=t.split("/").filter(Boolean)[0];r&&i.includes(r)&&(n=r)}if(c!==null&&n===a&&e.get(c)){const l=e.get(c)?.value;l&&i.includes(l)&&(n=l)}if(n===a)try{const l=s.get("accept-language");if(l){const r=A(l);for(const o of r)if(i.includes(o)){n=o;break}}}catch{}return n}function z(t,e,s){const a=t.map(o=>o.code),i=(o,g=[])=>{const f=o.replace(/^\//,"").replace(/\/$/,"");if(!f)return"index";const d=f.split("/").filter(Boolean),m=d[0];return m&&g.includes(m)&&d.shift(),d.length===0?"index":d.join("-")},c=(o,g="en",f=[])=>{const m=o.split("/").filter(Boolean)[0];return m&&f.includes(m)?m:g},u=(o,g,f=[],d)=>{const m=o.split("/").filter(Boolean),p=m[0];return p&&f.includes(p)&&m.shift(),(g!==d||d===void 0)&&m.unshift(g),`/${m.join("/")}`},n=(o,g,f=[],d)=>{const p=(o.replace(/^\//,"").replace(/\/$/,"")||"").split("/").filter(Boolean),h=p[0];return h&&f.includes(h)&&p.shift(),(g!==d||d===void 0)&&p.unshift(g),`/${p.join("/")}`};return{getCurrentPath:()=>s?s().pathname:typeof window<"u"?window.location.pathname:"/",getRouteName:i,getLocaleFromPath:c,switchLocalePath:u,localizePath:n,removeLocaleFromPath:(o,g=[])=>{const f=o.split("/").filter(Boolean),d=f[0];return d&&g.includes(d)&&f.shift(),`/${f.join("/")}`},resolvePath:(o,g)=>{const f=typeof o=="string"?o:o.path||"/";return n(f,g,a,e)},getRoute:()=>{if(s){const o=s();return{fullPath:o.pathname+o.search,query:Object.fromEntries(o.searchParams)}}if(typeof window<"u"){const o=new URL(window.location.href);return{fullPath:o.pathname+o.search,query:Object.fromEntries(o.searchParams)}}return{fullPath:"/",query:{}}},push:o=>{typeof window<"u"&&(window.location.href=o.path)},replace:o=>{typeof window<"u"&&window.location.replace(o.path)}}}function H(t,e=[]){const s=t.replace(/^\//,"").replace(/\/$/,"");if(!s)return"index";const a=s.split("/").filter(Boolean),i=a[0];return i&&e.includes(i)&&a.shift(),a.length===0?"index":a.join("-")}function U(t,e="en",s=[]){const i=t.split("/").filter(Boolean)[0];return i&&s.includes(i)?i:e}function E(t,e,s=[],a){const i=t.split("/").filter(Boolean),c=i[0];return c&&s.includes(c)&&i.shift(),(e!==a||a===void 0)&&i.unshift(e),`/${i.join("/")}`}function J(t,e,s=[],a){const c=(t.replace(/^\//,"").replace(/\/$/,"")||"").split("/").filter(Boolean),u=c[0];return u&&s.includes(u)&&c.shift(),(e!==a||a===void 0)&&c.unshift(e),`/${c.join("/")}`}function V(t,e=[]){const s=t.split("/").filter(Boolean),a=s[0];return a&&e.includes(a)&&s.shift(),`/${s.join("/")}`}function v(t){const e=t.locals.i18n;if(!e)throw new Error("i18n instance not found. Make sure i18n middleware is configured.");return e}function R(t){return t.locals.locale||"en"}function T(t){return t.locals.defaultLocale||"en"}function $(t){return t.locals.locales||[]}function B(t){return t.locals.routingStrategy||null}function G(t){const e=v(t),s=R(t),a=T(t),i=$(t),c=i.map(n=>n.code),u=B(t);return{locale:s,defaultLocale:a,locales:i,t:(n,l,r,o)=>e.t(n,l,r,o),ts:(n,l,r,o)=>e.ts(n,l,r,o),tc:(n,l,r)=>e.tc(n,l,r),tn:(n,l)=>e.tn(n,l),td:(n,l)=>e.td(n,l),tdr:(n,l)=>e.tdr(n,l),has:(n,l)=>e.has(n,l),getRoute:()=>e.getRoute(),getRouteName:n=>{const l=n||t.url.pathname;if(u?.getRouteName)return u.getRouteName(l,c);const r=l.replace(/^\//,"").replace(/\/$/,"");if(!r)return"index";const o=r.split("/").filter(Boolean),g=o[0];return g&&c.includes(g)&&o.shift(),o.length===0?"index":o.join("-")},getLocaleFromPath:n=>{const l=n||t.url.pathname;if(u?.getLocaleFromPath)return u.getLocaleFromPath(l,a,c);const o=l.split("/").filter(Boolean)[0];return o&&c.includes(o)?o:a},switchLocalePath:n=>{if(u?.switchLocalePath)return u.switchLocalePath(t.url.pathname,n,c,a);const l=t.url.pathname.split("/").filter(Boolean),r=l[0];return r&&c.includes(r)&&l.shift(),n!==a&&l.unshift(n),`/${l.join("/")}`},localizePath:(n,l)=>{if(u?.localizePath)return u.localizePath(n,l||s,c,a);const o=(n.replace(/^\//,"").replace(/\/$/,"")||"").split("/").filter(Boolean),g=o[0];return g&&c.includes(g)&&o.shift(),l&&l!==a&&o.unshift(l),`/${o.join("/")}`},getI18n:()=>e,getBasePath:n=>{const o=(n||t.url).pathname.split("/").filter(Boolean),g=o[0];return g&&c.includes(g)&&o.shift(),o.length>0?`/${o.join("/")}`:"/"},addTranslations:(n,l,r=!0)=>{e.addTranslations(n,l,r)},addRouteTranslations:(n,l,r,o=!0)=>{e.addRouteTranslations(n,l,r,o)},mergeTranslations:(n,l,r)=>{e.mergeTranslations(n,l,r)},clearCache:()=>{e.clearCache()}}}function K(t,e={}){const{baseUrl:s="/",addDirAttribute:a=!0,addSeoAttributes:i=!0}=e,c=R(t),u=T(t),l=$(t).filter(h=>!h.disabled),r=l.find(h=>h.code===c);if(!r)return{htmlAttrs:{},link:[],meta:[]};const o=r.iso||c,g=r.dir||"auto",f={htmlAttrs:{lang:o,...a?{dir:g}:{}},link:[],meta:[]};if(!i)return f;const d=`${s}${t.url.pathname}`;f.link.push({rel:"canonical",href:d});const m=B(t),p=l.map(h=>h.code);for(const h of l){let P=t.url.pathname;if(m?.switchLocalePath)P=m.switchLocalePath(t.url.pathname,h.code,p,u);else{const y=t.url.pathname.split("/").filter(Boolean),b=y[0];b&&p.includes(b)&&y.shift(),h.code!==u&&y.unshift(h.code),P=`/${y.join("/")}`}const L=`${s}${P}`;f.link.push({rel:"alternate",href:L,hreflang:h.code}),h.iso&&h.iso!==h.code&&f.link.push({rel:"alternate",href:L,hreflang:h.iso})}{let h=t.url.pathname;if(m?.switchLocalePath)h=m.switchLocalePath(t.url.pathname,u,p,u);else{const P=t.url.pathname.split("/").filter(Boolean),L=P[0];L&&p.includes(L)&&P.shift(),h=`/${P.join("/")}`}f.link.push({rel:"alternate",href:`${s}${h}`,hreflang:"x-default"})}f.meta.push({property:"og:locale",content:o}),f.meta.push({property:"og:url",content:d});for(const h of l)h.code!==c&&f.meta.push({property:"og:locale:alternate",content:h.iso||h.code});return f}function Q(t,e,s){const a=e.split(".");let i=t;for(let u=0;u<a.length-1;u++){const n=a[u];i[n]||(i[n]={}),i=i[n]}const c=a[a.length-1];c!==void 0&&(i[c]=s)}function X(t,e){const s=v(t),a=R(t),i=T(t),c=s.getRoute(),u={};if(e&&e.length>0){const n={};for(const l of e){const r=s.t(l,void 0,void 0,c);r!=null&&r!==l&&Q(n,l,r)}Object.keys(n).length>0&&(u[c]=n)}else{const n=s.getRouteTranslations(a,c);n&&(u[c]=n)}return{locale:a,fallbackLocale:i,currentRoute:c,translations:u}}Object.defineProperty(exports,"FormatService",{enumerable:!0,get:()=>w.FormatService});Object.defineProperty(exports,"defaultPlural",{enumerable:!0,get:()=>w.defaultPlural});Object.defineProperty(exports,"interpolate",{enumerable:!0,get:()=>w.interpolate});exports.AstroI18n=j;exports.createAstroRouterAdapter=z;exports.createI18n=N;exports.createI18nMiddleware=M;exports.detectLocale=W;exports.getDefaultLocale=T;exports.getI18n=v;exports.getI18nProps=X;exports.getLocale=R;exports.getLocaleFromPath=U;exports.getLocales=$;exports.getRouteName=H;exports.i18nIntegration=C;exports.loadTranslationsFromDir=F;exports.loadTranslationsIntoI18n=q;exports.localizePath=J;exports.removeLocaleFromPath=V;exports.switchLocalePath=E;exports.useI18n=G;exports.useLocaleHead=K;
package/dist/index.mjs CHANGED
@@ -4,35 +4,35 @@ import { existsSync as j, readdirSync as _, statSync as C, readFileSync as N } f
4
4
  import { resolve as O, join as q } from "node:path";
5
5
  class S extends I {
6
6
  constructor(e) {
7
- const a = e._storage || {
7
+ const s = e._storage || {
8
8
  translations: /* @__PURE__ */ new Map()
9
9
  };
10
10
  if (super({
11
- storage: a,
11
+ storage: s,
12
12
  plural: e.plural,
13
13
  missingWarn: e.missingWarn,
14
14
  missingHandler: e.missingHandler
15
- }), this.initialMessages = {}, this.storage = a, this._locale = e.locale, this._fallbackLocale = e.fallbackLocale || e.locale, this._currentRoute = "index", e.messages) {
15
+ }), this.initialMessages = {}, this.storage = s, this._locale = e.locale, this._fallbackLocale = e.fallbackLocale || e.locale, this._currentRoute = "index", e.messages) {
16
16
  this.initialMessages = { ...e.messages };
17
- for (const [o, i] of Object.entries(e.messages))
18
- this.helper.loadTranslations(o, i);
17
+ for (const [a, i] of Object.entries(e.messages))
18
+ this.helper.loadTranslations(a, i);
19
19
  }
20
20
  }
21
21
  cloneStorage(e) {
22
- const a = /* @__PURE__ */ new Map();
23
- for (const [o, i] of e.translations)
24
- a.set(o, { ...i });
25
- return { translations: a };
22
+ const s = /* @__PURE__ */ new Map();
23
+ for (const [a, i] of e.translations)
24
+ s.set(a, { ...i });
25
+ return { translations: s };
26
26
  }
27
27
  clone(e) {
28
- const a = this.cloneStorage(this.storage);
28
+ const s = this.cloneStorage(this.storage);
29
29
  return new S({
30
30
  locale: e || this._locale,
31
31
  fallbackLocale: this._fallbackLocale,
32
32
  plural: this.pluralFunc,
33
33
  missingWarn: this.missingWarn,
34
34
  missingHandler: this.missingHandler,
35
- _storage: a
35
+ _storage: s
36
36
  });
37
37
  }
38
38
  get locale() {
@@ -59,59 +59,59 @@ class S extends I {
59
59
  getRoute() {
60
60
  return this._currentRoute;
61
61
  }
62
- getRouteTranslations(e, a) {
63
- const o = `${e}:${a}`;
64
- return this.storage.translations.get(o) ?? null;
62
+ getRouteTranslations(e, s) {
63
+ const a = `${e}:${s}`;
64
+ return this.storage.translations.get(a) ?? null;
65
65
  }
66
- addTranslations(e, a, o = !0) {
67
- super.loadTranslationsCore(e, a, o);
66
+ addTranslations(e, s, a = !0) {
67
+ super.loadTranslationsCore(e, s, a);
68
68
  }
69
- addRouteTranslations(e, a, o, i = !0) {
70
- super.loadRouteTranslationsCore(e, a, o, i);
69
+ addRouteTranslations(e, s, a, i = !0) {
70
+ super.loadRouteTranslationsCore(e, s, a, i);
71
71
  }
72
- mergeTranslations(e, a, o) {
73
- this.helper.mergeTranslation(e, a, o, !0);
72
+ mergeTranslations(e, s, a) {
73
+ this.helper.mergeTranslation(e, s, a, !0);
74
74
  }
75
75
  clearCache() {
76
76
  const e = { ...this.initialMessages };
77
77
  if (super.clearCache(), Object.keys(e).length > 0)
78
- for (const [a, o] of Object.entries(e))
79
- this.helper.loadTranslations(a, o);
78
+ for (const [s, a] of Object.entries(e))
79
+ this.helper.loadTranslations(s, a);
80
80
  }
81
81
  }
82
82
  let T = null;
83
- function v() {
83
+ function $() {
84
84
  return T;
85
85
  }
86
- function E(n) {
87
- const { locale: e, fallbackLocale: a, translationDir: o, routingStrategy: i } = n;
86
+ function E(t) {
87
+ const { locale: e, fallbackLocale: s, translationDir: a, routingStrategy: i } = t;
88
88
  return T = i || null, {
89
89
  name: "@i18n-micro/astro",
90
90
  hooks: {
91
91
  // 1. Vite setup (virtual module) happens here
92
92
  "astro:config:setup": (c) => {
93
- const { updateConfig: f } = c, t = "virtual:i18n-micro/config", l = `\0${t}`, r = {
93
+ const { updateConfig: u } = c, n = "virtual:i18n-micro/config", l = `\0${n}`, r = {
94
94
  defaultLocale: e,
95
- fallbackLocale: a || e,
96
- locales: n.locales || [],
97
- localeCodes: (n.locales || []).map((s) => s.code),
98
- translationDir: o || null,
99
- autoDetect: n.autoDetect ?? !0,
100
- redirectToDefault: n.redirectToDefault ?? !1,
101
- localeCookie: n.localeCookie === null ? null : n.localeCookie || "i18n-locale",
102
- missingWarn: n.missingWarn ?? !1
95
+ fallbackLocale: s || e,
96
+ locales: t.locales || [],
97
+ localeCodes: (t.locales || []).map((o) => o.code),
98
+ translationDir: a || null,
99
+ autoDetect: t.autoDetect ?? !0,
100
+ redirectToDefault: t.redirectToDefault ?? !1,
101
+ localeCookie: t.localeCookie === null ? null : t.localeCookie || "i18n-locale",
102
+ missingWarn: t.missingWarn ?? !1
103
103
  };
104
- f({
104
+ u({
105
105
  vite: {
106
106
  plugins: [
107
107
  {
108
108
  name: "vite-plugin-i18n-micro-config",
109
- resolveId(s) {
110
- if (s === t)
109
+ resolveId(o) {
110
+ if (o === n)
111
111
  return l;
112
112
  },
113
- load(s) {
114
- if (s === l)
113
+ load(o) {
114
+ if (o === l)
115
115
  return `export const config = ${JSON.stringify(r)}`;
116
116
  }
117
117
  }
@@ -121,8 +121,8 @@ function E(n) {
121
121
  },
122
122
  // 2. Type injection happens here (per Astro documentation)
123
123
  "astro:config:done": (c) => {
124
- const { injectTypes: f } = c;
125
- f({
124
+ const { injectTypes: u } = c;
125
+ u({
126
126
  filename: "i18n-micro-env.d.ts",
127
127
  content: `
128
128
  /// <reference types="@i18n-micro/astro/env" />
@@ -146,159 +146,159 @@ function E(n) {
146
146
  }
147
147
  };
148
148
  }
149
- function J(n) {
150
- return new S(n);
149
+ function J(t) {
150
+ return new S(t);
151
151
  }
152
- function M(n) {
153
- const { translationDir: e, rootDir: a = process.cwd(), disablePageLocales: o = !1 } = n, i = O(a, e);
152
+ function M(t) {
153
+ const { translationDir: e, rootDir: s = process.cwd(), disablePageLocales: a = !1 } = t, i = O(s, e);
154
154
  if (!j(i))
155
155
  return console.warn(`[i18n] Translation directory not found: ${i}`), { root: {}, routes: {} };
156
- const c = {}, f = {}, t = (l, r = "") => {
156
+ const c = {}, u = {}, n = (l, r = "") => {
157
157
  if (!j(l)) return;
158
- const s = _(l);
159
- for (const u of s) {
160
- const h = q(l, u);
161
- if (C(h).isDirectory())
162
- u === "pages" && !o ? t(h, "") : r || o ? t(h, r) : t(h, u);
163
- else if (u.endsWith(".json")) {
164
- const m = u.replace(".json", "");
158
+ const o = _(l);
159
+ for (const g of o) {
160
+ const f = q(l, g);
161
+ if (C(f).isDirectory())
162
+ g === "pages" && !a ? n(f, "") : r || a ? n(f, r) : n(f, g);
163
+ else if (g.endsWith(".json")) {
164
+ const m = g.replace(".json", "");
165
165
  try {
166
- const g = N(h, "utf-8"), p = JSON.parse(g);
167
- r && !o ? (f[r] || (f[r] = {}), f[r][m] = p) : c[m] = p;
168
- } catch (g) {
169
- console.error(`[i18n] Failed to load translation file: ${h}`, g);
166
+ const p = N(f, "utf-8"), h = JSON.parse(p);
167
+ r && !a ? (u[r] || (u[r] = {}), u[r][m] = h) : c[m] = h;
168
+ } catch (p) {
169
+ console.error(`[i18n] Failed to load translation file: ${f}`, p);
170
170
  }
171
171
  }
172
172
  }
173
173
  };
174
- return t(i), { root: c, routes: f };
174
+ return n(i), { root: c, routes: u };
175
175
  }
176
- function V(n, e) {
177
- const { root: a, routes: o } = M(e);
176
+ function V(t, e) {
177
+ const { root: s, routes: a } = M(e);
178
+ for (const [i, c] of Object.entries(s))
179
+ t.addTranslations(i, c, !1);
178
180
  for (const [i, c] of Object.entries(a))
179
- n.addTranslations(i, c, !1);
180
- for (const [i, c] of Object.entries(o))
181
- for (const [f, t] of Object.entries(c)) {
182
- const l = a[f] || {};
183
- n.addRouteTranslations(f, i, { ...l, ...t }, !1);
181
+ for (const [u, n] of Object.entries(c)) {
182
+ const l = s[u] || {};
183
+ t.addRouteTranslations(u, i, { ...l, ...n }, !1);
184
184
  }
185
185
  }
186
- function G(n) {
186
+ function G(t) {
187
187
  const {
188
188
  i18n: e,
189
189
  // This is the global singleton with cache
190
- defaultLocale: a,
191
- locales: o,
190
+ defaultLocale: s,
191
+ locales: a,
192
192
  localeObjects: i,
193
193
  autoDetect: c = !0,
194
- redirectToDefault: f = !1,
195
- routingStrategy: t
196
- } = n, l = t || v();
197
- return async (r, s) => {
194
+ redirectToDefault: u = !1,
195
+ routingStrategy: n
196
+ } = t, l = n || $();
197
+ return async (r, o) => {
198
198
  if (r.locals.locale && r.locals.i18n)
199
- return s();
200
- const u = r.url, h = u.pathname;
199
+ return o();
200
+ const g = r.url, f = g.pathname;
201
201
  if (!l) {
202
- const b = e.clone(a), B = h === "/" || h === "" ? "index" : h.split("/").filter(Boolean).join("-");
203
- return b.setRoute(B), r.locals.i18n = b, r.locals.locale = a, r.locals.defaultLocale = a, r.locals.locales = i || o.map((F) => ({ code: F })), r.locals.currentUrl = u, s();
202
+ const b = e.clone(s), B = f === "/" || f === "" ? "index" : f.split("/").filter(Boolean).join("-");
203
+ return b.setRoute(B), r.locals.i18n = b, r.locals.locale = s, r.locals.defaultLocale = s, r.locals.locales = i || a.map((F) => ({ code: F })), r.locals.currentUrl = g, o();
204
204
  }
205
205
  const d = {
206
206
  ...l,
207
- getCurrentPath: () => h,
207
+ getCurrentPath: () => f,
208
208
  getRoute: () => ({
209
- fullPath: u.pathname + u.search,
210
- query: Object.fromEntries(u.searchParams)
209
+ fullPath: g.pathname + g.search,
210
+ query: Object.fromEntries(g.searchParams)
211
211
  })
212
- }, g = h.split("/").filter(Boolean)[0], p = g !== void 0 && o.includes(g);
212
+ }, p = f.split("/").filter(Boolean)[0], h = p !== void 0 && a.includes(p);
213
213
  let P;
214
- p && g ? P = g : d.getLocaleFromPath ? P = d.getLocaleFromPath(h, a, o) : P = a;
215
- const L = e.clone(P), y = d.getRouteName ? d.getRouteName(h, o) : "index";
216
- return L.setRoute(y), r.locals.i18n = L, r.locals.locale = P, r.locals.defaultLocale = a, r.locals.locales = i || o.map((b) => ({ code: b })), r.locals.currentUrl = u, r.locals.routingStrategy = d, s();
214
+ h && p ? P = p : d.getLocaleFromPath ? P = d.getLocaleFromPath(f, s, a) : P = s;
215
+ const L = e.clone(P), y = d.getRouteName ? d.getRouteName(f, a) : "index";
216
+ return L.setRoute(y), r.locals.i18n = L, r.locals.locale = P, r.locals.defaultLocale = s, r.locals.locales = i || a.map((b) => ({ code: b })), r.locals.currentUrl = g, r.locals.routingStrategy = d, o();
217
217
  };
218
218
  }
219
- function W(n) {
220
- const e = [], a = n.split(",");
221
- for (const o of a) {
222
- const [i, c = "1.0"] = o.trim().split(";q=");
219
+ function W(t) {
220
+ const e = [], s = t.split(",");
221
+ for (const a of s) {
222
+ const [i, c = "1.0"] = a.trim().split(";q=");
223
223
  if (Number.parseFloat(c) > 0 && i) {
224
- const t = i.split("-")[0]?.toLowerCase();
225
- t && (e.push(t), i !== t && e.push(i.toLowerCase()));
224
+ const n = i.split("-")[0]?.toLowerCase();
225
+ n && (e.push(n), i !== n && e.push(i.toLowerCase()));
226
226
  }
227
227
  }
228
228
  return e;
229
229
  }
230
- function K(n, e, a, o, i, c = "i18n-locale") {
231
- const f = v();
232
- let t = o;
233
- if (f?.getLocaleFromPath)
234
- t = f.getLocaleFromPath(n, o, i);
230
+ function K(t, e, s, a, i, c = "i18n-locale") {
231
+ const u = $();
232
+ let n = a;
233
+ if (u?.getLocaleFromPath)
234
+ n = u.getLocaleFromPath(t, a, i);
235
235
  else {
236
- const r = n.split("/").filter(Boolean)[0];
237
- r && i.includes(r) && (t = r);
236
+ const r = t.split("/").filter(Boolean)[0];
237
+ r && i.includes(r) && (n = r);
238
238
  }
239
- if (c !== null && t === o && e.get(c)) {
239
+ if (c !== null && n === a && e.get(c)) {
240
240
  const l = e.get(c)?.value;
241
- l && i.includes(l) && (t = l);
241
+ l && i.includes(l) && (n = l);
242
242
  }
243
- if (t === o)
243
+ if (n === a)
244
244
  try {
245
- const l = a.get("accept-language");
245
+ const l = s.get("accept-language");
246
246
  if (l) {
247
247
  const r = W(l);
248
- for (const s of r)
249
- if (i.includes(s)) {
250
- t = s;
248
+ for (const o of r)
249
+ if (i.includes(o)) {
250
+ n = o;
251
251
  break;
252
252
  }
253
253
  }
254
254
  } catch {
255
255
  }
256
- return t;
256
+ return n;
257
257
  }
258
- function Q(n, e, a) {
259
- const o = n.map((s) => s.code), i = (s, u = []) => {
260
- const h = s.replace(/^\//, "").replace(/\/$/, "");
261
- if (!h)
258
+ function x(t, e, s) {
259
+ const a = t.map((o) => o.code), i = (o, g = []) => {
260
+ const f = o.replace(/^\//, "").replace(/\/$/, "");
261
+ if (!f)
262
262
  return "index";
263
- const d = h.split("/").filter(Boolean), m = d[0];
264
- return m && u.includes(m) && d.shift(), d.length === 0 ? "index" : d.join("-");
265
- }, c = (s, u = "en", h = []) => {
266
- const m = s.split("/").filter(Boolean)[0];
267
- return m && h.includes(m) ? m : u;
268
- }, f = (s, u, h = [], d) => {
269
- const m = s.split("/").filter(Boolean), g = m[0];
270
- return g && h.includes(g) && m.shift(), (u !== d || d === void 0) && m.unshift(u), `/${m.join("/")}`;
271
- }, t = (s, u, h = [], d) => {
272
- const g = (s.replace(/^\//, "").replace(/\/$/, "") || "").split("/").filter(Boolean), p = g[0];
273
- return p && h.includes(p) && g.shift(), (u !== d || d === void 0) && g.unshift(u), `/${g.join("/")}`;
263
+ const d = f.split("/").filter(Boolean), m = d[0];
264
+ return m && g.includes(m) && d.shift(), d.length === 0 ? "index" : d.join("-");
265
+ }, c = (o, g = "en", f = []) => {
266
+ const m = o.split("/").filter(Boolean)[0];
267
+ return m && f.includes(m) ? m : g;
268
+ }, u = (o, g, f = [], d) => {
269
+ const m = o.split("/").filter(Boolean), p = m[0];
270
+ return p && f.includes(p) && m.shift(), (g !== d || d === void 0) && m.unshift(g), `/${m.join("/")}`;
271
+ }, n = (o, g, f = [], d) => {
272
+ const p = (o.replace(/^\//, "").replace(/\/$/, "") || "").split("/").filter(Boolean), h = p[0];
273
+ return h && f.includes(h) && p.shift(), (g !== d || d === void 0) && p.unshift(g), `/${p.join("/")}`;
274
274
  };
275
275
  return {
276
- getCurrentPath: () => a ? a().pathname : typeof window < "u" ? window.location.pathname : "/",
276
+ getCurrentPath: () => s ? s().pathname : typeof window < "u" ? window.location.pathname : "/",
277
277
  getRouteName: i,
278
278
  getLocaleFromPath: c,
279
- switchLocalePath: f,
280
- localizePath: t,
281
- removeLocaleFromPath: (s, u = []) => {
282
- const h = s.split("/").filter(Boolean), d = h[0];
283
- return d && u.includes(d) && h.shift(), `/${h.join("/")}`;
279
+ switchLocalePath: u,
280
+ localizePath: n,
281
+ removeLocaleFromPath: (o, g = []) => {
282
+ const f = o.split("/").filter(Boolean), d = f[0];
283
+ return d && g.includes(d) && f.shift(), `/${f.join("/")}`;
284
284
  },
285
- resolvePath: (s, u) => {
286
- const h = typeof s == "string" ? s : s.path || "/";
287
- return t(h, u, o, e);
285
+ resolvePath: (o, g) => {
286
+ const f = typeof o == "string" ? o : o.path || "/";
287
+ return n(f, g, a, e);
288
288
  },
289
289
  getRoute: () => {
290
- if (a) {
291
- const s = a();
290
+ if (s) {
291
+ const o = s();
292
292
  return {
293
- fullPath: s.pathname + s.search,
294
- query: Object.fromEntries(s.searchParams)
293
+ fullPath: o.pathname + o.search,
294
+ query: Object.fromEntries(o.searchParams)
295
295
  };
296
296
  }
297
297
  if (typeof window < "u") {
298
- const s = new URL(window.location.href);
298
+ const o = new URL(window.location.href);
299
299
  return {
300
- fullPath: s.pathname + s.search,
301
- query: Object.fromEntries(s.searchParams)
300
+ fullPath: o.pathname + o.search,
301
+ query: Object.fromEntries(o.searchParams)
302
302
  };
303
303
  }
304
304
  return {
@@ -307,229 +307,242 @@ function Q(n, e, a) {
307
307
  };
308
308
  },
309
309
  // Optional: client-side navigation for islands
310
- push: (s) => {
311
- typeof window < "u" && (window.location.href = s.path);
310
+ push: (o) => {
311
+ typeof window < "u" && (window.location.href = o.path);
312
312
  },
313
- replace: (s) => {
314
- typeof window < "u" && window.location.replace(s.path);
313
+ replace: (o) => {
314
+ typeof window < "u" && window.location.replace(o.path);
315
315
  }
316
316
  };
317
317
  }
318
- function X(n, e = []) {
319
- const a = n.replace(/^\//, "").replace(/\/$/, "");
320
- if (!a)
318
+ function Q(t, e = []) {
319
+ const s = t.replace(/^\//, "").replace(/\/$/, "");
320
+ if (!s)
321
321
  return "index";
322
- const o = a.split("/").filter(Boolean), i = o[0];
323
- return i && e.includes(i) && o.shift(), o.length === 0 ? "index" : o.join("-");
322
+ const a = s.split("/").filter(Boolean), i = a[0];
323
+ return i && e.includes(i) && a.shift(), a.length === 0 ? "index" : a.join("-");
324
324
  }
325
- function Y(n, e = "en", a = []) {
326
- const i = n.split("/").filter(Boolean)[0];
327
- return i && a.includes(i) ? i : e;
325
+ function X(t, e = "en", s = []) {
326
+ const i = t.split("/").filter(Boolean)[0];
327
+ return i && s.includes(i) ? i : e;
328
328
  }
329
- function Z(n, e, a = [], o) {
330
- const i = n.split("/").filter(Boolean), c = i[0];
331
- return c && a.includes(c) && i.shift(), (e !== o || o === void 0) && i.unshift(e), `/${i.join("/")}`;
329
+ function Y(t, e, s = [], a) {
330
+ const i = t.split("/").filter(Boolean), c = i[0];
331
+ return c && s.includes(c) && i.shift(), (e !== a || a === void 0) && i.unshift(e), `/${i.join("/")}`;
332
332
  }
333
- function x(n, e, a = [], o) {
334
- const c = (n.replace(/^\//, "").replace(/\/$/, "") || "").split("/").filter(Boolean), f = c[0];
335
- return f && a.includes(f) && c.shift(), (e !== o || o === void 0) && c.unshift(e), `/${c.join("/")}`;
333
+ function Z(t, e, s = [], a) {
334
+ const c = (t.replace(/^\//, "").replace(/\/$/, "") || "").split("/").filter(Boolean), u = c[0];
335
+ return u && s.includes(u) && c.shift(), (e !== a || a === void 0) && c.unshift(e), `/${c.join("/")}`;
336
336
  }
337
- function ee(n, e = []) {
338
- const a = n.split("/").filter(Boolean), o = a[0];
339
- return o && e.includes(o) && a.shift(), `/${a.join("/")}`;
337
+ function ee(t, e = []) {
338
+ const s = t.split("/").filter(Boolean), a = s[0];
339
+ return a && e.includes(a) && s.shift(), `/${s.join("/")}`;
340
340
  }
341
- function k(n) {
342
- const e = n.locals.i18n;
341
+ function v(t) {
342
+ const e = t.locals.i18n;
343
343
  if (!e)
344
344
  throw new Error("i18n instance not found. Make sure i18n middleware is configured.");
345
345
  return e;
346
346
  }
347
- function w(n) {
348
- return n.locals.locale || "en";
347
+ function w(t) {
348
+ return t.locals.locale || "en";
349
349
  }
350
- function R(n) {
351
- return n.locals.defaultLocale || "en";
350
+ function R(t) {
351
+ return t.locals.defaultLocale || "en";
352
352
  }
353
- function $(n) {
354
- return n.locals.locales || [];
353
+ function k(t) {
354
+ return t.locals.locales || [];
355
355
  }
356
- function D(n) {
357
- return n.locals.routingStrategy || null;
356
+ function D(t) {
357
+ return t.locals.routingStrategy || null;
358
358
  }
359
- function te(n) {
360
- const e = k(n), a = w(n), o = R(n), i = $(n), c = i.map((t) => t.code), f = D(n);
359
+ function te(t) {
360
+ const e = v(t), s = w(t), a = R(t), i = k(t), c = i.map((n) => n.code), u = D(t);
361
361
  return {
362
362
  // Current locale
363
- locale: a,
364
- defaultLocale: o,
363
+ locale: s,
364
+ defaultLocale: a,
365
365
  locales: i,
366
366
  // Translation methods
367
- t: (t, l, r, s) => e.t(t, l, r, s),
368
- ts: (t, l, r, s) => e.ts(t, l, r, s),
369
- tc: (t, l, r) => e.tc(t, l, r),
370
- tn: (t, l) => e.tn(t, l),
371
- td: (t, l) => e.td(t, l),
372
- tdr: (t, l) => e.tdr(t, l),
373
- has: (t, l) => e.has(t, l),
367
+ t: (n, l, r, o) => e.t(n, l, r, o),
368
+ ts: (n, l, r, o) => e.ts(n, l, r, o),
369
+ tc: (n, l, r) => e.tc(n, l, r),
370
+ tn: (n, l) => e.tn(n, l),
371
+ td: (n, l) => e.td(n, l),
372
+ tdr: (n, l) => e.tdr(n, l),
373
+ has: (n, l) => e.has(n, l),
374
374
  // Route management
375
375
  getRoute: () => e.getRoute(),
376
- getRouteName: (t) => {
377
- const l = t || n.url.pathname;
378
- if (f?.getRouteName)
379
- return f.getRouteName(l, c);
376
+ getRouteName: (n) => {
377
+ const l = n || t.url.pathname;
378
+ if (u?.getRouteName)
379
+ return u.getRouteName(l, c);
380
380
  const r = l.replace(/^\//, "").replace(/\/$/, "");
381
381
  if (!r) return "index";
382
- const s = r.split("/").filter(Boolean), u = s[0];
383
- return u && c.includes(u) && s.shift(), s.length === 0 ? "index" : s.join("-");
382
+ const o = r.split("/").filter(Boolean), g = o[0];
383
+ return g && c.includes(g) && o.shift(), o.length === 0 ? "index" : o.join("-");
384
384
  },
385
- getLocaleFromPath: (t) => {
386
- const l = t || n.url.pathname;
387
- if (f?.getLocaleFromPath)
388
- return f.getLocaleFromPath(l, o, c);
389
- const s = l.split("/").filter(Boolean)[0];
390
- return s && c.includes(s) ? s : o;
385
+ getLocaleFromPath: (n) => {
386
+ const l = n || t.url.pathname;
387
+ if (u?.getLocaleFromPath)
388
+ return u.getLocaleFromPath(l, a, c);
389
+ const o = l.split("/").filter(Boolean)[0];
390
+ return o && c.includes(o) ? o : a;
391
391
  },
392
392
  // Path utilities
393
- switchLocalePath: (t) => {
394
- if (f?.switchLocalePath)
395
- return f.switchLocalePath(n.url.pathname, t, c, o);
396
- const l = n.url.pathname.split("/").filter(Boolean), r = l[0];
397
- return r && c.includes(r) && l.shift(), t !== o && l.unshift(t), `/${l.join("/")}`;
393
+ switchLocalePath: (n) => {
394
+ if (u?.switchLocalePath)
395
+ return u.switchLocalePath(t.url.pathname, n, c, a);
396
+ const l = t.url.pathname.split("/").filter(Boolean), r = l[0];
397
+ return r && c.includes(r) && l.shift(), n !== a && l.unshift(n), `/${l.join("/")}`;
398
398
  },
399
- localizePath: (t, l) => {
400
- if (f?.localizePath)
401
- return f.localizePath(t, l || a, c, o);
402
- const s = (t.replace(/^\//, "").replace(/\/$/, "") || "").split("/").filter(Boolean), u = s[0];
403
- return u && c.includes(u) && s.shift(), l && l !== o && s.unshift(l), `/${s.join("/")}`;
399
+ localizePath: (n, l) => {
400
+ if (u?.localizePath)
401
+ return u.localizePath(n, l || s, c, a);
402
+ const o = (n.replace(/^\//, "").replace(/\/$/, "") || "").split("/").filter(Boolean), g = o[0];
403
+ return g && c.includes(g) && o.shift(), l && l !== a && o.unshift(l), `/${o.join("/")}`;
404
404
  },
405
405
  // Get i18n instance
406
406
  getI18n: () => e,
407
407
  // Get base path without locale (for rewrite)
408
- getBasePath: (t) => {
409
- const s = (t || n.url).pathname.split("/").filter(Boolean), u = s[0];
410
- return u && c.includes(u) && s.shift(), s.length > 0 ? `/${s.join("/")}` : "/";
408
+ getBasePath: (n) => {
409
+ const o = (n || t.url).pathname.split("/").filter(Boolean), g = o[0];
410
+ return g && c.includes(g) && o.shift(), o.length > 0 ? `/${o.join("/")}` : "/";
411
411
  },
412
412
  // Translation management
413
- addTranslations: (t, l, r = !0) => {
414
- e.addTranslations(t, l, r);
413
+ addTranslations: (n, l, r = !0) => {
414
+ e.addTranslations(n, l, r);
415
415
  },
416
- addRouteTranslations: (t, l, r, s = !0) => {
417
- e.addRouteTranslations(t, l, r, s);
416
+ addRouteTranslations: (n, l, r, o = !0) => {
417
+ e.addRouteTranslations(n, l, r, o);
418
418
  },
419
- mergeTranslations: (t, l, r) => {
420
- e.mergeTranslations(t, l, r);
419
+ mergeTranslations: (n, l, r) => {
420
+ e.mergeTranslations(n, l, r);
421
421
  },
422
422
  clearCache: () => {
423
423
  e.clearCache();
424
424
  }
425
425
  };
426
426
  }
427
- function ne(n, e = {}) {
428
- const { baseUrl: a = "/", addDirAttribute: o = !0, addSeoAttributes: i = !0 } = e, c = w(n), f = R(n), t = $(n), l = t.find((g) => g.code === c);
429
- if (!l)
427
+ function ne(t, e = {}) {
428
+ const { baseUrl: s = "/", addDirAttribute: a = !0, addSeoAttributes: i = !0 } = e, c = w(t), u = R(t), l = k(t).filter((h) => !h.disabled), r = l.find((h) => h.code === c);
429
+ if (!r)
430
430
  return { htmlAttrs: {}, link: [], meta: [] };
431
- const r = l.iso || c, s = l.dir || "auto", u = {
431
+ const o = r.iso || c, g = r.dir || "auto", f = {
432
432
  htmlAttrs: {
433
- lang: r,
434
- ...o ? { dir: s } : {}
433
+ lang: o,
434
+ ...a ? { dir: g } : {}
435
435
  },
436
436
  link: [],
437
437
  meta: []
438
438
  };
439
439
  if (!i)
440
- return u;
441
- const h = `${a}${n.url.pathname}`;
442
- u.link.push({
440
+ return f;
441
+ const d = `${s}${t.url.pathname}`;
442
+ f.link.push({
443
443
  rel: "canonical",
444
- href: h
444
+ href: d
445
445
  });
446
- const d = D(n), m = t.map((g) => g.code);
447
- for (const g of t) {
448
- if (g.code === c) continue;
449
- let p = n.url.pathname;
450
- if (d?.switchLocalePath)
451
- p = d.switchLocalePath(n.url.pathname, g.code, m, f);
446
+ const m = D(t), p = l.map((h) => h.code);
447
+ for (const h of l) {
448
+ let P = t.url.pathname;
449
+ if (m?.switchLocalePath)
450
+ P = m.switchLocalePath(t.url.pathname, h.code, p, u);
452
451
  else {
453
- const L = n.url.pathname.split("/").filter(Boolean), y = L[0];
454
- y && m.includes(y) && L.shift(), g.code !== f && L.unshift(g.code), p = `/${L.join("/")}`;
452
+ const y = t.url.pathname.split("/").filter(Boolean), b = y[0];
453
+ b && p.includes(b) && y.shift(), h.code !== u && y.unshift(h.code), P = `/${y.join("/")}`;
455
454
  }
456
- const P = `${a}${p}`;
457
- u.link.push({
455
+ const L = `${s}${P}`;
456
+ f.link.push({
458
457
  rel: "alternate",
459
- href: P,
460
- hreflang: g.code
461
- }), g.iso && g.iso !== g.code && u.link.push({
458
+ href: L,
459
+ hreflang: h.code
460
+ }), h.iso && h.iso !== h.code && f.link.push({
462
461
  rel: "alternate",
463
- href: P,
464
- hreflang: g.iso
462
+ href: L,
463
+ hreflang: h.iso
465
464
  });
466
465
  }
467
- u.meta.push({
466
+ {
467
+ let h = t.url.pathname;
468
+ if (m?.switchLocalePath)
469
+ h = m.switchLocalePath(t.url.pathname, u, p, u);
470
+ else {
471
+ const P = t.url.pathname.split("/").filter(Boolean), L = P[0];
472
+ L && p.includes(L) && P.shift(), h = `/${P.join("/")}`;
473
+ }
474
+ f.link.push({
475
+ rel: "alternate",
476
+ href: `${s}${h}`,
477
+ hreflang: "x-default"
478
+ });
479
+ }
480
+ f.meta.push({
468
481
  property: "og:locale",
469
- content: r
470
- }), u.meta.push({
482
+ content: o
483
+ }), f.meta.push({
471
484
  property: "og:url",
472
- content: h
485
+ content: d
473
486
  });
474
- for (const g of t)
475
- g.code !== c && u.meta.push({
487
+ for (const h of l)
488
+ h.code !== c && f.meta.push({
476
489
  property: "og:locale:alternate",
477
- content: g.iso || g.code
490
+ content: h.iso || h.code
478
491
  });
479
- return u;
492
+ return f;
480
493
  }
481
- function A(n, e, a) {
482
- const o = e.split(".");
483
- let i = n;
484
- for (let f = 0; f < o.length - 1; f++) {
485
- const t = o[f];
486
- i[t] || (i[t] = {}), i = i[t];
494
+ function A(t, e, s) {
495
+ const a = e.split(".");
496
+ let i = t;
497
+ for (let u = 0; u < a.length - 1; u++) {
498
+ const n = a[u];
499
+ i[n] || (i[n] = {}), i = i[n];
487
500
  }
488
- const c = o[o.length - 1];
489
- c !== void 0 && (i[c] = a);
501
+ const c = a[a.length - 1];
502
+ c !== void 0 && (i[c] = s);
490
503
  }
491
- function oe(n, e) {
492
- const a = k(n), o = w(n), i = R(n), c = a.getRoute(), f = {};
504
+ function oe(t, e) {
505
+ const s = v(t), a = w(t), i = R(t), c = s.getRoute(), u = {};
493
506
  if (e && e.length > 0) {
494
- const t = {};
507
+ const n = {};
495
508
  for (const l of e) {
496
- const r = a.t(l, void 0, void 0, c);
497
- r != null && r !== l && A(t, l, r);
509
+ const r = s.t(l, void 0, void 0, c);
510
+ r != null && r !== l && A(n, l, r);
498
511
  }
499
- Object.keys(t).length > 0 && (f[c] = t);
512
+ Object.keys(n).length > 0 && (u[c] = n);
500
513
  } else {
501
- const t = a.getRouteTranslations(o, c);
502
- t && (f[c] = t);
514
+ const n = s.getRouteTranslations(a, c);
515
+ n && (u[c] = n);
503
516
  }
504
517
  return {
505
- locale: o,
518
+ locale: a,
506
519
  fallbackLocale: i,
507
520
  currentRoute: c,
508
- translations: f
521
+ translations: u
509
522
  };
510
523
  }
511
524
  export {
512
525
  S as AstroI18n,
513
526
  le as FormatService,
514
- Q as createAstroRouterAdapter,
527
+ x as createAstroRouterAdapter,
515
528
  J as createI18n,
516
529
  G as createI18nMiddleware,
517
530
  re as defaultPlural,
518
531
  K as detectLocale,
519
532
  R as getDefaultLocale,
520
- k as getI18n,
533
+ v as getI18n,
521
534
  oe as getI18nProps,
522
535
  w as getLocale,
523
- Y as getLocaleFromPath,
524
- $ as getLocales,
525
- X as getRouteName,
536
+ X as getLocaleFromPath,
537
+ k as getLocales,
538
+ Q as getRouteName,
526
539
  E as i18nIntegration,
527
540
  ie as interpolate,
528
541
  M as loadTranslationsFromDir,
529
542
  V as loadTranslationsIntoI18n,
530
- x as localizePath,
543
+ Z as localizePath,
531
544
  ee as removeLocaleFromPath,
532
- Z as switchLocalePath,
545
+ Y as switchLocalePath,
533
546
  te as useI18n,
534
547
  ne as useLocaleHead
535
548
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@i18n-micro/astro",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -52,8 +52,8 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@i18n-micro/core": "1.2.0",
55
- "@i18n-micro/types": "1.1.5",
56
- "@i18n-micro/node": "1.2.0"
55
+ "@i18n-micro/node": "1.2.0",
56
+ "@i18n-micro/types": "1.1.6"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "astro": "^5.16.5",
package/src/utils.ts CHANGED
@@ -215,7 +215,8 @@ export function useLocaleHead(astro: AstroGlobal, options: LocaleHeadOptions = {
215
215
 
216
216
  const locale = getLocale(astro)
217
217
  const defaultLocale = getDefaultLocale(astro)
218
- const locales = getLocales(astro)
218
+ const allLocales = getLocales(astro)
219
+ const locales = allLocales.filter((l) => !l.disabled)
219
220
  const currentLocaleObj = locales.find((l) => l.code === locale)
220
221
 
221
222
  if (!currentLocaleObj) {
@@ -238,7 +239,7 @@ export function useLocaleHead(astro: AstroGlobal, options: LocaleHeadOptions = {
238
239
  return result
239
240
  }
240
241
 
241
- // Canonical URL
242
+ // Canonical URL (uses pathname only — query params are excluded)
242
243
  const canonicalUrl = `${baseUrl}${astro.url.pathname}`
243
244
  result.link.push({
244
245
  rel: 'canonical',
@@ -249,10 +250,8 @@ export function useLocaleHead(astro: AstroGlobal, options: LocaleHeadOptions = {
249
250
  const routingStrategy = getRoutingStrategy(astro)
250
251
  const allLocaleCodes = locales.map((l) => l.code)
251
252
 
252
- // Alternate languages
253
+ // Alternate languages (includes current locale for self-referencing hreflang, per Google guidelines)
253
254
  for (const loc of locales) {
254
- if (loc.code === locale) continue
255
-
256
255
  let alternatePath = astro.url.pathname
257
256
  if (routingStrategy?.switchLocalePath) {
258
257
  alternatePath = routingStrategy.switchLocalePath(astro.url.pathname, loc.code, allLocaleCodes, defaultLocale)
@@ -285,6 +284,28 @@ export function useLocaleHead(astro: AstroGlobal, options: LocaleHeadOptions = {
285
284
  }
286
285
  }
287
286
 
287
+ // x-default hreflang — points to the default locale's URL.
288
+ // Tells search engines which URL to show when none of the
289
+ // specified languages match the user's browser settings.
290
+ {
291
+ let xDefaultPath = astro.url.pathname
292
+ if (routingStrategy?.switchLocalePath) {
293
+ xDefaultPath = routingStrategy.switchLocalePath(astro.url.pathname, defaultLocale, allLocaleCodes, defaultLocale)
294
+ } else {
295
+ const segments = astro.url.pathname.split('/').filter(Boolean)
296
+ const firstSegment = segments[0]
297
+ if (firstSegment && allLocaleCodes.includes(firstSegment)) {
298
+ segments.shift()
299
+ }
300
+ xDefaultPath = `/${segments.join('/')}`
301
+ }
302
+ result.link.push({
303
+ rel: 'alternate',
304
+ href: `${baseUrl}${xDefaultPath}`,
305
+ hreflang: 'x-default',
306
+ })
307
+ }
308
+
288
309
  // Open Graph locale
289
310
  result.meta.push({
290
311
  property: 'og:locale',