@astroscope/i18n 1.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +28 -72
  2. package/dist/babel-plugin-CWafmw5z.js.map +1 -1
  3. package/dist/client/translate.d.ts +1 -1
  4. package/dist/client/translate.d.ts.map +1 -1
  5. package/dist/client/translate.js +19 -2
  6. package/dist/client/translate.js.map +1 -1
  7. package/dist/{context-DLfoS-uR.js → context-CYqyZJyH.js} +14 -60
  8. package/dist/context-CYqyZJyH.js.map +1 -0
  9. package/dist/extraction/index.d.ts +1 -1
  10. package/dist/extraction/index.d.ts.map +1 -1
  11. package/dist/extraction/index.js +2 -2
  12. package/dist/{i18n-Dzh54-at.d.ts → i18n-Bp8TFmd3.d.ts} +7 -8
  13. package/dist/i18n-Bp8TFmd3.d.ts.map +1 -0
  14. package/dist/index.d.ts +14 -30
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +20 -152
  17. package/dist/index.js.map +1 -1
  18. package/dist/internal.d.ts +2 -2
  19. package/dist/internal.js +1 -1
  20. package/dist/{manifest-BEm6GezL.js → manifest-Cma68XM-.js} +3 -3
  21. package/dist/manifest-Cma68XM-.js.map +1 -0
  22. package/dist/middleware-7SvnYV--.js +220 -0
  23. package/dist/middleware-7SvnYV--.js.map +1 -0
  24. package/dist/rich-CHisXE-A.js.map +1 -1
  25. package/dist/server/chunk-middleware-entrypoint.d.ts +5 -0
  26. package/dist/server/chunk-middleware-entrypoint.d.ts.map +1 -0
  27. package/dist/server/chunk-middleware-entrypoint.js +7 -0
  28. package/dist/server/chunk-middleware-entrypoint.js.map +1 -0
  29. package/dist/server/translate.d.ts +1 -1
  30. package/dist/server/translate.d.ts.map +1 -1
  31. package/dist/server/translate.js +5 -2
  32. package/dist/server/translate.js.map +1 -1
  33. package/dist/{types-C98CcjtN.d.ts → types-DU8QHch4.d.ts} +4 -3
  34. package/dist/types-DU8QHch4.d.ts.map +1 -0
  35. package/dist/{types-CkqZWnXH.d.ts → types-f-SNJdvf.d.ts} +8 -8
  36. package/dist/types-f-SNJdvf.d.ts.map +1 -0
  37. package/dist/{url-B8334XSD.js → url-CifeaDzl.js} +2 -12
  38. package/dist/{url-B8334XSD.js.map → url-CifeaDzl.js.map} +1 -1
  39. package/dist/{vite-plugin-BbdVKdt8.js → vite-plugin-C-jEpd8t.js} +18 -22
  40. package/dist/vite-plugin-C-jEpd8t.js.map +1 -0
  41. package/package.json +14 -35
  42. package/dist/client/directives/idle.d.ts +0 -6
  43. package/dist/client/directives/idle.d.ts.map +0 -1
  44. package/dist/client/directives/idle.js +0 -14
  45. package/dist/client/directives/idle.js.map +0 -1
  46. package/dist/client/directives/load.d.ts +0 -6
  47. package/dist/client/directives/load.d.ts.map +0 -1
  48. package/dist/client/directives/load.js +0 -10
  49. package/dist/client/directives/load.js.map +0 -1
  50. package/dist/client/directives/media.d.ts +0 -6
  51. package/dist/client/directives/media.d.ts.map +0 -1
  52. package/dist/client/directives/media.js +0 -17
  53. package/dist/client/directives/media.js.map +0 -1
  54. package/dist/client/directives/only.d.ts +0 -6
  55. package/dist/client/directives/only.d.ts.map +0 -1
  56. package/dist/client/directives/only.js +0 -10
  57. package/dist/client/directives/only.js.map +0 -1
  58. package/dist/client/directives/utils.d.ts +0 -10
  59. package/dist/client/directives/utils.d.ts.map +0 -1
  60. package/dist/client/directives/utils.js +0 -32
  61. package/dist/client/directives/utils.js.map +0 -1
  62. package/dist/client/directives/visible.d.ts +0 -6
  63. package/dist/client/directives/visible.d.ts.map +0 -1
  64. package/dist/client/directives/visible.js +0 -23
  65. package/dist/client/directives/visible.js.map +0 -1
  66. package/dist/context-DLfoS-uR.js.map +0 -1
  67. package/dist/i18n-Dzh54-at.d.ts.map +0 -1
  68. package/dist/manifest-BEm6GezL.js.map +0 -1
  69. package/dist/state-DeudhdeT.js +0 -20
  70. package/dist/state-DeudhdeT.js.map +0 -1
  71. package/dist/types-C98CcjtN.d.ts.map +0 -1
  72. package/dist/types-CkqZWnXH.d.ts.map +0 -1
  73. package/dist/vite-plugin-BbdVKdt8.js.map +0 -1
  74. package/src/astro/I18nScript.astro +0 -16
  75. package/src/astro/index.ts +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"translate.js","names":[],"sources":["../../src/server/translate.ts"],"sourcesContent":["import { 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\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 case 'fallback':\n return meta.fallback || key;\n case 'throw':\n throw new Error(`Missing translation for key: ${key}`);\n default:\n return meta.fallback || key;\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 // no context = probably during build or outside request\n // use cached compiled fallback to avoid recompiling on every call\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 // translation missing, apply fallback\n const fallbackValue = applyFallback(key, normalizedMeta, ctx.fallback);\n\n // compile and cache the fallback for consistency\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 (ICU MessageFormat)\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 // get raw translation string - prefer from context, then fallback, then key\n const raw = ctx?.rawTranslations[key] || normalizedMeta.fallback || key;\n\n const parts = formatMessageToParts(locale, raw, values);\n\n return partsToNodes(parts, components ?? {});\n}\n"],"mappings":";;;;AASA,MAAM,gCAAgB,IAAI,IAAiC;;;;AAK3D,SAAS,cAAc,KAAa,MAAuB,UAAoC;CAC7F,IAAI,OAAO,aAAa,YACtB,OAAO,SAAS,KAAK,IAAI;CAG3B,QAAQ,UAAR;EACE,KAAK,OACH,OAAO;EACT,KAAK,YACH,OAAO,KAAK,YAAY;EAC1B,KAAK,SACH,MAAM,IAAI,MAAM,gCAAgC,KAAK;EACvD,SACE,OAAO,KAAK,YAAY;CAC5B;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;EAGR,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;EAEb,MAAM,gBAAgB,cAAc,KAAK,gBAAgB,IAAI,QAAQ;EAGrE,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;CAQvB,OAAO,aAFO,qBALC,KAAK,UAAU,KAAK,UAAU,CAAC,CAAC,eAGnC,KAAK,gBAAgB,QAAQ,eAAe,YAAY,KAEpB,MAExB,GAAG,cAAc,CAAC,CAAC;AAC7C"}
1
+ {"version":3,"file":"translate.js","names":[],"sources":["../../src/server/translate.ts"],"sourcesContent":["import { 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\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 case 'fallback':\n return meta.fallback || key;\n case 'throw':\n throw new Error(`Missing translation for key: ${key}`);\n default:\n return meta.fallback || key;\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 // no context = probably during build or outside request\n // use cached compiled fallback to avoid recompiling on every call\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 const fallbackValue = applyFallback(key, normalizedMeta, ctx.fallback);\n\n // compile and cache the fallback for consistency\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 (ICU MessageFormat)\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 raw = ctx?.rawTranslations[key] || normalizedMeta.fallback || key;\n\n const parts = formatMessageToParts(locale, raw, values);\n\n return partsToNodes(parts, components ?? {});\n}\n"],"mappings":";;;;AASA,MAAM,gCAAgB,IAAI,IAAiC;;;;AAK3D,SAAS,cAAc,KAAa,MAAuB,UAAoC;CAC7F,IAAI,OAAO,aAAa,YACtB,OAAO,SAAS,KAAK,IAAI;CAG3B,QAAQ,UAAR;EACE,KAAK,OACH,OAAO;EACT,KAAK,YACH,OAAO,KAAK,YAAY;EAC1B,KAAK,SACH,MAAM,IAAI,MAAM,gCAAgC,KAAK;EACvD,SACE,OAAO,KAAK,YAAY;CAC5B;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;EAGR,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,MAAM,gBAAgB,cAAc,KAAK,gBAAgB,IAAI,QAAQ;EAGrE,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,MAAM,KAAK,gBAAgB,QAAQ,eAAe,YAAY;CAEpE,MAAM,QAAQ,qBAAqB,QAAQ,KAAK,MAAM;CAEtD,OAAO,aAAa,OAAO,cAAc,CAAC,CAAC;AAC7C"}
@@ -27,13 +27,14 @@ type CompiledTranslations = Record<string, CompiledTranslation>;
27
27
  */
28
28
  type RawTranslations = Record<string, string>;
29
29
  /**
30
- * Client-side i18n state injected into window.__i18n__
30
+ * Client-side i18n state on window.__i18n__ — bootstrapped by the middleware
31
+ * (script-chunk hashes in production, full translations in dev) and extended
32
+ * per island by the islands emitter with that island's chunk hashes.
31
33
  */
32
34
  type I18nClientState = {
33
35
  locale: string;
34
36
  hashes: Record<string, string>;
35
37
  translations: Record<string, string>;
36
- imports: Record<string, string[]>;
37
38
  };
38
39
  /**
39
40
  * Translate function
@@ -50,4 +51,4 @@ type I18nClientState = {
50
51
  type TranslateFunction = (key: string, meta: TranslationMeta | string, values?: Record<string, unknown> | undefined) => string;
51
52
  //#endregion
52
53
  export { TranslationMeta as a, TranslateFunction as i, I18nClientState as n, RawTranslations as r, CompiledTranslations as t };
53
- //# sourceMappingURL=types-C98CcjtN.d.ts.map
54
+ //# sourceMappingURL=types-DU8QHch4.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-DU8QHch4.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;;;;;;;;;;;;;;KAeJ,qBACV,aACA,MAAM,0BACN,SAAS"}
@@ -1,4 +1,4 @@
1
- import { a as TranslationMeta } from "./types-C98CcjtN.js";
1
+ import { a as TranslationMeta } from "./types-DU8QHch4.js";
2
2
  //#region src/extraction/types.d.ts
3
3
  /**
4
4
  * Deduplicated translation key with all file locations (used in manifest)
@@ -13,19 +13,19 @@ type ExtractedKey = {
13
13
  * Chunk-to-keys mapping produced by Vite plugin
14
14
  */
15
15
  type ChunkManifest = Record<string, string[]>;
16
- /**
17
- * Chunk imports mapping: chunk name → array of imported chunk names that have i18n
18
- * All direct and indirect descendants are flattened into a single array
19
- */
20
- type ImportsManifest = Record<string, string[]>;
21
16
  /**
22
17
  * Full extraction manifest
23
18
  */
24
19
  type ExtractionManifest = {
25
20
  keys: ExtractedKey[];
26
21
  chunks: ChunkManifest;
27
- imports: ImportsManifest;
22
+ /**
23
+ * i18n chunks reachable from astro `<script>` entries. Script modules are not
24
+ * islands, so no island carries their hashes — the middleware bootstraps these
25
+ * few page-agnostically instead.
26
+ */
27
+ scripts: string[];
28
28
  };
29
29
  //#endregion
30
30
  export { ExtractedKey as n, ExtractionManifest as r, ChunkManifest as t };
31
- //# sourceMappingURL=types-CkqZWnXH.d.ts.map
31
+ //# sourceMappingURL=types-f-SNJdvf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-f-SNJdvf.d.ts","names":[],"sources":["../src/extraction/types.ts"],"mappings":";;;;;KA8BY;EACV;EACA,MAAM;;EAEN;;;;;KAMU,gBAAgB;;;;KAKhB;EACV,MAAM;EACN,QAAQ;;;;;;EAMR"}
@@ -11,16 +11,6 @@ function chunkIdToName(chunkId) {
11
11
  return chunkId.replace(/^_astro\//, "");
12
12
  }
13
13
  /**
14
- * Extract chunk name from a component URL
15
- * Used by client directives to get the hash lookup key
16
- *
17
- * @example
18
- * componentUrlToChunkName('/_astro/Cart.C_sxtxbl.js') // → 'Cart.C_sxtxbl'
19
- */
20
- function componentUrlToChunkName(componentUrl) {
21
- return componentUrl.replace(/^\/_astro\//, "").replace(/\.js$/, "");
22
- }
23
- /**
24
14
  * Build the URL path for fetching a translation chunk
25
15
  *
26
16
  * @example
@@ -31,6 +21,6 @@ function buildI18nChunkUrl(locale, chunkId, hash) {
31
21
  return `/_i18n/${locale}/${chunkIdToName(chunkId)}.${hash}.js`;
32
22
  }
33
23
  //#endregion
34
- export { chunkIdToName as n, componentUrlToChunkName as r, buildI18nChunkUrl as t };
24
+ export { chunkIdToName as n, buildI18nChunkUrl as t };
35
25
 
36
- //# sourceMappingURL=url-B8334XSD.js.map
26
+ //# sourceMappingURL=url-CifeaDzl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"url-B8334XSD.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;;;;;;;;AASA,SAAgB,wBAAwB,cAA8B;CACpE,OAAO,aAAa,QAAQ,eAAe,EAAE,CAAC,CAAC,QAAQ,SAAS,EAAE;AACpE;;;;;;;;AASA,SAAgB,kBAAkB,QAAgB,SAAiB,MAAsB;CACvF,OAAO,UAAU,OAAO,GAAG,cAAc,OAAO,EAAE,GAAG,KAAK;AAC5D"}
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,5 +1,5 @@
1
- import { n as chunkIdToName } from "./url-B8334XSD.js";
2
- import { n as getManifest, t as getGlobalState } from "./manifest-BEm6GezL.js";
1
+ import { n as chunkIdToName } from "./url-CifeaDzl.js";
2
+ import { n as getManifest, t as getGlobalState } from "./manifest-Cma68XM-.js";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import MagicString from "magic-string";
@@ -410,7 +410,7 @@ export function getManifest() { return manifestJson; }
410
410
  `;
411
411
  return `
412
412
  import { getManifest as _getManifest } from '@astroscope/i18n/extraction';
413
- export const manifest = { keys: [], chunks: {} };
413
+ export const manifest = { keys: [], chunks: {}, scripts: [] };
414
414
  export function getManifest() { return _getManifest(); }
415
415
  `;
416
416
  }
@@ -438,10 +438,11 @@ export function getManifest() { return _getManifest(); }
438
438
  generateBundle(_, bundle) {
439
439
  const state = getGlobalState();
440
440
  state.chunkManifest = {};
441
- state.importsManifest = {};
441
+ state.scriptChunks = [];
442
442
  const chunksWithI18n = /* @__PURE__ */ new Set();
443
443
  const chunkNameToFileName = /* @__PURE__ */ new Map();
444
444
  const directImports = /* @__PURE__ */ new Map();
445
+ const scriptEntries = [];
445
446
  for (const [fileName, chunk] of Object.entries(bundle)) if (chunk.type === "chunk" && chunk.moduleIds) {
446
447
  const keys = /* @__PURE__ */ new Set();
447
448
  let hasI18nModule = false;
@@ -454,28 +455,23 @@ export function getManifest() { return _getManifest(); }
454
455
  if (hasI18nModule) chunksWithI18n.add(chunkName);
455
456
  chunkNameToFileName.set(chunkName, fileName);
456
457
  const imports = [];
457
- for (const importedFile of chunk.imports) {
458
- const importedChunkName = chunkIdToName(importedFile.replace(/^.*\//, "").replace(/\.js$/, ""));
459
- imports.push(importedChunkName);
458
+ for (const importedFile of [...chunk.imports, ...chunk.dynamicImports]) {
459
+ const baseName = importedFile.replace(/^.*\//, "").replace(/\.js$/, "");
460
+ imports.push(chunkIdToName(baseName));
460
461
  }
461
462
  directImports.set(chunkName, imports);
463
+ if ((chunk.isEntry || chunk.isDynamicEntry) && chunk.facadeModuleId?.includes("astro&type=script")) scriptEntries.push(chunkName);
462
464
  }
463
- const flattenImports = (chunkName, visited) => {
464
- if (visited.has(chunkName)) return [];
465
+ const scriptChunks = /* @__PURE__ */ new Set();
466
+ const walkScripts = (chunkName, visited) => {
467
+ if (visited.has(chunkName)) return;
465
468
  visited.add(chunkName);
466
- const result = /* @__PURE__ */ new Set();
467
- const imports = directImports.get(chunkName) ?? [];
468
- for (const imported of imports) {
469
- if (state.chunkManifest[imported]) result.add(imported);
470
- for (const descendant of flattenImports(imported, visited)) result.add(descendant);
471
- }
472
- visited.delete(chunkName);
473
- return Array.from(result);
469
+ if (state.chunkManifest[chunkName]) scriptChunks.add(chunkName);
470
+ for (const imported of directImports.get(chunkName) ?? []) walkScripts(imported, visited);
474
471
  };
475
- for (const chunkName of directImports.keys()) {
476
- const flattened = flattenImports(chunkName, /* @__PURE__ */ new Set());
477
- if (flattened.length > 0) state.importsManifest[chunkName] = flattened;
478
- }
472
+ const visited = /* @__PURE__ */ new Set();
473
+ for (const entry of scriptEntries) walkScripts(entry, visited);
474
+ state.scriptChunks = [...scriptChunks];
479
475
  for (const [fileName, chunk] of Object.entries(bundle)) {
480
476
  if (chunk.type !== "chunk") continue;
481
477
  const chunkName = chunkIdToName(fileName.replace(/\.js$/, ""));
@@ -504,4 +500,4 @@ export function getManifest() { return _getManifest(); }
504
500
  //#endregion
505
501
  export { i18nVitePlugin as t };
506
502
 
507
- //# sourceMappingURL=vite-plugin-BbdVKdt8.js.map
503
+ //# sourceMappingURL=vite-plugin-C-jEpd8t.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite-plugin-C-jEpd8t.js","names":[],"sources":["../src/extraction/extract.ts","../src/extraction/key-store.ts","../src/extraction/source-map.ts","../src/extraction/scan.ts","../src/extraction/vite-plugin.ts"],"sourcesContent":["import type { FileResult, PluginItem } from '@babel/core';\nimport type { ExtractedKeyOccurrence, ExtractionError } from './types.js';\n\n/** TypeScript extensions (need 'typescript' babel plugin) */\nexport const TS_EXTENSIONS = ['.ts', '.tsx'] as const;\n\n/** JSX extensions (need 'jsx' babel plugin) */\nexport const JSX_EXTENSIONS = ['.jsx', '.tsx'] as const;\n\n/** Plain JS extensions */\nexport const JS_EXTENSIONS = ['.js', '.jsx'] as const;\n\n/**\n * Extensions that can be parsed directly by Babel (raw source files).\n * Used for eager scanning before Vite processes them.\n */\nexport const BABEL_EXTENSIONS = [...TS_EXTENSIONS, ...JS_EXTENSIONS] as const;\n\n/**\n * All extensions that may contain t() calls.\n * Includes .astro which requires Astro's compiler before Babel can parse it.\n */\nexport const ALL_EXTENSIONS = [...BABEL_EXTENSIONS, '.astro'] as const;\n\nexport type ExtractOptions = {\n filename: string;\n code: string;\n stripFallbacks?: boolean | undefined;\n onKeyExtracted?: ((key: ExtractedKeyOccurrence) => void) | undefined;\n};\n\nexport type ExtractResult = {\n keys: ExtractedKeyOccurrence[];\n /** t() calls whose meta could not be read statically */\n errors: ExtractionError[];\n code: string | null;\n map: FileResult['map'];\n};\n\n/**\n * Extract keys from a single file using Babel.\n * Optionally strips fallbacks (for production builds).\n */\nexport async function extractKeysFromFile(options: ExtractOptions): Promise<ExtractResult> {\n const { filename, code, stripFallbacks = false, onKeyExtracted } = options;\n\n const keys: ExtractedKeyOccurrence[] = [];\n const errors: ExtractionError[] = [];\n\n // dynamic imports prevent Babel from being bundled into server runtime\n const [{ transformAsync }, { i18nExtractPlugin }] = await Promise.all([\n import('@babel/core'),\n import('./babel-plugin.js'),\n ]);\n\n // treat .astro files as TypeScript (otherwise type imports fail)\n const isTypeScript = TS_EXTENSIONS.some((ext) => filename.endsWith(ext)) || filename.endsWith('.astro');\n const isJSX = JSX_EXTENSIONS.some((ext) => filename.endsWith(ext));\n\n const result = await transformAsync(code, {\n filename,\n sourceMaps: stripFallbacks, // only need source maps when transforming\n babelrc: false,\n configFile: false,\n parserOpts: {\n plugins: [...(isTypeScript ? ['typescript' as const] : []), ...(isJSX ? ['jsx' as const] : [])],\n },\n plugins: [\n [\n i18nExtractPlugin,\n {\n stripFallbacks,\n onKeyExtracted: (key: ExtractedKeyOccurrence) => {\n keys.push(key);\n onKeyExtracted?.(key);\n },\n onExtractionError: (error: ExtractionError) => {\n errors.push(error);\n },\n },\n ] as PluginItem,\n ],\n });\n\n return {\n keys,\n errors,\n code: result?.code ?? null,\n map: result?.map ?? null,\n };\n}\n","import type { AstroIntegrationLogger } from 'astro';\nimport type { ConsistencyCheckLevel } from '../integration/types.js';\nimport type { TranslationMeta } from '../shared/types.js';\nimport type { ExtractedKey, ExtractedKeyOccurrence, ExtractionError } from './types.js';\n\n/**\n * Inconsistency between two occurrences of the same translation key\n */\nexport type KeyInconsistency = {\n key: string;\n field: 'fallback' | 'description' | 'variables';\n locations: [string, string];\n values: [string, string];\n};\n\n/**\n * Store for extracted i18n keys.\n * Stores occurrences and produces deduplicated keys with all file locations.\n */\nexport class KeyStore {\n /** All key occurrences (may have duplicates) */\n private readonly occurrences: ExtractedKeyOccurrence[] = [];\n\n /** Tracks reported inconsistencies to avoid duplicate warnings */\n private readonly reportedInconsistencies = new Set<string>();\n\n /** Whether an error-level inconsistency was found (for build failure) */\n private hasInconsistencyError = false;\n\n /** Non-extractable t() meta, per file (replaced wholesale on HMR) */\n private readonly errorsByFile = new Map<string, ExtractionError[]>();\n\n readonly fileToKeys = new Map<string, string[]>();\n readonly filesWithI18n = new Set<string>();\n\n constructor(\n private readonly logger: AstroIntegrationLogger,\n private readonly consistency: ConsistencyCheckLevel = 'error',\n ) {}\n\n /**\n * Add key occurrences for a file, replacing any existing occurrences for that file.\n */\n addFileKeys(filename: string, keys: ExtractedKeyOccurrence[]): void {\n const newKeyStrings = keys.map((k) => k.key);\n const oldKeys = this.fileToKeys.get(filename);\n\n // log key changes on HMR\n if (oldKeys) {\n const uniqueNew = [...new Set(newKeyStrings)];\n const uniqueOld = [...new Set(oldKeys)];\n const added = uniqueNew.filter((k) => !uniqueOld.includes(k));\n const removed = uniqueOld.filter((k) => !uniqueNew.includes(k));\n const file = filename.split('/').pop();\n\n if (added.length > 0 || removed.length > 0) {\n const parts: string[] = [];\n\n if (added.length > 0) parts.push(`+${added.length}`);\n if (removed.length > 0) parts.push(`-${removed.length}`);\n\n this.logger.info(`hmr: ${parts.join(' ')} key(s) in ${file}`);\n }\n }\n\n // remove old occurrences for this file (if any)\n if (oldKeys) {\n for (let i = this.occurrences.length - 1; i >= 0; i--) {\n if (this.occurrences[i]?.file === filename) {\n this.occurrences.splice(i, 1);\n }\n }\n }\n\n this.filesWithI18n.add(filename);\n\n // check for inconsistencies before adding new keys\n if (this.consistency !== 'off') {\n this.checkConsistency(keys);\n }\n\n if (keys.length > 0) {\n this.occurrences.push(...keys);\n }\n\n this.fileToKeys.set(filename, newKeyStrings);\n }\n\n /**\n * Record the non-extractable t() calls found in a file, replacing any\n * previously recorded for it.\n */\n addFileErrors(filename: string, errors: ExtractionError[]): void {\n if (errors.length > 0) {\n this.errorsByFile.set(filename, errors);\n } else {\n this.errorsByFile.delete(filename);\n }\n }\n\n /**\n * All non-extractable t() calls found so far, across every scanned file.\n */\n get extractionErrors(): ExtractionError[] {\n return Array.from(this.errorsByFile.values()).flat();\n }\n\n /**\n * Check new keys for inconsistencies with existing occurrences.\n */\n private checkConsistency(newKeys: ExtractedKeyOccurrence[]): void {\n // build a map of existing keys (first occurrence for each key)\n const existingByKey = new Map<string, ExtractedKeyOccurrence>();\n\n for (const occ of this.occurrences) {\n if (!existingByKey.has(occ.key)) {\n existingByKey.set(occ.key, occ);\n }\n }\n\n for (const newKey of newKeys) {\n const existing = existingByKey.get(newKey.key);\n\n if (!existing) continue;\n\n const inconsistencies = this.findInconsistencies(newKey, existing);\n\n for (const inc of inconsistencies) {\n this.reportInconsistency(inc);\n }\n }\n }\n\n /**\n * Compare two occurrences and find any metadata inconsistencies.\n */\n private findInconsistencies(a: ExtractedKeyOccurrence, b: ExtractedKeyOccurrence): KeyInconsistency[] {\n const result: KeyInconsistency[] = [];\n const locA = `${a.file}:${a.line}`;\n const locB = `${b.file}:${b.line}`;\n\n if (a.meta.fallback !== b.meta.fallback) {\n result.push({\n key: a.key,\n field: 'fallback',\n locations: [locA, locB],\n values: [a.meta.fallback, b.meta.fallback],\n });\n }\n\n if (a.meta.description !== b.meta.description) {\n result.push({\n key: a.key,\n field: 'description',\n locations: [locA, locB],\n values: [a.meta.description ?? '(none)', b.meta.description ?? '(none)'],\n });\n }\n\n const varsA = this.serializeVariables(a.meta);\n const varsB = this.serializeVariables(b.meta);\n\n if (varsA !== varsB) {\n result.push({\n key: a.key,\n field: 'variables',\n locations: [locA, locB],\n values: [varsA || '(none)', varsB || '(none)'],\n });\n }\n\n return result;\n }\n\n /**\n * Serialize variables for comparison.\n */\n private serializeVariables(meta: TranslationMeta): string {\n if (!meta.variables) return '';\n\n // sort keys for consistent comparison\n const sorted: Record<string, unknown> = {};\n\n for (const key of Object.keys(meta.variables).sort()) {\n sorted[key] = meta.variables[key];\n }\n\n return JSON.stringify(sorted);\n }\n\n /**\n * Report an inconsistency via logger.\n */\n private reportInconsistency(inc: KeyInconsistency): void {\n // create a unique key for this inconsistency to avoid duplicate reports\n // use key+field only (not locations) to report once per inconsistent key\n const incKey = `${inc.key}:${inc.field}`;\n\n if (this.reportedInconsistencies.has(incKey)) return;\n\n this.reportedInconsistencies.add(incKey);\n\n const message =\n `inconsistent ${inc.field} for key \"${inc.key}\"\\n` +\n ` ${inc.locations[0]}: ${JSON.stringify(inc.values[0])}\\n` +\n ` ${inc.locations[1]}: ${JSON.stringify(inc.values[1])}`;\n\n if (this.consistency === 'error') {\n this.logger.error(message);\n this.hasInconsistencyError = true;\n } else {\n this.logger.warn(message);\n }\n }\n\n /**\n * Check if any error-level inconsistencies were found.\n * Call this at the end of build to determine if it should fail.\n */\n get hasErrors(): boolean {\n return this.hasInconsistencyError;\n }\n\n /**\n * Get deduplicated keys with all file locations merged.\n * Last occurrence's meta wins for each key.\n */\n get extractedKeys(): ExtractedKey[] {\n const keyMap = new Map<string, ExtractedKey>();\n\n for (const occurrence of this.occurrences) {\n const existing = keyMap.get(occurrence.key);\n const fileLocation = `${occurrence.file}:${occurrence.line}`;\n\n if (existing) {\n if (!existing.files.includes(fileLocation)) {\n existing.files.push(fileLocation);\n }\n\n existing.meta = occurrence.meta;\n } else {\n keyMap.set(occurrence.key, {\n key: occurrence.key,\n meta: occurrence.meta,\n files: [fileLocation],\n });\n }\n }\n\n return Array.from(keyMap.values());\n }\n\n /**\n * Get count of unique keys.\n */\n get uniqueKeyCount(): number {\n return new Set(this.occurrences.map((k) => k.key)).size;\n }\n\n /**\n * Merge another store's data into this one.\n */\n merge(other: KeyStore): void {\n for (const [file, keys] of other.fileToKeys) {\n this.fileToKeys.set(file, keys);\n }\n\n for (const [file, errors] of other.errorsByFile) {\n this.errorsByFile.set(file, errors);\n }\n\n for (const file of other.filesWithI18n) {\n this.filesWithI18n.add(file);\n }\n\n if (this.consistency !== 'off') {\n this.checkConsistency(other.occurrences);\n }\n\n this.occurrences.push(...other.occurrences);\n }\n\n /**\n * Internal access to occurrences (for merge)\n */\n get occurrencesList(): ExtractedKeyOccurrence[] {\n return this.occurrences;\n }\n}\n","import { TraceMap, originalPositionFor } from '@jridgewell/trace-mapping';\nimport type { ExtractionError } from './types.js';\n\n/**\n * Rewrite compiled-output positions back to the authored source.\n *\n * Babel parses .astro files after Astro's compiler has rewritten them, so the\n * positions it reports refer to code the developer never wrote. Errors that\n * cannot be mapped keep the position babel gave them.\n */\nexport function mapErrorsToSource(errors: ExtractionError[], map: unknown): ExtractionError[] {\n if (errors.length === 0 || !map) {\n return errors;\n }\n\n let tracer: TraceMap;\n\n try {\n tracer = new TraceMap(map as never);\n } catch {\n return errors;\n }\n\n return errors.map((error) => {\n const position = originalPositionFor(tracer, { line: error.line, column: error.column });\n\n if (position.line === null) {\n return error;\n }\n\n return { ...error, line: position.line, column: position.column ?? error.column };\n });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { AstroIntegrationLogger } from 'astro';\nimport type { ConsistencyCheckLevel } from '../integration/types.js';\nimport { ALL_EXTENSIONS, extractKeysFromFile } from './extract.js';\nimport { KeyStore } from './key-store.js';\nimport { mapErrorsToSource } from './source-map.js';\n\nconst GLOB_PATTERN = `src/**/*.{${ALL_EXTENSIONS.map((e) => e.slice(1)).join(',')}}`;\n\n/**\n * Compile .astro file to JS using Astro's compiler.\n * Returns the compiled code and its source map, or null if compilation fails.\n */\nasync function compileAstro(code: string, filename: string): Promise<{ code: string; map: string } | null> {\n try {\n const { transform } = await import('@astrojs/compiler');\n const result = await transform(code, { filename, sourcemap: 'external' });\n\n return { code: result.code, map: result.map };\n } catch {\n return null;\n }\n}\n\nexport type ScanOptions = {\n projectRoot: string;\n logger: AstroIntegrationLogger;\n consistency: ConsistencyCheckLevel;\n};\n\n/**\n * Eagerly scan all source files for t() calls.\n * Used in dev mode to extract all keys upfront, instead of waiting for\n * Vite's lazy transform hook to process files on-demand.\n */\nexport async function scan(options: ScanOptions): Promise<KeyStore> {\n const { projectRoot, logger, consistency } = options;\n const store = new KeyStore(logger, consistency);\n\n const files: string[] = [];\n\n for await (const entry of fs.promises.glob(GLOB_PATTERN, {\n cwd: projectRoot,\n exclude: (name) => name === 'node_modules',\n })) {\n files.push(path.resolve(projectRoot, entry));\n }\n\n const results = await Promise.all(\n files.map(async (file) => {\n let code = await fs.promises.readFile(file, 'utf-8');\n\n // quick check: skip files without i18n translate import\n if (!code.includes('@astroscope/i18n/translate')) {\n return { file, keys: null, errors: [] };\n }\n\n // compile .astro files first, keeping the map to report authored positions\n let astroMap: string | undefined;\n\n if (file.endsWith('.astro')) {\n const compiled = await compileAstro(code, file);\n\n if (!compiled) {\n return { file, keys: null, errors: [] };\n }\n\n code = compiled.code;\n astroMap = compiled.map;\n }\n\n const result = await extractKeysFromFile({\n filename: file,\n code,\n stripFallbacks: false,\n });\n\n return {\n file,\n keys: result.keys.length > 0 ? result.keys : null,\n errors: mapErrorsToSource(result.errors, astroMap),\n };\n }),\n );\n\n for (const { file, keys, errors } of results) {\n if (keys) {\n store.addFileKeys(file, keys);\n }\n\n store.addFileErrors(file, errors);\n }\n\n return store;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { AstroIntegrationLogger } from 'astro';\nimport MagicString from 'magic-string';\nimport type { Plugin } from 'vite';\nimport type { ConsistencyCheckLevel } from '../integration/types.js';\nimport { chunkIdToName } from '../shared/url.js';\nimport { ALL_EXTENSIONS, extractKeysFromFile } from './extract.js';\nimport { KeyStore } from './key-store.js';\nimport { getGlobalState, getManifest } from './manifest.js';\nimport { scan } from './scan.js';\nimport { mapErrorsToSource } from './source-map.js';\nimport type { ExtractionError } from './types.js';\n\nconst VIRTUAL_MODULE_ID = 'virtual:@astroscope/i18n/manifest';\nconst isVirtualModuleId = (id: string) => id === VIRTUAL_MODULE_ID || id.startsWith(`${VIRTUAL_MODULE_ID}?`);\n\nconst RESOLVED_VIRTUAL_MODULE_ID = `\\0${VIRTUAL_MODULE_ID}`;\nconst isResolvedVirtualModuleId = (id: string) =>\n id === RESOLVED_VIRTUAL_MODULE_ID || id.startsWith(`\\0${VIRTUAL_MODULE_ID}?`);\n\n// manifest JSON file name (emitted during build)\nconst MANIFEST_FILE_NAME = 'i18n-manifest.json';\n\nexport type I18nVitePluginOptions = {\n logger: AstroIntegrationLogger;\n consistency: ConsistencyCheckLevel;\n};\n\n/**\n * Describe a non-extractable t() call for a developer.\n */\nfunction formatExtractionError(error: ExtractionError, projectRoot: string): string {\n const location = `${path.relative(projectRoot, error.file)}:${error.line}:${error.column + 1}`;\n\n return `${location} — t('${error.key}') ${error.reason}`;\n}\n\n/**\n * Non-extractable meta is fatal for a production build. The fallback argument is\n * stripped from the bundle, so a key whose fallback could not be read at build\n * time has nothing to fall back to and renders its own key string to end users.\n */\nfunction formatExtractionErrors(errors: ExtractionError[], projectRoot: string): string {\n const list = errors.map((e) => ` - ${formatExtractionError(e, projectRoot)}`).join('\\n');\n\n return (\n `i18n: ${errors.length} t() call(s) have a fallback that cannot be read at build time.\\n\\n` +\n `${list}\\n\\n` +\n `Production builds strip the fallback argument, so these keys would render as their own key string. ` +\n `Fallbacks must be static string literals — pass runtime values as MF2 variables instead:\\n` +\n ` t('some.key', 'Hello {$name}', { name })`\n );\n}\n\n/**\n * Vite plugin for i18n extraction, chunk mapping, and loader injection\n *\n * This plugin:\n * 1. Extracts all t() calls using Babel AST parsing\n * 2. Strips fallback arguments in production builds\n * 3. Maps translation keys to output chunks\n * 4. Generates a manifest for syncing with translation providers\n * 5. Injects translation loader into chunks that use t()\n */\nexport function i18nVitePlugin(options: I18nVitePluginOptions): Plugin {\n const { logger, consistency } = options;\n\n const store = new KeyStore(logger, consistency);\n\n // sync store's computed keys to global state (for dev mode live access)\n const syncGlobalState = () => {\n const state = getGlobalState();\n state.extractedKeys = store.extractedKeys;\n state.version++;\n };\n\n let isBuild = false;\n let projectRoot = '';\n\n return {\n name: '@astroscope/i18n/extract',\n enforce: 'pre',\n\n configResolved(config) {\n const state = getGlobalState();\n state.projectRoot = config.root;\n\n isBuild = config.command === 'build';\n projectRoot = config.root;\n },\n\n async configureServer(server) {\n // configureServer can be called during astro build's internal dev server\n // check isProduction to skip eager scanning during build\n if (server.config.isProduction || isBuild) {\n return;\n }\n\n // in dev mode, eagerly scan all files upfront\n // this ensures all t() calls are found immediately\n // (otherwise vite loads lazily as files are requested)\n const result = await scan({ projectRoot, logger, consistency });\n\n store.merge(result);\n\n syncGlobalState();\n\n logger.info(`dev mode: scanned ${result.fileToKeys.size} files, found ${result.uniqueKeyCount} keys`);\n\n // surface here what the build would later reject\n for (const error of store.extractionErrors) {\n logger.warn(formatExtractionError(error, projectRoot));\n }\n },\n\n resolveId(id) {\n if (isVirtualModuleId(id)) {\n return `\\0${id}`;\n }\n },\n\n load(id) {\n if (isResolvedVirtualModuleId(id)) {\n if (isBuild) {\n // in build mode, load manifest from JSON file at runtime\n return `\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst manifestJson = JSON.parse(readFileSync(join(__dirname, '${MANIFEST_FILE_NAME}'), 'utf-8'));\n\nexport const manifest = manifestJson;\nexport function getManifest() { return manifestJson; }\n`;\n }\n\n // in dev mode, import the getManifest function from the plugin\n // this provides live access to the extraction state as files are transformed\n return `\nimport { getManifest as _getManifest } from '@astroscope/i18n/extraction';\nexport const manifest = { keys: [], chunks: {}, scripts: [] };\nexport function getManifest() { return _getManifest(); }\n`;\n }\n },\n\n async transform(code, filename) {\n if (!ALL_EXTENSIONS.some((ext) => filename.endsWith(ext))) {\n return null;\n }\n\n if (filename.includes('node_modules')) {\n return null;\n }\n\n // quick check: skip files without i18n translate import\n if (!code.includes('@astroscope/i18n/translate')) {\n return null;\n }\n\n const result = await extractKeysFromFile({\n filename,\n code,\n stripFallbacks: isBuild,\n });\n\n // only pay for the sourcemap lookup when there is something to report\n const errors = result.errors.length > 0 ? mapErrorsToSource(result.errors, this.getCombinedSourcemap()) : [];\n\n store.addFileKeys(filename, result.keys);\n store.addFileErrors(filename, errors);\n\n // dev keeps the fallback argument, so a non-extractable one still renders\n // correctly at runtime — warn here and let the build be the hard gate\n if (!isBuild) {\n for (const error of errors) {\n logger.warn(formatExtractionError(error, projectRoot));\n }\n }\n\n syncGlobalState();\n\n // build mode: return transformed code with source map\n // serialize babel's map to a string: vite accepts string source maps and\n // its structural ExistingRawSourceMap type (vite 8) rejects babel's map shape\n if (isBuild && result.code) {\n return result.map ? { code: result.code, map: JSON.stringify(result.map) } : { code: result.code };\n }\n\n return null; // dev mode: keep fallbacks\n },\n\n generateBundle(_, bundle) {\n const state = getGlobalState();\n\n // reset for each build (server + client run separately)\n state.chunkManifest = {};\n state.scriptChunks = [];\n\n // first pass: collect keys, determine which chunks have i18n, and build direct imports map\n const chunksWithI18n = new Set<string>();\n const chunkNameToFileName = new Map<string, string>();\n const directImports = new Map<string, string[]>(); // chunk → direct imports incl. dynamic (chunks only)\n const scriptEntries: string[] = [];\n\n for (const [fileName, chunk] of Object.entries(bundle)) {\n if (chunk.type === 'chunk' && chunk.moduleIds) {\n const keys = new Set<string>();\n let hasI18nModule = false;\n\n // collect keys from all (sub)modules in the chunk\n for (const moduleId of chunk.moduleIds) {\n const moduleKeys = store.fileToKeys.get(moduleId);\n\n moduleKeys?.forEach((k) => keys.add(k));\n\n if (store.filesWithI18n.has(moduleId)) {\n hasI18nModule = true;\n }\n }\n\n const chunkName = chunkIdToName(fileName.replace(/\\.js$/, '')); // cut .js extension\n\n if (keys.size) {\n state.chunkManifest[chunkName] = Array.from(keys);\n }\n\n if (hasI18nModule) {\n chunksWithI18n.add(chunkName);\n }\n\n chunkNameToFileName.set(chunkName, fileName);\n\n const imports: string[] = [];\n\n for (const importedFile of [...chunk.imports, ...chunk.dynamicImports]) {\n const baseName = importedFile.replace(/^.*\\//, '').replace(/\\.js$/, '');\n\n imports.push(chunkIdToName(baseName));\n }\n\n directImports.set(chunkName, imports);\n\n // astro `<script>` entries are not islands, so no island carries their\n // hashes — collect them so the middleware can bootstrap their chunks\n if ((chunk.isEntry || chunk.isDynamicEntry) && chunk.facadeModuleId?.includes('astro&type=script')) {\n scriptEntries.push(chunkName);\n }\n }\n }\n\n // i18n chunks reachable from script entries (the entry itself included)\n const scriptChunks = new Set<string>();\n\n const walkScripts = (chunkName: string, visited: Set<string>): void => {\n if (visited.has(chunkName)) return;\n\n visited.add(chunkName);\n\n if (state.chunkManifest[chunkName]) {\n scriptChunks.add(chunkName);\n }\n\n for (const imported of directImports.get(chunkName) ?? []) {\n walkScripts(imported, visited);\n }\n };\n\n const visited = new Set<string>();\n\n for (const entry of scriptEntries) {\n walkScripts(entry, visited);\n }\n\n state.scriptChunks = [...scriptChunks];\n\n // second pass: inject loaders (prefetching is handled by the islands emitter)\n for (const [fileName, chunk] of Object.entries(bundle)) {\n if (chunk.type !== 'chunk') continue;\n\n const chunkName = chunkIdToName(fileName.replace(/\\.js$/, ''));\n\n if (!chunksWithI18n.has(chunkName)) continue;\n\n // simple translation loader - just load own translations\n const loaderCode =\n `if(typeof window!=='undefined'&&window.__i18n__){` +\n `const _=window.__i18n__,h=_.hashes[${JSON.stringify(chunkName)}];` +\n `if(h)await import(\\`/_i18n/\\${_.locale}/${chunkName}.\\${h}.js\\`);` +\n `}`;\n\n // inject loader at start of chunk preserving source maps\n const s = new MagicString(chunk.code);\n\n s.prepend(loaderCode);\n chunk.code = s.toString();\n\n if (chunk.map) {\n chunk.map = s.generateMap({ hires: true }) as typeof chunk.map;\n }\n }\n\n logger.info(`manifest: ${Object.keys(state.chunkManifest).length} chunks, ${store.uniqueKeyCount} keys`);\n\n // a fallback that could not be read is a broken string in production\n const extractionErrors = store.extractionErrors;\n\n if (extractionErrors.length > 0) {\n throw new Error(formatExtractionErrors(extractionErrors, projectRoot));\n }\n\n if (consistency === 'error' && store.hasErrors) {\n throw new Error('i18n: build failed due to translation key inconsistencies');\n }\n },\n\n writeBundle(outputOptions) {\n // write the manifest JSON file after bundle is written\n // only emit from client build (has full chunk mapping, runs after server build)\n // write to server directory so it's not publicly accessible (same location as the virtual module)\n if (this.environment.name === 'client' && outputOptions.dir) {\n const chunksDir = path.resolve(outputOptions.dir, '..', 'server', 'chunks');\n const manifestPath = path.join(chunksDir, MANIFEST_FILE_NAME);\n\n if (fs.existsSync(chunksDir)) {\n fs.writeFileSync(manifestPath, JSON.stringify(getManifest()));\n } else {\n logger.error(`server chunks directory not found, cannot write manifest to ${manifestPath}`);\n }\n }\n },\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@astroscope/i18n",
3
- "version": "1.1.1",
4
- "description": "i18n for Astro + React islands — MessageFormat 2, automatic tree-shaking, parallel loading, any translation source",
3
+ "version": "2.0.0",
4
+ "description": "i18n for Astro + React islands - MessageFormat 2, automatic tree-shaking, parallel loading, any translation source",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -15,28 +15,9 @@
15
15
  "browser": "./dist/client/translate.js",
16
16
  "default": "./dist/server/translate.js"
17
17
  },
18
- "./client-directives/load.js": {
19
- "types": "./dist/client/directives/load.d.ts",
20
- "import": "./dist/client/directives/load.js"
21
- },
22
- "./client-directives/idle.js": {
23
- "types": "./dist/client/directives/idle.d.ts",
24
- "import": "./dist/client/directives/idle.js"
25
- },
26
- "./client-directives/visible.js": {
27
- "types": "./dist/client/directives/visible.d.ts",
28
- "import": "./dist/client/directives/visible.js"
29
- },
30
- "./client-directives/media.js": {
31
- "types": "./dist/client/directives/media.d.ts",
32
- "import": "./dist/client/directives/media.js"
33
- },
34
- "./client-directives/only.js": {
35
- "types": "./dist/client/directives/only.d.ts",
36
- "import": "./dist/client/directives/only.js"
37
- },
38
- "./astro": {
39
- "import": "./src/astro/index.ts"
18
+ "./chunk-middleware": {
19
+ "types": "./dist/server/chunk-middleware-entrypoint.d.ts",
20
+ "import": "./dist/server/chunk-middleware-entrypoint.js"
40
21
  },
41
22
  "./internal": {
42
23
  "types": "./dist/internal.d.ts",
@@ -48,11 +29,9 @@
48
29
  }
49
30
  },
50
31
  "files": [
51
- "dist",
52
- "src/astro"
32
+ "dist"
53
33
  ],
54
34
  "sideEffects": [
55
- "./dist/client/directives/*.js",
56
35
  "./dist/chunk-*.js"
57
36
  ],
58
37
  "publishConfig": {
@@ -86,25 +65,25 @@
86
65
  "@babel/core": "^8.0.1",
87
66
  "@babel/preset-typescript": "^8.0.1",
88
67
  "@jridgewell/trace-mapping": "^0.3.31",
89
- "magic-string": "^0.30.21",
68
+ "magic-string": "^1.2.2",
90
69
  "messageformat": "^4.0.0"
91
70
  },
92
71
  "devDependencies": {
72
+ "@astroscope/node": "^2.0.0",
93
73
  "@babel/types": "^8.0.4",
94
74
  "@types/babel__core": "^7.20.5",
95
- "astro": "^7.0.9",
96
- "tsdown": "^0.22.8",
75
+ "astro": "^7.2.6",
76
+ "tsdown": "^0.22.14",
97
77
  "typescript": "^6.0.3",
98
- "vite": "^8.1.5",
99
- "@astroscope/node": "^1.4.0"
78
+ "vite": "^8.2.2"
100
79
  },
101
80
  "peerDependencies": {
81
+ "@astroscope/node": "^2.0.0",
102
82
  "astro": "^7.0.0",
103
- "vite": "^8.0.0",
104
- "@astroscope/node": "^1.4.0"
83
+ "vite": "^8.0.0"
105
84
  },
106
85
  "scripts": {
107
- "build": "tsdown src/index.ts src/internal.ts src/extraction/index.ts src/server/translate.ts src/client/translate.ts src/client/directives/load.ts src/client/directives/idle.ts src/client/directives/visible.ts src/client/directives/media.ts src/client/directives/only.ts src/client/directives/utils.ts --format esm --dts --no-fixed-extension --deps.never-bundle astro --deps.never-bundle astro/client/load.js --deps.never-bundle astro/client/idle.js --deps.never-bundle astro/client/visible.js --deps.never-bundle astro/client/media.js --deps.never-bundle astro/client/only.js --deps.never-bundle virtual:@astroscope/i18n/manifest --deps.never-bundle @babel/core",
86
+ "build": "tsdown",
108
87
  "typecheck": "tsc --noEmit",
109
88
  "lint": "eslint src --cache",
110
89
  "lint:fix": "eslint src --fix"
@@ -1,6 +0,0 @@
1
- import { ClientDirective } from "astro";
2
- //#region src/client/directives/idle.d.ts
3
- declare const idleDirective: ClientDirective;
4
- //#endregion
5
- export { idleDirective as default };
6
- //# sourceMappingURL=idle.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"idle.d.ts","names":[],"sources":["../../../src/client/directives/idle.ts"],"mappings":";;cASM,eAAe"}
@@ -1,14 +0,0 @@
1
- import { warmUpI18nForChunk } from "./utils.js";
2
- //#region src/client/directives/idle.ts
3
- const idleDirective = (load, _options, el) => {
4
- const cb = async () => {
5
- warmUpI18nForChunk(el);
6
- await (await load())();
7
- };
8
- if ("requestIdleCallback" in window) window.requestIdleCallback(cb);
9
- else setTimeout(cb, 200);
10
- };
11
- //#endregion
12
- export { idleDirective as default };
13
-
14
- //# sourceMappingURL=idle.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"idle.js","names":[],"sources":["../../../src/client/directives/idle.ts"],"sourcesContent":["/**\n * i18n-aware client:idle directive\n *\n * Based on Astro's idle directive (MIT License)\n * https://github.com/withastro/astro/blob/main/packages/astro/src/runtime/client/idle.ts\n */\nimport type { ClientDirective } from 'astro';\nimport { warmUpI18nForChunk } from './utils.js';\n\nconst idleDirective: ClientDirective = (load, _options, el) => {\n const cb = async () => {\n warmUpI18nForChunk(el);\n const hydrate = await load();\n await hydrate();\n };\n\n if ('requestIdleCallback' in window) {\n (window as unknown as { requestIdleCallback: (cb: () => void) => void }).requestIdleCallback(cb);\n } else {\n setTimeout(cb, 200);\n }\n};\n\nexport default idleDirective;\n"],"mappings":";;AASA,MAAM,iBAAkC,MAAM,UAAU,OAAO;CAC7D,MAAM,KAAK,YAAY;EACrB,mBAAmB,EAAE;EAErB,OAAM,MADgB,KAAK,EAAA,CACb;CAChB;CAEA,IAAI,yBAAyB,QAC3B,OAAyE,oBAAoB,EAAE;MAE/F,WAAW,IAAI,GAAG;AAEtB"}
@@ -1,6 +0,0 @@
1
- import { ClientDirective } from "astro";
2
- //#region src/client/directives/load.d.ts
3
- declare const loadDirective: ClientDirective;
4
- //#endregion
5
- export { loadDirective as default };
6
- //# sourceMappingURL=load.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"load.d.ts","names":[],"sources":["../../../src/client/directives/load.ts"],"mappings":";;cASM,eAAe"}
@@ -1,10 +0,0 @@
1
- import { warmUpI18nForChunk } from "./utils.js";
2
- //#region src/client/directives/load.ts
3
- const loadDirective = async (load, _options, el) => {
4
- warmUpI18nForChunk(el);
5
- await (await load())();
6
- };
7
- //#endregion
8
- export { loadDirective as default };
9
-
10
- //# sourceMappingURL=load.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"load.js","names":[],"sources":["../../../src/client/directives/load.ts"],"sourcesContent":["/**\n * i18n-aware client:load directive\n *\n * Based on Astro's load directive (MIT License)\n * https://github.com/withastro/astro/blob/main/packages/astro/src/runtime/client/load.ts\n */\nimport type { ClientDirective } from 'astro';\nimport { warmUpI18nForChunk } from './utils.js';\n\nconst loadDirective: ClientDirective = async (load, _options, el) => {\n warmUpI18nForChunk(el);\n const hydrate = await load();\n await hydrate();\n};\n\nexport default loadDirective;\n"],"mappings":";;AASA,MAAM,gBAAiC,OAAO,MAAM,UAAU,OAAO;CACnE,mBAAmB,EAAE;CAErB,OAAM,MADgB,KAAK,EAAA,CACb;AAChB"}
@@ -1,6 +0,0 @@
1
- import { ClientDirective } from "astro";
2
- //#region src/client/directives/media.d.ts
3
- declare const mediaDirective: ClientDirective;
4
- //#endregion
5
- export { mediaDirective as default };
6
- //# sourceMappingURL=media.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"media.d.ts","names":[],"sources":["../../../src/client/directives/media.ts"],"mappings":";;cASM,gBAAgB"}
@@ -1,17 +0,0 @@
1
- import { warmUpI18nForChunk } from "./utils.js";
2
- //#region src/client/directives/media.ts
3
- const mediaDirective = (load, options, el) => {
4
- const cb = async () => {
5
- warmUpI18nForChunk(el);
6
- await (await load())();
7
- };
8
- if (options.value) {
9
- const mql = matchMedia(options.value);
10
- if (mql.matches) cb();
11
- else mql.addEventListener("change", cb, { once: true });
12
- }
13
- };
14
- //#endregion
15
- export { mediaDirective as default };
16
-
17
- //# sourceMappingURL=media.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"media.js","names":[],"sources":["../../../src/client/directives/media.ts"],"sourcesContent":["/**\n * i18n-aware client:media directive\n *\n * Based on Astro's media directive (MIT License)\n * https://github.com/withastro/astro/blob/main/packages/astro/src/runtime/client/media.ts\n */\nimport type { ClientDirective } from 'astro';\nimport { warmUpI18nForChunk } from './utils.js';\n\nconst mediaDirective: ClientDirective = (load, options, el) => {\n const cb = async () => {\n warmUpI18nForChunk(el);\n const hydrate = await load();\n await hydrate();\n };\n\n if (options.value) {\n const mql = matchMedia(options.value);\n if (mql.matches) {\n cb();\n } else {\n mql.addEventListener('change', cb, { once: true });\n }\n }\n};\n\nexport default mediaDirective;\n"],"mappings":";;AASA,MAAM,kBAAmC,MAAM,SAAS,OAAO;CAC7D,MAAM,KAAK,YAAY;EACrB,mBAAmB,EAAE;EAErB,OAAM,MADgB,KAAK,EAAA,CACb;CAChB;CAEA,IAAI,QAAQ,OAAO;EACjB,MAAM,MAAM,WAAW,QAAQ,KAAK;EACpC,IAAI,IAAI,SACN,GAAG;OAEH,IAAI,iBAAiB,UAAU,IAAI,EAAE,MAAM,KAAK,CAAC;CAErD;AACF"}
@@ -1,6 +0,0 @@
1
- import { ClientDirective } from "astro";
2
- //#region src/client/directives/only.d.ts
3
- declare const onlyDirective: ClientDirective;
4
- //#endregion
5
- export { onlyDirective as default };
6
- //# sourceMappingURL=only.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"only.d.ts","names":[],"sources":["../../../src/client/directives/only.ts"],"mappings":";;cAWM,eAAe"}
@@ -1,10 +0,0 @@
1
- import { warmUpI18nForChunk } from "./utils.js";
2
- //#region src/client/directives/only.ts
3
- const onlyDirective = async (load, _options, el) => {
4
- warmUpI18nForChunk(el);
5
- await (await load())();
6
- };
7
- //#endregion
8
- export { onlyDirective as default };
9
-
10
- //# sourceMappingURL=only.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"only.js","names":[],"sources":["../../../src/client/directives/only.ts"],"sourcesContent":["/**\n * i18n-aware client:only directive\n *\n * Based on Astro's load directive (MIT License)\n * https://github.com/withastro/astro/blob/main/packages/astro/src/runtime/client/load.ts\n *\n * client:only works the same as client:load - immediate hydration\n */\nimport type { ClientDirective } from 'astro';\nimport { warmUpI18nForChunk } from './utils.js';\n\nconst onlyDirective: ClientDirective = async (load, _options, el) => {\n warmUpI18nForChunk(el);\n const hydrate = await load();\n await hydrate();\n};\n\nexport default onlyDirective;\n"],"mappings":";;AAWA,MAAM,gBAAiC,OAAO,MAAM,UAAU,OAAO;CACnE,mBAAmB,EAAE;CAErB,OAAM,MADgB,KAAK,EAAA,CACb;AAChB"}
@@ -1,10 +0,0 @@
1
- //#region src/client/directives/utils.d.ts
2
- /**
3
- * Warm up translation cache for a chunk and all its descendants (fire and forget)
4
- * Extracts chunk name from astro-island's component-url attribute
5
- * Uses flattened imports map from window.__i18n__ to prefetch all nested translations
6
- */
7
- declare function warmUpI18nForChunk(el: HTMLElement): void;
8
- //#endregion
9
- export { warmUpI18nForChunk };
10
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","names":[],"sources":["../../../src/client/directives/utils.ts"],"mappings":";;;;;;iBAqBgB,mBAAmB,IAAI"}
@@ -1,32 +0,0 @@
1
- import { r as componentUrlToChunkName, t as buildI18nChunkUrl } from "../../url-B8334XSD.js";
2
- import { t as getI18nState } from "../../state-DeudhdeT.js";
3
- //#region src/client/directives/utils.ts
4
- /**
5
- * Prefetch translation chunk (fire and forget)
6
- */
7
- function prefetchTranslation(chunkName, i18n) {
8
- const hash = i18n.hashes[chunkName];
9
- if (hash) import(
10
- /* @vite-ignore */
11
- buildI18nChunkUrl(i18n.locale, chunkName, hash)
12
- );
13
- }
14
- /**
15
- * Warm up translation cache for a chunk and all its descendants (fire and forget)
16
- * Extracts chunk name from astro-island's component-url attribute
17
- * Uses flattened imports map from window.__i18n__ to prefetch all nested translations
18
- */
19
- function warmUpI18nForChunk(el) {
20
- const componentUrl = el.getAttribute("component-url");
21
- if (!componentUrl) return;
22
- const i18n = getI18nState();
23
- if (!i18n) return;
24
- const chunkName = componentUrlToChunkName(componentUrl);
25
- prefetchTranslation(chunkName, i18n);
26
- const deps = i18n.imports[chunkName] ?? [];
27
- for (const dep of deps) prefetchTranslation(dep, i18n);
28
- }
29
- //#endregion
30
- export { warmUpI18nForChunk };
31
-
32
- //# sourceMappingURL=utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../../../src/client/directives/utils.ts"],"sourcesContent":["import type { I18nClientState } from '../../shared/types.js';\nimport { buildI18nChunkUrl, componentUrlToChunkName } from '../../shared/url.js';\nimport { getI18nState } from '../state.js';\n\n/**\n * Prefetch translation chunk (fire and forget)\n */\nfunction prefetchTranslation(chunkName: string, i18n: I18nClientState): void {\n const hash = i18n.hashes[chunkName];\n\n if (hash) {\n const url = buildI18nChunkUrl(i18n.locale, chunkName, hash);\n import(/* @vite-ignore */ url);\n }\n}\n\n/**\n * Warm up translation cache for a chunk and all its descendants (fire and forget)\n * Extracts chunk name from astro-island's component-url attribute\n * Uses flattened imports map from window.__i18n__ to prefetch all nested translations\n */\nexport function warmUpI18nForChunk(el: HTMLElement): void {\n const componentUrl = el.getAttribute('component-url');\n\n if (!componentUrl) return;\n\n const i18n = getI18nState();\n\n if (!i18n) return;\n\n const chunkName = componentUrlToChunkName(componentUrl);\n\n // prefetch this chunk's translations\n prefetchTranslation(chunkName, i18n);\n\n // prefetch all descendant translations (flattened in imports map)\n const deps = i18n.imports[chunkName] ?? [];\n\n for (const dep of deps) {\n prefetchTranslation(dep, i18n);\n }\n}\n"],"mappings":";;;;;;AAOA,SAAS,oBAAoB,WAAmB,MAA6B;CAC3E,MAAM,OAAO,KAAK,OAAO;CAEzB,IAAI,MAEF;;EADY,kBAAkB,KAAK,QAAQ,WAAW,IAC1B;;AAEhC;;;;;;AAOA,SAAgB,mBAAmB,IAAuB;CACxD,MAAM,eAAe,GAAG,aAAa,eAAe;CAEpD,IAAI,CAAC,cAAc;CAEnB,MAAM,OAAO,aAAa;CAE1B,IAAI,CAAC,MAAM;CAEX,MAAM,YAAY,wBAAwB,YAAY;CAGtD,oBAAoB,WAAW,IAAI;CAGnC,MAAM,OAAO,KAAK,QAAQ,cAAc,CAAC;CAEzC,KAAK,MAAM,OAAO,MAChB,oBAAoB,KAAK,IAAI;AAEjC"}
@@ -1,6 +0,0 @@
1
- import { ClientDirective } from "astro";
2
- //#region src/client/directives/visible.d.ts
3
- declare const visibleDirective: ClientDirective;
4
- //#endregion
5
- export { visibleDirective as default };
6
- //# sourceMappingURL=visible.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"visible.d.ts","names":[],"sources":["../../../src/client/directives/visible.ts"],"mappings":";;cASM,kBAAkB"}
@@ -1,23 +0,0 @@
1
- import { warmUpI18nForChunk } from "./utils.js";
2
- //#region src/client/directives/visible.ts
3
- const visibleDirective = (load, options, el) => {
4
- const cb = async () => {
5
- warmUpI18nForChunk(el);
6
- await (await load())();
7
- };
8
- const rawOptions = typeof options.value === "object" ? options.value : void 0;
9
- const ioOptions = rawOptions?.rootMargin ? { rootMargin: rawOptions.rootMargin } : {};
10
- const io = new IntersectionObserver((entries) => {
11
- for (const entry of entries) {
12
- if (!entry.isIntersecting) continue;
13
- io.disconnect();
14
- cb();
15
- break;
16
- }
17
- }, ioOptions);
18
- for (const child of el.children) io.observe(child);
19
- };
20
- //#endregion
21
- export { visibleDirective as default };
22
-
23
- //# sourceMappingURL=visible.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"visible.js","names":[],"sources":["../../../src/client/directives/visible.ts"],"sourcesContent":["/**\n * i18n-aware client:visible directive\n *\n * Based on Astro's visible directive (MIT License)\n * https://github.com/withastro/astro/blob/main/packages/astro/src/runtime/client/visible.ts\n */\nimport type { ClientDirective, ClientVisibleOptions } from 'astro';\nimport { warmUpI18nForChunk } from './utils.js';\n\nconst visibleDirective: ClientDirective = (load, options, el) => {\n const cb = async () => {\n warmUpI18nForChunk(el);\n const hydrate = await load();\n await hydrate();\n };\n\n const rawOptions = typeof options.value === 'object' ? (options.value as ClientVisibleOptions) : undefined;\n\n const ioOptions: IntersectionObserverInit = rawOptions?.rootMargin ? { rootMargin: rawOptions.rootMargin } : {};\n\n const io = new IntersectionObserver((entries) => {\n for (const entry of entries) {\n if (!entry.isIntersecting) continue;\n io.disconnect();\n cb();\n break;\n }\n }, ioOptions);\n\n for (const child of el.children) {\n io.observe(child);\n }\n};\n\nexport default visibleDirective;\n"],"mappings":";;AASA,MAAM,oBAAqC,MAAM,SAAS,OAAO;CAC/D,MAAM,KAAK,YAAY;EACrB,mBAAmB,EAAE;EAErB,OAAM,MADgB,KAAK,EAAA,CACb;CAChB;CAEA,MAAM,aAAa,OAAO,QAAQ,UAAU,WAAY,QAAQ,QAAiC,KAAA;CAEjG,MAAM,YAAsC,YAAY,aAAa,EAAE,YAAY,WAAW,WAAW,IAAI,CAAC;CAE9G,MAAM,KAAK,IAAI,sBAAsB,YAAY;EAC/C,KAAK,MAAM,SAAS,SAAS;GAC3B,IAAI,CAAC,MAAM,gBAAgB;GAC3B,GAAG,WAAW;GACd,GAAG;GACH;EACF;CACF,GAAG,SAAS;CAEZ,KAAK,MAAM,SAAS,GAAG,UACrB,GAAG,QAAQ,KAAK;AAEpB"}