mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
Shared Claude Code translation pipeline (scripts/i18n, no API key) plus Astro/VitePress/Scalar i18n wiring. Landing and API reference translated into all 20 languages; docs i18n wiring + English source anchors. The translated docs markdown (apps/docs/<locale>/**, 3,620 files) follows in a companion PR because it exceeds GitHub's per-PR CI file limit.
54 lines
2.1 KiB
TypeScript
54 lines
2.1 KiB
TypeScript
// tests/unit/scripts/i18n/batch.test.ts
|
|
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
batchResultTranslator,
|
|
readDone,
|
|
writePending,
|
|
} from "../../../../scripts/i18n/lib/batch.mjs";
|
|
|
|
describe("batch handoff", () => {
|
|
it("writes pending units as masked {id, masked} pairs", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "i18n-batch-"));
|
|
const path = writePending(dir, "docs", "de", [
|
|
{ unit: { id: "a", sourceText: "Run `x` for {n}" }, srcHash: "h" },
|
|
]);
|
|
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
expect(parsed[0].id).toBe("a");
|
|
expect(parsed[0].masked).not.toContain("`x`"); // masked
|
|
expect(parsed[0].masked).not.toContain("{n}");
|
|
});
|
|
|
|
it("batchResultTranslator restores tokens from the done map", async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "i18n-batch-"));
|
|
// Simulate a subagent producing a done file that keeps the mask tokens.
|
|
// Build the expected masked form by masking the same source the translator will mask.
|
|
const units = [{ id: "a", sourceText: "Run `x` for {n}" }];
|
|
// The subagent returns the translated masked text; here we fake "DE " prefix.
|
|
writePending(
|
|
dir,
|
|
"docs",
|
|
"de",
|
|
units.map((u) => ({ unit: u, srcHash: "h" })),
|
|
);
|
|
const pending = JSON.parse(readFileSync(join(dir, "docs.de.pending.json"), "utf8"));
|
|
const done = { a: `DE ${pending[0].masked}` };
|
|
writeFileSync(join(dir, "docs.de.done.json"), JSON.stringify(done));
|
|
|
|
const doneMap = readDone(dir, "docs", "de");
|
|
const translate = batchResultTranslator(doneMap);
|
|
const out = await translate(units, "de");
|
|
expect(out.get("a")).toContain("`x`"); // restored
|
|
expect(out.get("a")).toContain("{n}");
|
|
expect(out.get("a")).toContain("DE ");
|
|
});
|
|
|
|
it("batchResultTranslator returns null for a missing id", async () => {
|
|
const translate = batchResultTranslator(new Map());
|
|
const out = await translate([{ id: "z", sourceText: "hi" }], "de");
|
|
expect(out.get("z")).toBeNull();
|
|
});
|
|
});
|