feat(web): translate error messages surfaced from API error codes to English

Translates the five client-side error-message maps (world, hunting, combat,
inventory, local-location stores) that re-translate already-English API
error codes back to display text, per design doc §4. Also fixes four
component specs that hard-coded the same German strings when asserting
rendered error text (combat-page, hunt-page, location-interaction-panel,
location-page).
This commit is contained in:
Bastian Wagner
2026-08-21 21:29:10 +02:00
parent 5222bfb2ab
commit 5586e6c672
14 changed files with 53 additions and 53 deletions

View File

@@ -510,12 +510,12 @@ describe('CombatPageComponent', () => {
it('shows an error and retries loading the combat', async () => {
const fixture = await setup(null);
combatStore.error.set('Dieser Kampf wurde nicht gefunden.');
combatStore.error.set('This combat could not be found.');
fixture.detectChanges();
const element = fixture.nativeElement as HTMLElement;
expect(element.querySelector('[role="alert"]')?.textContent).toContain(
'Dieser Kampf wurde nicht gefunden.',
'This combat could not be found.',
);
element.querySelector<HTMLButtonElement>('[data-combat-retry]')?.click();

View File

@@ -80,7 +80,7 @@ describe('CombatStore', () => {
await store.startCombat('encounter-1');
expect(store.combat()).toBeNull();
expect(store.error()).toBe('Du befindest dich bereits in einem Kampf.');
expect(store.error()).toBe("You're already in a combat.");
expect(store.errorCode()).toBe('COMBAT_ALREADY_ACTIVE');
});
@@ -97,7 +97,7 @@ describe('CombatStore', () => {
await store.startCombat('encounter-1');
expect(store.error()).toBe('Du bist zu schwer verwundet, um zu kämpfen. Warte, bis du dich erholt hast.');
expect(store.error()).toBe("You're too badly wounded to fight. Wait until you've recovered.");
});
it('loads the running combat and clears the error that sent us looking for it', async () => {
@@ -150,7 +150,7 @@ describe('CombatStore', () => {
await store.loadCombat('unknown');
expect(store.error()).toBe('Dieser Kampf wurde nicht gefunden.');
expect(store.error()).toBe('This combat could not be found.');
});
it('sends only the ATTACK action and replaces combat with the server response', async () => {

View File

@@ -4,20 +4,20 @@ import { firstValueFrom } from 'rxjs';
import { Combat, CombatAction } from '../../core/api/game-api.models';
import { GameApiService } from '../../core/api/game-api.service';
const GENERIC_ERROR_MESSAGE = 'Der Kampf konnte nicht geladen werden.';
const GENERIC_ERROR_MESSAGE = 'Could not load the combat.';
// Mirrors the combat error codes returned by the combat endpoints.
// Unknown/missing codes fall back to `GENERIC_ERROR_MESSAGE`.
const COMBAT_ERROR_MESSAGES: Readonly<Record<string, string>> = {
HUNT_ENCOUNTER_NOT_FOUND: 'Diese Begegnung wurde nicht gefunden.',
HUNT_ENCOUNTER_ALREADY_CONSUMED: 'Diese Begegnung wurde bereits genutzt.',
INVALID_HUNT_ENCOUNTER: 'Diese Begegnung ist nicht mehr gültig.',
CHARACTER_TRAVELLING: 'Du kannst nicht kämpfen, während du unterwegs bist.',
CHARACTER_TOO_WOUNDED: 'Du bist zu schwer verwundet, um zu kämpfen. Warte, bis du dich erholt hast.',
COMBAT_ALREADY_ACTIVE: 'Du befindest dich bereits in einem Kampf.',
COMBAT_NOT_FOUND: 'Dieser Kampf wurde nicht gefunden.',
COMBAT_ALREADY_FINISHED: 'Dieser Kampf ist bereits beendet.',
COMBAT_NO_POTIONS_REMAINING: 'Du hast keine Tränke mehr.',
HUNT_ENCOUNTER_NOT_FOUND: 'This encounter could not be found.',
HUNT_ENCOUNTER_ALREADY_CONSUMED: 'This encounter has already been used.',
INVALID_HUNT_ENCOUNTER: 'This encounter is no longer valid.',
CHARACTER_TRAVELLING: "You can't fight while travelling.",
CHARACTER_TOO_WOUNDED: "You're too badly wounded to fight. Wait until you've recovered.",
COMBAT_ALREADY_ACTIVE: "You're already in a combat.",
COMBAT_NOT_FOUND: 'This combat could not be found.',
COMBAT_ALREADY_FINISHED: 'This combat has already ended.',
COMBAT_NO_POTIONS_REMAINING: 'You have no potions left.',
};
@Injectable({ providedIn: 'root' })