refactor(i18n): ask the catalogue for a sentence in one helper

`t()` answers a missing key with the key, so "does this code have a
sentence" was a comparison written inline at every site that wanted a
code's sentence or a fallback, twenty-odd times in several spellings.
translateOrNull, translateCodeOrNull and translateCode in
src/lib/i18n/translate-code.ts now hold that probe, every site uses
them, and a guard refuses the inline comparison anywhere else.
This commit is contained in:
Marc-André Bombeck committed 2026-10-20 09:53:31 +02:00
1 parent 2f7f04ecab
commit 6e54f33901
32 files changed
+291 -119

No files matched your search

@@ -24,8 +24,12 @@ import {
const ROOTS = ["src/components/timeline", "src/components/day"] as const;
/** `t(` or `tCount(` whose key is a template literal, across line breaks. */
const TEMPLATE_KEY = /(?<![\w.])(?:t|tCount)\(\s*`/g;
/**
* `t(`, `tCount(` or the catalogue probe `translateOrNull(t, ` whose key is
* a template literal, across line breaks.
*/
const TEMPLATE_KEY =
/(?<![\w.])(?:t|tCount)\(\s*`|(?<![\w.])translateOrNull\(\s*t\s*,\s*`/g;
const ALLOWED: Readonly<Record<string, { count: number; why: string }>> = {
"src/components/timeline/readiness-inventory.tsx": {
@@ -34,6 +34,7 @@ import {
} from "./label-keys";
import { formatMonthYear } from "./timeline-dates";
import { orderedReadinessLanes, readinessTally } from "./readiness-model";
import { translateOrNull } from "@/lib/i18n/translate-code";
type Translate = ReturnType<typeof useTranslations>["t"];
type TranslateCount = ReturnType<typeof useTranslations>["tCount"];
@@ -65,11 +66,10 @@ export function wordKey(
params: Record<string, string | number>,
): string | null {
const count = typeof params.count === "number" ? params.count : null;
if (count !== null && t(`${base}Other`) !== `${base}Other`) {
if (count !== null && translateOrNull(t, `${base}Other`) !== null) {
return tCount(base, count, params);
}
const single = t(base, params);
return single === base ? null : single;
return translateOrNull(t, base, params);
}
export function laneLabel(t: Translate, key: TimelineReadinessLane["key"]) {