---
quick_id: 260907-ipz
title: Anrede vereinheitlichen (Duzen auf Siezen) und Einzahl korrigieren
type: execute
wave: 1
depends_on: []
autonomous: false
files_modified:
- apps/web/src/messages/de.json
- apps/web/src/messages/en.json
- apps/web/src/app/(portal)/admin/groups/groups-page.test.tsx
- apps/web/src/app/(portal)/admin/modules/grants/grants-matrix.test.tsx
- apps/web/src/components/modules/module-access-gate.test.tsx
estimate:
tokens: 22000
raw_tokens: 22000
tasks: 2
confidence: low
must_haves:
truths:
- "Die vier bisher duzenden deutschen Texte siezen: leere Gruppenliste, Modul-Aktivierungsdialog, Modul-Sperrseite und Marktplatz-Hinweis."
- "Kein Wert in de.json enthaelt mehr eine Du-Form (du, dich, dir, dein*)."
- "Der Loeschdialog einer Gruppe mit genau einem Mitglied und einer Freigabe schreibt '1 Mitglied' und '1 Modul-Freigabe' — nicht '1 Mitglieder'."
- "Dasselbe gilt auf Englisch: '1 member' und '1 module grant'."
- "Ab zwei zeigt derselbe Text weiterhin die Mehrzahl."
- "de.json und en.json tragen weiterhin denselben Schluesselsatz."
- "Alle Tests, die diese Texte festnageln, laufen gruen — keiner wurde geloescht."
artifacts:
- apps/web/src/messages/de.json
- apps/web/src/messages/en.json
key_links:
- "Die Mock-Uebersetzer in den Tests spiegeln die Texte aus de.json — jede Textaenderung muss dort mitgezogen werden, sonst pinnen die Tests eine Fassung, die es nicht mehr gibt."
- "Der Mock-Uebersetzer in groups-page.test.tsx kann heute KEIN ICU-Plural — ohne Erweiterung bricht der Loeschdialog-Test durch die Plural-Umstellung."
---
Zwei Wortlaut-Maengel in der deutschen Oberflaeche, beide vom Nutzer beauftragt und beide am
Code verifiziert:
1. **Die Anrede springt.** Die Oberflaeche siezt ueberall — an genau vier Stellen duzt sie.
2. **Die Einzahl ist falsch.** Der Loeschdialog einer Gruppe schreibt "1 Mitglieder und
1 Modul-Freigaben", weil zwei Zahlen in fest formulierte Mehrzahl-Woerter eingesetzt
werden. Live beobachtet an der Gruppe "Vertrieb Innendienst".
Purpose: Ein Produkt, das an externe Kunden verkauft werden soll, redet seine Nutzer nicht
mal so und mal so an und zaehlt nicht falsch.
Output: Vier korrigierte deutsche Texte, ein Loeschdialog-Text mit echter Ein-/Mehrzahl in
beiden Sprachen, mitgezogene Tests und ein neuer Test, der genau den Einzahl-Fall festnagelt.
Ausdruecklich NICHT Teil dieses Plans: jede andere Umformulierung. Es werden ausschliesslich
die fuenf hier namentlich genannten Schluessel angefasst. Englisch ist von Defekt 1 nicht
betroffen — Englisch kennt den Unterschied nicht und ist bereits richtig formuliert.
@~/.claude/gsd-core/workflows/execute-plan.md
@CLAUDE.md
@apps/web/src/app/(portal)/admin/groups/components/DeleteGroupDialog.tsx
@apps/web/src/app/(portal)/admin/modules/grants/grants-matrix.test.tsx
Alles Folgende wurde beim Planen am Code nachgeprueft und erspart dem Executor die Suche.
**1. Die vier Du-Stellen sind vollstaendig — es gibt keine fuenfte.**
Ein Wortgrenzen-Grep ueber `de.json` nach `du|dich|dir|dein*` trifft heute exakt vier
Zeilen (400, 464, 492, 630) und nichts sonst. Die Erhebung im Auftrag ist damit
bestaetigt und abgeschlossen.
| Schluessel | Zeile | heute |
|---|---|---|
| `admin.groups.noGroupsBody` | 400 | "Lege deine erste Gruppe an, um Modulzugriff gezielt zu vergeben." |
| `adminModules.activationDialog.body` | 464 | "… oder moechtest du die Freigaben separat konfigurieren?" |
| `modules.accessDenied.body` | 492 | "Du hast fuer dieses Modul keine Freigabe. Wende dich an deinen Administrator." |
| `marketplace.toastNoAccess` | 630 | "Kein Zugriff auf dieses Modul — wende dich an deinen Administrator." |
`marketplace.toastNoAccess` liegt tatsaechlich unter `marketplace` (Zeile 630, direkt vor
`certManager`) — nicht unter `domaincheck`, obwohl die Nachbarzeilen im Ausschnitt so
wirken. Genutzt wird er in `app/(portal)/marketplace/page.tsx:178`.
**2. Derselbe Grep trifft in den drei Testdateien exakt vier Zeilen** — allesamt die oben
gelisteten Texte. Es gibt keine weitere Stelle im `src`-Baum, die diese Texte kopiert.
**3. ICU-Plural ist im Projekt bereits etabliert.** `admin.ldap.…resultSummary`
(de.json Zeile 365) nutzt `{errors, plural, =0 {} other {, # Fehler}}`. next-intl 4.13
kann das produktiv ohne jede Zusatzarbeit — es braucht kein neues Mittel, nur dieselbe
Schreibweise.
**4. Der Loeschdialog uebergibt beide Zahlen bereits als Parameter.**
`DeleteGroupDialog.tsx:102` ruft `t('deleteConfirm.body', { memberCount, grantCount })`.
Es ist also nichts am Aufrufer zu aendern — nur am Text.
**5. Der Mock-Uebersetzer in `groups-page.test.tsx` versteht KEIN ICU.**
Nachgelesen in `resolve()` (Zeile 66–80): er ersetzt stur `{k}` durch den Wert. Sobald
`deleteConfirm.body` auf Plural-Schreibweise umgestellt wird, findet er `{memberCount}`
nicht mehr, gibt den ICU-Rohtext aus, und die bestehenden Zusicherungen `/4 Mitglieder/`
(Zeile 475) und `/2 Modul-Freigaben/` (Zeile 477) schlagen fehl.
**Das ist keine Nebenwirkung, die man in Kauf nimmt — Task 2 loest es ausdruecklich.**
**6. Fuer die Loesung gibt es im Projekt bereits ein Vorbild.**
`grants-matrix.test.tsx` (Zeile 48–53) hat genau dieses Problem fuer `select` geloest: ein
winziger Regex-Ersatz im Mock, der die eine benutzte ICU-Form aufloest. Task 2 spiegelt
dieses Vorgehen fuer `plural`. Damit bleibt die Mock-Nachricht wortgleich mit `de.json` —
was der Sinn dieser Mocks ist.
**7. Der Umlaut-Waechter schlaegt bei keiner der neuen Formulierungen an.**
`umlaut-guard.spec.ts` meldet jedes neue Token mit `ae`/`oe`/`ue`/`ss`, das nicht auf der
Positivliste steht. Die geplanten Formulierungen wurden gegen genau diese Regel geprueft:
kein einziges verdaechtiges Token. Es ist also **kein** Eintrag in `umlaut-dictionary.ts`
noetig.
**8. de.json und en.json haben heute identische Schluesselsaetze** (maschinell verglichen,
beide Richtungen leer). Dieser Plan aendert ausschliesslich Werte, niemals Schluessel.
**Ja, der Einzahl-Test wird angelegt.** Begruendung, weil der Auftrag sie verlangt:
Der Fehler war ueber Monate im Code und kein Test hat ihn bemerkt — weil beide bestehenden
Loeschdialog-Tests mit `memberCount: 4, grantCount: 2` laufen, also nur im Mehrzahl-Fall.
Genau die eine Zahl, bei der der Text falsch wird, war nie abgedeckt. Ein Test, der nach
der Korrektur nur die Mehrzahl prueft, wuerde denselben Rueckfall wieder durchlassen.
Der Aufwand ist zudem praktisch null: `buildRouterFetchMock` nimmt `impact` bereits als
Parameter entgegen (Zeile 393/412), der neue Fall ist ein Aufruf mit `{ memberCount: 1,
grantCount: 1 }` und zwei Zusicherungen. Und der Test hat einen zweiten Nutzen: er ist der
Beweis, dass die Mock-Erweiterung aus Task 2 das ICU-Plural wirklich auswertet — ohne ihn
koennte der Mock stillschweigend falsch bleiben, solange nur mit 4 und 2 geprueft wird.
Keine der fuenf bestehenden Test-Fundstellen wird entfernt. Sie werden **mitgezogen**: die
Mock-Nachrichten und die Zusicherungen tragen danach den neuen Wortlaut. Ein Test, der
eine Formulierung festnagelt, ist nach einer Formulierungsaenderung nicht wertlos, sondern
schuetzt die neue Fassung.
Task 1: Anrede auf Siezen vereinheitlichen (Defekt 1)
apps/web/src/messages/de.json, apps/web/src/app/(portal)/admin/groups/groups-page.test.tsx, apps/web/src/app/(portal)/admin/modules/grants/grants-matrix.test.tsx, apps/web/src/components/modules/module-access-gate.test.tsx
Setze in `apps/web/src/messages/de.json` genau vier Werte auf die Sie-Form. Ausschliesslich
diese vier Schluessel werden angefasst, kein weiterer Text in der Datei wird umformuliert.
- `admin.groups.noGroupsBody` (Zeile 400) wird zu:
Legen Sie Ihre erste Gruppe an, um Modulzugriff gezielt zu vergeben.
- `adminModules.activationDialog.body` (Zeile 464) wird zu:
Soll die Standardgruppe sofort Zugriff auf dieses Modul erhalten, oder moechten Sie die
Freigaben separat konfigurieren? — mit korrektem Umlaut in "moechten" geschrieben.
- `modules.accessDenied.body` (Zeile 492) wird zu:
Sie haben fuer dieses Modul keine Freigabe. Wenden Sie sich an Ihren Administrator. —
mit korrekten Umlauten in "fuer".
- `marketplace.toastNoAccess` (Zeile 630) wird zu:
Kein Zugriff auf dieses Modul — wenden Sie sich an Ihren Administrator. — der
Geviertstrich bleibt unveraendert erhalten.
Alle vier Werte werden mit echten Umlauten geschrieben (`ü`, `ö`); die Ersatzschreibweisen
in dieser Aufgabenbeschreibung sind nur der Klartext dieses Plans.
`en.json` wird in dieser Aufgabe NICHT angefasst — Englisch kennt die Unterscheidung nicht
und ist bereits richtig formuliert. Es werden keine Schluessel hinzugefuegt, umbenannt oder
entfernt.
Ziehe anschliessend die drei Testdateien nach, damit ihre Mock-Nachrichten und
Zusicherungen wieder wortgleich zu `de.json` sind. Kein Test wird geloescht oder
uebersprungen — nur der Wortlaut wird aktualisiert:
- `grants-matrix.test.tsx` Zeile 27 — Mock-Nachricht `adminModules.activationDialog.body`.
- `groups-page.test.tsx` Zeile 15 — Mock-Nachricht `admin.groups.noGroupsBody`.
- `groups-page.test.tsx` Zeile 185 — die Zusicherung, die denselben Text im Leerzustand
sucht. Sie muss buchstabengleich zur Mock-Nachricht aus Zeile 15 bleiben.
- `module-access-gate.test.tsx` Zeile 27 — Eintrag `accessDenied.body` in der
handgepflegten Uebersetzungstabelle.
cd /home/vicolab/projects/tessera-ctl && ! grep -nE '\b([Dd]u|dich|dir|dein(e|en|er|em|es)?)\b' apps/web/src/messages/de.json 'apps/web/src/app/(portal)/admin/groups/groups-page.test.tsx' 'apps/web/src/app/(portal)/admin/modules/grants/grants-matrix.test.tsx' apps/web/src/components/modules/module-access-gate.test.tsx && grep -q 'Wenden Sie sich an Ihren Administrator' apps/web/src/messages/de.json
cd /home/vicolab/projects/tessera-ctl && pnpm --dir apps/web test -- groups-page.test.tsx grants-matrix.test.tsx module-access-gate.test.tsx umlaut-guard.spec.ts
`de.json` enthaelt in keinem Wert mehr eine Du-Form; dieselbe Pruefung ueber die drei
Testdateien ist ebenfalls leer. Die vier Texte lauten auf Sie/Ihr. `en.json` ist
unveraendert. Alle vier genannten Testdateien laufen gruen, keiner der fuenf bisherigen
Pruefpunkte wurde entfernt.
Task 2: Ein-/Mehrzahl im Loeschdialog korrigieren (Defekt 2)
apps/web/src/messages/de.json, apps/web/src/messages/en.json, apps/web/src/app/(portal)/admin/groups/groups-page.test.tsx
- Bei einem Mitglied und einer Freigabe lautet der deutsche Text "… hat 1 Mitglied und
1 Modul-Freigabe. …"; die Zeichenfolge "1 Mitglieder" kommt nicht vor.
- Bei vier Mitgliedern und zwei Freigaben lautet er weiterhin "… hat 4 Mitglieder und
2 Modul-Freigaben. …" (die beiden bestehenden Tests bleiben gruen).
- Auf Englisch gilt dasselbe: "1 member" / "1 module grant" gegen "4 members" /
"2 module grants".
- Der Rest des Satzes (Folgen des Loeschens, Unwiderruflichkeit) bleibt in beiden
Sprachen unveraendert.
Schreibe zuerst die Mock-Erweiterung und den neuen Einzahl-Test, dann die Textaenderung —
der neue Test muss vor der Textaenderung rot sein.
Schritt A — `resolve()` in `groups-page.test.tsx` (Zeile 66–80) um eine ICU-Plural-Aufloesung
erweitern, nach demselben Muster, mit dem `grants-matrix.test.tsx` (Zeile 48–53) bereits
`select` aufloest. Vor der bestehenden Schleife, die schlichte `{k}`-Platzhalter ersetzt,
laeuft ein globaler Ersatz mit dem Muster
`/\{(\w+),\s*plural,\s*one\s*\{([^}]*)\}\s*other\s*\{([^}]*)\}\}/g`.
Fuer jeden Treffer wird der Zweig `one` gewaehlt, wenn `Number(params[name]) === 1`, sonst
der Zweig `other`; im gewaehlten Zweig wird danach jedes `#` durch `String(params[name])`
ersetzt. Die bestehende schlichte Ersetzungsschleife bleibt unveraendert dahinter stehen —
sie greift weiterhin fuer alle anderen Schluessel wie `adDnLabel`. Aktualisiere den
Kopfkommentar der Datei so, dass er die nun ebenfalls aufgeloeste Plural-Form erwaehnt.
Schritt B — neuer Test im Block `DeleteGroupDialog (via AdminGroupsPage)`, direkt nach dem
bestehenden Test, der beide Zahlen prueft. Er nutzt `buildRouterFetchMock` mit
`impact: { memberCount: 1, grantCount: 1 }`, oeffnet den Loeschdialog ueber denselben Weg
wie der Nachbartest (letzte Loeschen-Schaltflaeche) und sichert zu, dass der Dialogtext
`/hat 1 Mitglied und 1 Modul-Freigabe\./` enthaelt. Zusaetzlich eine Gegenprobe: die
Mehrzahlform mit vorangestellter Eins darf nicht im Dokument sein
(`queryByText(/1 Mitglieder/)` ist `null`). Der Test muss an dieser Stelle fehlschlagen —
das ist der Nachweis, dass er den Defekt wirklich trifft.
Schritt C — `admin.groups.deleteConfirm.body` in beiden Sprachdateien auf ICU-Plural
umstellen, in derselben Schreibweise wie das bestehende `admin.ldap.…resultSummary`.
Beide Zahlen bekommen je ein eigenes `plural`-Argument mit den Zweigen `one` und `other`,
die Zahl selbst wird im Zweig als `#` gesetzt:
- `de.json` Zeile 433: erstes Argument `memberCount` mit den Zweigen Mitglied / Mitglieder,
zweites Argument `grantCount` mit den Zweigen Modul-Freigabe / Modul-Freigaben. Der
Satzanfang "Diese Gruppe hat" und die beiden Folgesaetze bleiben Wort fuer Wort stehen.
- `en.json` Zeile 433: dieselbe Struktur mit member / members und module grant /
module grants. "This group has" und die beiden Folgesaetze bleiben unveraendert.
Ziehe abschliessend die Mock-Nachricht in `groups-page.test.tsx` Zeile 49–50 nach, sodass
sie buchstabengleich zum neuen Wert aus `de.json` ist — die Erweiterung aus Schritt A wertet
sie dann korrekt aus. Es werden keine Schluessel hinzugefuegt oder entfernt; beide
Sprachdateien behalten denselben Schluesselsatz.
cd /home/vicolab/projects/tessera-ctl && test "$(grep -c 'memberCount, plural' apps/web/src/messages/de.json)" = "1" && test "$(grep -c 'memberCount, plural' apps/web/src/messages/en.json)" = "1" && test "$(grep -c 'grantCount, plural' apps/web/src/messages/de.json)" = "1" && test "$(grep -c 'grantCount, plural' apps/web/src/messages/en.json)" = "1"
cd /home/vicolab/projects/tessera-ctl && node -e "const a=require('./apps/web/src/messages/de.json'),b=require('./apps/web/src/messages/en.json');const f=(o,p='')=>Object.entries(o).flatMap(([k,v])=>typeof v==='object'&&v?f(v,p+k+'.'):[p+k]);const A=f(a).sort().join('|'),B=f(b).sort().join('|');if(A!==B){console.error('key sets differ');process.exit(1)}console.log('key parity ok:',f(a).length)"
cd /home/vicolab/projects/tessera-ctl && pnpm --dir apps/web test -- groups-page.test.tsx
Beide Sprachdateien tragen fuer `memberCount` und `grantCount` je ein `plural`-Argument.
Der Schluesselsatz beider Dateien ist weiterhin identisch (787). In `groups-page.test.tsx`
laufen alle Loeschdialog-Tests gruen: die beiden bestehenden mit 4/2 und der neue mit 1/1,
der ohne die Textkorrektur rot war. Der Mock-Uebersetzer loest das Plural-Argument auf,
statt den Rohtext auszugeben.
**Maschinell** (laeuft in beiden Aufgaben, hier nochmal als Gesamtlauf):
- `pnpm --dir apps/web test` — die gesamte Web-Testsuite, nicht nur die vier beruehrten
Dateien. Es soll auffallen, falls eine bisher unbekannte Stelle einen der Texte spiegelt.
- `pnpm --dir apps/web run type-check`
**Sichtpruefung im Browser** — vom Orchestrator auszufuehren, nicht vom Planer.
Vorher noetig: `docker compose build web && docker compose up -d --force-recreate web`.
Anschliessend `http://localhost:3000`.
Alle Bildschirme in **deutscher** Oberflaeche pruefen. Gesucht wird jeweils die Sie-Form —
kein "du", "dich", "dein".
1. **Modul-Aktivierungsdialog** — als `admin`/`admin123` anmelden, dann
Administration → Module, bei einem noch nicht aktivierten Modul auf Aktivieren klicken.
Der Dialogtext muss siezen ("… oder möchten Sie die Freigaben separat konfigurieren?").
2. **Löschdialog einer Gruppe, Einzahl** — als `admin` unter Administration → Gruppen die
Gruppe **"Vertrieb Innendienst"** loeschen (Dialog nur oeffnen, NICHT bestaetigen).
Der Text muss "1 Mitglied und 1 Modul-Freigabe" lauten — nicht "1 Mitglieder und
1 Modul-Freigaben". Zur Gegenprobe eine Gruppe mit mehreren Mitgliedern oeffnen: dort
muss weiterhin die Mehrzahl stehen. Beide Dialoge mit Abbrechen schliessen.
3. **Modul-Sperrseite** — abmelden, als `nutzer2`/`Test1234!` anmelden (dieser Benutzer hat
KEINE Freigabe fuer tender-radar) und die Modulseite von tender-radar direkt aufrufen.
Die 403-Seite muss "Sie haben für dieses Modul keine Freigabe. Wenden Sie sich an Ihren
Administrator." zeigen.
4. **Marktplatz-Hinweis** — als `nutzer2` im Marktplatz auf die Kachel eines aktiven Moduls
ohne Freigabe klicken. Die eingeblendete Meldung muss "… wenden Sie sich an Ihren
Administrator." lauten.
5. **Englische Fassung des Löschdialogs** — Sprache auf Englisch umstellen und Punkt 2
wiederholen: "1 member and 1 module grant".
**Nicht im Browser pruefbar:** der Leerzustand der Gruppenliste
(`admin.groups.noGroupsBody`) erscheint nur, wenn gar keine Gruppe existiert — im
Testsystem gibt es Gruppen. Dieser Text ist durch den Test in `groups-page.test.tsx`
(Zeile 185) abgedeckt und darf im Browser uebersprungen werden.
- Die vier bisher duzenden deutschen Texte siezen; `de.json` enthaelt keine Du-Form mehr.
- Der Loeschdialog schreibt bei genau einem Mitglied und einer Freigabe die Einzahl, ab
zwei weiterhin die Mehrzahl — in beiden Sprachen.
- `en.json` wurde nur fuer den Loeschdialog angefasst; die Schluesselsaetze beider
Sprachdateien sind weiterhin identisch (787).
- Kein bestehender Test wurde geloescht; alle fuenf bisherigen Fundstellen wurden auf den
neuen Wortlaut nachgezogen.
- Ein neuer Test nagelt den Einzahl-Fall fest und war vor der Korrektur rot.
- Kein anderer Text der Oberflaeche wurde umformuliert.