[MVP][frontend] Issue #241: host/player route i18n integration + secondary no-audio guard #247
@@ -69,6 +69,7 @@ describe('session route context', () => {
|
|||||||
sessionCode: 'AB12',
|
sessionCode: 'AB12',
|
||||||
playerId: 5,
|
playerId: 5,
|
||||||
token: 'tok-5',
|
token: 'tok-5',
|
||||||
|
locale: 'en',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -80,7 +81,25 @@ describe('session route context', () => {
|
|||||||
sessionCode: 'AB12',
|
sessionCode: 'AB12',
|
||||||
playerId: null,
|
playerId: null,
|
||||||
token: null,
|
token: null,
|
||||||
|
locale: 'en',
|
||||||
});
|
});
|
||||||
expect(sessionStorage.setItem).toHaveBeenCalledWith('wpp.host-session-code', 'AB12');
|
expect(sessionStorage.setItem).toHaveBeenCalledWith('wpp.host-session-code', 'AB12');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('resolvers normalize and expose locale from lang query param', () => {
|
||||||
|
setWindow(storageMock(), storageMock());
|
||||||
|
|
||||||
|
expect(hostRouteContextResolver(route({}, { lang: 'da-DK' }) as never, {} as never).locale).toBe('da');
|
||||||
|
expect(playerRouteContextResolver(route({}, { lang: 'EN' }) as never, {} as never).locale).toBe('en');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not reset persisted preferred locale when lang query param is absent', () => {
|
||||||
|
const localStorage = storageMock({ 'wpp.locale': 'da' });
|
||||||
|
setWindow(localStorage, storageMock());
|
||||||
|
|
||||||
|
expect(hostRouteContextResolver(route({}, { lang: 'da' }) as never, {} as never).locale).toBe('da');
|
||||||
|
expect(hostRouteContextResolver(route({}, {}) as never, {} as never).locale).toBe('da');
|
||||||
|
expect(localStorage.setItem).toHaveBeenCalledTimes(1);
|
||||||
|
expect(localStorage.setItem).toHaveBeenCalledWith('wpp.locale', 'da');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ import { inject } from '@angular/core';
|
|||||||
import { type ActivatedRouteSnapshot, type CanActivateFn, type ResolveFn, Router, type UrlTree } from '@angular/router';
|
import { type ActivatedRouteSnapshot, type CanActivateFn, type ResolveFn, Router, type UrlTree } from '@angular/router';
|
||||||
|
|
||||||
import { createSessionContextStore } from '../../../src/spa/session-context-store';
|
import { createSessionContextStore } from '../../../src/spa/session-context-store';
|
||||||
|
import { normalizeLocale, resolvePreferredLocale, setPreferredLocale } from './lobby-i18n';
|
||||||
|
|
||||||
export interface RouteSessionContext {
|
export interface RouteSessionContext {
|
||||||
sessionCode: string | null;
|
sessionCode: string | null;
|
||||||
playerId: number | null;
|
playerId: number | null;
|
||||||
token: string | null;
|
token: string | null;
|
||||||
|
locale: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HOST_STORAGE_KEY = 'wpp.host-session-code';
|
const HOST_STORAGE_KEY = 'wpp.host-session-code';
|
||||||
@@ -61,6 +63,17 @@ export function resolveSessionCode(route: ActivatedRouteSnapshot, mode: 'host' |
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveRouteLocale(route: ActivatedRouteSnapshot): string {
|
||||||
|
const langParam = route.queryParamMap.get('lang');
|
||||||
|
if (langParam !== null) {
|
||||||
|
const locale = normalizeLocale(langParam);
|
||||||
|
setPreferredLocale(locale);
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvePreferredLocale();
|
||||||
|
}
|
||||||
|
|
||||||
async function sessionExists(code: string): Promise<boolean> {
|
async function sessionExists(code: string): Promise<boolean> {
|
||||||
const response = await fetch(`/lobby/sessions/${encodeURIComponent(code)}`, {
|
const response = await fetch(`/lobby/sessions/${encodeURIComponent(code)}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@@ -118,23 +131,26 @@ export const playerRouteGuard: CanActivateFn = (route) => guard('player', route)
|
|||||||
|
|
||||||
export const hostRouteContextResolver: ResolveFn<RouteSessionContext> = (route) => {
|
export const hostRouteContextResolver: ResolveFn<RouteSessionContext> = (route) => {
|
||||||
const code = resolveSessionCode(route, 'host');
|
const code = resolveSessionCode(route, 'host');
|
||||||
|
const locale = resolveRouteLocale(route);
|
||||||
if (code) {
|
if (code) {
|
||||||
window.sessionStorage.setItem(HOST_STORAGE_KEY, code);
|
window.sessionStorage.setItem(HOST_STORAGE_KEY, code);
|
||||||
}
|
}
|
||||||
return { sessionCode: code, playerId: null, token: null };
|
return { sessionCode: code, playerId: null, token: null, locale };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const playerRouteContextResolver: ResolveFn<RouteSessionContext> = (route) => {
|
export const playerRouteContextResolver: ResolveFn<RouteSessionContext> = (route) => {
|
||||||
const code = resolveSessionCode(route, 'player');
|
const code = resolveSessionCode(route, 'player');
|
||||||
|
const locale = resolveRouteLocale(route);
|
||||||
const context = createSessionContextStore(window.localStorage).get();
|
const context = createSessionContextStore(window.localStorage).get();
|
||||||
|
|
||||||
if (!code || !context || normalizeCode(context.sessionCode) !== code) {
|
if (!code || !context || normalizeCode(context.sessionCode) !== code) {
|
||||||
return { sessionCode: code, playerId: null, token: null };
|
return { sessionCode: code, playerId: null, token: null, locale };
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sessionCode: code,
|
sessionCode: code,
|
||||||
playerId: Number.isInteger(context.playerId) && context.playerId > 0 ? context.playerId : null,
|
playerId: Number.isInteger(context.playerId) && context.playerId > 0 ? context.playerId : null,
|
||||||
token: context.token.trim() || null,
|
token: context.token.trim() || null,
|
||||||
|
locale,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user