@astroscope/i18n 2.1.2 → 3.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.
Files changed (63) hide show
  1. package/README.md +22 -31
  2. package/dist/{babel-plugin-DJZS9L_W.js → babel-plugin-CRgz4mri.js} +2 -3
  3. package/dist/{babel-plugin-DJZS9L_W.js.map → babel-plugin-CRgz4mri.js.map} +1 -1
  4. package/dist/client/translate.d.ts +2 -4
  5. package/dist/client/translate.d.ts.map +1 -1
  6. package/dist/client/translate.js +5 -7
  7. package/dist/client/translate.js.map +1 -1
  8. package/dist/{compiler-CkOVGWU5.js → compiler-K3uHKoFs.js} +2 -3
  9. package/dist/{compiler-CkOVGWU5.js.map → compiler-K3uHKoFs.js.map} +1 -1
  10. package/dist/context-CJvTEa-I.js +18 -0
  11. package/dist/context-CJvTEa-I.js.map +1 -0
  12. package/dist/extraction/index.d.ts +5 -6
  13. package/dist/extraction/index.d.ts.map +1 -1
  14. package/dist/extraction/index.js +2 -2
  15. package/dist/{i18n-Ca5mVXlq.d.ts → i18n-7dnqpAwm.d.ts} +16 -8
  16. package/dist/i18n-7dnqpAwm.d.ts.map +1 -0
  17. package/dist/{context-Cq9-KsBw.js → i18n-f7qdMTwm.js} +8 -25
  18. package/dist/i18n-f7qdMTwm.js.map +1 -0
  19. package/dist/index.d.ts +14 -64
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +20 -15
  22. package/dist/index.js.map +1 -1
  23. package/dist/internal.d.ts +2 -4
  24. package/dist/internal.d.ts.map +1 -1
  25. package/dist/internal.js +3 -1
  26. package/dist/{manifest-X-UhW6tH.js → manifest-DK513NbQ.js} +2 -3
  27. package/dist/{manifest-X-UhW6tH.js.map → manifest-DK513NbQ.js.map} +1 -1
  28. package/dist/{middleware-SkXWqtl3.js → middleware-CNXfXefr.js} +23 -29
  29. package/dist/middleware-CNXfXefr.js.map +1 -0
  30. package/dist/{rich-BDqjhv2h.js → rich-BbDoHrd9.js} +3 -5
  31. package/dist/{rich-BDqjhv2h.js.map → rich-BbDoHrd9.js.map} +1 -1
  32. package/dist/{rich-BWszYAzS.d.ts → rich-CavnJlKg.d.ts} +1 -3
  33. package/dist/rich-CavnJlKg.d.ts.map +1 -0
  34. package/dist/server/chunk-middleware-entrypoint.d.ts +0 -2
  35. package/dist/server/chunk-middleware-entrypoint.d.ts.map +1 -1
  36. package/dist/server/chunk-middleware-entrypoint.js +2 -3
  37. package/dist/server/locale-middleware-entrypoint.d.ts +2 -0
  38. package/dist/server/locale-middleware-entrypoint.d.ts.map +1 -0
  39. package/dist/server/locale-middleware-entrypoint.js +7 -0
  40. package/dist/server/locale-middleware-entrypoint.js.map +1 -0
  41. package/dist/server/translate.d.ts +2 -4
  42. package/dist/server/translate.d.ts.map +1 -1
  43. package/dist/server/translate.js +5 -5
  44. package/dist/server/translate.js.map +1 -1
  45. package/dist/{types-BjTD5hUT.d.ts → types-DYnR9xP3.d.ts} +1 -3
  46. package/dist/types-DYnR9xP3.d.ts.map +1 -0
  47. package/dist/{types-BC-tQ30r.d.ts → types-DwM0qsLj.d.ts} +2 -4
  48. package/dist/types-DwM0qsLj.d.ts.map +1 -0
  49. package/dist/{types-Bo4jMK8g.d.ts → types-ioAI5pu0.d.ts} +7 -3
  50. package/dist/types-ioAI5pu0.d.ts.map +1 -0
  51. package/dist/{url-CifeaDzl.js → url-6HS_IPPA.js} +2 -3
  52. package/dist/{url-CifeaDzl.js.map → url-6HS_IPPA.js.map} +1 -1
  53. package/dist/{vite-plugin-BPYFFBQp.js → vite-plugin-Yc5NP6bs.js} +17 -16
  54. package/dist/vite-plugin-Yc5NP6bs.js.map +1 -0
  55. package/package.json +15 -11
  56. package/dist/context-Cq9-KsBw.js.map +0 -1
  57. package/dist/i18n-Ca5mVXlq.d.ts.map +0 -1
  58. package/dist/middleware-SkXWqtl3.js.map +0 -1
  59. package/dist/rich-BWszYAzS.d.ts.map +0 -1
  60. package/dist/types-BC-tQ30r.d.ts.map +0 -1
  61. package/dist/types-BjTD5hUT.d.ts.map +0 -1
  62. package/dist/types-Bo4jMK8g.d.ts.map +0 -1
  63. package/dist/vite-plugin-BPYFFBQp.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,19 +1,21 @@
1
- import { t as i18nVitePlugin } from "./vite-plugin-BPYFFBQp.js";
2
- import { r as i18n } from "./context-Cq9-KsBw.js";
3
- import { n as createI18nMiddleware } from "./middleware-SkXWqtl3.js";
4
- //#region src/integration/integration.ts
1
+ import { t as i18nVitePlugin } from "./vite-plugin-Yc5NP6bs.js";
2
+ import { t as i18n } from "./i18n-f7qdMTwm.js";
3
+ // src/integration/integration.ts
5
4
  /**
6
5
  * Astro integration for i18n with automatic per-chunk translation loading.
7
6
  *
8
7
  * Registers the vite plugin for translation key extraction, chunk mapping and
9
- * loader injection, and injects the chunk middleware serving `/_i18n/`
10
- * translation chunks. Client state delivery and translation preloading happen at
11
- * runtime: the i18n middleware bootstraps `window.__i18n__`, and the islands
12
- * emitter (via `@astroscope/node`) slices hashes and preloads translation chunks
13
- * per island — plain `client:*` directives, no forks.
8
+ * loader injection, and injects both middlewares: the chunk middleware serving
9
+ * `/_i18n/` translation chunks ahead of the project's own middleware, and the
10
+ * locale middleware after it, so the locale resolver from `i18n.configure` sees
11
+ * what a session middleware put on `locals`. Client state delivery and
12
+ * translation preloading happen at runtime: the locale middleware bootstraps
13
+ * `window.__i18n__`, and the islands emitter (via `@astroscope/node`) slices
14
+ * hashes and preloads translation chunks per island — plain `client:*`
15
+ * directives, no forks.
14
16
  */
15
17
  function i18nIntegration(options = {}) {
16
- const { consistency = "error" } = options;
18
+ const { consistency = "error", exclude = null } = options;
17
19
  return {
18
20
  name: "@astroscope/i18n",
19
21
  hooks: { "astro:config:setup": ({ addMiddleware, updateConfig, logger }) => {
@@ -21,15 +23,19 @@ function i18nIntegration(options = {}) {
21
23
  order: "pre",
22
24
  entrypoint: "@astroscope/i18n/chunk-middleware"
23
25
  });
26
+ addMiddleware({
27
+ order: "post",
28
+ entrypoint: "@astroscope/i18n/locale-middleware"
29
+ });
24
30
  updateConfig({ vite: { plugins: [i18nVitePlugin({
25
31
  logger,
26
- consistency
32
+ consistency,
33
+ exclude
27
34
  })] } });
28
35
  } }
29
36
  };
30
37
  }
31
- //#endregion
32
- //#region src/server/locale.ts
38
+ // src/server/locale.ts
33
39
  /**
34
40
  * Detect locale from Accept-Language header.
35
41
  * Returns best match from configured locales, or undefined if none match.
@@ -49,7 +55,6 @@ function detectLocale(request) {
49
55
  preferred.sort((a, b) => b.q - a.q);
50
56
  for (const { lang } of preferred) if (locales.includes(lang)) return lang;
51
57
  }
52
- //#endregion
53
- export { createI18nMiddleware, i18nIntegration as default, detectLocale, i18n };
58
+ export { i18nIntegration as default, detectLocale, i18n };
54
59
 
55
60
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/integration/integration.ts","../src/server/locale.ts"],"sourcesContent":["import type { AstroIntegration } from 'astro';\nimport { i18nVitePlugin } from '../extraction/vite-plugin.js';\nimport type { I18nOptions } from './types.js';\n\n/**\n * Astro integration for i18n with automatic per-chunk translation loading.\n *\n * Registers the vite plugin for translation key extraction, chunk mapping and\n * loader injection, and injects the chunk middleware serving `/_i18n/`\n * translation chunks. Client state delivery and translation preloading happen at\n * runtime: the i18n middleware bootstraps `window.__i18n__`, and the islands\n * emitter (via `@astroscope/node`) slices hashes and preloads translation chunks\n * per island — plain `client:*` directives, no forks.\n */\nexport default function i18nIntegration(options: I18nOptions = {}): AstroIntegration {\n const { consistency = 'error' } = options;\n\n return {\n name: '@astroscope/i18n',\n hooks: {\n 'astro:config:setup': ({ addMiddleware, updateConfig, logger }) => {\n addMiddleware({ order: 'pre', entrypoint: '@astroscope/i18n/chunk-middleware' });\n\n updateConfig({\n vite: {\n plugins: [i18nVitePlugin({ logger, consistency })],\n },\n });\n },\n },\n };\n}\n","import { i18n } from './i18n.js';\n\n/**\n * Detect locale from Accept-Language header.\n * Returns best match from configured locales, or undefined if none match.\n */\nexport function detectLocale(request: Request): string | undefined {\n if (!i18n.isConfigured()) return undefined;\n\n const { locales } = i18n.getConfig();\n const acceptLanguage = request.headers.get('accept-language');\n\n if (!acceptLanguage) return undefined;\n\n const preferred = acceptLanguage\n .split(',')\n .map((part) => {\n // optional whitespace around `;` is legal per rfc 9110\n const [lang, q = 'q=1'] = part.split(';').map((s) => s.trim());\n const baseLang = lang?.split('-', 1)[0]?.toLowerCase();\n\n return {\n lang: baseLang,\n // eslint-disable-next-line unicorn/prefer-number-coercion -- Number() differs on malformed q values ('' → 0, '0.8x' → NaN)\n q: Number.parseFloat(q.replace('q=', '')),\n };\n })\n .filter((p): p is { lang: string; q: number } => !!p.lang);\n\n preferred.sort((a, b) => b.q - a.q);\n\n for (const { lang } of preferred) {\n if (locales.includes(lang)) {\n return lang;\n }\n }\n\n return undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,SAAwB,gBAAgB,UAAuB,CAAC,GAAqB;CACnF,MAAM,EAAE,cAAc,YAAY;CAElC,OAAO;EACL,MAAM;EACN,OAAO,EACL,uBAAuB,EAAE,eAAe,cAAc,aAAa;GACjE,cAAc;IAAE,OAAO;IAAO,YAAY;GAAoC,CAAC;GAE/E,aAAa,EACX,MAAM,EACJ,SAAS,CAAC,eAAe;IAAE;IAAQ;GAAY,CAAC,CAAC,EACnD,EACF,CAAC;EACH,EACF;CACF;AACF;;;;;;;ACzBA,SAAgB,aAAa,SAAsC;CACjE,IAAI,CAAC,KAAK,aAAa,GAAG,OAAO,KAAA;CAEjC,MAAM,EAAE,YAAY,KAAK,UAAU;CACnC,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,iBAAiB;CAE5D,IAAI,CAAC,gBAAgB,OAAO,KAAA;CAE5B,MAAM,YAAY,eACf,MAAM,GAAG,CAAC,CACV,KAAK,SAAS;EAEb,MAAM,CAAC,MAAM,IAAI,SAAS,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,MAAM,EAAE,KAAK,CAAC;EAG7D,OAAO;GACL,MAHe,MAAM,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,YAAY;GAKnD,GAAG,OAAO,WAAW,EAAE,QAAQ,MAAM,EAAE,CAAC;EAC1C;CACF,CAAC,CAAC,CACD,QAAQ,MAAwC,CAAC,CAAC,EAAE,IAAI;CAE3D,UAAU,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;CAElC,KAAK,MAAM,EAAE,UAAU,WACrB,IAAI,QAAQ,SAAS,IAAI,GACvB,OAAO;AAKb"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/integration/integration.ts","../src/server/locale.ts"],"sourcesContent":["import type { AstroIntegration } from 'astro';\nimport { i18nVitePlugin } from '../extraction/vite-plugin.js';\nimport type { I18nOptions } from './types.js';\n\n/**\n * Astro integration for i18n with automatic per-chunk translation loading.\n *\n * Registers the vite plugin for translation key extraction, chunk mapping and\n * loader injection, and injects both middlewares: the chunk middleware serving\n * `/_i18n/` translation chunks ahead of the project's own middleware, and the\n * locale middleware after it, so the locale resolver from `i18n.configure` sees\n * what a session middleware put on `locals`. Client state delivery and\n * translation preloading happen at runtime: the locale middleware bootstraps\n * `window.__i18n__`, and the islands emitter (via `@astroscope/node`) slices\n * hashes and preloads translation chunks per island — plain `client:*`\n * directives, no forks.\n */\nexport default function i18nIntegration(options: I18nOptions = {}): AstroIntegration {\n const { consistency = 'error', exclude = null } = options;\n\n return {\n name: '@astroscope/i18n',\n hooks: {\n 'astro:config:setup': ({ addMiddleware, updateConfig, logger }) => {\n addMiddleware({ order: 'pre', entrypoint: '@astroscope/i18n/chunk-middleware' });\n addMiddleware({ order: 'post', entrypoint: '@astroscope/i18n/locale-middleware' });\n\n updateConfig({\n vite: {\n plugins: [i18nVitePlugin({ logger, consistency, exclude })],\n },\n });\n },\n },\n };\n}\n","import { i18n } from './i18n.js';\n\n/**\n * Detect locale from Accept-Language header.\n * Returns best match from configured locales, or undefined if none match.\n */\nexport function detectLocale(request: Request): string | undefined {\n if (!i18n.isConfigured()) return undefined;\n\n const { locales } = i18n.getConfig();\n const acceptLanguage = request.headers.get('accept-language');\n\n if (!acceptLanguage) return undefined;\n\n const preferred = acceptLanguage\n .split(',')\n .map((part) => {\n // optional whitespace around `;` is legal per rfc 9110\n const [lang, q = 'q=1'] = part.split(';').map((s) => s.trim());\n const baseLang = lang?.split('-', 1)[0]?.toLowerCase();\n\n return {\n lang: baseLang,\n // eslint-disable-next-line unicorn/prefer-number-coercion -- Number() differs on malformed q values ('' → 0, '0.8x' → NaN)\n q: Number.parseFloat(q.replace('q=', '')),\n };\n })\n .filter((p): p is { lang: string; q: number } => !!p.lang);\n\n preferred.sort((a, b) => b.q - a.q);\n\n for (const { lang } of preferred) {\n if (locales.includes(lang)) {\n return lang;\n }\n }\n\n return undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiBA,SAAwB,gBAAgB,UAAuB,CAAC,GAAqB;CACnF,MAAM,EAAE,cAAc,SAAS,UAAU,SAAS;CAElD,OAAO;EACL,MAAM;EACN,OAAO,EACL,uBAAuB,EAAE,eAAe,cAAc,aAAa;GACjE,cAAc;IAAE,OAAO;IAAO,YAAY;GAAoC,CAAC;GAC/E,cAAc;IAAE,OAAO;IAAQ,YAAY;GAAqC,CAAC;GAEjF,aAAa,EACX,MAAM,EACJ,SAAS,CAAC,eAAe;IAAE;IAAQ;IAAa;GAAQ,CAAC,CAAC,EAC5D,EACF,CAAC;EACH,EACF;CACF;AACF;;;;;;AC7BA,SAAgB,aAAa,SAAsC;CACjE,IAAI,CAAC,KAAK,aAAa,GAAG,OAAO,KAAA;CAEjC,MAAM,EAAE,YAAY,KAAK,UAAU;CACnC,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,iBAAiB;CAE5D,IAAI,CAAC,gBAAgB,OAAO,KAAA;CAE5B,MAAM,YAAY,eACf,MAAM,GAAG,CAAC,CACV,KAAK,SAAS;EAEb,MAAM,CAAC,MAAM,IAAI,SAAS,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,MAAM,EAAE,KAAK,CAAC;EAG7D,OAAO;GACL,MAHe,MAAM,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,YAAY;GAKnD,GAAG,OAAO,WAAW,EAAE,QAAQ,MAAM,EAAE,CAAC;EAC1C;CACF,CAAC,CAAC,CACD,QAAQ,MAAwC,CAAC,CAAC,EAAE,IAAI;CAE3D,UAAU,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;CAElC,KAAK,MAAM,EAAE,UAAU,WACrB,IAAI,QAAQ,SAAS,IAAI,GACvB,OAAO;AAKb"}
@@ -1,10 +1,8 @@
1
- import { n as I18nClientState } from "./types-BjTD5hUT.js";
2
- import { i as I18nContext, n as i18n } from "./i18n-Ca5mVXlq.js";
3
- //#region src/server/context.d.ts
1
+ import { a as I18nContext, r as i18n } from "./i18n-7dnqpAwm.js";
2
+ import { n as I18nClientState } from "./types-DYnR9xP3.js";
4
3
  /**
5
4
  * Get the current i18n context
6
5
  */
7
6
  export declare function getContext(): I18nContext | null;
8
- //#endregion
9
7
  export { type I18nClientState, i18n };
10
8
  //# sourceMappingURL=internal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"internal.d.ts","names":[],"sources":["../src/server/context.ts"],"mappings":";;;;;;wBAegB,cAAc"}
1
+ {"version":3,"file":"internal.d.ts","names":[],"sources":["../src/server/context.ts"],"mappings":";;;;;wBAegB,cAAc"}
package/dist/internal.js CHANGED
@@ -1 +1,3 @@
1
- export { t as getContext, r as i18n } from "./context-Cq9-KsBw.js";
1
+ import { t as getContext } from "./context-CJvTEa-I.js";
2
+ import { t as i18n } from "./i18n-f7qdMTwm.js";
3
+ export { getContext, i18n };
@@ -1,5 +1,5 @@
1
1
  import path from "node:path";
2
- //#region src/extraction/manifest.ts
2
+ // src/extraction/manifest.ts
3
3
  /**
4
4
  * Manifest state management for i18n extraction
5
5
  *
@@ -38,7 +38,6 @@ function getManifest() {
38
38
  scripts: state.scriptChunks
39
39
  };
40
40
  }
41
- //#endregion
42
41
  export { getManifest as n, getGlobalState as t };
43
42
 
44
- //# sourceMappingURL=manifest-X-UhW6tH.js.map
43
+ //# sourceMappingURL=manifest-DK513NbQ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-X-UhW6tH.js","names":[],"sources":["../src/extraction/manifest.ts"],"sourcesContent":["/**\n * Manifest state management for i18n extraction\n *\n * Separated from vite-plugin to avoid bundling Babel at runtime\n */\n\nimport path from 'node:path';\nimport type { ChunkManifest, ExtractedKey, ExtractionManifest } from './types.js';\n\n// global state for dev mode live access via globalThis\n// this allows the virtual module to access current extraction data\n// even after initial import (since dev mode transforms are on-demand)\nconst I18N_MANIFEST_GLOBAL_KEY = '__astroscope_i18n_manifest__';\n\nexport type GlobalI18nState = {\n extractedKeys: ExtractedKey[];\n chunkManifest: ChunkManifest;\n scriptChunks: string[];\n\n // project root for relative paths\n projectRoot: string;\n\n // incremented on each sync to signal cache invalidation\n version: number;\n};\n\nexport function getGlobalState(): GlobalI18nState {\n const g = globalThis as Record<string, unknown>;\n\n g[I18N_MANIFEST_GLOBAL_KEY] ??= {\n extractedKeys: [],\n chunkManifest: {},\n scriptChunks: [],\n projectRoot: '',\n version: 0,\n } satisfies GlobalI18nState;\n\n return g[I18N_MANIFEST_GLOBAL_KEY] as GlobalI18nState;\n}\n\n/**\n * Get the current extraction manifest (for dev mode live access).\n * This bypasses Vite's module caching to return fresh data.\n */\nexport function getManifest(): ExtractionManifest {\n const state = getGlobalState();\n\n const keys = state.extractedKeys.map((key) => ({\n ...key,\n // make file paths relative to project root for better readability\n // and avoiding leaking absolute paths from dev or ci environments\n files: key.files.map((fileLocation) => {\n // split on the trailing `:line` only — the path itself may contain colons (windows drive letters)\n const match = /^(.+):(\\d+)$/.exec(fileLocation);\n const [filePath, line] = match ? [match[1], match[2]] : [fileLocation, undefined];\n\n if (!filePath) return fileLocation;\n\n const relativePath = state.projectRoot ? path.relative(state.projectRoot, filePath) : filePath;\n\n return line ? `${relativePath}:${line}` : relativePath;\n }),\n }));\n\n return { keys, chunks: state.chunkManifest, scripts: state.scriptChunks };\n}\n"],"mappings":";;;;;;;AAYA,MAAM,2BAA2B;AAcjC,SAAgB,iBAAkC;CAChD,MAAM,IAAI;CAEV,EAAE,8BAA8B;EAC9B,eAAe,CAAC;EAChB,eAAe,CAAC;EAChB,cAAc,CAAC;EACf,aAAa;EACb,SAAS;CACX;CAEA,OAAO,EAAE;AACX;;;;;AAMA,SAAgB,cAAkC;CAChD,MAAM,QAAQ,eAAe;CAmB7B,OAAO;EAAE,MAjBI,MAAM,cAAc,KAAK,SAAS;GAC7C,GAAG;GAGH,OAAO,IAAI,MAAM,KAAK,iBAAiB;IAErC,MAAM,QAAQ,eAAe,KAAK,YAAY;IAC9C,MAAM,CAAC,UAAU,QAAQ,QAAQ,CAAC,MAAM,IAAI,MAAM,EAAE,IAAI,CAAC,cAAc,KAAA,CAAS;IAEhF,IAAI,CAAC,UAAU,OAAO;IAEtB,MAAM,eAAe,MAAM,cAAc,KAAK,SAAS,MAAM,aAAa,QAAQ,IAAI;IAEtF,OAAO,OAAO,GAAG,aAAa,GAAG,SAAS;GAC5C,CAAC;EACH,EAEY;EAAG,QAAQ,MAAM;EAAe,SAAS,MAAM;CAAa;AAC1E"}
1
+ {"version":3,"file":"manifest-DK513NbQ.js","names":[],"sources":["../src/extraction/manifest.ts"],"sourcesContent":["/**\n * Manifest state management for i18n extraction\n *\n * Separated from vite-plugin to avoid bundling Babel at runtime\n */\n\nimport path from 'node:path';\nimport type { ChunkManifest, ExtractedKey, ExtractionManifest } from './types.js';\n\n// global state for dev mode live access via globalThis\n// this allows the virtual module to access current extraction data\n// even after initial import (since dev mode transforms are on-demand)\nconst I18N_MANIFEST_GLOBAL_KEY = '__astroscope_i18n_manifest__';\n\nexport type GlobalI18nState = {\n extractedKeys: ExtractedKey[];\n chunkManifest: ChunkManifest;\n scriptChunks: string[];\n\n // project root for relative paths\n projectRoot: string;\n\n // incremented on each sync to signal cache invalidation\n version: number;\n};\n\nexport function getGlobalState(): GlobalI18nState {\n const g = globalThis as Record<string, unknown>;\n\n g[I18N_MANIFEST_GLOBAL_KEY] ??= {\n extractedKeys: [],\n chunkManifest: {},\n scriptChunks: [],\n projectRoot: '',\n version: 0,\n } satisfies GlobalI18nState;\n\n return g[I18N_MANIFEST_GLOBAL_KEY] as GlobalI18nState;\n}\n\n/**\n * Get the current extraction manifest (for dev mode live access).\n * This bypasses Vite's module caching to return fresh data.\n */\nexport function getManifest(): ExtractionManifest {\n const state = getGlobalState();\n\n const keys = state.extractedKeys.map((key) => ({\n ...key,\n // make file paths relative to project root for better readability\n // and avoiding leaking absolute paths from dev or ci environments\n files: key.files.map((fileLocation) => {\n // split on the trailing `:line` only — the path itself may contain colons (windows drive letters)\n const match = /^(.+):(\\d+)$/.exec(fileLocation);\n const [filePath, line] = match ? [match[1], match[2]] : [fileLocation, undefined];\n\n if (!filePath) return fileLocation;\n\n const relativePath = state.projectRoot ? path.relative(state.projectRoot, filePath) : filePath;\n\n return line ? `${relativePath}:${line}` : relativePath;\n }),\n }));\n\n return { keys, chunks: state.chunkManifest, scripts: state.scriptChunks };\n}\n"],"mappings":";;;;;;;AAYA,MAAM,2BAA2B;AAcjC,SAAgB,iBAAkC;CAChD,MAAM,IAAI;CAEV,EAAE,8BAA8B;EAC9B,eAAe,CAAC;EAChB,eAAe,CAAC;EAChB,cAAc,CAAC;EACf,aAAa;EACb,SAAS;CACX;CAEA,OAAO,EAAE;AACX;;;;;AAMA,SAAgB,cAAkC;CAChD,MAAM,QAAQ,eAAe;CAmB7B,OAAO;EAAE,MAjBI,MAAM,cAAc,KAAK,SAAS;GAC7C,GAAG;GAGH,OAAO,IAAI,MAAM,KAAK,iBAAiB;IAErC,MAAM,QAAQ,eAAe,KAAK,YAAY;IAC9C,MAAM,CAAC,UAAU,QAAQ,QAAQ,CAAC,MAAM,IAAI,MAAM,EAAE,IAAI,CAAC,cAAc,KAAA,CAAS;IAEhF,IAAI,CAAC,UAAU,OAAO;IAEtB,MAAM,eAAe,MAAM,cAAc,KAAK,SAAS,MAAM,aAAa,QAAQ,IAAI;IAEtF,OAAO,OAAO,GAAG,aAAa,GAAG,SAAS;GAC5C,CAAC;EACH,EAEY;EAAG,QAAQ,MAAM;EAAe,SAAS,MAAM;CAAa;AAC1E"}
@@ -1,9 +1,10 @@
1
- import { t as buildI18nChunkUrl } from "./url-CifeaDzl.js";
2
- import { n as runWithContext, r as i18n } from "./context-Cq9-KsBw.js";
1
+ import { n as runWithContext } from "./context-CJvTEa-I.js";
2
+ import { t as i18n } from "./i18n-f7qdMTwm.js";
3
+ import { t as buildI18nChunkUrl } from "./url-6HS_IPPA.js";
3
4
  import { RECOMMENDED_EXCLUDES, shouldExclude } from "@astroscope/node/excludes";
4
- import { log, overrideRequestRoute } from "@astroscope/node/log";
5
5
  import { registerDocumentEmitter, registerIslandEmitter } from "@astroscope/node/islands";
6
- //#region src/server/client-state.ts
6
+ import { log, overrideRequestRoute } from "@astroscope/node/log";
7
+ // src/server/client-state.ts
7
8
  /**
8
9
  * Scripts bootstrapping `window.__i18n__` on html responses, delivered through the
9
10
  * `@astroscope/node` document emitter (see islands-emitter.ts for the placement
@@ -32,8 +33,7 @@ function createScriptHashesScript(locale) {
32
33
  translations: {}
33
34
  })};Object.assign(i.hashes,${jsonForScript(hashes)});}<\/script>`;
34
35
  }
35
- //#endregion
36
- //#region src/server/islands-emitter.ts
36
+ // src/server/islands-emitter.ts
37
37
  /**
38
38
  * Contributes the i18n slice for each island the `@astroscope/node` islands
39
39
  * middleware streams past:
@@ -156,8 +156,7 @@ function registerI18nEmitters() {
156
156
  };
157
157
  });
158
158
  }
159
- //#endregion
160
- //#region src/server/middleware.ts
159
+ // src/server/middleware.ts
161
160
  const I18N_ENDPOINT_PREFIX = "/_i18n/";
162
161
  const I18N_ENDPOINT_ROUTE = "/_i18n/[locale]/[chunk]";
163
162
  /**
@@ -217,43 +216,38 @@ function createI18nChunkMiddleware() {
217
216
  /**
218
217
  * Create the i18n locale middleware.
219
218
  *
220
- * Sets up the request context with locale and translations for `t()`, injects
221
- * the client i18n state into html responses, and records the locale for the
222
- * islands emitter. Place this after session middleware if your locale detection
223
- * depends on session/cookies.
219
+ * Resolves the request's locale through the resolver from `i18n.configure({ locale })`
220
+ * (the default locale when there is none or it returns `undefined`), sets up the
221
+ * request context for `t()`, records the locale for the islands emitter, which
222
+ * delivers the client state, and runs the rest of the chain inside that context.
224
223
  *
225
- * @example
226
- * ```typescript
227
- * import { createI18nMiddleware, detectLocale, i18n } from '@astroscope/i18n';
224
+ * Injected by the integration as `post` middleware, after the project's own, so the
225
+ * resolver sees whatever a session middleware put on `locals` — not part of the
226
+ * public API.
228
227
  *
229
- * export const i18nMiddleware = createI18nMiddleware({
230
- * locale: (ctx) =>
231
- * ctx.cookies.get('locale')?.value ??
232
- * detectLocale(ctx.request) ??
233
- * i18n.getConfig().defaultLocale,
234
- * });
235
- * ```
228
+ * @internal
236
229
  */
237
- function createI18nMiddleware(options) {
230
+ function createI18nLocaleMiddleware(options = {}) {
238
231
  registerI18nEmitters();
232
+ const exclude = options.exclude ?? RECOMMENDED_EXCLUDES;
239
233
  return (ctx, next) => {
240
- if (shouldExclude(ctx, options.exclude ?? RECOMMENDED_EXCLUDES)) return next();
234
+ if (shouldExclude(ctx, exclude)) return next();
241
235
  if (!i18n.isConfigured()) {
242
236
  log.error("i18n not configured, passing through");
243
237
  return next();
244
238
  }
245
- const locale = options.locale(ctx);
239
+ const config = i18n.getConfig();
240
+ const locale = config.locale?.(ctx) ?? config.defaultLocale;
246
241
  setRequestLocale(ctx, locale);
247
242
  const context = {
248
243
  locale,
249
244
  translations: i18n.getCompiledTranslations(locale),
250
245
  rawTranslations: i18n.getTranslations(locale),
251
- fallback: i18n.getConfig().fallback
246
+ fallback: config.fallback
252
247
  };
253
248
  return runWithContext(context, () => next());
254
249
  };
255
250
  }
256
- //#endregion
257
- export { createI18nMiddleware as n, createI18nChunkMiddleware as t };
251
+ export { createI18nLocaleMiddleware as n, createI18nChunkMiddleware as t };
258
252
 
259
- //# sourceMappingURL=middleware-SkXWqtl3.js.map
253
+ //# sourceMappingURL=middleware-CNXfXefr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware-CNXfXefr.js","names":[],"sources":["../src/server/client-state.ts","../src/server/islands-emitter.ts","../src/server/middleware.ts"],"sourcesContent":["import { i18n } from './i18n.js';\n\n/**\n * Scripts bootstrapping `window.__i18n__` on html responses, delivered through the\n * `@astroscope/node` document emitter (see islands-emitter.ts for the placement\n * policy). Both writers merge orderlessly (`??=` + assign), so emitter scripts and\n * the bootstrap can arrive in either order.\n */\n\n/** translation values may contain `</script>` — escape `<` so they cannot end the tag */\nexport function jsonForScript(value: unknown): string {\n return JSON.stringify(value).replaceAll('<', String.raw`\\u003c`);\n}\n\n/** the full dev-mode state: every translation for the locale */\nexport function createFullStateScript(locale: string): string {\n const translations = i18n.getTranslations(locale);\n const state = jsonForScript({ locale, hashes: {}, translations });\n\n return `<script>window.__i18n__=Object.assign(window.__i18n__??{hashes:{},translations:{}},${state});</script>`;\n}\n\n/** the prod bootstrap: chunk hashes for astro `<script>` entry consumers */\nexport function createScriptHashesScript(locale: string): string | null {\n const hashes = i18n.getScriptChunkHashes(locale);\n\n if (Object.keys(hashes).length === 0) {\n return null;\n }\n\n const init = jsonForScript({ locale, hashes: {}, translations: {} });\n\n return `<script>{const i=window.__i18n__??=${init};Object.assign(i.hashes,${jsonForScript(hashes)});}</script>`;\n}\n","import {\n type DocumentEmitter,\n type IslandInfo,\n registerDocumentEmitter,\n registerIslandEmitter,\n} from '@astroscope/node/islands';\nimport type { APIContext } from 'astro';\nimport { buildI18nChunkUrl } from '../shared/url.js';\nimport { createFullStateScript, createScriptHashesScript, jsonForScript } from './client-state.js';\nimport { i18n } from './i18n.js';\n\n/**\n * Contributes the i18n slice for each island the `@astroscope/node` islands\n * middleware streams past:\n *\n * - an inline merge script with the hashes of the island's full chunk closure —\n * dynamic imports included, since a `React.lazy` chunk's injected loader reads\n * its hash at execution time. Emitted before the island tag, it is parsed\n * strictly before the island connects, and the island's chunks execute at\n * least a network round-trip later — so each island's hashes win their race\n * even while the rest of the document is still streaming. Chunks already\n * covered earlier in the document are skipped.\n * - translation-chunk preload links for the static closure (link tags on\n * immediate islands).\n * - translation-chunk eager imports for the full closure, dynamic chunks\n * included, fired by the deferred gate: the chunks are idempotent data\n * modules, so early evaluation is free and the loader's awaited import hits\n * the module cache instead of fetching after the component graph evaluated.\n * No per-document dedup — a shared chunk is covered by whichever island's\n * gate fires first.\n *\n * The locale is recorded per request by the i18n middleware — the emitter runs\n * while the response streams, outside the middleware's AsyncLocalStorage scope.\n * It is keyed on `context.locals`, the one object astro keeps for the whole\n * request: `context.request` is replaced by every `next(url)` rewrite, once per\n * nesting level of `sequence`, so the request the middleware saw is not the one\n * the islands middleware holds when the emitters run.\n */\n\nconst requestLocales = new WeakMap<object, string>();\nconst emittedByRequest = new WeakMap<object, Set<string>>();\n\n// vite defines import.meta.env when bundling the middleware; typed structurally\n// so the package compiles without vite's global client types\nconst IS_DEV = !!(import.meta as { env?: { DEV?: boolean } }).env?.DEV;\n\nlet registered = false;\n\nexport function setRequestLocale(context: APIContext, locale: string): void {\n requestLocales.set(context.locals, locale);\n}\n\n/** public url of a chunk → manifest chunk name, e.g. `…/_astro/Cart.abc.js` → `Cart.abc` */\nfunction urlToChunkName(url: string): string {\n return url.slice(url.lastIndexOf('/') + 1).replace(/\\.js$/, '');\n}\n\n/** an island's translated chunks and their urls for one locale */\ntype IslandSlice = {\n /** full closure: what the merge script covers */\n chunks: [name: string, hash: string][];\n /** static closure: preload links */\n links: string[];\n /** full closure: eager imports */\n imports: string[];\n};\n\n// islands arrive as the same object per component/renderer/directive and the\n// hashes object is replaced whenever translations change, so keying on both\n// caches each slice for exactly as long as it is valid\nconst slices = new WeakMap<Record<string, string>, WeakMap<IslandInfo, IslandSlice>>();\nconst inits = new Map<string, string>();\n\nfunction sliceFor(island: IslandInfo, locale: string, hashes: Record<string, string>): IslandSlice {\n let byIsland = slices.get(hashes);\n\n if (!byIsland) {\n byIsland = new WeakMap();\n slices.set(hashes, byIsland);\n }\n\n let slice = byIsland.get(island);\n\n if (slice) {\n return slice;\n }\n\n const translated = (urls: string[]): [string, string][] => {\n const result: [string, string][] = [];\n\n for (const url of urls) {\n const chunk = urlToChunkName(url);\n const hash = hashes[chunk];\n\n if (hash) {\n result.push([chunk, hash]);\n }\n }\n\n return result;\n };\n\n const chunks = translated(island.fullClosure);\n\n slice = {\n chunks,\n links: translated(island.staticClosure).map(([chunk, hash]) => buildI18nChunkUrl(locale, chunk, hash)),\n imports: chunks.map(([chunk, hash]) => buildI18nChunkUrl(locale, chunk, hash)),\n };\n byIsland.set(island, slice);\n\n return slice;\n}\n\nfunction initFor(locale: string): string {\n let init = inits.get(locale);\n\n if (init === undefined) {\n init = jsonForScript({ locale, hashes: {}, translations: {} });\n inits.set(locale, init);\n }\n\n return init;\n}\n\n/**\n * The document-level bootstrap for `window.__i18n__`, exported for tests.\n */\nexport function createI18nDocumentEmitter(dev: boolean = IS_DEV): DocumentEmitter {\n return (context) => {\n if (!i18n.isConfigured()) {\n return null;\n }\n\n const locale = requestLocales.get(context.locals);\n\n if (locale === undefined) {\n return null;\n }\n\n if (dev) {\n return { head: createFullStateScript(locale) };\n }\n\n if (Object.keys(i18n.getManifest().chunks).length === 0) {\n return null;\n }\n\n return { end: () => createScriptHashesScript(locale) };\n };\n}\n\nexport function registerI18nEmitters(): void {\n if (registered) {\n return;\n }\n\n registered = true;\n\n registerDocumentEmitter(createI18nDocumentEmitter());\n\n registerIslandEmitter((island, context) => {\n // no request context (prerendered build pass) — the locale is unknowable\n if (!context || !i18n.isConfigured()) {\n return null;\n }\n\n const locale = requestLocales.get(context.locals);\n\n if (locale === undefined) {\n return null;\n }\n\n const hashes = i18n.getHashes(locale);\n const { chunks, links, imports } = sliceFor(island, locale, hashes);\n\n let emitted = emittedByRequest.get(context.locals);\n\n if (!emitted) {\n emitted = new Set();\n emittedByRequest.set(context.locals, emitted);\n }\n\n const merge: Record<string, string> = {};\n let fresh = false;\n\n for (const [chunk, hash] of chunks) {\n if (emitted.has(chunk)) {\n continue;\n }\n\n emitted.add(chunk);\n merge[chunk] = hash;\n fresh = true;\n }\n\n const html = fresh\n ? `<script>{const i=window.__i18n__??=${initFor(locale)};Object.assign(i.hashes,${jsonForScript(merge)});}</script>`\n : undefined;\n\n if (!html && links.length === 0 && imports.length === 0) {\n return null;\n }\n\n return {\n html,\n links: links.length > 0 ? links : undefined,\n imports: imports.length > 0 ? imports : undefined,\n };\n });\n}\n","import { type ExcludePattern, RECOMMENDED_EXCLUDES, shouldExclude } from '@astroscope/node/excludes';\nimport { log, overrideRequestRoute } from '@astroscope/node/log';\nimport type { MiddlewareHandler } from 'astro';\nimport { runWithContext } from './context.js';\nimport { i18n } from './i18n.js';\nimport { registerI18nEmitters, setRequestLocale } from './islands-emitter.js';\nimport type { I18nContext } from './types.js';\n\nexport type I18nLocaleMiddlewareOptions = {\n /** patterns to skip locale context setup for; defaults to RECOMMENDED_EXCLUDES */\n exclude?: ExcludePattern[] | undefined;\n};\n\nconst I18N_ENDPOINT_PREFIX = '/_i18n/';\n\n// astro has no route behind the chunk endpoint, so requests would otherwise be\n// logged and measured under whatever routing matched — typically `/404`\nconst I18N_ENDPOINT_ROUTE = '/_i18n/[locale]/[chunk]';\n\n/**\n * Serve a translation chunk. Returns `undefined` when the path isn't a chunk\n * request, and the caller passes it on to astro.\n */\nfunction createChunkResponse(pathname: string): Response | undefined {\n if (!pathname.startsWith(I18N_ENDPOINT_PREFIX)) {\n return undefined;\n }\n\n if (!i18n.isConfigured()) {\n log.error('i18n not configured, passing through');\n\n return undefined;\n }\n\n const path = pathname.slice(I18N_ENDPOINT_PREFIX.length);\n\n // {locale}/{chunkName}.{hash}.js — sliced by hand, this runs for every chunk request\n const slashIdx = path.indexOf('/');\n\n if (slashIdx === -1) {\n return undefined;\n }\n\n const locale = path.slice(0, slashIdx);\n\n // validate locale against configured locales to prevent arbitrary locale injection\n const config = i18n.getConfig();\n\n if (!config.locales.includes(locale)) {\n return new Response('/* unknown locale */', {\n status: 404,\n headers: { 'Content-Type': 'application/javascript' },\n });\n }\n\n const rest = path.slice(slashIdx + 1);\n\n if (!rest.endsWith('.js')) {\n return undefined;\n }\n\n const withoutJs = rest.slice(0, -3);\n const lastDotIdx = withoutJs.lastIndexOf('.');\n\n if (lastDotIdx === -1) {\n return undefined;\n }\n\n const chunkName = withoutJs.slice(0, lastDotIdx);\n const body = i18n.getChunkBody(locale, chunkName);\n\n if (!body) {\n return new Response(`/* chunk not found: ${chunkName} */`, {\n status: 404,\n headers: { 'Content-Type': 'application/javascript' },\n });\n }\n\n return new Response(body as BodyInit, {\n status: 200,\n headers: {\n 'Content-Type': 'text/javascript; charset=utf-8',\n 'Content-Length': String(body.byteLength),\n 'Cache-Control': 'public, max-age=31536000, immutable',\n },\n });\n}\n\n/**\n * Create the i18n chunk middleware that serves translation chunks at `/_i18n/` endpoints.\n *\n * Injected by the integration as `pre` middleware (before any user middleware) —\n * not part of the public API.\n *\n * @internal\n */\nexport function createI18nChunkMiddleware(): MiddlewareHandler {\n return (ctx, next) => {\n const response = createChunkResponse(ctx.url.pathname);\n\n if (!response) {\n return next();\n }\n\n // this middleware, not astro's routing, is what serves the request\n overrideRequestRoute(I18N_ENDPOINT_ROUTE);\n\n return response;\n };\n}\n\n/**\n * Create the i18n locale middleware.\n *\n * Resolves the request's locale through the resolver from `i18n.configure({ locale })`\n * (the default locale when there is none or it returns `undefined`), sets up the\n * request context for `t()`, records the locale for the islands emitter, which\n * delivers the client state, and runs the rest of the chain inside that context.\n *\n * Injected by the integration as `post` middleware, after the project's own, so the\n * resolver sees whatever a session middleware put on `locals` — not part of the\n * public API.\n *\n * @internal\n */\nexport function createI18nLocaleMiddleware(options: I18nLocaleMiddlewareOptions = {}): MiddlewareHandler {\n registerI18nEmitters();\n\n const exclude = options.exclude ?? RECOMMENDED_EXCLUDES;\n\n return (ctx, next) => {\n if (shouldExclude(ctx, exclude)) {\n return next();\n }\n\n if (!i18n.isConfigured()) {\n log.error('i18n not configured, passing through');\n\n return next();\n }\n\n const config = i18n.getConfig();\n const locale = config.locale?.(ctx) ?? config.defaultLocale;\n\n // the islands emitter runs while the response streams, outside this ALS scope\n setRequestLocale(ctx, locale);\n\n const context: I18nContext = {\n locale,\n translations: i18n.getCompiledTranslations(locale),\n rawTranslations: i18n.getTranslations(locale),\n fallback: config.fallback,\n };\n\n return runWithContext(context, () => next());\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAUA,SAAgB,cAAc,OAAwB;CACpD,OAAO,KAAK,UAAU,KAAK,CAAC,CAAC,WAAW,KAAK,OAAO,GAAG,QAAQ;AACjE;;AAGA,SAAgB,sBAAsB,QAAwB;CAI5D,OAAO,sFAFO,cAAc;EAAE;EAAQ,QAAQ,CAAC;EAAG,cAD7B,KAAK,gBAAgB,MACmB;CAAE,CAEkC,EAAE;AACrG;;AAGA,SAAgB,yBAAyB,QAA+B;CACtE,MAAM,SAAS,KAAK,qBAAqB,MAAM;CAE/C,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,WAAW,GACjC,OAAO;CAKT,OAAO,sCAFM,cAAc;EAAE;EAAQ,QAAQ,CAAC;EAAG,cAAc,CAAC;CAAE,CAElB,EAAE,0BAA0B,cAAc,MAAM,EAAE;AACpG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACMA,MAAM,iCAAiB,IAAI,QAAwB;AACnD,MAAM,mCAAmB,IAAI,QAA6B;AAI1D,MAAM,SAAS,CAAC,CAAE,YAA4C,KAAK;AAEnE,IAAI,aAAa;AAEjB,SAAgB,iBAAiB,SAAqB,QAAsB;CAC1E,eAAe,IAAI,QAAQ,QAAQ,MAAM;AAC3C;;AAGA,SAAS,eAAe,KAAqB;CAC3C,OAAO,IAAI,MAAM,IAAI,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,SAAS,EAAE;AAChE;AAeA,MAAM,yBAAS,IAAI,QAAkE;AACrF,MAAM,wBAAQ,IAAI,IAAoB;AAEtC,SAAS,SAAS,QAAoB,QAAgB,QAA6C;CACjG,IAAI,WAAW,OAAO,IAAI,MAAM;CAEhC,IAAI,CAAC,UAAU;EACb,2BAAW,IAAI,QAAQ;EACvB,OAAO,IAAI,QAAQ,QAAQ;CAC7B;CAEA,IAAI,QAAQ,SAAS,IAAI,MAAM;CAE/B,IAAI,OACF,OAAO;CAGT,MAAM,cAAc,SAAuC;EACzD,MAAM,SAA6B,CAAC;EAEpC,KAAK,MAAM,OAAO,MAAM;GACtB,MAAM,QAAQ,eAAe,GAAG;GAChC,MAAM,OAAO,OAAO;GAEpB,IAAI,MACF,OAAO,KAAK,CAAC,OAAO,IAAI,CAAC;EAE7B;EAEA,OAAO;CACT;CAEA,MAAM,SAAS,WAAW,OAAO,WAAW;CAE5C,QAAQ;EACN;EACA,OAAO,WAAW,OAAO,aAAa,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,kBAAkB,QAAQ,OAAO,IAAI,CAAC;EACrG,SAAS,OAAO,KAAK,CAAC,OAAO,UAAU,kBAAkB,QAAQ,OAAO,IAAI,CAAC;CAC/E;CACA,SAAS,IAAI,QAAQ,KAAK;CAE1B,OAAO;AACT;AAEA,SAAS,QAAQ,QAAwB;CACvC,IAAI,OAAO,MAAM,IAAI,MAAM;CAE3B,IAAI,SAAS,KAAA,GAAW;EACtB,OAAO,cAAc;GAAE;GAAQ,QAAQ,CAAC;GAAG,cAAc,CAAC;EAAE,CAAC;EAC7D,MAAM,IAAI,QAAQ,IAAI;CACxB;CAEA,OAAO;AACT;;;;AAKA,SAAgB,0BAA0B,MAAe,QAAyB;CAChF,QAAQ,YAAY;EAClB,IAAI,CAAC,KAAK,aAAa,GACrB,OAAO;EAGT,MAAM,SAAS,eAAe,IAAI,QAAQ,MAAM;EAEhD,IAAI,WAAW,KAAA,GACb,OAAO;EAGT,IAAI,KACF,OAAO,EAAE,MAAM,sBAAsB,MAAM,EAAE;EAG/C,IAAI,OAAO,KAAK,KAAK,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,GACpD,OAAO;EAGT,OAAO,EAAE,WAAW,yBAAyB,MAAM,EAAE;CACvD;AACF;AAEA,SAAgB,uBAA6B;CAC3C,IAAI,YACF;CAGF,aAAa;CAEb,wBAAwB,0BAA0B,CAAC;CAEnD,uBAAuB,QAAQ,YAAY;EAEzC,IAAI,CAAC,WAAW,CAAC,KAAK,aAAa,GACjC,OAAO;EAGT,MAAM,SAAS,eAAe,IAAI,QAAQ,MAAM;EAEhD,IAAI,WAAW,KAAA,GACb,OAAO;EAIT,MAAM,EAAE,QAAQ,OAAO,YAAY,SAAS,QAAQ,QADrC,KAAK,UAAU,MACmC,CAAC;EAElE,IAAI,UAAU,iBAAiB,IAAI,QAAQ,MAAM;EAEjD,IAAI,CAAC,SAAS;GACZ,0BAAU,IAAI,IAAI;GAClB,iBAAiB,IAAI,QAAQ,QAAQ,OAAO;EAC9C;EAEA,MAAM,QAAgC,CAAC;EACvC,IAAI,QAAQ;EAEZ,KAAK,MAAM,CAAC,OAAO,SAAS,QAAQ;GAClC,IAAI,QAAQ,IAAI,KAAK,GACnB;GAGF,QAAQ,IAAI,KAAK;GACjB,MAAM,SAAS;GACf,QAAQ;EACV;EAEA,MAAM,OAAO,QACT,sCAAsC,QAAQ,MAAM,EAAE,0BAA0B,cAAc,KAAK,EAAE,iBACrG,KAAA;EAEJ,IAAI,CAAC,QAAQ,MAAM,WAAW,KAAK,QAAQ,WAAW,GACpD,OAAO;EAGT,OAAO;GACL;GACA,OAAO,MAAM,SAAS,IAAI,QAAQ,KAAA;GAClC,SAAS,QAAQ,SAAS,IAAI,UAAU,KAAA;EAC1C;CACF,CAAC;AACH;;ACrMA,MAAM,uBAAuB;AAI7B,MAAM,sBAAsB;;;;;AAM5B,SAAS,oBAAoB,UAAwC;CACnE,IAAI,CAAC,SAAS,WAAW,oBAAoB,GAC3C;CAGF,IAAI,CAAC,KAAK,aAAa,GAAG;EACxB,IAAI,MAAM,sCAAsC;EAEhD;CACF;CAEA,MAAM,OAAO,SAAS,MAAM,CAA2B;CAGvD,MAAM,WAAW,KAAK,QAAQ,GAAG;CAEjC,IAAI,aAAa,IACf;CAGF,MAAM,SAAS,KAAK,MAAM,GAAG,QAAQ;CAKrC,IAAI,CAFW,KAAK,UAEV,CAAC,CAAC,QAAQ,SAAS,MAAM,GACjC,OAAO,IAAI,SAAS,wBAAwB;EAC1C,QAAQ;EACR,SAAS,EAAE,gBAAgB,yBAAyB;CACtD,CAAC;CAGH,MAAM,OAAO,KAAK,MAAM,WAAW,CAAC;CAEpC,IAAI,CAAC,KAAK,SAAS,KAAK,GACtB;CAGF,MAAM,YAAY,KAAK,MAAM,GAAG,EAAE;CAClC,MAAM,aAAa,UAAU,YAAY,GAAG;CAE5C,IAAI,eAAe,IACjB;CAGF,MAAM,YAAY,UAAU,MAAM,GAAG,UAAU;CAC/C,MAAM,OAAO,KAAK,aAAa,QAAQ,SAAS;CAEhD,IAAI,CAAC,MACH,OAAO,IAAI,SAAS,uBAAuB,UAAU,MAAM;EACzD,QAAQ;EACR,SAAS,EAAE,gBAAgB,yBAAyB;CACtD,CAAC;CAGH,OAAO,IAAI,SAAS,MAAkB;EACpC,QAAQ;EACR,SAAS;GACP,gBAAgB;GAChB,kBAAkB,OAAO,KAAK,UAAU;GACxC,iBAAiB;EACnB;CACF,CAAC;AACH;;;;;;;;;AAUA,SAAgB,4BAA+C;CAC7D,QAAQ,KAAK,SAAS;EACpB,MAAM,WAAW,oBAAoB,IAAI,IAAI,QAAQ;EAErD,IAAI,CAAC,UACH,OAAO,KAAK;EAId,qBAAqB,mBAAmB;EAExC,OAAO;CACT;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,2BAA2B,UAAuC,CAAC,GAAsB;CACvG,qBAAqB;CAErB,MAAM,UAAU,QAAQ,WAAW;CAEnC,QAAQ,KAAK,SAAS;EACpB,IAAI,cAAc,KAAK,OAAO,GAC5B,OAAO,KAAK;EAGd,IAAI,CAAC,KAAK,aAAa,GAAG;GACxB,IAAI,MAAM,sCAAsC;GAEhD,OAAO,KAAK;EACd;EAEA,MAAM,SAAS,KAAK,UAAU;EAC9B,MAAM,SAAS,OAAO,SAAS,GAAG,KAAK,OAAO;EAG9C,iBAAiB,KAAK,MAAM;EAE5B,MAAM,UAAuB;GAC3B;GACA,cAAc,KAAK,wBAAwB,MAAM;GACjD,iBAAiB,KAAK,gBAAgB,MAAM;GAC5C,UAAU,OAAO;EACnB;EAEA,OAAO,eAAe,eAAe,KAAK,CAAC;CAC7C;AACF"}
@@ -1,12 +1,11 @@
1
- //#region src/shared/meta.ts
1
+ // src/shared/meta.ts
2
2
  /**
3
3
  * Normalize meta argument to TranslationMeta object
4
4
  */
5
5
  function normalizeMeta(meta) {
6
6
  return typeof meta === "string" ? { fallback: meta } : meta;
7
7
  }
8
- //#endregion
9
- //#region src/shared/rich.ts
8
+ // src/shared/rich.ts
10
9
  const REACT_ELEMENT_TYPE = Symbol.for("react.element");
11
10
  const REACT_TRANSITIONAL_ELEMENT_TYPE = Symbol.for("react.transitional.element");
12
11
  /**
@@ -92,7 +91,6 @@ function partsToNodes(parts, components) {
92
91
  }
93
92
  return result;
94
93
  }
95
- //#endregion
96
94
  export { normalizeMeta as n, partsToNodes as t };
97
95
 
98
- //# sourceMappingURL=rich-BDqjhv2h.js.map
96
+ //# sourceMappingURL=rich-BbDoHrd9.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rich-BDqjhv2h.js","names":[],"sources":["../src/shared/meta.ts","../src/shared/rich.ts"],"sourcesContent":["import type { TranslationMeta } from './types.js';\n\n/**\n * Normalize meta argument to TranslationMeta object\n */\nexport function normalizeMeta(meta: TranslationMeta | string): TranslationMeta {\n return typeof meta === 'string' ? { fallback: meta } : meta;\n}\n","import type { MessageMarkupPart, MessagePart } from 'messageformat';\n\n// MessagePart<string> covers all built-in part types\ntype Part = MessagePart<string>;\n\n/**\n * Component callbacks for rich text rendering.\n * Each key maps to a function that wraps children in a component.\n *\n * @example\n * ```tsx\n * const components: RichComponents = {\n * link: (children) => <a href=\"/tos\">{children}</a>,\n * bold: (children) => <strong>{children}</strong>,\n * };\n * ```\n */\nexport type RichComponents<T = unknown> = Record<string, (children: (string | T)[]) => T>;\n\ntype StackFrame<T> = {\n name: string;\n children: (string | T)[];\n};\n\n// react element symbols - Symbol.for() returns the same symbol React uses internally\nconst REACT_ELEMENT_TYPE = Symbol.for('react.element');\nconst REACT_TRANSITIONAL_ELEMENT_TYPE = Symbol.for('react.transitional.element');\n\ntype ReactElementLike = {\n $$typeof: symbol;\n key: string | null;\n};\n\n/**\n * Duck-type check for React elements without importing React.\n * Uses Symbol.for() which returns the same symbol React uses internally.\n */\nfunction isReactElement(value: unknown): value is ReactElementLike {\n if (typeof value !== 'object' || value === null || !('$$typeof' in value)) {\n return false;\n }\n\n const type = (value as ReactElementLike).$$typeof;\n\n return type === REACT_ELEMENT_TYPE || type === REACT_TRANSITIONAL_ELEMENT_TYPE;\n}\n\n/**\n * Add a key to a React element if it doesn't have one.\n * Creates a shallow copy since React elements are frozen.\n */\nfunction addKeyIfNeeded<T>(element: T, key: string): T {\n if (isReactElement(element) && element.key === null) {\n return { ...element, key } as T;\n }\n\n return element;\n}\n\nfunction isMarkupPart(part: Part): part is MessageMarkupPart {\n return part.type === 'markup';\n}\n\nfunction applyMarkupPart<T>(\n part: MessageMarkupPart,\n stack: StackFrame<T>[],\n result: (string | T)[],\n components: RichComponents<T>,\n nextKey: () => string,\n): void {\n const target = stack.length > 0 ? stack.at(-1)!.children : result;\n\n switch (part.kind) {\n case 'open': {\n stack.push({ name: part.name, children: [] });\n\n break;\n }\n\n case 'close': {\n const frame = stack.pop();\n\n if (!frame) {\n // mismatched close tag, ignore\n break;\n }\n\n const component = components[frame.name];\n const parent = stack.length > 0 ? stack.at(-1)!.children : result;\n\n if (component) {\n parent.push(addKeyIfNeeded(component(frame.children), nextKey()));\n } else {\n // no component for this tag, just flatten children\n parent.push(...frame.children);\n }\n\n break;\n }\n\n case 'standalone': {\n // self-closing: {#icon/}\n const component = components[part.name];\n\n if (component) {\n target.push(addKeyIfNeeded(component([]), nextKey()));\n }\n\n break;\n }\n }\n}\n\n/**\n * Convert MF2 formatToParts() output to a tree of nodes.\n * Works with any JSX runtime (Astro, React, etc.) - the callbacks\n * return whatever JSX elements the active runtime compiles to.\n *\n * @example\n * MF2 message: \"Read our {#link}Terms{/link}\"\n * Parts: [\n * { type: 'text', value: 'Read our ' },\n * { type: 'markup', kind: 'open', name: 'link' },\n * { type: 'text', value: 'Terms' },\n * { type: 'markup', kind: 'close', name: 'link' },\n * ]\n * Result: ['Read our ', <a href=\"/tos\">Terms</a>]\n */\nexport function partsToNodes<T>(parts: Part[], components: RichComponents<T>): (string | T)[] {\n const result: (string | T)[] = [];\n const stack: StackFrame<T>[] = [];\n let keyIndex = 0;\n const nextKey = () => `rich-${keyIndex++}`;\n\n for (const part of parts) {\n const target = stack.length > 0 ? stack.at(-1)!.children : result;\n\n if (isMarkupPart(part)) {\n applyMarkupPart(part, stack, result, components, nextKey);\n } else if (part.type === 'text') {\n // plain text content - MessageTextPart.value is a string\n target.push(part.value as string);\n } else if (part.type === 'bidiIsolation') {\n // bidi isolation marks are direction control characters, not content\n } else {\n if ('value' in part && part.value !== undefined && part.value !== null) {\n const stringValue = String(part.value);\n\n target.push(stringValue);\n }\n }\n }\n\n // handle unclosed tags by flattening remaining stack frames\n while (stack.length > 0) {\n const frame = stack.pop()!;\n const parent = stack.length > 0 ? stack.at(-1)!.children : result;\n\n parent.push(...frame.children);\n }\n\n return result;\n}\n"],"mappings":";;;;AAKA,SAAgB,cAAc,MAAiD;CAC7E,OAAO,OAAO,SAAS,WAAW,EAAE,UAAU,KAAK,IAAI;AACzD;;;ACkBA,MAAM,qBAAqB,OAAO,IAAI,eAAe;AACrD,MAAM,kCAAkC,OAAO,IAAI,4BAA4B;;;;;AAW/E,SAAS,eAAe,OAA2C;CACjE,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,cAAc,QACjE,OAAO;CAGT,MAAM,OAAQ,MAA2B;CAEzC,OAAO,SAAS,sBAAsB,SAAS;AACjD;;;;;AAMA,SAAS,eAAkB,SAAY,KAAgB;CACrD,IAAI,eAAe,OAAO,KAAK,QAAQ,QAAQ,MAC7C,OAAO;EAAE,GAAG;EAAS;CAAI;CAG3B,OAAO;AACT;AAEA,SAAS,aAAa,MAAuC;CAC3D,OAAO,KAAK,SAAS;AACvB;AAEA,SAAS,gBACP,MACA,OACA,QACA,YACA,SACM;CACN,MAAM,SAAS,MAAM,SAAS,IAAI,MAAM,GAAG,EAAE,CAAC,CAAE,WAAW;CAE3D,QAAQ,KAAK,MAAb;EACE,KAAK;GACH,MAAM,KAAK;IAAE,MAAM,KAAK;IAAM,UAAU,CAAC;GAAE,CAAC;GAE5C;EAGF,KAAK,SAAS;GACZ,MAAM,QAAQ,MAAM,IAAI;GAExB,IAAI,CAAC,OAEH;GAGF,MAAM,YAAY,WAAW,MAAM;GACnC,MAAM,SAAS,MAAM,SAAS,IAAI,MAAM,GAAG,EAAE,CAAC,CAAE,WAAW;GAE3D,IAAI,WACF,OAAO,KAAK,eAAe,UAAU,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC;QAGhE,OAAO,KAAK,GAAG,MAAM,QAAQ;GAG/B;EACF;EAEA,KAAK,cAAc;GAEjB,MAAM,YAAY,WAAW,KAAK;GAElC,IAAI,WACF,OAAO,KAAK,eAAe,UAAU,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;GAGtD;EACF;CACF;AACF;;;;;;;;;;;;;;;;AAiBA,SAAgB,aAAgB,OAAe,YAA+C;CAC5F,MAAM,SAAyB,CAAC;CAChC,MAAM,QAAyB,CAAC;CAChC,IAAI,WAAW;CACf,MAAM,gBAAgB,QAAQ;CAE9B,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,SAAS,MAAM,SAAS,IAAI,MAAM,GAAG,EAAE,CAAC,CAAE,WAAW;EAE3D,IAAI,aAAa,IAAI,GACnB,gBAAgB,MAAM,OAAO,QAAQ,YAAY,OAAO;OACnD,IAAI,KAAK,SAAS,QAEvB,OAAO,KAAK,KAAK,KAAe;OAC3B,IAAI,KAAK,SAAS,iBAAiB,CAE1C,OACE,IAAI,WAAW,QAAQ,KAAK,UAAU,KAAA,KAAa,KAAK,UAAU,MAAM;GACtE,MAAM,cAAc,OAAO,KAAK,KAAK;GAErC,OAAO,KAAK,WAAW;EACzB;CAEJ;CAGA,OAAO,MAAM,SAAS,GAAG;EACvB,MAAM,QAAQ,MAAM,IAAI;EAGxB,CAFe,MAAM,SAAS,IAAI,MAAM,GAAG,EAAE,CAAC,CAAE,WAAW,OAAA,CAEpD,KAAK,GAAG,MAAM,QAAQ;CAC/B;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"rich-BbDoHrd9.js","names":[],"sources":["../src/shared/meta.ts","../src/shared/rich.ts"],"sourcesContent":["import type { TranslationMeta } from './types.js';\n\n/**\n * Normalize meta argument to TranslationMeta object\n */\nexport function normalizeMeta(meta: TranslationMeta | string): TranslationMeta {\n return typeof meta === 'string' ? { fallback: meta } : meta;\n}\n","import type { MessageMarkupPart, MessagePart } from 'messageformat';\n\n// MessagePart<string> covers all built-in part types\ntype Part = MessagePart<string>;\n\n/**\n * Component callbacks for rich text rendering.\n * Each key maps to a function that wraps children in a component.\n *\n * @example\n * ```tsx\n * const components: RichComponents = {\n * link: (children) => <a href=\"/tos\">{children}</a>,\n * bold: (children) => <strong>{children}</strong>,\n * };\n * ```\n */\nexport type RichComponents<T = unknown> = Record<string, (children: (string | T)[]) => T>;\n\ntype StackFrame<T> = {\n name: string;\n children: (string | T)[];\n};\n\n// react element symbols - Symbol.for() returns the same symbol React uses internally\nconst REACT_ELEMENT_TYPE = Symbol.for('react.element');\nconst REACT_TRANSITIONAL_ELEMENT_TYPE = Symbol.for('react.transitional.element');\n\ntype ReactElementLike = {\n $$typeof: symbol;\n key: string | null;\n};\n\n/**\n * Duck-type check for React elements without importing React.\n * Uses Symbol.for() which returns the same symbol React uses internally.\n */\nfunction isReactElement(value: unknown): value is ReactElementLike {\n if (typeof value !== 'object' || value === null || !('$$typeof' in value)) {\n return false;\n }\n\n const type = (value as ReactElementLike).$$typeof;\n\n return type === REACT_ELEMENT_TYPE || type === REACT_TRANSITIONAL_ELEMENT_TYPE;\n}\n\n/**\n * Add a key to a React element if it doesn't have one.\n * Creates a shallow copy since React elements are frozen.\n */\nfunction addKeyIfNeeded<T>(element: T, key: string): T {\n if (isReactElement(element) && element.key === null) {\n return { ...element, key } as T;\n }\n\n return element;\n}\n\nfunction isMarkupPart(part: Part): part is MessageMarkupPart {\n return part.type === 'markup';\n}\n\nfunction applyMarkupPart<T>(\n part: MessageMarkupPart,\n stack: StackFrame<T>[],\n result: (string | T)[],\n components: RichComponents<T>,\n nextKey: () => string,\n): void {\n const target = stack.length > 0 ? stack.at(-1)!.children : result;\n\n switch (part.kind) {\n case 'open': {\n stack.push({ name: part.name, children: [] });\n\n break;\n }\n\n case 'close': {\n const frame = stack.pop();\n\n if (!frame) {\n // mismatched close tag, ignore\n break;\n }\n\n const component = components[frame.name];\n const parent = stack.length > 0 ? stack.at(-1)!.children : result;\n\n if (component) {\n parent.push(addKeyIfNeeded(component(frame.children), nextKey()));\n } else {\n // no component for this tag, just flatten children\n parent.push(...frame.children);\n }\n\n break;\n }\n\n case 'standalone': {\n // self-closing: {#icon/}\n const component = components[part.name];\n\n if (component) {\n target.push(addKeyIfNeeded(component([]), nextKey()));\n }\n\n break;\n }\n }\n}\n\n/**\n * Convert MF2 formatToParts() output to a tree of nodes.\n * Works with any JSX runtime (Astro, React, etc.) - the callbacks\n * return whatever JSX elements the active runtime compiles to.\n *\n * @example\n * MF2 message: \"Read our {#link}Terms{/link}\"\n * Parts: [\n * { type: 'text', value: 'Read our ' },\n * { type: 'markup', kind: 'open', name: 'link' },\n * { type: 'text', value: 'Terms' },\n * { type: 'markup', kind: 'close', name: 'link' },\n * ]\n * Result: ['Read our ', <a href=\"/tos\">Terms</a>]\n */\nexport function partsToNodes<T>(parts: Part[], components: RichComponents<T>): (string | T)[] {\n const result: (string | T)[] = [];\n const stack: StackFrame<T>[] = [];\n let keyIndex = 0;\n const nextKey = () => `rich-${keyIndex++}`;\n\n for (const part of parts) {\n const target = stack.length > 0 ? stack.at(-1)!.children : result;\n\n if (isMarkupPart(part)) {\n applyMarkupPart(part, stack, result, components, nextKey);\n } else if (part.type === 'text') {\n // plain text content - MessageTextPart.value is a string\n target.push(part.value as string);\n } else if (part.type === 'bidiIsolation') {\n // bidi isolation marks are direction control characters, not content\n } else {\n if ('value' in part && part.value !== undefined && part.value !== null) {\n const stringValue = String(part.value);\n\n target.push(stringValue);\n }\n }\n }\n\n // handle unclosed tags by flattening remaining stack frames\n while (stack.length > 0) {\n const frame = stack.pop()!;\n const parent = stack.length > 0 ? stack.at(-1)!.children : result;\n\n parent.push(...frame.children);\n }\n\n return result;\n}\n"],"mappings":";;;;AAKA,SAAgB,cAAc,MAAiD;CAC7E,OAAO,OAAO,SAAS,WAAW,EAAE,UAAU,KAAK,IAAI;AACzD;;ACkBA,MAAM,qBAAqB,OAAO,IAAI,eAAe;AACrD,MAAM,kCAAkC,OAAO,IAAI,4BAA4B;;;;;AAW/E,SAAS,eAAe,OAA2C;CACjE,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,cAAc,QACjE,OAAO;CAGT,MAAM,OAAQ,MAA2B;CAEzC,OAAO,SAAS,sBAAsB,SAAS;AACjD;;;;;AAMA,SAAS,eAAkB,SAAY,KAAgB;CACrD,IAAI,eAAe,OAAO,KAAK,QAAQ,QAAQ,MAC7C,OAAO;EAAE,GAAG;EAAS;CAAI;CAG3B,OAAO;AACT;AAEA,SAAS,aAAa,MAAuC;CAC3D,OAAO,KAAK,SAAS;AACvB;AAEA,SAAS,gBACP,MACA,OACA,QACA,YACA,SACM;CACN,MAAM,SAAS,MAAM,SAAS,IAAI,MAAM,GAAG,EAAE,CAAC,CAAE,WAAW;CAE3D,QAAQ,KAAK,MAAb;EACE,KAAK;GACH,MAAM,KAAK;IAAE,MAAM,KAAK;IAAM,UAAU,CAAC;GAAE,CAAC;GAE5C;EAGF,KAAK,SAAS;GACZ,MAAM,QAAQ,MAAM,IAAI;GAExB,IAAI,CAAC,OAEH;GAGF,MAAM,YAAY,WAAW,MAAM;GACnC,MAAM,SAAS,MAAM,SAAS,IAAI,MAAM,GAAG,EAAE,CAAC,CAAE,WAAW;GAE3D,IAAI,WACF,OAAO,KAAK,eAAe,UAAU,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC;QAGhE,OAAO,KAAK,GAAG,MAAM,QAAQ;GAG/B;EACF;EAEA,KAAK,cAAc;GAEjB,MAAM,YAAY,WAAW,KAAK;GAElC,IAAI,WACF,OAAO,KAAK,eAAe,UAAU,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;GAGtD;EACF;CACF;AACF;;;;;;;;;;;;;;;;AAiBA,SAAgB,aAAgB,OAAe,YAA+C;CAC5F,MAAM,SAAyB,CAAC;CAChC,MAAM,QAAyB,CAAC;CAChC,IAAI,WAAW;CACf,MAAM,gBAAgB,QAAQ;CAE9B,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,SAAS,MAAM,SAAS,IAAI,MAAM,GAAG,EAAE,CAAC,CAAE,WAAW;EAE3D,IAAI,aAAa,IAAI,GACnB,gBAAgB,MAAM,OAAO,QAAQ,YAAY,OAAO;OACnD,IAAI,KAAK,SAAS,QAEvB,OAAO,KAAK,KAAK,KAAe;OAC3B,IAAI,KAAK,SAAS,iBAAiB,CAE1C,OACE,IAAI,WAAW,QAAQ,KAAK,UAAU,KAAA,KAAa,KAAK,UAAU,MAAM;GACtE,MAAM,cAAc,OAAO,KAAK,KAAK;GAErC,OAAO,KAAK,WAAW;EACzB;CAEJ;CAGA,OAAO,MAAM,SAAS,GAAG;EACvB,MAAM,QAAQ,MAAM,IAAI;EAGxB,CAFe,MAAM,SAAS,IAAI,MAAM,GAAG,EAAE,CAAC,CAAE,WAAW,OAAA,CAEpD,KAAK,GAAG,MAAM,QAAQ;CAC/B;CAEA,OAAO;AACT"}
@@ -1,5 +1,4 @@
1
1
  import "messageformat";
2
- //#region src/shared/rich.d.ts
3
2
  /**
4
3
  * Component callbacks for rich text rendering.
5
4
  * Each key maps to a function that wraps children in a component.
@@ -13,6 +12,5 @@ import "messageformat";
13
12
  * ```
14
13
  */
15
14
  type RichComponents<T = unknown> = Record<string, (children: (string | T)[]) => T>;
16
- //#endregion
17
15
  export { RichComponents as t };
18
- //# sourceMappingURL=rich-BWszYAzS.d.ts.map
16
+ //# sourceMappingURL=rich-CavnJlKg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rich-CavnJlKg.d.ts","names":[],"sources":["../src/shared/rich.ts"],"mappings":";;;;;;;;;;;;;KAiBY,eAAe,eAAe,gBAAgB,oBAAoB,SAAS"}
@@ -1,4 +1,2 @@
1
- //#region src/server/chunk-middleware-entrypoint.d.ts
2
1
  export declare const onRequest: import("astro").MiddlewareHandler;
3
- //#endregion
4
2
  //# sourceMappingURL=chunk-middleware-entrypoint.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-middleware-entrypoint.d.ts","names":[],"sources":["../../src/server/chunk-middleware-entrypoint.ts"],"mappings":";qBAEa,2BAAS"}
1
+ {"version":3,"file":"chunk-middleware-entrypoint.d.ts","names":[],"sources":["../../src/server/chunk-middleware-entrypoint.ts"],"mappings":"A,qBAEa,2BAAS"}
@@ -1,7 +1,6 @@
1
- import { t as createI18nChunkMiddleware } from "../middleware-SkXWqtl3.js";
2
- //#region src/server/chunk-middleware-entrypoint.ts
1
+ import { t as createI18nChunkMiddleware } from "../middleware-CNXfXefr.js";
2
+ // src/server/chunk-middleware-entrypoint.ts
3
3
  const onRequest = createI18nChunkMiddleware();
4
- //#endregion
5
4
  export { onRequest };
6
5
 
7
6
  //# sourceMappingURL=chunk-middleware-entrypoint.js.map
@@ -0,0 +1,2 @@
1
+ export declare const onRequest: import("astro").MiddlewareHandler;
2
+ //# sourceMappingURL=locale-middleware-entrypoint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale-middleware-entrypoint.d.ts","names":[],"sources":["../../src/server/locale-middleware-entrypoint.ts"],"mappings":"A,qBAGa,2BAAS"}
@@ -0,0 +1,7 @@
1
+ import { n as createI18nLocaleMiddleware } from "../middleware-CNXfXefr.js";
2
+ import { exclude } from "virtual:@astroscope/i18n/config";
3
+ // src/server/locale-middleware-entrypoint.ts
4
+ const onRequest = createI18nLocaleMiddleware({ exclude: exclude ?? void 0 });
5
+ export { onRequest };
6
+
7
+ //# sourceMappingURL=locale-middleware-entrypoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale-middleware-entrypoint.js","names":[],"sources":["../../src/server/locale-middleware-entrypoint.ts"],"sourcesContent":["import { exclude } from 'virtual:@astroscope/i18n/config';\nimport { createI18nLocaleMiddleware } from './middleware.js';\n\nexport const onRequest = createI18nLocaleMiddleware({ exclude: exclude ?? undefined });\n"],"mappings":";;;AAGA,MAAa,YAAY,2BAA2B,EAAE,SAAS,WAAW,KAAA,EAAU,CAAC"}
@@ -1,6 +1,5 @@
1
- import { t as RichComponents } from "../rich-BWszYAzS.js";
2
- import { a as TranslationMeta, i as TranslateFunction } from "../types-BjTD5hUT.js";
3
- //#region src/server/translate.d.ts
1
+ import { t as RichComponents } from "../rich-CavnJlKg.js";
2
+ import { a as TranslationMeta, i as TranslateFunction } from "../types-DYnR9xP3.js";
4
3
  /**
5
4
  * Get the current locale from request context.
6
5
  * Returns defaultLocale if called outside a request (e.g. during build).
@@ -34,5 +33,4 @@ export declare const t: TranslateFunction;
34
33
  * ```
35
34
  */
36
35
  export declare function rich<T = unknown>(key: string, meta?: TranslationMeta | string | undefined, components?: RichComponents<T> | undefined, values?: Record<string, unknown> | undefined): (string | T)[];
37
- //#endregion
38
36
  //# sourceMappingURL=translate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"translate.d.ts","names":[],"sources":["../../src/server/translate.ts"],"mappings":";;;;;;;wBAqDgB;;;;;;;;qBAYH,GAAG;;;;;;;;;;;;;;;;;;;;wBA2DA,KAAK,aACnB,aACA,OAAO,sCACP,aAAa,eAAe,gBAC5B,SAAS,gDACE"}
1
+ {"version":3,"file":"translate.d.ts","names":[],"sources":["../../src/server/translate.ts"],"mappings":";;;;;;wBAqDgB;;;;;;;;qBAYH,GAAG;;;;;;;;;;;;;;;;;;;;wBA2DA,KAAK,aACnB,aACA,OAAO,sCACP,aAAa,eAAe,gBAC5B,SAAS,gDACE"}
@@ -1,9 +1,10 @@
1
- import { r as i18n, t as getContext } from "../context-Cq9-KsBw.js";
2
- import { r as formatMessageToParts, t as compileMessage } from "../compiler-CkOVGWU5.js";
3
- import { n as normalizeMeta, t as partsToNodes } from "../rich-BDqjhv2h.js";
1
+ import { r as formatMessageToParts, t as compileMessage } from "../compiler-K3uHKoFs.js";
2
+ import { n as normalizeMeta, t as partsToNodes } from "../rich-BbDoHrd9.js";
3
+ import { t as getContext } from "../context-CJvTEa-I.js";
4
+ import { t as i18n } from "../i18n-f7qdMTwm.js";
4
5
  import { createCounter } from "@astroscope/node/telemetry";
5
6
  import { log } from "@astroscope/node/log";
6
- //#region src/server/translate.ts
7
+ // src/server/translate.ts
7
8
  const fallbackCache = /* @__PURE__ */ new Map();
8
9
  const missing = createCounter("astro.i18n.missing", {
9
10
  scope: "@astroscope/i18n",
@@ -96,7 +97,6 @@ function rich(key, meta, components, values) {
96
97
  const parts = formatMessageToParts(locale, raw, values);
97
98
  return partsToNodes(parts, components ?? {});
98
99
  }
99
- //#endregion
100
100
  export { getLocale, rich, t };
101
101
 
102
102
  //# sourceMappingURL=translate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"translate.js","names":[],"sources":["../../src/server/translate.ts"],"sourcesContent":["import { log } from '@astroscope/node/log';\nimport { createCounter } from '@astroscope/node/telemetry';\nimport { compileMessage, formatMessageToParts } from '../shared/compiler.js';\nimport { normalizeMeta } from '../shared/meta.js';\nimport { type RichComponents, partsToNodes } from '../shared/rich.js';\nimport type { CompiledTranslation, TranslateFunction, TranslationMeta } from '../shared/types.js';\nimport { getContext } from './context.js';\nimport { i18n } from './i18n.js';\nimport type { FallbackBehavior } from './types.js';\n\n// cache for fallbacks compiled outside request context (e.g. during build)\nconst fallbackCache = new Map<string, CompiledTranslation>();\n\nconst missing = createCounter('astro.i18n.missing', {\n scope: '@astroscope/i18n',\n description: 'Translation lookups that fell back (a key once per locale and translations version for t())',\n unit: '{lookup}',\n});\n\n// the key stays out of the metric label (unbounded) and goes to the log instead\nfunction reportMissing(key: string, locale: string): void {\n missing.add(1, { 'astro.i18n.locale': locale });\n log.debug({ key, locale }, 'missing translation');\n}\n\n/**\n * Apply fallback behavior when translation is missing\n */\nfunction applyFallback(key: string, meta: TranslationMeta, fallback: FallbackBehavior): string {\n if (typeof fallback === 'function') {\n return fallback(key, meta);\n }\n\n switch (fallback) {\n case 'key': {\n return key;\n }\n case 'fallback': {\n return meta.fallback || key;\n }\n case 'throw': {\n throw new Error(`Missing translation for key: ${key}`);\n }\n default: {\n return meta.fallback || key;\n }\n }\n}\n\n/**\n * Get the current locale from request context.\n * Returns defaultLocale if called outside a request (e.g. during build).\n */\nexport function getLocale(): string {\n const ctx = getContext();\n return ctx?.locale ?? i18n.getConfig().defaultLocale;\n}\n\n/**\n * Server-side translate function\n *\n * Call patterns:\n * - Development: t('key', 'fallback') or t('key', 'fallback', values)\n * - Production: t('key') or t('key', undefined, values)\n */\nexport const t: TranslateFunction = ((\n key: string,\n meta?: TranslationMeta | string,\n values?: Record<string, unknown>,\n): string => {\n const normalizedMeta: TranslationMeta = meta ? normalizeMeta(meta) : { fallback: '' };\n\n const ctx = getContext();\n\n if (!ctx) {\n const defaultLocale = i18n.getConfig().defaultLocale;\n const fallbackStr = normalizedMeta.fallback || key;\n const cacheKey = `${defaultLocale}:${fallbackStr}`;\n let compiled = fallbackCache.get(cacheKey);\n\n if (!compiled) {\n compiled = compileMessage(defaultLocale, fallbackStr);\n fallbackCache.set(cacheKey, compiled);\n }\n\n return compiled(values);\n }\n\n const compiled = ctx.translations[key];\n\n if (!compiled) {\n reportMissing(key, ctx.locale);\n\n const fallbackValue = applyFallback(key, normalizedMeta, ctx.fallback);\n\n const compiledFallback = compileMessage(ctx.locale, fallbackValue);\n\n ctx.translations[key] = compiledFallback;\n\n return compiledFallback(values);\n }\n\n return compiled(values);\n}) as TranslateFunction;\n\n/**\n * Server-side rich text translation function\n *\n * Parses MF2 markup syntax and applies component callbacks to wrap content.\n * Works with any JSX runtime (Astro, React during SSR, etc.).\n *\n * @param key - Translation key\n * @param meta - Fallback string or meta object with fallback (used as message template)\n * @param components - Map of tag names to component callbacks\n * @param values - Runtime interpolation values (MessageFormat 2)\n *\n * @example\n * ```tsx\n * rich('tos', 'Read our {#link}Terms{/link}', {\n * link: (children) => <a href=\"/tos\">{children}</a>\n * })\n * // Returns: ['Read our ', <a href=\"/tos\">Terms</a>]\n * ```\n */\nexport function rich<T = unknown>(\n key: string,\n meta?: TranslationMeta | string | undefined,\n components?: RichComponents<T> | undefined,\n values?: Record<string, unknown> | undefined,\n): (string | T)[] {\n const normalizedMeta: TranslationMeta = meta ? normalizeMeta(meta) : { fallback: '' };\n\n const ctx = getContext();\n const locale = ctx?.locale ?? i18n.getConfig().defaultLocale;\n\n const translated = ctx?.rawTranslations[key];\n\n if (ctx && !translated) {\n reportMissing(key, ctx.locale);\n }\n\n const raw = translated || normalizedMeta.fallback || key;\n\n const parts = formatMessageToParts(locale, raw, values);\n\n return partsToNodes(parts, components ?? {});\n}\n"],"mappings":";;;;;;AAWA,MAAM,gCAAgB,IAAI,IAAiC;AAE3D,MAAM,UAAU,cAAc,sBAAsB;CAClD,OAAO;CACP,aAAa;CACb,MAAM;AACR,CAAC;AAGD,SAAS,cAAc,KAAa,QAAsB;CACxD,QAAQ,IAAI,GAAG,EAAE,qBAAqB,OAAO,CAAC;CAC9C,IAAI,MAAM;EAAE;EAAK;CAAO,GAAG,qBAAqB;AAClD;;;;AAKA,SAAS,cAAc,KAAa,MAAuB,UAAoC;CAC7F,IAAI,OAAO,aAAa,YACtB,OAAO,SAAS,KAAK,IAAI;CAG3B,QAAQ,UAAR;EACE,KAAK,OACH,OAAO;EAET,KAAK,YACH,OAAO,KAAK,YAAY;EAE1B,KAAK,SACH,MAAM,IAAI,MAAM,gCAAgC,KAAK;EAEvD,SACE,OAAO,KAAK,YAAY;CAE5B;AACF;;;;;AAMA,SAAgB,YAAoB;CAElC,OADY,WACH,CAAC,EAAE,UAAU,KAAK,UAAU,CAAC,CAAC;AACzC;;;;;;;;AASA,MAAa,MACX,KACA,MACA,WACW;CACX,MAAM,iBAAkC,OAAO,cAAc,IAAI,IAAI,EAAE,UAAU,GAAG;CAEpF,MAAM,MAAM,WAAW;CAEvB,IAAI,CAAC,KAAK;EACR,MAAM,gBAAgB,KAAK,UAAU,CAAC,CAAC;EACvC,MAAM,cAAc,eAAe,YAAY;EAC/C,MAAM,WAAW,GAAG,cAAc,GAAG;EACrC,IAAI,WAAW,cAAc,IAAI,QAAQ;EAEzC,IAAI,CAAC,UAAU;GACb,WAAW,eAAe,eAAe,WAAW;GACpD,cAAc,IAAI,UAAU,QAAQ;EACtC;EAEA,OAAO,SAAS,MAAM;CACxB;CAEA,MAAM,WAAW,IAAI,aAAa;CAElC,IAAI,CAAC,UAAU;EACb,cAAc,KAAK,IAAI,MAAM;EAE7B,MAAM,gBAAgB,cAAc,KAAK,gBAAgB,IAAI,QAAQ;EAErE,MAAM,mBAAmB,eAAe,IAAI,QAAQ,aAAa;EAEjE,IAAI,aAAa,OAAO;EAExB,OAAO,iBAAiB,MAAM;CAChC;CAEA,OAAO,SAAS,MAAM;AACxB;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,KACd,KACA,MACA,YACA,QACgB;CAChB,MAAM,iBAAkC,OAAO,cAAc,IAAI,IAAI,EAAE,UAAU,GAAG;CAEpF,MAAM,MAAM,WAAW;CACvB,MAAM,SAAS,KAAK,UAAU,KAAK,UAAU,CAAC,CAAC;CAE/C,MAAM,aAAa,KAAK,gBAAgB;CAExC,IAAI,OAAO,CAAC,YACV,cAAc,KAAK,IAAI,MAAM;CAG/B,MAAM,MAAM,cAAc,eAAe,YAAY;CAErD,MAAM,QAAQ,qBAAqB,QAAQ,KAAK,MAAM;CAEtD,OAAO,aAAa,OAAO,cAAc,CAAC,CAAC;AAC7C"}
1
+ {"version":3,"file":"translate.js","names":[],"sources":["../../src/server/translate.ts"],"sourcesContent":["import { log } from '@astroscope/node/log';\nimport { createCounter } from '@astroscope/node/telemetry';\nimport { compileMessage, formatMessageToParts } from '../shared/compiler.js';\nimport { normalizeMeta } from '../shared/meta.js';\nimport { type RichComponents, partsToNodes } from '../shared/rich.js';\nimport type { CompiledTranslation, TranslateFunction, TranslationMeta } from '../shared/types.js';\nimport { getContext } from './context.js';\nimport { i18n } from './i18n.js';\nimport type { FallbackBehavior } from './types.js';\n\n// cache for fallbacks compiled outside request context (e.g. during build)\nconst fallbackCache = new Map<string, CompiledTranslation>();\n\nconst missing = createCounter('astro.i18n.missing', {\n scope: '@astroscope/i18n',\n description: 'Translation lookups that fell back (a key once per locale and translations version for t())',\n unit: '{lookup}',\n});\n\n// the key stays out of the metric label (unbounded) and goes to the log instead\nfunction reportMissing(key: string, locale: string): void {\n missing.add(1, { 'astro.i18n.locale': locale });\n log.debug({ key, locale }, 'missing translation');\n}\n\n/**\n * Apply fallback behavior when translation is missing\n */\nfunction applyFallback(key: string, meta: TranslationMeta, fallback: FallbackBehavior): string {\n if (typeof fallback === 'function') {\n return fallback(key, meta);\n }\n\n switch (fallback) {\n case 'key': {\n return key;\n }\n case 'fallback': {\n return meta.fallback || key;\n }\n case 'throw': {\n throw new Error(`Missing translation for key: ${key}`);\n }\n default: {\n return meta.fallback || key;\n }\n }\n}\n\n/**\n * Get the current locale from request context.\n * Returns defaultLocale if called outside a request (e.g. during build).\n */\nexport function getLocale(): string {\n const ctx = getContext();\n return ctx?.locale ?? i18n.getConfig().defaultLocale;\n}\n\n/**\n * Server-side translate function\n *\n * Call patterns:\n * - Development: t('key', 'fallback') or t('key', 'fallback', values)\n * - Production: t('key') or t('key', undefined, values)\n */\nexport const t: TranslateFunction = ((\n key: string,\n meta?: TranslationMeta | string,\n values?: Record<string, unknown>,\n): string => {\n const normalizedMeta: TranslationMeta = meta ? normalizeMeta(meta) : { fallback: '' };\n\n const ctx = getContext();\n\n if (!ctx) {\n const defaultLocale = i18n.getConfig().defaultLocale;\n const fallbackStr = normalizedMeta.fallback || key;\n const cacheKey = `${defaultLocale}:${fallbackStr}`;\n let compiled = fallbackCache.get(cacheKey);\n\n if (!compiled) {\n compiled = compileMessage(defaultLocale, fallbackStr);\n fallbackCache.set(cacheKey, compiled);\n }\n\n return compiled(values);\n }\n\n const compiled = ctx.translations[key];\n\n if (!compiled) {\n reportMissing(key, ctx.locale);\n\n const fallbackValue = applyFallback(key, normalizedMeta, ctx.fallback);\n\n const compiledFallback = compileMessage(ctx.locale, fallbackValue);\n\n ctx.translations[key] = compiledFallback;\n\n return compiledFallback(values);\n }\n\n return compiled(values);\n}) as TranslateFunction;\n\n/**\n * Server-side rich text translation function\n *\n * Parses MF2 markup syntax and applies component callbacks to wrap content.\n * Works with any JSX runtime (Astro, React during SSR, etc.).\n *\n * @param key - Translation key\n * @param meta - Fallback string or meta object with fallback (used as message template)\n * @param components - Map of tag names to component callbacks\n * @param values - Runtime interpolation values (MessageFormat 2)\n *\n * @example\n * ```tsx\n * rich('tos', 'Read our {#link}Terms{/link}', {\n * link: (children) => <a href=\"/tos\">{children}</a>\n * })\n * // Returns: ['Read our ', <a href=\"/tos\">Terms</a>]\n * ```\n */\nexport function rich<T = unknown>(\n key: string,\n meta?: TranslationMeta | string | undefined,\n components?: RichComponents<T> | undefined,\n values?: Record<string, unknown> | undefined,\n): (string | T)[] {\n const normalizedMeta: TranslationMeta = meta ? normalizeMeta(meta) : { fallback: '' };\n\n const ctx = getContext();\n const locale = ctx?.locale ?? i18n.getConfig().defaultLocale;\n\n const translated = ctx?.rawTranslations[key];\n\n if (ctx && !translated) {\n reportMissing(key, ctx.locale);\n }\n\n const raw = translated || normalizedMeta.fallback || key;\n\n const parts = formatMessageToParts(locale, raw, values);\n\n return partsToNodes(parts, components ?? {});\n}\n"],"mappings":";;;;;;;AAWA,MAAM,gCAAgB,IAAI,IAAiC;AAE3D,MAAM,UAAU,cAAc,sBAAsB;CAClD,OAAO;CACP,aAAa;CACb,MAAM;AACR,CAAC;AAGD,SAAS,cAAc,KAAa,QAAsB;CACxD,QAAQ,IAAI,GAAG,EAAE,qBAAqB,OAAO,CAAC;CAC9C,IAAI,MAAM;EAAE;EAAK;CAAO,GAAG,qBAAqB;AAClD;;;;AAKA,SAAS,cAAc,KAAa,MAAuB,UAAoC;CAC7F,IAAI,OAAO,aAAa,YACtB,OAAO,SAAS,KAAK,IAAI;CAG3B,QAAQ,UAAR;EACE,KAAK,OACH,OAAO;EAET,KAAK,YACH,OAAO,KAAK,YAAY;EAE1B,KAAK,SACH,MAAM,IAAI,MAAM,gCAAgC,KAAK;EAEvD,SACE,OAAO,KAAK,YAAY;CAE5B;AACF;;;;;AAMA,SAAgB,YAAoB;CAElC,OADY,WACH,CAAC,EAAE,UAAU,KAAK,UAAU,CAAC,CAAC;AACzC;;;;;;;;AASA,MAAa,MACX,KACA,MACA,WACW;CACX,MAAM,iBAAkC,OAAO,cAAc,IAAI,IAAI,EAAE,UAAU,GAAG;CAEpF,MAAM,MAAM,WAAW;CAEvB,IAAI,CAAC,KAAK;EACR,MAAM,gBAAgB,KAAK,UAAU,CAAC,CAAC;EACvC,MAAM,cAAc,eAAe,YAAY;EAC/C,MAAM,WAAW,GAAG,cAAc,GAAG;EACrC,IAAI,WAAW,cAAc,IAAI,QAAQ;EAEzC,IAAI,CAAC,UAAU;GACb,WAAW,eAAe,eAAe,WAAW;GACpD,cAAc,IAAI,UAAU,QAAQ;EACtC;EAEA,OAAO,SAAS,MAAM;CACxB;CAEA,MAAM,WAAW,IAAI,aAAa;CAElC,IAAI,CAAC,UAAU;EACb,cAAc,KAAK,IAAI,MAAM;EAE7B,MAAM,gBAAgB,cAAc,KAAK,gBAAgB,IAAI,QAAQ;EAErE,MAAM,mBAAmB,eAAe,IAAI,QAAQ,aAAa;EAEjE,IAAI,aAAa,OAAO;EAExB,OAAO,iBAAiB,MAAM;CAChC;CAEA,OAAO,SAAS,MAAM;AACxB;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,KACd,KACA,MACA,YACA,QACgB;CAChB,MAAM,iBAAkC,OAAO,cAAc,IAAI,IAAI,EAAE,UAAU,GAAG;CAEpF,MAAM,MAAM,WAAW;CACvB,MAAM,SAAS,KAAK,UAAU,KAAK,UAAU,CAAC,CAAC;CAE/C,MAAM,aAAa,KAAK,gBAAgB;CAExC,IAAI,OAAO,CAAC,YACV,cAAc,KAAK,IAAI,MAAM;CAG/B,MAAM,MAAM,cAAc,eAAe,YAAY;CAErD,MAAM,QAAQ,qBAAqB,QAAQ,KAAK,MAAM;CAEtD,OAAO,aAAa,OAAO,cAAc,CAAC,CAAC;AAC7C"}
@@ -1,4 +1,3 @@
1
- //#region src/shared/types.d.ts
2
1
  /**
3
2
  * Variable definition for documentation
4
3
  */
@@ -51,6 +50,5 @@ type I18nClientState = {
51
50
  * t('cart.total', { fallback: 'Total: {$amount}' }, { amount: '$49.99' })
52
51
  */
53
52
  type TranslateFunction = (key: string, meta: TranslationMeta | string, values?: Record<string, unknown> | undefined) => string;
54
- //#endregion
55
53
  export { TranslationMeta as a, TranslateFunction as i, I18nClientState as n, RawTranslations as r, CompiledTranslations as t };
56
- //# sourceMappingURL=types-BjTD5hUT.d.ts.map
54
+ //# sourceMappingURL=types-DYnR9xP3.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-DYnR9xP3.d.ts","names":[],"sources":["../src/shared/types.ts"],"mappings":";;;KAGY;EACV;EACA;;;;;KAMU;EACV;EACA,YAAY,eAAe;EAC3B;;;;;KAMU,uBAAuB,SAAS;;;;KAKhC,uBAAuB,eAAe;;;;KAKtC,kBAAkB;;;;;;KAOlB;EACV;EACA,QAAQ;EACR,cAAc;;;;;;;;;;;;;;;;KAiBJ,qBACV,aACA,MAAM,0BACN,SAAS"}
@@ -1,5 +1,4 @@
1
- import { a as TranslationMeta } from "./types-BjTD5hUT.js";
2
- //#region src/extraction/types.d.ts
1
+ import { a as TranslationMeta } from "./types-DYnR9xP3.js";
3
2
  /**
4
3
  * Deduplicated translation key with all file locations (used in manifest)
5
4
  */
@@ -26,6 +25,5 @@ type ExtractionManifest = {
26
25
  */
27
26
  scripts: string[];
28
27
  };
29
- //#endregion
30
28
  export { ExtractedKey as n, ExtractionManifest as r, ChunkManifest as t };
31
- //# sourceMappingURL=types-BC-tQ30r.d.ts.map
29
+ //# sourceMappingURL=types-DwM0qsLj.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-DwM0qsLj.d.ts","names":[],"sources":["../src/extraction/types.ts"],"mappings":";;;;KA8BY;EACV;EACA,MAAM;;EAEN;;;;;KAMU,gBAAgB;;;;KAKhB;EACV,MAAM;EACN,QAAQ;;;;;;EAMR"}
@@ -1,4 +1,4 @@
1
- //#region src/integration/types.d.ts
1
+ import { ExcludePattern } from "@astroscope/node/excludes";
2
2
  /**
3
3
  * Consistency check level for translation keys.
4
4
  * Controls behavior when the same key has different fallbacks/variables across files.
@@ -14,7 +14,11 @@ interface I18nOptions {
14
14
  * @default 'error'
15
15
  */
16
16
  consistency?: ConsistencyCheckLevel | undefined;
17
+ /**
18
+ * Paths the locale middleware skips — no locale is resolved and `t()` has no request context there.
19
+ * @default RECOMMENDED_EXCLUDES from `@astroscope/node/excludes`
20
+ */
21
+ exclude?: ExcludePattern[] | undefined;
17
22
  }
18
- //#endregion
19
23
  export { I18nOptions as n, ConsistencyCheckLevel as t };
20
- //# sourceMappingURL=types-Bo4jMK8g.d.ts.map
24
+ //# sourceMappingURL=types-ioAI5pu0.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-ioAI5pu0.d.ts","names":[],"sources":["../src/integration/types.ts"],"mappings":";;;;;;;;;KAUY;UAEK;;;;;EAKf,cAAc;;;;;EAKd,UAAU"}
@@ -1,4 +1,4 @@
1
- //#region src/shared/url.ts
1
+ // src/shared/url.ts
2
2
  /**
3
3
  * Convert a Vite chunk ID to a clean chunk name
4
4
  * Strips the _astro/ prefix that Vite adds
@@ -20,7 +20,6 @@ function chunkIdToName(chunkId) {
20
20
  function buildI18nChunkUrl(locale, chunkId, hash) {
21
21
  return `/_i18n/${locale}/${chunkIdToName(chunkId)}.${hash}.js`;
22
22
  }
23
- //#endregion
24
23
  export { chunkIdToName as n, buildI18nChunkUrl as t };
25
24
 
26
- //# sourceMappingURL=url-CifeaDzl.js.map
25
+ //# sourceMappingURL=url-6HS_IPPA.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"url-CifeaDzl.js","names":[],"sources":["../src/shared/url.ts"],"sourcesContent":["/**\n * Convert a Vite chunk ID to a clean chunk name\n * Strips the _astro/ prefix that Vite adds\n *\n * @example\n * chunkIdToName('_astro/Cart.C_sxtxbl') // → 'Cart.C_sxtxbl'\n * chunkIdToName('Cart.C_sxtxbl') // → 'Cart.C_sxtxbl'\n */\nexport function chunkIdToName(chunkId: string): string {\n return chunkId.replace(/^_astro\\//, '');\n}\n\n/**\n * Extract chunk name from a component URL\n * Used by client directives to get the hash lookup key\n *\n * @example\n * componentUrlToChunkName('/_astro/Cart.C_sxtxbl.js') // → 'Cart.C_sxtxbl'\n */\nexport function componentUrlToChunkName(componentUrl: string): string {\n return componentUrl.replace(/^\\/_astro\\//, '').replace(/\\.js$/, '');\n}\n\n/**\n * Build the URL path for fetching a translation chunk\n *\n * @example\n * buildI18nChunkUrl('en', '_astro/Cart.C_sxtxbl', 'bzh6rx')\n * // → '/_i18n/en/Cart.C_sxtxbl.bzh6rx.js'\n */\nexport function buildI18nChunkUrl(locale: string, chunkId: string, hash: string): string {\n return `/_i18n/${locale}/${chunkIdToName(chunkId)}.${hash}.js`;\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,cAAc,SAAyB;CACrD,OAAO,QAAQ,QAAQ,aAAa,EAAE;AACxC;;;;;;;;AAoBA,SAAgB,kBAAkB,QAAgB,SAAiB,MAAsB;CACvF,OAAO,UAAU,OAAO,GAAG,cAAc,OAAO,EAAE,GAAG,KAAK;AAC5D"}
1
+ {"version":3,"file":"url-6HS_IPPA.js","names":[],"sources":["../src/shared/url.ts"],"sourcesContent":["/**\n * Convert a Vite chunk ID to a clean chunk name\n * Strips the _astro/ prefix that Vite adds\n *\n * @example\n * chunkIdToName('_astro/Cart.C_sxtxbl') // → 'Cart.C_sxtxbl'\n * chunkIdToName('Cart.C_sxtxbl') // → 'Cart.C_sxtxbl'\n */\nexport function chunkIdToName(chunkId: string): string {\n return chunkId.replace(/^_astro\\//, '');\n}\n\n/**\n * Extract chunk name from a component URL\n * Used by client directives to get the hash lookup key\n *\n * @example\n * componentUrlToChunkName('/_astro/Cart.C_sxtxbl.js') // → 'Cart.C_sxtxbl'\n */\nexport function componentUrlToChunkName(componentUrl: string): string {\n return componentUrl.replace(/^\\/_astro\\//, '').replace(/\\.js$/, '');\n}\n\n/**\n * Build the URL path for fetching a translation chunk\n *\n * @example\n * buildI18nChunkUrl('en', '_astro/Cart.C_sxtxbl', 'bzh6rx')\n * // → '/_i18n/en/Cart.C_sxtxbl.bzh6rx.js'\n */\nexport function buildI18nChunkUrl(locale: string, chunkId: string, hash: string): string {\n return `/_i18n/${locale}/${chunkIdToName(chunkId)}.${hash}.js`;\n}\n"],"mappings":";;;;;;;;;AAQA,SAAgB,cAAc,SAAyB;CACrD,OAAO,QAAQ,QAAQ,aAAa,EAAE;AACxC;;;;;;;;AAoBA,SAAgB,kBAAkB,QAAgB,SAAiB,MAAsB;CACvF,OAAO,UAAU,OAAO,GAAG,cAAc,OAAO,EAAE,GAAG,KAAK;AAC5D"}