@i18n-micro/vitepress 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +73 -39
  2. package/client.d.ts +1 -0
  3. package/dist/adapter-BJ-0ltIc.cjs +2 -0
  4. package/dist/adapter-BJ-0ltIc.cjs.map +1 -0
  5. package/dist/adapter-BnsyIKhp.js +128 -0
  6. package/dist/adapter-BnsyIKhp.js.map +1 -0
  7. package/dist/config.cjs +64 -1
  8. package/dist/config.cjs.map +1 -1
  9. package/dist/config.d.cts +113 -111
  10. package/dist/config.d.ts +113 -111
  11. package/dist/config.mjs +393 -9
  12. package/dist/config.mjs.map +1 -1
  13. package/dist/create-BgMbe0w1.cjs +2 -0
  14. package/dist/create-BgMbe0w1.cjs.map +1 -0
  15. package/dist/create-Dev8Q66O.js +80 -0
  16. package/dist/create-Dev8Q66O.js.map +1 -0
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +87 -141
  20. package/dist/index.d.ts +87 -141
  21. package/dist/index.mjs +28 -249
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/node.cjs +1 -1
  24. package/dist/node.cjs.map +1 -1
  25. package/dist/node.d.cts +56 -116
  26. package/dist/node.d.ts +56 -116
  27. package/dist/node.mjs +23 -7
  28. package/dist/node.mjs.map +1 -1
  29. package/dist/{virtual-stubs → plugin/virtual-stubs}/config.d.cts +2 -1
  30. package/dist/runtime/define-theme.d.cts +39 -0
  31. package/dist/theme.cjs +2 -0
  32. package/dist/theme.cjs.map +1 -0
  33. package/dist/theme.d.cts +58 -0
  34. package/dist/theme.d.ts +58 -0
  35. package/dist/theme.mjs +35 -0
  36. package/dist/theme.mjs.map +1 -0
  37. package/dist/vitepress-locales-6msv22Sn.js +27 -0
  38. package/dist/vitepress-locales-6msv22Sn.js.map +1 -0
  39. package/dist/vitepress-locales-Cz4AutfI.cjs +2 -0
  40. package/dist/vitepress-locales-Cz4AutfI.cjs.map +1 -0
  41. package/package.json +18 -6
  42. package/dist/i18n-routing-CcppCuuS.js +0 -64
  43. package/dist/i18n-routing-CcppCuuS.js.map +0 -1
  44. package/dist/i18n-routing-D9iYAKDq.cjs +0 -46
  45. package/dist/i18n-routing-D9iYAKDq.cjs.map +0 -1
  46. package/dist/with-i18n-micro-01q-vPO9.cjs +0 -15
  47. package/dist/with-i18n-micro-01q-vPO9.cjs.map +0 -1
  48. package/dist/with-i18n-micro-DIAoqY71.js +0 -216
  49. package/dist/with-i18n-micro-DIAoqY71.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var V=Object.create;var S=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var E=Object.getPrototypeOf,G=Object.prototype.hasOwnProperty;var N=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of H(t))!G.call(e,s)&&s!==o&&S(e,s,{get:()=>t[s],enumerable:!(r=q(t,s))||r.enumerable});return e};var x=(e,t,o)=>(o=e!=null?V(E(e)):{},N(t||!e||!e.__esModule?S(o,"default",{value:e,enumerable:!0}):o,e));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const U=require("@i18n-micro/utils/parse-path"),P=require("@i18n-micro/vue"),K=require("vue"),B=require("./i18n-routing-D9iYAKDq.cjs"),k=require("@i18n-micro/core");function j(e){const t=e.indexOf("#"),o=e.indexOf("?");let r=e.length;return t>=0&&(r=Math.min(r,t)),o>=0&&(r=Math.min(r,o)),{pathname:e.slice(0,r)||"/",extras:e.slice(r)}}function O(e,t,o={}){const r=n=>{for(const[l,i]of Object.entries(o))if(i===n)return l;return n===t?"root":n},s=new Map;for(const n of e){if(n===t)continue;const l=r(n),i=l==="root"?n:l;s.set(i,n),i!==n&&s.set(n,n)}return s}function A(e,t,o,r={}){const{pathname:s}=j(e),n=s.split("/").filter(Boolean)[0];return n===void 0?o:O(t,o,r).get(n)??o}function W(e,t,o,r={}){const{pathname:s}=j(e),n=s.split("/").filter(Boolean),l=n[0];return l!==void 0&&(o!==void 0?O(t,o,r).has(l)&&n.shift():t.includes(l)&&n.shift()),n.length===0?"index":n.join("-").replace(/\.html$/,"")}function z(e){return K.defineComponent({name:"VitePressI18nLink",props:{to:{type:String,required:!0},style:{type:Object,default:void 0}},setup(t,{slots:o}){return()=>K.h("a",{href:t.to,style:t.style,onClick:r=>{r.defaultPrevented||r.button===0&&(r.metaKey||r.altKey||r.ctrlKey||r.shiftKey||(r.preventDefault(),e?e(t.to):typeof window<"u"&&window.location.assign(t.to)))}},o.default?.())}})}function M(e){const{locales:t,defaultLocale:o,localeKeyToCode:r={},getPath:s,go:n}=e,l=t.map(a=>a.code),i={...r},g=O(l,o,i),m=[...g.keys()],p=a=>i[a]?i[a]:a==="root"?o:a,u=a=>{for(const[c,h]of Object.entries(i))if(h===a)return c;return a===o?"root":a},w=a=>{if(a===o)return null;const c=u(a);return c==="root"?a:c},C=a=>{const c=a==="/"||a.endsWith("/"),h=a.split("/").filter(Boolean),b=h[0];return b!==void 0&&g.has(b)&&h.shift(),{segments:h,hadTrailingSlash:c}},v=a=>{const{pathname:c,extras:h}=j(a),{segments:b,hadTrailingSlash:T}=C(c);let L=b.length===0?"/":`/${b.join("/")}`;return L!=="/"&&T&&(L+="/"),`${L}${h}`},f=(a,c)=>{const{pathname:h,extras:b}=j(a),{segments:T,hadTrailingSlash:L}=C(h),R=w(c);R&&T.unshift(R);let I=T.length===0?"/":`/${T.join("/")}`;return I!=="/"&&L&&(I+="/"),`${I}${b}`},d=(a,c)=>f(a,c),y=(a,c)=>{const h=typeof a=="string"?a:a.path||"/";return f(h,c)},F=(a,c=!1)=>{if(n){n(a,{replace:c});return}typeof window<"u"&&(c?window.location.replace(a):window.location.assign(a))};return{localeCodes:l,defaultLocale:o,localeKeyToCode:i,urlPrefixes:m,codeFromLocaleKey:p,localeKeyFromCode:u,getLocaleFromPath:a=>A(a,l,o,i),switchLocalePath:d,localizePath:f,removeLocaleFromPath:v,linkComponent:z(n),getCurrentPath:()=>s?s():typeof window<"u"?window.location.pathname+window.location.search+window.location.hash:"/",push:a=>{F(a.path,!1)},replace:a=>{F(a.path,!0)},resolvePath:y,getRoute:()=>{const a=s?s():typeof window<"u"?window.location.pathname+window.location.search+window.location.hash:"/",c=typeof window<"u"?new URL(a,window.location.origin):new URL(a,"http://localhost");return{fullPath:c.pathname+c.search+c.hash,query:Object.fromEntries(c.searchParams)}}}}function D(e){return e.defaultLocale||e.locale}function _(e,t,o){if(o)for(const[r,s]of Object.entries(o))for(const[n,l]of Object.entries(s))e.global.addRouteTranslations(n,r,U.mergeRouteTranslationsWithRoot(t?.[n],l),!1)}function $(e){const t=D(e),o=e.locales??[],r=e.syncWithVitePress!==!1,s=P.createI18n({locale:e.locale,fallbackLocale:e.fallbackLocale??t,messages:e.messages,plural:e.plural,missingWarn:e.missingWarn,missingHandler:e.missingHandler,locales:o,defaultLocale:t});_(s,e.messages,e.routeMessages);const n=new WeakMap;let l=null;const i=g=>{const{app:m,router:p}=g;let u=n.get(m);if(!u){const f=M({locales:o,defaultLocale:t,localeKeyToCode:e.localeKeyToCode,getPath:()=>{const d=p.route;return`${d.path}${d.query||""}${d.hash||""}`},go:(d,y)=>p.go(d,y)});m.use(s),s.setRoutingStrategy(f),u={adapter:f,boundSyncHandler:null,chainedPrevious:void 0},n.set(m,u)}if(l=u.adapter,!r)return;const{adapter:w}=u,C=(f=p.route.path)=>{const d=w.getLocaleFromPath(f);s.global.getLocale()!==d&&(s.global.locale=d),s.global.setRoute(W(f,w.localeCodes,t,e.localeKeyToCode))};C();const v=p.onAfterRouteChange;v!==u.boundSyncHandler&&(u.chainedPrevious=typeof v=="function"?v:void 0),u.boundSyncHandler=async f=>{typeof u.chainedPrevious=="function"&&await u.chainedPrevious(f);const d=f.startsWith("http")?(()=>{const y=new URL(f);return y.pathname+y.search+y.hash})():f;C(d)},p.onAfterRouteChange=u.boundSyncHandler};return{i18n:s.global,plugin:s,get adapter(){return l},enhanceApp:i}}function J(e,t={}){const o=t.enhanceApp,r=e.enhanceApp,s=new WeakMap;return{...e,async enhanceApp(n){let l=s.get(n.app);if(!l){const[{config:i},g]=await Promise.all([import("virtual:i18n-micro/config"),import("virtual:i18n-micro/messages")]),m=i.localeCodes.length?i.localeCodes:i.locales.map(w=>w.code),p=t.localeKeyToCode??i.localeKeyToCode,u=A(n.router.route.path,m,i.defaultLocale,p);l=$({locale:u,defaultLocale:i.defaultLocale,fallbackLocale:i.fallbackLocale,locales:i.locales,messages:g.messages,routeMessages:g.routeMessages,missingWarn:i.missingWarn,syncWithVitePress:i.syncWithVitePress,localeKeyToCode:p,plural:t.plural,missingHandler:t.missingHandler}),s.set(n.app,l)}l.enhanceApp(n),r&&await r(n),o&&await o(n),l.enhanceApp(n)}}}function Q(e){if(!("default"in e)||!Object.keys(e).every(r=>r==="default"||r==="__esModule"))return!1;const o=e.default;return o!==null&&typeof o=="object"&&!Array.isArray(o)}function X(e){const t={};for(const[o,r]of Object.entries(e)){const n=(o.split("/").pop()||"").replace(/\.json$/,"");n&&(r&&typeof r=="object"&&Q(r)?t[n]=r.default:t[n]=r)}return t}Object.defineProperty(exports,"I18nGroup",{enumerable:!0,get:()=>P.I18nGroup});Object.defineProperty(exports,"I18nLink",{enumerable:!0,get:()=>P.I18nLink});Object.defineProperty(exports,"I18nSwitcher",{enumerable:!0,get:()=>P.I18nSwitcher});Object.defineProperty(exports,"I18nT",{enumerable:!0,get:()=>P.I18nT});Object.defineProperty(exports,"createI18n",{enumerable:!0,get:()=>P.createI18n});Object.defineProperty(exports,"useI18n",{enumerable:!0,get:()=>P.useI18n});exports.createI18nRoutingFromAdapter=B.createI18nRoutingFromAdapter;Object.defineProperty(exports,"FormatService",{enumerable:!0,get:()=>k.FormatService});Object.defineProperty(exports,"defaultPlural",{enumerable:!0,get:()=>k.defaultPlural});Object.defineProperty(exports,"interpolate",{enumerable:!0,get:()=>k.interpolate});exports.createVitePressI18n=$;exports.createVitePressRouterAdapter=M;exports.defineI18nTheme=J;exports.getLocaleFromPath=A;exports.messagesFromGlob=X;exports.routeNameFromPath=W;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("./create-BgMbe0w1.cjs"),u=require("./adapter-BJ-0ltIc.cjs"),n=require("@i18n-micro/vue"),i=require("@i18n-micro/core");function s(t){if(!("default"in t)||!Object.keys(t).every(e=>e==="default"||e==="__esModule"))return!1;const r=t.default;return r!==null&&typeof r=="object"&&!Array.isArray(r)}function l(t){const o={};for(const[r,e]of Object.entries(t)){const a=(r.split("/").pop()||"").replace(/\.json$/,"");a&&(e&&typeof e=="object"&&s(e)?o[a]=e.default:o[a]=e)}return o}exports.createI18n=c.createI18n;exports.getLocaleFromPath=u.getLocaleFromPath;exports.routeNameFromPath=u.routeNameFromPath;exports.stripSiteBase=u.stripSiteBase;Object.defineProperty(exports,"I18nGroup",{enumerable:!0,get:()=>n.I18nGroup});Object.defineProperty(exports,"I18nLink",{enumerable:!0,get:()=>n.I18nLink});Object.defineProperty(exports,"I18nSwitcher",{enumerable:!0,get:()=>n.I18nSwitcher});Object.defineProperty(exports,"I18nT",{enumerable:!0,get:()=>n.I18nT});Object.defineProperty(exports,"useI18n",{enumerable:!0,get:()=>n.useI18n});Object.defineProperty(exports,"FormatService",{enumerable:!0,get:()=>i.FormatService});Object.defineProperty(exports,"defaultPlural",{enumerable:!0,get:()=>i.defaultPlural});Object.defineProperty(exports,"interpolate",{enumerable:!0,get:()=>i.interpolate});exports.messagesFromGlob=l;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/router/adapter.ts","../src/create.ts","../src/define-theme.ts","../src/messages-from-glob.ts"],"sourcesContent":["import type { Locale } from '@i18n-micro/types'\nimport type { I18nRoutingStrategy } from '@i18n-micro/vue'\nimport { defineComponent, h, type Component, type PropType } from 'vue'\n\nexport interface VitePressRouterLike {\n route: {\n path: string\n hash?: string\n query?: string\n }\n go: (to: string, options?: { initialLoad?: boolean, replace?: boolean }) => void | Promise<void>\n onAfterRouteChange?: (to: string) => unknown\n}\n\nexport type VitePressGo = (href: string, options?: { replace?: boolean }) => void | Promise<void>\n\nexport interface VitePressRouterAdapterOptions {\n locales: Locale[]\n defaultLocale: string\n /**\n * Map VitePress locale keys (`root`, `fr`) to i18n locale codes.\n * Defaults: `root` → `defaultLocale`, other keys → same string as the key.\n * URL prefixes always use VitePress keys; i18n uses codes.\n */\n localeKeyToCode?: Record<string, string>\n getPath?: () => string\n go?: VitePressGo\n}\n\nexport interface VitePressRouterAdapter extends I18nRoutingStrategy {\n getLocaleFromPath: (path: string) => string\n switchLocalePath: (path: string, newLocale: string) => string\n localizePath: (path: string, locale: string) => string\n removeLocaleFromPath: (path: string) => string\n /** Resolve VitePress locale key (`root` / `fr`) to i18n code. */\n codeFromLocaleKey: (localeKey: string) => string\n /** Resolve i18n code to VitePress locale key. */\n localeKeyFromCode: (code: string) => string\n localeCodes: string[]\n defaultLocale: string\n /** Snapshot of mapping used when building the adapter (for `i18nRouting` serialization). */\n localeKeyToCode: Record<string, string>\n /** URL path prefixes (VitePress locale keys except `root`). */\n urlPrefixes: string[]\n}\n\nfunction splitPathAndExtras(path: string): { pathname: string, extras: string } {\n const hashIndex = path.indexOf('#')\n const queryIndex = path.indexOf('?')\n let cut = path.length\n if (hashIndex >= 0) cut = Math.min(cut, hashIndex)\n if (queryIndex >= 0) cut = Math.min(cut, queryIndex)\n return {\n pathname: path.slice(0, cut) || '/',\n extras: path.slice(cut),\n }\n}\n\n/**\n * Build URL prefix → i18n code map.\n * Prefixes are VitePress locale keys (and codes when they differ), never `root`.\n */\nexport function buildUrlPrefixToCode(\n localeCodes: string[],\n defaultLocale: string,\n localeKeyToCode: Record<string, string> = {},\n): Map<string, string> {\n const keyFromCode = (code: string): string => {\n for (const [key, mapped] of Object.entries(localeKeyToCode)) {\n if (mapped === code) return key\n }\n if (code === defaultLocale) return 'root'\n return code\n }\n\n const prefixToCode = new Map<string, string>()\n for (const code of localeCodes) {\n if (code === defaultLocale) continue\n const key = keyFromCode(code)\n const urlKey = key === 'root' ? code : key\n prefixToCode.set(urlKey, code)\n if (urlKey !== code) prefixToCode.set(code, code)\n }\n return prefixToCode\n}\n\n/**\n * Detect i18n locale code from a URL path (prefix_except_default).\n * Path prefixes are VitePress locale keys; return value is the i18n code.\n */\nexport function getLocaleFromPath(\n path: string,\n localeCodes: string[],\n defaultLocale: string,\n localeKeyToCode: Record<string, string> = {},\n): string {\n const { pathname } = splitPathAndExtras(path)\n const first = pathname.split('/').filter(Boolean)[0]\n if (first === undefined) return defaultLocale\n const prefixToCode = buildUrlPrefixToCode(localeCodes, defaultLocale, localeKeyToCode)\n return prefixToCode.get(first) ?? defaultLocale\n}\n\n/**\n * Route name for page-scoped dictionaries (`/guide/demo` → `guide-demo`).\n * Strips VitePress URL prefixes (keys), not only raw i18n codes.\n *\n * When `defaultLocale` is omitted (legacy 2-arg call), any segment that matches a\n * listed locale code is stripped — callers must not rely on `localeCodes[0]` as default.\n */\nexport function routeNameFromPath(\n path: string,\n localeCodes: string[],\n defaultLocale?: string,\n localeKeyToCode: Record<string, string> = {},\n): string {\n const { pathname } = splitPathAndExtras(path)\n const segments = pathname.split('/').filter(Boolean)\n const first = segments[0]\n if (first !== undefined) {\n if (defaultLocale !== undefined) {\n const prefixToCode = buildUrlPrefixToCode(localeCodes, defaultLocale, localeKeyToCode)\n if (prefixToCode.has(first)) segments.shift()\n }\n else if (localeCodes.includes(first)) {\n segments.shift()\n }\n }\n if (segments.length === 0) return 'index'\n return segments.join('-').replace(/\\.html$/, '')\n}\n\nfunction createVitePressLinkComponent(go?: VitePressGo): Component {\n return defineComponent({\n name: 'VitePressI18nLink',\n props: {\n to: { type: String, required: true },\n style: { type: Object as PropType<Record<string, string>>, default: undefined },\n },\n setup(props, { slots }) {\n return () =>\n h(\n 'a',\n {\n href: props.to,\n style: props.style,\n onClick: (e: MouseEvent) => {\n if (e.defaultPrevented) return\n if (e.button !== 0) return\n if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return\n e.preventDefault()\n if (go) {\n void go(props.to)\n }\n else if (typeof window !== 'undefined') {\n window.location.assign(props.to)\n }\n },\n },\n slots.default?.(),\n )\n },\n })\n}\n\n/**\n * VitePress path adapter (prefix_except_default semantics):\n * default locale has no URL prefix; other locales use `/{vitepressKey}/…`.\n * i18n locale values remain `locale.code` (via `localeKeyToCode`).\n */\nexport function createVitePressRouterAdapter(options: VitePressRouterAdapterOptions): VitePressRouterAdapter {\n const { locales, defaultLocale, localeKeyToCode = {}, getPath, go } = options\n const localeCodes = locales.map((loc) => loc.code)\n const localeKeyToCodeSnapshot = { ...localeKeyToCode }\n const prefixToCode = buildUrlPrefixToCode(localeCodes, defaultLocale, localeKeyToCodeSnapshot)\n const urlPrefixes = [...prefixToCode.keys()]\n\n const codeFromLocaleKey = (localeKey: string): string => {\n if (localeKeyToCodeSnapshot[localeKey]) return localeKeyToCodeSnapshot[localeKey]!\n if (localeKey === 'root') return defaultLocale\n return localeKey\n }\n\n const localeKeyFromCode = (code: string): string => {\n for (const [key, mapped] of Object.entries(localeKeyToCodeSnapshot)) {\n if (mapped === code) return key\n }\n if (code === defaultLocale) return 'root'\n return code\n }\n\n const urlPrefixForCode = (code: string): string | null => {\n if (code === defaultLocale) return null\n const key = localeKeyFromCode(code)\n return key === 'root' ? code : key\n }\n\n const stripPrefix = (pathname: string): { segments: string[], hadTrailingSlash: boolean } => {\n const hadTrailingSlash = pathname === '/' || pathname.endsWith('/')\n const segments = pathname.split('/').filter(Boolean)\n const first = segments[0]\n if (first !== undefined && prefixToCode.has(first)) {\n segments.shift()\n }\n return { segments, hadTrailingSlash }\n }\n\n const removeLocaleFromPath = (path: string): string => {\n const { pathname, extras } = splitPathAndExtras(path)\n const { segments, hadTrailingSlash } = stripPrefix(pathname)\n let clean = segments.length === 0 ? '/' : `/${segments.join('/')}`\n if (clean !== '/' && hadTrailingSlash) clean += '/'\n return `${clean}${extras}`\n }\n\n const localizePath = (path: string, locale: string): string => {\n const { pathname, extras } = splitPathAndExtras(path)\n const { segments, hadTrailingSlash } = stripPrefix(pathname)\n const prefix = urlPrefixForCode(locale)\n if (prefix) segments.unshift(prefix)\n let localized = segments.length === 0 ? '/' : `/${segments.join('/')}`\n if (localized !== '/' && hadTrailingSlash) localized += '/'\n return `${localized}${extras}`\n }\n\n const switchLocalePath = (path: string, newLocale: string): string => {\n return localizePath(path, newLocale)\n }\n\n const resolvePath = (to: string | { path?: string }, locale: string): string => {\n const path = typeof to === 'string' ? to : to.path || '/'\n return localizePath(path, locale)\n }\n\n const navigate = (href: string, replace = false) => {\n if (go) {\n void go(href, { replace })\n return\n }\n if (typeof window !== 'undefined') {\n if (replace) {\n window.location.replace(href)\n }\n else {\n window.location.assign(href)\n }\n }\n }\n\n return {\n localeCodes,\n defaultLocale,\n localeKeyToCode: localeKeyToCodeSnapshot,\n urlPrefixes,\n codeFromLocaleKey,\n localeKeyFromCode,\n getLocaleFromPath: (path: string) =>\n getLocaleFromPath(path, localeCodes, defaultLocale, localeKeyToCodeSnapshot),\n switchLocalePath,\n localizePath,\n removeLocaleFromPath,\n linkComponent: createVitePressLinkComponent(go),\n getCurrentPath: () => {\n if (getPath) return getPath()\n if (typeof window !== 'undefined') {\n return window.location.pathname + window.location.search + window.location.hash\n }\n return '/'\n },\n push: (target: { path: string }) => {\n navigate(target.path, false)\n },\n replace: (target: { path: string }) => {\n navigate(target.path, true)\n },\n resolvePath,\n getRoute: () => {\n const path = getPath\n ? getPath()\n : (typeof window !== 'undefined'\n ? window.location.pathname + window.location.search + window.location.hash\n : '/')\n const url = typeof window !== 'undefined'\n ? new URL(path, window.location.origin)\n : new URL(path, 'http://localhost')\n return {\n fullPath: url.pathname + url.search + url.hash,\n query: Object.fromEntries(url.searchParams),\n }\n },\n }\n}\n","import type { Locale, PluralFunc, Translations } from '@i18n-micro/types'\nimport { mergeRouteTranslationsWithRoot } from '@i18n-micro/utils/parse-path'\nimport { createI18n, type I18nPlugin } from '@i18n-micro/vue'\nimport type { App, Ref } from 'vue'\nimport {\n createVitePressRouterAdapter,\n routeNameFromPath,\n type VitePressRouterAdapter,\n type VitePressRouterLike,\n} from './router/adapter'\n\nexport interface VitePressI18nOptions {\n locale: string\n fallbackLocale?: string\n locales?: Locale[]\n defaultLocale?: string\n messages?: Record<string, Translations>\n /**\n * Page-scoped dictionaries keyed by route name (`guide-demo`), then locale.\n * Loaded from `locales/pages/**` when using `withI18nMicro`.\n */\n routeMessages?: Record<string, Record<string, Translations>>\n plural?: PluralFunc\n missingWarn?: boolean\n missingHandler?: (locale: string, key: string, routeName: string) => void\n /**\n * Sync i18n locale from the VitePress URL path on every navigation.\n * @default true\n */\n syncWithVitePress?: boolean\n /**\n * Map VitePress locale keys to i18n codes (`root` → default locale code).\n */\n localeKeyToCode?: Record<string, string>\n}\n\nexport interface VitePressSiteDataLike {\n locales?: Record<string, { lang?: string, link?: string, label?: string }>\n}\n\nexport interface CreateVitePressI18nResult {\n i18n: I18nPlugin['global']\n plugin: I18nPlugin\n adapter: VitePressRouterAdapter | null\n enhanceApp: (ctx: {\n app: App\n router: VitePressRouterLike\n siteData?: Ref<VitePressSiteDataLike> | VitePressSiteDataLike\n }) => void\n}\n\nfunction resolveDefaultLocale(options: VitePressI18nOptions): string {\n return options.defaultLocale || options.locale\n}\n\nfunction applyRouteMessages(\n plugin: I18nPlugin,\n root: Record<string, Translations> | undefined,\n routeMessages: Record<string, Record<string, Translations>> | undefined,\n): void {\n if (!routeMessages) return\n for (const [routeName, byLocale] of Object.entries(routeMessages)) {\n for (const [locale, translations] of Object.entries(byLocale)) {\n plugin.global.addRouteTranslations(\n locale,\n routeName,\n mergeRouteTranslationsWithRoot(root?.[locale], translations),\n false,\n )\n }\n }\n}\n\n/**\n * Create VitePress i18n runtime: Vue plugin + path sync + optional router adapter.\n */\nexport function createVitePressI18n(options: VitePressI18nOptions): CreateVitePressI18nResult {\n const defaultLocale = resolveDefaultLocale(options)\n const locales = options.locales ?? []\n const syncWithVitePress = options.syncWithVitePress !== false\n\n const plugin = createI18n({\n locale: options.locale,\n fallbackLocale: options.fallbackLocale ?? defaultLocale,\n messages: options.messages,\n plural: options.plural,\n missingWarn: options.missingWarn,\n missingHandler: options.missingHandler,\n locales,\n defaultLocale,\n })\n\n applyRouteMessages(plugin, options.messages, options.routeMessages)\n\n // Per Vue app (SSR / multiple VitePress apps sharing one createVitePressI18n result).\n const byApp = new WeakMap<object, {\n adapter: VitePressRouterAdapter\n boundSyncHandler: ((to: string) => unknown) | null\n chainedPrevious: ((to: string) => unknown) | undefined\n }>()\n let lastAdapter: VitePressRouterAdapter | null = null\n\n const enhanceApp = (ctx: {\n app: App\n router: VitePressRouterLike\n siteData?: Ref<VitePressSiteDataLike> | VitePressSiteDataLike\n }) => {\n const { app, router } = ctx\n\n let state = byApp.get(app)\n if (!state) {\n const adapter = createVitePressRouterAdapter({\n locales,\n defaultLocale,\n localeKeyToCode: options.localeKeyToCode,\n getPath: () => {\n const route = router.route\n return `${route.path}${route.query || ''}${route.hash || ''}`\n },\n go: (href, navOptions) => router.go(href, navOptions),\n })\n\n // Install first so `setRoutingStrategy` provides into this app (not a previous one).\n app.use(plugin)\n plugin.setRoutingStrategy(adapter)\n state = { adapter, boundSyncHandler: null, chainedPrevious: undefined }\n byApp.set(app, state)\n }\n // Re-enhance: do not call setRoutingStrategy — vue's setter targets last-installed\n // currentApp and would overwrite another app's router injection.\n lastAdapter = state.adapter\n\n if (!syncWithVitePress) return\n\n const { adapter } = state\n const sync = (path = router.route.path) => {\n const nextLocale = adapter.getLocaleFromPath(path)\n if (plugin.global.getLocale() !== nextLocale) {\n plugin.global.locale = nextLocale\n }\n plugin.global.setRoute(\n routeNameFromPath(path, adapter.localeCodes, defaultLocale, options.localeKeyToCode),\n )\n }\n\n sync()\n\n // Stay outermost: if base/user enhanceApp overwrote the hook, re-wrap on a later call.\n const current = router.onAfterRouteChange\n if (current !== state.boundSyncHandler) {\n state.chainedPrevious = typeof current === 'function' ? current : undefined\n }\n state.boundSyncHandler = async (to: string) => {\n if (typeof state.chainedPrevious === 'function') {\n await state.chainedPrevious(to)\n }\n const path = to.startsWith('http')\n ? (() => {\n const url = new URL(to)\n return url.pathname + url.search + url.hash\n })()\n : to\n sync(path)\n }\n router.onAfterRouteChange = state.boundSyncHandler\n }\n\n return {\n i18n: plugin.global,\n plugin,\n get adapter() {\n return lastAdapter\n },\n enhanceApp,\n }\n}\n","import type { PluralFunc, Translations } from '@i18n-micro/types'\nimport type { Theme } from 'vitepress'\nimport { createVitePressI18n, type CreateVitePressI18nResult } from './create'\nimport { getLocaleFromPath } from './router/adapter'\nimport type { VirtualI18nConfig } from './with-i18n-micro'\n\ntype EnhanceAppContext = Parameters<NonNullable<Theme['enhanceApp']>>[0]\n\nexport interface DefineI18nThemeOptions {\n /**\n * Extra `enhanceApp` run after i18n is installed.\n */\n enhanceApp?: NonNullable<Theme['enhanceApp']>\n /**\n * Overrides not serializable into `virtual:i18n-micro/config`.\n */\n plural?: PluralFunc\n missingHandler?: (locale: string, key: string, routeName: string) => void\n localeKeyToCode?: Record<string, string>\n}\n\ninterface VirtualMessagesModule {\n messages: Record<string, Translations>\n routeMessages?: Record<string, Record<string, Translations>>\n}\n\n/**\n * Zero-boilerplate theme wiring. Requires `withI18nMicro(...)` in `.vitepress/config`\n * so virtual config + messages modules exist.\n *\n * Virtual modules are loaded inside `enhanceApp` (not at package top-level) so\n * `@i18n-micro/vitepress` stays importable from Node when evaluating VitePress config.\n *\n * @example\n * ```ts\n * import DefaultTheme from 'vitepress/theme'\n * import { defineI18nTheme } from '@i18n-micro/vitepress'\n *\n * export default defineI18nTheme(DefaultTheme)\n * ```\n */\nexport function defineI18nTheme<T extends Theme>(base: T, options: DefineI18nThemeOptions = {}): T {\n const userEnhance = options.enhanceApp\n const baseEnhance = base.enhanceApp\n\n // Per app instance (SSR-safe: WeakMap by app).\n const byApp = new WeakMap<object, CreateVitePressI18nResult>()\n\n return {\n ...base,\n async enhanceApp(ctx: EnhanceAppContext) {\n let installed = byApp.get(ctx.app)\n if (!installed) {\n // Cast via `unknown`: root typecheck also sees Astro's ambient `virtual:i18n-micro/config`.\n const [{ config }, messagesMod] = await Promise.all([\n import('virtual:i18n-micro/config') as unknown as Promise<{ config: VirtualI18nConfig }>,\n import('virtual:i18n-micro/messages') as unknown as Promise<VirtualMessagesModule>,\n ])\n\n const localeCodes = config.localeCodes.length\n ? config.localeCodes\n : config.locales.map((l) => l.code)\n const localeKeyToCode = options.localeKeyToCode ?? config.localeKeyToCode\n const initialLocale = getLocaleFromPath(\n ctx.router.route.path,\n localeCodes,\n config.defaultLocale,\n localeKeyToCode,\n )\n\n installed = createVitePressI18n({\n locale: initialLocale,\n defaultLocale: config.defaultLocale,\n fallbackLocale: config.fallbackLocale,\n locales: config.locales,\n messages: messagesMod.messages,\n routeMessages: messagesMod.routeMessages,\n missingWarn: config.missingWarn,\n syncWithVitePress: config.syncWithVitePress,\n localeKeyToCode,\n plural: options.plural,\n missingHandler: options.missingHandler,\n })\n byApp.set(ctx.app, installed)\n }\n\n // Install plugin first so base/user enhanceApp can use $t / components.\n installed.enhanceApp(ctx as unknown as Parameters<typeof installed.enhanceApp>[0])\n if (baseEnhance) await baseEnhance(ctx)\n if (userEnhance) await userEnhance(ctx)\n // Re-run so route sync wraps any onAfterRouteChange set by base/user.\n installed.enhanceApp(ctx as unknown as Parameters<typeof installed.enhanceApp>[0])\n },\n }\n}\n","import type { Translations } from '@i18n-micro/types'\n\n/**\n * Vite `import.meta.glob(..., { eager: true })` modules look like\n * `{ default: { …json } }` or `{ default: { … }, __esModule: true }`.\n * Do not treat a real dictionary that only has a `default` string key as a namespace.\n */\nfunction isModuleNamespace(mod: object): mod is { default: Translations } {\n if (!('default' in mod)) return false\n const keys = Object.keys(mod)\n if (!keys.every((key) => key === 'default' || key === '__esModule')) return false\n const value = (mod as { default: unknown }).default\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\n/**\n * Tiny helper if you still prefer `import.meta.glob` instead of `defineI18nTheme`.\n * Only unwraps Vite module namespaces — dictionaries with a `default` key stay intact.\n */\nexport function messagesFromGlob(\n modules: Record<string, { default: Translations } | Translations>,\n): Record<string, Translations> {\n const messages: Record<string, Translations> = {}\n for (const [path, mod] of Object.entries(modules)) {\n const file = path.split('/').pop() || ''\n const code = file.replace(/\\.json$/, '')\n if (!code) continue\n if (mod && typeof mod === 'object' && isModuleNamespace(mod)) {\n messages[code] = mod.default\n }\n else {\n messages[code] = mod as Translations\n }\n }\n return messages\n}\n"],"names":["splitPathAndExtras","path","hashIndex","queryIndex","cut","buildUrlPrefixToCode","localeCodes","defaultLocale","localeKeyToCode","keyFromCode","code","key","mapped","prefixToCode","urlKey","getLocaleFromPath","pathname","first","routeNameFromPath","segments","createVitePressLinkComponent","go","defineComponent","props","slots","h","e","createVitePressRouterAdapter","options","locales","getPath","loc","localeKeyToCodeSnapshot","urlPrefixes","codeFromLocaleKey","localeKey","localeKeyFromCode","urlPrefixForCode","stripPrefix","hadTrailingSlash","removeLocaleFromPath","extras","clean","localizePath","locale","prefix","localized","switchLocalePath","newLocale","resolvePath","to","navigate","href","replace","target","url","resolveDefaultLocale","applyRouteMessages","plugin","root","routeMessages","routeName","byLocale","translations","mergeRouteTranslationsWithRoot","createVitePressI18n","syncWithVitePress","createI18n","byApp","lastAdapter","enhanceApp","ctx","app","router","state","adapter","route","navOptions","sync","nextLocale","current","defineI18nTheme","base","userEnhance","baseEnhance","installed","config","messagesMod","l","initialLocale","isModuleNamespace","mod","value","messagesFromGlob","modules","messages"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/runtime/messages-from-glob.ts"],"sourcesContent":["import type { Translations } from '@i18n-micro/types'\n\n/**\n * Vite `import.meta.glob(..., { eager: true })` modules look like\n * `{ default: { …json } }` or `{ default: { … }, __esModule: true }`.\n * Do not treat a real dictionary that only has a `default` string key as a namespace.\n */\nfunction isModuleNamespace(mod: object): mod is { default: Translations } {\n if (!('default' in mod)) return false\n const keys = Object.keys(mod)\n if (!keys.every((key) => key === 'default' || key === '__esModule')) return false\n const value = (mod as { default: unknown }).default\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\n/**\n * Tiny helper if you still prefer `import.meta.glob` instead of `defineI18nTheme`.\n * Only unwraps Vite module namespaces — dictionaries with a `default` key stay intact.\n */\nexport function messagesFromGlob(modules: Record<string, { default: Translations } | Translations>): Record<string, Translations> {\n const messages: Record<string, Translations> = {}\n for (const [path, mod] of Object.entries(modules)) {\n const file = path.split('/').pop() || ''\n const code = file.replace(/\\.json$/, '')\n if (!code) continue\n if (mod && typeof mod === 'object' && isModuleNamespace(mod)) {\n messages[code] = mod.default\n } else {\n messages[code] = mod as Translations\n }\n }\n return messages\n}\n"],"names":["isModuleNamespace","mod","key","value","messagesFromGlob","modules","messages","path","code"],"mappings":"wNAOA,SAASA,EAAkBC,EAA+C,CAGxE,GAFI,EAAE,YAAaA,IAEf,CADS,OAAO,KAAKA,CAAG,EAClB,MAAOC,GAAQA,IAAQ,WAAaA,IAAQ,YAAY,EAAG,MAAO,GAC5E,MAAMC,EAASF,EAA6B,QAC5C,OAAOE,IAAU,MAAQ,OAAOA,GAAU,UAAY,CAAC,MAAM,QAAQA,CAAK,CAC5E,CAMO,SAASC,EAAiBC,EAAiG,CAChI,MAAMC,EAAyC,CAAA,EAC/C,SAAW,CAACC,EAAMN,CAAG,IAAK,OAAO,QAAQI,CAAO,EAAG,CAEjD,MAAMG,GADOD,EAAK,MAAM,GAAG,EAAE,OAAS,IACpB,QAAQ,UAAW,EAAE,EAClCC,IACDP,GAAO,OAAOA,GAAQ,UAAYD,EAAkBC,CAAG,EACzDK,EAASE,CAAI,EAAIP,EAAI,QAErBK,EAASE,CAAI,EAAIP,EAErB,CACA,OAAOK,CACT"}
package/dist/index.d.cts CHANGED
@@ -1,7 +1,6 @@
1
1
  /// <reference types="@i18n-micro/vitepress/client" />
2
2
  import { App } from 'vue';
3
3
  import { CleanTranslation } from '@i18n-micro/types';
4
- import { createI18n } from '@i18n-micro/vue';
5
4
  import { defaultPlural } from '@i18n-micro/core';
6
5
  import { FormatService } from '@i18n-micro/core';
7
6
  import { Getter } from '@i18n-micro/types';
@@ -18,7 +17,6 @@ import { Params } from '@i18n-micro/types';
18
17
  import { Plugin as Plugin_2 } from 'vite';
19
18
  import { PluralFunc } from '@i18n-micro/types';
20
19
  import { Ref } from 'vue';
21
- import { Theme } from 'vitepress';
22
20
  import { Translations } from '@i18n-micro/types';
23
21
  import { useI18n } from '@i18n-micro/vue';
24
22
  import { UseI18nOptions } from '@i18n-micro/vue';
@@ -26,82 +24,62 @@ import { VueI18nOptions } from '@i18n-micro/vue';
26
24
 
27
25
  export { CleanTranslation }
28
26
 
29
- export { createI18n }
30
-
31
27
  /**
32
- * Bridge so VitePress navbar language menu and `<I18nSwitcher>` share path logic.
33
- * Pass the result to `themeConfig.i18nRouting`.
34
- *
35
- * `targetLocale` is a **VitePress locale key** (`root` / `fr`). URL prefixes use that key;
36
- * `localeKeyToCode` is only for resolving the i18n code when callers need it elsewhere.
37
- *
38
- * Returns a **self-contained** function (no closures) so VitePress can serialize it
39
- * into site data via `Function#toString()` + `new Function`.
28
+ * Universal VitePress i18n: Vue plugin + path helpers + `enhanceApp` sync.
29
+ * Path methods are the router adapter’s own functions (no wrapper layer).
40
30
  */
41
- export declare function createI18nRoutingFromAdapter(adapterOrOptions: VitePressRouterAdapter | I18nRoutingFromAdapterOptions): VitePressI18nRoutingFn;
31
+ export declare function createI18n(options: CreateI18nOptions): CreateI18nResult;
42
32
 
43
- /**
44
- * Create VitePress i18n runtime: Vue plugin + path sync + optional router adapter.
45
- */
46
- export declare function createVitePressI18n(options: VitePressI18nOptions): CreateVitePressI18nResult;
33
+ export declare interface CreateI18nOptions {
34
+ locale: string;
35
+ fallbackLocale?: string;
36
+ locales?: Locale[];
37
+ defaultLocale?: string;
38
+ messages?: Record<string, Translations>;
39
+ /**
40
+ * Page-scoped dictionaries keyed by route name (`guide-demo`), then locale.
41
+ * Loaded from `locales/pages/**` when using `withI18n`.
42
+ */
43
+ routeMessages?: Record<string, Record<string, Translations>>;
44
+ plural?: PluralFunc;
45
+ missingWarn?: boolean;
46
+ missingHandler?: (locale: string, key: string, routeName: string) => void;
47
+ /**
48
+ * Sync i18n locale from the VitePress URL path on every navigation.
49
+ * @default true
50
+ */
51
+ syncWithVitePress?: boolean;
52
+ /**
53
+ * Map VitePress locale keys to i18n codes (`root` → default locale code).
54
+ */
55
+ localeKeyToCode?: Record<string, string>;
56
+ /**
57
+ * VitePress `site.base`. Needed so SSG paths (`withBase`) and lang switcher
58
+ * do not treat the base segment as content / double-prefix links.
59
+ */
60
+ base?: string;
61
+ }
47
62
 
48
- export declare interface CreateVitePressI18nResult {
49
- i18n: I18nPlugin['global'];
50
- plugin: I18nPlugin;
51
- adapter: VitePressRouterAdapter | null;
63
+ export declare type CreateI18nResult = I18nPlugin & PathMethods & {
64
+ /** Same as `.global` (VueI18n + path methods). */
65
+ i18n: I18nPlugin['global'] & PathMethods;
52
66
  enhanceApp: (ctx: {
53
67
  app: App;
54
68
  router: VitePressRouterLike;
55
69
  siteData?: Ref<VitePressSiteDataLike> | VitePressSiteDataLike;
56
70
  }) => void;
57
- }
58
-
59
- /**
60
- * VitePress path adapter (prefix_except_default semantics):
61
- * default locale has no URL prefix; other locales use `/{vitepressKey}/…`.
62
- * i18n locale values remain `locale.code` (via `localeKeyToCode`).
63
- */
64
- export declare function createVitePressRouterAdapter(options: VitePressRouterAdapterOptions): VitePressRouterAdapter;
71
+ };
65
72
 
66
73
  export { defaultPlural }
67
74
 
68
- /**
69
- * Zero-boilerplate theme wiring. Requires `withI18nMicro(...)` in `.vitepress/config`
70
- * so virtual config + messages modules exist.
71
- *
72
- * Virtual modules are loaded inside `enhanceApp` (not at package top-level) so
73
- * `@i18n-micro/vitepress` stays importable from Node when evaluating VitePress config.
74
- *
75
- * @example
76
- * ```ts
77
- * import DefaultTheme from 'vitepress/theme'
78
- * import { defineI18nTheme } from '@i18n-micro/vitepress'
79
- *
80
- * export default defineI18nTheme(DefaultTheme)
81
- * ```
82
- */
83
- export declare function defineI18nTheme<T extends Theme>(base: T, options?: DefineI18nThemeOptions): T;
84
-
85
- export declare interface DefineI18nThemeOptions {
86
- /**
87
- * Extra `enhanceApp` run after i18n is installed.
88
- */
89
- enhanceApp?: NonNullable<Theme['enhanceApp']>;
90
- /**
91
- * Overrides not serializable into `virtual:i18n-micro/config`.
92
- */
93
- plural?: PluralFunc;
94
- missingHandler?: (locale: string, key: string, routeName: string) => void;
95
- localeKeyToCode?: Record<string, string>;
96
- }
97
-
98
75
  export { FormatService }
99
76
 
100
77
  /**
101
78
  * Detect i18n locale code from a URL path (prefix_except_default).
102
79
  * Path prefixes are VitePress locale keys; return value is the i18n code.
80
+ * Pass `base` when the path may include VitePress `site.base` (SSG).
103
81
  */
104
- export declare function getLocaleFromPath(path: string, localeCodes: string[], defaultLocale: string, localeKeyToCode?: Record<string, string>): string;
82
+ export declare function getLocaleFromPath(path: string, localeCodes: string[], defaultLocale: string, localeKeyToCode?: Record<string, string>, base?: string): string;
105
83
 
106
84
  export { Getter }
107
85
 
@@ -111,12 +89,6 @@ export { I18nLink }
111
89
 
112
90
  export { I18nPlugin }
113
91
 
114
- export declare interface I18nRoutingFromAdapterOptions {
115
- defaultLocale: string;
116
- localeCodes: string[];
117
- localeKeyToCode?: Record<string, string>;
118
- }
119
-
120
92
  export { I18nRoutingStrategy }
121
93
 
122
94
  export { I18nSwitcher }
@@ -139,6 +111,9 @@ export declare function messagesFromGlob(modules: Record<string, {
139
111
 
140
112
  export { Params }
141
113
 
114
+ /** Path helpers exposed on `createI18n` instances (slice of the router adapter). */
115
+ export declare type PathMethods = Pick<VitePressRouterAdapter, 'localizePath' | 'switchLocalePath' | 'getLocaleFromPath' | 'removeLocaleFromPath' | 'routeNameFromPath'>;
116
+
142
117
  export { PluralFunc }
143
118
 
144
119
  /**
@@ -148,7 +123,13 @@ export { PluralFunc }
148
123
  * When `defaultLocale` is omitted (legacy 2-arg call), any segment that matches a
149
124
  * listed locale code is stripped — callers must not rely on `localeCodes[0]` as default.
150
125
  */
151
- export declare function routeNameFromPath(path: string, localeCodes: string[], defaultLocale?: string, localeKeyToCode?: Record<string, string>): string;
126
+ export declare function routeNameFromPath(path: string, localeCodes: string[], defaultLocale?: string, localeKeyToCode?: Record<string, string>, base?: string): string;
127
+
128
+ /**
129
+ * Strip VitePress `site.base` from a path. Leaves query/hash intact.
130
+ * No-op when `base` is missing or `/`.
131
+ */
132
+ export declare function stripSiteBase(path: string, base?: string): string;
152
133
 
153
134
  export { Translations }
154
135
 
@@ -166,71 +147,17 @@ export declare interface VirtualI18nConfig {
166
147
  translationDir: string;
167
148
  disablePageLocales: boolean;
168
149
  localeKeyToCode: Record<string, string>;
150
+ /** VitePress `site.base` (normalized, trailing slash preserved from config). */
151
+ base?: string;
169
152
  }
170
153
 
171
- export declare type VitePressGo = (href: string, options?: {
172
- replace?: boolean;
173
- }) => void | Promise<void>;
174
-
175
- export declare interface VitePressI18nOptions {
176
- locale: string;
177
- fallbackLocale?: string;
178
- locales?: Locale[];
179
- defaultLocale?: string;
180
- messages?: Record<string, Translations>;
181
- /**
182
- * Page-scoped dictionaries keyed by route name (`guide-demo`), then locale.
183
- * Loaded from `locales/pages/**` when using `withI18nMicro`.
184
- */
185
- routeMessages?: Record<string, Record<string, Translations>>;
186
- plural?: PluralFunc;
187
- missingWarn?: boolean;
188
- missingHandler?: (locale: string, key: string, routeName: string) => void;
189
- /**
190
- * Sync i18n locale from the VitePress URL path on every navigation.
191
- * @default true
192
- */
193
- syncWithVitePress?: boolean;
194
- /**
195
- * Map VitePress locale keys to i18n codes (`root` → default locale code).
196
- */
197
- localeKeyToCode?: Record<string, string>;
198
- }
199
-
200
- /**
201
- * Minimal shapes used by VitePress `themeConfig.i18nRouting`.
202
- * Kept loose so we do not hard-depend on VitePress internal DefaultTheme types at compile time.
203
- */
204
- export declare interface VitePressI18nRoutingData {
205
- site?: {
206
- value?: {
207
- locales?: Record<string, {
208
- link?: string;
209
- lang?: string;
210
- }>;
211
- };
212
- };
213
- localeIndex?: {
214
- value?: string;
215
- };
216
- }
217
-
218
- export declare type VitePressI18nRoutingFn = (data: VitePressI18nRoutingData, route: VitePressI18nRoutingRoute, targetLocale: string) => string;
219
-
220
- export declare interface VitePressI18nRoutingRoute {
221
- path: string;
222
- hash?: string;
223
- query?: string;
224
- data?: {
225
- relativePath?: string;
226
- };
227
- }
228
-
229
- export declare interface VitePressRouterAdapter extends I18nRoutingStrategy {
154
+ declare interface VitePressRouterAdapter extends I18nRoutingStrategy {
230
155
  getLocaleFromPath: (path: string) => string;
231
156
  switchLocalePath: (path: string, newLocale: string) => string;
232
157
  localizePath: (path: string, locale: string) => string;
233
158
  removeLocaleFromPath: (path: string) => string;
159
+ /** Page dictionary route name (`/fr/guide/demo` → `guide-demo`). */
160
+ routeNameFromPath: (path: string) => string;
234
161
  /** Resolve VitePress locale key (`root` / `fr`) to i18n code. */
235
162
  codeFromLocaleKey: (localeKey: string) => string;
236
163
  /** Resolve i18n code to VitePress locale key. */
@@ -241,22 +168,11 @@ export declare interface VitePressRouterAdapter extends I18nRoutingStrategy {
241
168
  localeKeyToCode: Record<string, string>;
242
169
  /** URL path prefixes (VitePress locale keys except `root`). */
243
170
  urlPrefixes: string[];
171
+ /** VitePress `site.base` used when constructing this adapter (may be undefined). */
172
+ base?: string;
244
173
  }
245
174
 
246
- export declare interface VitePressRouterAdapterOptions {
247
- locales: Locale[];
248
- defaultLocale: string;
249
- /**
250
- * Map VitePress locale keys (`root`, `fr`) to i18n locale codes.
251
- * Defaults: `root` → `defaultLocale`, other keys → same string as the key.
252
- * URL prefixes always use VitePress keys; i18n uses codes.
253
- */
254
- localeKeyToCode?: Record<string, string>;
255
- getPath?: () => string;
256
- go?: VitePressGo;
257
- }
258
-
259
- export declare interface VitePressRouterLike {
175
+ declare interface VitePressRouterLike {
260
176
  route: {
261
177
  path: string;
262
178
  hash?: string;
@@ -282,9 +198,17 @@ export declare interface VitePressSiteDataLike {
282
198
  * Avoid importing `vitepress` types so the package stays usable as a pure library dep.
283
199
  */
284
200
  export declare interface VitePressUserConfigLike {
201
+ base?: string;
285
202
  locales?: Record<string, unknown>;
203
+ themeConfig?: Record<string, unknown> | null;
204
+ transformHead?: (...args: any[]) => any;
205
+ transformPageData?: (...args: any[]) => any;
286
206
  vite?: {
287
207
  plugins?: Plugin_2[] | Plugin_2[][];
208
+ ssr?: {
209
+ noExternal?: string | true | Array<string | RegExp>;
210
+ [key: string]: unknown;
211
+ };
288
212
  [key: string]: unknown;
289
213
  };
290
214
  [key: string]: unknown;
@@ -292,7 +216,7 @@ export declare interface VitePressUserConfigLike {
292
216
 
293
217
  export { VueI18nOptions }
294
218
 
295
- export declare interface WithI18nMicroOptions extends VitePressI18nOptions {
219
+ export declare interface WithI18nOptions extends CreateI18nOptions {
296
220
  /**
297
221
  * Directory with locale JSON (`en.json`, `pages/guide/demo/en.json`, …), relative to Vite root
298
222
  * (VitePress content / docs root). Used by `virtual:i18n-micro/messages`.
@@ -310,6 +234,28 @@ export declare interface WithI18nMicroOptions extends VitePressI18nOptions {
310
234
  * @default true
311
235
  */
312
236
  warnOnLocaleMismatch?: boolean;
237
+ /**
238
+ * Inject `themeConfig.i18nRouting` from adapter options + `config.base`.
239
+ * Set `false` to skip. Skipped automatically when `themeConfig.i18nRouting` is already set.
240
+ * @default true
241
+ */
242
+ i18nRouting?: boolean;
243
+ /**
244
+ * Emit i18n SEO tags via `transformHead` (canonical, hreflang, og:locale…) —
245
+ * Nuxt `meta` / plugin `02.meta` analogue.
246
+ * Absolute link tags require `metaBaseUrl`.
247
+ * @default true when `metaBaseUrl` is set, otherwise false
248
+ */
249
+ meta?: boolean;
250
+ /**
251
+ * Public origin without trailing slash (`https://example.com`).
252
+ * Same role as Nuxt `metaBaseUrl`.
253
+ */
254
+ metaBaseUrl?: string;
255
+ /** Also emit bare-language hreflang from `iso` (Nuxt `hreflangBaseLanguage`). @default false */
256
+ hreflangBaseLanguage?: boolean;
257
+ /** Query keys kept on canonical / alternate URLs. @default [] */
258
+ canonicalQueryWhitelist?: string[];
313
259
  }
314
260
 
315
261
  export { }