Zwei Wortlaut-Maengel, beide am Code verifiziert: vier deutsche Texte duzen
statt zu siezen, und der Gruppen-Loeschdialog setzt zwei Zahlen in fest
formulierte Mehrzahl-Woerter ("1 Mitglieder").
Beim Planen nachgeprueft: der Mock-Uebersetzer in groups-page.test.tsx kann
kein ICU-Plural — die Umstellung wuerde die beiden bestehenden
Loeschdialog-Tests brechen. Der Plan loest das ueber dieselbe Regex-Technik,
mit der grants-matrix.test.tsx bereits ICU-select aufloest, und nagelt den
Einzahl-Fall mit einem neuen Test fest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
18 KiB
quick_id, title, type, wave, depends_on, autonomous, files_modified, estimate, must_haves
| quick_id | title | type | wave | depends_on | autonomous | files_modified | estimate | must_haves | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 260907-ipz | Anrede vereinheitlichen (Duzen auf Siezen) und Einzahl korrigieren | execute | 1 | false |
|
|
|
- Die Anrede springt. Die Oberflaeche siezt ueberall — an genau vier Stellen duzt sie.
- 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.
<execution_context> @~/.claude/gsd-core/workflows/execute-plan.md </execution_context>
@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.
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.tsxZeile 27 — Mock-NachrichtadminModules.activationDialog.body.groups-page.test.tsxZeile 15 — Mock-Nachrichtadmin.groups.noGroupsBody.groups-page.test.tsxZeile 185 — die Zusicherung, die denselben Text im Leerzustand sucht. Sie muss buchstabengleich zur Mock-Nachricht aus Zeile 15 bleiben.module-access-gate.test.tsxZeile 27 — EintragaccessDenied.bodyin 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.tsde.jsonenthaelt in keinem Wert mehr eine Du-Form; dieselbe Pruefung ueber die drei Testdateien ist ebenfalls leer. Die vier Texte lauten auf Sie/Ihr.en.jsonist unveraendert. Alle vier genannten Testdateien laufen gruen, keiner der fuenf bisherigen Pruefpunkte wurde entfernt.
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.jsonZeile 433: erstes ArgumentmemberCountmit den Zweigen Mitglied / Mitglieder, zweites ArgumentgrantCountmit den Zweigen Modul-Freigabe / Modul-Freigaben. Der Satzanfang "Diese Gruppe hat" und die beiden Folgesaetze bleiben Wort fuer Wort stehen.en.jsonZeile 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.
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.
-
Modul-Aktivierungsdialog — als
admin/admin123anmelden, dann Administration → Module, bei einem noch nicht aktivierten Modul auf Aktivieren klicken. Der Dialogtext muss siezen ("… oder möchten Sie die Freigaben separat konfigurieren?"). -
Löschdialog einer Gruppe, Einzahl — als
adminunter 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. -
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. -
Marktplatz-Hinweis — als
nutzer2im Marktplatz auf die Kachel eines aktiven Moduls ohne Freigabe klicken. Die eingeblendete Meldung muss "… wenden Sie sich an Ihren Administrator." lauten. -
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.
<success_criteria>
- Die vier bisher duzenden deutschen Texte siezen;
de.jsonenthaelt 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.jsonwurde 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. </success_criteria>