Skip to content

feat(i18n): Regelverstöße lokalisieren über stabile Fehlercodes - #28

Merged
tehw0lf merged 3 commits into
mainfrom
feat/localized-engine-errors
Aug 12, 2026
Merged

feat(i18n): Regelverstöße lokalisieren über stabile Fehlercodes#28
tehw0lf merged 3 commits into
mainfrom
feat/localized-engine-errors

Conversation

@tehw0lf

@tehw0lf tehw0lf commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Die Engine warf ihre Meldungen als fertigen deutschen Text, den der Adapter roh an die UI durchreichte. Im englischen Modus stand damit deutscher Text im Toast.

Warum nicht einfach in der Engine übersetzen

Das hätte ihrem Kerndesign widersprochen: Die Engine ist UI-frei und soll später autoritativ auf einem Server laufen, der gar nicht weiß, welche Sprache ein Client eingestellt hat. Übersetzen ist Sache des Clients.

Deshalb:

Engine  ──EngineErrorCode──>  Adapter  ──EngineErrorCode──>  UI  ──t.errors[code]──>  Toast
        (sprachfrei)                    (sprachfrei)              (übersetzt)
  • EngineError trägt einen stabilen code plus eine englische Entwickler-Message für Logs und Stacktraces
  • GameAdapter.onError reicht den Code weiter statt des Textes – ein RemoteAdapter kann denselben Code unverändert über die Leitung schicken
  • erst die UI bildet ihn über t.errors[code] ab

ENGINE_ERROR_CODES ist bewusst ein Array mit abgeleitetem Typ und nicht nur eine Union – nur so lässt sich zur Laufzeit prüfen, dass jeder Code übersetzt ist.

Verifikation

Derselbe Verstoß, je nach Spracheinstellung:

de: code=cardNotInHand  ->  "Karte nicht auf der Hand."
en: code=cardNotInHand  ->  "That card isn't in your hand."

Und die Null-Ketten-Regel aus #27, die dieser Branch mit übernimmt:

code: mustPlayZero
  de: "Du musst eine 0 legen."
  en: "You have to play a 0."
  message (Logs): "a zero must be played while the zero chain is open"

Tests

37/37 (die 32 aus #27 plus 5 neue). Die bestehenden Fehlertests prüfen jetzt konkrete Codes statt nur die Fehlerklasse, dazu drei neue:

  • jeder Code hat in jeder Sprache einen nicht-leeren Text (ohne das fällt ein vergessener Code erst als leerer Toast auf)
  • die Sprachen unterscheiden sich tatsächlich – fängt einen versehentlich kopierten Block ab
  • der Adapter meldet den Code, nicht den Text

npm run check: 0 Fehler, 0 Warnungen. Build grün.

Merge-Stand

main ist eingemergt (Stand nach #26 und #27). Der inhaltliche Überlapp mit #27 ist aufgelöst: Dessen neue Wurfstelle für die Null-Kette nutzte noch den alten einargumentigen Aufruf mit deutschem Text – Git hat engine.ts sauber automerged und konnte das nicht sehen. Die Stelle ist jetzt auf mustPlayZero umgestellt und verifiziert.

Hinweis

EngineError nutzt ein normales Feld statt einer Parameter-Property (constructor(readonly code…)), weil Node die Tests im strip-only-Modus ausführt, der keinen Code erzeugen darf.

Summary by CodeRabbit

  • Bug Fixes

    • Error notifications now appear in the selected language instead of showing internal or untranslated messages.
    • Improved validation feedback for invalid turns, cards, player counts, wild-card color choices, and other gameplay actions.
    • Error handling now uses stable codes to display the correct localized message consistently.
  • Quality Improvements

    • Added coverage to verify complete German and English translations for all gameplay errors.
    • Improved consistency of error feedback across supported languages.

Die Engine warf ihre Meldungen als fertigen deutschen Text, den der
Adapter roh an die UI durchreichte. Im englischen Modus stand damit
deutscher Text im Toast.

Naheliegend waere gewesen, in der Engine nach Sprache zu verzweigen -
das widerspricht aber ihrem Kerndesign: sie ist UI-frei und soll spaeter
autoritativ auf einem Server laufen, der gar nicht weiss, welche Sprache
ein Client eingestellt hat. Uebersetzen ist Sache des Clients.

Deshalb traegt EngineError jetzt einen stabilen, sprachfreien Code
(EngineErrorCode) plus eine englische Entwickler-Message fuer Logs und
Stacktraces. Der Adapter reicht den Code weiter statt des Textes - auch
im GameAdapter-Interface, damit ein RemoteAdapter denselben Code
unveraendert ueber die Leitung schicken kann. Erst die UI bildet ihn
ueber t.errors[code] auf einen uebersetzten String ab.

ENGINE_ERROR_CODES ist bewusst ein Array mit abgeleitetem Typ und nicht
nur eine Union: nur so laesst sich zur Laufzeit pruefen, dass jeder Code
uebersetzt ist.

Der Code mustPlayZero ist bereits definiert, wird aber erst mit #27
geworfen - so passen die Branches beim Merge zusammen, ohne dass einer
auf den anderen warten muss.

Tests: 35 statt 32. Die bestehenden Fehlertests pruefen jetzt konkrete
Codes statt nur die Fehlerklasse, dazu drei neue: jeder Code hat in
jeder Sprache einen nicht-leeren Text, die Sprachen unterscheiden sich
tatsaechlich (faengt einen versehentlich kopierten Block), und der
Adapter meldet den Code statt des Textes.

Verifiziert, dass derselbe Verstoss je nach Spracheinstellung
"Karte nicht auf der Hand." bzw. "That card isn't in your hand." ergibt.

Nebenbei: EngineError nutzt ein normales Feld statt einer
Parameter-Property, weil Node die Tests im strip-only-Modus ausfuehrt,
der keinen Code erzeugen darf.
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0b0aa7d1-b5e8-4be9-b81c-2e390bb5b12f

📥 Commits

Reviewing files that changed from the base of the PR and between 17db469 and 517cfbd.

📒 Files selected for processing (3)
  • src/App.svelte
  • src/lib/engine/engine.ts
  • tests/engine.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/App.svelte
  • src/lib/engine/engine.ts
  • tests/engine.test.ts

📝 Walkthrough

Walkthrough

The engine now emits stable error codes with English developer messages. Adapters pass codes to the UI, which displays localized German or English translations. Tests cover code propagation, message format, and translation completeness.

Changes

Engine error localization

Layer / File(s) Summary
Engine error contract and validation
src/lib/engine/types.ts, src/lib/engine/engine.ts
Defines typed EngineErrorCode values. Engine validation failures now use these codes and English messages.
Adapter and UI translation flow
src/lib/adapter/types.ts, src/lib/adapter/local.ts, src/lib/i18n.ts, src/App.svelte
Adapter callbacks carry error codes. German and English translations cover all codes. The UI resolves localized text before showing the error.
Error coverage and release documentation
tests/engine.test.ts, tests/adapter.test.ts, CLAUDE.md, package.json
Tests verify error codes, message format, adapter propagation, and translation coverage. Documentation and package metadata reflect the updated contract.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Mergeability Score: ⚪ Minimal · up to 517cf

The change routes stable error codes to the UI for language-specific messages, with reported passing checks and tests; no actionable merge-blocking risk remains beyond normal review.

Sequence Diagram(s)

sequenceDiagram
  participant Engine
  participant LocalAdapter
  participant AppSvelte
  participant i18n
  Engine->>LocalAdapter: throw EngineError with code
  LocalAdapter->>AppSvelte: onError(code)
  AppSvelte->>i18n: resolve t.errors[code]
  i18n-->>AppSvelte: localized error text
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: localizing rule-violation messages through stable error codes.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/localized-engine-errors

Comment @coderabbitai help to get the list of available commands.

Konflikt betraf nur die Versionsnummer. Aufgeloest auf main-Basis und
auf 1.4.3 gesetzt, damit sie sich nicht mit #27 (1.4.2) ueberschneidet.

Mit dem a11y-Fix aus #26 zusammen: 0 Fehler, 0 Warnungen, 35/35 Tests.
Neben der Versionsnummer (jetzt 1.4.3, da #27 die 1.4.2 belegt) gab es
den erwarteten inhaltlichen Ueberlapp: #27 hat eine Wurfstelle fuer die
Null-Kette ergaenzt, die noch den alten einargumentigen Aufruf mit
deutschem Text nutzte. Git konnte das nicht sehen und hat engine.ts
sauber automerged - die Stelle ist jetzt auf den bereits vorbereiteten
Code mustPlayZero umgestellt.

Verifiziert, dass beide Features zusammen greifen:
  code: mustPlayZero
  de:   "Du musst eine 0 legen."
  en:   "You have to play a 0."

37/37 Tests, 0 Fehler, 0 Warnungen.
@tehw0lf
tehw0lf merged commit d31096a into main Aug 12, 2026
21 checks passed
@tehw0lf
tehw0lf deleted the feat/localized-engine-errors branch August 12, 2026 23:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant