Files
scrabble-game/ui/src/lib/i18n/catalog.ts
T
Ilia Denisov 453ddc5e94 Stage 7 (wip): UI shell, libs, mock transport, screens (lobby->game), e2e smoke
- plain Svelte 5 + TS + Vite (no SvelteKit); CSS-token design system (Telegram-ready), hash router, IndexedDB session
- pure libs: domain model, premium/value maps ported from solver, board replay, placement state machine, i18n en/ru
- in-memory mock transport + seed data; pnpm start runs lobby->active game->board with no backend
- board: pointer-drag + tap placement, MakeMove (popup / 1s-hold commit), two-state zoom, blank chooser, exchange, hint, word-check, chat
- Playwright smoke (mock) green; svelte-check clean; mock bundle ~37 KB gzip
2026-06-03 00:32:50 +02:00

38 lines
1.2 KiB
TypeScript

// Pure i18n catalog + lookup (no runes) so any module can import the types and
// translate without depending on the reactive layer.
import { en, type MessageKey } from './en';
import { ru } from './ru';
export type Locale = 'en' | 'ru';
export type { MessageKey };
export const catalogs: Record<Locale, Record<MessageKey, string>> = { en, ru };
export function translate(
locale: Locale,
key: MessageKey,
params?: Record<string, string | number>,
): string {
const dict = catalogs[locale] ?? en;
let s: string = dict[key] ?? en[key] ?? key;
if (params) {
for (const [k, v] of Object.entries(params)) {
s = s.replaceAll(`{${k}}`, String(v));
}
}
return s;
}
/** errorKey maps a gateway result/edge code to a message key, falling back to generic. */
export function errorKey(code: string): MessageKey {
const key = `error.${code}` as MessageKey;
return key in en ? key : 'error.generic';
}
/** localeFrom picks a supported locale from a free-form hint (e.g. 'ru-RU' -> 'ru'). */
export function localeFrom(hint: string | undefined | null, fallback: Locale = 'en'): Locale {
const l = (hint ?? '').slice(0, 2).toLowerCase();
return l === 'ru' ? 'ru' : l === 'en' ? 'en' : fallback;
}