@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,109 @@
1
+ const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
+ let fast_xml_parser = require("fast-xml-parser");
3
+
4
+ //#region src/translators/parse-xml.ts
5
+ const TAG_OBJECT = "object";
6
+ const TAG_ARRAY = "array";
7
+ const TAG_VALUE = "value";
8
+ /**
9
+ * Converts a JavaScript value to a generic XML node structure
10
+ */
11
+ function toGenericNode(value, key) {
12
+ if (Array.isArray(value)) {
13
+ const children = value.map((item) => toGenericNode(item));
14
+ return { [TAG_ARRAY]: {
15
+ ...key ? { key } : {},
16
+ ...groupChildren(children)
17
+ } };
18
+ }
19
+ if (value && typeof value === "object" && value.constructor === Object) {
20
+ const children = Object.entries(value).map(([k, v]) => toGenericNode(v, k));
21
+ return { [TAG_OBJECT]: {
22
+ ...key ? { key } : {},
23
+ ...groupChildren(children)
24
+ } };
25
+ }
26
+ return { [TAG_VALUE]: {
27
+ ...key ? { key } : {},
28
+ "#text": value ?? ""
29
+ } };
30
+ }
31
+ /**
32
+ * Groups nodes by tag name for proper XML array handling
33
+ */
34
+ function groupChildren(nodes) {
35
+ const grouped = {};
36
+ for (const node of nodes) {
37
+ const tag = Object.keys(node)[0];
38
+ if (!grouped[tag]) grouped[tag] = [];
39
+ grouped[tag].push(node[tag]);
40
+ }
41
+ return grouped;
42
+ }
43
+ /**
44
+ * Recursively converts a generic XML node back to a JavaScript value
45
+ */
46
+ function fromGenericNode(tag, data) {
47
+ if (tag === TAG_VALUE) {
48
+ if (data && typeof data === "object" && "#text" in data) return data["#text"] ?? "";
49
+ if (data && typeof data === "object") return "";
50
+ return data ?? "";
51
+ }
52
+ if (tag === TAG_ARRAY) {
53
+ const result = [];
54
+ for (const childTag of [
55
+ TAG_VALUE,
56
+ TAG_OBJECT,
57
+ TAG_ARRAY
58
+ ]) {
59
+ const childNodes = Array.isArray(data[childTag]) ? data[childTag] : data[childTag] ? [data[childTag]] : [];
60
+ for (const child of childNodes) result.push(fromGenericNode(childTag, child));
61
+ }
62
+ return result;
63
+ }
64
+ const obj = {};
65
+ for (const childTag of [
66
+ TAG_VALUE,
67
+ TAG_OBJECT,
68
+ TAG_ARRAY
69
+ ]) {
70
+ const childNodes = Array.isArray(data[childTag]) ? data[childTag] : data[childTag] ? [data[childTag]] : [];
71
+ for (const child of childNodes) {
72
+ const key = child.key || "";
73
+ obj[key] = fromGenericNode(childTag, child);
74
+ }
75
+ }
76
+ return obj;
77
+ }
78
+ function obj2xml(obj) {
79
+ const rootNode = toGenericNode(obj)[TAG_OBJECT];
80
+ return new fast_xml_parser.XMLBuilder({
81
+ ignoreAttributes: false,
82
+ attributeNamePrefix: "",
83
+ format: true,
84
+ suppressEmptyNode: true
85
+ }).build({ [TAG_OBJECT]: rootNode });
86
+ }
87
+ function parseXmlFromResponseText(text) {
88
+ const xmlStart = text.indexOf("<");
89
+ const xmlEnd = text.lastIndexOf(">") + 1;
90
+ if (xmlStart !== -1 && xmlEnd > xmlStart) text = text.substring(xmlStart, xmlEnd);
91
+ const { "?xml": _, ...withoutDeclaration } = new fast_xml_parser.XMLParser({
92
+ ignoreAttributes: false,
93
+ attributeNamePrefix: "",
94
+ parseTagValue: true,
95
+ parseAttributeValue: false,
96
+ processEntities: true,
97
+ isArray: (name) => [
98
+ TAG_VALUE,
99
+ TAG_ARRAY,
100
+ TAG_OBJECT
101
+ ].includes(name)
102
+ }).parse(text);
103
+ const rootTag = Object.keys(withoutDeclaration)[0];
104
+ return fromGenericNode(rootTag, Array.isArray(withoutDeclaration[rootTag]) ? withoutDeclaration[rootTag][0] : withoutDeclaration[rootTag]);
105
+ }
106
+
107
+ //#endregion
108
+ exports.obj2xml = obj2xml;
109
+ exports.parseXmlFromResponseText = parseXmlFromResponseText;
@@ -0,0 +1,108 @@
1
+ import { XMLBuilder, XMLParser } from "fast-xml-parser";
2
+
3
+ //#region src/translators/parse-xml.ts
4
+ const TAG_OBJECT = "object";
5
+ const TAG_ARRAY = "array";
6
+ const TAG_VALUE = "value";
7
+ /**
8
+ * Converts a JavaScript value to a generic XML node structure
9
+ */
10
+ function toGenericNode(value, key) {
11
+ if (Array.isArray(value)) {
12
+ const children = value.map((item) => toGenericNode(item));
13
+ return { [TAG_ARRAY]: {
14
+ ...key ? { key } : {},
15
+ ...groupChildren(children)
16
+ } };
17
+ }
18
+ if (value && typeof value === "object" && value.constructor === Object) {
19
+ const children = Object.entries(value).map(([k, v]) => toGenericNode(v, k));
20
+ return { [TAG_OBJECT]: {
21
+ ...key ? { key } : {},
22
+ ...groupChildren(children)
23
+ } };
24
+ }
25
+ return { [TAG_VALUE]: {
26
+ ...key ? { key } : {},
27
+ "#text": value ?? ""
28
+ } };
29
+ }
30
+ /**
31
+ * Groups nodes by tag name for proper XML array handling
32
+ */
33
+ function groupChildren(nodes) {
34
+ const grouped = {};
35
+ for (const node of nodes) {
36
+ const tag = Object.keys(node)[0];
37
+ if (!grouped[tag]) grouped[tag] = [];
38
+ grouped[tag].push(node[tag]);
39
+ }
40
+ return grouped;
41
+ }
42
+ /**
43
+ * Recursively converts a generic XML node back to a JavaScript value
44
+ */
45
+ function fromGenericNode(tag, data) {
46
+ if (tag === TAG_VALUE) {
47
+ if (data && typeof data === "object" && "#text" in data) return data["#text"] ?? "";
48
+ if (data && typeof data === "object") return "";
49
+ return data ?? "";
50
+ }
51
+ if (tag === TAG_ARRAY) {
52
+ const result = [];
53
+ for (const childTag of [
54
+ TAG_VALUE,
55
+ TAG_OBJECT,
56
+ TAG_ARRAY
57
+ ]) {
58
+ const childNodes = Array.isArray(data[childTag]) ? data[childTag] : data[childTag] ? [data[childTag]] : [];
59
+ for (const child of childNodes) result.push(fromGenericNode(childTag, child));
60
+ }
61
+ return result;
62
+ }
63
+ const obj = {};
64
+ for (const childTag of [
65
+ TAG_VALUE,
66
+ TAG_OBJECT,
67
+ TAG_ARRAY
68
+ ]) {
69
+ const childNodes = Array.isArray(data[childTag]) ? data[childTag] : data[childTag] ? [data[childTag]] : [];
70
+ for (const child of childNodes) {
71
+ const key = child.key || "";
72
+ obj[key] = fromGenericNode(childTag, child);
73
+ }
74
+ }
75
+ return obj;
76
+ }
77
+ function obj2xml(obj) {
78
+ const rootNode = toGenericNode(obj)[TAG_OBJECT];
79
+ return new XMLBuilder({
80
+ ignoreAttributes: false,
81
+ attributeNamePrefix: "",
82
+ format: true,
83
+ suppressEmptyNode: true
84
+ }).build({ [TAG_OBJECT]: rootNode });
85
+ }
86
+ function parseXmlFromResponseText(text) {
87
+ const xmlStart = text.indexOf("<");
88
+ const xmlEnd = text.lastIndexOf(">") + 1;
89
+ if (xmlStart !== -1 && xmlEnd > xmlStart) text = text.substring(xmlStart, xmlEnd);
90
+ const { "?xml": _, ...withoutDeclaration } = new XMLParser({
91
+ ignoreAttributes: false,
92
+ attributeNamePrefix: "",
93
+ parseTagValue: true,
94
+ parseAttributeValue: false,
95
+ processEntities: true,
96
+ isArray: (name) => [
97
+ TAG_VALUE,
98
+ TAG_ARRAY,
99
+ TAG_OBJECT
100
+ ].includes(name)
101
+ }).parse(text);
102
+ const rootTag = Object.keys(withoutDeclaration)[0];
103
+ return fromGenericNode(rootTag, Array.isArray(withoutDeclaration[rootTag]) ? withoutDeclaration[rootTag][0] : withoutDeclaration[rootTag]);
104
+ }
105
+
106
+ //#endregion
107
+ export { obj2xml, parseXmlFromResponseText };
108
+ //# sourceMappingURL=parse-xml.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-xml.mjs","names":["grouped: Record<string, any[]>","result: any[]","obj: Record<string, any>"],"sources":["../../src/translators/parse-xml.ts"],"sourcesContent":["import { XMLParser, XMLBuilder } from \"fast-xml-parser\";\n\n// Generic tag names used in XML output\nconst TAG_OBJECT = \"object\";\nconst TAG_ARRAY = \"array\";\nconst TAG_VALUE = \"value\";\n\n/**\n * Converts a JavaScript value to a generic XML node structure\n */\nfunction toGenericNode(value: any, key?: string): Record<string, any> {\n if (Array.isArray(value)) {\n const children = value.map((item) => toGenericNode(item));\n return {\n [TAG_ARRAY]: {\n ...(key ? { key } : {}),\n ...groupChildren(children),\n },\n };\n }\n\n if (value && typeof value === \"object\" && value.constructor === Object) {\n const children = Object.entries(value).map(([k, v]) => toGenericNode(v, k));\n return {\n [TAG_OBJECT]: {\n ...(key ? { key } : {}),\n ...groupChildren(children),\n },\n };\n }\n\n return {\n [TAG_VALUE]: {\n ...(key ? { key } : {}),\n \"#text\": value ?? \"\",\n },\n };\n}\n\n/**\n * Groups nodes by tag name for proper XML array handling\n */\nfunction groupChildren(nodes: Record<string, any>[]): Record<string, any> {\n const grouped: Record<string, any[]> = {};\n\n for (const node of nodes) {\n const tag = Object.keys(node)[0];\n if (!grouped[tag]) {\n grouped[tag] = [];\n }\n grouped[tag].push(node[tag]);\n }\n\n return grouped;\n}\n\n/**\n * Recursively converts a generic XML node back to a JavaScript value\n */\nfunction fromGenericNode(tag: string, data: any): any {\n if (tag === TAG_VALUE) {\n if (data && typeof data === \"object\" && \"#text\" in data) {\n return data[\"#text\"] ?? \"\";\n }\n // For self-closing tags like <value key=\"x\" />, data is { key: \"x\" }\n // We should return empty string, not the attributes object\n if (data && typeof data === \"object\") {\n return \"\";\n }\n return data ?? \"\";\n }\n\n if (tag === TAG_ARRAY) {\n const result: any[] = [];\n for (const childTag of [TAG_VALUE, TAG_OBJECT, TAG_ARRAY]) {\n const childNodes = Array.isArray(data[childTag])\n ? data[childTag]\n : data[childTag]\n ? [data[childTag]]\n : [];\n for (const child of childNodes) {\n result.push(fromGenericNode(childTag, child));\n }\n }\n return result;\n }\n\n // TAG_OBJECT\n const obj: Record<string, any> = {};\n for (const childTag of [TAG_VALUE, TAG_OBJECT, TAG_ARRAY]) {\n const childNodes = Array.isArray(data[childTag])\n ? data[childTag]\n : data[childTag]\n ? [data[childTag]]\n : [];\n for (const child of childNodes) {\n const key = child.key || \"\";\n obj[key] = fromGenericNode(childTag, child);\n }\n }\n return obj;\n}\n\nexport function obj2xml<T>(obj: T): string {\n const rootNode = toGenericNode(obj)[TAG_OBJECT];\n const builder = new XMLBuilder({\n ignoreAttributes: false,\n attributeNamePrefix: \"\",\n format: true,\n suppressEmptyNode: true,\n });\n return builder.build({ [TAG_OBJECT]: rootNode });\n}\n\nexport function parseXmlFromResponseText<T = any>(text: string): T {\n const xmlStart = text.indexOf(\"<\");\n const xmlEnd = text.lastIndexOf(\">\") + 1;\n\n if (xmlStart !== -1 && xmlEnd > xmlStart) {\n text = text.substring(xmlStart, xmlEnd);\n }\n\n const parser = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: \"\",\n parseTagValue: true,\n parseAttributeValue: false,\n processEntities: true,\n isArray: (name) => [TAG_VALUE, TAG_ARRAY, TAG_OBJECT].includes(name),\n });\n const parsed = parser.parse(text);\n\n // Remove XML declaration\n const { \"?xml\": _, ...withoutDeclaration } = parsed;\n\n const rootTag = Object.keys(withoutDeclaration)[0];\n const rootNode = Array.isArray(withoutDeclaration[rootTag])\n ? withoutDeclaration[rootTag][0]\n : withoutDeclaration[rootTag];\n\n return fromGenericNode(rootTag, rootNode);\n}\n"],"mappings":";;;AAGA,MAAM,aAAa;AACnB,MAAM,YAAY;AAClB,MAAM,YAAY;;;;AAKlB,SAAS,cAAc,OAAY,KAAmC;AACpE,KAAI,MAAM,QAAQ,MAAM,EAAE;EACxB,MAAM,WAAW,MAAM,KAAK,SAAS,cAAc,KAAK,CAAC;AACzD,SAAO,GACJ,YAAY;GACX,GAAI,MAAM,EAAE,KAAK,GAAG,EAAE;GACtB,GAAG,cAAc,SAAS;GAC3B,EACF;;AAGH,KAAI,SAAS,OAAO,UAAU,YAAY,MAAM,gBAAgB,QAAQ;EACtE,MAAM,WAAW,OAAO,QAAQ,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,cAAc,GAAG,EAAE,CAAC;AAC3E,SAAO,GACJ,aAAa;GACZ,GAAI,MAAM,EAAE,KAAK,GAAG,EAAE;GACtB,GAAG,cAAc,SAAS;GAC3B,EACF;;AAGH,QAAO,GACJ,YAAY;EACX,GAAI,MAAM,EAAE,KAAK,GAAG,EAAE;EACtB,SAAS,SAAS;EACnB,EACF;;;;;AAMH,SAAS,cAAc,OAAmD;CACxE,MAAMA,UAAiC,EAAE;AAEzC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,MAAM,OAAO,KAAK,KAAK,CAAC;AAC9B,MAAI,CAAC,QAAQ,KACX,SAAQ,OAAO,EAAE;AAEnB,UAAQ,KAAK,KAAK,KAAK,KAAK;;AAG9B,QAAO;;;;;AAMT,SAAS,gBAAgB,KAAa,MAAgB;AACpD,KAAI,QAAQ,WAAW;AACrB,MAAI,QAAQ,OAAO,SAAS,YAAY,WAAW,KACjD,QAAO,KAAK,YAAY;AAI1B,MAAI,QAAQ,OAAO,SAAS,SAC1B,QAAO;AAET,SAAO,QAAQ;;AAGjB,KAAI,QAAQ,WAAW;EACrB,MAAMC,SAAgB,EAAE;AACxB,OAAK,MAAM,YAAY;GAAC;GAAW;GAAY;GAAU,EAAE;GACzD,MAAM,aAAa,MAAM,QAAQ,KAAK,UAAU,GAC5C,KAAK,YACL,KAAK,YACH,CAAC,KAAK,UAAU,GAChB,EAAE;AACR,QAAK,MAAM,SAAS,WAClB,QAAO,KAAK,gBAAgB,UAAU,MAAM,CAAC;;AAGjD,SAAO;;CAIT,MAAMC,MAA2B,EAAE;AACnC,MAAK,MAAM,YAAY;EAAC;EAAW;EAAY;EAAU,EAAE;EACzD,MAAM,aAAa,MAAM,QAAQ,KAAK,UAAU,GAC5C,KAAK,YACL,KAAK,YACH,CAAC,KAAK,UAAU,GAChB,EAAE;AACR,OAAK,MAAM,SAAS,YAAY;GAC9B,MAAM,MAAM,MAAM,OAAO;AACzB,OAAI,OAAO,gBAAgB,UAAU,MAAM;;;AAG/C,QAAO;;AAGT,SAAgB,QAAW,KAAgB;CACzC,MAAM,WAAW,cAAc,IAAI,CAAC;AAOpC,QANgB,IAAI,WAAW;EAC7B,kBAAkB;EAClB,qBAAqB;EACrB,QAAQ;EACR,mBAAmB;EACpB,CAAC,CACa,MAAM,GAAG,aAAa,UAAU,CAAC;;AAGlD,SAAgB,yBAAkC,MAAiB;CACjE,MAAM,WAAW,KAAK,QAAQ,IAAI;CAClC,MAAM,SAAS,KAAK,YAAY,IAAI,GAAG;AAEvC,KAAI,aAAa,MAAM,SAAS,SAC9B,QAAO,KAAK,UAAU,UAAU,OAAO;CAczC,MAAM,EAAE,QAAQ,GAAG,GAAG,uBAXP,IAAI,UAAU;EAC3B,kBAAkB;EAClB,qBAAqB;EACrB,eAAe;EACf,qBAAqB;EACrB,iBAAiB;EACjB,UAAU,SAAS;GAAC;GAAW;GAAW;GAAW,CAAC,SAAS,KAAK;EACrE,CAAC,CACoB,MAAM,KAAK;CAKjC,MAAM,UAAU,OAAO,KAAK,mBAAmB,CAAC;AAKhD,QAAO,gBAAgB,SAJN,MAAM,QAAQ,mBAAmB,SAAS,GACvD,mBAAmB,SAAS,KAC5B,mBAAmB,SAEkB"}
@@ -0,0 +1,36 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ let _formatjs_icu_messageformat_parser = require("@formatjs/icu-messageformat-parser");
3
+
4
+ //#region src/translators/pluralization/icu-validator.ts
5
+ /**
6
+ * ICU MessageFormat validator using FormatJS parser
7
+ *
8
+ * Uses the official ICU MessageFormat parser for validation instead of custom regex logic.
9
+ * This ensures standards-compliant validation that matches runtime behavior.
10
+ */
11
+ /**
12
+ * Validate and log result
13
+ *
14
+ * @param icuText ICU format text
15
+ * @param originalText Original source text (for logging)
16
+ * @param logger
17
+ * @returns True if valid, false otherwise
18
+ */
19
+ function validateICU(icuText, originalText, logger) {
20
+ try {
21
+ (0, _formatjs_icu_messageformat_parser.parse)(icuText, {
22
+ ignoreTag: false,
23
+ requiresOtherClause: true
24
+ });
25
+ logger.debug(`✓ ICU format valid for: "${originalText}"`);
26
+ return true;
27
+ } catch (error) {
28
+ const errorMessage = error instanceof Error ? error.message : "Unknown parsing error";
29
+ logger.warn(`✗ ICU format invalid for: "${originalText}"`);
30
+ logger.warn(` - ${errorMessage}`);
31
+ return false;
32
+ }
33
+ }
34
+
35
+ //#endregion
36
+ exports.validateICU = validateICU;
@@ -0,0 +1,36 @@
1
+ import { parse } from "@formatjs/icu-messageformat-parser";
2
+
3
+ //#region src/translators/pluralization/icu-validator.ts
4
+ /**
5
+ * ICU MessageFormat validator using FormatJS parser
6
+ *
7
+ * Uses the official ICU MessageFormat parser for validation instead of custom regex logic.
8
+ * This ensures standards-compliant validation that matches runtime behavior.
9
+ */
10
+ /**
11
+ * Validate and log result
12
+ *
13
+ * @param icuText ICU format text
14
+ * @param originalText Original source text (for logging)
15
+ * @param logger
16
+ * @returns True if valid, false otherwise
17
+ */
18
+ function validateICU(icuText, originalText, logger) {
19
+ try {
20
+ parse(icuText, {
21
+ ignoreTag: false,
22
+ requiresOtherClause: true
23
+ });
24
+ logger.debug(`✓ ICU format valid for: "${originalText}"`);
25
+ return true;
26
+ } catch (error) {
27
+ const errorMessage = error instanceof Error ? error.message : "Unknown parsing error";
28
+ logger.warn(`✗ ICU format invalid for: "${originalText}"`);
29
+ logger.warn(` - ${errorMessage}`);
30
+ return false;
31
+ }
32
+ }
33
+
34
+ //#endregion
35
+ export { validateICU };
36
+ //# sourceMappingURL=icu-validator.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icu-validator.mjs","names":[],"sources":["../../../src/translators/pluralization/icu-validator.ts"],"sourcesContent":["/**\n * ICU MessageFormat validator using FormatJS parser\n *\n * Uses the official ICU MessageFormat parser for validation instead of custom regex logic.\n * This ensures standards-compliant validation that matches runtime behavior.\n */\nimport { parse } from \"@formatjs/icu-messageformat-parser\";\nimport type { Logger } from \"../../utils/logger\";\n\n/**\n * Validate and log result\n *\n * @param icuText ICU format text\n * @param originalText Original source text (for logging)\n * @param logger\n * @returns True if valid, false otherwise\n */\nexport function validateICU(\n icuText: string,\n originalText: string,\n logger: Logger,\n): boolean {\n try {\n // I guess `new IntlMessageFormat(icuText, \"locale\")` could also be used, but it looks less obvious than using parser explicitly.\n parse(icuText, {\n ignoreTag: false, // Don't ignore HTML-like tags\n requiresOtherClause: true, // Require 'other' clause in plural/select\n });\n // LLM initially generated more validations. But validation for \"other\" clause is already done by the parser, and we care only about the validity of the message,\n // we do not require it to have the pluralization. We trust that LLM adds them where needed.\n logger.debug(`✓ ICU format valid for: \"${originalText}\"`);\n return true;\n } catch (error) {\n // Parser throws SyntaxError for invalid ICU syntax\n const errorMessage =\n error instanceof Error ? error.message : \"Unknown parsing error\";\n logger.warn(`✗ ICU format invalid for: \"${originalText}\"`);\n logger.warn(` - ${errorMessage}`);\n return false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,SAAgB,YACd,SACA,cACA,QACS;AACT,KAAI;AAEF,QAAM,SAAS;GACb,WAAW;GACX,qBAAqB;GACtB,CAAC;AAGF,SAAO,MAAM,4BAA4B,aAAa,GAAG;AACzD,SAAO;UACA,OAAO;EAEd,MAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,SAAO,KAAK,8BAA8B,aAAa,GAAG;AAC1D,SAAO,KAAK,OAAO,eAAe;AAClC,SAAO"}
@@ -0,0 +1,25 @@
1
+
2
+ //#region src/translators/pluralization/pattern-detector.ts
3
+ const EXPRESSION_PATTERN = /\{(\w+)}/g;
4
+ /**
5
+ * Detect plural candidates from a list of entries
6
+ *
7
+ * @param entries Map of hash -> source text
8
+ * @returns Array of plural candidates
9
+ */
10
+ function detectPluralCandidates(entries, logger) {
11
+ const candidates = [];
12
+ for (const [hash, sourceText] of Object.entries(entries)) {
13
+ const match = sourceText.match(EXPRESSION_PATTERN);
14
+ if (!match) continue;
15
+ logger.debug(`Found ${match[1]} expression in: "${sourceText}. Text selected for pluralization."`);
16
+ candidates.push({
17
+ hash,
18
+ sourceText
19
+ });
20
+ }
21
+ return candidates;
22
+ }
23
+
24
+ //#endregion
25
+ exports.detectPluralCandidates = detectPluralCandidates;
@@ -0,0 +1,25 @@
1
+ //#region src/translators/pluralization/pattern-detector.ts
2
+ const EXPRESSION_PATTERN = /\{(\w+)}/g;
3
+ /**
4
+ * Detect plural candidates from a list of entries
5
+ *
6
+ * @param entries Map of hash -> source text
7
+ * @returns Array of plural candidates
8
+ */
9
+ function detectPluralCandidates(entries, logger) {
10
+ const candidates = [];
11
+ for (const [hash, sourceText] of Object.entries(entries)) {
12
+ const match = sourceText.match(EXPRESSION_PATTERN);
13
+ if (!match) continue;
14
+ logger.debug(`Found ${match[1]} expression in: "${sourceText}. Text selected for pluralization."`);
15
+ candidates.push({
16
+ hash,
17
+ sourceText
18
+ });
19
+ }
20
+ return candidates;
21
+ }
22
+
23
+ //#endregion
24
+ export { detectPluralCandidates };
25
+ //# sourceMappingURL=pattern-detector.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pattern-detector.mjs","names":["candidates: PluralCandidate[]"],"sources":["../../../src/translators/pluralization/pattern-detector.ts"],"sourcesContent":["/**\n * Pattern-based detection for plural candidates\n *\n * Uses heuristics to identify messages that might benefit from pluralization\n */\n\nimport type { PluralCandidate } from \"./types\";\nimport type { Logger } from \"../../utils/logger\";\n\n// Anything that's not a variable name like is not expected.\nconst EXPRESSION_PATTERN = /\\{(\\w+)}/g;\n\n/**\n * Detect plural candidates from a list of entries\n *\n * @param entries Map of hash -> source text\n * @returns Array of plural candidates\n */\nexport function detectPluralCandidates(\n entries: Record<string, string>,\n logger: Logger,\n): PluralCandidate[] {\n const candidates: PluralCandidate[] = [];\n\n for (const [hash, sourceText] of Object.entries(entries)) {\n const match = sourceText.match(EXPRESSION_PATTERN);\n if (!match) {\n continue;\n }\n logger.debug(\n `Found ${match[1]} expression in: \"${sourceText}. Text selected for pluralization.\"`,\n );\n candidates.push({\n hash,\n sourceText,\n });\n }\n\n return candidates;\n}\n"],"mappings":";AAUA,MAAM,qBAAqB;;;;;;;AAQ3B,SAAgB,uBACd,SACA,QACmB;CACnB,MAAMA,aAAgC,EAAE;AAExC,MAAK,MAAM,CAAC,MAAM,eAAe,OAAO,QAAQ,QAAQ,EAAE;EACxD,MAAM,QAAQ,WAAW,MAAM,mBAAmB;AAClD,MAAI,CAAC,MACH;AAEF,SAAO,MACL,SAAS,MAAM,GAAG,mBAAmB,WAAW,qCACjD;AACD,aAAW,KAAK;GACd;GACA;GACD,CAAC;;AAGJ,QAAO"}
@@ -0,0 +1,98 @@
1
+
2
+ //#region src/translators/pluralization/prompt.ts
3
+ function getSystemPrompt(args) {
4
+ return `
5
+ # Identity
6
+
7
+ You are an advanced AI localization engine. You do state-of-the-art localization for software products.
8
+ Your task is to analyze text messages and determine if they should be pluralized.
9
+ If pluralization is appropriate, convert the message to ICU MessageFormat with proper plural rules.
10
+
11
+ ## Setup
12
+
13
+ Source language (locale code): ${args.sourceLocale}
14
+
15
+ ICU MessageFormat syntax for plurals:
16
+ {variable, plural,
17
+ =0 {zero form}
18
+ one {singular form}
19
+ other {plural form}
20
+ }
21
+
22
+ Use # to represent the count in the message (e.g., "# item" becomes "1 item", "5 items").
23
+
24
+ ## Guidelines
25
+
26
+ 1. Only pluralize if the message varies based on a count/quantity
27
+ 2. Detect the variable name from the message (e.g., {count}, {itemCount})
28
+ 3. Generate appropriate forms: =0 (optional zero case), one (singular), other (plural)
29
+ 4. Preserve the original message structure and style
30
+ 5. Keep variable names from the original text
31
+ 6. If pluralization is NOT appropriate, explain why
32
+ 7. YOU MUST ONLY PRODUCE VALID XML.
33
+
34
+ ## Input Format
35
+
36
+ You will receive an XML document with candidates to analyze:
37
+
38
+ <pluralizationBatch>
39
+ <version>0.1</version>
40
+ <sourceLocale>${args.sourceLocale}</sourceLocale>
41
+ <candidates>
42
+ <candidate>
43
+ <hash>abc123</hash>
44
+ <text>You have {count} items</text>
45
+ </candidate>
46
+ </candidates>
47
+ </pluralizationBatch>
48
+
49
+ ## Output Format
50
+
51
+ Respond with XML containing results for each candidate:
52
+
53
+ <pluralizationResponse>
54
+ <version>0.1</version>
55
+ <results>
56
+ <result>
57
+ <hash>abc123</hash>
58
+ <shouldPluralize>true</shouldPluralize>
59
+ <icuText>You have {count, plural, =0 {no items} one {# item} other {# items}}</icuText>
60
+ <reasoning>Message varies based on count quantity</reasoning>
61
+ </result>
62
+ </results>
63
+ </pluralizationResponse>
64
+
65
+ ## Examples
66
+
67
+ Example 1 - Should pluralize:
68
+ Input:
69
+ <candidate>
70
+ <hash>h1</hash>
71
+ <text>You have {count} items</text>
72
+ </candidate>
73
+
74
+ Output:
75
+ <result>
76
+ <hash>h1</hash>
77
+ <shouldPluralize>true</shouldPluralize>
78
+ <icuText>You have {count, plural, =0 {no items} one {# item} other {# items}}</icuText>
79
+ <reasoning>Message varies based on count quantity</reasoning>
80
+ </result>
81
+
82
+ Example 2 - Should NOT pluralize:
83
+ Input:
84
+ <candidate>
85
+ <hash>h2</hash>
86
+ <text>Hello {name}</text>
87
+ </candidate>
88
+
89
+ Output:
90
+ <result>
91
+ <hash>h2</hash>
92
+ <shouldPluralize>false</shouldPluralize>
93
+ <reasoning>Message does not vary based on quantity, {name} is not a count variable</reasoning>
94
+ </result>`;
95
+ }
96
+
97
+ //#endregion
98
+ exports.getSystemPrompt = getSystemPrompt;
@@ -0,0 +1,98 @@
1
+ //#region src/translators/pluralization/prompt.ts
2
+ function getSystemPrompt(args) {
3
+ return `
4
+ # Identity
5
+
6
+ You are an advanced AI localization engine. You do state-of-the-art localization for software products.
7
+ Your task is to analyze text messages and determine if they should be pluralized.
8
+ If pluralization is appropriate, convert the message to ICU MessageFormat with proper plural rules.
9
+
10
+ ## Setup
11
+
12
+ Source language (locale code): ${args.sourceLocale}
13
+
14
+ ICU MessageFormat syntax for plurals:
15
+ {variable, plural,
16
+ =0 {zero form}
17
+ one {singular form}
18
+ other {plural form}
19
+ }
20
+
21
+ Use # to represent the count in the message (e.g., "# item" becomes "1 item", "5 items").
22
+
23
+ ## Guidelines
24
+
25
+ 1. Only pluralize if the message varies based on a count/quantity
26
+ 2. Detect the variable name from the message (e.g., {count}, {itemCount})
27
+ 3. Generate appropriate forms: =0 (optional zero case), one (singular), other (plural)
28
+ 4. Preserve the original message structure and style
29
+ 5. Keep variable names from the original text
30
+ 6. If pluralization is NOT appropriate, explain why
31
+ 7. YOU MUST ONLY PRODUCE VALID XML.
32
+
33
+ ## Input Format
34
+
35
+ You will receive an XML document with candidates to analyze:
36
+
37
+ <pluralizationBatch>
38
+ <version>0.1</version>
39
+ <sourceLocale>${args.sourceLocale}</sourceLocale>
40
+ <candidates>
41
+ <candidate>
42
+ <hash>abc123</hash>
43
+ <text>You have {count} items</text>
44
+ </candidate>
45
+ </candidates>
46
+ </pluralizationBatch>
47
+
48
+ ## Output Format
49
+
50
+ Respond with XML containing results for each candidate:
51
+
52
+ <pluralizationResponse>
53
+ <version>0.1</version>
54
+ <results>
55
+ <result>
56
+ <hash>abc123</hash>
57
+ <shouldPluralize>true</shouldPluralize>
58
+ <icuText>You have {count, plural, =0 {no items} one {# item} other {# items}}</icuText>
59
+ <reasoning>Message varies based on count quantity</reasoning>
60
+ </result>
61
+ </results>
62
+ </pluralizationResponse>
63
+
64
+ ## Examples
65
+
66
+ Example 1 - Should pluralize:
67
+ Input:
68
+ <candidate>
69
+ <hash>h1</hash>
70
+ <text>You have {count} items</text>
71
+ </candidate>
72
+
73
+ Output:
74
+ <result>
75
+ <hash>h1</hash>
76
+ <shouldPluralize>true</shouldPluralize>
77
+ <icuText>You have {count, plural, =0 {no items} one {# item} other {# items}}</icuText>
78
+ <reasoning>Message varies based on count quantity</reasoning>
79
+ </result>
80
+
81
+ Example 2 - Should NOT pluralize:
82
+ Input:
83
+ <candidate>
84
+ <hash>h2</hash>
85
+ <text>Hello {name}</text>
86
+ </candidate>
87
+
88
+ Output:
89
+ <result>
90
+ <hash>h2</hash>
91
+ <shouldPluralize>false</shouldPluralize>
92
+ <reasoning>Message does not vary based on quantity, {name} is not a count variable</reasoning>
93
+ </result>`;
94
+ }
95
+
96
+ //#endregion
97
+ export { getSystemPrompt };
98
+ //# sourceMappingURL=prompt.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.mjs","names":[],"sources":["../../../src/translators/pluralization/prompt.ts"],"sourcesContent":["interface PromptArguments {\n sourceLocale: string;\n}\n\nexport function getSystemPrompt(args: PromptArguments): string {\n return `\n# Identity\n\nYou are an advanced AI localization engine. You do state-of-the-art localization for software products.\nYour task is to analyze text messages and determine if they should be pluralized.\nIf pluralization is appropriate, convert the message to ICU MessageFormat with proper plural rules.\n\n## Setup\n\nSource language (locale code): ${args.sourceLocale}\n\nICU MessageFormat syntax for plurals:\n{variable, plural,\n =0 {zero form}\n one {singular form}\n other {plural form}\n}\n\nUse # to represent the count in the message (e.g., \"# item\" becomes \"1 item\", \"5 items\").\n\n## Guidelines\n\n1. Only pluralize if the message varies based on a count/quantity\n2. Detect the variable name from the message (e.g., {count}, {itemCount})\n3. Generate appropriate forms: =0 (optional zero case), one (singular), other (plural)\n4. Preserve the original message structure and style\n5. Keep variable names from the original text\n6. If pluralization is NOT appropriate, explain why\n7. YOU MUST ONLY PRODUCE VALID XML.\n\n## Input Format\n\nYou will receive an XML document with candidates to analyze:\n\n<pluralizationBatch>\n <version>0.1</version>\n <sourceLocale>${args.sourceLocale}</sourceLocale>\n <candidates>\n <candidate>\n <hash>abc123</hash>\n <text>You have {count} items</text>\n </candidate>\n </candidates>\n</pluralizationBatch>\n\n## Output Format\n\nRespond with XML containing results for each candidate:\n\n<pluralizationResponse>\n <version>0.1</version>\n <results>\n <result>\n <hash>abc123</hash>\n <shouldPluralize>true</shouldPluralize>\n <icuText>You have {count, plural, =0 {no items} one {# item} other {# items}}</icuText>\n <reasoning>Message varies based on count quantity</reasoning>\n </result>\n </results>\n</pluralizationResponse>\n\n## Examples\n\nExample 1 - Should pluralize:\nInput:\n<candidate>\n <hash>h1</hash>\n <text>You have {count} items</text>\n</candidate>\n\nOutput:\n<result>\n <hash>h1</hash>\n <shouldPluralize>true</shouldPluralize>\n <icuText>You have {count, plural, =0 {no items} one {# item} other {# items}}</icuText>\n <reasoning>Message varies based on count quantity</reasoning>\n</result>\n\nExample 2 - Should NOT pluralize:\nInput:\n<candidate>\n <hash>h2</hash>\n <text>Hello {name}</text>\n</candidate>\n\nOutput:\n<result>\n <hash>h2</hash>\n <shouldPluralize>false</shouldPluralize>\n <reasoning>Message does not vary based on quantity, {name} is not a count variable</reasoning>\n</result>`;\n}\n"],"mappings":";AAIA,SAAgB,gBAAgB,MAA+B;AAC7D,QAAO;;;;;;;;;iCASwB,KAAK,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA2BjC,KAAK,aAAa"}