* fix(web): use English Lingui sources for German UI text
Several web surfaces hard-coded German (the project card, roster and
activity status labels, the sidebar "Heute" label) or used German text as
the Lingui source message (sidebar sections, project timeline, bot picker,
voice entry, group stage, copy and read-aloud buttons). English users saw
German, and because production builds keep only message ids, none of these
strings could be translated per locale.
Convert them to English source messages, keeping the meaning:
- ProjectCreatedCard: Lingui Trans/Plural instead of literals.
- agent-activity: labels go through i18n._ with literal ids so the module
stays importable from plain unit tests; the extractor still collects them.
- Shell, ProjectSessionTimeline, bot-picker, StageVoiceEntry, OoStage:
English sources, reusing existing messages where one already fit
("just now", "{n}m ago", "Search", "No bots match", "Set up voice",
"Group conversation", "Transcript").
- The conversation picker matches its create entry against the translated
label instead of a fixed German string.
The German wording returns through the de catalog in the next commit.
Unit and E2E tests now assert the English labels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
* feat(web): keep Lingui catalogs complete and in sync
The committed catalogs were last extracted weeks ago: about 330 source
messages were missing from every locale, and production builds keep only
message ids, so those strings rendered as hash ids (sidebar sections,
privacy settings, profile, timeline, ...). German also had 226 empty
entries, and every extraction rewrote the files because references carried
line numbers.
- lingui.config.ts: po references without line numbers, and a stable sort
that breaks Lingui's ordering ties (explicit ids, equal text) by id, so
the output no longer depends on file-system order.
- Re-extract all catalogs with --clean (drops 25-44 obsolete entries per
locale; no existing translation changed).
- Translate every German entry (du form, consistent with the existing
catalog). Other locales keep empty entries and fall back to English.
- i18n-catalog-sync.test.ts extracts into a copy of the catalogs and fails
when the committed files differ or a German entry is empty, so stale
catalogs fail the unit test job (offline, about 5 s).
Adds @lingui/format-po (already installed through @lingui/cli) as a direct
dev dependency to configure the formatter.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
* test(web): find the sidebar Today button by its English label
The shell contrast test added on main looks up the sidebar button by the
old German source text, which this branch replaces with "Today".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
* chore(web): extract catalogs and translate the in-app browser strings
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
* test: look up the home main conversation in the scheduling journey
Since every project has its own main conversation, the journey that
schedules for a specialist found the user's main conversation with
findFirst over all of them. With the Lab project's conversation also
matching, it picked either one, so the check failed about one run in
three. The lookup now names the home space, where the specialist joined
and the routine is created.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u
---------
Co-authored-by: Claude <noreply@anthropic.com>
50 lines
1.5 KiB
TypeScript
50 lines
1.5 KiB
TypeScript
/**
|
|
* Smoke test: verify the app loads without React errors.
|
|
*
|
|
* This test ensures that the Vite build resolves a single React
|
|
* instance (no duplicate React versions from pnpm transitive deps).
|
|
*/
|
|
import { expect, test } from "@playwright/test";
|
|
|
|
test("app loads without React hook errors", async ({ page }) => {
|
|
const consoleErrors: string[] = [];
|
|
const pageErrors: string[] = [];
|
|
|
|
page.on("console", (msg) => {
|
|
if (msg.type() === "error") consoleErrors.push(msg.text());
|
|
});
|
|
page.on("pageerror", (err) => {
|
|
pageErrors.push(err.message);
|
|
});
|
|
|
|
await page.goto("/app", { waitUntil: "domcontentloaded", timeout: 10_000 });
|
|
await page.waitForTimeout(5000);
|
|
|
|
// The critical check: no "Invalid hook call" or related React errors
|
|
const hookErrors = pageErrors.filter(
|
|
(error) =>
|
|
error.includes("Invalid hook call") ||
|
|
error.includes("useMemo") ||
|
|
error.includes("useRef") ||
|
|
error.includes("useContext") ||
|
|
error.includes("more than one copy of React"),
|
|
);
|
|
|
|
expect(hookErrors).toEqual([]);
|
|
|
|
// Root element must exist
|
|
await expect(page.locator("#root")).toBeAttached();
|
|
|
|
// Should show either login form or app content (not a blank/dark screen)
|
|
const bodyText = await page.evaluate(() => document.body?.innerText || "");
|
|
const hasContent =
|
|
bodyText.includes("Sign in") ||
|
|
bodyText.includes("Anmelden") ||
|
|
bodyText.includes("EvOo") ||
|
|
bodyText.includes("Projects") ||
|
|
bodyText.includes("Today") ||
|
|
bodyText.includes("Team");
|
|
|
|
expect(hasContent).toBe(true);
|
|
});
|