@i18n-micro/vitepress 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,140 @@
1
+ import { Locale } from '@i18n-micro/types';
2
+ import { Plugin as Plugin_2 } from 'vite';
3
+ import { PluralFunc } from '@i18n-micro/types';
4
+ import { TranslationFileBuckets } from '@i18n-micro/utils/parse-path';
5
+ import { Translations } from '@i18n-micro/types';
6
+
7
+ /**
8
+ * Apply page dictionaries onto an i18n instance (merged with root).
9
+ */
10
+ export declare function applyLoadedTranslations(i18n: {
11
+ addTranslations: (locale: string, translations: Translations, merge?: boolean) => void;
12
+ addRouteTranslations: (locale: string, routeName: string, translations: Translations, merge?: boolean) => void;
13
+ }, loaded: LoadedTranslations): void;
14
+
15
+ /**
16
+ * List JSON translation files under `translationDir` (absolute + relative paths).
17
+ */
18
+ export declare function listTranslationFiles(options: LoadMessagesOptions): TranslationFileRef[];
19
+
20
+ export declare type LoadedTranslations = TranslationFileBuckets<Translations>;
21
+
22
+ /**
23
+ * Load root-level locale JSON only (`en.json`, `fr.json`, …).
24
+ * Prefer `loadTranslationBuckets` when page locales are needed.
25
+ *
26
+ * Node.js-only (`node:fs`). For bundler-friendly loading prefer
27
+ * `withI18nMicro` virtual modules or `messagesFromGlob` in the theme.
28
+ */
29
+ export declare function loadMessages(options: LoadMessagesOptions): Record<string, Translations>;
30
+
31
+ export declare interface LoadMessagesOptions {
32
+ /** Directory with locale JSON (`en.json`, `pages/guide/demo/en.json`, …). */
33
+ translationDir: string;
34
+ rootDir?: string;
35
+ /**
36
+ * When true, treat `pages/**` files as root-level dictionaries.
37
+ * @default false
38
+ */
39
+ disablePageLocales?: boolean;
40
+ }
41
+
42
+ /**
43
+ * Load root + page-scoped dictionaries (`pages/** /xx.json`).
44
+ * Node.js-only (`node:fs`).
45
+ */
46
+ export declare function loadTranslationBuckets(options: LoadMessagesOptions): LoadedTranslations;
47
+
48
+ export declare interface TranslationFileRef {
49
+ /** Path relative to `translationDir` using `/` separators. */
50
+ relativePath: string;
51
+ absolutePath: string;
52
+ }
53
+
54
+ export declare interface VirtualI18nConfig {
55
+ defaultLocale: string;
56
+ fallbackLocale: string;
57
+ locales: Locale[];
58
+ localeCodes: string[];
59
+ missingWarn: boolean;
60
+ syncWithVitePress: boolean;
61
+ translationDir: string;
62
+ disablePageLocales: boolean;
63
+ localeKeyToCode: Record<string, string>;
64
+ }
65
+
66
+ declare interface VitePressI18nOptions {
67
+ locale: string;
68
+ fallbackLocale?: string;
69
+ locales?: Locale[];
70
+ defaultLocale?: string;
71
+ messages?: Record<string, Translations>;
72
+ /**
73
+ * Page-scoped dictionaries keyed by route name (`guide-demo`), then locale.
74
+ * Loaded from `locales/pages/**` when using `withI18nMicro`.
75
+ */
76
+ routeMessages?: Record<string, Record<string, Translations>>;
77
+ plural?: PluralFunc;
78
+ missingWarn?: boolean;
79
+ missingHandler?: (locale: string, key: string, routeName: string) => void;
80
+ /**
81
+ * Sync i18n locale from the VitePress URL path on every navigation.
82
+ * @default true
83
+ */
84
+ syncWithVitePress?: boolean;
85
+ /**
86
+ * Map VitePress locale keys to i18n codes (`root` → default locale code).
87
+ */
88
+ localeKeyToCode?: Record<string, string>;
89
+ }
90
+
91
+ /**
92
+ * Minimal VitePress / Vite user config shape we merge into.
93
+ * Avoid importing `vitepress` types so the package stays usable as a pure library dep.
94
+ */
95
+ export declare interface VitePressUserConfigLike {
96
+ locales?: Record<string, unknown>;
97
+ vite?: {
98
+ plugins?: Plugin_2[] | Plugin_2[][];
99
+ [key: string]: unknown;
100
+ };
101
+ [key: string]: unknown;
102
+ }
103
+
104
+ export declare function warnLocaleMismatch(config: VitePressUserConfigLike, options: WithI18nMicroOptions): void;
105
+
106
+ /**
107
+ * Config helper (like `withMermaid`). Name is `withI18nMicro` on purpose —
108
+ * `withI18n` is already used by the unrelated `vitepress-i18n` package.
109
+ *
110
+ * Registers virtual modules:
111
+ * - `virtual:i18n-micro/config`
112
+ * - `virtual:i18n-micro/messages` (from `translationDir`, default `locales/`)
113
+ *
114
+ * Pair with `defineI18nTheme(DefaultTheme)` — no manual `import.meta.glob` in the theme.
115
+ *
116
+ * Import from `@i18n-micro/vitepress/config` (Node / config files only).
117
+ */
118
+ export declare function withI18nMicro<T extends VitePressUserConfigLike>(config: T, options: WithI18nMicroOptions): T;
119
+
120
+ export declare interface WithI18nMicroOptions extends VitePressI18nOptions {
121
+ /**
122
+ * Directory with locale JSON (`en.json`, `pages/guide/demo/en.json`, …), relative to Vite root
123
+ * (VitePress content / docs root). Used by `virtual:i18n-micro/messages`.
124
+ * @default 'locales'
125
+ */
126
+ translationDir?: string;
127
+ /**
128
+ * When true, treat `pages/**` as root-level dictionaries.
129
+ * @default false
130
+ */
131
+ disablePageLocales?: boolean;
132
+ /**
133
+ * When true, logs a warning if VitePress `locales` keys do not align with
134
+ * configured i18n locale codes.
135
+ * @default true
136
+ */
137
+ warnOnLocaleMismatch?: boolean;
138
+ }
139
+
140
+ export { }
package/dist/node.d.ts ADDED
@@ -0,0 +1,140 @@
1
+ import { Locale } from '@i18n-micro/types';
2
+ import { Plugin as Plugin_2 } from 'vite';
3
+ import { PluralFunc } from '@i18n-micro/types';
4
+ import { TranslationFileBuckets } from '@i18n-micro/utils/parse-path';
5
+ import { Translations } from '@i18n-micro/types';
6
+
7
+ /**
8
+ * Apply page dictionaries onto an i18n instance (merged with root).
9
+ */
10
+ export declare function applyLoadedTranslations(i18n: {
11
+ addTranslations: (locale: string, translations: Translations, merge?: boolean) => void;
12
+ addRouteTranslations: (locale: string, routeName: string, translations: Translations, merge?: boolean) => void;
13
+ }, loaded: LoadedTranslations): void;
14
+
15
+ /**
16
+ * List JSON translation files under `translationDir` (absolute + relative paths).
17
+ */
18
+ export declare function listTranslationFiles(options: LoadMessagesOptions): TranslationFileRef[];
19
+
20
+ export declare type LoadedTranslations = TranslationFileBuckets<Translations>;
21
+
22
+ /**
23
+ * Load root-level locale JSON only (`en.json`, `fr.json`, …).
24
+ * Prefer `loadTranslationBuckets` when page locales are needed.
25
+ *
26
+ * Node.js-only (`node:fs`). For bundler-friendly loading prefer
27
+ * `withI18nMicro` virtual modules or `messagesFromGlob` in the theme.
28
+ */
29
+ export declare function loadMessages(options: LoadMessagesOptions): Record<string, Translations>;
30
+
31
+ export declare interface LoadMessagesOptions {
32
+ /** Directory with locale JSON (`en.json`, `pages/guide/demo/en.json`, …). */
33
+ translationDir: string;
34
+ rootDir?: string;
35
+ /**
36
+ * When true, treat `pages/**` files as root-level dictionaries.
37
+ * @default false
38
+ */
39
+ disablePageLocales?: boolean;
40
+ }
41
+
42
+ /**
43
+ * Load root + page-scoped dictionaries (`pages/** /xx.json`).
44
+ * Node.js-only (`node:fs`).
45
+ */
46
+ export declare function loadTranslationBuckets(options: LoadMessagesOptions): LoadedTranslations;
47
+
48
+ export declare interface TranslationFileRef {
49
+ /** Path relative to `translationDir` using `/` separators. */
50
+ relativePath: string;
51
+ absolutePath: string;
52
+ }
53
+
54
+ export declare interface VirtualI18nConfig {
55
+ defaultLocale: string;
56
+ fallbackLocale: string;
57
+ locales: Locale[];
58
+ localeCodes: string[];
59
+ missingWarn: boolean;
60
+ syncWithVitePress: boolean;
61
+ translationDir: string;
62
+ disablePageLocales: boolean;
63
+ localeKeyToCode: Record<string, string>;
64
+ }
65
+
66
+ declare interface VitePressI18nOptions {
67
+ locale: string;
68
+ fallbackLocale?: string;
69
+ locales?: Locale[];
70
+ defaultLocale?: string;
71
+ messages?: Record<string, Translations>;
72
+ /**
73
+ * Page-scoped dictionaries keyed by route name (`guide-demo`), then locale.
74
+ * Loaded from `locales/pages/**` when using `withI18nMicro`.
75
+ */
76
+ routeMessages?: Record<string, Record<string, Translations>>;
77
+ plural?: PluralFunc;
78
+ missingWarn?: boolean;
79
+ missingHandler?: (locale: string, key: string, routeName: string) => void;
80
+ /**
81
+ * Sync i18n locale from the VitePress URL path on every navigation.
82
+ * @default true
83
+ */
84
+ syncWithVitePress?: boolean;
85
+ /**
86
+ * Map VitePress locale keys to i18n codes (`root` → default locale code).
87
+ */
88
+ localeKeyToCode?: Record<string, string>;
89
+ }
90
+
91
+ /**
92
+ * Minimal VitePress / Vite user config shape we merge into.
93
+ * Avoid importing `vitepress` types so the package stays usable as a pure library dep.
94
+ */
95
+ export declare interface VitePressUserConfigLike {
96
+ locales?: Record<string, unknown>;
97
+ vite?: {
98
+ plugins?: Plugin_2[] | Plugin_2[][];
99
+ [key: string]: unknown;
100
+ };
101
+ [key: string]: unknown;
102
+ }
103
+
104
+ export declare function warnLocaleMismatch(config: VitePressUserConfigLike, options: WithI18nMicroOptions): void;
105
+
106
+ /**
107
+ * Config helper (like `withMermaid`). Name is `withI18nMicro` on purpose —
108
+ * `withI18n` is already used by the unrelated `vitepress-i18n` package.
109
+ *
110
+ * Registers virtual modules:
111
+ * - `virtual:i18n-micro/config`
112
+ * - `virtual:i18n-micro/messages` (from `translationDir`, default `locales/`)
113
+ *
114
+ * Pair with `defineI18nTheme(DefaultTheme)` — no manual `import.meta.glob` in the theme.
115
+ *
116
+ * Import from `@i18n-micro/vitepress/config` (Node / config files only).
117
+ */
118
+ export declare function withI18nMicro<T extends VitePressUserConfigLike>(config: T, options: WithI18nMicroOptions): T;
119
+
120
+ export declare interface WithI18nMicroOptions extends VitePressI18nOptions {
121
+ /**
122
+ * Directory with locale JSON (`en.json`, `pages/guide/demo/en.json`, …), relative to Vite root
123
+ * (VitePress content / docs root). Used by `virtual:i18n-micro/messages`.
124
+ * @default 'locales'
125
+ */
126
+ translationDir?: string;
127
+ /**
128
+ * When true, treat `pages/**` as root-level dictionaries.
129
+ * @default false
130
+ */
131
+ disablePageLocales?: boolean;
132
+ /**
133
+ * When true, logs a warning if VitePress `locales` keys do not align with
134
+ * configured i18n locale codes.
135
+ * @default true
136
+ */
137
+ warnOnLocaleMismatch?: boolean;
138
+ }
139
+
140
+ export { }
package/dist/node.mjs ADDED
@@ -0,0 +1,10 @@
1
+ import { a as l, l as o, b as i, c as n, w as t, d as e } from "./with-i18n-micro-DIAoqY71.js";
2
+ export {
3
+ l as applyLoadedTranslations,
4
+ o as listTranslationFiles,
5
+ i as loadMessages,
6
+ n as loadTranslationBuckets,
7
+ t as warnLocaleMismatch,
8
+ e as withI18nMicro
9
+ };
10
+ //# sourceMappingURL=node.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -0,0 +1,13 @@
1
+ import { Locale } from '@i18n-micro/types';
2
+ /** Typecheck stub — real module is provided by `withI18nMicro` Vite plugin. */
3
+ export declare const config: {
4
+ defaultLocale: string;
5
+ fallbackLocale: string;
6
+ locales: Locale[];
7
+ localeCodes: string[];
8
+ missingWarn: boolean;
9
+ syncWithVitePress: boolean;
10
+ translationDir: string;
11
+ disablePageLocales: boolean;
12
+ localeKeyToCode: Record<string, string>;
13
+ };
@@ -0,0 +1,15 @@
1
+ "use strict";const h=require("node:fs"),m=require("node:path"),S=require("@i18n-micro/utils/parse-path"),D=require("@i18n-micro/utils/deep-merge");function N(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function L(e,t){if(h.existsSync(e))for(const r of h.readdirSync(e)){const s=m.join(e,r);if(h.statSync(s).isDirectory()){L(s,t);continue}r.endsWith(".json")&&t(s)}}function $(e){const t=e.rootDir??process.cwd(),r=m.resolve(t,e.translationDir),s=[];return L(r,i=>{s.push({absolutePath:i,relativePath:m.relative(r,i).split(m.sep).join("/")})}),s.sort((i,c)=>i.relativePath.localeCompare(c.relativePath))}function v(e){const t=e.rootDir??process.cwd(),r=m.resolve(t,e.translationDir),s={root:{},routes:{}},i=e.disablePageLocales===!0;return h.existsSync(r)&&L(r,c=>{const a=m.relative(r,c).split(m.sep).join("/");try{const l=JSON.parse(h.readFileSync(c,"utf-8"));if(!N(l)){console.error(`[i18n-micro/vitepress] Skipping ${a}: expected a JSON object, got ${Array.isArray(l)?"array":typeof l}`);return}const f=l,u=S.classifyTranslationRelativePath(a,i);if(u.type==="page"){const n=s.routes[u.pageName]??(s.routes[u.pageName]={});n[u.locale]=f;return}if(u.type==="root"){const n=s.root[u.locale];s.root[u.locale]=n?D.deepMergeTranslations(n,f):f}}catch(l){console.error(`[i18n-micro/vitepress] Failed to load ${a}:`,l)}}),s}function O(e){return v(e).root}function P(e,t){for(const[r,s]of Object.entries(t.root))e.addTranslations(r,s,!1);for(const[r,s]of Object.entries(t.routes))for(const[i,c]of Object.entries(s))e.addRouteTranslations(i,r,S.mergeRouteTranslationsWithRoot(t.root[i],c),!1)}const b="virtual:i18n-micro/config",T=`\0${b}`,j="virtual:i18n-micro/messages",p=`\0${j}`;function I(e){return e.replace(/\\/g,"/")}function x(e,t,r){const s=$({rootDir:e,translationDir:t});if(s.length===0)return`export const messages = {}
2
+ export const routeMessages = {}
3
+ `;const i=[],c=[],a=new Map;let l=0;for(const u of s){const n=S.classifyTranslationRelativePath(u.relativePath,r);if(n.type==="ignore")continue;const d=`__i18n_${l++}`;if(i.push(`import ${d} from ${JSON.stringify(I(u.absolutePath))}`),n.type==="root"){c.push(` ${JSON.stringify(n.locale)}: ${d}`);continue}let o=a.get(n.pageName);o||(o=new Map,a.set(n.pageName,o)),o.set(n.locale,d)}const f=[];for(const[u,n]of a){const d=[...n.entries()].map(([o,y])=>` ${JSON.stringify(o)}: ${y}`).join(`,
4
+ `);f.push(` ${JSON.stringify(u)}: {
5
+ ${d}
6
+ }`)}return[...i,`export const messages = {
7
+ ${c.join(`,
8
+ `)}
9
+ }`,`export const routeMessages = {
10
+ ${f.join(`,
11
+ `)}
12
+ }`,""].join(`
13
+ `)}function k(e,t){return[`export const messages = ${JSON.stringify(e)}`,`export const routeMessages = ${JSON.stringify(t)}`,""].join(`
14
+ `)}function R(e){const t=e.defaultLocale||e.locale,r=e.translationDir??"locales",s=e.disablePageLocales===!0,i={defaultLocale:t,fallbackLocale:e.fallbackLocale||t,locales:e.locales||[],localeCodes:(e.locales||[]).map(o=>o.code),missingWarn:e.missingWarn??!0,syncWithVitePress:e.syncWithVitePress!==!1,translationDir:r,disablePageLocales:s,localeKeyToCode:e.localeKeyToCode??{}};let c=process.cwd(),a=!!(e.messages||e.routeMessages),l=e.messages??{},f=e.routeMessages??{},u;const n=()=>!e.messages||!e.routeMessages,d=()=>{if(!n())return;const o=v({rootDir:c,translationDir:r,disablePageLocales:s});e.messages||(l=o.root),e.routeMessages||(f=o.routes)};return{name:"vite-plugin-i18n-micro-vitepress",configResolved(o){c=o.root,a=!!(e.messages||e.routeMessages),a&&(e.messages&&(l=e.messages),e.routeMessages&&(f=e.routeMessages),n()&&d(),e.messages&&(l=e.messages),e.routeMessages&&(f=e.routeMessages))},configureServer(o){if(a&&!n())return;const y=m.resolve(c,r);if(!h.existsSync(y))return;o.watcher.add(y);const M=()=>{u&&clearTimeout(u),u=setTimeout(()=>{a&&d();const g=o.moduleGraph.getModuleById(p);g&&(o.moduleGraph.invalidateModule(g),o.ws.send({type:"full-reload"}))},50)};o.watcher.on("add",g=>{g.startsWith(y)&&g.endsWith(".json")&&M()}),o.watcher.on("unlink",g=>{g.startsWith(y)&&g.endsWith(".json")&&M()}),a&&n()&&o.watcher.on("change",g=>{g.startsWith(y)&&g.endsWith(".json")&&M()})},resolveId(o){if(o===b)return T;if(o===j)return p},load(o){if(o===T)return`export const config = ${JSON.stringify(i)}`;if(o===p)return a?k(l,f):x(c,r,s)}}}function w(e,t){if(t.warnOnLocaleMismatch===!1)return;const r=e.locales;if(!r||!t.locales?.length)return;const s=t.defaultLocale||t.locale,i=Object.keys(r),c=new Set(t.locales.map(a=>a.code));for(const a of i){const l=a==="root"?s:t.localeKeyToCode?.[a]??a;c.has(l)||console.warn(`[i18n-micro/vitepress] VitePress locale key "${a}" maps to "${l}", which is not in i18n locales (${[...c].join(", ")}).`)}}function _(e,t){w(e,t);const r=e.vite?.plugins,s=[...Array.isArray(r)?r.flat():[],R(t)];return{...e,vite:{...e.vite,plugins:s}}}exports.applyLoadedTranslations=P;exports.listTranslationFiles=$;exports.loadMessages=O;exports.loadTranslationBuckets=v;exports.warnLocaleMismatch=w;exports.withI18nMicro=_;
15
+ //# sourceMappingURL=with-i18n-micro-01q-vPO9.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-i18n-micro-01q-vPO9.cjs","sources":["../src/load-messages.ts","../src/with-i18n-micro.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'\nimport { join, relative, resolve, sep } from 'node:path'\nimport type { Translations } from '@i18n-micro/types'\nimport { deepMergeTranslations } from '@i18n-micro/utils/deep-merge'\nimport {\n classifyTranslationRelativePath,\n mergeRouteTranslationsWithRoot,\n type TranslationFileBuckets,\n} from '@i18n-micro/utils/parse-path'\n\nexport interface LoadMessagesOptions {\n /** Directory with locale JSON (`en.json`, `pages/guide/demo/en.json`, …). */\n translationDir: string\n rootDir?: string\n /**\n * When true, treat `pages/**` files as root-level dictionaries.\n * @default false\n */\n disablePageLocales?: boolean\n}\n\nexport type LoadedTranslations = TranslationFileBuckets<Translations>\n\nexport interface TranslationFileRef {\n /** Path relative to `translationDir` using `/` separators. */\n relativePath: string\n absolutePath: string\n}\n\nfunction isTranslationsObject(value: unknown): value is Translations {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction walkTranslationFiles(dir: string, onFile: (fullPath: string) => void): void {\n if (!existsSync(dir)) return\n\n for (const entry of readdirSync(dir)) {\n const fullPath = join(dir, entry)\n const stat = statSync(fullPath)\n if (stat.isDirectory()) {\n walkTranslationFiles(fullPath, onFile)\n continue\n }\n if (entry.endsWith('.json')) {\n onFile(fullPath)\n }\n }\n}\n\n/**\n * List JSON translation files under `translationDir` (absolute + relative paths).\n */\nexport function listTranslationFiles(options: LoadMessagesOptions): TranslationFileRef[] {\n const rootDir = options.rootDir ?? process.cwd()\n const dir = resolve(rootDir, options.translationDir)\n const files: TranslationFileRef[] = []\n\n walkTranslationFiles(dir, (fullPath) => {\n files.push({\n absolutePath: fullPath,\n relativePath: relative(dir, fullPath).split(sep).join('/'),\n })\n })\n\n return files.sort((a, b) => a.relativePath.localeCompare(b.relativePath))\n}\n\n/**\n * Load root + page-scoped dictionaries (`pages/** /xx.json`).\n * Node.js-only (`node:fs`).\n */\nexport function loadTranslationBuckets(options: LoadMessagesOptions): LoadedTranslations {\n const rootDir = options.rootDir ?? process.cwd()\n const dir = resolve(rootDir, options.translationDir)\n const buckets: LoadedTranslations = { root: {}, routes: {} }\n const disablePageLocales = options.disablePageLocales === true\n\n if (!existsSync(dir)) {\n return buckets\n }\n\n walkTranslationFiles(dir, (fullPath) => {\n const relativePath = relative(dir, fullPath).split(sep).join('/')\n try {\n const parsed: unknown = JSON.parse(readFileSync(fullPath, 'utf-8'))\n if (!isTranslationsObject(parsed)) {\n console.error(\n `[i18n-micro/vitepress] Skipping ${relativePath}: expected a JSON object, got ${Array.isArray(parsed) ? 'array' : typeof parsed}`,\n )\n return\n }\n const translations = parsed\n const classified = classifyTranslationRelativePath(relativePath, disablePageLocales)\n\n if (classified.type === 'page') {\n const routeBucket = buckets.routes[classified.pageName]\n ?? (buckets.routes[classified.pageName] = {})\n routeBucket[classified.locale] = translations\n return\n }\n\n if (classified.type === 'root') {\n const existing = buckets.root[classified.locale]\n buckets.root[classified.locale] = existing\n ? deepMergeTranslations(existing as Record<string, unknown>, translations as Record<string, unknown>) as Translations\n : translations\n }\n }\n catch (error) {\n console.error(`[i18n-micro/vitepress] Failed to load ${relativePath}:`, error)\n }\n })\n\n return buckets\n}\n\n/**\n * Load root-level locale JSON only (`en.json`, `fr.json`, …).\n * Prefer `loadTranslationBuckets` when page locales are needed.\n *\n * Node.js-only (`node:fs`). For bundler-friendly loading prefer\n * `withI18nMicro` virtual modules or `messagesFromGlob` in the theme.\n */\nexport function loadMessages(options: LoadMessagesOptions): Record<string, Translations> {\n return loadTranslationBuckets(options).root\n}\n\n/**\n * Apply page dictionaries onto an i18n instance (merged with root).\n */\nexport function applyLoadedTranslations(\n i18n: {\n addTranslations: (locale: string, translations: Translations, merge?: boolean) => void\n addRouteTranslations: (locale: string, routeName: string, translations: Translations, merge?: boolean) => void\n },\n loaded: LoadedTranslations,\n): void {\n for (const [locale, translations] of Object.entries(loaded.root)) {\n i18n.addTranslations(locale, translations, false)\n }\n for (const [routeName, byLocale] of Object.entries(loaded.routes)) {\n for (const [locale, translations] of Object.entries(byLocale)) {\n i18n.addRouteTranslations(\n locale,\n routeName,\n mergeRouteTranslationsWithRoot(loaded.root[locale], translations),\n false,\n )\n }\n }\n}\n","import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { Locale, Translations } from '@i18n-micro/types'\nimport { classifyTranslationRelativePath } from '@i18n-micro/utils/parse-path'\nimport type { Plugin } from 'vite'\nimport type { VitePressI18nOptions } from './create'\nimport { listTranslationFiles, loadTranslationBuckets } from './load-messages'\n\nexport interface WithI18nMicroOptions extends VitePressI18nOptions {\n /**\n * Directory with locale JSON (`en.json`, `pages/guide/demo/en.json`, …), relative to Vite root\n * (VitePress content / docs root). Used by `virtual:i18n-micro/messages`.\n * @default 'locales'\n */\n translationDir?: string\n /**\n * When true, treat `pages/**` as root-level dictionaries.\n * @default false\n */\n disablePageLocales?: boolean\n /**\n * When true, logs a warning if VitePress `locales` keys do not align with\n * configured i18n locale codes.\n * @default true\n */\n warnOnLocaleMismatch?: boolean\n}\n\n/**\n * Minimal VitePress / Vite user config shape we merge into.\n * Avoid importing `vitepress` types so the package stays usable as a pure library dep.\n */\nexport interface VitePressUserConfigLike {\n locales?: Record<string, unknown>\n vite?: {\n plugins?: Plugin[] | Plugin[][]\n [key: string]: unknown\n }\n [key: string]: unknown\n}\n\nexport interface VirtualI18nConfig {\n defaultLocale: string\n fallbackLocale: string\n locales: Locale[]\n localeCodes: string[]\n missingWarn: boolean\n syncWithVitePress: boolean\n translationDir: string\n disablePageLocales: boolean\n localeKeyToCode: Record<string, string>\n}\n\nconst VIRTUAL_CONFIG_ID = 'virtual:i18n-micro/config'\nconst RESOLVED_CONFIG_ID = `\\0${VIRTUAL_CONFIG_ID}`\nconst VIRTUAL_MESSAGES_ID = 'virtual:i18n-micro/messages'\nconst RESOLVED_MESSAGES_ID = `\\0${VIRTUAL_MESSAGES_ID}`\n\nfunction toPosix(path: string): string {\n return path.replace(/\\\\/g, '/')\n}\n\nfunction generateImportMessagesModule(\n rootDir: string,\n translationDir: string,\n disablePageLocales: boolean,\n): string {\n const files = listTranslationFiles({ rootDir, translationDir })\n if (files.length === 0) {\n return 'export const messages = {}\\nexport const routeMessages = {}\\n'\n }\n\n const imports: string[] = []\n const rootEntries: string[] = []\n const routeVarNames = new Map<string, Map<string, string>>()\n let i = 0\n\n for (const file of files) {\n const parsed = classifyTranslationRelativePath(file.relativePath, disablePageLocales)\n if (parsed.type === 'ignore') continue\n\n const varName = `__i18n_${i++}`\n imports.push(`import ${varName} from ${JSON.stringify(toPosix(file.absolutePath))}`)\n\n if (parsed.type === 'root') {\n rootEntries.push(` ${JSON.stringify(parsed.locale)}: ${varName}`)\n continue\n }\n\n let byLocale = routeVarNames.get(parsed.pageName)\n if (!byLocale) {\n byLocale = new Map()\n routeVarNames.set(parsed.pageName, byLocale)\n }\n byLocale.set(parsed.locale, varName)\n }\n\n const routeEntries: string[] = []\n for (const [routeName, byLocale] of routeVarNames) {\n const localeEntries = [...byLocale.entries()]\n .map(([locale, varName]) => ` ${JSON.stringify(locale)}: ${varName}`)\n .join(',\\n')\n routeEntries.push(` ${JSON.stringify(routeName)}: {\\n${localeEntries}\\n }`)\n }\n\n return [\n ...imports,\n `export const messages = {\\n${rootEntries.join(',\\n')}\\n}`,\n `export const routeMessages = {\\n${routeEntries.join(',\\n')}\\n}`,\n '',\n ].join('\\n')\n}\n\nfunction generateInlineMessagesModule(\n messages: Record<string, Translations>,\n routeMessages: Record<string, Record<string, Translations>>,\n): string {\n return [\n `export const messages = ${JSON.stringify(messages)}`,\n `export const routeMessages = ${JSON.stringify(routeMessages)}`,\n '',\n ].join('\\n')\n}\n\nfunction createI18nMicroVitePlugin(options: WithI18nMicroOptions): Plugin {\n const defaultLocale = options.defaultLocale || options.locale\n const translationDir = options.translationDir ?? 'locales'\n const disablePageLocales = options.disablePageLocales === true\n const configData: VirtualI18nConfig = {\n defaultLocale,\n fallbackLocale: options.fallbackLocale || defaultLocale,\n locales: options.locales || [],\n localeCodes: (options.locales || []).map((l) => l.code),\n missingWarn: options.missingWarn ?? true,\n syncWithVitePress: options.syncWithVitePress !== false,\n translationDir,\n disablePageLocales,\n localeKeyToCode: options.localeKeyToCode ?? {},\n }\n\n let rootDir = process.cwd()\n let useInline = Boolean(options.messages || options.routeMessages)\n let inlineRoot = options.messages ?? {}\n let inlineRoutes = options.routeMessages ?? {}\n let debounceTimer: ReturnType<typeof setTimeout> | undefined\n const needsDiskReload = () => !options.messages || !options.routeMessages\n\n const reloadInlineFromDisk = () => {\n // Fully inline config: skip disk I/O (and avoid spurious JSON parse errors).\n if (!needsDiskReload()) return\n const loaded = loadTranslationBuckets({\n rootDir,\n translationDir,\n disablePageLocales,\n })\n if (!options.messages) {\n inlineRoot = loaded.root\n }\n if (!options.routeMessages) {\n inlineRoutes = loaded.routes\n }\n }\n\n return {\n name: 'vite-plugin-i18n-micro-vitepress',\n configResolved(config) {\n rootDir = config.root\n // Inline when caller passed messages and/or routeMessages.\n // routeMessages alone still loads root dictionaries from translationDir.\n useInline = Boolean(options.messages || options.routeMessages)\n if (useInline) {\n if (options.messages) inlineRoot = options.messages\n if (options.routeMessages) inlineRoutes = options.routeMessages\n if (needsDiskReload()) {\n reloadInlineFromDisk()\n }\n if (options.messages) inlineRoot = options.messages\n if (options.routeMessages) inlineRoutes = options.routeMessages\n }\n },\n configureServer(server) {\n // Both maps provided inline — nothing to watch on disk.\n if (useInline && !needsDiskReload()) return\n\n const dir = resolve(rootDir, translationDir)\n if (!existsSync(dir)) return\n\n server.watcher.add(dir)\n\n const invalidate = () => {\n if (debounceTimer) clearTimeout(debounceTimer)\n debounceTimer = setTimeout(() => {\n if (useInline) reloadInlineFromDisk()\n const mod = server.moduleGraph.getModuleById(RESOLVED_MESSAGES_ID)\n if (mod) {\n server.moduleGraph.invalidateModule(mod)\n server.ws.send({ type: 'full-reload' })\n }\n }, 50)\n }\n\n // add/unlink need virtual module regen; change is usually handled by JSON import HMR,\n // but we still invalidate when using inline payload that still reads disk.\n server.watcher.on('add', (file) => {\n if (file.startsWith(dir) && file.endsWith('.json')) invalidate()\n })\n server.watcher.on('unlink', (file) => {\n if (file.startsWith(dir) && file.endsWith('.json')) invalidate()\n })\n if (useInline && needsDiskReload()) {\n server.watcher.on('change', (file) => {\n if (file.startsWith(dir) && file.endsWith('.json')) invalidate()\n })\n }\n },\n resolveId(id) {\n if (id === VIRTUAL_CONFIG_ID) return RESOLVED_CONFIG_ID\n if (id === VIRTUAL_MESSAGES_ID) return RESOLVED_MESSAGES_ID\n },\n load(id) {\n if (id === RESOLVED_CONFIG_ID) {\n return `export const config = ${JSON.stringify(configData)}`\n }\n if (id === RESOLVED_MESSAGES_ID) {\n if (useInline) {\n return generateInlineMessagesModule(inlineRoot, inlineRoutes)\n }\n return generateImportMessagesModule(rootDir, translationDir, disablePageLocales)\n }\n },\n }\n}\n\nexport function warnLocaleMismatch(config: VitePressUserConfigLike, options: WithI18nMicroOptions): void {\n if (options.warnOnLocaleMismatch === false) return\n const vpLocales = config.locales\n if (!vpLocales || !options.locales?.length) return\n\n const defaultLocale = options.defaultLocale || options.locale\n const vpKeys = Object.keys(vpLocales)\n const codes = new Set(options.locales.map((l) => l.code))\n\n for (const key of vpKeys) {\n const expectedCode = key === 'root' ? defaultLocale : (options.localeKeyToCode?.[key] ?? key)\n if (!codes.has(expectedCode)) {\n console.warn(\n `[i18n-micro/vitepress] VitePress locale key \"${key}\" maps to \"${expectedCode}\", `\n + `which is not in i18n locales (${[...codes].join(', ')}).`,\n )\n }\n }\n}\n\n/**\n * Config helper (like `withMermaid`). Name is `withI18nMicro` on purpose —\n * `withI18n` is already used by the unrelated `vitepress-i18n` package.\n *\n * Registers virtual modules:\n * - `virtual:i18n-micro/config`\n * - `virtual:i18n-micro/messages` (from `translationDir`, default `locales/`)\n *\n * Pair with `defineI18nTheme(DefaultTheme)` — no manual `import.meta.glob` in the theme.\n *\n * Import from `@i18n-micro/vitepress/config` (Node / config files only).\n */\nexport function withI18nMicro<T extends VitePressUserConfigLike>(\n config: T,\n options: WithI18nMicroOptions,\n): T {\n warnLocaleMismatch(config, options)\n\n const existingPlugins = config.vite?.plugins\n const plugins = [\n ...(Array.isArray(existingPlugins) ? existingPlugins.flat() : []),\n createI18nMicroVitePlugin(options),\n ]\n\n return {\n ...config,\n vite: {\n ...config.vite,\n plugins,\n },\n }\n}\n"],"names":["isTranslationsObject","value","walkTranslationFiles","dir","onFile","existsSync","entry","readdirSync","fullPath","join","statSync","listTranslationFiles","options","rootDir","resolve","files","relative","sep","a","b","loadTranslationBuckets","buckets","disablePageLocales","relativePath","parsed","readFileSync","translations","classified","classifyTranslationRelativePath","routeBucket","existing","deepMergeTranslations","error","loadMessages","applyLoadedTranslations","i18n","loaded","locale","routeName","byLocale","mergeRouteTranslationsWithRoot","VIRTUAL_CONFIG_ID","RESOLVED_CONFIG_ID","VIRTUAL_MESSAGES_ID","RESOLVED_MESSAGES_ID","toPosix","path","generateImportMessagesModule","translationDir","imports","rootEntries","routeVarNames","i","file","varName","routeEntries","localeEntries","generateInlineMessagesModule","messages","routeMessages","createI18nMicroVitePlugin","defaultLocale","configData","l","useInline","inlineRoot","inlineRoutes","debounceTimer","needsDiskReload","reloadInlineFromDisk","config","server","invalidate","mod","id","warnLocaleMismatch","vpLocales","vpKeys","codes","key","expectedCode","withI18nMicro","existingPlugins","plugins"],"mappings":"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"}
@@ -0,0 +1,216 @@
1
+ import { existsSync as p, readdirSync as v, statSync as w, readFileSync as T } from "node:fs";
2
+ import { resolve as M, join as P, relative as b, sep as L } from "node:path";
3
+ import { mergeRouteTranslationsWithRoot as I, classifyTranslationRelativePath as j } from "@i18n-micro/utils/parse-path";
4
+ import { deepMergeTranslations as x } from "@i18n-micro/utils/deep-merge";
5
+ function k(e) {
6
+ return e !== null && typeof e == "object" && !Array.isArray(e);
7
+ }
8
+ function S(e, s) {
9
+ if (p(e))
10
+ for (const r of v(e)) {
11
+ const t = P(e, r);
12
+ if (w(t).isDirectory()) {
13
+ S(t, s);
14
+ continue;
15
+ }
16
+ r.endsWith(".json") && s(t);
17
+ }
18
+ }
19
+ function R(e) {
20
+ const s = e.rootDir ?? process.cwd(), r = M(s, e.translationDir), t = [];
21
+ return S(r, (i) => {
22
+ t.push({
23
+ absolutePath: i,
24
+ relativePath: b(r, i).split(L).join("/")
25
+ });
26
+ }), t.sort((i, c) => i.relativePath.localeCompare(c.relativePath));
27
+ }
28
+ function D(e) {
29
+ const s = e.rootDir ?? process.cwd(), r = M(s, e.translationDir), t = { root: {}, routes: {} }, i = e.disablePageLocales === !0;
30
+ return p(r) && S(r, (c) => {
31
+ const a = b(r, c).split(L).join("/");
32
+ try {
33
+ const l = JSON.parse(T(c, "utf-8"));
34
+ if (!k(l)) {
35
+ console.error(
36
+ `[i18n-micro/vitepress] Skipping ${a}: expected a JSON object, got ${Array.isArray(l) ? "array" : typeof l}`
37
+ );
38
+ return;
39
+ }
40
+ const f = l, u = j(a, i);
41
+ if (u.type === "page") {
42
+ const n = t.routes[u.pageName] ?? (t.routes[u.pageName] = {});
43
+ n[u.locale] = f;
44
+ return;
45
+ }
46
+ if (u.type === "root") {
47
+ const n = t.root[u.locale];
48
+ t.root[u.locale] = n ? x(n, f) : f;
49
+ }
50
+ } catch (l) {
51
+ console.error(`[i18n-micro/vitepress] Failed to load ${a}:`, l);
52
+ }
53
+ }), t;
54
+ }
55
+ function B(e) {
56
+ return D(e).root;
57
+ }
58
+ function K(e, s) {
59
+ for (const [r, t] of Object.entries(s.root))
60
+ e.addTranslations(r, t, !1);
61
+ for (const [r, t] of Object.entries(s.routes))
62
+ for (const [i, c] of Object.entries(t))
63
+ e.addRouteTranslations(
64
+ i,
65
+ r,
66
+ I(s.root[i], c),
67
+ !1
68
+ );
69
+ }
70
+ const N = "virtual:i18n-micro/config", $ = `\0${N}`, O = "virtual:i18n-micro/messages", h = `\0${O}`;
71
+ function W(e) {
72
+ return e.replace(/\\/g, "/");
73
+ }
74
+ function E(e, s, r) {
75
+ const t = R({ rootDir: e, translationDir: s });
76
+ if (t.length === 0)
77
+ return `export const messages = {}
78
+ export const routeMessages = {}
79
+ `;
80
+ const i = [], c = [], a = /* @__PURE__ */ new Map();
81
+ let l = 0;
82
+ for (const u of t) {
83
+ const n = j(u.relativePath, r);
84
+ if (n.type === "ignore") continue;
85
+ const d = `__i18n_${l++}`;
86
+ if (i.push(`import ${d} from ${JSON.stringify(W(u.absolutePath))}`), n.type === "root") {
87
+ c.push(` ${JSON.stringify(n.locale)}: ${d}`);
88
+ continue;
89
+ }
90
+ let o = a.get(n.pageName);
91
+ o || (o = /* @__PURE__ */ new Map(), a.set(n.pageName, o)), o.set(n.locale, d);
92
+ }
93
+ const f = [];
94
+ for (const [u, n] of a) {
95
+ const d = [...n.entries()].map(([o, m]) => ` ${JSON.stringify(o)}: ${m}`).join(`,
96
+ `);
97
+ f.push(` ${JSON.stringify(u)}: {
98
+ ${d}
99
+ }`);
100
+ }
101
+ return [
102
+ ...i,
103
+ `export const messages = {
104
+ ${c.join(`,
105
+ `)}
106
+ }`,
107
+ `export const routeMessages = {
108
+ ${f.join(`,
109
+ `)}
110
+ }`,
111
+ ""
112
+ ].join(`
113
+ `);
114
+ }
115
+ function _(e, s) {
116
+ return [
117
+ `export const messages = ${JSON.stringify(e)}`,
118
+ `export const routeMessages = ${JSON.stringify(s)}`,
119
+ ""
120
+ ].join(`
121
+ `);
122
+ }
123
+ function A(e) {
124
+ const s = e.defaultLocale || e.locale, r = e.translationDir ?? "locales", t = e.disablePageLocales === !0, i = {
125
+ defaultLocale: s,
126
+ fallbackLocale: e.fallbackLocale || s,
127
+ locales: e.locales || [],
128
+ localeCodes: (e.locales || []).map((o) => o.code),
129
+ missingWarn: e.missingWarn ?? !0,
130
+ syncWithVitePress: e.syncWithVitePress !== !1,
131
+ translationDir: r,
132
+ disablePageLocales: t,
133
+ localeKeyToCode: e.localeKeyToCode ?? {}
134
+ };
135
+ let c = process.cwd(), a = !!(e.messages || e.routeMessages), l = e.messages ?? {}, f = e.routeMessages ?? {}, u;
136
+ const n = () => !e.messages || !e.routeMessages, d = () => {
137
+ if (!n()) return;
138
+ const o = D({
139
+ rootDir: c,
140
+ translationDir: r,
141
+ disablePageLocales: t
142
+ });
143
+ e.messages || (l = o.root), e.routeMessages || (f = o.routes);
144
+ };
145
+ return {
146
+ name: "vite-plugin-i18n-micro-vitepress",
147
+ configResolved(o) {
148
+ c = o.root, a = !!(e.messages || e.routeMessages), a && (e.messages && (l = e.messages), e.routeMessages && (f = e.routeMessages), n() && d(), e.messages && (l = e.messages), e.routeMessages && (f = e.routeMessages));
149
+ },
150
+ configureServer(o) {
151
+ if (a && !n()) return;
152
+ const m = M(c, r);
153
+ if (!p(m)) return;
154
+ o.watcher.add(m);
155
+ const y = () => {
156
+ u && clearTimeout(u), u = setTimeout(() => {
157
+ a && d();
158
+ const g = o.moduleGraph.getModuleById(h);
159
+ g && (o.moduleGraph.invalidateModule(g), o.ws.send({ type: "full-reload" }));
160
+ }, 50);
161
+ };
162
+ o.watcher.on("add", (g) => {
163
+ g.startsWith(m) && g.endsWith(".json") && y();
164
+ }), o.watcher.on("unlink", (g) => {
165
+ g.startsWith(m) && g.endsWith(".json") && y();
166
+ }), a && n() && o.watcher.on("change", (g) => {
167
+ g.startsWith(m) && g.endsWith(".json") && y();
168
+ });
169
+ },
170
+ resolveId(o) {
171
+ if (o === N) return $;
172
+ if (o === O) return h;
173
+ },
174
+ load(o) {
175
+ if (o === $)
176
+ return `export const config = ${JSON.stringify(i)}`;
177
+ if (o === h)
178
+ return a ? _(l, f) : E(c, r, t);
179
+ }
180
+ };
181
+ }
182
+ function J(e, s) {
183
+ if (s.warnOnLocaleMismatch === !1) return;
184
+ const r = e.locales;
185
+ if (!r || !s.locales?.length) return;
186
+ const t = s.defaultLocale || s.locale, i = Object.keys(r), c = new Set(s.locales.map((a) => a.code));
187
+ for (const a of i) {
188
+ const l = a === "root" ? t : s.localeKeyToCode?.[a] ?? a;
189
+ c.has(l) || console.warn(
190
+ `[i18n-micro/vitepress] VitePress locale key "${a}" maps to "${l}", which is not in i18n locales (${[...c].join(", ")}).`
191
+ );
192
+ }
193
+ }
194
+ function U(e, s) {
195
+ J(e, s);
196
+ const r = e.vite?.plugins, t = [
197
+ ...Array.isArray(r) ? r.flat() : [],
198
+ A(s)
199
+ ];
200
+ return {
201
+ ...e,
202
+ vite: {
203
+ ...e.vite,
204
+ plugins: t
205
+ }
206
+ };
207
+ }
208
+ export {
209
+ K as a,
210
+ B as b,
211
+ D as c,
212
+ U as d,
213
+ R as l,
214
+ J as w
215
+ };
216
+ //# sourceMappingURL=with-i18n-micro-DIAoqY71.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-i18n-micro-DIAoqY71.js","sources":["../src/load-messages.ts","../src/with-i18n-micro.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'\nimport { join, relative, resolve, sep } from 'node:path'\nimport type { Translations } from '@i18n-micro/types'\nimport { deepMergeTranslations } from '@i18n-micro/utils/deep-merge'\nimport {\n classifyTranslationRelativePath,\n mergeRouteTranslationsWithRoot,\n type TranslationFileBuckets,\n} from '@i18n-micro/utils/parse-path'\n\nexport interface LoadMessagesOptions {\n /** Directory with locale JSON (`en.json`, `pages/guide/demo/en.json`, …). */\n translationDir: string\n rootDir?: string\n /**\n * When true, treat `pages/**` files as root-level dictionaries.\n * @default false\n */\n disablePageLocales?: boolean\n}\n\nexport type LoadedTranslations = TranslationFileBuckets<Translations>\n\nexport interface TranslationFileRef {\n /** Path relative to `translationDir` using `/` separators. */\n relativePath: string\n absolutePath: string\n}\n\nfunction isTranslationsObject(value: unknown): value is Translations {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction walkTranslationFiles(dir: string, onFile: (fullPath: string) => void): void {\n if (!existsSync(dir)) return\n\n for (const entry of readdirSync(dir)) {\n const fullPath = join(dir, entry)\n const stat = statSync(fullPath)\n if (stat.isDirectory()) {\n walkTranslationFiles(fullPath, onFile)\n continue\n }\n if (entry.endsWith('.json')) {\n onFile(fullPath)\n }\n }\n}\n\n/**\n * List JSON translation files under `translationDir` (absolute + relative paths).\n */\nexport function listTranslationFiles(options: LoadMessagesOptions): TranslationFileRef[] {\n const rootDir = options.rootDir ?? process.cwd()\n const dir = resolve(rootDir, options.translationDir)\n const files: TranslationFileRef[] = []\n\n walkTranslationFiles(dir, (fullPath) => {\n files.push({\n absolutePath: fullPath,\n relativePath: relative(dir, fullPath).split(sep).join('/'),\n })\n })\n\n return files.sort((a, b) => a.relativePath.localeCompare(b.relativePath))\n}\n\n/**\n * Load root + page-scoped dictionaries (`pages/** /xx.json`).\n * Node.js-only (`node:fs`).\n */\nexport function loadTranslationBuckets(options: LoadMessagesOptions): LoadedTranslations {\n const rootDir = options.rootDir ?? process.cwd()\n const dir = resolve(rootDir, options.translationDir)\n const buckets: LoadedTranslations = { root: {}, routes: {} }\n const disablePageLocales = options.disablePageLocales === true\n\n if (!existsSync(dir)) {\n return buckets\n }\n\n walkTranslationFiles(dir, (fullPath) => {\n const relativePath = relative(dir, fullPath).split(sep).join('/')\n try {\n const parsed: unknown = JSON.parse(readFileSync(fullPath, 'utf-8'))\n if (!isTranslationsObject(parsed)) {\n console.error(\n `[i18n-micro/vitepress] Skipping ${relativePath}: expected a JSON object, got ${Array.isArray(parsed) ? 'array' : typeof parsed}`,\n )\n return\n }\n const translations = parsed\n const classified = classifyTranslationRelativePath(relativePath, disablePageLocales)\n\n if (classified.type === 'page') {\n const routeBucket = buckets.routes[classified.pageName]\n ?? (buckets.routes[classified.pageName] = {})\n routeBucket[classified.locale] = translations\n return\n }\n\n if (classified.type === 'root') {\n const existing = buckets.root[classified.locale]\n buckets.root[classified.locale] = existing\n ? deepMergeTranslations(existing as Record<string, unknown>, translations as Record<string, unknown>) as Translations\n : translations\n }\n }\n catch (error) {\n console.error(`[i18n-micro/vitepress] Failed to load ${relativePath}:`, error)\n }\n })\n\n return buckets\n}\n\n/**\n * Load root-level locale JSON only (`en.json`, `fr.json`, …).\n * Prefer `loadTranslationBuckets` when page locales are needed.\n *\n * Node.js-only (`node:fs`). For bundler-friendly loading prefer\n * `withI18nMicro` virtual modules or `messagesFromGlob` in the theme.\n */\nexport function loadMessages(options: LoadMessagesOptions): Record<string, Translations> {\n return loadTranslationBuckets(options).root\n}\n\n/**\n * Apply page dictionaries onto an i18n instance (merged with root).\n */\nexport function applyLoadedTranslations(\n i18n: {\n addTranslations: (locale: string, translations: Translations, merge?: boolean) => void\n addRouteTranslations: (locale: string, routeName: string, translations: Translations, merge?: boolean) => void\n },\n loaded: LoadedTranslations,\n): void {\n for (const [locale, translations] of Object.entries(loaded.root)) {\n i18n.addTranslations(locale, translations, false)\n }\n for (const [routeName, byLocale] of Object.entries(loaded.routes)) {\n for (const [locale, translations] of Object.entries(byLocale)) {\n i18n.addRouteTranslations(\n locale,\n routeName,\n mergeRouteTranslationsWithRoot(loaded.root[locale], translations),\n false,\n )\n }\n }\n}\n","import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { Locale, Translations } from '@i18n-micro/types'\nimport { classifyTranslationRelativePath } from '@i18n-micro/utils/parse-path'\nimport type { Plugin } from 'vite'\nimport type { VitePressI18nOptions } from './create'\nimport { listTranslationFiles, loadTranslationBuckets } from './load-messages'\n\nexport interface WithI18nMicroOptions extends VitePressI18nOptions {\n /**\n * Directory with locale JSON (`en.json`, `pages/guide/demo/en.json`, …), relative to Vite root\n * (VitePress content / docs root). Used by `virtual:i18n-micro/messages`.\n * @default 'locales'\n */\n translationDir?: string\n /**\n * When true, treat `pages/**` as root-level dictionaries.\n * @default false\n */\n disablePageLocales?: boolean\n /**\n * When true, logs a warning if VitePress `locales` keys do not align with\n * configured i18n locale codes.\n * @default true\n */\n warnOnLocaleMismatch?: boolean\n}\n\n/**\n * Minimal VitePress / Vite user config shape we merge into.\n * Avoid importing `vitepress` types so the package stays usable as a pure library dep.\n */\nexport interface VitePressUserConfigLike {\n locales?: Record<string, unknown>\n vite?: {\n plugins?: Plugin[] | Plugin[][]\n [key: string]: unknown\n }\n [key: string]: unknown\n}\n\nexport interface VirtualI18nConfig {\n defaultLocale: string\n fallbackLocale: string\n locales: Locale[]\n localeCodes: string[]\n missingWarn: boolean\n syncWithVitePress: boolean\n translationDir: string\n disablePageLocales: boolean\n localeKeyToCode: Record<string, string>\n}\n\nconst VIRTUAL_CONFIG_ID = 'virtual:i18n-micro/config'\nconst RESOLVED_CONFIG_ID = `\\0${VIRTUAL_CONFIG_ID}`\nconst VIRTUAL_MESSAGES_ID = 'virtual:i18n-micro/messages'\nconst RESOLVED_MESSAGES_ID = `\\0${VIRTUAL_MESSAGES_ID}`\n\nfunction toPosix(path: string): string {\n return path.replace(/\\\\/g, '/')\n}\n\nfunction generateImportMessagesModule(\n rootDir: string,\n translationDir: string,\n disablePageLocales: boolean,\n): string {\n const files = listTranslationFiles({ rootDir, translationDir })\n if (files.length === 0) {\n return 'export const messages = {}\\nexport const routeMessages = {}\\n'\n }\n\n const imports: string[] = []\n const rootEntries: string[] = []\n const routeVarNames = new Map<string, Map<string, string>>()\n let i = 0\n\n for (const file of files) {\n const parsed = classifyTranslationRelativePath(file.relativePath, disablePageLocales)\n if (parsed.type === 'ignore') continue\n\n const varName = `__i18n_${i++}`\n imports.push(`import ${varName} from ${JSON.stringify(toPosix(file.absolutePath))}`)\n\n if (parsed.type === 'root') {\n rootEntries.push(` ${JSON.stringify(parsed.locale)}: ${varName}`)\n continue\n }\n\n let byLocale = routeVarNames.get(parsed.pageName)\n if (!byLocale) {\n byLocale = new Map()\n routeVarNames.set(parsed.pageName, byLocale)\n }\n byLocale.set(parsed.locale, varName)\n }\n\n const routeEntries: string[] = []\n for (const [routeName, byLocale] of routeVarNames) {\n const localeEntries = [...byLocale.entries()]\n .map(([locale, varName]) => ` ${JSON.stringify(locale)}: ${varName}`)\n .join(',\\n')\n routeEntries.push(` ${JSON.stringify(routeName)}: {\\n${localeEntries}\\n }`)\n }\n\n return [\n ...imports,\n `export const messages = {\\n${rootEntries.join(',\\n')}\\n}`,\n `export const routeMessages = {\\n${routeEntries.join(',\\n')}\\n}`,\n '',\n ].join('\\n')\n}\n\nfunction generateInlineMessagesModule(\n messages: Record<string, Translations>,\n routeMessages: Record<string, Record<string, Translations>>,\n): string {\n return [\n `export const messages = ${JSON.stringify(messages)}`,\n `export const routeMessages = ${JSON.stringify(routeMessages)}`,\n '',\n ].join('\\n')\n}\n\nfunction createI18nMicroVitePlugin(options: WithI18nMicroOptions): Plugin {\n const defaultLocale = options.defaultLocale || options.locale\n const translationDir = options.translationDir ?? 'locales'\n const disablePageLocales = options.disablePageLocales === true\n const configData: VirtualI18nConfig = {\n defaultLocale,\n fallbackLocale: options.fallbackLocale || defaultLocale,\n locales: options.locales || [],\n localeCodes: (options.locales || []).map((l) => l.code),\n missingWarn: options.missingWarn ?? true,\n syncWithVitePress: options.syncWithVitePress !== false,\n translationDir,\n disablePageLocales,\n localeKeyToCode: options.localeKeyToCode ?? {},\n }\n\n let rootDir = process.cwd()\n let useInline = Boolean(options.messages || options.routeMessages)\n let inlineRoot = options.messages ?? {}\n let inlineRoutes = options.routeMessages ?? {}\n let debounceTimer: ReturnType<typeof setTimeout> | undefined\n const needsDiskReload = () => !options.messages || !options.routeMessages\n\n const reloadInlineFromDisk = () => {\n // Fully inline config: skip disk I/O (and avoid spurious JSON parse errors).\n if (!needsDiskReload()) return\n const loaded = loadTranslationBuckets({\n rootDir,\n translationDir,\n disablePageLocales,\n })\n if (!options.messages) {\n inlineRoot = loaded.root\n }\n if (!options.routeMessages) {\n inlineRoutes = loaded.routes\n }\n }\n\n return {\n name: 'vite-plugin-i18n-micro-vitepress',\n configResolved(config) {\n rootDir = config.root\n // Inline when caller passed messages and/or routeMessages.\n // routeMessages alone still loads root dictionaries from translationDir.\n useInline = Boolean(options.messages || options.routeMessages)\n if (useInline) {\n if (options.messages) inlineRoot = options.messages\n if (options.routeMessages) inlineRoutes = options.routeMessages\n if (needsDiskReload()) {\n reloadInlineFromDisk()\n }\n if (options.messages) inlineRoot = options.messages\n if (options.routeMessages) inlineRoutes = options.routeMessages\n }\n },\n configureServer(server) {\n // Both maps provided inline — nothing to watch on disk.\n if (useInline && !needsDiskReload()) return\n\n const dir = resolve(rootDir, translationDir)\n if (!existsSync(dir)) return\n\n server.watcher.add(dir)\n\n const invalidate = () => {\n if (debounceTimer) clearTimeout(debounceTimer)\n debounceTimer = setTimeout(() => {\n if (useInline) reloadInlineFromDisk()\n const mod = server.moduleGraph.getModuleById(RESOLVED_MESSAGES_ID)\n if (mod) {\n server.moduleGraph.invalidateModule(mod)\n server.ws.send({ type: 'full-reload' })\n }\n }, 50)\n }\n\n // add/unlink need virtual module regen; change is usually handled by JSON import HMR,\n // but we still invalidate when using inline payload that still reads disk.\n server.watcher.on('add', (file) => {\n if (file.startsWith(dir) && file.endsWith('.json')) invalidate()\n })\n server.watcher.on('unlink', (file) => {\n if (file.startsWith(dir) && file.endsWith('.json')) invalidate()\n })\n if (useInline && needsDiskReload()) {\n server.watcher.on('change', (file) => {\n if (file.startsWith(dir) && file.endsWith('.json')) invalidate()\n })\n }\n },\n resolveId(id) {\n if (id === VIRTUAL_CONFIG_ID) return RESOLVED_CONFIG_ID\n if (id === VIRTUAL_MESSAGES_ID) return RESOLVED_MESSAGES_ID\n },\n load(id) {\n if (id === RESOLVED_CONFIG_ID) {\n return `export const config = ${JSON.stringify(configData)}`\n }\n if (id === RESOLVED_MESSAGES_ID) {\n if (useInline) {\n return generateInlineMessagesModule(inlineRoot, inlineRoutes)\n }\n return generateImportMessagesModule(rootDir, translationDir, disablePageLocales)\n }\n },\n }\n}\n\nexport function warnLocaleMismatch(config: VitePressUserConfigLike, options: WithI18nMicroOptions): void {\n if (options.warnOnLocaleMismatch === false) return\n const vpLocales = config.locales\n if (!vpLocales || !options.locales?.length) return\n\n const defaultLocale = options.defaultLocale || options.locale\n const vpKeys = Object.keys(vpLocales)\n const codes = new Set(options.locales.map((l) => l.code))\n\n for (const key of vpKeys) {\n const expectedCode = key === 'root' ? defaultLocale : (options.localeKeyToCode?.[key] ?? key)\n if (!codes.has(expectedCode)) {\n console.warn(\n `[i18n-micro/vitepress] VitePress locale key \"${key}\" maps to \"${expectedCode}\", `\n + `which is not in i18n locales (${[...codes].join(', ')}).`,\n )\n }\n }\n}\n\n/**\n * Config helper (like `withMermaid`). Name is `withI18nMicro` on purpose —\n * `withI18n` is already used by the unrelated `vitepress-i18n` package.\n *\n * Registers virtual modules:\n * - `virtual:i18n-micro/config`\n * - `virtual:i18n-micro/messages` (from `translationDir`, default `locales/`)\n *\n * Pair with `defineI18nTheme(DefaultTheme)` — no manual `import.meta.glob` in the theme.\n *\n * Import from `@i18n-micro/vitepress/config` (Node / config files only).\n */\nexport function withI18nMicro<T extends VitePressUserConfigLike>(\n config: T,\n options: WithI18nMicroOptions,\n): T {\n warnLocaleMismatch(config, options)\n\n const existingPlugins = config.vite?.plugins\n const plugins = [\n ...(Array.isArray(existingPlugins) ? existingPlugins.flat() : []),\n createI18nMicroVitePlugin(options),\n ]\n\n return {\n ...config,\n vite: {\n ...config.vite,\n plugins,\n },\n }\n}\n"],"names":["isTranslationsObject","value","walkTranslationFiles","dir","onFile","existsSync","entry","readdirSync","fullPath","join","statSync","listTranslationFiles","options","rootDir","resolve","files","relative","sep","a","b","loadTranslationBuckets","buckets","disablePageLocales","relativePath","parsed","readFileSync","translations","classified","classifyTranslationRelativePath","routeBucket","existing","deepMergeTranslations","error","loadMessages","applyLoadedTranslations","i18n","loaded","locale","routeName","byLocale","mergeRouteTranslationsWithRoot","VIRTUAL_CONFIG_ID","RESOLVED_CONFIG_ID","VIRTUAL_MESSAGES_ID","RESOLVED_MESSAGES_ID","toPosix","path","generateImportMessagesModule","translationDir","imports","rootEntries","routeVarNames","i","file","varName","routeEntries","localeEntries","generateInlineMessagesModule","messages","routeMessages","createI18nMicroVitePlugin","defaultLocale","configData","l","useInline","inlineRoot","inlineRoutes","debounceTimer","needsDiskReload","reloadInlineFromDisk","config","server","invalidate","mod","id","warnLocaleMismatch","vpLocales","vpKeys","codes","key","expectedCode","withI18nMicro","existingPlugins","plugins"],"mappings":";;;;AA6BA,SAASA,EAAqBC,GAAuC;AACnE,SAAOA,MAAU,QAAQ,OAAOA,KAAU,YAAY,CAAC,MAAM,QAAQA,CAAK;AAC5E;AAEA,SAASC,EAAqBC,GAAaC,GAA0C;AACnF,MAAKC,EAAWF,CAAG;AAEnB,eAAWG,KAASC,EAAYJ,CAAG,GAAG;AACpC,YAAMK,IAAWC,EAAKN,GAAKG,CAAK;AAEhC,UADaI,EAASF,CAAQ,EACrB,eAAe;AACtB,QAAAN,EAAqBM,GAAUJ,CAAM;AACrC;AAAA,MACF;AACA,MAAIE,EAAM,SAAS,OAAO,KACxBF,EAAOI,CAAQ;AAAA,IAEnB;AACF;AAKO,SAASG,EAAqBC,GAAoD;AACvF,QAAMC,IAAUD,EAAQ,WAAW,QAAQ,IAAA,GACrCT,IAAMW,EAAQD,GAASD,EAAQ,cAAc,GAC7CG,IAA8B,CAAA;AAEpC,SAAAb,EAAqBC,GAAK,CAACK,MAAa;AACtC,IAAAO,EAAM,KAAK;AAAA,MACT,cAAcP;AAAA,MACd,cAAcQ,EAASb,GAAKK,CAAQ,EAAE,MAAMS,CAAG,EAAE,KAAK,GAAG;AAAA,IAAA,CAC1D;AAAA,EACH,CAAC,GAEMF,EAAM,KAAK,CAACG,GAAGC,MAAMD,EAAE,aAAa,cAAcC,EAAE,YAAY,CAAC;AAC1E;AAMO,SAASC,EAAuBR,GAAkD;AACvF,QAAMC,IAAUD,EAAQ,WAAW,QAAQ,IAAA,GACrCT,IAAMW,EAAQD,GAASD,EAAQ,cAAc,GAC7CS,IAA8B,EAAE,MAAM,CAAA,GAAI,QAAQ,CAAA,EAAC,GACnDC,IAAqBV,EAAQ,uBAAuB;AAE1D,SAAKP,EAAWF,CAAG,KAInBD,EAAqBC,GAAK,CAACK,MAAa;AACtC,UAAMe,IAAeP,EAASb,GAAKK,CAAQ,EAAE,MAAMS,CAAG,EAAE,KAAK,GAAG;AAChE,QAAI;AACF,YAAMO,IAAkB,KAAK,MAAMC,EAAajB,GAAU,OAAO,CAAC;AAClE,UAAI,CAACR,EAAqBwB,CAAM,GAAG;AACjC,gBAAQ;AAAA,UACN,mCAAmCD,CAAY,iCAAiC,MAAM,QAAQC,CAAM,IAAI,UAAU,OAAOA,CAAM;AAAA,QAAA;AAEjI;AAAA,MACF;AACA,YAAME,IAAeF,GACfG,IAAaC,EAAgCL,GAAcD,CAAkB;AAEnF,UAAIK,EAAW,SAAS,QAAQ;AAC9B,cAAME,IAAcR,EAAQ,OAAOM,EAAW,QAAQ,MAChDN,EAAQ,OAAOM,EAAW,QAAQ,IAAI,CAAA;AAC5C,QAAAE,EAAYF,EAAW,MAAM,IAAID;AACjC;AAAA,MACF;AAEA,UAAIC,EAAW,SAAS,QAAQ;AAC9B,cAAMG,IAAWT,EAAQ,KAAKM,EAAW,MAAM;AAC/C,QAAAN,EAAQ,KAAKM,EAAW,MAAM,IAAIG,IAC9BC,EAAsBD,GAAqCJ,CAAuC,IAClGA;AAAA,MACN;AAAA,IACF,SACOM,GAAO;AACZ,cAAQ,MAAM,yCAAyCT,CAAY,KAAKS,CAAK;AAAA,IAC/E;AAAA,EACF,CAAC,GAEMX;AACT;AASO,SAASY,EAAarB,GAA4D;AACvF,SAAOQ,EAAuBR,CAAO,EAAE;AACzC;AAKO,SAASsB,EACdC,GAIAC,GACM;AACN,aAAW,CAACC,GAAQX,CAAY,KAAK,OAAO,QAAQU,EAAO,IAAI;AAC7D,IAAAD,EAAK,gBAAgBE,GAAQX,GAAc,EAAK;AAElD,aAAW,CAACY,GAAWC,CAAQ,KAAK,OAAO,QAAQH,EAAO,MAAM;AAC9D,eAAW,CAACC,GAAQX,CAAY,KAAK,OAAO,QAAQa,CAAQ;AAC1D,MAAAJ,EAAK;AAAA,QACHE;AAAA,QACAC;AAAA,QACAE,EAA+BJ,EAAO,KAAKC,CAAM,GAAGX,CAAY;AAAA,QAChE;AAAA,MAAA;AAIR;ACjGA,MAAMe,IAAoB,6BACpBC,IAAqB,KAAKD,CAAiB,IAC3CE,IAAsB,+BACtBC,IAAuB,KAAKD,CAAmB;AAErD,SAASE,EAAQC,GAAsB;AACrC,SAAOA,EAAK,QAAQ,OAAO,GAAG;AAChC;AAEA,SAASC,EACPlC,GACAmC,GACA1B,GACQ;AACR,QAAMP,IAAQJ,EAAqB,EAAE,SAAAE,GAAS,gBAAAmC,GAAgB;AAC9D,MAAIjC,EAAM,WAAW;AACnB,WAAO;AAAA;AAAA;AAGT,QAAMkC,IAAoB,CAAA,GACpBC,IAAwB,CAAA,GACxBC,wBAAoB,IAAA;AAC1B,MAAIC,IAAI;AAER,aAAWC,KAAQtC,GAAO;AACxB,UAAMS,IAASI,EAAgCyB,EAAK,cAAc/B,CAAkB;AACpF,QAAIE,EAAO,SAAS,SAAU;AAE9B,UAAM8B,IAAU,UAAUF,GAAG;AAG7B,QAFAH,EAAQ,KAAK,UAAUK,CAAO,SAAS,KAAK,UAAUT,EAAQQ,EAAK,YAAY,CAAC,CAAC,EAAE,GAE/E7B,EAAO,SAAS,QAAQ;AAC1B,MAAA0B,EAAY,KAAK,KAAK,KAAK,UAAU1B,EAAO,MAAM,CAAC,KAAK8B,CAAO,EAAE;AACjE;AAAA,IACF;AAEA,QAAIf,IAAWY,EAAc,IAAI3B,EAAO,QAAQ;AAChD,IAAKe,MACHA,wBAAe,IAAA,GACfY,EAAc,IAAI3B,EAAO,UAAUe,CAAQ,IAE7CA,EAAS,IAAIf,EAAO,QAAQ8B,CAAO;AAAA,EACrC;AAEA,QAAMC,IAAyB,CAAA;AAC/B,aAAW,CAACjB,GAAWC,CAAQ,KAAKY,GAAe;AACjD,UAAMK,IAAgB,CAAC,GAAGjB,EAAS,SAAS,EACzC,IAAI,CAAC,CAACF,GAAQiB,CAAO,MAAM,OAAO,KAAK,UAAUjB,CAAM,CAAC,KAAKiB,CAAO,EAAE,EACtE,KAAK;AAAA,CAAK;AACb,IAAAC,EAAa,KAAK,KAAK,KAAK,UAAUjB,CAAS,CAAC;AAAA,EAAQkB,CAAa;AAAA,IAAO;AAAA,EAC9E;AAEA,SAAO;AAAA,IACL,GAAGP;AAAA,IACH;AAAA,EAA8BC,EAAY,KAAK;AAAA,CAAK,CAAC;AAAA;AAAA,IACrD;AAAA,EAAmCK,EAAa,KAAK;AAAA,CAAK,CAAC;AAAA;AAAA,IAC3D;AAAA,EAAA,EACA,KAAK;AAAA,CAAI;AACb;AAEA,SAASE,EACPC,GACAC,GACQ;AACR,SAAO;AAAA,IACL,2BAA2B,KAAK,UAAUD,CAAQ,CAAC;AAAA,IACnD,gCAAgC,KAAK,UAAUC,CAAa,CAAC;AAAA,IAC7D;AAAA,EAAA,EACA,KAAK;AAAA,CAAI;AACb;AAEA,SAASC,EAA0BhD,GAAuC;AACxE,QAAMiD,IAAgBjD,EAAQ,iBAAiBA,EAAQ,QACjDoC,IAAiBpC,EAAQ,kBAAkB,WAC3CU,IAAqBV,EAAQ,uBAAuB,IACpDkD,IAAgC;AAAA,IACpC,eAAAD;AAAA,IACA,gBAAgBjD,EAAQ,kBAAkBiD;AAAA,IAC1C,SAASjD,EAAQ,WAAW,CAAA;AAAA,IAC5B,cAAcA,EAAQ,WAAW,CAAA,GAAI,IAAI,CAACmD,MAAMA,EAAE,IAAI;AAAA,IACtD,aAAanD,EAAQ,eAAe;AAAA,IACpC,mBAAmBA,EAAQ,sBAAsB;AAAA,IACjD,gBAAAoC;AAAA,IACA,oBAAA1B;AAAA,IACA,iBAAiBV,EAAQ,mBAAmB,CAAA;AAAA,EAAC;AAG/C,MAAIC,IAAU,QAAQ,IAAA,GAClBmD,IAAY,GAAQpD,EAAQ,YAAYA,EAAQ,gBAChDqD,IAAarD,EAAQ,YAAY,CAAA,GACjCsD,IAAetD,EAAQ,iBAAiB,CAAA,GACxCuD;AACJ,QAAMC,IAAkB,MAAM,CAACxD,EAAQ,YAAY,CAACA,EAAQ,eAEtDyD,IAAuB,MAAM;AAEjC,QAAI,CAACD,IAAmB;AACxB,UAAMhC,IAAShB,EAAuB;AAAA,MACpC,SAAAP;AAAA,MACA,gBAAAmC;AAAA,MACA,oBAAA1B;AAAA,IAAA,CACD;AACD,IAAKV,EAAQ,aACXqD,IAAa7B,EAAO,OAEjBxB,EAAQ,kBACXsD,IAAe9B,EAAO;AAAA,EAE1B;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,eAAekC,GAAQ;AACrB,MAAAzD,IAAUyD,EAAO,MAGjBN,IAAY,GAAQpD,EAAQ,YAAYA,EAAQ,gBAC5CoD,MACEpD,EAAQ,aAAUqD,IAAarD,EAAQ,WACvCA,EAAQ,kBAAesD,IAAetD,EAAQ,gBAC9CwD,OACFC,EAAA,GAEEzD,EAAQ,aAAUqD,IAAarD,EAAQ,WACvCA,EAAQ,kBAAesD,IAAetD,EAAQ;AAAA,IAEtD;AAAA,IACA,gBAAgB2D,GAAQ;AAEtB,UAAIP,KAAa,CAACI,IAAmB;AAErC,YAAMjE,IAAMW,EAAQD,GAASmC,CAAc;AAC3C,UAAI,CAAC3C,EAAWF,CAAG,EAAG;AAEtB,MAAAoE,EAAO,QAAQ,IAAIpE,CAAG;AAEtB,YAAMqE,IAAa,MAAM;AACvB,QAAIL,kBAA4BA,CAAa,GAC7CA,IAAgB,WAAW,MAAM;AAC/B,UAAIH,KAAWK,EAAA;AACf,gBAAMI,IAAMF,EAAO,YAAY,cAAc3B,CAAoB;AACjE,UAAI6B,MACFF,EAAO,YAAY,iBAAiBE,CAAG,GACvCF,EAAO,GAAG,KAAK,EAAE,MAAM,eAAe;AAAA,QAE1C,GAAG,EAAE;AAAA,MACP;AAIA,MAAAA,EAAO,QAAQ,GAAG,OAAO,CAAClB,MAAS;AACjC,QAAIA,EAAK,WAAWlD,CAAG,KAAKkD,EAAK,SAAS,OAAO,KAAGmB,EAAA;AAAA,MACtD,CAAC,GACDD,EAAO,QAAQ,GAAG,UAAU,CAAClB,MAAS;AACpC,QAAIA,EAAK,WAAWlD,CAAG,KAAKkD,EAAK,SAAS,OAAO,KAAGmB,EAAA;AAAA,MACtD,CAAC,GACGR,KAAaI,OACfG,EAAO,QAAQ,GAAG,UAAU,CAAClB,MAAS;AACpC,QAAIA,EAAK,WAAWlD,CAAG,KAAKkD,EAAK,SAAS,OAAO,KAAGmB,EAAA;AAAA,MACtD,CAAC;AAAA,IAEL;AAAA,IACA,UAAUE,GAAI;AACZ,UAAIA,MAAOjC,EAAmB,QAAOC;AACrC,UAAIgC,MAAO/B,EAAqB,QAAOC;AAAA,IACzC;AAAA,IACA,KAAK8B,GAAI;AACP,UAAIA,MAAOhC;AACT,eAAO,yBAAyB,KAAK,UAAUoB,CAAU,CAAC;AAE5D,UAAIY,MAAO9B;AACT,eAAIoB,IACKP,EAA6BQ,GAAYC,CAAY,IAEvDnB,EAA6BlC,GAASmC,GAAgB1B,CAAkB;AAAA,IAEnF;AAAA,EAAA;AAEJ;AAEO,SAASqD,EAAmBL,GAAiC1D,GAAqC;AACvG,MAAIA,EAAQ,yBAAyB,GAAO;AAC5C,QAAMgE,IAAYN,EAAO;AACzB,MAAI,CAACM,KAAa,CAAChE,EAAQ,SAAS,OAAQ;AAE5C,QAAMiD,IAAgBjD,EAAQ,iBAAiBA,EAAQ,QACjDiE,IAAS,OAAO,KAAKD,CAAS,GAC9BE,IAAQ,IAAI,IAAIlE,EAAQ,QAAQ,IAAI,CAACmD,MAAMA,EAAE,IAAI,CAAC;AAExD,aAAWgB,KAAOF,GAAQ;AACxB,UAAMG,IAAeD,MAAQ,SAASlB,IAAiBjD,EAAQ,kBAAkBmE,CAAG,KAAKA;AACzF,IAAKD,EAAM,IAAIE,CAAY,KACzB,QAAQ;AAAA,MACN,gDAAgDD,CAAG,cAAcC,CAAY,oCAC1C,CAAC,GAAGF,CAAK,EAAE,KAAK,IAAI,CAAC;AAAA,IAAA;AAAA,EAG9D;AACF;AAcO,SAASG,EACdX,GACA1D,GACG;AACH,EAAA+D,EAAmBL,GAAQ1D,CAAO;AAElC,QAAMsE,IAAkBZ,EAAO,MAAM,SAC/Ba,IAAU;AAAA,IACd,GAAI,MAAM,QAAQD,CAAe,IAAIA,EAAgB,KAAA,IAAS,CAAA;AAAA,IAC9DtB,EAA0BhD,CAAO;AAAA,EAAA;AAGnC,SAAO;AAAA,IACL,GAAG0D;AAAA,IACH,MAAM;AAAA,MACJ,GAAGA,EAAO;AAAA,MACV,SAAAa;AAAA,IAAA;AAAA,EACF;AAEJ;"}