mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 05:42:19 +00:00
test(i18n): give the per-locale copy guards their pt-BR vocabulary
The delete-confirmation, sleep-debt, mood-prognosis, MCP-token and AI-consent guards match each locale against its own phrases, and the sharing-boundary guard against the word for account; pt-BR now has them. The locale-count floors read nine, and the managed-profile picker test counts the locale list instead of a literal.
This commit is contained in:
1 parent
71123e5fae
commit
51f7d38b3c
6 files changed
+38
-10
No files matched your search
@@ -92,6 +92,13 @@ const FINALITY_PHRASES: Record<string, readonly string[]> = {
|
||||
pl: ["nie można cofnąć", "nie można tego cofnąć", "trwale", "nieodwracaln"],
|
||||
ko: ["되돌릴 수 없", "복구할 수 없", "영구", "완전히 삭제"],
|
||||
nl: ["niet ongedaan", "definitief", "permanent", "onherroepelijk"],
|
||||
"pt-BR": [
|
||||
"não pode ser desfeit",
|
||||
"não é possível desfazer",
|
||||
"permanentemente",
|
||||
"definitivamente",
|
||||
"irreversível",
|
||||
],
|
||||
};
|
||||
|
||||
/** Per-locale phrase that promises the short undo window. */
|
||||
@@ -104,6 +111,7 @@ const UNDO_PHRASES: Record<string, string> = {
|
||||
pl: "cofnąć",
|
||||
ko: "되돌릴 수 있",
|
||||
nl: "ongedaan maken",
|
||||
"pt-BR": "desfazer",
|
||||
};
|
||||
|
||||
/** Confirmation bodies whose surface renders an Undo affordance. */
|
||||
@@ -189,6 +197,7 @@ describe("sleep debt is labelled as a balance, not a summed deficit", () => {
|
||||
pl: ["skumulowan", "niedobór", "niedoboru"],
|
||||
ko: ["누적", "부족분", "적자", "쌓인"],
|
||||
nl: ["cumulatief", "opgeteld", "tekort", "opgebouwd"],
|
||||
"pt-BR": ["acumulad", "déficit", "deficit", "somad"],
|
||||
};
|
||||
|
||||
for (const locale of LOCALES) {
|
||||
@@ -326,6 +335,17 @@ describe("the mood prognosis never states a cause", () => {
|
||||
"verlaagt je",
|
||||
"verhoogt je",
|
||||
],
|
||||
"pt-BR": [
|
||||
"porque",
|
||||
"por causa de",
|
||||
"devido a",
|
||||
"provoca",
|
||||
"leva a",
|
||||
"melhora o seu",
|
||||
"melhora a sua",
|
||||
"piora o seu",
|
||||
"piora a sua",
|
||||
],
|
||||
};
|
||||
|
||||
/** Every leaf string under `insights.mood.prognosis`, flattened. */
|
||||
@@ -430,6 +450,12 @@ describe("the MCP token copy never claims the mint is read-only", () => {
|
||||
"alleen-lezentoken",
|
||||
"token met alleen leesrechten",
|
||||
],
|
||||
"pt-BR": [
|
||||
"token somente leitura",
|
||||
"token de somente leitura",
|
||||
"token só de leitura",
|
||||
"token apenas de leitura",
|
||||
],
|
||||
};
|
||||
|
||||
for (const locale of LOCALES) {
|
||||
@@ -480,6 +506,7 @@ describe("AI consent withdrawal copy matches what withdrawing does", () => {
|
||||
pl: ["własnym kluczu", "lokalnym modelu"],
|
||||
ko: ["자신의 키", "로컬 모델"],
|
||||
nl: ["eigen sleutel", "lokaal model"],
|
||||
"pt-BR": ["sua própria chave", "modelo local"],
|
||||
};
|
||||
|
||||
for (const locale of LOCALES) {
|
||||
|
||||
@@ -105,7 +105,7 @@ describe("the published boundary matches the one the code draws", () => {
|
||||
expect(accessDescription()).toMatch(/allergies, family history/i);
|
||||
});
|
||||
|
||||
it("keeps the refusal paragraph honest in all six locales", () => {
|
||||
it("keeps the refusal paragraph honest in every locale", () => {
|
||||
// The delegate-facing half. It is shown on a page sharing does NOT cover,
|
||||
// so a sentence that over-claims there is read at the exact moment
|
||||
// somebody is working out where the edge is.
|
||||
@@ -125,7 +125,7 @@ describe("the published boundary matches the one the code draws", () => {
|
||||
// And it must still say the account itself stays with its owner —
|
||||
// dropping that would fix one over-claim by removing the boundary.
|
||||
expect(text, locale).toMatch(
|
||||
/konto|account|compte|cuenta|konta|koncie|계정/i,
|
||||
/konto|account|compte|cuenta|konta|koncie|conta|계정/i,
|
||||
);
|
||||
}
|
||||
expect(missing).toEqual([]);
|
||||
|
||||
@@ -223,9 +223,9 @@ const FULL_RECORD = {
|
||||
const DOTTED_KEY = /\b[a-z][A-Za-z0-9]*(\.[A-Za-z0-9_]+){2,}\b/g;
|
||||
|
||||
describe("<ClinicianView> resolves every label in every locale", () => {
|
||||
it("covers all eight shipped locales", () => {
|
||||
it("covers all nine shipped locales", () => {
|
||||
// A floor: an empty locale list would make the loop below assert nothing.
|
||||
expect(locales.length).toBe(8);
|
||||
expect(locales.length).toBe(9);
|
||||
});
|
||||
|
||||
for (const locale of locales) {
|
||||
|
||||
@@ -34,6 +34,7 @@ import { join } from "node:path";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { locales } from "@/lib/i18n/config";
|
||||
import { I18nProvider } from "@/lib/i18n/context";
|
||||
import { ApiError } from "@/lib/api/api-fetch";
|
||||
import type { AccountAccessEntry } from "@/lib/sharing/account-access-view";
|
||||
@@ -285,12 +286,12 @@ describe("the managed-profile card, in the shared-access section", () => {
|
||||
}
|
||||
// The timezone control is the shared picker, which labels itself.
|
||||
expect(html).toContain('id="managed-profile-timezone"');
|
||||
// Eight languages offered, which is the route's enum exactly.
|
||||
// Every shipped language offered, which is the route's enum exactly.
|
||||
const options =
|
||||
/<select[^>]*data-slot="managed-profile-locale"[\s\S]*?<\/select>/
|
||||
.exec(html)?.[0]
|
||||
.match(/<option/g) ?? [];
|
||||
expect(options).toHaveLength(8);
|
||||
expect(options).toHaveLength(locales.length);
|
||||
// Four sex options, and the first is the empty one: null is a real answer
|
||||
// ("not recorded") rather than an absent field, and a form offering only
|
||||
// the three enum members would make it unsayable.
|
||||
|
||||
@@ -73,10 +73,10 @@ const VALUE_GROUPS: Array<{ group: string; keys: readonly string[] }> = [
|
||||
];
|
||||
|
||||
describe("mood context vocabulary labels", () => {
|
||||
it("reads eight locales and a non-empty vocabulary", () => {
|
||||
it("reads nine locales and a non-empty vocabulary", () => {
|
||||
// Both ends have to be there before anything below proves anything. A
|
||||
// guard that walks an empty list is a green light nobody earned.
|
||||
expect(LOCALES.length).toBe(8);
|
||||
expect(LOCALES.length).toBe(9);
|
||||
expect(VALUE_GROUPS.length).toBeGreaterThan(0);
|
||||
const total = VALUE_GROUPS.reduce((n, g) => n + g.keys.length, 0);
|
||||
expect(total).toBeGreaterThan(30);
|
||||
|
||||
@@ -186,8 +186,8 @@ describe("connect-source state copy", () => {
|
||||
) as Record<string, never>,
|
||||
}));
|
||||
|
||||
it("covers all eight locales", () => {
|
||||
expect(LOCALES.length).toBe(8);
|
||||
it("covers all nine locales", () => {
|
||||
expect(LOCALES.length).toBe(9);
|
||||
});
|
||||
|
||||
it.each(LOCALES)(
|
||||
|
||||
Reference in new issue
Block a user