fix: correct final whole-branch review findings for 0.6.6 English content
- TRAVELLING spelling: fix TRAVELING -> TRAVELLING in travel-panel.component.html to match UK spelling used everywhere else (world/hunting/combat stores + API error messages) - Grenzwacht -> Border Watch: fix stale German faction display name in reputation-display, reputation.service/controller, turn-in.service specs, and the vertical-slice seed spec test title - Suedtor von Graufurt -> Graufurt South Gate: fix stale ASCII-transliterated German location name in hunting.service.spec.ts - Aschenfelder(n) -> Ashen Fields: fix stale German location name/description in top-bar.component.spec.ts and context-panel.component.spec.ts (key identifiers left untouched) - Fix 7 test titles still describing translated error messages as "German" across world/hunting/inventory/combat store specs - README: update demo location names from German to their current English names (Graufurt South Gate, Burned Road) - item-rarity.enum.ts: fix now-false comment claiming rarity labels are German; the frontend RARITY_LABELS map is English Pure literal-string/comment substitutions; no keys, ids, or logic changed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ACkMEDYiwtcfchqKkiUJNX
This commit is contained in:
@@ -7,8 +7,8 @@ A dark-fantasy browser RPG built as an npm-workspace modular monolith:
|
|||||||
- `packages/*` — reserved shared boundaries (currently unused)
|
- `packages/*` — reserved shared boundaries (currently unused)
|
||||||
|
|
||||||
This README documents the first visible vertical slice: a server-authoritative
|
This README documents the first visible vertical slice: a server-authoritative
|
||||||
world/travel loop between two locations (Südtor von Graufurt and Verbrannte
|
world/travel loop between two locations (Graufurt South Gate and Burned Road)
|
||||||
Straße) for one demo character, with no login required.
|
for one demo character, with no login required.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@@ -47,8 +47,8 @@ running. Once both are up:
|
|||||||
- Web: `http://localhost:4200`, which proxies `/api/*` requests to
|
- Web: `http://localhost:4200`, which proxies `/api/*` requests to
|
||||||
`http://localhost:3000` in development (see `apps/web/proxy.conf.json`)
|
`http://localhost:3000` in development (see `apps/web/proxy.conf.json`)
|
||||||
|
|
||||||
Open `http://localhost:4200/world` to see Aric Duskwalker at the Südtor von
|
Open `http://localhost:4200/world` to see Aric Duskwalker at the Graufurt
|
||||||
Graufurt and travel to the Verbrannte Straße and back.
|
South Gate and travel to the Burned Road and back.
|
||||||
|
|
||||||
### Configuration (`.env`)
|
### Configuration (`.env`)
|
||||||
|
|
||||||
|
|||||||
@@ -606,7 +606,7 @@ describe('seedVisibleVerticalSlice', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('seeds the Grenzwacht faction', async () => {
|
it('seeds the Border Watch faction', async () => {
|
||||||
const reputationFactionRepository = new InMemoryRepository();
|
const reputationFactionRepository = new InMemoryRepository();
|
||||||
const dataSource = createDataSource(
|
const dataSource = createDataSource(
|
||||||
new InMemoryRepository(),
|
new InMemoryRepository(),
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ function safeLocation(): LocationDefinition {
|
|||||||
return {
|
return {
|
||||||
id: SAFE_LOCATION_ID,
|
id: SAFE_LOCATION_ID,
|
||||||
key: 'south-gate',
|
key: 'south-gate',
|
||||||
name: 'Suedtor von Graufurt',
|
name: 'Graufurt South Gate',
|
||||||
description: 'A safe gate.',
|
description: 'A safe gate.',
|
||||||
regionKey: 'ashen-fields',
|
regionKey: 'ashen-fields',
|
||||||
minRecommendedLevel: 1,
|
minRecommendedLevel: 1,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// Mirrors docs/Ashen_Realms_Balancing_Items_Loot_Design_V1.md §19:
|
// Mirrors docs/Ashen_Realms_Balancing_Items_Loot_Design_V1.md §19:
|
||||||
// Gewöhnlich / Selten / Episch. German labels live in the frontend.
|
// Common / Rare / Epic. Display labels live in the frontend.
|
||||||
export enum ItemRarity {
|
export enum ItemRarity {
|
||||||
COMMON = 'COMMON',
|
COMMON = 'COMMON',
|
||||||
RARE = 'RARE',
|
RARE = 'RARE',
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ describe('ReputationController', () => {
|
|||||||
const entries = [
|
const entries = [
|
||||||
{
|
{
|
||||||
factionKey: 'border-guard',
|
factionKey: 'border-guard',
|
||||||
factionName: 'Grenzwacht',
|
factionName: 'Border Watch',
|
||||||
reputation: 40,
|
reputation: 40,
|
||||||
rank: 'STRANGER',
|
rank: 'STRANGER',
|
||||||
rankLabel: 'Stranger',
|
rankLabel: 'Stranger',
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ function faction(
|
|||||||
return {
|
return {
|
||||||
id: FACTION_ID,
|
id: FACTION_ID,
|
||||||
key: 'border-guard',
|
key: 'border-guard',
|
||||||
name: 'Grenzwacht',
|
name: 'Border Watch',
|
||||||
description: '',
|
description: '',
|
||||||
regionKey: 'ashen-fields',
|
regionKey: 'ashen-fields',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -312,7 +312,7 @@ describe('ReputationService', () => {
|
|||||||
expect(result).toEqual([
|
expect(result).toEqual([
|
||||||
{
|
{
|
||||||
factionKey: 'border-guard',
|
factionKey: 'border-guard',
|
||||||
factionName: 'Grenzwacht',
|
factionName: 'Border Watch',
|
||||||
reputation: 0,
|
reputation: 0,
|
||||||
rank: 'STRANGER',
|
rank: 'STRANGER',
|
||||||
rankLabel: 'Stranger',
|
rankLabel: 'Stranger',
|
||||||
@@ -330,7 +330,7 @@ describe('ReputationService', () => {
|
|||||||
|
|
||||||
expect(result[0]).toEqual({
|
expect(result[0]).toEqual({
|
||||||
factionKey: 'border-guard',
|
factionKey: 'border-guard',
|
||||||
factionName: 'Grenzwacht',
|
factionName: 'Border Watch',
|
||||||
reputation: 300,
|
reputation: 300,
|
||||||
rank: 'KNOWN',
|
rank: 'KNOWN',
|
||||||
rankLabel: 'Known',
|
rankLabel: 'Known',
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ function faction(
|
|||||||
return {
|
return {
|
||||||
id: FACTION_ID,
|
id: FACTION_ID,
|
||||||
key: 'border-guard',
|
key: 'border-guard',
|
||||||
name: 'Grenzwacht',
|
name: 'Border Watch',
|
||||||
enabled: true,
|
enabled: true,
|
||||||
...overrides,
|
...overrides,
|
||||||
} as ReputationFaction;
|
} as ReputationFaction;
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ describe('CombatStore', () => {
|
|||||||
expect(store.errorCode()).toBe('COMBAT_ALREADY_ACTIVE');
|
expect(store.errorCode()).toBe('COMBAT_ALREADY_ACTIVE');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('maps CHARACTER_TOO_WOUNDED to its German message', async () => {
|
it('maps CHARACTER_TOO_WOUNDED to its English message', async () => {
|
||||||
api.startCombat.mockReturnValue(
|
api.startCombat.mockReturnValue(
|
||||||
throwError(
|
throwError(
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ describe('HuntingStore', () => {
|
|||||||
expect(store.encounters()).toEqual(refreshedHuntResult.encounters);
|
expect(store.encounters()).toEqual(refreshedHuntResult.encounters);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('maps CHARACTER_NOT_FOUND to its German message', async () => {
|
it('maps CHARACTER_NOT_FOUND to its English message', async () => {
|
||||||
api.startHunt.mockReturnValue(
|
api.startHunt.mockReturnValue(
|
||||||
throwError(
|
throwError(
|
||||||
() =>
|
() =>
|
||||||
@@ -136,7 +136,7 @@ describe('HuntingStore', () => {
|
|||||||
expect(store.error()).toBe('Your character could not be found.');
|
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 English message', async () => {
|
||||||
api.startHunt.mockReturnValue(
|
api.startHunt.mockReturnValue(
|
||||||
throwError(
|
throwError(
|
||||||
() =>
|
() =>
|
||||||
@@ -152,7 +152,7 @@ describe('HuntingStore', () => {
|
|||||||
expect(store.error()).toBe("You can't hunt while travelling.");
|
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 English message', async () => {
|
||||||
api.startHunt.mockReturnValue(
|
api.startHunt.mockReturnValue(
|
||||||
throwError(
|
throwError(
|
||||||
() =>
|
() =>
|
||||||
@@ -168,7 +168,7 @@ describe('HuntingStore', () => {
|
|||||||
expect(store.error()).toBe("There's no hunting ground at this location.");
|
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 English message', async () => {
|
||||||
api.startHunt.mockReturnValue(
|
api.startHunt.mockReturnValue(
|
||||||
throwError(
|
throwError(
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ describe('InventoryStore', () => {
|
|||||||
expect(worldStore.refreshCharacter).toHaveBeenCalledOnce();
|
expect(worldStore.refreshCharacter).toHaveBeenCalledOnce();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('surfaces a German message for a known equip error', async () => {
|
it('surfaces an English message for a known equip error', async () => {
|
||||||
await store.load();
|
await store.load();
|
||||||
api.equipItem.mockReturnValue(
|
api.equipItem.mockReturnValue(
|
||||||
throwError(() => new HttpErrorResponse({ error: { code: 'ITEM_NOT_EQUIPPABLE' }, status: 400 })),
|
throwError(() => new HttpErrorResponse({ error: { code: 'ITEM_NOT_EQUIPPABLE' }, status: 400 })),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<section class="travel-panel" aria-labelledby="travel-panel-title">
|
<section class="travel-panel" aria-labelledby="travel-panel-title">
|
||||||
@if (travellingTravel; as travel) {
|
@if (travellingTravel; as travel) {
|
||||||
<span class="travel-panel__eyebrow" role="status">TRAVELING</span>
|
<span class="travel-panel__eyebrow" role="status">TRAVELLING</span>
|
||||||
<h2 id="travel-panel-title">Destination: {{ travel.targetLocation.name }}</h2>
|
<h2 id="travel-panel-title">Destination: {{ travel.targetLocation.name }}</h2>
|
||||||
<dl class="travel-panel__details">
|
<dl class="travel-panel__details">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ describe('WorldStore', () => {
|
|||||||
expect(store.currentTravel()).toEqual({ status: 'IDLE' });
|
expect(store.currentTravel()).toEqual({ status: 'IDLE' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('maps a known HttpErrorResponse travel error code to a specific German message', async () => {
|
it('maps a known HttpErrorResponse travel error code to a specific English message', async () => {
|
||||||
await store.load();
|
await store.load();
|
||||||
store.selectConnection(currentLocation.connections[0]);
|
store.selectConnection(currentLocation.connections[0]);
|
||||||
api.startTravel.mockReturnValue(
|
api.startTravel.mockReturnValue(
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const southGate = {
|
|||||||
id: 'south-gate-id',
|
id: 'south-gate-id',
|
||||||
key: 'south-gate',
|
key: 'south-gate',
|
||||||
name: 'Graufurt South Gate',
|
name: 'Graufurt South Gate',
|
||||||
description: 'Der letzte sichere Schritt vor den Aschenfeldern.',
|
description: 'The last safe step before the Ashen Fields.',
|
||||||
regionKey: 'ashen-fields',
|
regionKey: 'ashen-fields',
|
||||||
minRecommendedLevel: 1,
|
minRecommendedLevel: 1,
|
||||||
maxRecommendedLevel: 1,
|
maxRecommendedLevel: 1,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ function characterFixture(overrides: Partial<CharacterResponse> = {}): Character
|
|||||||
attack: 10,
|
attack: 10,
|
||||||
hpRegenPerSecond: 1,
|
hpRegenPerSecond: 1,
|
||||||
hpRegenSince: null,
|
hpRegenSince: null,
|
||||||
currentLocation: { id: 'location-1', key: 'aschenfelder', name: 'Aschenfelder' },
|
currentLocation: { id: 'location-1', key: 'aschenfelder', name: 'Ashen Fields' },
|
||||||
...overrides,
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ describe('ReputationDisplayComponent', () => {
|
|||||||
it('renders the faction name and rank', async () => {
|
it('renders the faction name and rank', async () => {
|
||||||
const fixture = await setup({
|
const fixture = await setup({
|
||||||
factionKey: 'border-guard',
|
factionKey: 'border-guard',
|
||||||
factionName: 'Grenzwacht',
|
factionName: 'Border Watch',
|
||||||
reputation: 320,
|
reputation: 320,
|
||||||
rank: 'KNOWN',
|
rank: 'KNOWN',
|
||||||
rankLabel: 'Known',
|
rankLabel: 'Known',
|
||||||
@@ -22,14 +22,14 @@ describe('ReputationDisplayComponent', () => {
|
|||||||
});
|
});
|
||||||
const element = fixture.nativeElement as HTMLElement;
|
const element = fixture.nativeElement as HTMLElement;
|
||||||
|
|
||||||
expect(element.textContent).toContain('Grenzwacht');
|
expect(element.textContent).toContain('Border Watch');
|
||||||
expect(element.textContent).toContain('Known');
|
expect(element.textContent).toContain('Known');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows current reputation against the next threshold', async () => {
|
it('shows current reputation against the next threshold', async () => {
|
||||||
const fixture = await setup({
|
const fixture = await setup({
|
||||||
factionKey: 'border-guard',
|
factionKey: 'border-guard',
|
||||||
factionName: 'Grenzwacht',
|
factionName: 'Border Watch',
|
||||||
reputation: 320,
|
reputation: 320,
|
||||||
rank: 'KNOWN',
|
rank: 'KNOWN',
|
||||||
rankLabel: 'Known',
|
rankLabel: 'Known',
|
||||||
@@ -44,7 +44,7 @@ describe('ReputationDisplayComponent', () => {
|
|||||||
it('renders a progress fraction between 0 and 100', async () => {
|
it('renders a progress fraction between 0 and 100', async () => {
|
||||||
const fixture = await setup({
|
const fixture = await setup({
|
||||||
factionKey: 'border-guard',
|
factionKey: 'border-guard',
|
||||||
factionName: 'Grenzwacht',
|
factionName: 'Border Watch',
|
||||||
reputation: 320,
|
reputation: 320,
|
||||||
rank: 'KNOWN',
|
rank: 'KNOWN',
|
||||||
rankLabel: 'Known',
|
rankLabel: 'Known',
|
||||||
@@ -61,7 +61,7 @@ describe('ReputationDisplayComponent', () => {
|
|||||||
it('handles the top rank with no next threshold without crashing or showing a bogus progress bar', async () => {
|
it('handles the top rank with no next threshold without crashing or showing a bogus progress bar', async () => {
|
||||||
const fixture = await setup({
|
const fixture = await setup({
|
||||||
factionKey: 'border-guard',
|
factionKey: 'border-guard',
|
||||||
factionName: 'Grenzwacht',
|
factionName: 'Border Watch',
|
||||||
reputation: 1500,
|
reputation: 1500,
|
||||||
rank: 'ESTEEMED',
|
rank: 'ESTEEMED',
|
||||||
rankLabel: 'Esteemed',
|
rankLabel: 'Esteemed',
|
||||||
|
|||||||
Reference in New Issue
Block a user