fix(ui,i18n): E30 review round 1 — audit rows in the reader's language, one HU name per thing

- audit log: a job run named from its result data (nested phases too), a skipped run says so, a
  secret's reset reads as a reset, choices named as Configuration names them, interval / batch /
  counts localized; the inbox shares the same jobRunText
- HU: remux is "Közvetlen közvetítés" (it shared "Közvetlen lejátszás" with direct play); backfill is
  behúzás, enrich is dúsítás, collection is kollekció, the allow-list is fehérlista; the last
  "jobnak" / "transzkódolás"; a test holds the options of one choice to distinct names
- contract: every skipped / reason word a job returns is named in both languages
- person page: the bio wait is timed from the open and a failing ask stops the polling; ClampedText
  (ui) shared with the collection page, whose short summary lost its dead More
- a playlist names season 0 the Specials; the channel re-slot compares in the reader's alphabet; an
  invite's date is in the admin's language; the language-ordered lists are asked again once a
  language switch is saved (saveLanguage)
- poster grids' column minimum in rem; lint refuses minmax(Npx,…)
This commit is contained in:
2026-09-30 03:26:58 +02:00
parent ab963c81d2
commit fa55e01ef0
46 changed files with 624 additions and 187 deletions
+29
View File
@@ -43,3 +43,32 @@ describe("the copy rule", () => {
expect(offenders((v) => /(\d|\}\})\s?(m|h|d|s)(?![\p{L}\d/])/u.test(v))).toEqual([]);
});
});
describe("one name per thing", () => {
// The options of one choice are told apart by their names alone: two playback classes once shared
// "Közvetlen lejátszás" in the HU filter (E30 review). A set = a `…Opt` object, or one choice key's
// options under config.choices.
const sets = (): [string, Record<string, unknown>][] => {
const out: [string, Record<string, unknown>][] = [];
const walk = (o: unknown, path: string, parent: string) => {
if (!o || typeof o !== "object") return;
if (/Opt$/.test(path.split(".").pop() ?? "") || parent.endsWith("/config:.choices"))
out.push([path, o as Record<string, unknown>]);
for (const [k, v] of Object.entries(o)) walk(v, `${path}.${k}`, path);
};
for (const [file, json] of Object.entries(files))
walk(json, file.replace("./locales/", "").replace(".json", ":"), "");
return out;
};
it("names the options of one choice differently", () => {
const found = sets();
expect(found.some(([p]) => p.endsWith("playableOpt"))).toBe(true);
expect(found.some(([p]) => p.endsWith("choices.log_level"))).toBe(true);
const clashes = found.flatMap(([path, opts]) => {
const names = Object.values(opts).filter((v): v is string => typeof v === "string");
return names.length === new Set(names).size ? [] : [path];
});
expect(clashes).toEqual([]);
});
});