Deno-first i18n JSON translator. Node distribution mirrored via scripts/build_npm.ts.
deno check cli.ts— type check (entry point covers all reachable files)deno fmt— format (config indeno.json: 160 cols, single quotes, semicolons)deno task build— single-file binarydeno task build:npm— npm package via@deno/dntdeno eval "<code>"— fast smoke tests forsrc/logic without spinning up the CLI
When adding/removing imports in deno.json, mirror in scripts/build_npm.ts dependencies block. Pure JSR imports (@std/*) don't need mirroring; npm: ones
do. Static asset additions (e.g. files under schema/) must also be copied in postBuild().
extractLeaves— walks JSON to flatLeaf[] { id, path, value, translatable }. Empty objects/arrays kept as non-translatable so reconstruction is lossless.groupIntoBatches— packs translatable leaves under--max-batch-sizebyte budget.buildBatchPrompt— wraps each entry as≪id≫value≪/id≫, single prompt per batch.- Provider — implements
TextTranslator { translate(prompt) → { text, usage? } }. No JSON mode anywhere; usage is{ inputTokens, outputTokens }if the SDK exposes it, undefined otherwise. decodeResponse— multi-pattern tolerant parser (≪≫ primary, <<>> «» fallbacks).- Per-entry fallback — auto-triggers when batch first attempt loses ≥50% (
PER_LEAF_FALLBACK_RATIO). Uses TranslateGemma-style single-input prompt. reconstruct— walksallLeaves, places translated/original values viasetPath. Number path step → array, string → object.runBatchesreturns{ translations, usage, calls }—usageaccumulated across batch + per-leaf attempts;callsis total provider invocations.
validateArgsparses--toand--outputas comma-separated lists intostring[]. Lengths must match.cli.tsreads source + extracts leaves once, then loops per target (sequential to keep rate-limit semantics across targets).- Incremental mode (
--incremental) reads the existing target file viareadJsonIfExists. If found:findMissingLeaves(insrc/diff.ts) returns only translatable source leaves whose target value is missing or empty-string;mergeTranslationsdeep-clones the existing target and overwrites only those paths. If the target file doesn't exist, falls through to full translation.
- Default lookup:
./glotto.config.jsonin CWD. Overridable via--config <path>. - Loader is
src/config.ts→loadConfig(). Merging isapplyConfig(cli, config, rawArgs)with CLI precedence over config. - Booleans need
rawArgsbecauseparseArgsalways materializes declared boolean flags asfalse/true, neverundefined. We detect explicit user flags by scanningDeno.argsliteral tokens. - JSON Schema lives at
schema/glotto.schema.jsonand is bundled into the npm build viapostBuild().
- No comments unless explaining a non-obvious why. User explicitly dislikes verbose comments and "what" commentary.
- Responses to the user are in Turkish; keep tight (precision/minimalism).
- Provider files stay tiny — just
translate(prompt) → { text, usage? }. No i18n/JSON awareness inside providers. - Use
functionkeyword for all named functions — noconst fn = () => {}pattern. - All
ifblocks must use{}, even single-line bodies. - Never use
any. Useunknown+ type guards or explicit type predicates (e.g.(x): x is T => ...). - No
awaitinsideifconditions. Await into a variable first, then check withif.
AbortSignal.timeout(0)fires immediately. For OpenAI/Gemini "no timeout" use2_147_483_647(max 32-bit signed). Anthropic'stimeout: 0is documented as disable.--max-batch-sizevalue is in KB, not bytes (maxBatchBytes = parsed * 1024invalidateArgs).- Single JSON keys whose value >
maxBatchBytesare unsplittable (string leaves) — they go alone in a batch with a warning, not an error. parseArgsboolean flags default tofalse, notundefined. UserawArgsHas(Deno.args, 'flag')to distinguish "user didn't pass" from "user passed false".setPathis exported fromsrc/translator.tssosrc/diff.tscan reuse it formergeTranslations. Keep them aligned (number path step → array, string → object).