mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 05:12:14 +00:00
test(i18n): hold every catalogue to the English placeholders
Key parity let 38 pt-BR strings through that renamed or dropped a
{placeholder}: a renamed one renders as a raw token, a dropped one
loses what the sentence was for. Every non-English bundle now has to
use exactly the placeholders of the English string, with one
allowance: a singular plural form may spell out or add {count}.
This commit is contained in:
1 parent
5c2f91463c
commit
71123e5fae
1 file changed
+56
@@ -345,6 +345,62 @@ describe("i18n locale file integrity", () => {
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Placeholder parity. `t()` replaces `{name}` tokens literally, so a
|
||||
* translation that renames one ("{when}" for "{date}") renders the raw
|
||||
* token, and one that drops one ("Plano limitado" for "Your {provider}
|
||||
* plan does not include {list}") loses the information the sentence was
|
||||
* for. Neither breaks the key-parity check above, which is how 38 of them
|
||||
* reached a bundle unnoticed.
|
||||
*
|
||||
* A singular plural form (`…One`) may name the count in words instead of
|
||||
* `{count}`, or name it where English does not.
|
||||
*/
|
||||
function placeholderSet(value: string, singular: boolean): string {
|
||||
const names = new Set(
|
||||
[...value.matchAll(/\{(\w+)\}/g)].map((match) => match[1]),
|
||||
);
|
||||
if (singular) names.delete("count");
|
||||
return [...names].sort().join(",");
|
||||
}
|
||||
|
||||
it.each(NON_EN_LOCALES)(
|
||||
"$locale uses exactly the English placeholders",
|
||||
({ locale, path }) => {
|
||||
const enFlat: [string, string][] = [];
|
||||
flattenValues(JSON.parse(readFileSync(EN_PATH, "utf8")), "", enFlat);
|
||||
const other = new Map<string, string>();
|
||||
const otherFlat: [string, string][] = [];
|
||||
flattenValues(JSON.parse(readFileSync(path, "utf8")), "", otherFlat);
|
||||
for (const [key, value] of otherFlat) other.set(key, value);
|
||||
|
||||
// A floor, so an empty or unreadable English bundle cannot pass.
|
||||
requireFloor(
|
||||
"English strings carrying a placeholder",
|
||||
enFlat.filter(([, value]) => /\{\w+\}/.test(value)),
|
||||
1000,
|
||||
);
|
||||
const drift = enFlat
|
||||
.filter(([key, enValue]) => {
|
||||
const value = other.get(key);
|
||||
if (value === undefined) return false;
|
||||
const singular = key.endsWith("One");
|
||||
return (
|
||||
placeholderSet(value, singular) !==
|
||||
placeholderSet(enValue, singular)
|
||||
);
|
||||
})
|
||||
.map(
|
||||
([key, enValue]) =>
|
||||
` ${key}: en {${placeholderSet(enValue, false)}} vs ${locale} {${placeholderSet(other.get(key) ?? "", false)}}`,
|
||||
);
|
||||
expect(
|
||||
drift,
|
||||
`Translations whose placeholders differ from English:\n${drift.join("\n")}`,
|
||||
).toEqual([]);
|
||||
},
|
||||
);
|
||||
|
||||
it("DE locale renders Health Score pillar labels in German", () => {
|
||||
const de = JSON.parse(readFileSync(DE_PATH, "utf8")) as Record<
|
||||
string,
|
||||
|
||||
Reference in new issue
Block a user