feat(#239): add angular i18n shell namespace bridge
This commit is contained in:
@@ -26,13 +26,13 @@ describe('i18n MVP flow smoke (host/player + audio policy)', () => {
|
|||||||
host.ngOnInit();
|
host.ngOnInit();
|
||||||
player.ngOnInit();
|
player.ngOnInit();
|
||||||
|
|
||||||
expect(host.copy('host.start_round')).toBe('Start round');
|
expect(host.copy('game.host.start_round')).toBe('Start round');
|
||||||
expect(player.copy('player.submit_guess')).toBe('Submit guess');
|
expect(player.copy('game.player.submit_guess')).toBe('Submit guess');
|
||||||
|
|
||||||
setPreferredLocale('da');
|
setPreferredLocale('da');
|
||||||
|
|
||||||
expect(host.copy('host.start_round')).toBe('Start runde');
|
expect(host.copy('game.host.start_round')).toBe('Start runde');
|
||||||
expect(player.copy('player.submit_guess')).toBe('Send gæt');
|
expect(player.copy('game.player.submit_guess')).toBe('Send gæt');
|
||||||
|
|
||||||
player.ngOnDestroy();
|
player.ngOnDestroy();
|
||||||
host.ngOnDestroy();
|
host.ngOnDestroy();
|
||||||
|
|||||||
@@ -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 () => {
|
it('exposes primary-only audio routing policy to clients', async () => {
|
||||||
vi.stubGlobal('window', {
|
vi.stubGlobal('window', {
|
||||||
location: { search: '' },
|
location: { search: '' },
|
||||||
|
|||||||
@@ -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 {
|
export function t(key: string, locale: string): string {
|
||||||
const normalizedLocale = normalizeLocale(locale);
|
const normalizedLocale = normalizeLocale(locale);
|
||||||
const fallbackLocale = DEFAULT_LOCALE;
|
const fallbackLocale = DEFAULT_LOCALE;
|
||||||
const segments = key.split('.');
|
const segments = resolveCatalogPath(key).split('.');
|
||||||
|
|
||||||
let cursor: unknown = lobbyCatalog.frontend.ui;
|
let cursor: unknown = lobbyCatalog.frontend.ui;
|
||||||
for (const segment of segments) {
|
for (const segment of segments) {
|
||||||
|
|||||||
Reference in New Issue
Block a user