/* global React */
/*
 * i18n.jsx — Polski (domyślny) + Ukraiński.
 * Eksportuje na window: LangProvider, useT, LangSwitcher.
 * Stan języka trzymany w localStorage('dec_onb_lang'), domyślnie 'pl'.
 */

const LANG_KEY = 'dec_onb_lang';
const LangContext = React.createContext({ lang: 'pl', setLang: () => {}, t: (k) => k });

const TRANSLATIONS = {
  pl: {
    // ── header / nav ───────────────────────────────────────────
    'nav.start': 'Start',
    'nav.panel': 'Panel',
    'nav.module': 'Moduł',
    'nav.chat': 'Asystent',
    'nav.announcements': 'Ogłoszenia',
    'nav.workers': 'Pracownicy',
    'brand.section': 'STANDARD ANTRESOLA',
    'brand.admin': 'Admin',
    'brand.onboarding': 'Onboarding',
    'header.logout': 'Wyloguj',
    'lang.aria': 'Język',
    'lang.pl_aria': 'Polski',
    'lang.uk_aria': 'Українська',

    // ── login ──────────────────────────────────────────────────
    'login.badge': 'Magazyn Łódź',
    'login.title': 'Witaj. Wpisz swój kod onboardingu.',
    'login.subtitle': 'Po wpisaniu kodu zobaczysz swoje moduły, postęp i asystenta.',
    'login.label': 'Kod onboardingu',
    'login.placeholder': 'np. LDZ-XXXX-XXXX',
    'login.submit': 'Wejdź →',
    'login.err_empty': 'Wpisz kod, który dostałeś od menedżera.',
    'login.err_unknown': 'Nie znamy tego kodu. Sprawdź go u menedżera.',
    'login.help_title': 'Nie masz kodu?',
    'login.help_body': 'Zapytaj menedżera.',
    'login.demo_prefix': 'Demo: spróbuj',
    'login.demo_or': 'lub',

    // ── welcome ────────────────────────────────────────────────
    'welcome.eyebrow': 'Magazyn Łódź · Standard',
    'welcome.greet': (p) => `Cześć, ${p.name} 👋`,
    'welcome.cta_start': 'Otwórz moduły →',
    'welcome.cta_ask': 'Mam pytanie',
    'welcome.next_label': 'NASTĘPNY KROK',
    'welcome.next_step': (p) => `Krok ${p.n} z 6`,
    'welcome.ctx_done_label': 'Modułów ukończonych',
    'welcome.ctx_remaining_label': 'Pozostało modułów',

    // ── panel ──────────────────────────────────────────────────
    'panel.eyebrow': 'Twój panel',
    'panel.greet': (p) => `Cześć, ${p.name} 👋`,
    'panel.sub': 'Ukończyłeś ',
    'panel.sub_of': (p) => ` z ${p.total} modułów`,
    'panel.sub_done': (p) => `${p.done}`,
    'panel.sub_next_prefix': '. Następny: ',
    'panel.ring_ttl': 'Postęp ścieżki',
    'panel.ring_meta': (p) => `${p.done}/${p.total} modułów ukończonych`,
    'panel.section_h3': 'Moduły działu',
    'panel.filter_all': 'Wszystkie',
    'panel.filter_progress': 'Do zrobienia',
    'panel.filter_done': 'Ukończone',
    'panel.tag_done': '✓ Ukończony',
    'panel.tag_todo': 'Do zrobienia',
    'panel.tag_progress': (p) => `▶ ${p.pct}%`,

    // ── moduł — sidebar / lesson ──────────────────────────────
    'module.back': '← Wróć do panelu',
    'module.eyebrow': 'Moduł 02',
    'module.sidebar_meta': '60% ukończone · 2 z 6 kroków',
    'module.step_meta': (p) => `Krok ${p.n} z 6`,
    'module.breadcrumb': (p) => `Krok ${p.n} z 6 · ${p.sub}`,
    'module.lesson_h2_anatomy': 'Anatomia ekranu Logpada',
    'module.lesson_lead_anatomy': 'Tak wygląda jedno zamówienie po wejściu w szczegóły. Kliknij w kropki, żeby zobaczyć, co znaczy każda część ekranu.',
    'module.lesson_lead_other': 'Treść tego kroku — wybierz krok 3 z lewej, żeby zobaczyć interaktywny przykład.',
    'module.prev': '← Poprzedni',
    'module.next': 'Następny krok →',
    'module.legend_ttl': 'Co znaczą kolumny',

    // logipad mock
    'logipad.head_dev': 'LOGIPAD · MAG ŁDZ',
    'logipad.battery': '● 87% · 11:49',

    // ── moduły (lista) ─────────────────────────────────────────
    'mod.1.num': '01 · WPROWADZENIE',
    'mod.1.title': 'Wprowadzenie',
    'mod.1.desc': 'Pierwszy dzień w naszym dziale.',
    'mod.1.foot': '3 filmy · 5 zdjęć · 4 pytania',
    'mod.2.num': '02 · LOGPAD',
    'mod.2.title': 'Logpad od A do Z',
    'mod.2.desc': 'Twój ekran — zamówienia, statusy, kody.',
    'mod.2.foot': '5 filmów · 12 zdjęć · 8 pytań',
    'mod.3.num': '03 · BHP',
    'mod.3.title': 'BHP na dziale',
    'mod.3.desc': 'Bezpieczeństwo przy pickingu, wózki, regały.',
    'mod.3.foot': '4 filmy · 8 zdjęć · 6 pytań',
    'mod.4.num': '04 · STREFY',
    'mod.4.title': 'Strefy NAT, FIT, U71-75',
    'mod.4.desc': 'Mapa działu — gdzie co leży.',
    'mod.4.foot': '3 filmy · 14 zdjęć · 5 pytań',
    'mod.5.num': '05 · PICKING',
    'mod.5.title': 'Picking krok po kroku',
    'mod.5.desc': 'Skanowanie, układanie, weryfikacja.',
    'mod.5.foot': '4 filmy · 7 zdjęć · 6 pytań',
    'mod.6.num': '06 · CO ROBIĆ JEŚLI',
    'mod.6.title': 'Co robić jeśli',
    'mod.6.desc': 'Sytuacje awaryjne — brak towaru, błąd skanu.',
    'mod.6.foot': '6 filmów · 4 zdjęcia · 7 pytań',
    'mod.completed': 'Ukończony',

    // ── kroki modułu 03 ────────────────────────────────────────
    'step.1.label': 'Wprowadzenie',
    'step.1.sub': '📺 Wideo · 2:14',
    'step.2.label': 'Galeria ekranów',
    'step.2.sub': '📷 6 zdjęć',
    'step.3.label': 'Anatomia ekranu',
    'step.3.sub': '📖 Lekcja',
    'step.4.label': 'Cały proces',
    'step.4.sub': '📺 Wideo · 4:50',
    'step.5.label': 'Statusy i kolory',
    'step.5.sub': '📺 Wideo · 1:40',
    'step.6.label': 'Test końcowy',
    'step.6.sub': '✓ 6 pytań',

    // ── hotspots ───────────────────────────────────────────────
    'hs.1.title': 'Numer zamówienia',
    'hs.1.desc': 'FIT4D1 to kod strefy (FITNESS, regał 4D1). 20260510 to data (YYYYMMDD = 10 maja 2026). n°390055 to wewnętrzny numer zamówienia.',
    'hs.2.title': 'Liczba artykułów',
    'hs.2.desc': '73 sztuki do skompletowania, 40 lokalizacji w hali do obejścia, 47 unikalnych kodów EAN do zeskanowania.',
    'hs.3.title': 'Kody artykułów',
    'hs.3.desc': 'Każdy 3-cyfrowy kod to typ produktu. Liczba w nawiasie = ile sztuk tego typu. Tutaj 6 typów: 28 szt. modelu 063, 7 szt. modelu 064, 16 szt. modelu 062 itd. — różne modele odzieży fitness.',
    'hs.4.title': 'Sklepy docelowe',
    'hs.4.desc': 'Jedno zamówienie często idzie do kilku sklepów jednocześnie. Tutaj te 73 artykuły rozdzielisz między Bielsko-Biała (BIELA) i Lublin (LUBLI) — pakujesz osobno dla każdego sklepu.',

    // ── chat ───────────────────────────────────────────────────
    'chat.back': '← Panel',
    'chat.threads_h4': 'Twoje rozmowy',
    'chat.thread1_ttl': 'Pytania o Logpad',
    'chat.thread1_when': 'Dzisiaj · 5 wiadomości',
    'chat.thread2_ttl': 'Strefy NAT i FIT',
    'chat.thread2_when': 'Wczoraj · 3 wiadomości',
    'chat.thread3_ttl': 'Pierwszy dzień',
    'chat.thread3_when': 'Pon · 8 wiadomości',
    'chat.shortcuts_h4': 'Skróty',
    'chat.shortcut_mod_ttl': 'Otwórz Moduł 03',
    'chat.shortcut_mod_when': 'Logpad od A do Z',
    'chat.shortcut_phone_ttl': 'Dyżurny: +48 42 555 01 12',
    'chat.shortcut_phone_when': 'Łódź · zmiana B',
    'chat.head_h3': 'Asystent onboardingu',
    'chat.head_sub': 'AI · po polsku · cytuje moduły',
    'chat.online': 'Zawsze online',
    'chat.placeholder': 'Napisz pytanie po polsku…',
    'chat.cite_label': 'źródło',
    'chat.greeting': (p) => (<>Cześć {p.name} 👋 Pamiętam, co już obejrzałeś. Pytaj o procedury, kody stref, sytuacje awaryjne.</>),
    'chat.q1': 'co znaczy NAT4D1?',
    'chat.a1': (<><strong>NAT4D1</strong> to kod strefy w sektorze U71-75 NATURA — sporty natura, kemping, turystyka. Litera <strong>D</strong> = poziom regału, <strong>1</strong> = rząd.</>),
    'chat.a1_cite': 'Moduł 03 · krok 3',
    'chat.s_zone_fit': 'Gdzie jest strefa FIT?',
    'chat.s_held': 'Co to wstrzymane zamówienie?',
    'chat.s_no_stock': 'Co zrobić jeśli brak towaru?',
    'chat.r_zone_fit': (<>Strefa <strong>FIT</strong> to sektor fitness — siłownia, joga, bieganie. Wejdziesz od bramy 4, regały od F1 do F8 po prawej stronie korytarza. Pełna mapa w Module 04.</>),
    'chat.r_zone_fit_cite': 'Moduł 04 · mapa działu',
    'chat.r_held': (<>Wstrzymane = czerwone tło na logipadzie. Zazwyczaj brak towaru lub błąd systemu. <strong>Nie pickujesz</strong> — czekasz, aż status się zmieni.</>),
    'chat.r_held_cite': 'Moduł 03 · krok 5',
    'chat.r_no_stock': (<>Skanujesz lokalizację z nalepką „BRAK", a procedura sama oznaczy artykuł do weryfikacji. Pełna procedura: Moduł 06, krok 2. Nigdy nie zostawiaj zamówienia otwartego bez statusu.</>),
    'chat.r_no_stock_cite': 'Moduł 06 · sytuacje awaryjne',
    'chat.r_default': (<>Cześć 👋 Jestem asystentem onboardingu. W wersji produkcyjnej odpowiem na pytania o procedury, kody stref i sytuacje awaryjne. To prototyp — pełna integracja AI niedługo.</>),
    'chat.r_default_cite': '',

    // ── admin ──────────────────────────────────────────────────
    'admin.eyebrow': 'Panel administratora',
    'admin.h2': 'Postępy zespołu',
    'admin.new_code': '+ Nowy kod',
    'admin.stat_workers': 'Pracownicy',
    'admin.stat_done': 'Zakończone',
    'admin.stat_inprogress': 'W trakcie',
    'admin.workers_h3': (p) => `Pracownicy (${p.n})`,
    'admin.search_placeholder': 'Szukaj po imieniu lub kodzie…',
    'admin.th_worker': 'Pracownik',
    'admin.th_progress': 'Postęp',
    'admin.th_step': 'Aktualny moduł',
    'admin.th_status': 'Status',
    'admin.status_done': 'Zakończony',
    'admin.status_progress': 'W trakcie',
    'admin.details': 'Szczegóły →',
    'admin.codes_h3': 'Aktywne kody dostępu',
    'admin.codes_for': (p) => `dla: ${p.name}`,
    'admin.copied': '✓ Skopiowano',
    'admin.copy': 'Kopiuj',
    'admin.how_h3': 'Jak to działa',
    'admin.how_1': 'Generujesz kod dla nowej osoby (przycisk „+ Nowy kod").',
    'admin.how_2': 'Dajesz kod nowej osobie pierwszego dnia.',
    'admin.how_3': 'Pracownik wpisuje kod i zaczyna moduły.',

    // ── ogłoszenia ─────────────────────────────────────────────
    'ann.welcome_h3': 'Najnowsze ogłoszenia',
    'ann.welcome_see_all': 'Zobacz wszystkie →',
    'ann.page_h2': 'Ogłoszenia',
    'ann.empty': 'Brak ogłoszeń.',
    'ann.loading': 'Ładowanie…',
    'ann.priority_normal': 'Standardowe',
    'ann.priority_important': 'Ważne',
    'ann.priority_event': 'Wydarzenie',
    'ann.author': 'Autor',
    'admin.ann_h3': 'Zarządzaj ogłoszeniami',
    'admin.ann_new_title': 'Nowe ogłoszenie',
    'admin.ann_field_title': 'Tytuł',
    'admin.ann_field_body': 'Treść',
    'admin.ann_field_priority': 'Priorytet',
    'admin.ann_post': 'Opublikuj',
    'admin.ann_posting': 'Publikuję…',
    'admin.ann_delete': 'Usuń',
    'admin.ann_delete_confirm': 'Usunąć to ogłoszenie?',
    'admin.ann_list': 'Aktywne ogłoszenia',
  },

  uk: {
    // ── header / nav ───────────────────────────────────────────
    'nav.start': 'Старт',
    'nav.panel': 'Панель',
    'nav.module': 'Модуль',
    'nav.chat': 'Асистент',
    'nav.announcements': 'Оголошення',
    'nav.workers': 'Працівники',
    'brand.section': 'STANDARD ANTRESOLA',
    'brand.admin': 'Адмін',
    'brand.onboarding': 'Онбординг',
    'header.logout': 'Вийти',
    'lang.aria': 'Мова',
    'lang.pl_aria': 'Польська',
    'lang.uk_aria': 'Українська',

    // ── login ──────────────────────────────────────────────────
    'login.badge': 'Склад Лодзь',
    'login.title': 'Вітаємо. Введи свій код онбордингу.',
    'login.subtitle': 'Після введення коду ти побачиш свої модулі, прогрес і асистента.',
    'login.label': 'Код онбордингу',
    'login.placeholder': 'напр. LDZ-XXXX-XXXX',
    'login.submit': 'Увійти →',
    'login.err_empty': 'Введи код, який ти отримав від менеджера.',
    'login.err_unknown': 'Не знаємо цього коду. Уточни у менеджера.',
    'login.help_title': 'Немає коду?',
    'login.help_body': 'Звернись до менеджера.',
    'login.demo_prefix': 'Демо: спробуй',
    'login.demo_or': 'або',

    // ── welcome ────────────────────────────────────────────────
    'welcome.eyebrow': 'Склад Лодзь · Стандарт',
    'welcome.greet': (p) => `Привіт, ${p.name} 👋`,
    'welcome.cta_start': 'Відкрити модулі →',
    'welcome.cta_ask': 'Маю питання',
    'welcome.next_label': 'НАСТУПНИЙ КРОК',
    'welcome.next_step': (p) => `Крок ${p.n} з 6`,
    'welcome.ctx_done_label': 'Модулів завершено',
    'welcome.ctx_remaining_label': 'Залишилось модулів',

    // ── panel ──────────────────────────────────────────────────
    'panel.eyebrow': 'Твоя панель',
    'panel.greet': (p) => `Привіт, ${p.name} 👋`,
    'panel.sub': 'Ти завершив ',
    'panel.sub_of': (p) => ` з ${p.total} модулів`,
    'panel.sub_done': (p) => `${p.done}`,
    'panel.sub_next_prefix': '. Наступний: ',
    'panel.ring_ttl': 'Загальний прогрес',
    'panel.ring_meta': (p) => `${p.done}/${p.total} модулів завершено`,
    'panel.section_h3': 'Модулі відділу',
    'panel.filter_all': 'Усі',
    'panel.filter_progress': 'До виконання',
    'panel.filter_done': 'Завершені',
    'panel.tag_done': '✓ Завершено',
    'panel.tag_todo': 'До виконання',
    'panel.tag_progress': (p) => `▶ ${p.pct}%`,

    // ── moduł — sidebar / lesson ──────────────────────────────
    'module.back': '← Назад до панелі',
    'module.eyebrow': 'Модуль 02',
    'module.sidebar_meta': '60% завершено · 2 з 6 кроків',
    'module.step_meta': (p) => `Крок ${p.n} з 6`,
    'module.breadcrumb': (p) => `Крок ${p.n} з 6 · ${p.sub}`,
    'module.lesson_h2_anatomy': 'Анатомія екрану Logpad',
    'module.lesson_lead_anatomy': 'Так виглядає одне замовлення після переходу в деталі. Натисни на крапки, щоб побачити, що означає кожна частина екрану.',
    'module.lesson_lead_other': 'Зміст цього кроку — обери крок 3 ліворуч, щоб побачити інтерактивний приклад.',
    'module.prev': '← Попередній',
    'module.next': 'Наступний крок →',
    'module.legend_ttl': 'Що означають колонки',

    // logipad mock
    'logipad.head_dev': 'LOGIPAD · СКЛ ЛДЗ',
    'logipad.battery': '● 87% · 11:49',

    // ── moduły (lista) ─────────────────────────────────────────
    'mod.1.num': '01 · ВВЕДЕННЯ',
    'mod.1.title': 'Введення',
    'mod.1.desc': 'Перший день у нашому відділі.',
    'mod.1.foot': '3 відео · 5 фото · 4 запитання',
    'mod.2.num': '02 · LOGPAD',
    'mod.2.title': 'Logpad від А до Я',
    'mod.2.desc': 'Твій екран — замовлення, статуси, коди.',
    'mod.2.foot': '5 відео · 12 фото · 8 запитань',
    'mod.3.num': '03 · ОХОРОНА ПРАЦІ',
    'mod.3.title': 'Охорона праці на відділі',
    'mod.3.desc': 'Безпека при пікінгу, візки, стелажі.',
    'mod.3.foot': '4 відео · 8 фото · 6 запитань',
    'mod.4.num': '04 · ЗОНИ',
    'mod.4.title': 'Зони NAT, FIT, U71-75',
    'mod.4.desc': 'Карта відділу — де що лежить.',
    'mod.4.foot': '3 відео · 14 фото · 5 запитань',
    'mod.5.num': '05 · ПІКІНГ',
    'mod.5.title': 'Пікінг крок за кроком',
    'mod.5.desc': 'Сканування, укладання, перевірка.',
    'mod.5.foot': '4 відео · 7 фото · 6 запитань',
    'mod.6.num': '06 · ЩО РОБИТИ ЯКЩО',
    'mod.6.title': 'Що робити якщо',
    'mod.6.desc': 'Аварійні ситуації — немає товару, помилка сканування.',
    'mod.6.foot': '6 відео · 4 фото · 7 запитань',
    'mod.completed': 'Завершено',

    // ── кроки модуля 03 ────────────────────────────────────────
    'step.1.label': 'Введення',
    'step.1.sub': '📺 Відео · 2:14',
    'step.2.label': 'Галерея екранів',
    'step.2.sub': '📷 6 фото',
    'step.3.label': 'Анатомія екрану',
    'step.3.sub': '📖 Урок',
    'step.4.label': 'Повний процес',
    'step.4.sub': '📺 Відео · 4:50',
    'step.5.label': 'Статуси і кольори',
    'step.5.sub': '📺 Відео · 1:40',
    'step.6.label': 'Підсумковий тест',
    'step.6.sub': '✓ 6 запитань',

    // ── hotspots ───────────────────────────────────────────────
    'hs.1.title': 'Номер замовлення',
    'hs.1.desc': 'FIT4D1 — це код зони (FITNESS, стелаж 4D1). 20260510 — дата (РРРРММДД = 10 травня 2026). n°390055 — внутрішній номер замовлення.',
    'hs.2.title': 'Кількість артикулів',
    'hs.2.desc': '73 штуки для збору, 40 локацій у відділі для обходу, 47 унікальних кодів EAN для сканування.',
    'hs.3.title': 'Коди артикулів',
    'hs.3.desc': 'Кожен 3-значний код — це тип товару. Число в дужках = скільки штук цього типу. Тут 6 типів: 28 шт. моделі 063, 7 шт. моделі 064, 16 шт. моделі 062 і т.д. — різні моделі фітнес-одягу.',
    'hs.4.title': 'Цільові магазини',
    'hs.4.desc': 'Одне замовлення часто йде в кілька магазинів одночасно. Тут ці 73 артикули розподілиш між Bielsko-Biała (BIELA) і Lublin (LUBLI) — пакуєш окремо для кожного магазину.',

    // ── chat ───────────────────────────────────────────────────
    'chat.back': '← Панель',
    'chat.threads_h4': 'Твої розмови',
    'chat.thread1_ttl': 'Питання про Logpad',
    'chat.thread1_when': 'Сьогодні · 5 повідомлень',
    'chat.thread2_ttl': 'Зони NAT та FIT',
    'chat.thread2_when': 'Вчора · 3 повідомлення',
    'chat.thread3_ttl': 'Перший день',
    'chat.thread3_when': 'Пн · 8 повідомлень',
    'chat.shortcuts_h4': 'Швидкі дії',
    'chat.shortcut_mod_ttl': 'Відкрити Модуль 03',
    'chat.shortcut_mod_when': 'Logpad від А до Я',
    'chat.shortcut_phone_ttl': 'Черговий: +48 42 555 01 12',
    'chat.shortcut_phone_when': 'Лодзь · зміна B',
    'chat.head_h3': 'Асистент онбордингу',
    'chat.head_sub': 'AI · польською · цитує модулі',
    'chat.online': 'Завжди онлайн',
    'chat.placeholder': 'Напиши питання польською…',
    'chat.cite_label': 'джерело',
    'chat.greeting': (p) => (<>Привіт, {p.name} 👋 Я пам’ятаю, що ти вже переглянув. Питай про процедури, коди зон, аварійні ситуації.</>),
    'chat.q1': 'що означає NAT4D1?',
    'chat.a1': (<><strong>NAT4D1</strong> — це код зони в секторі U71-75 NATURA (спорт на природі, кемпінг, туризм). Літера <strong>D</strong> = рівень стелажа, <strong>1</strong> = ряд.</>),
    'chat.a1_cite': 'Модуль 03 · крок 3',
    'chat.s_zone_fit': 'Де знаходиться зона FIT?',
    'chat.s_held': 'Що таке призупинене замовлення?',
    'chat.s_no_stock': 'Що робити, якщо немає товару?',
    'chat.r_zone_fit': (<>Зона <strong>FIT</strong> — це сектор фітнесу (тренажерний зал, йога, біг). Заходиш від брами 4, стелажі від F1 до F8 з правого боку коридору. Повна карта в Модулі 04.</>),
    'chat.r_zone_fit_cite': 'Модуль 04 · карта відділу',
    'chat.r_held': (<>Призупинене = червоний фон у логіпаді. Зазвичай немає товару або помилка системи. <strong>Не пікінгуєш</strong> — чекаєш, поки статус зміниться.</>),
    'chat.r_held_cite': 'Модуль 03 · крок 5',
    'chat.r_no_stock': (<>Скануєш локацію з наклейкою «BRAK», і процедура сама позначить артикул на перевірку. Повна процедура: Модуль 06, крок 2. Ніколи не залишай замовлення відкритим без статусу.</>),
    'chat.r_no_stock_cite': 'Модуль 06 · аварійні ситуації',
    'chat.r_default': (<>Привіт 👋 Я асистент онбордингу. У повній версії відповідатиму на питання про процедури, коди зон та аварійні ситуації. Це прототип — справжня інтеграція AI вже скоро.</>),
    'chat.r_default_cite': '',

    // ── admin ──────────────────────────────────────────────────
    'admin.eyebrow': 'Панель адміністратора',
    'admin.h2': 'Прогрес команди',
    'admin.new_code': '+ Новий код',
    'admin.stat_workers': 'Працівники',
    'admin.stat_done': 'Завершено',
    'admin.stat_inprogress': 'У процесі',
    'admin.workers_h3': (p) => `Працівники (${p.n})`,
    'admin.search_placeholder': 'Шукати за ім’ям або кодом…',
    'admin.th_worker': 'Працівник',
    'admin.th_progress': 'Прогрес',
    'admin.th_step': 'Поточний модуль',
    'admin.th_status': 'Статус',
    'admin.status_done': 'Завершено',
    'admin.status_progress': 'У процесі',
    'admin.details': 'Деталі →',
    'admin.codes_h3': 'Активні коди доступу',
    'admin.codes_for': (p) => `для: ${p.name}`,
    'admin.copied': '✓ Скопійовано',
    'admin.copy': 'Копіювати',
    'admin.how_h3': 'Як це працює',
    'admin.how_1': 'Генеруєш код для нової особи (кнопка «+ Новий код»).',
    'admin.how_2': 'Даєш код новій особі першого дня.',
    'admin.how_3': 'Працівник вводить код і починає модулі.',

    // ── оголошення ────────────────────────────────────────────
    'ann.welcome_h3': 'Останні оголошення',
    'ann.welcome_see_all': 'Переглянути всі →',
    'ann.page_h2': 'Оголошення',
    'ann.empty': 'Немає оголошень.',
    'ann.loading': 'Завантаження…',
    'ann.priority_normal': 'Стандартне',
    'ann.priority_important': 'Важливе',
    'ann.priority_event': 'Подія',
    'ann.author': 'Автор',
    'admin.ann_h3': 'Керування оголошеннями',
    'admin.ann_new_title': 'Нове оголошення',
    'admin.ann_field_title': 'Заголовок',
    'admin.ann_field_body': 'Зміст',
    'admin.ann_field_priority': 'Пріоритет',
    'admin.ann_post': 'Опублікувати',
    'admin.ann_posting': 'Публікація…',
    'admin.ann_delete': 'Видалити',
    'admin.ann_delete_confirm': 'Видалити це оголошення?',
    'admin.ann_list': 'Активні оголошення',
  },
};

function LangProvider({ children }) {
  const [lang, setLangState] = React.useState(() => {
    try {
      const stored = localStorage.getItem(LANG_KEY);
      return stored === 'uk' || stored === 'pl' ? stored : 'pl';
    } catch { return 'pl'; }
  });

  React.useEffect(() => {
    document.documentElement.setAttribute('lang', lang === 'uk' ? 'uk' : 'pl');
  }, [lang]);

  const setLang = React.useCallback((l) => {
    if (l !== 'pl' && l !== 'uk') return;
    setLangState(l);
    try { localStorage.setItem(LANG_KEY, l); } catch {}
  }, []);

  const t = React.useCallback((key, params) => {
    const dict = TRANSLATIONS[lang] || TRANSLATIONS.pl;
    let val = dict[key];
    if (val == null) val = TRANSLATIONS.pl[key];
    if (val == null) return key;
    if (typeof val === 'function') return val(params || {});
    return val;
  }, [lang]);

  return (
    <LangContext.Provider value={{ lang, setLang, t }}>
      {children}
    </LangContext.Provider>
  );
}

function useT() { return React.useContext(LangContext); }

function LangSwitcher() {
  const { lang, setLang, t } = useT();
  return (
    <div className="lang-switcher" role="group" aria-label={t('lang.aria')}>
      <button
        type="button"
        className={'lang-btn ' + (lang === 'pl' ? 'active' : '')}
        onClick={() => setLang('pl')}
        aria-label={t('lang.pl_aria')}
        aria-pressed={lang === 'pl'}
      >PL</button>
      <button
        type="button"
        className={'lang-btn ' + (lang === 'uk' ? 'active' : '')}
        onClick={() => setLang('uk')}
        aria-label={t('lang.uk_aria')}
        aria-pressed={lang === 'uk'}
      >UA</button>
    </div>
  );
}

Object.assign(window, {
  LangContext, LangProvider, useT, LangSwitcher, TRANSLATIONS,
});
