Merge pull request '[MVP][READY] #175-B Angular i18n shell (shared keys + da/en bootstrap) (#239)' (#244) from dev/issue-239-angular-i18n-shell into main
All checks were successful
CI / test-and-quality (push) Successful in 2m34s

Auto-merge by integrator: required checks green + official approval.
This commit was merged in pull request #244.
This commit is contained in:
2026-03-02 01:23:21 +01:00
3 changed files with 48 additions and 5 deletions

View File

@@ -26,13 +26,13 @@ describe('i18n MVP flow smoke (host/player + audio policy)', () => {
host.ngOnInit();
player.ngOnInit();
expect(host.copy('host.start_round')).toBe('Start round');
expect(player.copy('player.submit_guess')).toBe('Submit guess');
expect(host.copy('game.host.start_round')).toBe('Start round');
expect(player.copy('game.player.submit_guess')).toBe('Submit guess');
setPreferredLocale('da');
expect(host.copy('host.start_round')).toBe('Start runde');
expect(player.copy('player.submit_guess')).toBe('Send gæt');
expect(host.copy('game.host.start_round')).toBe('Start runde');
expect(player.copy('game.player.submit_guess')).toBe('Send gæt');
player.ngOnDestroy();
host.ngOnDestroy();

View File

@@ -93,6 +93,36 @@ describe('lobby i18n locale propagation', () => {
}
});
it('resolves baseline shell/game keys from shared namespaces', async () => {
vi.stubGlobal('window', {
location: { search: '' },
localStorage: storageMock({ 'wpp.locale': 'da' }),
});
vi.stubGlobal('navigator', { language: 'da-DK' });
const i18n = await import('./lobby-i18n');
const baselineKeys = [
'lobby.shell.title',
'lobby.shell.host_nav',
'lobby.shell.player_nav',
'lobby.shell.language_label',
'common.refresh',
'common.session_code',
'game.host.title',
'game.host.start_round',
'game.player.title',
'game.player.submit_guess',
] as const;
for (const key of baselineKeys) {
const value = i18n.t(key, 'da');
expect(value).toBeTypeOf('string');
expect(value.length).toBeGreaterThan(0);
expect(value).not.toBe(key);
}
});
it('exposes primary-only audio routing policy to clients', async () => {
vi.stubGlobal('window', {
location: { search: '' },

View File

@@ -65,10 +65,23 @@ export function subscribeToLocaleChanges(callback: (locale: SupportedLocale) =>
};
}
function resolveCatalogPath(key: string): string {
if (key.startsWith('lobby.shell.')) {
return key.replace(/^lobby\.shell\./, 'app.');
}
if (key.startsWith('game.host.')) {
return key.replace(/^game\.host\./, 'host.');
}
if (key.startsWith('game.player.')) {
return key.replace(/^game\.player\./, 'player.');
}
return key;
}
export function t(key: string, locale: string): string {
const normalizedLocale = normalizeLocale(locale);
const fallbackLocale = DEFAULT_LOCALE;
const segments = key.split('.');
const segments = resolveCatalogPath(key).split('.');
let cursor: unknown = lobbyCatalog.frontend.ui;
for (const segment of segments) {