forked from yvv/decision
82 lines
3.4 KiB
TypeScript
82 lines
3.4 KiB
TypeScript
// The words of the screen: every catalogue has the same keys and the same
|
|
// placeholders, and no visible text uses a forbidden term.
|
|
import { readdirSync, readFileSync, statSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { describe, expect, it } from 'vitest';
|
|
import { en } from '../../src/lib/i18n/en';
|
|
import { es } from '../../src/lib/i18n/es';
|
|
import { fr } from '../../src/lib/i18n/fr';
|
|
|
|
/** Never shown to a person (case- and accent-insensitive). They may live on as code identifiers. */
|
|
export const FORBIDDEN_UI_TERMS = [
|
|
'déléguer', 'délégation', 'délégué', 'dette', 'retard', 'en souffrance', 'corpus', 'snapshot',
|
|
'verdict', 'triage', 'oligarchie', 'peuple adulte',
|
|
// The Ğ1 chain and its wallets, in plain words (lot B): never the jargon.
|
|
'blockchain', 'extrinsic', 'extrinsèque',
|
|
];
|
|
|
|
const fold = (s: string) => s.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase();
|
|
const marks = (s: string) => (s.match(/\{\w+\}/g) ?? []).sort().join(',');
|
|
|
|
function svelteFiles(dir: string): string[] {
|
|
return readdirSync(dir).flatMap((name) => {
|
|
const p = join(dir, name);
|
|
return statSync(p).isDirectory() ? svelteFiles(p) : p.endsWith('.svelte') ? [p] : [];
|
|
});
|
|
}
|
|
|
|
describe('catalogues', () => {
|
|
it('en and es have exactly the keys of fr, in order', () => {
|
|
expect(Object.keys(en)).toEqual(Object.keys(fr));
|
|
expect(Object.keys(es)).toEqual(Object.keys(fr));
|
|
});
|
|
it('placeholders are kept', () => {
|
|
for (const k of Object.keys(fr) as (keyof typeof fr)[]) {
|
|
expect(marks(en[k]), `en ${k}`).toBe(marks(fr[k]));
|
|
expect(marks(es[k]), `es ${k}`).toBe(marks(fr[k]));
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('anti-lexicon', () => {
|
|
it('no forbidden term in the French catalogue', () => {
|
|
for (const [k, v] of Object.entries(fr)) {
|
|
for (const term of FORBIDDEN_UI_TERMS) expect(fold(v).includes(fold(term)), `${k}: ${term}`).toBe(false);
|
|
}
|
|
});
|
|
it('no forbidden term in template text of components', () => {
|
|
for (const file of svelteFiles(join(__dirname, '../../src'))) {
|
|
const markup = readFileSync(file, 'utf8')
|
|
.replace(/<script[\s\S]*?<\/script>/g, '')
|
|
.replace(/<style[\s\S]*?<\/style>/g, '')
|
|
.replace(/\{[^}]*\}/g, ' ');
|
|
const text = fold(markup.replace(/<[^>]+>/g, ' '));
|
|
for (const term of FORBIDDEN_UI_TERMS) expect(text.includes(fold(term)), `${file}: ${term}`).toBe(false);
|
|
}
|
|
});
|
|
});
|
|
|
|
// Lot U2 (reviews of M6c and M7): the same words for the same things.
|
|
describe('the reading of the formula', () => {
|
|
it('the settings say, like N1.1 and the formula, that the share falls beyond the quorum', () => {
|
|
expect(fr['formula.reading']).toContain('Au-delà');
|
|
expect(fr['settings.reading']).toContain('au-delà du quorum');
|
|
expect(en['settings.reading']).toContain('beyond the quorum');
|
|
expect(es['settings.reading']).toContain('más allá del quórum');
|
|
});
|
|
});
|
|
|
|
describe('English: one vocabulary', () => {
|
|
it('« Pour » and « Contre » are for and against, never yes and no', () => {
|
|
for (const [k, v] of Object.entries(en)) {
|
|
// What is read, the placeholders ({yes}, {no}: the numbers) left out.
|
|
const shown = v.replace(/\{\w+\}/g, '#');
|
|
expect(shown, k).not.toMatch(/\byes\b/i);
|
|
expect(shown, k).not.toMatch(/“no”|# no\b/);
|
|
}
|
|
});
|
|
it('one spelling, the one that dominates: favour', () => {
|
|
for (const [k, v] of Object.entries(en)) expect(v, k).not.toMatch(/\bfavor\b/i);
|
|
});
|
|
});
|