glotto 2.9.0 → 3.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/README.md +150 -54
- package/esm/cli.js +155 -43
- package/esm/deno.d.ts +5 -1
- package/esm/deno.js +18 -7
- package/esm/src/config.d.ts +4 -0
- package/esm/src/config.d.ts.map +1 -0
- package/esm/src/config.js +95 -0
- package/esm/src/contants.d.ts +6 -2
- package/esm/src/contants.d.ts.map +1 -1
- package/esm/src/contants.js +34 -15
- package/esm/src/diff.d.ts +4 -0
- package/esm/src/diff.d.ts.map +1 -0
- package/esm/src/diff.js +53 -0
- package/esm/src/file.d.ts +5 -9
- package/esm/src/file.d.ts.map +1 -1
- package/esm/src/file.js +14 -103
- 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 +21 -107
- 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 +20 -113
- 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 +17 -108
- package/esm/src/translator.d.ts +15 -0
- package/esm/src/translator.d.ts.map +1 -0
- package/esm/src/translator.js +284 -0
- package/esm/src/types.d.ts +58 -13
- package/esm/src/types.d.ts.map +1 -1
- package/esm/src/utilites.d.ts +3 -10
- package/esm/src/utilites.d.ts.map +1 -1
- package/esm/src/utilites.js +41 -131
- package/package.json +20 -6
- package/schema/glotto.schema.json +87 -0
- package/script/cli.js +153 -41
- package/script/deno.d.ts +5 -1
- package/script/deno.js +18 -7
- package/script/src/config.d.ts +4 -0
- package/script/src/config.d.ts.map +1 -0
- package/script/src/config.js +132 -0
- package/script/src/contants.d.ts +6 -2
- package/script/src/contants.d.ts.map +1 -1
- package/script/src/contants.js +35 -16
- package/script/src/diff.d.ts +4 -0
- package/script/src/diff.d.ts.map +1 -0
- package/script/src/diff.js +57 -0
- package/script/src/file.d.ts +5 -9
- package/script/src/file.d.ts.map +1 -1
- package/script/src/file.js +19 -113
- 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 +20 -106
- 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 +19 -112
- 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 +16 -107
- package/script/src/translator.d.ts +15 -0
- package/script/src/translator.d.ts.map +1 -0
- package/script/src/translator.js +294 -0
- package/script/src/types.d.ts +58 -13
- package/script/src/types.d.ts.map +1 -1
- package/script/src/utilites.d.ts +3 -10
- package/script/src/utilites.d.ts.map +1 -1
- package/script/src/utilites.js +44 -138
- 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
package/script/cli.js
CHANGED
|
@@ -42,6 +42,9 @@ 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");
|
|
46
|
+
const diff_js_1 = require("./src/diff.js");
|
|
47
|
+
const config_js_1 = require("./src/config.js");
|
|
45
48
|
const contants_js_1 = require("./src/contants.js");
|
|
46
49
|
const utilites_js_1 = require("./src/utilites.js");
|
|
47
50
|
const logger_js_1 = require("./src/logger.js");
|
|
@@ -50,11 +53,110 @@ const gemini_js_1 = __importDefault(require("./src/providers/gemini.js"));
|
|
|
50
53
|
const openai_js_1 = __importDefault(require("./src/providers/openai.js"));
|
|
51
54
|
const anthropic_js_1 = __importDefault(require("./src/providers/anthropic.js"));
|
|
52
55
|
const spinner = new unstable_spinner_js_1.Spinner({ message: 'AI Thinks...', color: 'cyan' });
|
|
56
|
+
function createTranslator(args, options) {
|
|
57
|
+
switch (args.provider) {
|
|
58
|
+
case 'gemini':
|
|
59
|
+
return new gemini_js_1.default(args.key, args.model, options);
|
|
60
|
+
case 'openai':
|
|
61
|
+
return new openai_js_1.default(args.key, args.url, args.model, options);
|
|
62
|
+
case 'anthropic':
|
|
63
|
+
return new anthropic_js_1.default(args.key, args.url, args.model, options);
|
|
64
|
+
default:
|
|
65
|
+
throw new Error(`Unknown provider: ${args.provider}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function printBanner() {
|
|
69
|
+
logger_js_1.logger.box(`Glotto AI Translator v${deno_js_1.default.version}\n${contants_js_1.GITHUB_REPO_URL}`);
|
|
70
|
+
}
|
|
71
|
+
function printStats(args, perTarget) {
|
|
72
|
+
const totalInput = perTarget.reduce((sum, t) => sum + t.usage.inputTokens, 0);
|
|
73
|
+
const totalOutput = perTarget.reduce((sum, t) => sum + t.usage.outputTokens, 0);
|
|
74
|
+
const totalCalls = perTarget.reduce((sum, t) => sum + t.calls, 0);
|
|
75
|
+
const totalBytes = perTarget.reduce((sum, t) => sum + t.bytes, 0);
|
|
76
|
+
const totalTranslated = perTarget.reduce((sum, t) => sum + t.translatedCount, 0);
|
|
77
|
+
const lines = [];
|
|
78
|
+
lines.push(`Provider: ${args.provider}${args.model ? ` (${args.model})` : ''}`);
|
|
79
|
+
lines.push(`Targets: ${perTarget.length}`);
|
|
80
|
+
lines.push('');
|
|
81
|
+
for (const t of perTarget) {
|
|
82
|
+
const mode = t.incrementalApplied ? ' [incremental]' : '';
|
|
83
|
+
lines.push(`→ ${t.to} (${t.output})${mode}: ${t.translatedCount}/${t.fullCount} entries, ${t.batchCount} batch(es), ${(0, utilites_js_1.formatBytes)(t.bytes)}, ${t.calls} call(s)`);
|
|
84
|
+
lines.push(` tokens — in: ${t.usage.inputTokens}, out: ${t.usage.outputTokens}`);
|
|
85
|
+
}
|
|
86
|
+
lines.push('');
|
|
87
|
+
lines.push(`Total: ${totalTranslated} entries translated, ${totalCalls} call(s), ${(0, utilites_js_1.formatBytes)(totalBytes)}`);
|
|
88
|
+
lines.push(`Total tokens — in: ${totalInput}, out: ${totalOutput}, sum: ${totalInput + totalOutput}`);
|
|
89
|
+
logger_js_1.logger.box(lines.join('\n'));
|
|
90
|
+
}
|
|
91
|
+
async function translateForTarget(validatedArgs, fileContent, allLeaves, to, outputRel, translator, translateOptions, targetIndex, totalTargets) {
|
|
92
|
+
const outputPath = (0, file_js_1.resolvePath)(outputRel);
|
|
93
|
+
const targetLabel = `[Target ${targetIndex + 1}/${totalTargets}: ${to}]`;
|
|
94
|
+
logger_js_1.logger.info(`${targetLabel} → ${outputRel}`);
|
|
95
|
+
const translatableLeaves = allLeaves.filter((leaf) => leaf.translatable);
|
|
96
|
+
let leavesToTranslate = translatableLeaves;
|
|
97
|
+
let existingTarget = null;
|
|
98
|
+
let incrementalApplied = false;
|
|
99
|
+
if (validatedArgs.incremental) {
|
|
100
|
+
existingTarget = await (0, file_js_1.readJsonIfExists)(outputPath);
|
|
101
|
+
if (existingTarget !== null) {
|
|
102
|
+
leavesToTranslate = (0, diff_js_1.findMissingLeaves)(allLeaves, existingTarget);
|
|
103
|
+
incrementalApplied = true;
|
|
104
|
+
logger_js_1.logger.info(`${targetLabel} Incremental: ${leavesToTranslate.length}/${translatableLeaves.length} entries missing in existing target`);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
logger_js_1.logger.info(`${targetLabel} Incremental: target file not found, doing full translation`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (leavesToTranslate.length === 0) {
|
|
111
|
+
logger_js_1.logger.info(`${targetLabel} Nothing to translate, writing existing/source content`);
|
|
112
|
+
const content = existingTarget !== null ? existingTarget : fileContent;
|
|
113
|
+
await (0, file_js_1.writeOutput)(outputPath, JSON.stringify(content, null, 2));
|
|
114
|
+
return {
|
|
115
|
+
to,
|
|
116
|
+
output: outputRel,
|
|
117
|
+
fullCount: translatableLeaves.length,
|
|
118
|
+
translatedCount: 0,
|
|
119
|
+
batchCount: 0,
|
|
120
|
+
bytes: 0,
|
|
121
|
+
calls: 0,
|
|
122
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
123
|
+
incrementalApplied,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const batches = (0, translator_js_1.groupIntoBatches)(leavesToTranslate, validatedArgs.maxBatchBytes);
|
|
127
|
+
const totalBytes = batches.reduce((sum, b) => sum + b.byteSize, 0);
|
|
128
|
+
logger_js_1.logger.info(`${targetLabel} ${leavesToTranslate.length} translatable entries, ${(0, utilites_js_1.formatBytes)(totalBytes)}, split into ${batches.length} batch(es)`);
|
|
129
|
+
for (const batch of batches) {
|
|
130
|
+
logger_js_1.logger.info(` Batch ${batch.index + 1}: ${batch.leaves.length} entries, ${(0, utilites_js_1.formatBytes)(batch.byteSize)}`);
|
|
131
|
+
}
|
|
132
|
+
spinner.start();
|
|
133
|
+
const result = await (0, translator_js_1.runBatches)(batches, translator, validatedArgs.from, to, translateOptions);
|
|
134
|
+
spinner.stop();
|
|
135
|
+
let finalContent;
|
|
136
|
+
if (incrementalApplied && existingTarget !== null) {
|
|
137
|
+
finalContent = (0, diff_js_1.mergeTranslations)(existingTarget, allLeaves, result.translations);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
finalContent = (0, translator_js_1.reconstruct)(allLeaves, result.translations);
|
|
141
|
+
}
|
|
142
|
+
await (0, file_js_1.writeOutput)(outputPath, JSON.stringify(finalContent, null, 2));
|
|
143
|
+
return {
|
|
144
|
+
to,
|
|
145
|
+
output: outputRel,
|
|
146
|
+
fullCount: translatableLeaves.length,
|
|
147
|
+
translatedCount: result.translations.size,
|
|
148
|
+
batchCount: batches.length,
|
|
149
|
+
bytes: totalBytes,
|
|
150
|
+
calls: result.calls,
|
|
151
|
+
usage: result.usage,
|
|
152
|
+
incrementalApplied,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
53
155
|
async function main() {
|
|
54
156
|
try {
|
|
55
157
|
const args = (0, mod_js_1.parseArgs)(dntShim.Deno.args, {
|
|
56
|
-
string: ['key', 'provider', 'model', 'input', 'output', 'from', 'to', 'url'],
|
|
57
|
-
boolean: ['help', 'version'],
|
|
158
|
+
string: ['key', 'provider', 'model', 'input', 'output', 'from', 'to', 'url', 'max-batch-size', 'config'],
|
|
159
|
+
boolean: ['help', 'version', 'no-limit', 'no-timeout', 'stats', 'incremental'],
|
|
58
160
|
alias: {
|
|
59
161
|
provider: 'p',
|
|
60
162
|
model: 'm',
|
|
@@ -66,75 +168,85 @@ async function main() {
|
|
|
66
168
|
help: 'h',
|
|
67
169
|
version: 'v',
|
|
68
170
|
},
|
|
69
|
-
default: { provider: contants_js_1.DEFAULT_PROVIDER },
|
|
70
171
|
});
|
|
71
172
|
const help = args.help || dntShim.Deno.args.length === 0;
|
|
72
173
|
const version = args.version;
|
|
73
174
|
if (version) {
|
|
74
|
-
|
|
75
|
-
logger_js_1.logger.info('Glotto version: ' + VERSION);
|
|
175
|
+
logger_js_1.logger.info('Glotto version: ' + deno_js_1.default.version);
|
|
76
176
|
dntShim.Deno.exit(0);
|
|
77
177
|
}
|
|
78
178
|
if (help) {
|
|
179
|
+
printBanner();
|
|
79
180
|
logger_js_1.logger.box(contants_js_1.HELP_TEXT);
|
|
80
181
|
dntShim.Deno.exit(0);
|
|
81
182
|
}
|
|
82
|
-
|
|
183
|
+
printBanner();
|
|
184
|
+
const config = await (0, config_js_1.loadConfig)(args.config);
|
|
185
|
+
const merged = (0, config_js_1.applyConfig)(args, config, dntShim.Deno.args);
|
|
186
|
+
if (!merged.provider) {
|
|
187
|
+
merged.provider = contants_js_1.DEFAULT_PROVIDER;
|
|
188
|
+
}
|
|
189
|
+
const validatedArgs = (0, utilites_js_1.validateArgs)(merged);
|
|
83
190
|
const fileContent = await (0, file_js_1.getImportJson)(validatedArgs.input);
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
const totalKeys = chunks.reduce((sum, c) => sum + c.keyCount, 0);
|
|
87
|
-
const outputPath = (0, file_js_1.resolvePath)(validatedArgs.output);
|
|
191
|
+
const allLeaves = (0, translator_js_1.extractLeaves)(fileContent);
|
|
192
|
+
const translatableLeaves = allLeaves.filter((leaf) => leaf.translatable);
|
|
88
193
|
logger_js_1.logger.info('Provider: ', validatedArgs.provider);
|
|
89
194
|
logger_js_1.logger.info('Input: ', validatedArgs.input);
|
|
90
|
-
logger_js_1.logger.info('
|
|
195
|
+
logger_js_1.logger.info('Targets: ', validatedArgs.to.map((to, i) => `${to} → ${validatedArgs.output[i]}`).join(', '));
|
|
91
196
|
logger_js_1.logger.info('From: ', validatedArgs.from);
|
|
92
|
-
logger_js_1.logger.info('To: ', validatedArgs.to);
|
|
93
197
|
if (validatedArgs.model) {
|
|
94
198
|
logger_js_1.logger.info('Model: ', validatedArgs.model);
|
|
95
199
|
}
|
|
96
200
|
if (validatedArgs.url) {
|
|
97
201
|
logger_js_1.logger.info('URL: ', validatedArgs.url);
|
|
98
202
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
logger_js_1.logger.info(` Chunk ${chunk.index + 1}: ${chunk.keyCount} keys, ${(0, utilites_js_1.formatBytes)(chunk.byteSize)}`);
|
|
203
|
+
if (validatedArgs.noLimit) {
|
|
204
|
+
logger_js_1.logger.info('Rate limit protection: disabled (--no-limit)');
|
|
102
205
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
default: {
|
|
122
|
-
logger_js_1.logger.warn('Provider not found');
|
|
123
|
-
break;
|
|
206
|
+
if (validatedArgs.noTimeout) {
|
|
207
|
+
logger_js_1.logger.info('Request timeout: disabled (--no-timeout)');
|
|
208
|
+
}
|
|
209
|
+
if (validatedArgs.incremental) {
|
|
210
|
+
logger_js_1.logger.info('Incremental mode: enabled (--incremental)');
|
|
211
|
+
}
|
|
212
|
+
if (validatedArgs.stats) {
|
|
213
|
+
logger_js_1.logger.info('Stats: enabled (--stats)');
|
|
214
|
+
}
|
|
215
|
+
if (validatedArgs.maxBatchBytes !== contants_js_1.DEFAULT_MAX_BATCH_BYTES) {
|
|
216
|
+
logger_js_1.logger.info(`Max batch size: ${(0, utilites_js_1.formatBytes)(validatedArgs.maxBatchBytes)}`);
|
|
217
|
+
}
|
|
218
|
+
logger_js_1.logger.info(`Source: ${translatableLeaves.length} translatable entries (of ${allLeaves.length} leaves)`);
|
|
219
|
+
if (translatableLeaves.length === 0 && !validatedArgs.incremental) {
|
|
220
|
+
logger_js_1.logger.warn('No translatable entries found, copying input to output(s)');
|
|
221
|
+
for (const outputRel of validatedArgs.output) {
|
|
222
|
+
await (0, file_js_1.writeOutput)((0, file_js_1.resolvePath)(outputRel), JSON.stringify(fileContent, null, 2));
|
|
124
223
|
}
|
|
224
|
+
logger_js_1.logger.success('Translation completed');
|
|
225
|
+
logger_js_1.logger.info(`★ Glotto faydalı olduysa GitHub'da yıldızlamayı unutma: ${contants_js_1.GITHUB_REPO_URL}`);
|
|
226
|
+
dntShim.Deno.exit(0);
|
|
227
|
+
}
|
|
228
|
+
const translateOptions = {
|
|
229
|
+
noLimit: validatedArgs.noLimit,
|
|
230
|
+
noTimeout: validatedArgs.noTimeout,
|
|
231
|
+
};
|
|
232
|
+
const translator = createTranslator(validatedArgs, translateOptions);
|
|
233
|
+
const perTarget = [];
|
|
234
|
+
for (let i = 0; i < validatedArgs.to.length; i++) {
|
|
235
|
+
const stat = await translateForTarget(validatedArgs, fileContent, allLeaves, validatedArgs.to[i], validatedArgs.output[i], translator, translateOptions, i, validatedArgs.to.length);
|
|
236
|
+
perTarget.push(stat);
|
|
125
237
|
}
|
|
126
|
-
await (0, file_js_1.writeOutput)(outputPath, result);
|
|
127
238
|
spinner.stop();
|
|
128
239
|
logger_js_1.logger.success('Translation completed');
|
|
240
|
+
if (validatedArgs.stats) {
|
|
241
|
+
printStats(validatedArgs, perTarget);
|
|
242
|
+
}
|
|
243
|
+
logger_js_1.logger.info(`★ Glotto faydalı olduysa GitHub'da yıldızlamayı unutma: ${contants_js_1.GITHUB_REPO_URL}`);
|
|
244
|
+
dntShim.Deno.exit(0);
|
|
129
245
|
}
|
|
130
246
|
catch (error) {
|
|
131
247
|
spinner.stop();
|
|
132
248
|
logger_js_1.logger.error(error);
|
|
133
249
|
dntShim.Deno.exit(1);
|
|
134
250
|
}
|
|
135
|
-
finally {
|
|
136
|
-
spinner.stop();
|
|
137
|
-
dntShim.Deno.exit(0);
|
|
138
|
-
}
|
|
139
251
|
}
|
|
140
252
|
main();
|
package/script/deno.d.ts
CHANGED
|
@@ -11,19 +11,23 @@ declare namespace _default {
|
|
|
11
11
|
publish: string;
|
|
12
12
|
"publish:npm": string;
|
|
13
13
|
check: string;
|
|
14
|
+
test: string;
|
|
14
15
|
};
|
|
15
16
|
namespace fmt {
|
|
16
17
|
let semiColons: boolean;
|
|
17
18
|
let singleQuote: boolean;
|
|
18
19
|
let lineWidth: number;
|
|
19
20
|
}
|
|
21
|
+
namespace publish {
|
|
22
|
+
let exclude: string[];
|
|
23
|
+
}
|
|
20
24
|
let imports: {
|
|
21
25
|
"@anthropic-ai/sdk": string;
|
|
22
26
|
"@deno/dnt": string;
|
|
23
27
|
"@google/genai": string;
|
|
24
28
|
"@openai/openai": string;
|
|
29
|
+
"@std/assert": string;
|
|
25
30
|
"@std/cli": string;
|
|
26
|
-
"@std/encoding": string;
|
|
27
31
|
"@std/path": string;
|
|
28
32
|
consola: string;
|
|
29
33
|
};
|
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.1.0",
|
|
6
6
|
"exports": "./cli.ts",
|
|
7
7
|
"lock": false,
|
|
8
8
|
"nodeModulesDir": "auto",
|
|
@@ -12,22 +12,33 @@ exports.default = {
|
|
|
12
12
|
"build:npm": "deno run -A scripts/build_npm.ts",
|
|
13
13
|
"publish": "deno publish",
|
|
14
14
|
"publish:npm": "cd ./npm && npm publish",
|
|
15
|
-
"check": "deno check **/*.ts"
|
|
15
|
+
"check": "deno check **/*.ts",
|
|
16
|
+
"test": "deno test -A --no-check tests/"
|
|
16
17
|
},
|
|
17
18
|
"fmt": {
|
|
18
19
|
"semiColons": true,
|
|
19
20
|
"singleQuote": true,
|
|
20
21
|
"lineWidth": 160
|
|
21
22
|
},
|
|
23
|
+
"publish": {
|
|
24
|
+
"exclude": [
|
|
25
|
+
"tests/",
|
|
26
|
+
"scripts/",
|
|
27
|
+
"npm/",
|
|
28
|
+
"assets/",
|
|
29
|
+
"glotto.exe",
|
|
30
|
+
"CLAUDE.md"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
22
33
|
"imports": {
|
|
23
|
-
"@anthropic-ai/sdk": "npm:@anthropic-ai/sdk@^0.95.
|
|
34
|
+
"@anthropic-ai/sdk": "npm:@anthropic-ai/sdk@^0.95.1",
|
|
24
35
|
"@deno/dnt": "jsr:@deno/dnt@^0.42.3",
|
|
25
|
-
"@google/genai": "npm:@google/genai@^
|
|
26
|
-
"@openai/openai": "npm:openai@^6.
|
|
36
|
+
"@google/genai": "npm:@google/genai@^2.0.0",
|
|
37
|
+
"@openai/openai": "npm:openai@^6.37.0",
|
|
38
|
+
"@std/assert": "jsr:@std/assert@^1.0.19",
|
|
27
39
|
"@std/cli": "jsr:@std/cli@^1.0.29",
|
|
28
|
-
"@std/encoding": "jsr:@std/encoding@^1.0.10",
|
|
29
40
|
"@std/path": "jsr:@std/path@^1.1.4",
|
|
30
41
|
"consola": "npm:consola@^3.4.2"
|
|
31
42
|
},
|
|
32
|
-
"allowScripts": ["npm:@google/genai@1.52.0", "npm:protobufjs@7.5.6"]
|
|
43
|
+
"allowScripts": ["npm:@google/genai@1.52.0", "npm:@google/genai@2.0.0", "npm:protobufjs@7.5.6"]
|
|
33
44
|
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { GlottoConfig, TranslateArgs } from './types.js';
|
|
2
|
+
export declare function loadConfig(explicitPath?: string): Promise<GlottoConfig>;
|
|
3
|
+
export declare function applyConfig(cli: TranslateArgs, config: GlottoConfig, rawArgs: string[]): TranslateArgs;
|
|
4
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/src/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAuB9D,wBAAsB,UAAU,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAc7E;AAkBD,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,aAAa,CA0CtG"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadConfig = loadConfig;
|
|
37
|
+
exports.applyConfig = applyConfig;
|
|
38
|
+
const dntShim = __importStar(require("../_dnt.shims.js"));
|
|
39
|
+
const mod_js_1 = require("../deps/jsr.io/@std/path/1.1.4/mod.js");
|
|
40
|
+
const contants_js_1 = require("./contants.js");
|
|
41
|
+
async function readConfigFile(path) {
|
|
42
|
+
let raw;
|
|
43
|
+
try {
|
|
44
|
+
raw = await dntShim.Deno.readTextFile(path);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (error instanceof dntShim.Deno.errors.NotFound) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
if (raw.trim() === '') {
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
const parsed = JSON.parse(raw);
|
|
56
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
57
|
+
throw new Error(`Config file must contain a JSON object: ${path}`);
|
|
58
|
+
}
|
|
59
|
+
return parsed;
|
|
60
|
+
}
|
|
61
|
+
async function loadConfig(explicitPath) {
|
|
62
|
+
if (explicitPath) {
|
|
63
|
+
const config = await readConfigFile(explicitPath);
|
|
64
|
+
if (config === null) {
|
|
65
|
+
throw new Error(`Config file not found: ${explicitPath}`);
|
|
66
|
+
}
|
|
67
|
+
return config;
|
|
68
|
+
}
|
|
69
|
+
const defaultPath = (0, mod_js_1.join)(dntShim.Deno.cwd(), contants_js_1.CONFIG_FILE_NAME);
|
|
70
|
+
const config = await readConfigFile(defaultPath);
|
|
71
|
+
if (config === null) {
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
return config;
|
|
75
|
+
}
|
|
76
|
+
function joinList(value) {
|
|
77
|
+
if (value === undefined) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
if (Array.isArray(value)) {
|
|
81
|
+
return value.join(',');
|
|
82
|
+
}
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
function rawArgsHas(rawArgs, flag) {
|
|
86
|
+
const long = `--${flag}`;
|
|
87
|
+
const longEq = `--${flag}=`;
|
|
88
|
+
return rawArgs.some((a) => a === long || a.startsWith(longEq));
|
|
89
|
+
}
|
|
90
|
+
function applyConfig(cli, config, rawArgs) {
|
|
91
|
+
const merged = { ...cli };
|
|
92
|
+
if (merged.key === undefined && config.key !== undefined) {
|
|
93
|
+
merged.key = config.key;
|
|
94
|
+
}
|
|
95
|
+
if (merged.provider === undefined && config.provider !== undefined) {
|
|
96
|
+
merged.provider = config.provider;
|
|
97
|
+
}
|
|
98
|
+
if (merged.model === undefined && config.model !== undefined) {
|
|
99
|
+
merged.model = config.model;
|
|
100
|
+
}
|
|
101
|
+
if (merged.input === undefined && config.input !== undefined) {
|
|
102
|
+
merged.input = config.input;
|
|
103
|
+
}
|
|
104
|
+
if (merged.output === undefined && config.output !== undefined) {
|
|
105
|
+
merged.output = joinList(config.output);
|
|
106
|
+
}
|
|
107
|
+
if (merged.from === undefined && config.from !== undefined) {
|
|
108
|
+
merged.from = config.from;
|
|
109
|
+
}
|
|
110
|
+
if (merged.to === undefined && config.to !== undefined) {
|
|
111
|
+
merged.to = joinList(config.to);
|
|
112
|
+
}
|
|
113
|
+
if (merged.url === undefined && config.url !== undefined) {
|
|
114
|
+
merged.url = config.url;
|
|
115
|
+
}
|
|
116
|
+
if (merged['max-batch-size'] === undefined && config.maxBatchSize !== undefined) {
|
|
117
|
+
merged['max-batch-size'] = String(config.maxBatchSize);
|
|
118
|
+
}
|
|
119
|
+
if (!rawArgsHas(rawArgs, 'no-limit') && config.noLimit !== undefined) {
|
|
120
|
+
merged['no-limit'] = config.noLimit;
|
|
121
|
+
}
|
|
122
|
+
if (!rawArgsHas(rawArgs, 'no-timeout') && config.noTimeout !== undefined) {
|
|
123
|
+
merged['no-timeout'] = config.noTimeout;
|
|
124
|
+
}
|
|
125
|
+
if (!rawArgsHas(rawArgs, 'stats') && config.stats !== undefined) {
|
|
126
|
+
merged.stats = config.stats;
|
|
127
|
+
}
|
|
128
|
+
if (!rawArgsHas(rawArgs, 'incremental') && config.incremental !== undefined) {
|
|
129
|
+
merged.incremental = config.incremental;
|
|
130
|
+
}
|
|
131
|
+
return merged;
|
|
132
|
+
}
|
package/script/src/contants.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
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
|
+
export declare const INTER_LEAF_DELAY_MS: 200;
|
|
9
|
+
export declare const PER_LEAF_FALLBACK_RATIO: 0.5;
|
|
10
|
+
export declare const GITHUB_REPO_URL: "https://github.com/ibodev1/glotto";
|
|
11
|
+
export declare const CONFIG_FILE_NAME: "glotto.config.json";
|
|
8
12
|
export declare const HELP_TEXT: string;
|
|
9
13
|
//# 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,mBAAmB,EAAG,GAAY,CAAC;AAEhD,eAAO,MAAM,uBAAuB,EAAG,GAAY,CAAC;AAEpD,eAAO,MAAM,eAAe,EAAG,mCAA4C,CAAC;AAE5E,eAAO,MAAM,gBAAgB,EAAG,oBAA6B,CAAC;AAE9D,eAAO,MAAM,SAAS,QAqCrB,CAAC"}
|
package/script/src/contants.js
CHANGED
|
@@ -1,36 +1,55 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HELP_TEXT = exports.
|
|
4
|
-
exports.DEFAULT_PROVIDER = '
|
|
3
|
+
exports.HELP_TEXT = exports.CONFIG_FILE_NAME = exports.GITHUB_REPO_URL = exports.PER_LEAF_FALLBACK_RATIO = exports.INTER_LEAF_DELAY_MS = exports.INTER_BATCH_DELAY_MS = exports.BASE_RETRY_DELAY_MS = exports.MAX_RETRIES = exports.DEFAULT_MAX_BATCH_BYTES = exports.DEFAULT_MODELS = exports.DEFAULT_PROVIDER = void 0;
|
|
4
|
+
exports.DEFAULT_PROVIDER = 'openai';
|
|
5
5
|
exports.DEFAULT_MODELS = {
|
|
6
6
|
gemini: 'gemini-2.5-flash',
|
|
7
7
|
openai: 'gpt-4.1-mini',
|
|
8
8
|
anthropic: 'claude-3-5-haiku-latest',
|
|
9
9
|
};
|
|
10
|
-
exports.
|
|
10
|
+
exports.DEFAULT_MAX_BATCH_BYTES = 12_000;
|
|
11
11
|
exports.MAX_RETRIES = 3;
|
|
12
12
|
exports.BASE_RETRY_DELAY_MS = 2_000;
|
|
13
|
-
exports.
|
|
13
|
+
exports.INTER_BATCH_DELAY_MS = 1_500;
|
|
14
|
+
exports.INTER_LEAF_DELAY_MS = 200;
|
|
15
|
+
exports.PER_LEAF_FALLBACK_RATIO = 0.5;
|
|
16
|
+
exports.GITHUB_REPO_URL = 'https://github.com/ibodev1/glotto';
|
|
17
|
+
exports.CONFIG_FILE_NAME = 'glotto.config.json';
|
|
14
18
|
exports.HELP_TEXT = `
|
|
15
19
|
Glotto AI Translator
|
|
16
20
|
-------------------
|
|
17
21
|
A tool for translating i18n JSON files using AI services.
|
|
18
22
|
|
|
23
|
+
Glotto walks the input JSON, extracts every string leaf with its path, sends them to the
|
|
24
|
+
chosen provider as plain-text batches (using ≪id≫value≪/id≫ tagged entries), and
|
|
25
|
+
reconstructs the JSON from the responses. JSON structure, keys, variables and HTML tags
|
|
26
|
+
are preserved by the tool itself — the model only sees and produces text.
|
|
27
|
+
|
|
19
28
|
Options:
|
|
20
|
-
--key
|
|
21
|
-
-p, --provider
|
|
22
|
-
-m, --model
|
|
23
|
-
-i, --input
|
|
24
|
-
-o, --output
|
|
25
|
-
-f, --from
|
|
26
|
-
-t, --to
|
|
27
|
-
--url
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
--key API key for the AI service (required)
|
|
30
|
+
-p, --provider AI translation provider to use (default: ${exports.DEFAULT_PROVIDER})
|
|
31
|
+
-m, --model Model name for the selected provider (optional)
|
|
32
|
+
-i, --input Path to source JSON file (required)
|
|
33
|
+
-o, --output Target JSON file path. Comma-separated for multi-target (required)
|
|
34
|
+
-f, --from Source language (required)
|
|
35
|
+
-t, --to Target language. Comma-separated for multi-target (required)
|
|
36
|
+
--url Custom base URL for OpenAI/Anthropic (optional)
|
|
37
|
+
--config Path to a glotto.config.json (default: ./glotto.config.json if present)
|
|
38
|
+
--stats Print AI usage stats (input/output tokens, calls) at the end
|
|
39
|
+
--incremental Translate only missing/empty keys when the target file already exists
|
|
40
|
+
--no-limit Disable rate limit delay between batches
|
|
41
|
+
--no-timeout Disable request timeout (wait indefinitely for AI response)
|
|
42
|
+
--max-batch-size Maximum source size per batch, in KB (default: ${exports.DEFAULT_MAX_BATCH_BYTES / 1024} KB)
|
|
43
|
+
-h, --help Display this help message
|
|
44
|
+
-v, --version Display version
|
|
30
45
|
|
|
31
46
|
Examples:
|
|
32
47
|
glotto --key {{key}} --input=en.json --output=tr.json --from=english --to=turkish
|
|
33
48
|
glotto --key {{key}} -i en.json -o tr.json -f english -t turkish -p gemini
|
|
34
|
-
glotto --key {{key}} -i en.json -
|
|
35
|
-
glotto --key {{key}} -i en.json -o tr.json -f english -t turkish
|
|
49
|
+
glotto --key {{key}} -i en.json -f english -t "turkish,french" -o "tr.json,fr.json"
|
|
50
|
+
glotto --key {{key}} -i en.json -o tr.json -f english -t turkish --incremental
|
|
51
|
+
glotto --key {{key}} -i en.json -o tr.json -f english -t turkish --stats
|
|
52
|
+
glotto --key {{key}} --config ./glotto.config.json
|
|
53
|
+
glotto --key {{key}} -i en.json -o tr.json -f english -t turkish --no-limit --no-timeout
|
|
54
|
+
glotto --key {{key}} -i en.json -o tr.json -f english -t turkish --max-batch-size 8
|
|
36
55
|
`;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { JsonValue, Leaf } from './types.js';
|
|
2
|
+
export declare function findMissingLeaves(sourceLeaves: Leaf[], existingTarget: JsonValue): Leaf[];
|
|
3
|
+
export declare function mergeTranslations(existingTarget: JsonValue, sourceLeaves: Leaf[], translations: Map<number, string>): JsonValue;
|
|
4
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/src/diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAQ,MAAM,YAAY,CAAC;AAyBxD,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE,cAAc,EAAE,SAAS,GAAG,IAAI,EAAE,CAYzF;AASD,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,SAAS,EACzB,YAAY,EAAE,IAAI,EAAE,EACpB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,SAAS,CAYX"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findMissingLeaves = findMissingLeaves;
|
|
4
|
+
exports.mergeTranslations = mergeTranslations;
|
|
5
|
+
const translator_js_1 = require("./translator.js");
|
|
6
|
+
function getPath(root, path) {
|
|
7
|
+
let node = root;
|
|
8
|
+
for (const key of path) {
|
|
9
|
+
if (node === null || typeof node !== 'object') {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
const container = node;
|
|
13
|
+
if (!(key in container)) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
node = container[key];
|
|
17
|
+
}
|
|
18
|
+
return node;
|
|
19
|
+
}
|
|
20
|
+
function isPresentTranslation(value) {
|
|
21
|
+
if (typeof value !== 'string') {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return value.trim().length > 0;
|
|
25
|
+
}
|
|
26
|
+
function findMissingLeaves(sourceLeaves, existingTarget) {
|
|
27
|
+
const missing = [];
|
|
28
|
+
for (const leaf of sourceLeaves) {
|
|
29
|
+
if (!leaf.translatable) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const existingValue = getPath(existingTarget, leaf.path);
|
|
33
|
+
if (!isPresentTranslation(existingValue)) {
|
|
34
|
+
missing.push(leaf);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return missing;
|
|
38
|
+
}
|
|
39
|
+
function deepClone(value) {
|
|
40
|
+
if (value === null || typeof value !== 'object') {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
return JSON.parse(JSON.stringify(value));
|
|
44
|
+
}
|
|
45
|
+
function mergeTranslations(existingTarget, sourceLeaves, translations) {
|
|
46
|
+
const clone = deepClone(existingTarget);
|
|
47
|
+
for (const leaf of sourceLeaves) {
|
|
48
|
+
if (!translations.has(leaf.id)) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (leaf.path.length === 0) {
|
|
52
|
+
return translations.get(leaf.id);
|
|
53
|
+
}
|
|
54
|
+
(0, translator_js_1.setPath)(clone, leaf.path, translations.get(leaf.id));
|
|
55
|
+
}
|
|
56
|
+
return clone;
|
|
57
|
+
}
|
package/script/src/file.d.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare
|
|
3
|
-
export declare
|
|
4
|
-
export declare
|
|
5
|
-
export declare
|
|
6
|
-
export declare const ensureDirectoryExists: (directory: string) => Promise<void>;
|
|
7
|
-
export declare const splitJson: (data: JsonObject, maxChunkBytes?: number) => ChunkInfo[];
|
|
8
|
-
export declare const mergeInputs: (inputs: JsonObject[]) => JsonObject;
|
|
9
|
-
export declare const writeTemp: (targetLanguage: string, tempJsonFileName: string, content: string) => Promise<void>;
|
|
1
|
+
import type { JsonValue } from './types.js';
|
|
2
|
+
export declare function resolvePath(...paths: string[]): string;
|
|
3
|
+
export declare function getImportJson<T = JsonValue>(input: string): Promise<T>;
|
|
4
|
+
export declare function writeOutput(outputPath: string, content: string): Promise<void>;
|
|
5
|
+
export declare function readJsonIfExists<T = JsonValue>(path: string): Promise<T | null>;
|
|
10
6
|
//# sourceMappingURL=file.d.ts.map
|
package/script/src/file.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/src/file.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/src/file.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,wBAAgB,WAAW,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAEtD;AAED,wBAAsB,aAAa,CAAC,CAAC,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAO5E;AAED,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpF;AAED,wBAAsB,gBAAgB,CAAC,CAAC,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAcrF"}
|