@lingo.dev/compiler 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/LICENSE.md +201 -0
  2. package/README.md +192 -0
  3. package/build/_virtual/rolldown_runtime.cjs +29 -0
  4. package/build/_virtual/rolldown_runtime.mjs +7 -0
  5. package/build/index.cjs +0 -0
  6. package/build/index.d.cts +2 -0
  7. package/build/index.d.mts +2 -0
  8. package/build/index.mjs +1 -0
  9. package/build/metadata/manager.cjs +131 -0
  10. package/build/metadata/manager.mjs +123 -0
  11. package/build/metadata/manager.mjs.map +1 -0
  12. package/build/plugin/build-translator.cjs +198 -0
  13. package/build/plugin/build-translator.mjs +196 -0
  14. package/build/plugin/build-translator.mjs.map +1 -0
  15. package/build/plugin/cleanup.cjs +20 -0
  16. package/build/plugin/cleanup.mjs +20 -0
  17. package/build/plugin/cleanup.mjs.map +1 -0
  18. package/build/plugin/next-compiler-loader.cjs +41 -0
  19. package/build/plugin/next-compiler-loader.d.cts +12 -0
  20. package/build/plugin/next-compiler-loader.d.cts.map +1 -0
  21. package/build/plugin/next-compiler-loader.d.mts +13 -0
  22. package/build/plugin/next-compiler-loader.d.mts.map +1 -0
  23. package/build/plugin/next-compiler-loader.mjs +42 -0
  24. package/build/plugin/next-compiler-loader.mjs.map +1 -0
  25. package/build/plugin/next-config-loader.cjs +13 -0
  26. package/build/plugin/next-config-loader.d.cts +8 -0
  27. package/build/plugin/next-config-loader.d.cts.map +1 -0
  28. package/build/plugin/next-config-loader.d.mts +9 -0
  29. package/build/plugin/next-config-loader.d.mts.map +1 -0
  30. package/build/plugin/next-config-loader.mjs +14 -0
  31. package/build/plugin/next-config-loader.mjs.map +1 -0
  32. package/build/plugin/next-locale-client-loader.cjs +9 -0
  33. package/build/plugin/next-locale-client-loader.d.cts +8 -0
  34. package/build/plugin/next-locale-client-loader.d.cts.map +1 -0
  35. package/build/plugin/next-locale-client-loader.d.mts +9 -0
  36. package/build/plugin/next-locale-client-loader.d.mts.map +1 -0
  37. package/build/plugin/next-locale-client-loader.mjs +10 -0
  38. package/build/plugin/next-locale-client-loader.mjs.map +1 -0
  39. package/build/plugin/next-locale-server-loader.cjs +9 -0
  40. package/build/plugin/next-locale-server-loader.d.cts +8 -0
  41. package/build/plugin/next-locale-server-loader.d.cts.map +1 -0
  42. package/build/plugin/next-locale-server-loader.d.mts +9 -0
  43. package/build/plugin/next-locale-server-loader.d.mts.map +1 -0
  44. package/build/plugin/next-locale-server-loader.mjs +10 -0
  45. package/build/plugin/next-locale-server-loader.mjs.map +1 -0
  46. package/build/plugin/next.cjs +220 -0
  47. package/build/plugin/next.d.cts +9 -0
  48. package/build/plugin/next.d.cts.map +1 -0
  49. package/build/plugin/next.d.mts +9 -0
  50. package/build/plugin/next.d.mts.map +1 -0
  51. package/build/plugin/next.mjs +222 -0
  52. package/build/plugin/next.mjs.map +1 -0
  53. package/build/plugin/transform/babel-compat.cjs +13 -0
  54. package/build/plugin/transform/babel-compat.mjs +10 -0
  55. package/build/plugin/transform/babel-compat.mjs.map +1 -0
  56. package/build/plugin/transform/index.cjs +44 -0
  57. package/build/plugin/transform/index.mjs +42 -0
  58. package/build/plugin/transform/index.mjs.map +1 -0
  59. package/build/plugin/transform/metadata.cjs +142 -0
  60. package/build/plugin/transform/metadata.mjs +141 -0
  61. package/build/plugin/transform/metadata.mjs.map +1 -0
  62. package/build/plugin/transform/parse-override.cjs +145 -0
  63. package/build/plugin/transform/parse-override.mjs +144 -0
  64. package/build/plugin/transform/parse-override.mjs.map +1 -0
  65. package/build/plugin/transform/process-file.cjs +391 -0
  66. package/build/plugin/transform/process-file.mjs +390 -0
  67. package/build/plugin/transform/process-file.mjs.map +1 -0
  68. package/build/plugin/transform/use-i18n.cjs +8 -0
  69. package/build/plugin/transform/use-i18n.mjs +7 -0
  70. package/build/plugin/transform/use-i18n.mjs.map +1 -0
  71. package/build/plugin/transform/utils.cjs +205 -0
  72. package/build/plugin/transform/utils.mjs +192 -0
  73. package/build/plugin/transform/utils.mjs.map +1 -0
  74. package/build/plugin/unplugin.cjs +188 -0
  75. package/build/plugin/unplugin.d.cts +8 -0
  76. package/build/plugin/unplugin.d.cts.map +1 -0
  77. package/build/plugin/unplugin.d.mts +8 -0
  78. package/build/plugin/unplugin.d.mts.map +1 -0
  79. package/build/plugin/unplugin.mjs +186 -0
  80. package/build/plugin/unplugin.mjs.map +1 -0
  81. package/build/plugin/vite.cjs +28 -0
  82. package/build/plugin/vite.d.cts +9 -0
  83. package/build/plugin/vite.d.cts.map +1 -0
  84. package/build/plugin/vite.d.mts +9 -0
  85. package/build/plugin/vite.d.mts.map +1 -0
  86. package/build/plugin/vite.mjs +29 -0
  87. package/build/plugin/vite.mjs.map +1 -0
  88. package/build/plugin/webpack.cjs +27 -0
  89. package/build/plugin/webpack.d.cts +8 -0
  90. package/build/plugin/webpack.d.cts.map +1 -0
  91. package/build/plugin/webpack.d.mts +8 -0
  92. package/build/plugin/webpack.d.mts.map +1 -0
  93. package/build/plugin/webpack.mjs +28 -0
  94. package/build/plugin/webpack.mjs.map +1 -0
  95. package/build/react/client/index.cjs +9 -0
  96. package/build/react/client/index.d.cts +5 -0
  97. package/build/react/client/index.d.mts +5 -0
  98. package/build/react/client/index.mjs +6 -0
  99. package/build/react/client/useTranslation.cjs +71 -0
  100. package/build/react/client/useTranslation.d.cts +42 -0
  101. package/build/react/client/useTranslation.d.cts.map +1 -0
  102. package/build/react/client/useTranslation.d.mts +42 -0
  103. package/build/react/client/useTranslation.d.mts.map +1 -0
  104. package/build/react/client/useTranslation.mjs +71 -0
  105. package/build/react/client/useTranslation.mjs.map +1 -0
  106. package/build/react/next/client.cjs +25 -0
  107. package/build/react/next/client.d.cts +9 -0
  108. package/build/react/next/client.d.cts.map +1 -0
  109. package/build/react/next/client.d.mts +9 -0
  110. package/build/react/next/client.d.mts.map +1 -0
  111. package/build/react/next/client.mjs +24 -0
  112. package/build/react/next/client.mjs.map +1 -0
  113. package/build/react/next/cookie-locale-resolver.cjs +29 -0
  114. package/build/react/next/cookie-locale-resolver.d.cts +33 -0
  115. package/build/react/next/cookie-locale-resolver.d.cts.map +1 -0
  116. package/build/react/next/cookie-locale-resolver.d.mts +33 -0
  117. package/build/react/next/cookie-locale-resolver.d.mts.map +1 -0
  118. package/build/react/next/cookie-locale-resolver.mjs +29 -0
  119. package/build/react/next/cookie-locale-resolver.mjs.map +1 -0
  120. package/build/react/next/server.cjs +21 -0
  121. package/build/react/next/server.d.cts +13 -0
  122. package/build/react/next/server.d.cts.map +1 -0
  123. package/build/react/next/server.d.mts +14 -0
  124. package/build/react/next/server.d.mts.map +1 -0
  125. package/build/react/next/server.mjs +20 -0
  126. package/build/react/next/server.mjs.map +1 -0
  127. package/build/react/server/ServerLingoProvider.cjs +19 -0
  128. package/build/react/server/ServerLingoProvider.d.cts +12 -0
  129. package/build/react/server/ServerLingoProvider.d.cts.map +1 -0
  130. package/build/react/server/ServerLingoProvider.d.mts +12 -0
  131. package/build/react/server/ServerLingoProvider.d.mts.map +1 -0
  132. package/build/react/server/ServerLingoProvider.mjs +19 -0
  133. package/build/react/server/ServerLingoProvider.mjs.map +1 -0
  134. package/build/react/server/index.cjs +7 -0
  135. package/build/react/server/index.d.cts +4 -0
  136. package/build/react/server/index.d.mts +4 -0
  137. package/build/react/server/index.mjs +5 -0
  138. package/build/react/server/useTranslation.cjs +60 -0
  139. package/build/react/server/useTranslation.d.cts +36 -0
  140. package/build/react/server/useTranslation.d.cts.map +1 -0
  141. package/build/react/server/useTranslation.d.mts +36 -0
  142. package/build/react/server/useTranslation.d.mts.map +1 -0
  143. package/build/react/server/useTranslation.mjs +60 -0
  144. package/build/react/server/useTranslation.mjs.map +1 -0
  145. package/build/react/server-only/index.cjs +42 -0
  146. package/build/react/server-only/index.d.cts +38 -0
  147. package/build/react/server-only/index.d.cts.map +1 -0
  148. package/build/react/server-only/index.d.mts +38 -0
  149. package/build/react/server-only/index.d.mts.map +1 -0
  150. package/build/react/server-only/index.mjs +42 -0
  151. package/build/react/server-only/index.mjs.map +1 -0
  152. package/build/react/server-only/translations.cjs +85 -0
  153. package/build/react/server-only/translations.mjs +85 -0
  154. package/build/react/server-only/translations.mjs.map +1 -0
  155. package/build/react/shared/LingoContext.cjs +14 -0
  156. package/build/react/shared/LingoContext.d.cts +41 -0
  157. package/build/react/shared/LingoContext.d.cts.map +1 -0
  158. package/build/react/shared/LingoContext.d.mts +41 -0
  159. package/build/react/shared/LingoContext.d.mts.map +1 -0
  160. package/build/react/shared/LingoContext.mjs +13 -0
  161. package/build/react/shared/LingoContext.mjs.map +1 -0
  162. package/build/react/shared/LingoProvider.cjs +274 -0
  163. package/build/react/shared/LingoProvider.d.cts +76 -0
  164. package/build/react/shared/LingoProvider.d.cts.map +1 -0
  165. package/build/react/shared/LingoProvider.d.mts +76 -0
  166. package/build/react/shared/LingoProvider.d.mts.map +1 -0
  167. package/build/react/shared/LingoProvider.mjs +274 -0
  168. package/build/react/shared/LingoProvider.mjs.map +1 -0
  169. package/build/react/shared/LocaleSwitcher.cjs +61 -0
  170. package/build/react/shared/LocaleSwitcher.d.cts +71 -0
  171. package/build/react/shared/LocaleSwitcher.d.cts.map +1 -0
  172. package/build/react/shared/LocaleSwitcher.d.mts +71 -0
  173. package/build/react/shared/LocaleSwitcher.d.mts.map +1 -0
  174. package/build/react/shared/LocaleSwitcher.mjs +61 -0
  175. package/build/react/shared/LocaleSwitcher.mjs.map +1 -0
  176. package/build/react/shared/render-rich-text.cjs +55 -0
  177. package/build/react/shared/render-rich-text.d.cts +17 -0
  178. package/build/react/shared/render-rich-text.d.cts.map +1 -0
  179. package/build/react/shared/render-rich-text.d.mts +17 -0
  180. package/build/react/shared/render-rich-text.d.mts.map +1 -0
  181. package/build/react/shared/render-rich-text.mjs +54 -0
  182. package/build/react/shared/render-rich-text.mjs.map +1 -0
  183. package/build/react/shared/utils.cjs +34 -0
  184. package/build/react/shared/utils.mjs +35 -0
  185. package/build/react/shared/utils.mjs.map +1 -0
  186. package/build/react/types.d.cts +16 -0
  187. package/build/react/types.d.cts.map +1 -0
  188. package/build/react/types.d.mts +16 -0
  189. package/build/react/types.d.mts.map +1 -0
  190. package/build/translation-server/logger.cjs +37 -0
  191. package/build/translation-server/logger.mjs +37 -0
  192. package/build/translation-server/logger.mjs.map +1 -0
  193. package/build/translation-server/translation-server.cjs +547 -0
  194. package/build/translation-server/translation-server.mjs +544 -0
  195. package/build/translation-server/translation-server.mjs.map +1 -0
  196. package/build/translation-server/ws-events.cjs +15 -0
  197. package/build/translation-server/ws-events.mjs +15 -0
  198. package/build/translation-server/ws-events.mjs.map +1 -0
  199. package/build/translators/api.cjs +12 -0
  200. package/build/translators/api.mjs +12 -0
  201. package/build/translators/api.mjs.map +1 -0
  202. package/build/translators/cache-factory.cjs +26 -0
  203. package/build/translators/cache-factory.mjs +27 -0
  204. package/build/translators/cache-factory.mjs.map +1 -0
  205. package/build/translators/lingo/model-factory.cjs +179 -0
  206. package/build/translators/lingo/model-factory.mjs +174 -0
  207. package/build/translators/lingo/model-factory.mjs.map +1 -0
  208. package/build/translators/lingo/prompt.cjs +43 -0
  209. package/build/translators/lingo/prompt.mjs +43 -0
  210. package/build/translators/lingo/prompt.mjs.map +1 -0
  211. package/build/translators/lingo/service.cjs +152 -0
  212. package/build/translators/lingo/service.mjs +152 -0
  213. package/build/translators/lingo/service.mjs.map +1 -0
  214. package/build/translators/lingo/shots.cjs +28 -0
  215. package/build/translators/lingo/shots.mjs +28 -0
  216. package/build/translators/lingo/shots.mjs.map +1 -0
  217. package/build/translators/local-cache.cjs +115 -0
  218. package/build/translators/local-cache.mjs +113 -0
  219. package/build/translators/local-cache.mjs.map +1 -0
  220. package/build/translators/parse-xml.cjs +109 -0
  221. package/build/translators/parse-xml.mjs +108 -0
  222. package/build/translators/parse-xml.mjs.map +1 -0
  223. package/build/translators/pluralization/icu-validator.cjs +36 -0
  224. package/build/translators/pluralization/icu-validator.mjs +36 -0
  225. package/build/translators/pluralization/icu-validator.mjs.map +1 -0
  226. package/build/translators/pluralization/pattern-detector.cjs +25 -0
  227. package/build/translators/pluralization/pattern-detector.mjs +25 -0
  228. package/build/translators/pluralization/pattern-detector.mjs.map +1 -0
  229. package/build/translators/pluralization/prompt.cjs +98 -0
  230. package/build/translators/pluralization/prompt.mjs +98 -0
  231. package/build/translators/pluralization/prompt.mjs.map +1 -0
  232. package/build/translators/pluralization/service.cjs +247 -0
  233. package/build/translators/pluralization/service.mjs +247 -0
  234. package/build/translators/pluralization/service.mjs.map +1 -0
  235. package/build/translators/pluralization/shots.cjs +53 -0
  236. package/build/translators/pluralization/shots.mjs +53 -0
  237. package/build/translators/pluralization/shots.mjs.map +1 -0
  238. package/build/translators/pluralization/types.d.cts +17 -0
  239. package/build/translators/pluralization/types.d.cts.map +1 -0
  240. package/build/translators/pluralization/types.d.mts +17 -0
  241. package/build/translators/pluralization/types.d.mts.map +1 -0
  242. package/build/translators/pseudotranslator/index.cjs +129 -0
  243. package/build/translators/pseudotranslator/index.mjs +129 -0
  244. package/build/translators/pseudotranslator/index.mjs.map +1 -0
  245. package/build/translators/translation-service.cjs +182 -0
  246. package/build/translators/translation-service.mjs +183 -0
  247. package/build/translators/translation-service.mjs.map +1 -0
  248. package/build/translators/translator-factory.cjs +49 -0
  249. package/build/translators/translator-factory.mjs +50 -0
  250. package/build/translators/translator-factory.mjs.map +1 -0
  251. package/build/types.d.cts +161 -0
  252. package/build/types.d.cts.map +1 -0
  253. package/build/types.d.mts +161 -0
  254. package/build/types.d.mts.map +1 -0
  255. package/build/utils/config-factory.cjs +58 -0
  256. package/build/utils/config-factory.mjs +58 -0
  257. package/build/utils/config-factory.mjs.map +1 -0
  258. package/build/utils/hash.cjs +17 -0
  259. package/build/utils/hash.mjs +16 -0
  260. package/build/utils/hash.mjs.map +1 -0
  261. package/build/utils/is-valid-locale.cjs +14 -0
  262. package/build/utils/is-valid-locale.mjs +14 -0
  263. package/build/utils/is-valid-locale.mjs.map +1 -0
  264. package/build/utils/logger.cjs +51 -0
  265. package/build/utils/logger.mjs +50 -0
  266. package/build/utils/logger.mjs.map +1 -0
  267. package/build/utils/path-helpers.cjs +49 -0
  268. package/build/utils/path-helpers.mjs +47 -0
  269. package/build/utils/path-helpers.mjs.map +1 -0
  270. package/build/utils/timeout.cjs +42 -0
  271. package/build/utils/timeout.mjs +41 -0
  272. package/build/utils/timeout.mjs.map +1 -0
  273. package/build/virtual/code-generator.cjs +54 -0
  274. package/build/virtual/code-generator.mjs +53 -0
  275. package/build/virtual/code-generator.mjs.map +1 -0
  276. package/build/virtual/config.cjs +10 -0
  277. package/build/virtual/config.d.cts +9 -0
  278. package/build/virtual/config.d.cts.map +1 -0
  279. package/build/virtual/config.d.mts +9 -0
  280. package/build/virtual/config.d.mts.map +1 -0
  281. package/build/virtual/config.mjs +8 -0
  282. package/build/virtual/config.mjs.map +1 -0
  283. package/build/virtual/locale/client.cjs +23 -0
  284. package/build/virtual/locale/client.d.cts +19 -0
  285. package/build/virtual/locale/client.d.cts.map +1 -0
  286. package/build/virtual/locale/client.d.mts +19 -0
  287. package/build/virtual/locale/client.d.mts.map +1 -0
  288. package/build/virtual/locale/client.mjs +22 -0
  289. package/build/virtual/locale/client.mjs.map +1 -0
  290. package/build/virtual/locale/server.cjs +13 -0
  291. package/build/virtual/locale/server.d.cts +13 -0
  292. package/build/virtual/locale/server.d.cts.map +1 -0
  293. package/build/virtual/locale/server.d.mts +13 -0
  294. package/build/virtual/locale/server.d.mts.map +1 -0
  295. package/build/virtual/locale/server.mjs +13 -0
  296. package/build/virtual/locale/server.mjs.map +1 -0
  297. package/build/widget/lingo-dev-widget.cjs +228 -0
  298. package/build/widget/lingo-dev-widget.mjs +229 -0
  299. package/build/widget/lingo-dev-widget.mjs.map +1 -0
  300. package/package.json +189 -0
@@ -0,0 +1,391 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ const require_logger = require('../../utils/logger.cjs');
3
+ const require_utils = require('./utils.cjs');
4
+ const require_metadata = require('./metadata.cjs');
5
+ const require_babel_compat = require('./babel-compat.cjs');
6
+ const require_parse_override = require('./parse-override.cjs');
7
+ let _babel_types = require("@babel/types");
8
+ _babel_types = require_rolldown_runtime.__toESM(_babel_types);
9
+
10
+ //#region src/plugin/transform/process-file.ts
11
+ /**
12
+ * Keep mutations to the current node and children. Do not mutate program inserting imports when processing the component.
13
+ * This should be done in the end.
14
+ * The overall idea is that state is used for side effect tracking. When we exit relevant points, we check if we need to make extra changes at this level.
15
+ * e.g. when we transform elements to insert translations, we record their hashes and add the translation hook call when leaving the component.
16
+ */
17
+ function updateWithMetadataState(state, newState) {
18
+ state.newEntries = [...state.newEntries, ...newState.newEntries];
19
+ state.needsAsyncImport = state.needsAsyncImport || newState.needsAsyncImport;
20
+ return state;
21
+ }
22
+ const SKIP_ATTRIBUTE = "data-lingo-skip";
23
+ /**
24
+ * Elements whose content should not be translated by default.
25
+ * These are typically code-related or technical elements where translation
26
+ * would break functionality or meaning.
27
+ */
28
+ const NON_TRANSLATABLE_ELEMENTS = new Set([
29
+ "code",
30
+ "pre",
31
+ "script",
32
+ "style",
33
+ "kbd",
34
+ "samp",
35
+ "var"
36
+ ]);
37
+ const TRANSLATABLE_ATTRIBUTES = new Set([
38
+ "title",
39
+ "aria-label",
40
+ "aria-description",
41
+ "alt",
42
+ "label",
43
+ "description",
44
+ "placeholder",
45
+ "content",
46
+ "subtitle"
47
+ ]);
48
+ /**
49
+ * Check if a JSX element should skip translation based on:
50
+ * 1. Element type (code, pre, script, style, etc.)
51
+ * 2. translate="no" attribute (HTML standard)
52
+ * 3. data-lingo-skip attribute
53
+ */
54
+ function shouldSkipTranslationForElement(element) {
55
+ if (element.type === "JSXFragment") return false;
56
+ const openingElement = element.openingElement;
57
+ if (openingElement.name.type === "JSXIdentifier") {
58
+ if (NON_TRANSLATABLE_ELEMENTS.has(openingElement.name.name)) return true;
59
+ }
60
+ for (const attr of openingElement.attributes) if (attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier") {
61
+ if (attr.name.name === "translate") {
62
+ if (attr.value?.type === "StringLiteral" && attr.value.value === "no") return true;
63
+ }
64
+ if (attr.name.name === SKIP_ATTRIBUTE) return true;
65
+ }
66
+ return false;
67
+ }
68
+ function translateAttributes(node, state) {
69
+ const openingElement = node.openingElement;
70
+ const component = state.componentsStack.at(-1);
71
+ if (!component) return;
72
+ for (const attr of openingElement.attributes) if (attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && TRANSLATABLE_ATTRIBUTES.has(attr.name.name) && attr.value?.type === "StringLiteral") {
73
+ const text = require_utils.normalizeWhitespace(attr.value.value);
74
+ if (text.length == 0) continue;
75
+ const entry = require_utils.createTranslationEntry("attribute", text, {
76
+ attributeName: attr.name.name,
77
+ componentName: component.name
78
+ }, state.filePath, node.loc?.start.line, node.loc?.start.column);
79
+ registerEntry(entry, state, component.name);
80
+ attr.value = require_utils.constructTranslationCall(entry.hash, text);
81
+ }
82
+ }
83
+ /**
84
+ * Check if a JSX element has mixed content that needs rich text translation
85
+ * Mixed content = text nodes + expressions + nested JSX elements (excluding void elements)
86
+ */
87
+ function hasMixedContent(element) {
88
+ const children = element.children;
89
+ if (children.length === 0) return false;
90
+ let state = 0;
91
+ for (const child of children) if (child.type === "JSXText") {
92
+ if (child.value.trim().length > 0) switch (state) {
93
+ case 0:
94
+ state = 1;
95
+ break;
96
+ case 1: break;
97
+ case 2: return true;
98
+ case 3: return true;
99
+ }
100
+ } else if (child.type === "JSXExpressionContainer") switch (state) {
101
+ case 0:
102
+ state = 2;
103
+ break;
104
+ case 1: return true;
105
+ case 2: break;
106
+ case 3: return true;
107
+ }
108
+ else if (child.type === "JSXElement") if (!require_utils.isVoidElement(child)) switch (state) {
109
+ case 0:
110
+ state = 2;
111
+ break;
112
+ case 1: return true;
113
+ case 2: break;
114
+ case 3: return true;
115
+ }
116
+ else switch (state) {
117
+ case 0: break;
118
+ case 1:
119
+ state = 3;
120
+ break;
121
+ case 2: break;
122
+ case 3: break;
123
+ }
124
+ return false;
125
+ }
126
+ /**
127
+ * Serialize JSX children to a translation string with placeholders
128
+ */
129
+ function serializeJSXChildren(children, state) {
130
+ let text = "";
131
+ const variables = [];
132
+ const expressions = /* @__PURE__ */ new Map();
133
+ const components = /* @__PURE__ */ new Map();
134
+ const elementCounts = /* @__PURE__ */ new Map();
135
+ for (const child of children) if (child.type === "JSXText") {
136
+ let normalized = require_utils.normalizeWhitespace(child.value);
137
+ if (text.length > 0 && child.value.match(/^\s/) && normalized.length > 0) {
138
+ if (!text.endsWith(" ")) normalized = ` ${normalized}`;
139
+ }
140
+ if (normalized.length > 0 && child.value.match(/\s$/)) {
141
+ if (!text.endsWith(" ")) normalized = `${normalized} `;
142
+ }
143
+ text += require_utils.escapeTextForICU(normalized);
144
+ } else if (child.type === "JSXExpressionContainer") {
145
+ const expr = child.expression;
146
+ if (expr.type === "Identifier") {
147
+ text += `{${expr.name}}`;
148
+ if (!variables.includes(expr.name)) variables.push(expr.name);
149
+ } else if (expr.type === "StringLiteral") text += require_utils.escapeTextForICU(expr.value);
150
+ else if (expr.type !== "JSXEmptyExpression") {
151
+ const name = `expression${expressions.size}`;
152
+ text += `{${name}}`;
153
+ expressions.set(name, expr);
154
+ }
155
+ } else if (child.type === "JSXElement") {
156
+ let shouldTranslate = true;
157
+ if (require_utils.isVoidElement(child)) shouldTranslate = false;
158
+ if (shouldSkipTranslationForElement(child)) shouldTranslate = false;
159
+ const openingElement = child.openingElement;
160
+ let elementName = "";
161
+ if (openingElement.name.type === "JSXIdentifier") elementName = openingElement.name.name;
162
+ else elementName = "element";
163
+ const count = elementCounts.get(elementName) || 0;
164
+ elementCounts.set(elementName, count + 1);
165
+ const tagName = `${elementName}${count}`;
166
+ translateAttributes(child, state);
167
+ if (shouldTranslate) {
168
+ const nested = serializeJSXChildren(child.children, state);
169
+ text += `<${tagName}>${nested.text}</${tagName}>`;
170
+ for (const v of nested.variables) if (!variables.includes(v)) variables.push(v);
171
+ for (const [nestedTag, nestedElement] of nested.components) components.set(`${tagName}_${nestedTag}`, nestedElement);
172
+ } else {
173
+ text += `<${tagName}></${tagName}>`;
174
+ child.extra = {
175
+ ...child.extra,
176
+ shouldTranslate: false
177
+ };
178
+ }
179
+ components.set(tagName, child);
180
+ }
181
+ return {
182
+ text,
183
+ variables,
184
+ expressions,
185
+ components
186
+ };
187
+ }
188
+ function transformVoidElement(node, state) {
189
+ translateAttributes(node, state);
190
+ }
191
+ function getTranslationScope(node, state) {
192
+ if (hasMixedContent(node)) {
193
+ const serialized = serializeJSXChildren(node.children, state);
194
+ const text$1 = serialized.text.trim();
195
+ if (text$1.length === 0) return null;
196
+ return {
197
+ kind: "mixed",
198
+ text: text$1,
199
+ args: {
200
+ variables: serialized.variables,
201
+ expressions: serialized.expressions,
202
+ components: serialized.components
203
+ }
204
+ };
205
+ }
206
+ const textNodeIndex = node.children.findIndex((child) => child.type === "JSXText" && child.value.trim().length > 0);
207
+ if (textNodeIndex === -1) return null;
208
+ if (!node.children.every((child) => child.type === "JSXText" || child.type === "JSXElement" && require_utils.isVoidElement(child))) return null;
209
+ const textNode = node.children[textNodeIndex];
210
+ const text = require_utils.normalizeWhitespace(textNode.value);
211
+ if (text.length === 0) return null;
212
+ return {
213
+ kind: "text",
214
+ text,
215
+ textNodeIndex
216
+ };
217
+ }
218
+ function registerEntry(entry, state, componentName) {
219
+ state.newEntries.push(entry);
220
+ const hashes = state.componentHashes.get(componentName) ?? [];
221
+ hashes.push(entry.hash);
222
+ state.componentHashes.set(componentName, hashes);
223
+ }
224
+ function rewriteChildren(path, state, translationScope, entryHash) {
225
+ if (translationScope.kind === "mixed") {
226
+ path.node.children = [require_utils.constructTranslationCall(entryHash, translationScope.text, translationScope.args)];
227
+ return;
228
+ }
229
+ const { textNodeIndex, text } = translationScope;
230
+ path.node.children = path.node.children.map((child, index) => {
231
+ if (index === textNodeIndex) return require_utils.constructTranslationCall(entryHash, text);
232
+ if (child.type === "JSXElement") transformVoidElement(child, state);
233
+ return child;
234
+ });
235
+ }
236
+ function processJSXElement(path, state) {
237
+ const component = state.componentsStack.at(-1);
238
+ if (!component) return;
239
+ const scope = getTranslationScope(path.node, state);
240
+ if (!scope) return;
241
+ const overrides = require_parse_override.processOverrideAttributes(path);
242
+ const entry = require_utils.createTranslationEntry("content", scope.text, { componentName: component.name }, state.filePath, path.node.loc?.start.line, path.node.loc?.start.column, overrides);
243
+ registerEntry(entry, state, component.name);
244
+ rewriteChildren(path, state, scope, entry.hash);
245
+ path.skip();
246
+ }
247
+ /**
248
+ * Inject dynamic locale attribute into <html> elements
249
+ * Transforms: <html> → <html lang={locale}>
250
+ *
251
+ * Only injects if:
252
+ * 1. Element is <html>
253
+ * 2. No existing lang/language attribute
254
+ * 3. We're inside a React component (has locale context)
255
+ */
256
+ function injectHtmlLangAttribute(node, state) {
257
+ const openingElement = node.openingElement;
258
+ if (openingElement.name.type !== "JSXIdentifier" || openingElement.name.name !== "html") return;
259
+ if (openingElement.attributes.some((attr) => {
260
+ return attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && (attr.name.name === "lang" || attr.name.name === "language");
261
+ })) return;
262
+ const component = state.componentsStack.at(-1);
263
+ if (!component) return;
264
+ const langAttr = _babel_types.jsxAttribute(_babel_types.jsxIdentifier("lang"), _babel_types.jsxExpressionContainer(_babel_types.identifier("locale")));
265
+ openingElement.attributes.push(langAttr);
266
+ require_logger.logger.debug(`Injected locale attribute into <html> element in component: ${component.name}`);
267
+ state.componentsNeedingLocale.add(component.name);
268
+ }
269
+ /**
270
+ * Inject translation hook into a component when it's done processing
271
+ * Called when popping component from stack
272
+ */
273
+ function injectTranslationHook(path, component, state) {
274
+ const needsLocale = state.componentsNeedingLocale.has(component.name);
275
+ const hashes = state.componentHashes.get(component.name);
276
+ if ((!hashes || hashes.length === 0) && !needsLocale) return;
277
+ if (component.isAsync) {
278
+ require_utils.injectServerHook(path, hashes ?? [], needsLocale);
279
+ state.needsAsyncImport = true;
280
+ } else {
281
+ require_utils.injectUnifiedHook(path, hashes ?? [], needsLocale);
282
+ state.needsUnifiedImport = true;
283
+ }
284
+ }
285
+ /**
286
+ * Add translation imports at the top of the file
287
+ * Called on Program exit after all components have been processed
288
+ */
289
+ function addTranslationImports(programPath, state) {
290
+ if (state.needsAsyncImport) programPath.node.body.unshift(require_utils.constructServerImport());
291
+ if (state.needsUnifiedImport) programPath.node.body.unshift(require_utils.comstructUnifiedImport());
292
+ }
293
+ /**
294
+ * Handle component function detection and state update
295
+ */
296
+ function processComponentFunction(path, state) {
297
+ if (!require_utils.isReactComponent(path)) {
298
+ path.skip();
299
+ require_logger.logger.debug(`Skipping non-React component: ${path.node.type}`);
300
+ return;
301
+ }
302
+ const componentName = require_utils.inferComponentName(path);
303
+ if (!componentName) {
304
+ path.skip();
305
+ return;
306
+ }
307
+ if (!state.componentHashes.has(componentName)) state.componentHashes.set(componentName, []);
308
+ const componentEntry = {
309
+ name: componentName,
310
+ isAsync: path.node.async
311
+ };
312
+ state.componentsStack.push(componentEntry);
313
+ require_logger.logger.debug(`Component ${JSON.stringify(componentEntry)} entered`);
314
+ path.setData("componentName", componentName);
315
+ path.traverse(componentVisitors, { visitorState: state });
316
+ const component = state.componentsStack.pop();
317
+ if (component) injectTranslationHook(path, component, state);
318
+ path.skip();
319
+ }
320
+ const componentVisitors = {
321
+ FunctionDeclaration(path) {
322
+ processComponentFunction(path, this.visitorState);
323
+ },
324
+ ArrowFunctionExpression(path) {
325
+ processComponentFunction(path, this.visitorState);
326
+ },
327
+ FunctionExpression(path) {
328
+ processComponentFunction(path, this.visitorState);
329
+ },
330
+ JSXFragment(path) {
331
+ processJSXElement(path, this.visitorState);
332
+ },
333
+ JSXElement(path) {
334
+ translateAttributes(path.node, this.visitorState);
335
+ injectHtmlLangAttribute(path.node, this.visitorState);
336
+ if (shouldSkipTranslationForElement(path.node)) {
337
+ path.skip();
338
+ return;
339
+ }
340
+ processJSXElement(path, this.visitorState);
341
+ }
342
+ };
343
+ const fileVisitors = {
344
+ ExportNamedDeclaration(path) {
345
+ const metadataState = require_metadata.processNextStaticMetadata(path, { filePath: this.visitorState.filePath });
346
+ if (metadataState) updateWithMetadataState(this.visitorState, metadataState);
347
+ },
348
+ FunctionDeclaration(path) {
349
+ const metadataState = require_metadata.processNextDynamicMetadata(path, { filePath: this.visitorState.filePath });
350
+ if (metadataState) updateWithMetadataState(this.visitorState, metadataState);
351
+ processComponentFunction(path, this.visitorState);
352
+ },
353
+ ArrowFunctionExpression(path) {
354
+ processComponentFunction(path, this.visitorState);
355
+ },
356
+ FunctionExpression(path) {
357
+ processComponentFunction(path, this.visitorState);
358
+ }
359
+ };
360
+ /**
361
+ * Create Babel visitors for auto-translation (single-pass transformation)
362
+ */
363
+ const programVisitor = { Program: {
364
+ enter(path) {
365
+ if (this.visitorState.needsDirective && !require_utils.hasUseI18nDirective(path)) {
366
+ path.skip();
367
+ return;
368
+ }
369
+ path.traverse(fileVisitors, { visitorState: this.visitorState });
370
+ },
371
+ exit(path) {
372
+ if (this.visitorState.needsUnifiedImport || this.visitorState.needsAsyncImport) addTranslationImports(path, this.visitorState);
373
+ }
374
+ } };
375
+ function processFile(ast, options) {
376
+ const state = {
377
+ needsDirective: options.needsDirective,
378
+ filePath: options.relativeFilePath,
379
+ newEntries: [],
380
+ componentsStack: [],
381
+ componentHashes: /* @__PURE__ */ new Map(),
382
+ needsUnifiedImport: false,
383
+ needsAsyncImport: false,
384
+ componentsNeedingLocale: /* @__PURE__ */ new Set()
385
+ };
386
+ require_babel_compat.traverse(ast, programVisitor, void 0, { visitorState: state });
387
+ return state.newEntries;
388
+ }
389
+
390
+ //#endregion
391
+ exports.processFile = processFile;