glotfile 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/cli.js +56 -2
- package/dist/server/server.js +56 -2
- package/package.json +1 -1
package/dist/server/cli.js
CHANGED
|
@@ -1981,7 +1981,7 @@ function buildSystemPrompt(hasPluralItems) {
|
|
|
1981
1981
|
"- Preserve ICU plural/select structure verbatim (e.g. {count, plural, one {\u2026} other {\u2026}}); translate only the human-readable text inside each branch.",
|
|
1982
1982
|
"- Glossary: a term marked do-not-translate MUST appear unchanged in the translation. A term with a forced translation for the target locale MUST use that exact translation.",
|
|
1983
1983
|
"- Respect the max length (characters) when given; prefer a shorter natural phrasing over exceeding it.",
|
|
1984
|
-
|
|
1984
|
+
'- Quotation marks and apostrophes: punctuate exactly as a professional native translator instinctively would for the target language \u2014 its typographic conventions (e.g. \u201EGerman\u201C, \xABFrench\xBB, \u201CEnglish\u201D, \u2019 for apostrophes), applied with judgment about what is quoted prose versus a literal that must stay untouched. Never emit a raw ASCII double-quote (") inside a translated string \u2014 it corrupts the JSON reply.',
|
|
1985
1985
|
"- Match the register and capitalization conventions of the target language and of UI microcopy.",
|
|
1986
1986
|
"- Return ONLY the translated string for each item \u2014 no quotes, notes, or explanations."
|
|
1987
1987
|
];
|
|
@@ -2071,12 +2071,66 @@ var init_provider = __esm({
|
|
|
2071
2071
|
});
|
|
2072
2072
|
|
|
2073
2073
|
// src/server/ai/batch.ts
|
|
2074
|
+
function repairUnescapedQuotes(text) {
|
|
2075
|
+
const skipWs = (from) => {
|
|
2076
|
+
let i = from;
|
|
2077
|
+
while (i < text.length && /\s/.test(text[i])) i++;
|
|
2078
|
+
return i;
|
|
2079
|
+
};
|
|
2080
|
+
const stack = [];
|
|
2081
|
+
let out = "";
|
|
2082
|
+
let inString = false;
|
|
2083
|
+
let isKey = false;
|
|
2084
|
+
for (let i = 0; i < text.length; i++) {
|
|
2085
|
+
const ch = text[i];
|
|
2086
|
+
const top = stack[stack.length - 1];
|
|
2087
|
+
if (inString) {
|
|
2088
|
+
if (ch === "\\") {
|
|
2089
|
+
out += ch + (text[i + 1] ?? "");
|
|
2090
|
+
i++;
|
|
2091
|
+
} else if (ch !== '"') {
|
|
2092
|
+
out += ch;
|
|
2093
|
+
} else {
|
|
2094
|
+
const next = text[skipWs(i + 1)];
|
|
2095
|
+
const startsNextMember = () => {
|
|
2096
|
+
const after = text[skipWs(skipWs(i + 1) + 1)];
|
|
2097
|
+
return top?.type === "obj" ? after === '"' : after === "{" || after === "[" || after === '"';
|
|
2098
|
+
};
|
|
2099
|
+
const closes = isKey ? next === ":" : next === "}" || next === "]" || next === void 0 || next === "," && startsNextMember();
|
|
2100
|
+
if (closes) {
|
|
2101
|
+
inString = false;
|
|
2102
|
+
out += ch;
|
|
2103
|
+
} else {
|
|
2104
|
+
out += '\\"';
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
continue;
|
|
2108
|
+
}
|
|
2109
|
+
out += ch;
|
|
2110
|
+
if (ch === '"') {
|
|
2111
|
+
inString = true;
|
|
2112
|
+
isKey = top?.type === "obj" && top.expectingKey;
|
|
2113
|
+
} else if (ch === "{") stack.push({ type: "obj", expectingKey: true });
|
|
2114
|
+
else if (ch === "[") stack.push({ type: "arr", expectingKey: false });
|
|
2115
|
+
else if (ch === "}" || ch === "]") stack.pop();
|
|
2116
|
+
else if (ch === "," && top?.type === "obj") top.expectingKey = true;
|
|
2117
|
+
else if (ch === ":" && top) top.expectingKey = false;
|
|
2118
|
+
}
|
|
2119
|
+
try {
|
|
2120
|
+
JSON.parse(out);
|
|
2121
|
+
return out;
|
|
2122
|
+
} catch {
|
|
2123
|
+
return void 0;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2074
2126
|
function parseReplyItems(text) {
|
|
2075
2127
|
let parsed;
|
|
2076
2128
|
try {
|
|
2077
2129
|
parsed = JSON.parse(text);
|
|
2078
2130
|
} catch {
|
|
2079
|
-
|
|
2131
|
+
const repaired = repairUnescapedQuotes(text);
|
|
2132
|
+
if (repaired === void 0) throw new MalformedReplyError(text);
|
|
2133
|
+
parsed = JSON.parse(repaired);
|
|
2080
2134
|
}
|
|
2081
2135
|
if (!Array.isArray(parsed.items)) throw new MalformedReplyError(text);
|
|
2082
2136
|
return parsed.items;
|
package/dist/server/server.js
CHANGED
|
@@ -2806,7 +2806,7 @@ function buildSystemPrompt(hasPluralItems) {
|
|
|
2806
2806
|
"- Preserve ICU plural/select structure verbatim (e.g. {count, plural, one {\u2026} other {\u2026}}); translate only the human-readable text inside each branch.",
|
|
2807
2807
|
"- Glossary: a term marked do-not-translate MUST appear unchanged in the translation. A term with a forced translation for the target locale MUST use that exact translation.",
|
|
2808
2808
|
"- Respect the max length (characters) when given; prefer a shorter natural phrasing over exceeding it.",
|
|
2809
|
-
|
|
2809
|
+
'- Quotation marks and apostrophes: punctuate exactly as a professional native translator instinctively would for the target language \u2014 its typographic conventions (e.g. \u201EGerman\u201C, \xABFrench\xBB, \u201CEnglish\u201D, \u2019 for apostrophes), applied with judgment about what is quoted prose versus a literal that must stay untouched. Never emit a raw ASCII double-quote (") inside a translated string \u2014 it corrupts the JSON reply.',
|
|
2810
2810
|
"- Match the register and capitalization conventions of the target language and of UI microcopy.",
|
|
2811
2811
|
"- Return ONLY the translated string for each item \u2014 no quotes, notes, or explanations."
|
|
2812
2812
|
];
|
|
@@ -2898,12 +2898,66 @@ var MalformedReplyError = class extends Error {
|
|
|
2898
2898
|
}
|
|
2899
2899
|
raw;
|
|
2900
2900
|
};
|
|
2901
|
+
function repairUnescapedQuotes(text) {
|
|
2902
|
+
const skipWs = (from) => {
|
|
2903
|
+
let i = from;
|
|
2904
|
+
while (i < text.length && /\s/.test(text[i])) i++;
|
|
2905
|
+
return i;
|
|
2906
|
+
};
|
|
2907
|
+
const stack = [];
|
|
2908
|
+
let out = "";
|
|
2909
|
+
let inString = false;
|
|
2910
|
+
let isKey = false;
|
|
2911
|
+
for (let i = 0; i < text.length; i++) {
|
|
2912
|
+
const ch = text[i];
|
|
2913
|
+
const top = stack[stack.length - 1];
|
|
2914
|
+
if (inString) {
|
|
2915
|
+
if (ch === "\\") {
|
|
2916
|
+
out += ch + (text[i + 1] ?? "");
|
|
2917
|
+
i++;
|
|
2918
|
+
} else if (ch !== '"') {
|
|
2919
|
+
out += ch;
|
|
2920
|
+
} else {
|
|
2921
|
+
const next = text[skipWs(i + 1)];
|
|
2922
|
+
const startsNextMember = () => {
|
|
2923
|
+
const after = text[skipWs(skipWs(i + 1) + 1)];
|
|
2924
|
+
return top?.type === "obj" ? after === '"' : after === "{" || after === "[" || after === '"';
|
|
2925
|
+
};
|
|
2926
|
+
const closes = isKey ? next === ":" : next === "}" || next === "]" || next === void 0 || next === "," && startsNextMember();
|
|
2927
|
+
if (closes) {
|
|
2928
|
+
inString = false;
|
|
2929
|
+
out += ch;
|
|
2930
|
+
} else {
|
|
2931
|
+
out += '\\"';
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
continue;
|
|
2935
|
+
}
|
|
2936
|
+
out += ch;
|
|
2937
|
+
if (ch === '"') {
|
|
2938
|
+
inString = true;
|
|
2939
|
+
isKey = top?.type === "obj" && top.expectingKey;
|
|
2940
|
+
} else if (ch === "{") stack.push({ type: "obj", expectingKey: true });
|
|
2941
|
+
else if (ch === "[") stack.push({ type: "arr", expectingKey: false });
|
|
2942
|
+
else if (ch === "}" || ch === "]") stack.pop();
|
|
2943
|
+
else if (ch === "," && top?.type === "obj") top.expectingKey = true;
|
|
2944
|
+
else if (ch === ":" && top) top.expectingKey = false;
|
|
2945
|
+
}
|
|
2946
|
+
try {
|
|
2947
|
+
JSON.parse(out);
|
|
2948
|
+
return out;
|
|
2949
|
+
} catch {
|
|
2950
|
+
return void 0;
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2901
2953
|
function parseReplyItems(text) {
|
|
2902
2954
|
let parsed;
|
|
2903
2955
|
try {
|
|
2904
2956
|
parsed = JSON.parse(text);
|
|
2905
2957
|
} catch {
|
|
2906
|
-
|
|
2958
|
+
const repaired = repairUnescapedQuotes(text);
|
|
2959
|
+
if (repaired === void 0) throw new MalformedReplyError(text);
|
|
2960
|
+
parsed = JSON.parse(repaired);
|
|
2907
2961
|
}
|
|
2908
2962
|
if (!Array.isArray(parsed.items)) throw new MalformedReplyError(text);
|
|
2909
2963
|
return parsed.items;
|