chore: add a command-line translation check

Mirrors the button on the settings page, for verifying a deployment from
the host before anyone signs in, and for watching the cache work.

Measured against the live service, which settles a question the spec had
guessed at: a short phrase takes between 4.6 and 10.7 seconds, because
the endpoint really does start a Claude Code process. The ten-second
timeout the spec assumed would have failed intermittently on exactly the
kind of message this shop writes. Thirty seconds stands.

Cached answers come back in 3 milliseconds, so the cache is worth
roughly three thousand times its complexity.

Quality checked on real phrasing: times and dates survive unchanged
("Ouverture retardée à 14:00" to "Delayed opening at 14:00 today"),
which is what the prompt asks for and what the screen needs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012cSY9pVhZmJUKNN7wf1Myd
This commit is contained in:
2026-09-20 22:08:39 +02:00
co-authored by Claude Opus 5
parent 1668240724
commit ebc69dc109
2 changed files with 58 additions and 1 deletions
+2 -1
View File
@@ -19,7 +19,8 @@
"screen:preview": "tsx scripts/preview.ts", "screen:preview": "tsx scripts/preview.ts",
"brand": "tsx scripts/brand.ts", "brand": "tsx scripts/brand.ts",
"e2e": "playwright test", "e2e": "playwright test",
"holidays:sync": "tsx scripts/sync-holidays.ts" "holidays:sync": "tsx scripts/sync-holidays.ts",
"translate:test": "tsx scripts/test-translation.ts"
}, },
"dependencies": { "dependencies": {
"@fontsource-variable/inter": "^5.3.0", "@fontsource-variable/inter": "^5.3.0",
+56
View File
@@ -0,0 +1,56 @@
/**
* Round-trips a phrase through the translation service.
*
* npm run translate:test ["texte à traduire"]
*
* The settings page has the same button; this exists to check a deployment
* from the host, before anyone signs in, and to see the cache working.
*/
import 'dotenv/config';
import { prisma } from '../lib/db';
import { defaultProvider, translateToEnglish } from '../lib/translation/service';
async function main(): Promise<void> {
const text = process.argv[2] ?? 'Fermeture exceptionnelle jeudi après-midi';
const provider = defaultProvider();
if (!provider) {
console.error('Service non configuré : renseignez TRANSLATION_API_URL et TRANSLATION_API_KEY.');
process.exitCode = 1;
return;
}
console.log(`Modèle : ${provider.model}`);
console.log(`Français : ${text}`);
const started = Date.now();
const first = await translateToEnglish(text, provider);
const elapsed = Date.now() - started;
if (!first.ok) {
console.error(`Échec : ${first.error}`);
process.exitCode = 1;
return;
}
console.log(`Anglais : ${first.text}`);
console.log(`Durée : ${elapsed} ms (cache : ${first.cached ? 'oui' : 'non'})`);
// Second pass proves the cache: it must not touch the network at all.
const again = Date.now();
const second = await translateToEnglish(text, provider);
console.log(
`2e appel : ${Date.now() - again} ms (cache : ${second.ok && second.cached ? 'oui' : 'non'})`,
);
}
main()
.catch((error: unknown) => {
console.error(error);
process.exitCode = 1;
})
.finally(() => {
void prisma.$disconnect();
});