// i18n.jsx — localization engine + PL / EN / RU dictionary.
// Exposes: I18N (state), tx (exact string), tdate (relative/date tokens),
// fmt (string with {placeholders}), setLang, getLang. Loaded before ui/views/app.

const I18N = {
  lang: (() => { try { return localStorage.getItem('ac_lang') || 'en'; } catch (e) { return 'en'; } })(),
};
const LOCALES = { en: 'en-US', pl: 'pl-PL', ru: 'ru-RU' };
const LANGS = [
  { code: 'pl', label: 'PL', name: 'Polski' },
  { code: 'en', label: 'EN', name: 'English' },
  { code: 'ru', label: 'RU', name: 'Русский' },
];

function setLang(l) {
  I18N.lang = l;
  try { localStorage.setItem('ac_lang', l); } catch (e) {}
  document.documentElement.setAttribute('lang', l);
}
const i18nLocale = () => LOCALES[I18N.lang] || 'en-US';

// exact-string lookup with English fallback
function tx(s) {
  if (I18N.lang === 'en' || s == null) return s;
  const d = DICT[I18N.lang];
  return (d && d[s] != null) ? d[s] : s;
}
// string with {placeholders} → translate template then substitute
function fmt(s, vars) {
  let out = tx(s);
  if (vars) for (const k in vars) out = out.split('{' + k + '}').join(vars[k]);
  return out;
}

// relative-time + date token translation (Today / 12 min ago / Jun 4 / In 2 days …)
const MONTHS = {
  pl: { Jan: 'sty', Feb: 'lut', Mar: 'mar', Apr: 'kwi', May: 'maj', Jun: 'cze', Jul: 'lip', Aug: 'sie', Sep: 'wrz', Oct: 'paź', Nov: 'lis', Dec: 'gru' },
  ru: { Jan: 'янв', Feb: 'фев', Mar: 'мар', Apr: 'апр', May: 'май', Jun: 'июн', Jul: 'июл', Aug: 'авг', Sep: 'сен', Oct: 'окт', Nov: 'ноя', Dec: 'дек' },
};
// Russian day plural: 1 день, 2-4 дня, 5+ дней
function ruDays(n) {
  n = +n; const m10 = n % 10, m100 = n % 100;
  if (m10 === 1 && m100 !== 11) return 'день';
  if (m10 >= 2 && m10 <= 4 && (m100 < 12 || m100 > 14)) return 'дня';
  return 'дней';
}
function tdate(s) {
  if (I18N.lang === 'en' || s == null) return s;
  const L = I18N.lang;
  let out = String(s);
  if (L === 'pl') {
    out = out.replace(/\bToday\b/g, 'Dziś').replace(/\bTomorrow\b/g, 'Jutro').replace(/\bYesterday\b/g, 'Wczoraj');
    out = out.replace(/(\d+)\s*min ago/g, '$1 min temu');
    out = out.replace(/(\d+)\s*h ago/g, '$1 godz. temu');
    out = out.replace(/In (\d+) days?/g, 'za $1 dni');
    out = out.replace(/(\d+) days? ago/g, '$1 dni temu');
    out = out.replace(/\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b/g, (m) => MONTHS.pl[m] || m);
  } else if (L === 'ru') {
    out = out.replace(/\bToday\b/g, 'Сегодня').replace(/\bTomorrow\b/g, 'Завтра').replace(/\bYesterday\b/g, 'Вчера');
    out = out.replace(/(\d+)\s*min ago/g, '$1 мин назад');
    out = out.replace(/(\d+)\s*h ago/g, '$1 ч назад');
    out = out.replace(/In (\d+) days?/g, (m, n) => 'через ' + n + ' ' + ruDays(n));
    out = out.replace(/(\d+) days? ago/g, (m, n) => n + ' ' + ruDays(n) + ' назад');
    out = out.replace(/\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\b/g, (m) => MONTHS.ru[m] || m);
  }
  return out;
}

const DICT = {
  pl: {
    // ---- nav / shell ----
    'Operations': 'Operacje', 'Shop': 'Serwis', 'Manage': 'Zarządzanie',
    'Overview': 'Pulpit', 'Requests': 'Zgłoszenia', 'Work orders': 'Zlecenia', 'Schedule': 'Harmonogram',
    'Services & pricing': 'Usługi i cennik', 'Purchasing': 'Zakupy', 'Finances': 'Finanse', 'Reviews': 'Opinie',
    'Team & roles': 'Zespół i role', 'Settings': 'Ustawienia',
    'Manager cabinet': 'Panel menedżera', 'Manager': 'Menedżer',
    'reviews': 'opinii', '3 new this week': '3 nowe w tym tygodniu',
    'Search': 'Szukaj', 'Notifications': 'Powiadomienia', 'Language': 'Język',
    // ---- pay ----
    'Cash': 'Gotówka', 'Card': 'Karta',
    // ---- statuses ----
    'Request': 'Zgłoszenie', 'Accepted': 'Przyjęte', 'In progress': 'W trakcie',
    'Ready': 'Gotowe', 'Paid': 'Opłacone', 'Closed': 'Zamknięte',
    // ---- categories ----
    'Maintenance': 'Przeglądy', 'Brakes': 'Hamulce', 'Chassis': 'Podwozie', 'Climate': 'Klimatyzacja',
    'Diagnostics': 'Diagnostyka', 'Paint': 'Lakiernictwo', 'Electrical': 'Elektryka', 'Engine': 'Silnik',
    // ---- specializations / roles ----
    'Mechanics': 'Mechanika', 'Bodywork': 'Blacharstwo', 'Reception': 'Recepcja',
    'Mechanic': 'Mechanik', 'Painter': 'Lakiernik',
    // ---- services ----
    'Oil & filter change': 'Wymiana oleju i filtra', 'Front brake pads': 'Przednie klocki hamulcowe',
    'Wheel alignment': 'Geometria kół', 'A/C service & recharge': 'Serwis i nabicie klimatyzacji',
    'Computer diagnostics': 'Diagnostyka komputerowa', 'Suspension inspection': 'Przegląd zawieszenia',
    'Body panel respray': 'Lakierowanie elementu', 'Paintless dent removal': 'Usuwanie wgnieceń bez lakierowania',
    'Battery replacement': 'Wymiana akumulatora', 'Timing belt replacement': 'Wymiana rozrządu',
    // ---- durations ----
    '45 min': '45 min', '1.5 h': '1,5 godz.', '1 h': '1 godz.', '30 min': '30 min', '40 min': '40 min',
    '1 day': '1 dzień', '2 h': '2 godz.', '4 h': '4 godz.',
    // ---- ticket types + reqs ----
    'Additional work': 'Dodatkowa praca', 'Problem found': 'Wykryty problem',
    'Part replacement': 'Wymiana części', 'Part order': 'Zamówienie części',
    'Photo of completed work': 'Zdjęcie wykonanej pracy', 'Photo of problem + result': 'Zdjęcie problemu + efektu',
    'Photo of the part': 'Zdjęcie części', 'Receipt + photo of part': 'Paragon + zdjęcie części',
    'receipt req.': 'paragon wym.', 'photo req.': 'zdjęcie wym.',
    // ---- supply ----
    'Front brake discs OEM (pair)': 'Tarcze hamulcowe przód OEM (para)', 'Control arm, front-left OEM': 'Wahacz przedni lewy OEM',
    'White base coat (RAL 9003)': 'Baza biała (RAL 9003)', 'PDR glue tabs assortment': 'Zestaw przyssawek klejowych PDR',
    'Body filler 1 kg': 'Szpachla 1 kg', 'Clear coat hardener': 'Utwardzacz do lakieru',
    '2 pcs': '2 szt.', '1 pc': '1 szt.', '2 L': '2 l', '1 set': '1 zestaw', '1 L': '1 l',
    'Ordered via Lakmal — ETA tomorrow AM': 'Zamówione w Lakmal — dostawa jutro rano', 'Picked up from warehouse': 'Odebrane z magazynu',
    // ---- hero tickets ----
    'Replace front brake discs': 'Wymiana przednich tarcz hamulcowych', 'Front-left control arm worn': 'Zużyty wahacz przedni lewy',
    'Order OEM control arm (left)': 'Zamów wahacz OEM (lewy)',
    'Discs scored below minimum thickness — replacement required alongside the pad change.': 'Tarcze starte poniżej minimalnej grubości — wymiana konieczna razem z klockami.',
    'Play in the lower control arm bushing found during the suspension inspection. Recommend replacing before alignment.': 'Wykryto luz w tulei wahacza podczas przeglądu zawieszenia. Zalecana wymiana przed geometrią.',
    'Genuine part to be ordered from supplier for the control-arm replacement above.': 'Oryginalna część do zamówienia u dostawcy dla powyższej wymiany wahacza.',
    'Mon–Fri 8:00–18:00 · Sat 9:00–14:00': 'Pon–Pt 8:00–18:00 · Sob 9:00–14:00',
    // ---- overview ----
    'Good morning': 'Dzień dobry', 'Review requests': 'Przejrzyj zgłoszenia',
    'Awaiting confirmation': 'Oczekuje potwierdzenia', '2 new today': '2 nowe dziś',
    'Active work orders': 'Aktywne zlecenia', 'on track': 'zgodnie z planem',
    'Tickets awaiting client': 'Zgłoszenia u klienta', 'avg 18 min to decision': 'śr. 18 min do decyzji',
    'New requests': 'Nowe zgłoszenia', '3 awaiting': '3 oczekują', 'View all': 'Zobacz wszystkie',
    'from': 'od', 'Open board': 'Otwórz tablicę', 'Supply requests': 'Zapotrzebowania',
    '1 overdue': '1 zaległe', 'Open purchasing': 'Otwórz zakupy', 'by': 'od',
    // ---- bookings ----
    'Guest': 'Gość', 'Registered': 'Zarejestrowany', 'OTP verified': 'Zweryfikowano OTP', 'requested': 'zgłoszono',
    'Vehicle': 'Pojazd', 'Requested slot': 'Wybrany termin', 'pays on pickup': 'płaci przy odbiorze',
    'hold on confirm': 'blokada przy potwierdzeniu', 'Total from': 'Razem od',
    'Confirmed · work order created · customer notified': 'Potwierdzone · utworzono zlecenie · klient powiadomiony',
    'Confirm': 'Potwierdź', '& place hold': 'i zablokuj środki', 'Propose new slot': 'Zaproponuj nowy termin',
    'Decline': 'Odrzuć', 'New bookings waiting for your confirmation': 'Nowe rezerwacje czekające na potwierdzenie',
    'Awaiting': 'Oczekujące', 'Confirmed': 'Potwierdzone', 'All': 'Wszystkie', 'No pending requests.': 'Brak oczekujących zgłoszeń.',
    'Booking confirmed — customer notified': 'Rezerwacja potwierdzona — klient powiadomiony', 'Booking declined': 'Rezerwacja odrzucona',
    // ---- orders ----
    'Active': 'Aktywne', 'Every job in progress across the shop': 'Wszystkie bieżące prace w serwisie', 'Filter': 'Filtruj',
    'Vehicle / customer': 'Pojazd / klient', 'Order': 'Zlecenie', 'Status': 'Status', 'Assigned': 'Przypisani',
    'Tickets': 'Zgłoszenia', 'Payment': 'Płatność', 'Total': 'Razem',
    // ---- pricing ----
    'Net prices you set · clients see the “from” price incl. {n}% platform fee': 'Ceny netto, które ustalasz · klient widzi cenę „od” z {n}% prowizją platformy',
    'Add service': 'Dodaj usługę', 'Active services': 'Aktywne usługi', 'Platform take rate': 'Prowizja platformy',
    'global default': 'domyślnie globalnie', 'Avg. client price': 'Śr. cena klienta',
    'Service': 'Usługa', 'Category': 'Kategoria', 'Specialization': 'Specjalizacja', 'Duration': 'Czas',
    'Net (you)': 'Netto (Ty)', 'Client “from”': 'Klient „od”', 'Fee': 'Prowizja',
    // ---- purchasing ----
    'Supply requests from the floor — order, then close to notify the author': 'Zapotrzebowania z warsztatu — zamów, a po zamknięciu autor zostanie powiadomiony',
    'Part orders': 'Zamówienia części', 'New request': 'Nowe zapotrzebowanie', 'Open requests': 'Otwarte zgłoszenia',
    'Overdue': 'Zaległe', 'needs attention': 'wymaga uwagi', 'Closed this week': 'Zamknięte w tym tygodniu', 'on time 91%': 'na czas 91%',
    'Shopping list': 'Lista zakupów', 'By deadline': 'Wg terminu', 'By order': 'Wg zlecenia', 'By author': 'Wg autora',
    'Item': 'Pozycja', 'Requested by': 'Zgłaszający', 'Priority': 'Priorytet', 'Deadline': 'Termin',
    'standalone': 'samodzielne', 'High': 'Wysoki', 'Low': 'Niski', 'Normal': 'Normalny',
    'Open': 'Otwarte', 'Ordered': 'Zamówione', 'Mark ordered': 'Oznacz zamówione', 'Close': 'Zamknij',
    'Marked as ordered — author notified': 'Oznaczone jako zamówione — autor powiadomiony', 'Request closed — author notified': 'Zgłoszenie zamknięte — autor powiadomiony',
    // ---- finances ----
    'Card payouts via Stripe Connect · cash commission accrued and invoiced separately': 'Wypłaty kartowe przez Stripe Connect · prowizja gotówkowa naliczana i fakturowana osobno',
    'Week': 'Tydzień', 'Month': 'Miesiąc', 'Quarter': 'Kwartał', 'This month': 'W tym miesiącu', 'June 2026': 'Czerwiec 2026',
    'GMV (this month)': 'GMV (ten miesiąc)', '12% vs last month': '12% wzgl. zeszłego miesiąca',
    'Net payout (card)': 'Wypłata netto (karta)', 'via Stripe': 'przez Stripe', 'Cash collected': 'Zebrana gotówka',
    'Commission owed': 'Należna prowizja', 'invoice due Jun 30': 'faktura do 30 cze',
    'Today’s money': 'Dzisiejsze wpływy', 'cash-first': 'najpierw gotówka', 'Collected (cash)': 'Zebrane (gotówka)',
    'Captured (card)': 'Pobrane (karta)', 'Gross today': 'Dziś brutto', 'Settlement status': 'Status rozliczeń',
    'Next Stripe payout': 'Następna wypłata Stripe', 'Pending capture': 'Oczekuje pobrania',
    'Commission owed (cash)': 'Należna prowizja (gotówka)', 'Invoiced monthly · due Jun 30': 'Fakturowane miesięcznie · termin 30 cze',
    'Transactions': 'Transakcje', 'Card payouts': 'Wypłaty kartowe', 'Gross': 'Brutto', 'Net': 'Netto', 'Pending': 'Oczekuje',
    'Cash commission': 'Prowizja gotówkowa', 'accrued': 'naliczone', 'Collected': 'Zebrane', 'Commission': 'Prowizja',
    'Invoiced': 'Zafakturowane', 'Accrued': 'Naliczone', 'Outstanding to platform': 'Do zapłaty platformie', 'View invoice': 'Zobacz fakturę',
    // ---- team ----
    'Invite team member': 'Zaproś członka zespołu', 'They receive an SMS invite and set their own password on first login': 'Otrzymają zaproszenie SMS i ustawią własne hasło przy pierwszym logowaniu',
    'Cancel': 'Anuluj', 'Send invite': 'Wyślij zaproszenie', 'Full name': 'Imię i nazwisko', 'Login email:': 'E-mail logowania:',
    'Phone (for SMS invite)': 'Telefon (do SMS)', 'Role': 'Rola', 'Admin access': 'Dostęp administratora', 'Limited access': 'Ograniczony dostęp',
    'Full access · all orders, finances, pricing, team': 'Pełny dostęp · wszystkie zlecenia, finanse, cennik, zespół', 'Own assigned orders only': 'Tylko własne przypisane zlecenia',
    'Add or remove staff and set what each role can see · staff see only the orders assigned to them': 'Dodawaj lub usuwaj pracowników i ustal, co widzi każda rola · pracownicy widzą tylko przypisane im zlecenia',
    'Invite member': 'Zaproś', 'Team members': 'Członkowie zespołu', '{a} admin · {b} staff': '{a} admin · {b} personel',
    'Pending invites': 'Oczekujące zaproszenia', 'awaiting first login': 'oczekuje pierwszego logowania', 'none': 'brak',
    'Specializations covered': 'Pokryte specjalizacje', 'Invite sent': 'Wysłano zaproszenie', 'Resend': 'Wyślij ponownie', 'Revoke': 'Cofnij',
    'Active members': 'Aktywni członkowie', 'Member': 'Osoba', 'Access': 'Dostęp', 'Active orders': 'Aktywne zlecenia', 'Manage': 'Zarządzaj',
    'you': 'Ty', 'You': 'Ty', 'All orders': 'Wszystkie zlecenia', 'finances': 'finanse', 'pricing': 'cennik', 'Remove': 'Usuń',
    'Remove team member': 'Usuń członka zespołu',
    'Their login is revoked immediately. Any orders assigned to them are released back to the unassigned pool — reassign them before they go unattended.': 'Ich dostęp zostanie natychmiast cofnięty. Przypisane im zlecenia wrócą do puli nieprzypisanych — przydziel je ponownie, zanim zostaną bez opieki.',
    'Invite sent to {name} · SMS delivered': 'Zaproszenie wysłane do {name} · SMS dostarczony', 'Invite revoked': 'Zaproszenie cofnięte',
    'Invite re-sent to {name}': 'Zaproszenie wysłane ponownie do {name}', '{name} removed · access revoked': '{name} usunięty · dostęp cofnięty',
    // ---- stubs ----
    'Working hours, slots & box capacity': 'Godziny pracy, terminy i przepustowość stanowisk',
    'Week grid of bookable slots and bay load. Drag bookings between bays; capacity per specialization. (Planned for the schedule build-out.)': 'Tygodniowa siatka dostępnych terminów i obłożenia stanowisk. Przeciągaj rezerwacje między stanowiskami; przepustowość wg specjalizacji. (W planach rozbudowy harmonogramu.)',
    'Customer ratings that build your shop rating': 'Oceny klientów budujące reputację serwisu',
    'Per-order ratings and written reviews feed your 4.8★ shop rating shown to clients in the marketplace.': 'Oceny zleceń i pisemne opinie tworzą ocenę 4.8★ serwisu widoczną dla klientów na platformie.',
    'Shop profile, Stripe Connect, monetization': 'Profil serwisu, Stripe Connect, monetyzacja',
    'Shop profile & specializations, Stripe Connect (KYC) status, and the monetization model switch (commission ↔ subscription).': 'Profil serwisu i specjalizacje, status Stripe Connect (KYC) oraz przełącznik modelu monetyzacji (prowizja ↔ abonament).',
    // ---- settings: shop profile + capabilities ----
    'Shop profile': 'Profil serwisu', 'Marketplace capabilities': 'Możliwości na platformie',
    'Shop name': 'Nazwa serwisu', 'Phone': 'Telefon', 'Address': 'Adres', 'City': 'Miasto', 'Opening hours': 'Godziny otwarcia',
    'Save changes': 'Zapisz zmiany', 'Settings saved': 'Ustawienia zapisane',
    'Warranty repair': 'Naprawa gwarancyjna',
    'Authorized for manufacturer warranty repairs': 'Autoryzacja do napraw gwarancyjnych producenta',
    'Authorized brands': 'Autoryzowane marki', 'Add brand': 'Dodaj markę', 'Select brands': 'Wybierz marki',
    'Insurance repair': 'Naprawa z ubezpieczenia', 'Settles repairs directly with insurers': 'Rozlicza naprawy bezpośrednio z ubezpieczycielami',
    'Partner insurers': 'Ubezpieczyciele partnerzy', 'Add insurer': 'Dodaj ubezpieczyciela', 'Select insurers': 'Wybierz ubezpieczycieli',
    'These capabilities appear as filters and badges to clients searching the marketplace.': 'Te możliwości pojawiają się jako filtry i oznaczenia dla klientów na platformie.',
    'How clients see you': 'Jak widzą Cię klienci', 'No brands selected yet': 'Nie wybrano marek',
    'Specializations': 'Specjalizacje', 'Done': 'Gotowe', 'Verified shop': 'Zweryfikowany serwis',
    // ---- work order ----
    'Awaiting client': 'Oczekuje na klienta', '{req} missing': 'brak: {req}', 'Simulate client:': 'Symuluj klienta:',
    'Approve': 'Zatwierdź', 'Approved · added to total': 'Zatwierdzone · dodano do sumy',
    '{req} missing — blocks “Ready”': 'brak: {req} — blokuje „Gotowe”', 'attachments complete': 'załączniki kompletne',
    'Declined by client': 'Odrzucone przez klienta', 'Hide chat': 'Ukryj czat', 'Open chat': 'Otwórz czat', 'Re-propose': 'Zaproponuj ponownie',
    'Client declined. Explain why the work is needed or propose a different scope — price only goes up from the “from” floor.': 'Klient odrzucił. Wyjaśnij, dlaczego praca jest potrzebna, lub zaproponuj inny zakres — cena rośnie tylko od progu „od”.',
    'You · shop': 'Ty · serwis', 'client': 'klient', 'Explain or propose another scope…': 'Wyjaśnij lub zaproponuj inny zakres…', 'Send': 'Wyślij',
    'I’d rather skip this for now — is it really necessary?': 'Wolę to na razie pominąć — czy to naprawdę konieczne?',
    'New ticket': 'Nowe zgłoszenie', 'Additional work or part discovered during the repair': 'Dodatkowa praca lub część wykryta podczas naprawy',
    'Send to client for approval': 'Wyślij do zatwierdzenia przez klienta', 'Ticket type': 'Typ zgłoszenia', 'Required on completion:': 'Wymagane przy zakończeniu:',
    'Title': 'Tytuł', 'e.g. Replace front brake discs': 'np. Wymiana przednich tarcz hamulcowych', 'Description for the client': 'Opis dla klienta',
    'Explain what was found and why the work is needed…': 'Wyjaśnij, co wykryto i dlaczego praca jest potrzebna…', 'Net price (shop)': 'Cena netto (serwis)',
    'Client sees': 'Klient widzi', 'incl. {n}% platform fee {fee}': 'w tym {n}% prowizji platformy {fee}',
    'opened': 'otwarte', 'Base work order': 'Podstawowe zlecenie', 'price “from” floor · cannot decrease': 'cena od progu „od” · nie może spaść',
    'assigned to': 'przypisane do', 'net': 'netto', '{a} approved · {b} awaiting': '{a} zatwierdzone · {b} oczekuje',
    'Running total': 'Suma bieżąca', 'live': 'na żywo', 'Base work ({n})': 'Praca podstawowa ({n})', 'Approved tickets': 'Zatwierdzone zgłoszenia',
    'Customer pays': 'Klient płaci', 'Shop net ({n}% take rate)': 'Netto serwisu ({n}% prowizji)', 'Platform commission': 'Prowizja platformy',
    '{amt} awaiting client approval': '{amt} oczekuje na zatwierdzenie klienta', 'awaiting client': 'oczekuje na klienta',
    'Cash on pickup. No hold is placed. Platform commission is': 'Gotówka przy odbiorze. Bez blokady. Prowizja platformy jest',
    'and billed to the shop separately.': 'i fakturowana serwisowi osobno.', 'Due on pickup': 'Do zapłaty przy odbiorze',
    'Paid in cash · {amt} collected': 'Opłacone gotówką · zebrano {amt}', 'Amount collected': 'Zebrana kwota', 'Record cash payment': 'Zapisz płatność gotówką',
    'Available once the order is marked': 'Dostępne, gdy zlecenie zostanie oznaczone jako', 'Commission to invoice:': 'Prowizja do faktury:',
    'Card via Stripe Connect. Hold on confirm, capture on completion with automatic commission split.': 'Karta przez Stripe Connect. Blokada przy potwierdzeniu, pobranie po zakończeniu z automatycznym podziałem prowizji.',
    'Authorized hold': 'Autoryzowana blokada', 'Re-auth (approved tickets)': 'Ponowna autoryzacja (zatwierdzone)', 'Captured': 'Pobrane', 'To capture': 'Do pobrania',
    'Captured · split {net} shop / {com} platform': 'Pobrane · podział {net} serwis / {com} platforma', 'Capture {amt}': 'Pobierz {amt}',
    'Funds held · capture on completion': 'Środki zablokowane · pobranie po zakończeniu', 'Completion checklist': 'Lista kontrolna zakończenia',
    'No approved tickets — base work photos only.': 'Brak zatwierdzonych zgłoszeń — tylko zdjęcia pracy podstawowej.', 'Mark ready & notify customer': 'Oznacz gotowe i powiadom klienta',
    'Attach required photos/receipts to continue': 'Dołącz wymagane zdjęcia/paragony, aby kontynuować', 'Assign': 'Przypisz',
    'Client approved — added to total': 'Klient zatwierdził — dodano do sumy', 'Client declined — chat opened': 'Klient odrzucił — otwarto czat',
    'Ticket re-proposed to client': 'Zgłoszenie ponownie zaproponowane klientowi', 'Ticket sent to client for approval': 'Zgłoszenie wysłane do zatwierdzenia przez klienta',
    'Customer notified: “Your car is ready”': 'Klient powiadomiony: „Twój samochód jest gotowy”', 'Cash payment recorded · {amt}': 'Zapisano płatność gotówką · {amt}', 'Card captured · {amt}': 'Karta pobrana · {amt}',
  },
  ru: {
    // ---- nav / shell ----
    'Operations': 'Операции', 'Shop': 'Сервис', 'Manage': 'Управление',
    'Overview': 'Обзор', 'Requests': 'Заявки', 'Work orders': 'Заказ-наряды', 'Schedule': 'Расписание',
    'Services & pricing': 'Услуги и цены', 'Purchasing': 'Закупки', 'Finances': 'Финансы', 'Reviews': 'Отзывы',
    'Team & roles': 'Команда и роли', 'Settings': 'Настройки',
    'Manager cabinet': 'Кабинет менеджера', 'Manager': 'Менеджер',
    'reviews': 'отзывов', '3 new this week': '3 новых за неделю',
    'Search': 'Поиск', 'Notifications': 'Уведомления', 'Language': 'Язык',
    // ---- pay ----
    'Cash': 'Наличные', 'Card': 'Карта',
    // ---- statuses ----
    'Request': 'Заявка', 'Accepted': 'Принят', 'In progress': 'В работе',
    'Ready': 'Готов', 'Paid': 'Оплачен', 'Closed': 'Закрыт',
    // ---- categories ----
    'Maintenance': 'ТО', 'Brakes': 'Тормоза', 'Chassis': 'Ходовая', 'Climate': 'Климат',
    'Diagnostics': 'Диагностика', 'Paint': 'Покраска', 'Electrical': 'Электрика', 'Engine': 'Двигатель',
    // ---- specializations / roles ----
    'Mechanics': 'Механика', 'Bodywork': 'Кузовные работы', 'Reception': 'Приёмка',
    'Mechanic': 'Механик', 'Painter': 'Маляр',
    // ---- services ----
    'Oil & filter change': 'Замена масла и фильтра', 'Front brake pads': 'Передние тормозные колодки',
    'Wheel alignment': 'Развал-схождение', 'A/C service & recharge': 'Обслуживание и заправка кондиционера',
    'Computer diagnostics': 'Компьютерная диагностика', 'Suspension inspection': 'Проверка подвески',
    'Body panel respray': 'Покраска кузовной детали', 'Paintless dent removal': 'Удаление вмятин без покраски',
    'Battery replacement': 'Замена аккумулятора', 'Timing belt replacement': 'Замена ремня ГРМ',
    // ---- durations ----
    '45 min': '45 мин', '1.5 h': '1,5 ч', '1 h': '1 ч', '30 min': '30 мин', '40 min': '40 мин',
    '1 day': '1 день', '2 h': '2 ч', '4 h': '4 ч',
    // ---- ticket types + reqs ----
    'Additional work': 'Доп. работа', 'Problem found': 'Найдена проблема',
    'Part replacement': 'Замена детали', 'Part order': 'Заказ детали',
    'Photo of completed work': 'Фото выполненной работы', 'Photo of problem + result': 'Фото проблемы + результата',
    'Photo of the part': 'Фото детали', 'Receipt + photo of part': 'Чек + фото детали',
    'receipt req.': 'нужен чек', 'photo req.': 'нужно фото',
    // ---- supply ----
    'Front brake discs OEM (pair)': 'Тормозные диски перед OEM (пара)', 'Control arm, front-left OEM': 'Рычаг передний левый OEM',
    'White base coat (RAL 9003)': 'Белая база (RAL 9003)', 'PDR glue tabs assortment': 'Набор клеевых аппликаторов PDR',
    'Body filler 1 kg': 'Шпатлёвка 1 кг', 'Clear coat hardener': 'Отвердитель для лака',
    '2 pcs': '2 шт.', '1 pc': '1 шт.', '2 L': '2 л', '1 set': '1 набор', '1 L': '1 л',
    'Ordered via Lakmal — ETA tomorrow AM': 'Заказано через Lakmal — доставка завтра утром', 'Picked up from warehouse': 'Забрано со склада',
    // ---- hero tickets ----
    'Replace front brake discs': 'Замена передних тормозных дисков', 'Front-left control arm worn': 'Износ переднего левого рычага',
    'Order OEM control arm (left)': 'Заказать рычаг OEM (левый)',
    'Discs scored below minimum thickness — replacement required alongside the pad change.': 'Диски изношены ниже минимальной толщины — замена необходима вместе с колодками.',
    'Play in the lower control arm bushing found during the suspension inspection. Recommend replacing before alignment.': 'При проверке подвески обнаружен люфт в сайлентблоке рычага. Рекомендуется замена до развал-схождения.',
    'Genuine part to be ordered from supplier for the control-arm replacement above.': 'Оригинальную деталь нужно заказать у поставщика для замены рычага выше.',
    'Mon–Fri 8:00–18:00 · Sat 9:00–14:00': 'Пн–Пт 8:00–18:00 · Сб 9:00–14:00',
    // ---- overview ----
    'Good morning': 'Доброе утро', 'Review requests': 'Просмотреть заявки',
    'Awaiting confirmation': 'Ожидают подтверждения', '2 new today': '2 новых сегодня',
    'Active work orders': 'Активные заказы', 'on track': 'по плану',
    'Tickets awaiting client': 'Тикеты у клиента', 'avg 18 min to decision': 'в среднем 18 мин до решения',
    'New requests': 'Новые заявки', '3 awaiting': '3 ожидают', 'View all': 'Все',
    'from': 'от', 'Open board': 'Открыть доску', 'Supply requests': 'Заявки на закупку',
    '1 overdue': '1 просрочена', 'Open purchasing': 'Открыть закупки', 'by': 'от',
    // ---- bookings ----
    'Guest': 'Гость', 'Registered': 'Зарегистрирован', 'OTP verified': 'OTP подтверждён', 'requested': 'запрошено',
    'Vehicle': 'Автомобиль', 'Requested slot': 'Запрошенное время', 'pays on pickup': 'оплата при выдаче',
    'hold on confirm': 'блокировка при подтверждении', 'Total from': 'Итого от',
    'Confirmed · work order created · customer notified': 'Подтверждено · заказ создан · клиент уведомлён',
    'Confirm': 'Подтвердить', '& place hold': 'и заблокировать сумму', 'Propose new slot': 'Предложить новое время',
    'Decline': 'Отклонить', 'New bookings waiting for your confirmation': 'Новые записи, ожидающие подтверждения',
    'Awaiting': 'Ожидают', 'Confirmed': 'Подтверждённые', 'All': 'Все', 'No pending requests.': 'Нет ожидающих заявок.',
    'Booking confirmed — customer notified': 'Запись подтверждена — клиент уведомлён', 'Booking declined': 'Запись отклонена',
    // ---- orders ----
    'Active': 'Активные', 'Every job in progress across the shop': 'Все текущие работы в сервисе', 'Filter': 'Фильтр',
    'Vehicle / customer': 'Авто / клиент', 'Order': 'Заказ', 'Status': 'Статус', 'Assigned': 'Назначены',
    'Tickets': 'Тикеты', 'Payment': 'Оплата', 'Total': 'Итого',
    // ---- pricing ----
    'Net prices you set · clients see the “from” price incl. {n}% platform fee': 'Цены нетто, которые вы задаёте · клиент видит цену «от» с комиссией платформы {n}%',
    'Add service': 'Добавить услугу', 'Active services': 'Активные услуги', 'Platform take rate': 'Комиссия платформы',
    'global default': 'по умолчанию', 'Avg. client price': 'Ср. цена для клиента',
    'Service': 'Услуга', 'Category': 'Категория', 'Specialization': 'Специализация', 'Duration': 'Длительность',
    'Net (you)': 'Нетто (вам)', 'Client “from”': 'Клиент «от»', 'Fee': 'Комиссия',
    // ---- purchasing ----
    'Supply requests from the floor — order, then close to notify the author': 'Заявки на закупку из цеха — закажите, затем закройте, чтобы уведомить автора',
    'Part orders': 'Заказы деталей', 'New request': 'Новая заявка', 'Open requests': 'Открытые заявки',
    'Overdue': 'Просрочено', 'needs attention': 'требует внимания', 'Closed this week': 'Закрыто за неделю', 'on time 91%': 'вовремя 91%',
    'Shopping list': 'Список покупок', 'By deadline': 'По сроку', 'By order': 'По заказу', 'By author': 'По автору',
    'Item': 'Позиция', 'Requested by': 'Запросил', 'Priority': 'Приоритет', 'Deadline': 'Срок',
    'standalone': 'отдельно', 'High': 'Высокий', 'Low': 'Низкий', 'Normal': 'Обычный',
    'Open': 'Открыта', 'Ordered': 'Заказано', 'Mark ordered': 'Отметить заказанным', 'Close': 'Закрыть',
    'Marked as ordered — author notified': 'Отмечено заказанным — автор уведомлён', 'Request closed — author notified': 'Заявка закрыта — автор уведомлён',
    // ---- finances ----
    'Card payouts via Stripe Connect · cash commission accrued and invoiced separately': 'Выплаты по картам через Stripe Connect · комиссия с наличных начисляется и выставляется отдельно',
    'Week': 'Неделя', 'Month': 'Месяц', 'Quarter': 'Квартал', 'This month': 'За месяц', 'June 2026': 'Июнь 2026',
    'GMV (this month)': 'GMV (за месяц)', '12% vs last month': '12% к прошлому месяцу',
    'Net payout (card)': 'Выплата нетто (карта)', 'via Stripe': 'через Stripe', 'Cash collected': 'Собрано наличными',
    'Commission owed': 'Комиссия к оплате', 'invoice due Jun 30': 'счёт до 30 июн',
    'Today’s money': 'Деньги за сегодня', 'cash-first': 'сначала наличные', 'Collected (cash)': 'Собрано (наличные)',
    'Captured (card)': 'Списано (карта)', 'Gross today': 'Брутто за сегодня', 'Settlement status': 'Статус расчётов',
    'Next Stripe payout': 'Следующая выплата Stripe', 'Pending capture': 'Ожидает списания',
    'Commission owed (cash)': 'Комиссия к оплате (наличные)', 'Invoiced monthly · due Jun 30': 'Счёт ежемесячно · до 30 июн',
    'Transactions': 'Транзакции', 'Card payouts': 'Выплаты по картам', 'Gross': 'Брутто', 'Net': 'Нетто', 'Pending': 'Ожидает',
    'Cash commission': 'Комиссия с наличных', 'accrued': 'начислено', 'Collected': 'Собрано', 'Commission': 'Комиссия',
    'Invoiced': 'Выставлен счёт', 'Accrued': 'Начислено', 'Outstanding to platform': 'К оплате платформе', 'View invoice': 'Открыть счёт',
    // ---- team ----
    'Invite team member': 'Пригласить сотрудника', 'They receive an SMS invite and set their own password on first login': 'Они получат приглашение по SMS и зададут пароль при первом входе',
    'Cancel': 'Отмена', 'Send invite': 'Отправить приглашение', 'Full name': 'Полное имя', 'Login email:': 'E-mail для входа:',
    'Phone (for SMS invite)': 'Телефон (для SMS)', 'Role': 'Роль', 'Admin access': 'Права администратора', 'Limited access': 'Ограниченный доступ',
    'Full access · all orders, finances, pricing, team': 'Полный доступ · все заказы, финансы, цены, команда', 'Own assigned orders only': 'Только свои назначенные заказы',
    'Add or remove staff and set what each role can see · staff see only the orders assigned to them': 'Добавляйте или удаляйте сотрудников и настраивайте, что видит каждая роль · сотрудники видят только назначенные им заказы',
    'Invite member': 'Пригласить', 'Team members': 'Сотрудники', '{a} admin · {b} staff': '{a} админ · {b} сотр.',
    'Pending invites': 'Ожидающие приглашения', 'awaiting first login': 'ожидает первого входа', 'none': 'нет',
    'Specializations covered': 'Покрытые специализации', 'Invite sent': 'Приглашение отправлено', 'Resend': 'Отправить снова', 'Revoke': 'Отозвать',
    'Active members': 'Активные сотрудники', 'Member': 'Сотрудник', 'Access': 'Доступ', 'Active orders': 'Активные заказы', 'Manage': 'Управление',
    'you': 'вы', 'You': 'Вы', 'All orders': 'Все заказы', 'finances': 'финансы', 'pricing': 'цены', 'Remove': 'Удалить',
    'Remove team member': 'Удалить сотрудника',
    'Their login is revoked immediately. Any orders assigned to them are released back to the unassigned pool — reassign them before they go unattended.': 'Их доступ отзывается немедленно. Назначенные им заказы возвращаются в общий пул — переназначьте их, пока они не остались без присмотра.',
    'Invite sent to {name} · SMS delivered': 'Приглашение отправлено {name} · SMS доставлено', 'Invite revoked': 'Приглашение отозвано',
    'Invite re-sent to {name}': 'Приглашение повторно отправлено {name}', '{name} removed · access revoked': '{name} удалён · доступ отозван',
    // ---- stubs ----
    'Working hours, slots & box capacity': 'Часы работы, слоты и загрузка постов',
    'Week grid of bookable slots and bay load. Drag bookings between bays; capacity per specialization. (Planned for the schedule build-out.)': 'Недельная сетка доступных слотов и загрузки постов. Перетаскивайте записи между постами; вместимость по специализациям. (В планах развития расписания.)',
    'Customer ratings that build your shop rating': 'Оценки клиентов, формирующие рейтинг сервиса',
    'Per-order ratings and written reviews feed your 4.8★ shop rating shown to clients in the marketplace.': 'Оценки заказов и письменные отзывы формируют рейтинг сервиса 4.8★, видимый клиентам на платформе.',
    'Shop profile, Stripe Connect, monetization': 'Профиль сервиса, Stripe Connect, монетизация',
    'Shop profile & specializations, Stripe Connect (KYC) status, and the monetization model switch (commission ↔ subscription).': 'Профиль и специализации сервиса, статус Stripe Connect (KYC) и переключатель модели монетизации (комиссия ↔ подписка).',
    // ---- settings: shop profile + capabilities ----
    'Shop profile': 'Профиль сервиса', 'Marketplace capabilities': 'Возможности на платформе',
    'Shop name': 'Название сервиса', 'Phone': 'Телефон', 'Address': 'Адрес', 'City': 'Город', 'Opening hours': 'Часы работы',
    'Save changes': 'Сохранить', 'Settings saved': 'Настройки сохранены',
    'Warranty repair': 'Гарантийный ремонт',
    'Authorized for manufacturer warranty repairs': 'Авторизация на гарантийный ремонт производителя',
    'Authorized brands': 'Авторизованные марки', 'Add brand': 'Добавить марку', 'Select brands': 'Выберите марки',
    'Insurance repair': 'Ремонт по страховке', 'Settles repairs directly with insurers': 'Рассчитывает ремонт напрямую со страховыми',
    'Partner insurers': 'Страховые-партнёры', 'Add insurer': 'Добавить страховую', 'Select insurers': 'Выберите страховые',
    'These capabilities appear as filters and badges to clients searching the marketplace.': 'Эти возможности отображаются клиентам как фильтры и метки на платформе.',
    'How clients see you': 'Как вас видят клиенты', 'No brands selected yet': 'Марки не выбраны',
    'Specializations': 'Специализации', 'Done': 'Готово', 'Verified shop': 'Проверенный сервис',
    // ---- work order ----
    'Awaiting client': 'Ожидает клиента', '{req} missing': 'нет: {req}', 'Simulate client:': 'Симулировать клиента:',
    'Approve': 'Одобрить', 'Approved · added to total': 'Одобрено · добавлено в сумму',
    '{req} missing — blocks “Ready”': 'нет: {req} — блокирует «Готов»', 'attachments complete': 'вложения полные',
    'Declined by client': 'Отклонено клиентом', 'Hide chat': 'Скрыть чат', 'Open chat': 'Открыть чат', 'Re-propose': 'Предложить снова',
    'Client declined. Explain why the work is needed or propose a different scope — price only goes up from the “from” floor.': 'Клиент отклонил. Объясните, зачем нужна работа, или предложите другой объём — цена растёт только от порога «от».',
    'You · shop': 'Вы · сервис', 'client': 'клиент', 'Explain or propose another scope…': 'Объясните или предложите другой объём…', 'Send': 'Отправить',
    'I’d rather skip this for now — is it really necessary?': 'Я бы пока это пропустил — это действительно необходимо?',
    'New ticket': 'Новый тикет', 'Additional work or part discovered during the repair': 'Доп. работа или деталь, обнаруженная при ремонте',
    'Send to client for approval': 'Отправить клиенту на одобрение', 'Ticket type': 'Тип тикета', 'Required on completion:': 'Требуется при завершении:',
    'Title': 'Заголовок', 'e.g. Replace front brake discs': 'напр. Замена передних тормозных дисков', 'Description for the client': 'Описание для клиента',
    'Explain what was found and why the work is needed…': 'Объясните, что обнаружено и зачем нужна работа…', 'Net price (shop)': 'Цена нетто (сервис)',
    'Client sees': 'Клиент видит', 'incl. {n}% platform fee {fee}': 'вкл. {n}% комиссии платформы {fee}',
    'opened': 'открыт', 'Base work order': 'Базовый заказ-наряд', 'price “from” floor · cannot decrease': 'цена от порога «от» · не может снижаться',
    'assigned to': 'назначено', 'net': 'нетто', '{a} approved · {b} awaiting': '{a} одобрено · {b} ожидает',
    'Running total': 'Текущая сумма', 'live': 'вживую', 'Base work ({n})': 'Базовые работы ({n})', 'Approved tickets': 'Одобренные тикеты',
    'Customer pays': 'Клиент платит', 'Shop net ({n}% take rate)': 'Нетто сервиса (комиссия {n}%)', 'Platform commission': 'Комиссия платформы',
    '{amt} awaiting client approval': '{amt} ожидает одобрения клиента', 'awaiting client': 'ожидает клиента',
    'Cash on pickup. No hold is placed. Platform commission is': 'Наличные при выдаче. Без блокировки. Комиссия платформы',
    'and billed to the shop separately.': 'и выставляется сервису отдельно.', 'Due on pickup': 'К оплате при выдаче',
    'Paid in cash · {amt} collected': 'Оплачено наличными · собрано {amt}', 'Amount collected': 'Полученная сумма', 'Record cash payment': 'Зафиксировать оплату наличными',
    'Available once the order is marked': 'Доступно после того, как заказ отмечен как', 'Commission to invoice:': 'Комиссия к счёту:',
    'Card via Stripe Connect. Hold on confirm, capture on completion with automatic commission split.': 'Карта через Stripe Connect. Блокировка при подтверждении, списание по завершении с автоматическим разделением комиссии.',
    'Authorized hold': 'Авторизованная блокировка', 'Re-auth (approved tickets)': 'Переавторизация (одобренные)', 'Captured': 'Списано', 'To capture': 'К списанию',
    'Captured · split {net} shop / {com} platform': 'Списано · раздел {net} сервис / {com} платформа', 'Capture {amt}': 'Списать {amt}',
    'Funds held · capture on completion': 'Средства заблокированы · списание по завершении', 'Completion checklist': 'Чек-лист завершения',
    'No approved tickets — base work photos only.': 'Нет одобренных тикетов — только фото базовых работ.', 'Mark ready & notify customer': 'Отметить готовым и уведомить клиента',
    'Attach required photos/receipts to continue': 'Прикрепите нужные фото/чеки, чтобы продолжить', 'Assign': 'Назначить',
    'Client approved — added to total': 'Клиент одобрил — добавлено в сумму', 'Client declined — chat opened': 'Клиент отклонил — открыт чат',
    'Ticket re-proposed to client': 'Тикет повторно предложен клиенту', 'Ticket sent to client for approval': 'Тикет отправлен клиенту на одобрение',
    'Customer notified: “Your car is ready”': 'Клиент уведомлён: «Ваш автомобиль готов»', 'Cash payment recorded · {amt}': 'Оплата наличными зафиксирована · {amt}', 'Card captured · {amt}': 'Карта списана · {amt}',
  },
};

Object.assign(window, { I18N, LANGS, setLang, i18nLocale, tx, tdate, fmt });
