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:
@@ -510,12 +510,12 @@ describe('CombatPageComponent', () => {
|
|||||||
|
|
||||||
it('shows an error and retries loading the combat', async () => {
|
it('shows an error and retries loading the combat', async () => {
|
||||||
const fixture = await setup(null);
|
const fixture = await setup(null);
|
||||||
combatStore.error.set('Dieser Kampf wurde nicht gefunden.');
|
combatStore.error.set('This combat could not be found.');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const element = fixture.nativeElement as HTMLElement;
|
const element = fixture.nativeElement as HTMLElement;
|
||||||
expect(element.querySelector('[role="alert"]')?.textContent).toContain(
|
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();
|
element.querySelector<HTMLButtonElement>('[data-combat-retry]')?.click();
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ describe('CombatStore', () => {
|
|||||||
await store.startCombat('encounter-1');
|
await store.startCombat('encounter-1');
|
||||||
|
|
||||||
expect(store.combat()).toBeNull();
|
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');
|
expect(store.errorCode()).toBe('COMBAT_ALREADY_ACTIVE');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ describe('CombatStore', () => {
|
|||||||
|
|
||||||
await store.startCombat('encounter-1');
|
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 () => {
|
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');
|
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 () => {
|
it('sends only the ATTACK action and replaces combat with the server response', async () => {
|
||||||
|
|||||||
@@ -4,20 +4,20 @@ import { firstValueFrom } from 'rxjs';
|
|||||||
import { Combat, CombatAction } from '../../core/api/game-api.models';
|
import { Combat, CombatAction } from '../../core/api/game-api.models';
|
||||||
import { GameApiService } from '../../core/api/game-api.service';
|
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.
|
// Mirrors the combat error codes returned by the combat endpoints.
|
||||||
// Unknown/missing codes fall back to `GENERIC_ERROR_MESSAGE`.
|
// Unknown/missing codes fall back to `GENERIC_ERROR_MESSAGE`.
|
||||||
const COMBAT_ERROR_MESSAGES: Readonly<Record<string, string>> = {
|
const COMBAT_ERROR_MESSAGES: Readonly<Record<string, string>> = {
|
||||||
HUNT_ENCOUNTER_NOT_FOUND: 'Diese Begegnung wurde nicht gefunden.',
|
HUNT_ENCOUNTER_NOT_FOUND: 'This encounter could not be found.',
|
||||||
HUNT_ENCOUNTER_ALREADY_CONSUMED: 'Diese Begegnung wurde bereits genutzt.',
|
HUNT_ENCOUNTER_ALREADY_CONSUMED: 'This encounter has already been used.',
|
||||||
INVALID_HUNT_ENCOUNTER: 'Diese Begegnung ist nicht mehr gültig.',
|
INVALID_HUNT_ENCOUNTER: 'This encounter is no longer valid.',
|
||||||
CHARACTER_TRAVELLING: 'Du kannst nicht kämpfen, während du unterwegs bist.',
|
CHARACTER_TRAVELLING: "You can't fight while travelling.",
|
||||||
CHARACTER_TOO_WOUNDED: 'Du bist zu schwer verwundet, um zu kämpfen. Warte, bis du dich erholt hast.',
|
CHARACTER_TOO_WOUNDED: "You're too badly wounded to fight. Wait until you've recovered.",
|
||||||
COMBAT_ALREADY_ACTIVE: 'Du befindest dich bereits in einem Kampf.',
|
COMBAT_ALREADY_ACTIVE: "You're already in a combat.",
|
||||||
COMBAT_NOT_FOUND: 'Dieser Kampf wurde nicht gefunden.',
|
COMBAT_NOT_FOUND: 'This combat could not be found.',
|
||||||
COMBAT_ALREADY_FINISHED: 'Dieser Kampf ist bereits beendet.',
|
COMBAT_ALREADY_FINISHED: 'This combat has already ended.',
|
||||||
COMBAT_NO_POTIONS_REMAINING: 'Du hast keine Tränke mehr.',
|
COMBAT_NO_POTIONS_REMAINING: 'You have no potions left.',
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ describe('HuntPageComponent', () => {
|
|||||||
const fixture = await setup(burnedRoad, threeEncounterHunt);
|
const fixture = await setup(burnedRoad, threeEncounterHunt);
|
||||||
combatStore.startCombat.mockImplementation(async () => {
|
combatStore.startCombat.mockImplementation(async () => {
|
||||||
combatStore.errorCode.set('COMBAT_ALREADY_ACTIVE');
|
combatStore.errorCode.set('COMBAT_ALREADY_ACTIVE');
|
||||||
combatStore.error.set('Du befindest dich bereits in einem Kampf.');
|
combatStore.error.set("You're already in a combat.");
|
||||||
});
|
});
|
||||||
combatStore.loadActiveCombat.mockResolvedValue({ ...startedCombat, id: 'combat-running' });
|
combatStore.loadActiveCombat.mockResolvedValue({ ...startedCombat, id: 'combat-running' });
|
||||||
const element = fixture.nativeElement as HTMLElement;
|
const element = fixture.nativeElement as HTMLElement;
|
||||||
@@ -249,7 +249,7 @@ describe('HuntPageComponent', () => {
|
|||||||
const fixture = await setup(burnedRoad, threeEncounterHunt);
|
const fixture = await setup(burnedRoad, threeEncounterHunt);
|
||||||
combatStore.startCombat.mockImplementation(async () => {
|
combatStore.startCombat.mockImplementation(async () => {
|
||||||
combatStore.errorCode.set('HUNT_ENCOUNTER_ALREADY_CONSUMED');
|
combatStore.errorCode.set('HUNT_ENCOUNTER_ALREADY_CONSUMED');
|
||||||
combatStore.error.set('Diese Begegnung wurde bereits genutzt.');
|
combatStore.error.set('This encounter has already been used.');
|
||||||
});
|
});
|
||||||
const element = fixture.nativeElement as HTMLElement;
|
const element = fixture.nativeElement as HTMLElement;
|
||||||
|
|
||||||
@@ -267,12 +267,12 @@ describe('HuntPageComponent', () => {
|
|||||||
|
|
||||||
it('shows a combat-start error and dismisses it', async () => {
|
it('shows a combat-start error and dismisses it', async () => {
|
||||||
const fixture = await setup(burnedRoad, threeEncounterHunt);
|
const fixture = await setup(burnedRoad, threeEncounterHunt);
|
||||||
combatStore.error.set('Du befindest dich bereits in einem Kampf.');
|
combatStore.error.set("You're already in a combat.");
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const element = fixture.nativeElement as HTMLElement;
|
const element = fixture.nativeElement as HTMLElement;
|
||||||
const alerts = Array.from(element.querySelectorAll('[role="alert"]'));
|
const alerts = Array.from(element.querySelectorAll('[role="alert"]'));
|
||||||
expect(alerts.some((alert) => alert.textContent?.includes('Du befindest dich bereits in einem Kampf.'))).toBe(
|
expect(alerts.some((alert) => alert.textContent?.includes("You're already in a combat."))).toBe(
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -380,12 +380,12 @@ describe('HuntPageComponent', () => {
|
|||||||
|
|
||||||
it('displays a hunting error and retries via startHunt when there is no current hunt', async () => {
|
it('displays a hunting error and retries via startHunt when there is no current hunt', async () => {
|
||||||
const fixture = await setup(burnedRoad);
|
const fixture = await setup(burnedRoad);
|
||||||
huntingStore.error.set('An diesem Ort gibt es keine Jagdgebiete.');
|
huntingStore.error.set("There's no hunting ground at this location.");
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
const element = fixture.nativeElement as HTMLElement;
|
const element = fixture.nativeElement as HTMLElement;
|
||||||
expect(element.querySelector('[role="alert"]')?.textContent).toContain(
|
expect(element.querySelector('[role="alert"]')?.textContent).toContain(
|
||||||
'An diesem Ort gibt es keine Jagdgebiete.',
|
"There's no hunting ground at this location.",
|
||||||
);
|
);
|
||||||
element.querySelector<HTMLButtonElement>('[data-hunt-retry]')?.click();
|
element.querySelector<HTMLButtonElement>('[data-hunt-retry]')?.click();
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ describe('HuntingStore', () => {
|
|||||||
|
|
||||||
await store.startHunt();
|
await store.startHunt();
|
||||||
|
|
||||||
expect(store.error()).toBe('Dein Charakter konnte nicht gefunden werden.');
|
expect(store.error()).toBe('Your character could not be found.');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('maps CHARACTER_TRAVELLING to its German message', async () => {
|
it('maps CHARACTER_TRAVELLING to its German message', async () => {
|
||||||
@@ -149,7 +149,7 @@ describe('HuntingStore', () => {
|
|||||||
|
|
||||||
await store.startHunt();
|
await store.startHunt();
|
||||||
|
|
||||||
expect(store.error()).toBe('Du kannst nicht jagen, während du unterwegs bist.');
|
expect(store.error()).toBe("You can't hunt while travelling.");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('maps HUNTING_NOT_AVAILABLE to its German message', async () => {
|
it('maps HUNTING_NOT_AVAILABLE to its German message', async () => {
|
||||||
@@ -165,7 +165,7 @@ describe('HuntingStore', () => {
|
|||||||
|
|
||||||
await store.startHunt();
|
await store.startHunt();
|
||||||
|
|
||||||
expect(store.error()).toBe('An diesem Ort gibt es keine Jagdgebiete.');
|
expect(store.error()).toBe("There's no hunting ground at this location.");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('maps NO_HUNT_ENCOUNTERS_AVAILABLE to its German message', async () => {
|
it('maps NO_HUNT_ENCOUNTERS_AVAILABLE to its German message', async () => {
|
||||||
@@ -185,7 +185,7 @@ describe('HuntingStore', () => {
|
|||||||
|
|
||||||
await store.startHunt();
|
await store.startHunt();
|
||||||
|
|
||||||
expect(store.error()).toBe('Aktuell sind hier keine Gegner zu finden.');
|
expect(store.error()).toBe('No enemies can currently be found here.');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('falls back to the generic message for an HttpErrorResponse with no known code', async () => {
|
it('falls back to the generic message for an HttpErrorResponse with no known code', async () => {
|
||||||
@@ -201,7 +201,7 @@ describe('HuntingStore', () => {
|
|||||||
|
|
||||||
await store.startHunt();
|
await store.startHunt();
|
||||||
|
|
||||||
expect(store.error()).toBe('Weltzustand konnte nicht geladen werden.');
|
expect(store.error()).toBe('Could not load world state.');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses the message of a genuine non-HTTP Error', async () => {
|
it('uses the message of a genuine non-HTTP Error', async () => {
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ import { firstValueFrom } from 'rxjs';
|
|||||||
import { HuntResult } from '../../core/api/game-api.models';
|
import { HuntResult } from '../../core/api/game-api.models';
|
||||||
import { GameApiService } from '../../core/api/game-api.service';
|
import { GameApiService } from '../../core/api/game-api.service';
|
||||||
|
|
||||||
const GENERIC_ERROR_MESSAGE = 'Weltzustand konnte nicht geladen werden.';
|
const GENERIC_ERROR_MESSAGE = 'Could not load world state.';
|
||||||
|
|
||||||
// Mirrors the hunt error codes returned by `POST /api/hunts`.
|
// Mirrors the hunt error codes returned by `POST /api/hunts`.
|
||||||
// Unknown/missing codes fall back to `GENERIC_ERROR_MESSAGE`.
|
// Unknown/missing codes fall back to `GENERIC_ERROR_MESSAGE`.
|
||||||
const HUNT_ERROR_MESSAGES: Readonly<Record<string, string>> = {
|
const HUNT_ERROR_MESSAGES: Readonly<Record<string, string>> = {
|
||||||
CHARACTER_NOT_FOUND: 'Dein Charakter konnte nicht gefunden werden.',
|
CHARACTER_NOT_FOUND: 'Your character could not be found.',
|
||||||
CHARACTER_TRAVELLING: 'Du kannst nicht jagen, während du unterwegs bist.',
|
CHARACTER_TRAVELLING: "You can't hunt while travelling.",
|
||||||
HUNTING_NOT_AVAILABLE: 'An diesem Ort gibt es keine Jagdgebiete.',
|
HUNTING_NOT_AVAILABLE: "There's no hunting ground at this location.",
|
||||||
NO_HUNT_ENCOUNTERS_AVAILABLE: 'Aktuell sind hier keine Gegner zu finden.',
|
NO_HUNT_ENCOUNTERS_AVAILABLE: 'No enemies can currently be found here.',
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
|
|||||||
@@ -140,6 +140,6 @@ describe('InventoryStore', () => {
|
|||||||
|
|
||||||
await store.equip('item-blade');
|
await store.equip('item-blade');
|
||||||
|
|
||||||
expect(store.error()).toBe('Dieser Gegenstand kann nicht ausgerüstet werden.');
|
expect(store.error()).toBe("This item can't be equipped.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ import { EquipmentResponse, InventoryItem, InventoryResponse } from '../../core/
|
|||||||
import { GameApiService } from '../../core/api/game-api.service';
|
import { GameApiService } from '../../core/api/game-api.service';
|
||||||
import { WorldStore } from '../world/world.store';
|
import { WorldStore } from '../world/world.store';
|
||||||
|
|
||||||
const GENERIC_ERROR_MESSAGE = 'Inventar konnte nicht geladen werden.';
|
const GENERIC_ERROR_MESSAGE = 'Could not load the inventory.';
|
||||||
|
|
||||||
// Mirrors `EquipmentErrorCode` in `apps/api/src/equipment/equipment.errors.ts`.
|
// Mirrors `EquipmentErrorCode` in `apps/api/src/equipment/equipment.errors.ts`.
|
||||||
const EQUIPMENT_ERROR_MESSAGES: Readonly<Record<string, string>> = {
|
const EQUIPMENT_ERROR_MESSAGES: Readonly<Record<string, string>> = {
|
||||||
CHARACTER_ITEM_NOT_FOUND: 'Dieser Gegenstand konnte nicht gefunden werden.',
|
CHARACTER_ITEM_NOT_FOUND: 'This item could not be found.',
|
||||||
ITEM_NOT_OWNED: 'Dieser Gegenstand gehört dir nicht.',
|
ITEM_NOT_OWNED: "This item doesn't belong to you.",
|
||||||
ITEM_NOT_EQUIPPABLE: 'Dieser Gegenstand kann nicht ausgerüstet werden.',
|
ITEM_NOT_EQUIPPABLE: "This item can't be equipped.",
|
||||||
INVALID_EQUIPMENT_SLOT: 'Dieser Ausrüstungsplatz ist ungültig.',
|
INVALID_EQUIPMENT_SLOT: 'This equipment slot is invalid.',
|
||||||
CHARACTER_IN_COMBAT: 'Ausrüstung kann während eines Kampfes nicht geändert werden.',
|
CHARACTER_IN_COMBAT: "Equipment can't be changed during combat.",
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ describe('LocalLocationStore', () => {
|
|||||||
|
|
||||||
await store.runInteraction('inspect-tracks');
|
await store.runInteraction('inspect-tracks');
|
||||||
|
|
||||||
expect(store.interactionError()).toBe('Hier gibt es dazu nichts zu entdecken.');
|
expect(store.interactionError()).toBe("There's nothing to discover here.");
|
||||||
expect(store.interactionResult()).toBeNull();
|
expect(store.interactionResult()).toBeNull();
|
||||||
expect(store.interactionOpen()).toBe(true);
|
expect(store.interactionOpen()).toBe(true);
|
||||||
});
|
});
|
||||||
@@ -107,7 +107,7 @@ describe('LocalLocationStore', () => {
|
|||||||
|
|
||||||
await store.runInteraction('inspect-tracks');
|
await store.runInteraction('inspect-tracks');
|
||||||
|
|
||||||
expect(store.interactionError()).toBe('Diese Handlung ist gerade nicht möglich.');
|
expect(store.interactionError()).toBe("This action isn't possible right now.");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('closes the panel without clearing the location', async () => {
|
it('closes the panel without clearing the location', async () => {
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import {
|
|||||||
import { GameApiService } from '../../core/api/game-api.service';
|
import { GameApiService } from '../../core/api/game-api.service';
|
||||||
import { WorldStore } from './world.store';
|
import { WorldStore } from './world.store';
|
||||||
|
|
||||||
const GENERIC_INTERACTION_ERROR = 'Diese Handlung ist gerade nicht möglich.';
|
const GENERIC_INTERACTION_ERROR = "This action isn't possible right now.";
|
||||||
|
|
||||||
// Mirrors the codes in `apps/api/src/world/world.errors.ts`.
|
// Mirrors the codes in `apps/api/src/world/world.errors.ts`.
|
||||||
const INTERACTION_ERROR_MESSAGES: Readonly<Record<string, string>> = {
|
const INTERACTION_ERROR_MESSAGES: Readonly<Record<string, string>> = {
|
||||||
LOCATION_INTERACTION_UNAVAILABLE: 'Hier gibt es dazu nichts zu entdecken.',
|
LOCATION_INTERACTION_UNAVAILABLE: "There's nothing to discover here.",
|
||||||
CHARACTER_NOT_FOUND: 'Dein Charakter konnte nicht gefunden werden.',
|
CHARACTER_NOT_FOUND: 'Your character could not be found.',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -61,10 +61,10 @@ describe('LocationInteractionPanelComponent', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('reports a rejected interaction in place instead of navigating away', async () => {
|
it('reports a rejected interaction in place instead of navigating away', async () => {
|
||||||
const { element } = await setup({ error: 'Hier gibt es dazu nichts zu entdecken.' });
|
const { element } = await setup({ error: "There's nothing to discover here." });
|
||||||
|
|
||||||
expect(element.querySelector('[role="alert"]')?.textContent).toContain(
|
expect(element.querySelector('[role="alert"]')?.textContent).toContain(
|
||||||
'Hier gibt es dazu nichts zu entdecken.',
|
"There's nothing to discover here.",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ describe('LocationPageComponent', () => {
|
|||||||
it('offers a retry when the location could not be loaded', async () => {
|
it('offers a retry when the location could not be loaded', async () => {
|
||||||
const { fixture, element } = await setup(null);
|
const { fixture, element } = await setup(null);
|
||||||
|
|
||||||
error.set('Weltzustand konnte nicht geladen werden.');
|
error.set('Could not load world state.');
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
expect(element.querySelector('[role="alert"]')?.textContent).toContain(
|
expect(element.querySelector('[role="alert"]')?.textContent).toContain(
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ describe('WorldStore', () => {
|
|||||||
|
|
||||||
await store.startTravel();
|
await store.startTravel();
|
||||||
|
|
||||||
expect(store.error()).toBe('Du befindest dich bereits auf Reisen.');
|
expect(store.error()).toBe("You're already travelling.");
|
||||||
|
|
||||||
pendingResync.next({ status: 'IDLE' });
|
pendingResync.next({ status: 'IDLE' });
|
||||||
pendingResync.complete();
|
pendingResync.complete();
|
||||||
@@ -307,7 +307,7 @@ describe('WorldStore', () => {
|
|||||||
|
|
||||||
await store.startTravel();
|
await store.startTravel();
|
||||||
|
|
||||||
expect(store.error()).toBe('Weltzustand konnte nicht geladen werden.');
|
expect(store.error()).toBe('Could not load world state.');
|
||||||
|
|
||||||
pendingResync.next({ status: 'IDLE' });
|
pendingResync.next({ status: 'IDLE' });
|
||||||
pendingResync.complete();
|
pendingResync.complete();
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ import {
|
|||||||
} from '../../core/api/game-api.models';
|
} from '../../core/api/game-api.models';
|
||||||
import { GameApiService } from '../../core/api/game-api.service';
|
import { GameApiService } from '../../core/api/game-api.service';
|
||||||
|
|
||||||
const GENERIC_ERROR_MESSAGE = 'Weltzustand konnte nicht geladen werden.';
|
const GENERIC_ERROR_MESSAGE = 'Could not load world state.';
|
||||||
|
|
||||||
// Mirrors the `TravelErrorCode` union in `apps/api/src/travel/travel.errors.ts`.
|
// Mirrors the `TravelErrorCode` union in `apps/api/src/travel/travel.errors.ts`.
|
||||||
// Unknown/missing codes fall back to `GENERIC_ERROR_MESSAGE`.
|
// Unknown/missing codes fall back to `GENERIC_ERROR_MESSAGE`.
|
||||||
const TRAVEL_ERROR_MESSAGES: Readonly<Record<string, string>> = {
|
const TRAVEL_ERROR_MESSAGES: Readonly<Record<string, string>> = {
|
||||||
TRAVEL_ALREADY_ACTIVE: 'Du befindest dich bereits auf Reisen.',
|
TRAVEL_ALREADY_ACTIVE: "You're already travelling.",
|
||||||
INVALID_TRAVEL_TARGET: 'Dieses Ziel ist von hier aus nicht erreichbar.',
|
INVALID_TRAVEL_TARGET: "This destination isn't reachable from here.",
|
||||||
CHARACTER_NOT_FOUND: 'Dein Charakter konnte nicht gefunden werden.',
|
CHARACTER_NOT_FOUND: 'Your character could not be found.',
|
||||||
TRAVEL_STATE_INVALID: 'Der Reisezustand ist ungültig. Bitte lade die Seite neu.',
|
TRAVEL_STATE_INVALID: 'Travel state is invalid. Please reload the page.',
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
|
|||||||
Reference in New Issue
Block a user