Files
govoplan-portal/webui/scripts/test-translations.mjs
T
zemion 2f5a69034a fix(i18n): complete Portal German headings and contextual help
Verified with the coordinated workspace changes by devkit full run
2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed).
This shared UI pass does not mark the individual module reviews complete.
2026-09-09 02:03:59 +02:00

86 lines
3.9 KiB
JavaScript
Executable File

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { createRequire } from "node:module";
import { resolve } from "node:path";
import { test } from "node:test";
const webui = resolve(import.meta.dirname, "..");
const core = resolve(webui, "../../govoplan-core/webui");
const require = createRequire(resolve(core, "package.json"));
const { buildSync } = require("esbuild");
const expected = {
"My function postboxes": "Meine Funktionspostfächer",
"Sign in to view status": "Anmelden, um den Status anzuzeigen",
"Request a short-lived status link": "Kurzlebigen Statuslink anfordern",
"Timeline": "Verlauf",
};
// Exercise the real locale provider and shared Card contract. Compile in memory:
// no server, shared build directory, optional module imports, or browser effects.
const { outputFiles } = buildSync({
stdin: {
contents: `
import { renderToStaticMarkup } from 'react-dom/server';
import { generatedTranslations } from ${JSON.stringify(resolve(webui, "src/i18n/generatedTranslations.ts"))};
import { PlatformLanguageProvider, usePlatformLanguage } from ${JSON.stringify(resolve(core, "src/i18n/LanguageContext.tsx"))};
import Card from ${JSON.stringify(resolve(core, "src/components/Card.tsx"))};
export const catalog = generatedTranslations;
function NativeHeading({ label }) {
const { translateText } = usePlatformLanguage();
return <h2 id="portal-postboxes-heading">{translateText(label)}</h2>;
}
export function heading(language, label, native) {
return renderToStaticMarkup(
<PlatformLanguageProvider preferredLanguageCode={language} moduleTranslations={[catalog]}>
{native ? <NativeHeading label={label} /> : <Card title={label}>Fixture</Card>}
</PlatformLanguageProvider>
);
}
`,
loader: "tsx",
resolveDir: core,
},
bundle: true,
write: false,
platform: "node",
format: "cjs",
jsx: "automatic",
external: ["react", "react-dom/server"],
logLevel: "silent",
});
const compiled = { exports: {} };
new Function("require", "module", "exports", outputFiles[0].text)(require, compiled, compiled.exports);
const { catalog, heading } = compiled.exports;
test("Portal registers and owns all four translations", () => {
const module = readFileSync(resolve(webui, "src/module.ts"), "utf8");
assert.match(module, /import\s*\{\s*generatedTranslations\s*\}\s*from\s*["']\.\/i18n\/generatedTranslations["']/);
assert.match(module, /translations:\s*generatedTranslations/);
for (const [english, german] of Object.entries(expected)) {
assert.equal(catalog.en[english], english);
assert.equal(catalog.de[english], german);
}
});
test("each heading renders in English and German without the DOM translation bridge", () => {
for (const [english, german] of Object.entries(expected)) {
for (const [language, translation] of [["en", english], ["de", german]]) {
const native = english === "My function postboxes";
const markup = heading(language, english, native);
const tag = native ? '<h2 id="portal-postboxes-heading">' : "<h2>";
assert.ok(markup.includes(`${tag}${translation}</h2>`), `${language}: ${english}`);
if (language === "de") assert.ok(!markup.includes(`>${english}</h2>`));
}
}
});
test("Portal pages keep the verified native-heading and shared-card translation paths", () => {
const directory = readFileSync(resolve(webui, "src/features/portal/PortalPage.tsx"), "utf8");
assert.match(directory, /const\s*\{\s*translateText\s*\}\s*=\s*usePlatformLanguage\(\)/);
assert.ok(directory.includes('<h2 id="portal-postboxes-heading">{translateText("My function postboxes")}</h2>'));
const status = readFileSync(resolve(webui, "src/features/portal/PortalStatusPage.tsx"), "utf8");
for (const english of Object.keys(expected).slice(1)) {
assert.ok(status.includes(`<Card title="${english}"`), `Shared card title: ${english}`);
}
});