i18n: parity checks itself, over the locales actually on disk
master was out of parity and every test was green. sv-SE named commandHq.referencePath and referencePathHint; en-GB named workingDirectory and cwdHint. Two reasons neither was caught. The three parity tests LISTED their locales literally, so adding a sixth added a file none of them looked at. A guard that has to be maintained to keep guarding is the thing it exists to prevent — the same shape as the bug that made three locales ship dead last night. They now read the directory. And findMissingKeys is one-directional: it asks whether every English key is present, so a rename reports half of itself. The new key is missing and caught; the stale one the translation still carries is invisible. findExtraKeys is the other half, and both are asserted. Realigns sv-SE onto the committed key names. It was translated from a working tree where that rename existed and was not yet committed — the commander directory work, still unreviewed — so on master it named keys English did not have. The rename will land across all six locales together when that work does. Also asserts there IS at least one locale besides en-GB, because otherwise every assertion passes over an empty set and reports nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
@@ -1,15 +1,37 @@
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { findMissingKeys } from 'i18n';
|
||||
import { readdirSync, readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { findMissingKeys, findExtraKeys } from 'i18n';
|
||||
import en from './en-GB.json';
|
||||
import ptPT from './pt-PT.json';
|
||||
import frFR from './fr-FR.json';
|
||||
import deDE from './de-DE.json';
|
||||
import esES from './es-ES.json';
|
||||
|
||||
// D2: every shipped locale ships a COMPLETE catalog. A key en-GB has and another locale lacks is a red
|
||||
// build, not a warning — there is no regional fallback to paper over the gap.
|
||||
/**
|
||||
* Parity, over whatever locales are actually ON DISK — not a list written here.
|
||||
*
|
||||
* This used to name its locales literally, and that made it a check you had to remember to update. Adding
|
||||
* `sv-SE` added a file no parity test looked at, so it shipped out of step and every test stayed green.
|
||||
* A guard that needs maintaining to keep guarding is the thing it was written to prevent.
|
||||
*
|
||||
* Both directions, too. `findMissingKeys` alone reports half of a rename: the new key is missing from the
|
||||
* translation and caught, while the stale one it still carries is invisible. That is exactly how sv-SE
|
||||
* ended up naming two keys en-GB did not have.
|
||||
*/
|
||||
const LOCALES: Record<string, Record<string, unknown>> = Object.fromEntries(
|
||||
readdirSync(__dirname)
|
||||
.filter((f) => f.endsWith('.json') && f !== 'en-GB.json')
|
||||
.map((f) => [f.replace(/\.json$/, ''), JSON.parse(readFileSync(join(__dirname, f), 'utf8'))]),
|
||||
);
|
||||
|
||||
describe('officer-web (app.*) locale catalogs', () => {
|
||||
test('every shipped locale has every key en-GB has', () => {
|
||||
expect(findMissingKeys(en, { 'pt-PT': ptPT, 'fr-FR': frFR, 'de-DE': deDE, 'es-ES': esES })).toEqual([]);
|
||||
test('there is at least one locale besides en-GB', () => {
|
||||
// Otherwise every assertion below passes over an empty set and says nothing.
|
||||
expect(Object.keys(LOCALES).length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('every locale has every key en-GB has', () => {
|
||||
expect(findMissingKeys(en, LOCALES)).toEqual([]);
|
||||
});
|
||||
|
||||
test('no locale has a key en-GB does not', () => {
|
||||
expect(findExtraKeys(en, LOCALES)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user