diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx
index d1e90fd9..0ad1a8e5 100644
--- a/frontend/src/App.test.tsx
+++ b/frontend/src/App.test.tsx
@@ -3,5 +3,5 @@ import { App } from "./App";
test("App renders the shell with create affordance", () => {
render( );
- expect(screen.getByRole("button", { name: /nuova/i })).toBeInTheDocument();
+ expect(screen.getByRole("button", { name: /new/i })).toBeInTheDocument();
});
diff --git a/frontend/src/shell/AppShell.tsx b/frontend/src/shell/AppShell.tsx
index 67754427..5fbe99ac 100644
--- a/frontend/src/shell/AppShell.tsx
+++ b/frontend/src/shell/AppShell.tsx
@@ -61,7 +61,7 @@ export function AppShell() {
ThothII
- Query in linguaggio naturale
+ Datamart Builder with Human In The Loop
@@ -72,7 +72,7 @@ export function AppShell() {
- Sessioni
+ Sessions
@@ -95,8 +95,9 @@ function EmptyState() {
Thoth
II
- Interroga il tuo data warehouse in linguaggio naturale. Crea una nuova
- domanda dal pannello a destra per avviare una sessione guidata.
+ Build datamarts from your data warehouse through a guided,
+ human-in-the-loop workflow. Start a new question from the panel on the
+ right to begin a session.
);
diff --git a/frontend/src/shell/NavSessions.tsx b/frontend/src/shell/NavSessions.tsx
index 0512ae4b..f35f288c 100644
--- a/frontend/src/shell/NavSessions.tsx
+++ b/frontend/src/shell/NavSessions.tsx
@@ -26,7 +26,7 @@ export function NavSessions({ activeSessionId, onSessionSelect }: Props) {
if (sessions.length === 0) {
return (
- Nessuna sessione. Inizia con Nuova domanda .
+ No sessions yet. Start with New question .
);
}
diff --git a/frontend/src/shell/NewSessionDialog.test.tsx b/frontend/src/shell/NewSessionDialog.test.tsx
index 09338401..aa276a3e 100644
--- a/frontend/src/shell/NewSessionDialog.test.tsx
+++ b/frontend/src/shell/NewSessionDialog.test.tsx
@@ -19,10 +19,10 @@ function renderDialog() {
test("the form has only a question field (no workspace/model/provider/thinking)", async () => {
renderDialog();
- await userEvent.click(screen.getByRole("button", { name: /nuova/i }));
- expect(await screen.findByLabelText(/domanda/i)).toBeInTheDocument();
+ await userEvent.click(screen.getByRole("button", { name: /new/i }));
+ expect(await screen.findByLabelText(/question/i)).toBeInTheDocument();
expect(screen.queryByLabelText(/workspace/i)).not.toBeInTheDocument();
- expect(screen.queryByLabelText(/modello/i)).not.toBeInTheDocument();
+ expect(screen.queryByLabelText(/model/i)).not.toBeInTheDocument();
expect(screen.queryByLabelText(/provider/i)).not.toBeInTheDocument();
expect(screen.queryByLabelText(/thinking/i)).not.toBeInTheDocument();
});
@@ -36,9 +36,9 @@ test("submitting posts only { question } and calls onCreated", async () => {
}),
);
const { onCreated } = renderDialog();
- await userEvent.click(screen.getByRole("button", { name: /nuova/i }));
- await userEvent.type(await screen.findByLabelText(/domanda/i), "Quante vendite nel 2025?");
- await userEvent.click(screen.getByRole("button", { name: /^crea$/i }));
+ await userEvent.click(screen.getByRole("button", { name: /new/i }));
+ await userEvent.type(await screen.findByLabelText(/question/i), "Quante vendite nel 2025?");
+ await userEvent.click(screen.getByRole("button", { name: /^create$/i }));
await waitFor(() => expect(body).toEqual({ question: "Quante vendite nel 2025?" }));
await waitFor(() => expect(onCreated).toHaveBeenCalledWith("s1"));
@@ -46,7 +46,7 @@ test("submitting posts only { question } and calls onCreated", async () => {
test("empty question shows a validation error and does not submit", async () => {
renderDialog();
- await userEvent.click(screen.getByRole("button", { name: /nuova/i }));
- await userEvent.click(screen.getByRole("button", { name: /^crea$/i }));
- expect(await screen.findByRole("alert")).toHaveTextContent(/vuota/i);
+ await userEvent.click(screen.getByRole("button", { name: /new/i }));
+ await userEvent.click(screen.getByRole("button", { name: /^create$/i }));
+ expect(await screen.findByRole("alert")).toHaveTextContent(/empty/i);
});
diff --git a/frontend/src/shell/NewSessionDialog.tsx b/frontend/src/shell/NewSessionDialog.tsx
index a21752f5..3a8053a0 100644
--- a/frontend/src/shell/NewSessionDialog.tsx
+++ b/frontend/src/shell/NewSessionDialog.tsx
@@ -23,7 +23,7 @@ export function NewSessionDialog({ onCreated }: Props) {
e.preventDefault();
setError(null);
if (!question.trim()) {
- setError("La domanda non può essere vuota.");
+ setError("The question cannot be empty.");
return;
}
setBusy(true);
@@ -33,7 +33,7 @@ export function NewSessionDialog({ onCreated }: Props) {
setQuestion("");
onCreated(id);
} catch (err) {
- setError(err instanceof Error ? err.message : "Errore nella creazione della sessione.");
+ setError(err instanceof Error ? err.message : "Failed to create the session.");
} finally {
setBusy(false);
}
@@ -47,16 +47,16 @@ export function NewSessionDialog({ onCreated }: Props) {
className="w-full"
onClick={() => setOpen(true)}
>
- Nuova domanda
+ New question
- Nuova sessione
+ New session
diff --git a/frontend/src/shell/SettingsDialog.test.tsx b/frontend/src/shell/SettingsDialog.test.tsx
index 2b33e75c..134a7ebf 100644
--- a/frontend/src/shell/SettingsDialog.test.tsx
+++ b/frontend/src/shell/SettingsDialog.test.tsx
@@ -54,7 +54,7 @@ test("provider change filters the model list", async () => {
const provider = (await screen.findByLabelText(/provider/i)) as HTMLSelectElement;
await userEvent.selectOptions(provider, "anthropic");
- const model = screen.getByLabelText(/modello/i) as HTMLSelectElement;
+ const model = screen.getByLabelText(/model/i) as HTMLSelectElement;
const optionValues = Array.from(model.options).map((o) => o.value);
expect(optionValues).toContain("claude-opus-4-8");
expect(optionValues).not.toContain("glm-5.2");
@@ -65,14 +65,14 @@ test("Salva PUTs the selected settings", async () => {
server.use(
http.put("http://localhost:8787/settings", async ({ request }) => {
body = await request.json();
- return HttpResponse.json(body);
+ return HttpResponse.json({ workspace: "psd", provider: "zai", model: "glm-5.2", thinking: "high" });
}),
);
renderDialog();
await userEvent.click(screen.getByRole("button", { name: /settings/i }));
await screen.findByLabelText(/workspace/i);
await userEvent.selectOptions(screen.getByLabelText(/thinking/i), "high");
- await userEvent.click(screen.getByRole("button", { name: /salva/i }));
+ await userEvent.click(screen.getByRole("button", { name: /save/i }));
await waitFor(() =>
expect(body).toEqual({ workspace: "psd", provider: "zai", model: "glm-5.2", thinking: "high" }),
diff --git a/frontend/src/shell/SettingsDialog.tsx b/frontend/src/shell/SettingsDialog.tsx
index 717700de..19aa4c6e 100644
--- a/frontend/src/shell/SettingsDialog.tsx
+++ b/frontend/src/shell/SettingsDialog.tsx
@@ -76,7 +76,7 @@ export function SettingsDialog() {
await queryClient.invalidateQueries({ queryKey: ["settings"] });
setOpen(false);
} catch (err) {
- setError(err instanceof Error ? err.message : "Errore nel salvataggio dei settings.");
+ setError(err instanceof Error ? err.message : "Failed to save settings.");
} finally {
setBusy(false);
}
@@ -133,7 +133,7 @@ export function SettingsDialog() {
}}
className="w-full rounded-lg border border-input bg-card px-3 py-2 text-sm outline-none transition-colors focus:border-primary/50 focus:ring-3 focus:ring-ring/15"
>
- — tutti —
+ — all —
{providers.map((p) => (
{p}
@@ -146,7 +146,7 @@ export function SettingsDialog() {
type="text"
value={provider}
onChange={(e) => setProvider(e.target.value)}
- placeholder="es. anthropic"
+ placeholder="e.g. anthropic"
className="w-full rounded-lg border border-input bg-card px-3 py-2 text-sm outline-none transition-colors focus:border-primary/50 focus:ring-3 focus:ring-ring/15"
data-testid="provider-freetext"
/>
@@ -155,7 +155,7 @@ export function SettingsDialog() {
- Modello
+ Model
{hasModels ? (
setModel(e.target.value)}
- placeholder="es. glm-5.2"
+ placeholder="e.g. glm-5.2"
className="w-full rounded-lg border border-input bg-card px-3 py-2 text-sm outline-none transition-colors focus:border-primary/50 focus:ring-3 focus:ring-ring/15"
data-testid="model-freetext"
/>
@@ -204,7 +204,7 @@ export function SettingsDialog() {
{!hasModels && (
- Pi non ha restituito modelli (non in esecuzione o nessuna API key): inserimento libero.
+ Pi returned no models (not running or no API key): free text entry.
)}
{error && (
@@ -215,10 +215,10 @@ export function SettingsDialog() {
setOpen(false)}>
- Annulla
+ Cancel
- {busy ? "Salvataggio…" : "Salva"}
+ {busy ? "Saving…" : "Save"}
diff --git a/frontend/src/shell/SteerInput.tsx b/frontend/src/shell/SteerInput.tsx
index 9c3d4527..07d02fc2 100644
--- a/frontend/src/shell/SteerInput.tsx
+++ b/frontend/src/shell/SteerInput.tsx
@@ -32,7 +32,7 @@ export function SteerInput({ sessionId }: Props) {
value={text}
onChange={(e) => setText(e.target.value)}
onKeyDown={handleKeyDown}
- placeholder="Steering libero (!)…"
+ placeholder="Free steering (!)…"
aria-label="Steering"
className="flex-1 bg-transparent px-2 text-sm outline-none placeholder:text-muted-foreground"
/>
@@ -40,7 +40,7 @@ export function SteerInput({ sessionId }: Props) {
size="icon-sm"
onClick={submit}
disabled={!text.trim()}
- aria-label="Invia"
+ aria-label="Send"
>
diff --git a/frontend/src/shell/WidgetHost.tsx b/frontend/src/shell/WidgetHost.tsx
index 0436e357..ca9f4c8c 100644
--- a/frontend/src/shell/WidgetHost.tsx
+++ b/frontend/src/shell/WidgetHost.tsx
@@ -19,8 +19,8 @@ export function WidgetHost({ sessionId }: { sessionId: string | null }) {
level: "error",
text:
err instanceof Error
- ? `Invio risposta fallito: ${err.message}`
- : "Invio risposta fallito.",
+ ? `Failed to send response: ${err.message}`
+ : "Failed to send response.",
});
return;
}
diff --git a/frontend/src/shell/WorkflowBar.tsx b/frontend/src/shell/WorkflowBar.tsx
index c22f5d64..1bfae4da 100644
--- a/frontend/src/shell/WorkflowBar.tsx
+++ b/frontend/src/shell/WorkflowBar.tsx
@@ -2,14 +2,14 @@
import { useSessionStore } from "../store/sessionStore";
const PHASES = [
- { id: "F1", name: "Disambiguazione" },
+ { id: "F1", name: "Disambiguation" },
{ id: "F2", name: "Schema linking" },
- { id: "F3", name: "Esplorazione" },
- { id: "F4", name: "Piano SQL" },
- { id: "F5", name: "Generazione SQL" },
- { id: "F6", name: "Validazione" },
- { id: "F7", name: "Revisione" },
- { id: "F8", name: "Risultati" },
+ { id: "F3", name: "Exploration" },
+ { id: "F4", name: "SQL plan" },
+ { id: "F5", name: "SQL generation" },
+ { id: "F6", name: "Validation" },
+ { id: "F7", name: "Review" },
+ { id: "F8", name: "Results" },
];
export function WorkflowBar() {
@@ -18,7 +18,7 @@ export function WorkflowBar() {
return (
{PHASES.map((p, i) => {
diff --git a/frontend/src/shell/f1-loop.test.tsx b/frontend/src/shell/f1-loop.test.tsx
index 22642404..5356b414 100644
--- a/frontend/src/shell/f1-loop.test.tsx
+++ b/frontend/src/shell/f1-loop.test.tsx
@@ -31,12 +31,12 @@ test("F1: create session -> widget via SSE -> respond -> POST /response", async
render( );
// Open the "Nuova domanda" dialog
- await userEvent.click(screen.getByRole("button", { name: /nuova/i }));
+ await userEvent.click(screen.getByRole("button", { name: /new/i }));
// Fill in the question and submit
- const textarea = await screen.findByLabelText(/domanda/i);
+ const textarea = await screen.findByLabelText(/question/i);
await userEvent.type(textarea, "Quante vendite?");
- await userEvent.click(screen.getByRole("button", { name: /^crea$/i }));
+ await userEvent.click(screen.getByRole("button", { name: /^create$/i }));
// Wait for the session to be created and SSE to connect
await waitFor(() => expect(FakeEventSource.instances).toHaveLength(1));
diff --git a/frontend/src/viewers/ResultsPanel.test.tsx b/frontend/src/viewers/ResultsPanel.test.tsx
index d205e485..191d3cd7 100644
--- a/frontend/src/viewers/ResultsPanel.test.tsx
+++ b/frontend/src/viewers/ResultsPanel.test.tsx
@@ -48,8 +48,8 @@ test("(a) renders grid cells for a 2×2 preview result", async () => {
// Grid must be present, not bold scalar
expect(screen.queryByTestId("scalar-value")).not.toBeInTheDocument();
- // truncated:true → show the "risultati troncati" indicator
- expect(screen.getByText(/risultati troncati/i)).toBeInTheDocument();
+ // truncated:true → show the "results truncated" indicator
+ expect(screen.getByText(/results truncated/i)).toBeInTheDocument();
});
// (b) 1×1 preview → bold scalar shown, no grid
@@ -105,7 +105,7 @@ test("(c) Esporta CSV button calls the export endpoint", async () => {
// Wait for preview to load (use role to avoid ambiguity with paging panel)
await waitFor(() => expect(screen.getAllByRole("gridcell")).not.toHaveLength(0));
- const btn = screen.getByRole("button", { name: /esporta csv/i });
+ const btn = screen.getByRole("button", { name: /export csv/i });
await user.click(btn);
await waitFor(() => expect(exportCalled).toBe(true));
@@ -136,9 +136,9 @@ test("(d) selecting tutti re-fetches preview with the large limit", async () =>
// Initial fetch uses limit 10
await waitFor(() => expect(limits).toContain(10));
- // Select "tutti"
- const select = screen.getByLabelText(/righe da visualizzare/i);
- await user.selectOptions(select, "tutti");
+ // Select "all"
+ const select = screen.getByLabelText(/rows to display/i);
+ await user.selectOptions(select, "all");
// A re-fetch with the large/unlimited limit must occur
await waitFor(() => expect(limits.some((l) => (l as number) > 10)).toBe(true));
diff --git a/frontend/src/viewers/ResultsPanel.tsx b/frontend/src/viewers/ResultsPanel.tsx
index 3200d9c7..f09e481d 100644
--- a/frontend/src/viewers/ResultsPanel.tsx
+++ b/frontend/src/viewers/ResultsPanel.tsx
@@ -47,20 +47,20 @@ export function ResultsPanel({ sessionId }: Props) {
- setLimit(e.target.value === "tutti" ? 1_000_000 : Number(e.target.value))
+ setLimit(e.target.value === "all" ? 1_000_000 : Number(e.target.value))
}
- aria-label="Righe da visualizzare"
+ aria-label="Rows to display"
>
10
- tutti
+ all
- Esporta CSV
+ Export CSV
{/* Loading / error states */}
- {isLoading && Caricamento...
}
- {error && Errore: {String(error)}
}
+ {isLoading && Loading…
}
+ {error && Error: {String(error)}
}
{/* Scalar result: 1 col × 1 row → bold value */}
{data && isScalar && (
@@ -73,7 +73,7 @@ export function ResultsPanel({ sessionId }: Props) {
- {data.truncated && (risultati troncati)
}
+ {data.truncated && (results truncated)
}
>
)}
diff --git a/frontend/src/viewers/SchemaLinkingViewer.test.tsx b/frontend/src/viewers/SchemaLinkingViewer.test.tsx
index 7651d2a9..9ae5c0d3 100644
--- a/frontend/src/viewers/SchemaLinkingViewer.test.tsx
+++ b/frontend/src/viewers/SchemaLinkingViewer.test.tsx
@@ -42,7 +42,7 @@ test("(b) clicking toggle switches to table listing a promoted table name", asyn
// wait for mermaid to load
await waitFor(() => expect(screen.getByTestId("mm")).toBeInTheDocument());
- const toggle = screen.getByRole("button", { name: /tabella/i });
+ const toggle = screen.getByRole("button", { name: /table/i });
await userEvent.click(toggle);
expect(screen.getByText("orders")).toBeInTheDocument();
@@ -52,7 +52,7 @@ test("(b) clicking toggle switches to table listing a promoted table name", asyn
test("(c) oversized linking (>45) shows cap notice", () => {
render( );
expect(
- screen.getByText(/troppi elementi per il grafico/i)
+ screen.getByText(/too many elements for the graph/i)
).toBeInTheDocument();
});
diff --git a/frontend/src/viewers/SchemaLinkingViewer.tsx b/frontend/src/viewers/SchemaLinkingViewer.tsx
index c0b9ea24..32b3fc57 100644
--- a/frontend/src/viewers/SchemaLinkingViewer.tsx
+++ b/frontend/src/viewers/SchemaLinkingViewer.tsx
@@ -109,19 +109,19 @@ export function SchemaLinkingViewer({ linking }: { linking: SchemaLinking }) {
disabled={oversized}
className={view === "chart" ? "font-bold" : ""}
>
- Grafico
+ Graph
setView("table")}
className={view === "table" ? "font-bold" : ""}
>
- Tabella
+ Table
{oversized && (
- Troppi elementi per il grafico, usa la tabella
+ Too many elements for the graph, use the table
)}
@@ -137,9 +137,9 @@ export function SchemaLinkingViewer({ linking }: { linking: SchemaLinking }) {
- Nome
- Tipo
- Perché
+ Name
+ Type
+ Why
@@ -147,7 +147,7 @@ export function SchemaLinkingViewer({ linking }: { linking: SchemaLinking }) {
{table.name}
- tabella
+ table
{reasonFor(table)}
@@ -157,7 +157,7 @@ export function SchemaLinkingViewer({ linking }: { linking: SchemaLinking }) {
{col.name}
- colonna
+ column
{reasonFor(col)}
@@ -170,7 +170,7 @@ export function SchemaLinkingViewer({ linking }: { linking: SchemaLinking }) {
{col.name}
- colonna
+ column
{reasonFor(col)}
diff --git a/frontend/src/viewers/SqlViewer.test.tsx b/frontend/src/viewers/SqlViewer.test.tsx
index 4f623b1b..8e58b60e 100644
--- a/frontend/src/viewers/SqlViewer.test.tsx
+++ b/frontend/src/viewers/SqlViewer.test.tsx
@@ -71,16 +71,16 @@ test("(c) layout toggle flips its label between Orizzontale and Verticale", asyn
await waitFor(() => expect(screen.getAllByTestId("hl")).toHaveLength(2));
// Default layout is vertical, so the toggle offers "Orizzontale".
- const toggle = screen.getByRole("button", { name: /orizzontale/i });
+ const toggle = screen.getByRole("button", { name: /horizontal/i });
expect(toggle).toBeInTheDocument();
await userEvent.click(toggle);
// After switching to horizontal, the toggle now offers "Verticale".
expect(
- screen.getByRole("button", { name: /verticale/i })
+ screen.getByRole("button", { name: /vertical/i })
).toBeInTheDocument();
expect(
- screen.queryByRole("button", { name: /orizzontale/i })
+ screen.queryByRole("button", { name: /horizontal/i })
).not.toBeInTheDocument();
});
diff --git a/frontend/src/viewers/SqlViewer.tsx b/frontend/src/viewers/SqlViewer.tsx
index d22709f9..5b95a6f9 100644
--- a/frontend/src/viewers/SqlViewer.tsx
+++ b/frontend/src/viewers/SqlViewer.tsx
@@ -101,7 +101,7 @@ export function SqlViewer({ blocks }: { blocks: SqlBlock[] }) {
setLayout((l) => (l === "vertical" ? "horizontal" : "vertical"))
}
>
- {layout === "vertical" ? "Orizzontale" : "Verticale"}
+ {layout === "vertical" ? "Horizontal" : "Vertical"}
diff --git a/frontend/src/widgets/ArtifactGateWidget.test.tsx b/frontend/src/widgets/ArtifactGateWidget.test.tsx
index 5e68299d..1facd7da 100644
--- a/frontend/src/widgets/ArtifactGateWidget.test.tsx
+++ b/frontend/src/widgets/ArtifactGateWidget.test.tsx
@@ -49,6 +49,6 @@ test("reserved control responds with control field", async () => {
onRespond={onRespond}
/>
);
- await userEvent.click(screen.getByRole("button", { name: /indietro/i }));
+ await userEvent.click(screen.getByRole("button", { name: /back/i }));
expect(onRespond).toHaveBeenCalledWith({ id: "u1", control: "back" });
});
diff --git a/frontend/src/widgets/FallbackWidget.tsx b/frontend/src/widgets/FallbackWidget.tsx
index bc937334..8ce63d4c 100644
--- a/frontend/src/widgets/FallbackWidget.tsx
+++ b/frontend/src/widgets/FallbackWidget.tsx
@@ -5,10 +5,10 @@ export function FallbackWidget({ descriptor, onRespond }: WidgetProps) {
const [text, setText] = useState("");
return (
-
Widget non supportato (kind: {descriptor.widget}) — rispondi manualmente
+
Unsupported widget (kind: {descriptor.widget}) — respond manually
{JSON.stringify(descriptor, null, 2)}
setText(e.target.value)} />
- onRespond({ id: descriptor.id, control: "freetext", text })}>Invia
+ onRespond({ id: descriptor.id, control: "freetext", text })}>Send
);
}
diff --git a/frontend/src/widgets/FreetextWidget.test.tsx b/frontend/src/widgets/FreetextWidget.test.tsx
index 64db4be6..665ae121 100644
--- a/frontend/src/widgets/FreetextWidget.test.tsx
+++ b/frontend/src/widgets/FreetextWidget.test.tsx
@@ -5,6 +5,6 @@ test("submits typed text", async () => {
const onRespond = vi.fn();
render( );
await userEvent.type(screen.getByRole("textbox"), "ciao");
- await userEvent.click(screen.getByRole("button", { name: /invia/i }));
+ await userEvent.click(screen.getByRole("button", { name: /send/i }));
expect(onRespond).toHaveBeenCalledWith({ id: "u1", kind: "freetext", text: "ciao" });
});
diff --git a/frontend/src/widgets/FreetextWidget.tsx b/frontend/src/widgets/FreetextWidget.tsx
index 178c4844..ae1d1655 100644
--- a/frontend/src/widgets/FreetextWidget.tsx
+++ b/frontend/src/widgets/FreetextWidget.tsx
@@ -6,7 +6,7 @@ export function FreetextWidget({ descriptor, onRespond }: WidgetProps) {
{descriptor.title &&
{descriptor.title}
}
setText(e.target.value)} />
- onRespond({ id: descriptor.id, kind: "freetext", text })}>Invia
+ onRespond({ id: descriptor.id, kind: "freetext", text })}>Send
);
}
diff --git a/frontend/src/widgets/MultiselectWidget.test.tsx b/frontend/src/widgets/MultiselectWidget.test.tsx
index 19b47658..97d93b2b 100644
--- a/frontend/src/widgets/MultiselectWidget.test.tsx
+++ b/frontend/src/widgets/MultiselectWidget.test.tsx
@@ -18,7 +18,7 @@ test("confirms the checked ids including initially selected", async () => {
/>
);
await userEvent.click(screen.getByRole("checkbox", { name: /t2/ }));
- await userEvent.click(screen.getByRole("button", { name: /conferma/i }));
+ await userEvent.click(screen.getByRole("button", { name: /confirm/i }));
expect(onRespond).toHaveBeenCalledWith({ id: "u1", kind: "multiselect", choices: ["t1", "t2"] });
});
@@ -37,8 +37,8 @@ test("select-all checks all options", async () => {
onRespond={onRespond}
/>
);
- await userEvent.click(screen.getByRole("button", { name: /seleziona tutti/i }));
- await userEvent.click(screen.getByRole("button", { name: /conferma/i }));
+ await userEvent.click(screen.getByRole("button", { name: /select all/i }));
+ await userEvent.click(screen.getByRole("button", { name: /confirm/i }));
expect(onRespond).toHaveBeenCalledWith({ id: "u1", kind: "multiselect", choices: ["a", "b"] });
});
@@ -57,8 +57,8 @@ test("deselect-all unchecks all options", async () => {
onRespond={onRespond}
/>
);
- await userEvent.click(screen.getByRole("button", { name: /deseleziona tutti/i }));
- await userEvent.click(screen.getByRole("button", { name: /conferma/i }));
+ await userEvent.click(screen.getByRole("button", { name: /deselect all/i }));
+ await userEvent.click(screen.getByRole("button", { name: /confirm/i }));
expect(onRespond).toHaveBeenCalledWith({ id: "u1", kind: "multiselect", choices: [] });
});
@@ -75,7 +75,7 @@ test("confirm is disabled when nothing checked and allow_empty is false", async
onRespond={onRespond}
/>
);
- const btn = screen.getByRole("button", { name: /conferma/i });
+ const btn = screen.getByRole("button", { name: /confirm/i });
expect(btn).toBeDisabled();
await userEvent.click(btn);
expect(onRespond).not.toHaveBeenCalled();
@@ -97,9 +97,9 @@ test("deselect-all with allow_empty false disables Conferma (empty confirm impos
onRespond={onRespond}
/>
);
- const btn = screen.getByRole("button", { name: /conferma/i });
+ const btn = screen.getByRole("button", { name: /confirm/i });
expect(btn).not.toBeDisabled();
- await userEvent.click(screen.getByRole("button", { name: /deseleziona tutti/i }));
+ await userEvent.click(screen.getByRole("button", { name: /deselect all/i }));
expect(btn).toBeDisabled();
await userEvent.click(btn);
expect(onRespond).not.toHaveBeenCalled();
@@ -118,7 +118,7 @@ test("confirm is enabled when allow_empty is false but something is checked", as
onRespond={onRespond}
/>
);
- const btn = screen.getByRole("button", { name: /conferma/i });
+ const btn = screen.getByRole("button", { name: /confirm/i });
expect(btn).not.toBeDisabled();
await userEvent.click(btn);
expect(onRespond).toHaveBeenCalledWith({ id: "u1", kind: "multiselect", choices: ["x"] });
diff --git a/frontend/src/widgets/MultiselectWidget.tsx b/frontend/src/widgets/MultiselectWidget.tsx
index 67f621ba..38caf8c7 100644
--- a/frontend/src/widgets/MultiselectWidget.tsx
+++ b/frontend/src/widgets/MultiselectWidget.tsx
@@ -32,7 +32,7 @@ export function MultiselectWidget({ descriptor, onRespond }: WidgetProps) {
{descriptor.title && {descriptor.title}
}
- {allChecked ? "Deseleziona tutti" : "Seleziona tutti"}
+ {allChecked ? "Deselect all" : "Select all"}
@@ -52,7 +52,7 @@ export function MultiselectWidget({ descriptor, onRespond }: WidgetProps) {
disabled={isDisabled}
onClick={() => onRespond({ id: descriptor.id, kind: "multiselect", choices: Array.from(checked) })}
>
- Conferma
+ Confirm
);
diff --git a/frontend/src/widgets/ReservedControls.tsx b/frontend/src/widgets/ReservedControls.tsx
index cdbfc740..7311733a 100644
--- a/frontend/src/widgets/ReservedControls.tsx
+++ b/frontend/src/widgets/ReservedControls.tsx
@@ -1,4 +1,4 @@
-const LABELS: Record = { back: "Torna indietro", exit: "Esci", other: "Altro — specifica" };
+const LABELS: Record = { back: "Go back", exit: "Exit", other: "Other — specify" };
export function ReservedControls({ reserved, onControl }: { reserved?: string[]; onControl: (c: string) => void }) {
if (!reserved?.length) return null;
return {reserved.map((c) => (
diff --git a/frontend/src/widgets/SelectWidget.test.tsx b/frontend/src/widgets/SelectWidget.test.tsx
index f3c807f7..aaf9afa9 100644
--- a/frontend/src/widgets/SelectWidget.test.tsx
+++ b/frontend/src/widgets/SelectWidget.test.tsx
@@ -12,6 +12,6 @@ test("picking an option responds with its id", async () => {
test("a reserved control responds with control, not a choice", async () => {
const onRespond = vi.fn();
render( );
- await userEvent.click(screen.getByRole("button", { name: /indietro/i }));
+ await userEvent.click(screen.getByRole("button", { name: /back/i }));
expect(onRespond).toHaveBeenCalledWith({ id: "u1", control: "back" });
});
diff --git a/frontend/src/widgets/linkage.test.tsx b/frontend/src/widgets/linkage.test.tsx
index c044a1ea..18f503d4 100644
--- a/frontend/src/widgets/linkage.test.tsx
+++ b/frontend/src/widgets/linkage.test.tsx
@@ -24,7 +24,7 @@ test("reject opens a freetext and combines the reason", async () => {
);
await userEvent.click(screen.getByRole("button", { name: /Rifiuta/ }));
await userEvent.type(screen.getByRole("textbox"), "join sbagliata");
- await userEvent.click(screen.getByRole("button", { name: /invia/i }));
+ await userEvent.click(screen.getByRole("button", { name: /send/i }));
expect(onRespond).toHaveBeenCalledWith({
id: "u1",
kind: "artifact-gate",
diff --git a/frontend/src/widgets/registry.test.tsx b/frontend/src/widgets/registry.test.tsx
index e1591e0a..34b605cf 100644
--- a/frontend/src/widgets/registry.test.tsx
+++ b/frontend/src/widgets/registry.test.tsx
@@ -11,5 +11,5 @@ test("resolve returns the registered renderer", () => {
test("resolve falls back for unknown kind and shows the JSON", () => {
const Comp = resolve("totally-unknown");
render( {}} />);
- expect(screen.getByText(/Widget non supportato/i)).toBeInTheDocument();
+ expect(screen.getByText(/Unsupported widget/i)).toBeInTheDocument();
});