Translate remaining frontend

This commit is contained in:
2026-07-22 23:25:53 +02:00
parent 7257deacdc
commit e4fd7e0df6
11 changed files with 79 additions and 53 deletions
@@ -142,12 +142,22 @@ function normalizeUiError(err: unknown): string {
if (message.includes("Duplicate equipmentIdentifier")) {
return "Das Betriebsmittelkennzeichen ist in dieser Stromkreisliste bereits vorhanden.";
}
if (message.includes("Invalid number")) {
if (message.includes("Invalid number") || message.includes("Ungültiger Zahlenwert")) {
return "Bitte einen gültigen Zahlenwert eingeben.";
}
return message;
}
function formatPhaseTypeLabel(value: string): string {
if (value === "three_phase") {
return "Dreiphasig";
}
if (value === "single_phase") {
return "Einphasig";
}
return value;
}
function isPrintableKey(event: KeyboardEvent<HTMLElement>) {
return event.key.length === 1 && !event.metaKey && !event.ctrlKey && !event.altKey;
}
@@ -2587,7 +2597,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
>
<strong>{device.displayName || device.name}</strong>
<span>Name: {device.name}</span>
<span>Phase: {device.phaseType}</span>
<span>Phasenart: {formatPhaseTypeLabel(device.phaseType)}</span>
<span>Anzahl: {device.quantity}</span>
<span>Leistung/Gerät: {device.powerPerUnit}</span>
<span>Gleichzeitigkeit: {device.simultaneityFactor}</span>
@@ -15,12 +15,22 @@ function formatNumber(value: number | undefined, digits = 2) {
}).format(value);
}
function formatPhaseType(value: string | undefined) {
if (value === "three_phase") {
return "Dreiphasig";
}
if (value === "single_phase") {
return "Einphasig";
}
return value ?? "-";
}
function renderCircuitSummaryLabel(circuit: CircuitTreeCircuitDto) {
if (circuit.displayName?.trim()) {
return circuit.displayName;
}
if (circuit.deviceRows.length > 1) {
return `${circuit.deviceRows.length} devices`;
return `${circuit.deviceRows.length} Geräte`;
}
return "Reserve";
}
@@ -37,13 +47,13 @@ export function CircuitTreePreview(props: { projectId: string; circuitListId: st
getCircuitTree(projectId, circuitListId)
.then(setData)
.catch((err: unknown) =>
setError(err instanceof Error ? err.message : "Circuit tree could not be loaded.")
setError(err instanceof Error ? err.message : "Die Stromkreisstruktur konnte nicht geladen werden.")
)
.finally(() => setIsLoading(false));
}, [projectId, circuitListId]);
if (isLoading) {
return <div className="alert alert-info">Loading circuit tree...</div>;
return <div className="alert alert-info">Stromkreisstruktur wird geladen </div>;
}
if (error) {
@@ -51,12 +61,12 @@ export function CircuitTreePreview(props: { projectId: string; circuitListId: st
}
if (!data || !data.sections.length) {
return <div className="alert alert-secondary">No sections or circuits available.</div>;
return <div className="alert alert-secondary">Keine Bereiche oder Stromkreise vorhanden.</div>;
}
const hasAnyCircuits = data.sections.some((section) => section.circuits.length > 0);
if (!hasAnyCircuits) {
return <div className="alert alert-secondary">Sections exist, but no circuits were found yet.</div>;
return <div className="alert alert-secondary">Bereiche sind vorhanden, enthalten aber noch keine Stromkreise.</div>;
}
return (
@@ -66,28 +76,28 @@ export function CircuitTreePreview(props: { projectId: string; circuitListId: st
<table className="table table-sm align-middle circuit-tree-table">
<thead>
<tr>
<th>Equipment identifier</th>
<th>Display name</th>
<th>Phase type</th>
<th>Connection kind</th>
<th>Cost group</th>
<th>Category</th>
<th>Level</th>
<th>Room number</th>
<th>Room name</th>
<th className="text-end">Quantity</th>
<th className="text-end">Power / unit</th>
<th className="text-end">Simultaneity</th>
<th className="text-end">cosPhi</th>
<th className="text-end">Row total</th>
<th className="text-end">Circuit total</th>
<th>Protection type</th>
<th className="text-end">Protection current</th>
<th>Protection characteristic</th>
<th>Cable type</th>
<th>Cable cross-section</th>
<th className="text-end">Cable length</th>
<th>Remark</th>
<th>Betriebsmittelkennzeichen</th>
<th>Anzeigename</th>
<th>Phasenart</th>
<th>Anschlussart</th>
<th>Kostengruppe</th>
<th>Kategorie</th>
<th>Ebene</th>
<th>Raumnummer</th>
<th>Raumname</th>
<th className="text-end">Anzahl</th>
<th className="text-end">Leistung / Gerät</th>
<th className="text-end">Gleichzeitigkeit</th>
<th className="text-end">cos φ</th>
<th className="text-end">Zeilensumme</th>
<th className="text-end">Stromkreissumme</th>
<th>Schutzart</th>
<th className="text-end">Bemessungsstrom</th>
<th>Charakteristik</th>
<th>Kabeltyp</th>
<th>Kabelquerschnitt</th>
<th className="text-end">Kabellänge</th>
<th>Bemerkung</th>
</tr>
</thead>
<tbody>
@@ -136,7 +146,7 @@ function SectionRows(props: { section: CircuitTreeResponseDto["sections"][number
<tr key={circuit.id} className={circuit.isReserve ? "reserve-row" : ""}>
<td>{circuit.equipmentIdentifier}</td>
<td>{row.displayName || row.name}</td>
<td>{row.phaseType ?? "-"}</td>
<td>{formatPhaseType(row.phaseType)}</td>
<td>{row.connectionKind ?? "-"}</td>
<td>{row.costGroup ?? "-"}</td>
<td>{row.category ?? "-"}</td>
@@ -179,7 +189,7 @@ function SectionRows(props: { section: CircuitTreeResponseDto["sections"][number
<tr key={row.id} className="device-row">
<td className="text-muted"> </td>
<td className="indented-cell">{row.displayName || row.name}</td>
<td>{row.phaseType ?? "-"}</td>
<td>{formatPhaseType(row.phaseType)}</td>
<td>{row.connectionKind ?? "-"}</td>
<td>{row.costGroup ?? "-"}</td>
<td>{row.category ?? "-"}</td>
@@ -206,7 +216,7 @@ function SectionRows(props: { section: CircuitTreeResponseDto["sections"][number
})}
<tr className="placeholder-row">
<td>-frei-</td>
<td colSpan={21}>free placeholder</td>
<td colSpan={21}>Freie Zeile</td>
</tr>
</>
);
@@ -321,7 +321,7 @@ export function PowerBalanceWorkspace() {
setEditConsumerForm(null);
}
} catch (err) {
setError(err instanceof Error ? err.message : "Verbraucher konnte nicht geloescht werden.");
setError(err instanceof Error ? err.message : "Verbraucher konnte nicht gelöscht werden.");
} finally {
setIsSaving(false);
}
@@ -424,7 +424,7 @@ export function PowerBalanceWorkspace() {
<form className="consumerForm" onSubmit={handleCreateConsumer}>
<label>
Verbraucher
<input value={consumerForm.name} onChange={(event) => updateConsumerForm("name", event.target.value)} placeholder="z. B. Steckdosen Buero" />
<input value={consumerForm.name} onChange={(event) => updateConsumerForm("name", event.target.value)} placeholder="z. B. Steckdosen Büro" />
</label>
<label>
Kategorie
@@ -435,7 +435,7 @@ export function PowerBalanceWorkspace() {
<input min="0" type="number" value={consumerForm.quantity} onChange={(event) => updateConsumerForm("quantity", event.target.value)} />
</label>
<label>
Leistung je Stueck [kW]
Leistung je Stück [kW]
<input min="0" step="0.01" type="number" value={consumerForm.installedPowerPerUnitKw} onChange={(event) => updateConsumerForm("installedPowerPerUnitKw", event.target.value)} />
</label>
<label>
@@ -463,7 +463,7 @@ export function PowerBalanceWorkspace() {
</label>
<button className="primaryButton" type="submit" disabled={!selectedProjectId || isSaving}>
<Plus size={17} />
Hinzufuegen
Hinzufügen
</button>
</form>
</section>
@@ -472,12 +472,12 @@ export function PowerBalanceWorkspace() {
<div className="tableHeader">
<div>
<p className="eyebrow">Aktuelles Projekt</p>
<h2>{selectedProject?.name || "Noch kein Projekt ausgewaehlt"}</h2>
<h2>{selectedProject?.name || "Noch kein Projekt ausgewählt"}</h2>
<p className="subline">{selectedBoard ? `Verteilung: ${selectedBoard.name}` : "Alle Verteilungen"}</p>
</div>
<div className="statusPill">
<Activity size={16} />
{isLoading ? "Laedt" : "Bereit"}
{isLoading ? "Lädt" : "Bereit"}
</div>
</div>
@@ -505,7 +505,7 @@ export function PowerBalanceWorkspace() {
{!totalsByBoard.length ? (
<tr>
<td colSpan={4} className="emptyState">
Noch keine Verbraucher fuer eine Summenbildung vorhanden.
Noch keine Verbraucher für eine Summenbildung vorhanden.
</td>
</tr>
) : null}
@@ -528,7 +528,7 @@ export function PowerBalanceWorkspace() {
<th>Verteilung</th>
<th>Kategorie</th>
<th>Anzahl</th>
<th>Leistung je Stueck [kW]</th>
<th>Leistung je Stück [kW]</th>
<th>Installierte Leistung [kW]</th>
<th>GZF</th>
<th>Berechnete Leistung [kW]</th>
@@ -642,7 +642,7 @@ export function PowerBalanceWorkspace() {
<Pencil size={14} />
</button>
)}
<button className="iconButton small danger" type="button" title="Loeschen" onClick={() => handleDeleteConsumer(consumer.id)} disabled={isSaving}>
<button className="iconButton small danger" type="button" title="Löschen" onClick={() => handleDeleteConsumer(consumer.id)} disabled={isSaving}>
<Trash2 size={14} />
</button>
</div>
+1 -1
View File
@@ -37,7 +37,7 @@ async function request<T>(url: string, init?: RequestInit): Promise<T> {
if (!response.ok) {
const details = await response.text();
throw new Error(details || `Request failed with ${response.status}`);
throw new Error(details || `Anfrage fehlgeschlagen (Status ${response.status})`);
}
if (response.status === 204) {
+1 -1
View File
@@ -184,7 +184,7 @@ export function parseNumeric(cellKey: CellKey, draft: string): number | undefine
}
const parsed = Number(trimmed);
if (Number.isNaN(parsed)) {
throw new Error(`Invalid number in ${cellKey}`);
throw new Error(`Ungültiger Zahlenwert in ${cellKey}`);
}
return parsed;
}