fix(ui): echte Umlaute in allen sichtbaren Texten

Menüs, Dialoge, Schaltflächen, Platzhalter, Hinweise und die
Fehlermeldungen der API standen in Ersatzschreibweise (oe/ae/ue). Sie
erscheinen als Toast oder Beschriftung direkt in der Oberfläche und
gehören damit richtig geschrieben; sechs sichtbare Texte mit ss statt ß
sind gleich mit erledigt ("Schließen", "Straße", "zu groß").

Unangetastet bleibt bewusst:

- Kommentare im Quelltext - die sind durchgängig ASCII, und der Diff wäre
  dreimal so groß ohne Nutzen für den Benutzer
- Protokollzeilen (console.*) - die landen im journal, nicht in der App
- Datenbankwerte und interne Kennungen: 'uebernommen', 'empfaenger',
  'vorschlaege', 'laeuft-bereits' stecken in Enums, SQL und
  Zustandsvergleichen. Ein Umlaut darin hätte still falsche Ergebnisse
  geliefert
- server/src/mail/extract.js - die Muster decken absichtlich beide
  Schreibweisen ab: /gr(ü|ue)(ß|ss)e/
- scanner/utils/crypto.js - der Ersatzschlüssel darf sich nicht ändern,
  sonst sind gespeicherte Portal-Passwörter nicht mehr lesbar

Geprüft mit einem Rundgang durch die Ansichten und Dialoge: sichtbarer
Text plus title/aria-label/placeholder enthalten keine
Ersatzschreibweisen mehr.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sascha Wolf
2026-08-11 09:37:24 +02:00
co-authored by Claude Opus 5
parent ea55acdb5c
commit 8b7ce448a6
42 changed files with 168 additions and 168 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ export const ColorPicker: React.FC<ColorPickerProps> = ({ value, onChange, fallb
})}
<label
title="Eigene Farbe waehlen"
title="Eigene Farbe wählen"
className="flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg border border-dashed border-ink-300 text-ink-400 transition hover:border-brand-400 hover:text-brand-600"
>
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
+6 -6
View File
@@ -49,7 +49,7 @@ const AccountTab: React.FC = () => {
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
if (newPassword !== confirmPassword) {
addToast('Die neuen Passwoerter stimmen nicht ueberein.', 'error');
addToast('Die neuen Passwörter stimmen nicht überein.', 'error');
return;
}
if (newPassword.length < 8) {
@@ -60,12 +60,12 @@ const AccountTab: React.FC = () => {
setIsSaving(true);
try {
await authApi.changePassword(currentPassword, newPassword);
addToast('Passwort geaendert.', 'success');
addToast('Passwort geändert.', 'success');
setCurrentPassword('');
setNewPassword('');
setConfirmPassword('');
} catch (err) {
addToast(err instanceof Error ? err.message : 'Aenderung fehlgeschlagen.', 'error');
addToast(err instanceof Error ? err.message : 'Änderung fehlgeschlagen.', 'error');
} finally {
setIsSaving(false);
}
@@ -126,7 +126,7 @@ const AccountTab: React.FC = () => {
</section>
<section className="rounded-2xl border border-ink-200 bg-surface p-5">
<h3 className="text-base text-ink-900">Passwort aendern</h3>
<h3 className="text-base text-ink-900">Passwort ändern</h3>
<form onSubmit={handleSubmit} className="mt-4 space-y-4">
<div>
<label className={labelClass}>Aktuelles Passwort</label>
@@ -152,7 +152,7 @@ const AccountTab: React.FC = () => {
/>
</div>
<div>
<label className={labelClass}>Neues Passwort bestaetigen</label>
<label className={labelClass}>Neues Passwort bestätigen</label>
<input
type="password"
required
@@ -167,7 +167,7 @@ const AccountTab: React.FC = () => {
disabled={isSaving}
className="w-full rounded-xl bg-brand-500 py-2.5 text-sm font-bold text-white transition hover:bg-brand-600 disabled:opacity-60"
>
{isSaving ? 'Speichere...' : 'Passwort aendern'}
{isSaving ? 'Speichere...' : 'Passwort ändern'}
</button>
</form>
</section>
+6 -6
View File
@@ -145,10 +145,10 @@ export const UserManagement: React.FC = () => {
if (!userToDelete) return;
try {
await usersApi.remove(userToDelete.id);
addToast(`Benutzer "${userToDelete.name}" wurde geloescht.`, 'success');
addToast(`Benutzer "${userToDelete.name}" wurde gelöscht.`, 'success');
await load();
} catch (err) {
addToast(err instanceof Error ? err.message : 'Loeschen fehlgeschlagen.', 'error');
addToast(err instanceof Error ? err.message : 'Löschen fehlgeschlagen.', 'error');
} finally {
setUserToDelete(null);
}
@@ -222,7 +222,7 @@ export const UserManagement: React.FC = () => {
<button
onClick={() => setUserToDelete(user)}
className="rounded-lg p-2 text-ink-400 transition hover:bg-red-50 hover:text-red-600"
aria-label={`${user.name} loeschen`}
aria-label={`${user.name} löschen`}
>
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
@@ -243,7 +243,7 @@ export const UserManagement: React.FC = () => {
{isModalOpen && (
<Modal
title={editingUser ? `${editingUser.name} bearbeiten` : 'Neuer Benutzer'}
subtitle={editingUser ? `@${editingUser.username}` : 'Zugang fuer das perinco CRM anlegen'}
subtitle={editingUser ? `@${editingUser.username}` : 'Zugang für das perinco CRM anlegen'}
onClose={() => setIsModalOpen(false)}
size="md"
footer={
@@ -324,7 +324,7 @@ export const UserManagement: React.FC = () => {
required={!editingUser}
value={form.password}
onChange={(event) => set('password', event.target.value)}
placeholder={editingUser ? 'Leer lassen, um es nicht zu aendern' : 'Mindestens 8 Zeichen'}
placeholder={editingUser ? 'Leer lassen, um es nicht zu ändern' : 'Mindestens 8 Zeichen'}
className={inputClass}
autoComplete="new-password"
/>
@@ -352,7 +352,7 @@ export const UserManagement: React.FC = () => {
{userToDelete && (
<ConfirmDialog
title="Benutzer loeschen?"
title="Benutzer löschen?"
message={`"${userToDelete.name}" verliert den Zugang. Angelegte Kontakte bleiben erhalten, verlieren aber die Zuordnung.`}
onConfirm={confirmDelete}
onCancel={() => setUserToDelete(null)}