glotto 2.9.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -55
- package/esm/cli.js +47 -39
- package/esm/deno.d.ts +0 -1
- package/esm/deno.js +1 -2
- package/esm/src/contants.d.ts +2 -2
- package/esm/src/contants.d.ts.map +1 -1
- package/esm/src/contants.js +22 -12
- package/esm/src/file.d.ts +2 -7
- package/esm/src/file.d.ts.map +1 -1
- package/esm/src/file.js +1 -108
- package/esm/src/providers/anthropic.d.ts +6 -11
- package/esm/src/providers/anthropic.d.ts.map +1 -1
- package/esm/src/providers/anthropic.js +14 -108
- package/esm/src/providers/gemini.d.ts +6 -11
- package/esm/src/providers/gemini.d.ts.map +1 -1
- package/esm/src/providers/gemini.js +13 -114
- package/esm/src/providers/openai.d.ts +6 -11
- package/esm/src/providers/openai.d.ts.map +1 -1
- package/esm/src/providers/openai.js +10 -109
- package/esm/src/translator.d.ts +8 -0
- package/esm/src/translator.d.ts.map +1 -0
- package/esm/src/translator.js +200 -0
- package/esm/src/types.d.ts +28 -11
- package/esm/src/types.d.ts.map +1 -1
- package/esm/src/utilites.d.ts +0 -6
- package/esm/src/utilites.d.ts.map +1 -1
- package/esm/src/utilites.js +18 -132
- package/package.json +1 -1
- package/script/cli.js +45 -37
- package/script/deno.d.ts +0 -1
- package/script/deno.js +1 -2
- package/script/src/contants.d.ts +2 -2
- package/script/src/contants.d.ts.map +1 -1
- package/script/src/contants.js +23 -13
- package/script/src/file.d.ts +2 -7
- package/script/src/file.d.ts.map +1 -1
- package/script/src/file.js +2 -114
- package/script/src/providers/anthropic.d.ts +6 -11
- package/script/src/providers/anthropic.d.ts.map +1 -1
- package/script/src/providers/anthropic.js +13 -107
- package/script/src/providers/gemini.d.ts +6 -11
- package/script/src/providers/gemini.d.ts.map +1 -1
- package/script/src/providers/gemini.js +12 -113
- package/script/src/providers/openai.d.ts +6 -11
- package/script/src/providers/openai.d.ts.map +1 -1
- package/script/src/providers/openai.js +9 -108
- package/script/src/translator.d.ts +8 -0
- package/script/src/translator.d.ts.map +1 -0
- package/script/src/translator.js +209 -0
- package/script/src/types.d.ts +28 -11
- package/script/src/types.d.ts.map +1 -1
- package/script/src/utilites.d.ts +0 -6
- package/script/src/utilites.d.ts.map +1 -1
- package/script/src/utilites.js +19 -136
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common16.d.ts +0 -23
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common16.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common16.js +0 -51
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common32.d.ts +0 -35
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common32.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common32.js +0 -192
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common64.d.ts +0 -35
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common64.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common64.js +0 -113
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common_detach.d.ts +0 -4
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common_detach.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common_detach.js +0 -13
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_types.d.ts +0 -9
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_types.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_types.js +0 -2
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_validate_binary_like.d.ts +0 -2
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_validate_binary_like.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_validate_binary_like.js +0 -26
- package/esm/deps/jsr.io/@std/encoding/1.0.10/ascii85.d.ts +0 -61
- package/esm/deps/jsr.io/@std/encoding/1.0.10/ascii85.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/ascii85.js +0 -152
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base32.d.ts +0 -40
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base32.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base32.js +0 -87
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base58.d.ts +0 -40
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base58.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base58.js +0 -131
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base64.d.ts +0 -40
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base64.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base64.js +0 -82
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base64url.d.ts +0 -40
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base64url.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base64url.js +0 -72
- package/esm/deps/jsr.io/@std/encoding/1.0.10/hex.d.ts +0 -39
- package/esm/deps/jsr.io/@std/encoding/1.0.10/hex.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/hex.js +0 -87
- package/esm/deps/jsr.io/@std/encoding/1.0.10/mod.d.ts +0 -98
- package/esm/deps/jsr.io/@std/encoding/1.0.10/mod.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/mod.js +0 -99
- package/esm/deps/jsr.io/@std/encoding/1.0.10/varint.d.ts +0 -120
- package/esm/deps/jsr.io/@std/encoding/1.0.10/varint.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/varint.js +0 -205
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common16.d.ts +0 -23
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common16.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common16.js +0 -57
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common32.d.ts +0 -35
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common32.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common32.js +0 -198
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common64.d.ts +0 -35
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common64.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common64.js +0 -119
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common_detach.d.ts +0 -4
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common_detach.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common_detach.js +0 -16
- package/script/deps/jsr.io/@std/encoding/1.0.10/_types.d.ts +0 -9
- package/script/deps/jsr.io/@std/encoding/1.0.10/_types.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/_types.js +0 -3
- package/script/deps/jsr.io/@std/encoding/1.0.10/_validate_binary_like.d.ts +0 -2
- package/script/deps/jsr.io/@std/encoding/1.0.10/_validate_binary_like.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/_validate_binary_like.js +0 -29
- package/script/deps/jsr.io/@std/encoding/1.0.10/ascii85.d.ts +0 -61
- package/script/deps/jsr.io/@std/encoding/1.0.10/ascii85.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/ascii85.js +0 -156
- package/script/deps/jsr.io/@std/encoding/1.0.10/base32.d.ts +0 -40
- package/script/deps/jsr.io/@std/encoding/1.0.10/base32.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/base32.js +0 -91
- package/script/deps/jsr.io/@std/encoding/1.0.10/base58.d.ts +0 -40
- package/script/deps/jsr.io/@std/encoding/1.0.10/base58.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/base58.js +0 -135
- package/script/deps/jsr.io/@std/encoding/1.0.10/base64.d.ts +0 -40
- package/script/deps/jsr.io/@std/encoding/1.0.10/base64.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/base64.js +0 -86
- package/script/deps/jsr.io/@std/encoding/1.0.10/base64url.d.ts +0 -40
- package/script/deps/jsr.io/@std/encoding/1.0.10/base64url.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/base64url.js +0 -76
- package/script/deps/jsr.io/@std/encoding/1.0.10/hex.d.ts +0 -39
- package/script/deps/jsr.io/@std/encoding/1.0.10/hex.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/hex.js +0 -91
- package/script/deps/jsr.io/@std/encoding/1.0.10/mod.d.ts +0 -98
- package/script/deps/jsr.io/@std/encoding/1.0.10/mod.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/mod.js +0 -115
- package/script/deps/jsr.io/@std/encoding/1.0.10/varint.d.ts +0 -120
- package/script/deps/jsr.io/@std/encoding/1.0.10/varint.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/varint.js +0 -211
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { logger } from './logger.js';
|
|
2
|
+
import { delay, formatBytes } from './utilites.js';
|
|
3
|
+
import { BASE_RETRY_DELAY_MS, INTER_BATCH_DELAY_MS, MAX_RETRIES } from './contants.js';
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
const byteSize = (s) => encoder.encode(s).byteLength;
|
|
6
|
+
export const extractLeaves = (data) => {
|
|
7
|
+
const out = [];
|
|
8
|
+
let nextId = 0;
|
|
9
|
+
const walk = (node, path) => {
|
|
10
|
+
if (node === null || typeof node !== 'object') {
|
|
11
|
+
const isString = typeof node === 'string';
|
|
12
|
+
out.push({
|
|
13
|
+
id: ++nextId,
|
|
14
|
+
path,
|
|
15
|
+
value: node,
|
|
16
|
+
translatable: isString && node.trim().length > 0,
|
|
17
|
+
});
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(node)) {
|
|
21
|
+
if (node.length === 0) {
|
|
22
|
+
out.push({ id: ++nextId, path, value: node, translatable: false });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
node.forEach((item, i) => walk(item, [...path, i]));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const entries = Object.entries(node);
|
|
29
|
+
if (entries.length === 0) {
|
|
30
|
+
out.push({ id: ++nextId, path, value: node, translatable: false });
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
for (const [k, v] of entries)
|
|
34
|
+
walk(v, [...path, k]);
|
|
35
|
+
};
|
|
36
|
+
walk(data, []);
|
|
37
|
+
return out;
|
|
38
|
+
};
|
|
39
|
+
const TAG_OPEN = (id) => `≪${id}≫`;
|
|
40
|
+
const TAG_CLOSE = (id) => `≪/${id}≫`;
|
|
41
|
+
const TAG_OVERHEAD_CHARS = 8;
|
|
42
|
+
const wrapEntry = (leaf) => `${TAG_OPEN(leaf.id)}${String(leaf.value)}${TAG_CLOSE(leaf.id)}`;
|
|
43
|
+
export const groupIntoBatches = (leaves, maxBytes) => {
|
|
44
|
+
const translatable = leaves.filter((l) => l.translatable);
|
|
45
|
+
const batches = [];
|
|
46
|
+
let current = [];
|
|
47
|
+
let currentSize = 0;
|
|
48
|
+
for (const leaf of translatable) {
|
|
49
|
+
const valueBytes = byteSize(String(leaf.value));
|
|
50
|
+
const idChars = String(leaf.id).length;
|
|
51
|
+
const overhead = TAG_OVERHEAD_CHARS + idChars * 2 + 1;
|
|
52
|
+
const itemSize = valueBytes + overhead;
|
|
53
|
+
if (current.length > 0 && currentSize + itemSize > maxBytes) {
|
|
54
|
+
batches.push({ index: batches.length, leaves: current, byteSize: currentSize });
|
|
55
|
+
current = [];
|
|
56
|
+
currentSize = 0;
|
|
57
|
+
}
|
|
58
|
+
current.push(leaf);
|
|
59
|
+
currentSize += itemSize;
|
|
60
|
+
}
|
|
61
|
+
if (current.length > 0) {
|
|
62
|
+
batches.push({ index: batches.length, leaves: current, byteSize: currentSize });
|
|
63
|
+
}
|
|
64
|
+
return batches;
|
|
65
|
+
};
|
|
66
|
+
export const buildBatchPrompt = (from, to, leaves) => {
|
|
67
|
+
const entries = leaves.map(wrapEntry).join('\n');
|
|
68
|
+
return `Translate each tagged entry below from ${from} to ${to}.
|
|
69
|
+
|
|
70
|
+
Tag format:
|
|
71
|
+
- Every entry is wrapped exactly as ≪N≫value≪/N≫, where N is the entry id (a positive integer).
|
|
72
|
+
- The opening marker is the character ≪ (U+226A), then the id, then ≫ (U+226B). The closing marker is ≪, /, the same id, then ≫.
|
|
73
|
+
- Copy these markers verbatim. Do not put spaces inside them. Do not change them to <<>>, «», <tag>, [n], or any other notation.
|
|
74
|
+
- The id must match the input id of the same entry — never renumber, merge, split, or reorder entries.
|
|
75
|
+
|
|
76
|
+
What to write back:
|
|
77
|
+
- One ≪N≫translated_value≪/N≫ block per input entry, in the same order, separated by single newlines.
|
|
78
|
+
- Translate only the text that sits between ≪N≫ and ≪/N≫.
|
|
79
|
+
- Preserve every variable ({{name}}, {name}, __VAR__, $t(...), %s, %d), HTML tag, markdown token, escape sequence, and special character inside the value.
|
|
80
|
+
- Output nothing else: no headings, no prose, no commentary, no code fences, no language labels.
|
|
81
|
+
|
|
82
|
+
Now translate the following entries:
|
|
83
|
+
${entries}`;
|
|
84
|
+
};
|
|
85
|
+
const TAG_PATTERNS = [
|
|
86
|
+
/≪\s*(\d+)\s*≫([\s\S]*?)≪\s*\/\s*\1\s*≫/g,
|
|
87
|
+
/<<\s*(\d+)\s*>>([\s\S]*?)<<\s*\/\s*\1\s*>>/g,
|
|
88
|
+
/«\s*(\d+)\s*»([\s\S]*?)«\s*\/\s*\1\s*»/g,
|
|
89
|
+
];
|
|
90
|
+
export const decodeResponse = (text) => {
|
|
91
|
+
const map = new Map();
|
|
92
|
+
for (const pattern of TAG_PATTERNS) {
|
|
93
|
+
for (const match of text.matchAll(pattern)) {
|
|
94
|
+
const id = parseInt(match[1], 10);
|
|
95
|
+
if (!map.has(id))
|
|
96
|
+
map.set(id, match[2].trim());
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return map;
|
|
100
|
+
};
|
|
101
|
+
const setPath = (root, path, value) => {
|
|
102
|
+
let node = root;
|
|
103
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
104
|
+
const key = path[i];
|
|
105
|
+
const nextKey = path[i + 1];
|
|
106
|
+
const container = node;
|
|
107
|
+
if (container[key] === undefined) {
|
|
108
|
+
container[key] = typeof nextKey === 'number' ? [] : {};
|
|
109
|
+
}
|
|
110
|
+
node = container[key];
|
|
111
|
+
}
|
|
112
|
+
node[path[path.length - 1]] = value;
|
|
113
|
+
};
|
|
114
|
+
export const reconstruct = (allLeaves, translations) => {
|
|
115
|
+
if (allLeaves.length === 0)
|
|
116
|
+
return {};
|
|
117
|
+
const firstStep = allLeaves[0].path[0];
|
|
118
|
+
if (firstStep === undefined) {
|
|
119
|
+
const only = allLeaves[0];
|
|
120
|
+
return only.translatable ? translations.get(only.id) ?? only.value : only.value;
|
|
121
|
+
}
|
|
122
|
+
const root = typeof firstStep === 'number' ? [] : {};
|
|
123
|
+
for (const leaf of allLeaves) {
|
|
124
|
+
const value = leaf.translatable && translations.has(leaf.id) ? translations.get(leaf.id) : leaf.value;
|
|
125
|
+
setPath(root, leaf.path, value);
|
|
126
|
+
}
|
|
127
|
+
return root;
|
|
128
|
+
};
|
|
129
|
+
export const runBatches = async (batches, translator, from, to, options) => {
|
|
130
|
+
const translations = new Map();
|
|
131
|
+
const failedIds = [];
|
|
132
|
+
for (let i = 0; i < batches.length; i++) {
|
|
133
|
+
const batch = batches[i];
|
|
134
|
+
const label = `[Batch ${batch.index + 1}/${batches.length}]`;
|
|
135
|
+
if (i > 0 && !options.noLimit) {
|
|
136
|
+
logger.info(`Waiting ${INTER_BATCH_DELAY_MS}ms before next batch (rate limit protection)...`);
|
|
137
|
+
await delay(INTER_BATCH_DELAY_MS);
|
|
138
|
+
}
|
|
139
|
+
let remaining = [...batch.leaves];
|
|
140
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
141
|
+
if (attempt > 0) {
|
|
142
|
+
const backoffMs = BASE_RETRY_DELAY_MS * Math.pow(2, attempt - 1);
|
|
143
|
+
logger.warn(`${label} Retry ${attempt}/${MAX_RETRIES} after ${backoffMs}ms backoff (${remaining.length} entries)...`);
|
|
144
|
+
await delay(backoffMs);
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
const prompt = buildBatchPrompt(from, to, remaining);
|
|
148
|
+
const response = await translator.translate(prompt);
|
|
149
|
+
if (!response || response.trim().length === 0) {
|
|
150
|
+
if (attempt === MAX_RETRIES) {
|
|
151
|
+
logger.error(`${label} Failed after ${MAX_RETRIES + 1} attempts: empty response`);
|
|
152
|
+
for (const leaf of remaining)
|
|
153
|
+
failedIds.push(leaf.id);
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
logger.warn(`${label} Attempt ${attempt + 1} returned empty response`);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const decoded = decodeResponse(response);
|
|
160
|
+
const stillMissing = [];
|
|
161
|
+
for (const leaf of remaining) {
|
|
162
|
+
const value = decoded.get(leaf.id);
|
|
163
|
+
if (!value || value.trim().length === 0) {
|
|
164
|
+
stillMissing.push(leaf);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
translations.set(leaf.id, value);
|
|
168
|
+
}
|
|
169
|
+
if (stillMissing.length === 0) {
|
|
170
|
+
logger.info(`${label} Translated successfully (${formatBytes(batch.byteSize)}, ${batch.leaves.length} entries)`);
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
if (attempt === MAX_RETRIES) {
|
|
174
|
+
logger.error(`${label} Failed after ${MAX_RETRIES + 1} attempts: ${stillMissing.length} entries missing`);
|
|
175
|
+
for (const leaf of stillMissing)
|
|
176
|
+
failedIds.push(leaf.id);
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
logger.warn(`${label} ${stillMissing.length}/${remaining.length} entries missing, will retry`);
|
|
180
|
+
remaining = stillMissing;
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
184
|
+
if (attempt === MAX_RETRIES) {
|
|
185
|
+
logger.error(`${label} Failed after ${MAX_RETRIES + 1} attempts: ${message}`);
|
|
186
|
+
for (const leaf of remaining)
|
|
187
|
+
failedIds.push(leaf.id);
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
logger.warn(`${label} Attempt ${attempt + 1} failed: ${message}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (failedIds.length > 0) {
|
|
195
|
+
const preview = failedIds.slice(0, 20).join(', ');
|
|
196
|
+
const more = failedIds.length > 20 ? `, …(+${failedIds.length - 20})` : '';
|
|
197
|
+
throw new Error(`Translation failed for ${failedIds.length} entry/entries (ids: ${preview}${more})`);
|
|
198
|
+
}
|
|
199
|
+
return translations;
|
|
200
|
+
};
|
package/esm/src/types.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export type Provider = 'gemini' | 'openai' | 'anthropic';
|
|
2
|
+
export type TranslateOptions = {
|
|
3
|
+
noLimit: boolean;
|
|
4
|
+
noTimeout: boolean;
|
|
5
|
+
};
|
|
2
6
|
export type TranslateArgs = {
|
|
3
7
|
key?: string;
|
|
4
8
|
provider?: string;
|
|
@@ -8,6 +12,9 @@ export type TranslateArgs = {
|
|
|
8
12
|
from?: string;
|
|
9
13
|
to?: string;
|
|
10
14
|
url?: string;
|
|
15
|
+
'no-limit'?: boolean;
|
|
16
|
+
'no-timeout'?: boolean;
|
|
17
|
+
'max-batch-size'?: string;
|
|
11
18
|
};
|
|
12
19
|
export type ValidatedTranslateArgs = {
|
|
13
20
|
key: string;
|
|
@@ -18,19 +25,29 @@ export type ValidatedTranslateArgs = {
|
|
|
18
25
|
from: string;
|
|
19
26
|
to: string;
|
|
20
27
|
url?: string;
|
|
28
|
+
noLimit: boolean;
|
|
29
|
+
noTimeout: boolean;
|
|
30
|
+
maxBatchBytes: number;
|
|
21
31
|
};
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
to: string;
|
|
26
|
-
translate(): Promise<string>;
|
|
32
|
+
export type JsonValue = string | number | boolean | null | JsonObject | JsonArray;
|
|
33
|
+
export interface JsonObject {
|
|
34
|
+
[key: string]: JsonValue;
|
|
27
35
|
}
|
|
28
|
-
export type
|
|
29
|
-
export type
|
|
30
|
-
export type
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
export type JsonArray = JsonValue[];
|
|
37
|
+
export type PathSegment = string | number;
|
|
38
|
+
export type Path = PathSegment[];
|
|
39
|
+
export type Leaf = {
|
|
40
|
+
id: number;
|
|
41
|
+
path: Path;
|
|
42
|
+
value: JsonValue;
|
|
43
|
+
translatable: boolean;
|
|
44
|
+
};
|
|
45
|
+
export type Batch = {
|
|
34
46
|
index: number;
|
|
47
|
+
leaves: Leaf[];
|
|
48
|
+
byteSize: number;
|
|
35
49
|
};
|
|
50
|
+
export interface TextTranslator {
|
|
51
|
+
translate(prompt: string): Promise<string>;
|
|
52
|
+
}
|
|
36
53
|
//# sourceMappingURL=types.d.ts.map
|
package/esm/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEzD,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEzD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,UAAU,GAAG,SAAS,CAAC;AAClF,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AACD,MAAM,MAAM,SAAS,GAAG,SAAS,EAAE,CAAC;AAEpC,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;AAC1C,MAAM,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;AAEjC,MAAM,MAAM,IAAI,GAAG;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,SAAS,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,IAAI,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC5C"}
|
package/esm/src/utilites.d.ts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import type { TranslateArgs, ValidatedTranslateArgs } from './types.js';
|
|
2
2
|
import type { Args } from '../deps/jsr.io/@std/cli/1.0.29/mod.js';
|
|
3
3
|
export declare const validateArgs: (args: Args<TranslateArgs>) => ValidatedTranslateArgs;
|
|
4
|
-
export declare const generatePrompts: (from: string, to: string) => {
|
|
5
|
-
systemPrompt: string;
|
|
6
|
-
userPrompt: string;
|
|
7
|
-
};
|
|
8
|
-
export declare const stripJsonMarkdown: (text: string) => string;
|
|
9
|
-
export declare const isValidJson: (value: string) => boolean;
|
|
10
4
|
export declare const formatBytes: (bytes: number) => string;
|
|
11
5
|
export declare const delay: (ms: number) => Promise<void>;
|
|
12
6
|
//# sourceMappingURL=utilites.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utilites.d.ts","sourceRoot":"","sources":["../../src/src/utilites.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,aAAa,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"utilites.d.ts","sourceRoot":"","sources":["../../src/src/utilites.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,aAAa,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uCAAuC,CAAC;AAGlE,eAAO,MAAM,YAAY,GAAI,MAAM,IAAI,CAAC,aAAa,CAAC,KAAG,sBA+BxD,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,KAAG,MAI3C,CAAC;AAEF,eAAO,MAAM,KAAK,GAAI,IAAI,MAAM,KAAG,OAAO,CAAC,IAAI,CAE9C,CAAC"}
|
package/esm/src/utilites.js
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
|
+
import { DEFAULT_MAX_BATCH_BYTES } from './contants.js';
|
|
1
2
|
export const validateArgs = (args) => {
|
|
2
|
-
if (!args.key)
|
|
3
|
+
if (!args.key)
|
|
3
4
|
throw new Error('AI Key is required');
|
|
4
|
-
|
|
5
|
-
if (!args.provider) {
|
|
5
|
+
if (!args.provider)
|
|
6
6
|
throw new Error('Provider parameter is required');
|
|
7
|
-
|
|
8
|
-
if (!args.input) {
|
|
7
|
+
if (!args.input)
|
|
9
8
|
throw new Error('Input parameter is required');
|
|
10
|
-
|
|
11
|
-
if (!args.output) {
|
|
9
|
+
if (!args.output)
|
|
12
10
|
throw new Error('Output parameter is required');
|
|
13
|
-
|
|
14
|
-
if (!args.from) {
|
|
11
|
+
if (!args.from)
|
|
15
12
|
throw new Error('Source language (from) parameter is required');
|
|
16
|
-
|
|
17
|
-
if (!args.to) {
|
|
13
|
+
if (!args.to)
|
|
18
14
|
throw new Error('Target language (to) parameter is required');
|
|
15
|
+
let maxBatchBytes = DEFAULT_MAX_BATCH_BYTES;
|
|
16
|
+
const rawMaxBatchSize = args['max-batch-size'];
|
|
17
|
+
if (rawMaxBatchSize !== undefined) {
|
|
18
|
+
const parsed = parseInt(rawMaxBatchSize, 10);
|
|
19
|
+
if (isNaN(parsed) || parsed <= 0) {
|
|
20
|
+
throw new Error('--max-batch-size must be a positive integer (value in KB, e.g. --max-batch-size 8)');
|
|
21
|
+
}
|
|
22
|
+
maxBatchBytes = parsed * 1024;
|
|
19
23
|
}
|
|
20
24
|
return {
|
|
21
25
|
key: args.key,
|
|
@@ -26,129 +30,11 @@ export const validateArgs = (args) => {
|
|
|
26
30
|
from: args.from,
|
|
27
31
|
to: args.to,
|
|
28
32
|
url: args.url,
|
|
33
|
+
noLimit: args['no-limit'] ?? false,
|
|
34
|
+
noTimeout: args['no-timeout'] ?? false,
|
|
35
|
+
maxBatchBytes,
|
|
29
36
|
};
|
|
30
37
|
};
|
|
31
|
-
export const generatePrompts = (from, to) => {
|
|
32
|
-
const systemPrompt = `You are a specialized i18next JSON translation expert. Your role is to translate content from ${from} to ${to} with these strict requirements:
|
|
33
|
-
|
|
34
|
-
1. COMPLETE TRANSLATION:
|
|
35
|
-
- Translate ALL text values comprehensively
|
|
36
|
-
- Double-check to ensure no text is left untranslated
|
|
37
|
-
- Pay special attention to arrays and nested objects to ensure everything is translated
|
|
38
|
-
- If unsure about any translation, provide the most accurate and natural translation possible
|
|
39
|
-
|
|
40
|
-
2. TRANSLATION QUALITY:
|
|
41
|
-
- Use natural, context-appropriate language
|
|
42
|
-
- Maintain consistent terminology throughout the translation
|
|
43
|
-
- Use formal language unless the source is clearly casual
|
|
44
|
-
- Preserve the exact meaning and tone of the original text
|
|
45
|
-
- For UI elements, use standard localized terms common in ${to} applications
|
|
46
|
-
|
|
47
|
-
3. STRUCTURAL PRESERVATION:
|
|
48
|
-
- Keep all JSON structure and keys exactly as they are
|
|
49
|
-
- Maintain all variables and interpolation patterns ({{name}}, __VARIABLE__, $t(), etc.)
|
|
50
|
-
- Preserve all HTML tags and markdown formatting
|
|
51
|
-
- Keep all whitespace, nesting, and formatting intact
|
|
52
|
-
|
|
53
|
-
4. VALIDATION:
|
|
54
|
-
- Return only valid JSON
|
|
55
|
-
- Verify that all text is translated
|
|
56
|
-
- Ensure no source language text remains
|
|
57
|
-
- Confirm all arrays and nested objects are fully translated`;
|
|
58
|
-
const userPrompt = `Please translate this i18next JSON file with these specific requirements:
|
|
59
|
-
|
|
60
|
-
1. THOROUGH TRANSLATION:
|
|
61
|
-
- Translate every single text value from ${from} to ${to}
|
|
62
|
-
- Pay special attention to arrays and nested objects
|
|
63
|
-
- Verify no text is left in ${from}
|
|
64
|
-
- Double-check all translations for completeness
|
|
65
|
-
|
|
66
|
-
2. PRESERVE STRUCTURE:
|
|
67
|
-
- Keep all keys unchanged (e.g. "button.submit")
|
|
68
|
-
- Maintain all variables: {{name}}, __VAR__, $t()
|
|
69
|
-
- Preserve HTML tags and markdown
|
|
70
|
-
- Keep all special characters
|
|
71
|
-
- Maintain exact JSON structure
|
|
72
|
-
|
|
73
|
-
3. QUALITY REQUIREMENTS:
|
|
74
|
-
- Use natural ${to} language
|
|
75
|
-
- Maintain consistent terminology
|
|
76
|
-
- Use formal language unless source is casual
|
|
77
|
-
- Ensure translations match the context
|
|
78
|
-
- Use standard ${to} UI terminology for interface elements
|
|
79
|
-
|
|
80
|
-
4. OUTPUT:
|
|
81
|
-
- Return only the translated JSON
|
|
82
|
-
- No explanations or comments
|
|
83
|
-
- No additional text
|
|
84
|
-
- No formatting changes
|
|
85
|
-
- Must be valid JSON`;
|
|
86
|
-
return { systemPrompt, userPrompt };
|
|
87
|
-
};
|
|
88
|
-
export const stripJsonMarkdown = (text) => {
|
|
89
|
-
const trimmed = text.trim();
|
|
90
|
-
// Extract from code fence if present (handles surrounding text too)
|
|
91
|
-
const fenceMatch = trimmed.match(/```(?:\w+)?\s*\n?([\s\S]*?)\n?```/);
|
|
92
|
-
if (fenceMatch) {
|
|
93
|
-
const candidate = fenceMatch[1].trim();
|
|
94
|
-
if (candidate.startsWith('{') || candidate.startsWith('[')) {
|
|
95
|
-
return candidate;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
// Find outermost JSON structure by tracking bracket depth,
|
|
99
|
-
// correctly ignoring brackets inside strings and escape sequences
|
|
100
|
-
const firstBrace = trimmed.indexOf('{');
|
|
101
|
-
const firstBracket = trimmed.indexOf('[');
|
|
102
|
-
if (firstBrace === -1 && firstBracket === -1)
|
|
103
|
-
return trimmed;
|
|
104
|
-
let startIndex;
|
|
105
|
-
let openChar;
|
|
106
|
-
let closeChar;
|
|
107
|
-
if (firstBrace === -1 || (firstBracket !== -1 && firstBracket < firstBrace)) {
|
|
108
|
-
startIndex = firstBracket;
|
|
109
|
-
openChar = '[';
|
|
110
|
-
closeChar = ']';
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
startIndex = firstBrace;
|
|
114
|
-
openChar = '{';
|
|
115
|
-
closeChar = '}';
|
|
116
|
-
}
|
|
117
|
-
let depth = 0;
|
|
118
|
-
let inString = false;
|
|
119
|
-
let escaped = false;
|
|
120
|
-
for (let i = startIndex; i < trimmed.length; i++) {
|
|
121
|
-
const char = trimmed[i];
|
|
122
|
-
if (escaped) {
|
|
123
|
-
escaped = false;
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
if (char === '\\' && inString) {
|
|
127
|
-
escaped = true;
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
if (char === '"') {
|
|
131
|
-
inString = !inString;
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
if (inString)
|
|
135
|
-
continue;
|
|
136
|
-
if (char === openChar)
|
|
137
|
-
depth++;
|
|
138
|
-
else if (char === closeChar && --depth === 0)
|
|
139
|
-
return trimmed.slice(startIndex, i + 1);
|
|
140
|
-
}
|
|
141
|
-
return trimmed;
|
|
142
|
-
};
|
|
143
|
-
export const isValidJson = (value) => {
|
|
144
|
-
try {
|
|
145
|
-
JSON.parse(value);
|
|
146
|
-
return true;
|
|
147
|
-
}
|
|
148
|
-
catch {
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
38
|
export const formatBytes = (bytes) => {
|
|
153
39
|
if (bytes < 1024)
|
|
154
40
|
return `${bytes} B`;
|
package/package.json
CHANGED
package/script/cli.js
CHANGED
|
@@ -42,6 +42,7 @@ const dntShim = __importStar(require("./_dnt.shims.js"));
|
|
|
42
42
|
const unstable_spinner_js_1 = require("./deps/jsr.io/@std/cli/1.0.29/unstable_spinner.js");
|
|
43
43
|
const mod_js_1 = require("./deps/jsr.io/@std/cli/1.0.29/mod.js");
|
|
44
44
|
const file_js_1 = require("./src/file.js");
|
|
45
|
+
const translator_js_1 = require("./src/translator.js");
|
|
45
46
|
const contants_js_1 = require("./src/contants.js");
|
|
46
47
|
const utilites_js_1 = require("./src/utilites.js");
|
|
47
48
|
const logger_js_1 = require("./src/logger.js");
|
|
@@ -50,11 +51,23 @@ const gemini_js_1 = __importDefault(require("./src/providers/gemini.js"));
|
|
|
50
51
|
const openai_js_1 = __importDefault(require("./src/providers/openai.js"));
|
|
51
52
|
const anthropic_js_1 = __importDefault(require("./src/providers/anthropic.js"));
|
|
52
53
|
const spinner = new unstable_spinner_js_1.Spinner({ message: 'AI Thinks...', color: 'cyan' });
|
|
54
|
+
const createTranslator = (args, options) => {
|
|
55
|
+
switch (args.provider) {
|
|
56
|
+
case 'gemini':
|
|
57
|
+
return new gemini_js_1.default(args.key, args.model, options);
|
|
58
|
+
case 'openai':
|
|
59
|
+
return new openai_js_1.default(args.key, args.url, args.model, options);
|
|
60
|
+
case 'anthropic':
|
|
61
|
+
return new anthropic_js_1.default(args.key, args.url, args.model, options);
|
|
62
|
+
default:
|
|
63
|
+
throw new Error(`Unknown provider: ${args.provider}`);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
53
66
|
async function main() {
|
|
54
67
|
try {
|
|
55
68
|
const args = (0, mod_js_1.parseArgs)(dntShim.Deno.args, {
|
|
56
|
-
string: ['key', 'provider', 'model', 'input', 'output', 'from', 'to', 'url'],
|
|
57
|
-
boolean: ['help', 'version'],
|
|
69
|
+
string: ['key', 'provider', 'model', 'input', 'output', 'from', 'to', 'url', 'max-batch-size'],
|
|
70
|
+
boolean: ['help', 'version', 'no-limit', 'no-timeout'],
|
|
58
71
|
alias: {
|
|
59
72
|
provider: 'p',
|
|
60
73
|
model: 'm',
|
|
@@ -71,8 +84,7 @@ async function main() {
|
|
|
71
84
|
const help = args.help || dntShim.Deno.args.length === 0;
|
|
72
85
|
const version = args.version;
|
|
73
86
|
if (version) {
|
|
74
|
-
|
|
75
|
-
logger_js_1.logger.info('Glotto version: ' + VERSION);
|
|
87
|
+
logger_js_1.logger.info('Glotto version: ' + deno_js_1.default.version);
|
|
76
88
|
dntShim.Deno.exit(0);
|
|
77
89
|
}
|
|
78
90
|
if (help) {
|
|
@@ -81,49 +93,45 @@ async function main() {
|
|
|
81
93
|
}
|
|
82
94
|
const validatedArgs = (0, utilites_js_1.validateArgs)(args);
|
|
83
95
|
const fileContent = await (0, file_js_1.getImportJson)(validatedArgs.input);
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
const
|
|
96
|
+
const allLeaves = (0, translator_js_1.extractLeaves)(fileContent);
|
|
97
|
+
const translatableLeaves = allLeaves.filter((leaf) => leaf.translatable);
|
|
98
|
+
const batches = (0, translator_js_1.groupIntoBatches)(allLeaves, validatedArgs.maxBatchBytes);
|
|
99
|
+
const totalBytes = batches.reduce((sum, b) => sum + b.byteSize, 0);
|
|
88
100
|
logger_js_1.logger.info('Provider: ', validatedArgs.provider);
|
|
89
101
|
logger_js_1.logger.info('Input: ', validatedArgs.input);
|
|
90
102
|
logger_js_1.logger.info('Output: ', validatedArgs.output);
|
|
91
103
|
logger_js_1.logger.info('From: ', validatedArgs.from);
|
|
92
104
|
logger_js_1.logger.info('To: ', validatedArgs.to);
|
|
93
|
-
if (validatedArgs.model)
|
|
105
|
+
if (validatedArgs.model)
|
|
94
106
|
logger_js_1.logger.info('Model: ', validatedArgs.model);
|
|
95
|
-
|
|
96
|
-
if (validatedArgs.url) {
|
|
107
|
+
if (validatedArgs.url)
|
|
97
108
|
logger_js_1.logger.info('URL: ', validatedArgs.url);
|
|
109
|
+
if (validatedArgs.noLimit)
|
|
110
|
+
logger_js_1.logger.info('Rate limit protection: disabled (--no-limit)');
|
|
111
|
+
if (validatedArgs.noTimeout)
|
|
112
|
+
logger_js_1.logger.info('Request timeout: disabled (--no-timeout)');
|
|
113
|
+
if (validatedArgs.maxBatchBytes !== contants_js_1.DEFAULT_MAX_BATCH_BYTES) {
|
|
114
|
+
logger_js_1.logger.info(`Max batch size: ${(0, utilites_js_1.formatBytes)(validatedArgs.maxBatchBytes)}`);
|
|
98
115
|
}
|
|
99
|
-
logger_js_1.logger.info(`Total: ${
|
|
100
|
-
for (const
|
|
101
|
-
logger_js_1.logger.info(`
|
|
116
|
+
logger_js_1.logger.info(`Total: ${translatableLeaves.length} translatable entries (of ${allLeaves.length} leaves), ${(0, utilites_js_1.formatBytes)(totalBytes)}, split into ${batches.length} batch(es)`);
|
|
117
|
+
for (const batch of batches) {
|
|
118
|
+
logger_js_1.logger.info(` Batch ${batch.index + 1}: ${batch.leaves.length} entries, ${(0, utilites_js_1.formatBytes)(batch.byteSize)}`);
|
|
102
119
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const gemini = new gemini_js_1.default(validatedArgs.key, chunks, validatedArgs.from, validatedArgs.to, validatedArgs.model);
|
|
108
|
-
result = await gemini.translate();
|
|
109
|
-
break;
|
|
110
|
-
}
|
|
111
|
-
case 'openai': {
|
|
112
|
-
const openai = new openai_js_1.default(validatedArgs.key, chunks, validatedArgs.from, validatedArgs.to, validatedArgs.url, validatedArgs.model);
|
|
113
|
-
result = await openai.translate();
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
case 'anthropic': {
|
|
117
|
-
const anthropic = new anthropic_js_1.default(validatedArgs.key, chunks, validatedArgs.from, validatedArgs.to, validatedArgs.url, validatedArgs.model);
|
|
118
|
-
result = await anthropic.translate();
|
|
119
|
-
break;
|
|
120
|
-
}
|
|
121
|
-
default: {
|
|
122
|
-
logger_js_1.logger.warn('Provider not found');
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
120
|
+
if (batches.length === 0) {
|
|
121
|
+
logger_js_1.logger.warn('No translatable entries found, copying input to output');
|
|
122
|
+
await (0, file_js_1.writeOutput)((0, file_js_1.resolvePath)(validatedArgs.output), JSON.stringify(fileContent, null, 2));
|
|
123
|
+
dntShim.Deno.exit(0);
|
|
125
124
|
}
|
|
126
|
-
|
|
125
|
+
const translateOptions = {
|
|
126
|
+
noLimit: validatedArgs.noLimit,
|
|
127
|
+
noTimeout: validatedArgs.noTimeout,
|
|
128
|
+
};
|
|
129
|
+
const translator = createTranslator(validatedArgs, translateOptions);
|
|
130
|
+
spinner.start();
|
|
131
|
+
const translations = await (0, translator_js_1.runBatches)(batches, translator, validatedArgs.from, validatedArgs.to, translateOptions);
|
|
132
|
+
const result = (0, translator_js_1.reconstruct)(allLeaves, translations);
|
|
133
|
+
const outputPath = (0, file_js_1.resolvePath)(validatedArgs.output);
|
|
134
|
+
await (0, file_js_1.writeOutput)(outputPath, JSON.stringify(result, null, 2));
|
|
127
135
|
spinner.stop();
|
|
128
136
|
logger_js_1.logger.success('Translation completed');
|
|
129
137
|
}
|
package/script/deno.d.ts
CHANGED
package/script/deno.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = {
|
|
4
4
|
"name": "@ibodev/glotto",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "3.0.0",
|
|
6
6
|
"exports": "./cli.ts",
|
|
7
7
|
"lock": false,
|
|
8
8
|
"nodeModulesDir": "auto",
|
|
@@ -25,7 +25,6 @@ exports.default = {
|
|
|
25
25
|
"@google/genai": "npm:@google/genai@^1.52.0",
|
|
26
26
|
"@openai/openai": "npm:openai@^6.36.0",
|
|
27
27
|
"@std/cli": "jsr:@std/cli@^1.0.29",
|
|
28
|
-
"@std/encoding": "jsr:@std/encoding@^1.0.10",
|
|
29
28
|
"@std/path": "jsr:@std/path@^1.1.4",
|
|
30
29
|
"consola": "npm:consola@^3.4.2"
|
|
31
30
|
},
|
package/script/src/contants.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Provider } from './types.js';
|
|
2
2
|
export declare const DEFAULT_PROVIDER: Provider;
|
|
3
3
|
export declare const DEFAULT_MODELS: Record<Provider, string>;
|
|
4
|
-
export declare const
|
|
4
|
+
export declare const DEFAULT_MAX_BATCH_BYTES: 12000;
|
|
5
5
|
export declare const MAX_RETRIES: 3;
|
|
6
6
|
export declare const BASE_RETRY_DELAY_MS: 2000;
|
|
7
|
-
export declare const
|
|
7
|
+
export declare const INTER_BATCH_DELAY_MS: 1500;
|
|
8
8
|
export declare const HELP_TEXT: string;
|
|
9
9
|
//# sourceMappingURL=contants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contants.d.ts","sourceRoot":"","sources":["../../src/src/contants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,eAAO,MAAM,gBAAgB,EAAE,QAAmB,CAAC;AAEnD,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAInD,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAG,KAAe,CAAC;AAEvD,eAAO,MAAM,WAAW,EAAG,CAAU,CAAC;AAEtC,eAAO,MAAM,mBAAmB,EAAG,IAAc,CAAC;AAElD,eAAO,MAAM,oBAAoB,EAAG,IAAc,CAAC;AAEnD,eAAO,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"contants.d.ts","sourceRoot":"","sources":["../../src/src/contants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,eAAO,MAAM,gBAAgB,EAAE,QAAmB,CAAC;AAEnD,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAInD,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAG,KAAe,CAAC;AAEvD,eAAO,MAAM,WAAW,EAAG,CAAU,CAAC;AAEtC,eAAO,MAAM,mBAAmB,EAAG,IAAc,CAAC;AAElD,eAAO,MAAM,oBAAoB,EAAG,IAAc,CAAC;AAEnD,eAAO,MAAM,SAAS,QAgCrB,CAAC"}
|