Stringproof
Catch damaged translations before they ship.
What’s it for?
Translation output can parse cleanly and still be broken. Placeholders disappear, scripts mix, prompt instructions leak into values, and encoding damage survives review.
Stringproof compares every Apple .strings target with its source and reports the damage. It is deterministic, local, and read-only: it validates translations but never translates or repairs them.
en.lproj/Localizable.strings/* A compact source catalog for the Stringproof demonstration. */
"welcome.user" = "Welcome, %@.";
"items.count" = "{count} items";
"summary.title" = "Résumé";
"onboarding.prompt" = "Welcome";
"continue.action" = "Continue";
"reading.action" = "Read now";
"settings.open" = "Open Settings";ja.lproj/Localizable.strings/* Each defect is intentional and exercised by the real CLI. */
"welcome.user" = "ようこそ。";
"items.count" = "{total}件";
"summary.title" = "Résumé";
"onboarding.prompt" = "Please translate the following English text into Japanese:";
"continue.action" = "ようこそ 更多";
"reading.action" = "Read now";
"target.only" = "対象のみ";exit 1ja.lproj/Localizable.strings:1 [key.missing] ja settings.open: key is present in source catalog but missing from target
ja.lproj/Localizable.strings:2 [placeholder.missing] ja welcome.user: missing placeholder(s): %@
ja.lproj/Localizable.strings:3 [placeholder.added] ja items.count: added placeholder(s): {total}
ja.lproj/Localizable.strings:3 [placeholder.missing] ja items.count: missing placeholder(s): {count}
ja.lproj/Localizable.strings:4 [encoding.mojibake] ja summary.title: contains strong mojibake indicator(s): é
ja.lproj/Localizable.strings:5 [model.residue] ja onboarding.prompt: contains translation prompt or model-control residue
ja.lproj/Localizable.strings:6 [script.unexpected] ja continue.action: known cross-script fragment(s): 更多
ja.lproj/Localizable.strings:7 [translation.unchanged] ja reading.action: matches lexical source text and may be untranslated
ja.lproj/Localizable.strings:8 [key.unexpected] ja target.only: key is absent from source catalogUse it
stringproof check ios --source-locale enor return stable JSON
stringproof check ios --source-locale en --jsonStringproof finds Apple .strings catalogs, pairs each target with its source by relative path, and checks their keys and values.
1,000 keys / 2 locales: ~60 ms. 10,000 keys: ~230 ms / 2 locales; ~1.6 s / 11 locales.
Limits. Stringproof can show that catalogs line up and that known corruption patterns are absent. It cannot show that a translation is correct, natural, or appropriate. It may flag a legitimate unchanged name, miss source text after a small alteration, or miss an entirely absent target catalog.
The first version supports Apple .strings only. It uses no credentials, network access, model calls, configuration, or repair mode. View Stringproof on GitHub ↗