@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.
- package/LICENSE.md +201 -0
- package/README.md +192 -0
- package/build/_virtual/rolldown_runtime.cjs +29 -0
- package/build/_virtual/rolldown_runtime.mjs +7 -0
- package/build/index.cjs +0 -0
- package/build/index.d.cts +2 -0
- package/build/index.d.mts +2 -0
- package/build/index.mjs +1 -0
- package/build/metadata/manager.cjs +131 -0
- package/build/metadata/manager.mjs +123 -0
- package/build/metadata/manager.mjs.map +1 -0
- package/build/plugin/build-translator.cjs +198 -0
- package/build/plugin/build-translator.mjs +196 -0
- package/build/plugin/build-translator.mjs.map +1 -0
- package/build/plugin/cleanup.cjs +20 -0
- package/build/plugin/cleanup.mjs +20 -0
- package/build/plugin/cleanup.mjs.map +1 -0
- package/build/plugin/next-compiler-loader.cjs +41 -0
- package/build/plugin/next-compiler-loader.d.cts +12 -0
- package/build/plugin/next-compiler-loader.d.cts.map +1 -0
- package/build/plugin/next-compiler-loader.d.mts +13 -0
- package/build/plugin/next-compiler-loader.d.mts.map +1 -0
- package/build/plugin/next-compiler-loader.mjs +42 -0
- package/build/plugin/next-compiler-loader.mjs.map +1 -0
- package/build/plugin/next-config-loader.cjs +13 -0
- package/build/plugin/next-config-loader.d.cts +8 -0
- package/build/plugin/next-config-loader.d.cts.map +1 -0
- package/build/plugin/next-config-loader.d.mts +9 -0
- package/build/plugin/next-config-loader.d.mts.map +1 -0
- package/build/plugin/next-config-loader.mjs +14 -0
- package/build/plugin/next-config-loader.mjs.map +1 -0
- package/build/plugin/next-locale-client-loader.cjs +9 -0
- package/build/plugin/next-locale-client-loader.d.cts +8 -0
- package/build/plugin/next-locale-client-loader.d.cts.map +1 -0
- package/build/plugin/next-locale-client-loader.d.mts +9 -0
- package/build/plugin/next-locale-client-loader.d.mts.map +1 -0
- package/build/plugin/next-locale-client-loader.mjs +10 -0
- package/build/plugin/next-locale-client-loader.mjs.map +1 -0
- package/build/plugin/next-locale-server-loader.cjs +9 -0
- package/build/plugin/next-locale-server-loader.d.cts +8 -0
- package/build/plugin/next-locale-server-loader.d.cts.map +1 -0
- package/build/plugin/next-locale-server-loader.d.mts +9 -0
- package/build/plugin/next-locale-server-loader.d.mts.map +1 -0
- package/build/plugin/next-locale-server-loader.mjs +10 -0
- package/build/plugin/next-locale-server-loader.mjs.map +1 -0
- package/build/plugin/next.cjs +220 -0
- package/build/plugin/next.d.cts +9 -0
- package/build/plugin/next.d.cts.map +1 -0
- package/build/plugin/next.d.mts +9 -0
- package/build/plugin/next.d.mts.map +1 -0
- package/build/plugin/next.mjs +222 -0
- package/build/plugin/next.mjs.map +1 -0
- package/build/plugin/transform/babel-compat.cjs +13 -0
- package/build/plugin/transform/babel-compat.mjs +10 -0
- package/build/plugin/transform/babel-compat.mjs.map +1 -0
- package/build/plugin/transform/index.cjs +44 -0
- package/build/plugin/transform/index.mjs +42 -0
- package/build/plugin/transform/index.mjs.map +1 -0
- package/build/plugin/transform/metadata.cjs +142 -0
- package/build/plugin/transform/metadata.mjs +141 -0
- package/build/plugin/transform/metadata.mjs.map +1 -0
- package/build/plugin/transform/parse-override.cjs +145 -0
- package/build/plugin/transform/parse-override.mjs +144 -0
- package/build/plugin/transform/parse-override.mjs.map +1 -0
- package/build/plugin/transform/process-file.cjs +391 -0
- package/build/plugin/transform/process-file.mjs +390 -0
- package/build/plugin/transform/process-file.mjs.map +1 -0
- package/build/plugin/transform/use-i18n.cjs +8 -0
- package/build/plugin/transform/use-i18n.mjs +7 -0
- package/build/plugin/transform/use-i18n.mjs.map +1 -0
- package/build/plugin/transform/utils.cjs +205 -0
- package/build/plugin/transform/utils.mjs +192 -0
- package/build/plugin/transform/utils.mjs.map +1 -0
- package/build/plugin/unplugin.cjs +188 -0
- package/build/plugin/unplugin.d.cts +8 -0
- package/build/plugin/unplugin.d.cts.map +1 -0
- package/build/plugin/unplugin.d.mts +8 -0
- package/build/plugin/unplugin.d.mts.map +1 -0
- package/build/plugin/unplugin.mjs +186 -0
- package/build/plugin/unplugin.mjs.map +1 -0
- package/build/plugin/vite.cjs +28 -0
- package/build/plugin/vite.d.cts +9 -0
- package/build/plugin/vite.d.cts.map +1 -0
- package/build/plugin/vite.d.mts +9 -0
- package/build/plugin/vite.d.mts.map +1 -0
- package/build/plugin/vite.mjs +29 -0
- package/build/plugin/vite.mjs.map +1 -0
- package/build/plugin/webpack.cjs +27 -0
- package/build/plugin/webpack.d.cts +8 -0
- package/build/plugin/webpack.d.cts.map +1 -0
- package/build/plugin/webpack.d.mts +8 -0
- package/build/plugin/webpack.d.mts.map +1 -0
- package/build/plugin/webpack.mjs +28 -0
- package/build/plugin/webpack.mjs.map +1 -0
- package/build/react/client/index.cjs +9 -0
- package/build/react/client/index.d.cts +5 -0
- package/build/react/client/index.d.mts +5 -0
- package/build/react/client/index.mjs +6 -0
- package/build/react/client/useTranslation.cjs +71 -0
- package/build/react/client/useTranslation.d.cts +42 -0
- package/build/react/client/useTranslation.d.cts.map +1 -0
- package/build/react/client/useTranslation.d.mts +42 -0
- package/build/react/client/useTranslation.d.mts.map +1 -0
- package/build/react/client/useTranslation.mjs +71 -0
- package/build/react/client/useTranslation.mjs.map +1 -0
- package/build/react/next/client.cjs +25 -0
- package/build/react/next/client.d.cts +9 -0
- package/build/react/next/client.d.cts.map +1 -0
- package/build/react/next/client.d.mts +9 -0
- package/build/react/next/client.d.mts.map +1 -0
- package/build/react/next/client.mjs +24 -0
- package/build/react/next/client.mjs.map +1 -0
- package/build/react/next/cookie-locale-resolver.cjs +29 -0
- package/build/react/next/cookie-locale-resolver.d.cts +33 -0
- package/build/react/next/cookie-locale-resolver.d.cts.map +1 -0
- package/build/react/next/cookie-locale-resolver.d.mts +33 -0
- package/build/react/next/cookie-locale-resolver.d.mts.map +1 -0
- package/build/react/next/cookie-locale-resolver.mjs +29 -0
- package/build/react/next/cookie-locale-resolver.mjs.map +1 -0
- package/build/react/next/server.cjs +21 -0
- package/build/react/next/server.d.cts +13 -0
- package/build/react/next/server.d.cts.map +1 -0
- package/build/react/next/server.d.mts +14 -0
- package/build/react/next/server.d.mts.map +1 -0
- package/build/react/next/server.mjs +20 -0
- package/build/react/next/server.mjs.map +1 -0
- package/build/react/server/ServerLingoProvider.cjs +19 -0
- package/build/react/server/ServerLingoProvider.d.cts +12 -0
- package/build/react/server/ServerLingoProvider.d.cts.map +1 -0
- package/build/react/server/ServerLingoProvider.d.mts +12 -0
- package/build/react/server/ServerLingoProvider.d.mts.map +1 -0
- package/build/react/server/ServerLingoProvider.mjs +19 -0
- package/build/react/server/ServerLingoProvider.mjs.map +1 -0
- package/build/react/server/index.cjs +7 -0
- package/build/react/server/index.d.cts +4 -0
- package/build/react/server/index.d.mts +4 -0
- package/build/react/server/index.mjs +5 -0
- package/build/react/server/useTranslation.cjs +60 -0
- package/build/react/server/useTranslation.d.cts +36 -0
- package/build/react/server/useTranslation.d.cts.map +1 -0
- package/build/react/server/useTranslation.d.mts +36 -0
- package/build/react/server/useTranslation.d.mts.map +1 -0
- package/build/react/server/useTranslation.mjs +60 -0
- package/build/react/server/useTranslation.mjs.map +1 -0
- package/build/react/server-only/index.cjs +42 -0
- package/build/react/server-only/index.d.cts +38 -0
- package/build/react/server-only/index.d.cts.map +1 -0
- package/build/react/server-only/index.d.mts +38 -0
- package/build/react/server-only/index.d.mts.map +1 -0
- package/build/react/server-only/index.mjs +42 -0
- package/build/react/server-only/index.mjs.map +1 -0
- package/build/react/server-only/translations.cjs +85 -0
- package/build/react/server-only/translations.mjs +85 -0
- package/build/react/server-only/translations.mjs.map +1 -0
- package/build/react/shared/LingoContext.cjs +14 -0
- package/build/react/shared/LingoContext.d.cts +41 -0
- package/build/react/shared/LingoContext.d.cts.map +1 -0
- package/build/react/shared/LingoContext.d.mts +41 -0
- package/build/react/shared/LingoContext.d.mts.map +1 -0
- package/build/react/shared/LingoContext.mjs +13 -0
- package/build/react/shared/LingoContext.mjs.map +1 -0
- package/build/react/shared/LingoProvider.cjs +274 -0
- package/build/react/shared/LingoProvider.d.cts +76 -0
- package/build/react/shared/LingoProvider.d.cts.map +1 -0
- package/build/react/shared/LingoProvider.d.mts +76 -0
- package/build/react/shared/LingoProvider.d.mts.map +1 -0
- package/build/react/shared/LingoProvider.mjs +274 -0
- package/build/react/shared/LingoProvider.mjs.map +1 -0
- package/build/react/shared/LocaleSwitcher.cjs +61 -0
- package/build/react/shared/LocaleSwitcher.d.cts +71 -0
- package/build/react/shared/LocaleSwitcher.d.cts.map +1 -0
- package/build/react/shared/LocaleSwitcher.d.mts +71 -0
- package/build/react/shared/LocaleSwitcher.d.mts.map +1 -0
- package/build/react/shared/LocaleSwitcher.mjs +61 -0
- package/build/react/shared/LocaleSwitcher.mjs.map +1 -0
- package/build/react/shared/render-rich-text.cjs +55 -0
- package/build/react/shared/render-rich-text.d.cts +17 -0
- package/build/react/shared/render-rich-text.d.cts.map +1 -0
- package/build/react/shared/render-rich-text.d.mts +17 -0
- package/build/react/shared/render-rich-text.d.mts.map +1 -0
- package/build/react/shared/render-rich-text.mjs +54 -0
- package/build/react/shared/render-rich-text.mjs.map +1 -0
- package/build/react/shared/utils.cjs +34 -0
- package/build/react/shared/utils.mjs +35 -0
- package/build/react/shared/utils.mjs.map +1 -0
- package/build/react/types.d.cts +16 -0
- package/build/react/types.d.cts.map +1 -0
- package/build/react/types.d.mts +16 -0
- package/build/react/types.d.mts.map +1 -0
- package/build/translation-server/logger.cjs +37 -0
- package/build/translation-server/logger.mjs +37 -0
- package/build/translation-server/logger.mjs.map +1 -0
- package/build/translation-server/translation-server.cjs +547 -0
- package/build/translation-server/translation-server.mjs +544 -0
- package/build/translation-server/translation-server.mjs.map +1 -0
- package/build/translation-server/ws-events.cjs +15 -0
- package/build/translation-server/ws-events.mjs +15 -0
- package/build/translation-server/ws-events.mjs.map +1 -0
- package/build/translators/api.cjs +12 -0
- package/build/translators/api.mjs +12 -0
- package/build/translators/api.mjs.map +1 -0
- package/build/translators/cache-factory.cjs +26 -0
- package/build/translators/cache-factory.mjs +27 -0
- package/build/translators/cache-factory.mjs.map +1 -0
- package/build/translators/lingo/model-factory.cjs +179 -0
- package/build/translators/lingo/model-factory.mjs +174 -0
- package/build/translators/lingo/model-factory.mjs.map +1 -0
- package/build/translators/lingo/prompt.cjs +43 -0
- package/build/translators/lingo/prompt.mjs +43 -0
- package/build/translators/lingo/prompt.mjs.map +1 -0
- package/build/translators/lingo/service.cjs +152 -0
- package/build/translators/lingo/service.mjs +152 -0
- package/build/translators/lingo/service.mjs.map +1 -0
- package/build/translators/lingo/shots.cjs +28 -0
- package/build/translators/lingo/shots.mjs +28 -0
- package/build/translators/lingo/shots.mjs.map +1 -0
- package/build/translators/local-cache.cjs +115 -0
- package/build/translators/local-cache.mjs +113 -0
- package/build/translators/local-cache.mjs.map +1 -0
- package/build/translators/parse-xml.cjs +109 -0
- package/build/translators/parse-xml.mjs +108 -0
- package/build/translators/parse-xml.mjs.map +1 -0
- package/build/translators/pluralization/icu-validator.cjs +36 -0
- package/build/translators/pluralization/icu-validator.mjs +36 -0
- package/build/translators/pluralization/icu-validator.mjs.map +1 -0
- package/build/translators/pluralization/pattern-detector.cjs +25 -0
- package/build/translators/pluralization/pattern-detector.mjs +25 -0
- package/build/translators/pluralization/pattern-detector.mjs.map +1 -0
- package/build/translators/pluralization/prompt.cjs +98 -0
- package/build/translators/pluralization/prompt.mjs +98 -0
- package/build/translators/pluralization/prompt.mjs.map +1 -0
- package/build/translators/pluralization/service.cjs +247 -0
- package/build/translators/pluralization/service.mjs +247 -0
- package/build/translators/pluralization/service.mjs.map +1 -0
- package/build/translators/pluralization/shots.cjs +53 -0
- package/build/translators/pluralization/shots.mjs +53 -0
- package/build/translators/pluralization/shots.mjs.map +1 -0
- package/build/translators/pluralization/types.d.cts +17 -0
- package/build/translators/pluralization/types.d.cts.map +1 -0
- package/build/translators/pluralization/types.d.mts +17 -0
- package/build/translators/pluralization/types.d.mts.map +1 -0
- package/build/translators/pseudotranslator/index.cjs +129 -0
- package/build/translators/pseudotranslator/index.mjs +129 -0
- package/build/translators/pseudotranslator/index.mjs.map +1 -0
- package/build/translators/translation-service.cjs +182 -0
- package/build/translators/translation-service.mjs +183 -0
- package/build/translators/translation-service.mjs.map +1 -0
- package/build/translators/translator-factory.cjs +49 -0
- package/build/translators/translator-factory.mjs +50 -0
- package/build/translators/translator-factory.mjs.map +1 -0
- package/build/types.d.cts +161 -0
- package/build/types.d.cts.map +1 -0
- package/build/types.d.mts +161 -0
- package/build/types.d.mts.map +1 -0
- package/build/utils/config-factory.cjs +58 -0
- package/build/utils/config-factory.mjs +58 -0
- package/build/utils/config-factory.mjs.map +1 -0
- package/build/utils/hash.cjs +17 -0
- package/build/utils/hash.mjs +16 -0
- package/build/utils/hash.mjs.map +1 -0
- package/build/utils/is-valid-locale.cjs +14 -0
- package/build/utils/is-valid-locale.mjs +14 -0
- package/build/utils/is-valid-locale.mjs.map +1 -0
- package/build/utils/logger.cjs +51 -0
- package/build/utils/logger.mjs +50 -0
- package/build/utils/logger.mjs.map +1 -0
- package/build/utils/path-helpers.cjs +49 -0
- package/build/utils/path-helpers.mjs +47 -0
- package/build/utils/path-helpers.mjs.map +1 -0
- package/build/utils/timeout.cjs +42 -0
- package/build/utils/timeout.mjs +41 -0
- package/build/utils/timeout.mjs.map +1 -0
- package/build/virtual/code-generator.cjs +54 -0
- package/build/virtual/code-generator.mjs +53 -0
- package/build/virtual/code-generator.mjs.map +1 -0
- package/build/virtual/config.cjs +10 -0
- package/build/virtual/config.d.cts +9 -0
- package/build/virtual/config.d.cts.map +1 -0
- package/build/virtual/config.d.mts +9 -0
- package/build/virtual/config.d.mts.map +1 -0
- package/build/virtual/config.mjs +8 -0
- package/build/virtual/config.mjs.map +1 -0
- package/build/virtual/locale/client.cjs +23 -0
- package/build/virtual/locale/client.d.cts +19 -0
- package/build/virtual/locale/client.d.cts.map +1 -0
- package/build/virtual/locale/client.d.mts +19 -0
- package/build/virtual/locale/client.d.mts.map +1 -0
- package/build/virtual/locale/client.mjs +22 -0
- package/build/virtual/locale/client.mjs.map +1 -0
- package/build/virtual/locale/server.cjs +13 -0
- package/build/virtual/locale/server.d.cts +13 -0
- package/build/virtual/locale/server.d.cts.map +1 -0
- package/build/virtual/locale/server.d.mts +13 -0
- package/build/virtual/locale/server.d.mts.map +1 -0
- package/build/virtual/locale/server.mjs +13 -0
- package/build/virtual/locale/server.mjs.map +1 -0
- package/build/widget/lingo-dev-widget.cjs +228 -0
- package/build/widget/lingo-dev-widget.mjs +229 -0
- package/build/widget/lingo-dev-widget.mjs.map +1 -0
- 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":"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"}
|
|
@@ -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"}
|