portofel / client / test / i18n.test.mjs
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// The three catalogs, held to each other and to the money-word contract —
// plus portofel's own rule: this is a WALLET, and no catalog may talk like a
// chat room.

import test from "node:test";
import assert from "node:assert/strict";
import * as L from "../test-dist/testlib.js";

const LANGS = ["en", "ro", "hu"];

test("the three catalogs carry exactly the same keys", () => {
  const en = [...L.catalogKeys("en")];
  for (const lang of ["ro", "hu"]) {
    assert.deepEqual([...L.catalogKeys(lang)], en, `en vs ${lang}`);
  }
});

test("no catalog says the word the protocol forbids a screen to say", () => {
  // banca's rule, inherited whole: the fold's own word for not-yet-pinned
  // money is `settled`, and in every other financial interface that word
  // means "done". It reaches no screen. English word-boundary checks; ro/hu
  // are held to the key parity above and to review.
  for (const k of [...L.catalogKeys("en")]) {
    const v = L.catalogValue("en", k);
    const text = typeof v === "string" ? v : Object.values(v).join(" ");
    assert.ok(!/\bsettled\b/i.test(text), `${k} says "settled"`);
  }
});

test("a wallet does not talk like a chat room", () => {
  // The screen-shape rule made checkable: no EN value (nor key) reaches for
  // the rooms-line vocabulary. "bank" is the noun here; a "room" is an
  // implementation detail no user of a wallet should meet.
  for (const k of [...L.catalogKeys("en")]) {
    const v = L.catalogValue("en", k);
    const text = typeof v === "string" ? v : Object.values(v).join(" ");
    for (const word of [/\broom(s)?\b/i, /\bchat\b/i, /\bmessage(s)?\b/i]) {
      assert.ok(!word.test(text), `${k} says ${word}: "${text}"`);
      assert.ok(!word.test(k), `key ${k} is room/chat-shaped`);
    }
  }
});

test("every outstanding-money word ships with its sentence", () => {
  // The three totals are three different claims, and each word must carry its
  // meaning beside it — a chip reading "provisional" with the reason parked in
  // a tooltip is the same lie with an extra step.
  for (const lang of LANGS) {
    const keys = new Set(L.catalogKeys(lang));
    for (const word of ["provisional", "unpinned", "locked"]) {
      assert.ok(keys.has(`wallet.${word}`), `${lang}: wallet.${word}`);
      assert.ok(keys.has(`wallet.${word}.warn`), `${lang}: wallet.${word}.warn`);
    }
  }
});

test("the six state words exist in every language", () => {
  for (const lang of LANGS) {
    const keys = new Set(L.catalogKeys(lang));
    for (const s of ["final", "provisional", "unpinned", "failed", "locked", "returned"]) {
      assert.ok(keys.has(`pay.state.${s}`), `${lang}: pay.state.${s}`);
    }
  }
});

test("every placeholder an English string uses exists in the translations", () => {
  // A translation may REORDER placeholders, never lose or invent one.
  const ph = (s) => [...String(s).matchAll(/\{(\w+)\}/g)].map((m) => m[1]).sort();
  for (const k of [...L.catalogKeys("en")]) {
    const en = L.catalogValue("en", k);
    for (const lang of ["ro", "hu"]) {
      const tr = L.catalogValue(lang, k);
      if (typeof en === "string" && typeof tr === "string") {
        assert.deepEqual(ph(tr), ph(en), `${lang}:${k}`);
      } else if (typeof en === "object" && typeof tr === "object") {
        // plural maps: every variant must use the union of the en variants'
        // placeholders — {n} may legitimately vanish in a "one" form
        const enAll = [...new Set(Object.values(en).flatMap((s) => ph(s)))].sort();
        for (const [variant, s] of Object.entries(tr)) {
          for (const p of ph(s)) {
            assert.ok(enAll.includes(p), `${lang}:${k}.${variant} invents {${p}}`);
          }
        }
      }
    }
  }
});

static mirror of HEAD · about · clone: git clone https://git.ardegazu.ro/portofel.git