import { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from 'react'; import { createT, formatAmd, formatDateTime, isLocale, type Locale, type TFunction } from '@barev/i18n'; import { reportClientError } from './telegram.ts'; interface I18nValue { locale: Locale; t: TFunction; setLocale: (l: Locale) => void; amd: (n: number) => string; dt: (d: Date, opts?: Intl.DateTimeFormatOptions) => string; } const Ctx = createContext(null); export function pickLocale(...candidates: (string | null | undefined)[]): Locale { for (const c of candidates) { const base = c?.split('-')[0]?.toLowerCase(); if (isLocale(base)) return base; } return 'ru'; } export function I18nProvider({ initial, children }: { initial: Locale; children: ReactNode }) { const [locale, setLocale] = useState(initial); useEffect(() => setLocale(initial), [initial]); useEffect(() => { document.documentElement.lang = locale; }, [locale]); const value = useMemo( () => ({ locale, t: createT(locale), setLocale, amd: (n) => formatAmd(locale, n), dt: (d, opts) => formatDateTime(locale, d, opts), }), [locale], ); return {children}; } export function useI18n(): I18nValue { const v = useContext(Ctx); if (!v) throw new Error('I18nProvider missing'); return v; } /** Текст ошибки API: errors.<код бизнес-ошибки> или общий */ export function errorText(t: TFunction, err: unknown): string { reportClientError(err, 'errorText'); const e = err as { data?: { domainCode?: string | null; code?: string }; message?: string } | null; const code = e?.data?.domainCode ?? e?.message; if (code && /^[A-Z0-9_]+$/.test(code)) { const s = t(`errors.${code}`); if (s !== `errors.${code}`) return s; } return t('errors.generic'); }