103 lines
3.4 KiB
TypeScript
103 lines
3.4 KiB
TypeScript
import lobbyCatalog from '../../../../shared/i18n/lobby.json';
|
|
|
|
type SupportedLocale = (typeof lobbyCatalog.locales.supported)[number];
|
|
|
|
const DEFAULT_LOCALE = lobbyCatalog.locales.default as SupportedLocale;
|
|
const SUPPORTED_LOCALES = lobbyCatalog.locales.supported as readonly SupportedLocale[];
|
|
|
|
let activeLocale: SupportedLocale | null = null;
|
|
const localeSubscribers = new Set<(locale: SupportedLocale) => void>();
|
|
|
|
export function normalizeLocale(rawLocale?: string | null): SupportedLocale {
|
|
const locale = (rawLocale ?? '').trim().toLowerCase();
|
|
if ((SUPPORTED_LOCALES as readonly string[]).includes(locale)) {
|
|
return locale as SupportedLocale;
|
|
}
|
|
|
|
const shortLocale = locale.split('-')[0] ?? '';
|
|
if ((SUPPORTED_LOCALES as readonly string[]).includes(shortLocale)) {
|
|
return shortLocale as SupportedLocale;
|
|
}
|
|
|
|
return DEFAULT_LOCALE;
|
|
}
|
|
|
|
export function resolvePreferredLocale(): SupportedLocale {
|
|
if (activeLocale) {
|
|
return activeLocale;
|
|
}
|
|
|
|
if (typeof window === 'undefined') {
|
|
activeLocale = DEFAULT_LOCALE;
|
|
return activeLocale;
|
|
}
|
|
|
|
const rootLocale =
|
|
typeof document !== 'undefined' ? document.querySelector<HTMLElement>('app-root')?.dataset?.['wppLocale'] : null;
|
|
const shellLocale = typeof document !== 'undefined' ? document.body?.dataset?.['wppLocale'] : null;
|
|
const queryLocale = new URLSearchParams(window.location?.search ?? '').get('lang');
|
|
const storedLocale = window.localStorage?.getItem?.('wpp.locale');
|
|
const browserLocale = typeof navigator !== 'undefined' ? navigator.language : '';
|
|
|
|
activeLocale = normalizeLocale(rootLocale || shellLocale || queryLocale || storedLocale || browserLocale || DEFAULT_LOCALE);
|
|
return activeLocale;
|
|
}
|
|
|
|
export function setPreferredLocale(locale: string): SupportedLocale {
|
|
const normalized = normalizeLocale(locale);
|
|
activeLocale = normalized;
|
|
if (typeof window !== 'undefined') {
|
|
window.localStorage?.setItem?.('wpp.locale', normalized);
|
|
}
|
|
|
|
for (const subscriber of localeSubscribers) {
|
|
subscriber(normalized);
|
|
}
|
|
|
|
return normalized;
|
|
}
|
|
|
|
export function subscribeToLocaleChanges(callback: (locale: SupportedLocale) => void): () => void {
|
|
localeSubscribers.add(callback);
|
|
callback(resolvePreferredLocale());
|
|
return () => {
|
|
localeSubscribers.delete(callback);
|
|
};
|
|
}
|
|
|
|
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 = resolveCatalogPath(key).split('.');
|
|
|
|
let cursor: unknown = lobbyCatalog.frontend.ui;
|
|
for (const segment of segments) {
|
|
if (!cursor || typeof cursor !== 'object' || !(segment in (cursor as Record<string, unknown>))) {
|
|
return key;
|
|
}
|
|
cursor = (cursor as Record<string, unknown>)[segment];
|
|
}
|
|
|
|
if (!cursor || typeof cursor !== 'object') {
|
|
return key;
|
|
}
|
|
|
|
const translations = cursor as Record<string, string>;
|
|
return translations[normalizedLocale] ?? translations[fallbackLocale] ?? key;
|
|
}
|
|
|
|
export const clientHasNoAudioOutput = Boolean(lobbyCatalog.frontend.capabilities.client_has_no_audio_output);
|