feat(a11y,i18n): more modal focus-traps + Telegram theme/language sync

Modal a11y:
- focus-trap + role=dialog/aria-modal/aria-labelledby on AdminRoles delete confirm
  and AdminBanSystem user-detail modal (+ close aria-label)

Telegram theme/language sync (first run only, explicit choice always wins):
- getTelegramColorScheme() / getTelegramLanguageCode() helpers in useTelegramSDK
- useTheme initial state follows the Telegram client color scheme when no stored theme
- applyTelegramLanguage() adopts the Telegram client language when no stored choice,
  called from main.tsx after SDK init (launch params unavailable before init)
This commit is contained in:
c0mrade
2026-05-25 23:31:38 +03:00
parent 8e0b63bac8
commit 0caba3dffb
6 changed files with 96 additions and 4 deletions

View File

@@ -1,6 +1,7 @@
import i18n, { type ResourceLanguage } from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import { getTelegramLanguageCode } from './hooks/useTelegramSDK';
const localeLoaders: Record<string, () => Promise<{ default: ResourceLanguage }>> = {
ru: () => import('./locales/ru.json'),
@@ -11,6 +12,7 @@ const localeLoaders: Record<string, () => Promise<{ default: ResourceLanguage }>
const SUPPORTED_LANGS = Object.keys(localeLoaders);
const FALLBACK_LNG = 'ru';
const LANGUAGE_STORAGE_KEY = 'cabinet_language';
const loadedLanguages = new Set<string>();
@@ -61,4 +63,21 @@ i18n.on('languageChanged', (lng: string) => {
loadLanguage(code);
});
/**
* On first run inside Telegram (no explicit stored choice), adopt the user's
* Telegram client language. Must be called after the Telegram SDK is initialised
* (e.g. from main.tsx), since launch params are unavailable before init().
*/
export function applyTelegramLanguage(): void {
try {
if (localStorage.getItem(LANGUAGE_STORAGE_KEY)) return; // explicit choice wins
} catch {
return;
}
const code = getTelegramLanguageCode();
if (code && SUPPORTED_LANGS.includes(code) && i18n.language?.split('-')[0] !== code) {
i18n.changeLanguage(code);
}
}
export default i18n;