WinUpGo
Szukaj
CASWINO
SKYSLOTS
BRAMA
TETHERPAY
777 FREE SPINS + 300%
Kasyno Cryptocurrency Crypto Casino Torrent Gear to twoje wyszukiwanie torrentów! Bieg torrent

Jak wielojęzyczność jest wdrażana na platformach kasynowych

Dlaczego wielojęzyczność kasyna

Gracze wpłacają i umieszczają zakłady, gdzie rozumieją interfejs, widzą ceny w swojej walucie i czują lokalne znaczenie (sport, wakacje, metody płatności, teksty prawne). Poprawna wielojęzyczność zwiększa registratsii → depozit CR, zmniejsza tarcie CCG/box i poprawia retencję.


Terminologia podstawowa

i18n (Internacjonalizacja) - przygotowanie produktu do lokalizacji: klucze, znaczniki, daty formatowania/numery/waluty, wsparcie dla RTL i klejnotów.

L10n (Lokalizacja) - rzeczywiste tłumaczenia i lokalne adaptacje: teksty, obrazy, promo, bloki prawne, RG (odpowiedzialna gra).

Locale - język + region (np. „pt-BR”, „fr-CA”), wpływa na formaty, walutę, banery prawne i treść.


architektura i18n: jak układać się od podstaw

1. Klucze zamiast „twardych” strun.

Kluczowe nazwy w znaczeniu ('cashier. depozyt. tytuł ") zamiast na ekranie.

Linie - w plikach/tabelach tłumaczeniowych, nie w kodzie.

2. Format OIOM.

Plurale, płeć, przypadki, waluta/data/format procentowy:

{count, liczba mnoga, jeden {# bet} kilka {# bets} wiele {# bets} inne {# bets}}

3. Formaty i waluty.

Kody ISO, lokalne delimitery, format daty 'yyyy-MM-dd' w bazie danych, renderowanie lokalne z przodu.

Przeliczanie kursów wymiany na serwerze, wyświetlanie zgodnie z zasadami waluty (znak/przestrzeń/pozycja).

4. Timezony.

W BAZIE DANYCH - UTC. Z przodu/z literami - lokalny TZ gracza (zapisany w profilu).

5. RTL/dwukierunkowość.

Support 'dir =' rtl' 'dla' ar ',' fa ',' he '; ikony lustrzane, zamówienie elementu, style kaskadowe bez włamania.

6. Oddzielenie domen tłumaczeniowych.

'core' (навивавий), 'cashier', 'kyc',' rg ',' promotions ',' games ',' email/push ',' seo '. Pozwala zaktualizować część bez wpływu na wszystko.


Co dokładnie znajduje się w kasynie

Lobby/katalog gier: nazwy, kategorie, banery, znaczniki wyszukiwania, opisy.

Gra i dostawcy: nazwa/gry, paytable/zasady, ostrzeżenia. Jeśli usługodawca nie dostarczy wymaganego języka, przygotuj opcję awaryjną i ostrzeżenie.

Kasjer: nazwy metod (lokalny APM), statusy, błędy PSP, teksty prawne 3-D Secure, na/off-ramp crypts.

KYC/AML/RG: instrukcje dokumentowe, teksty timeout/limit, self-exclusion, wiek i odpowiedzialne banery.

Strony prawne: ToS, polityka prywatności, licencja, zakazy krajów, banery cookies.

Marketing: strony lądowania, promo/misje/turnieje, puchary, e-mail, banery w CDN.

SEO meta: '', '<meta description>', 'hreflang', micro markup.</p> <hr> <p>L10n Przepływ pracy</p> <p>1. Ekstrakcja kluczy z repozytorium (linter + CI sprawdza „twarde” ciągi).</p> <p>2. System CAT/Platforma TS (Zwrot/Smartling/Lokalise, itp.): słownik terminów, pamięci tłumaczeniowej, zrzutów ekranu kontekstowego.</p> <p>3. Role: translator → edytor → przegląd prawny (dla RG/ToS/cash desk).</p> <p>4. QA lokalizacji: regresje interfejsu użytkownika (zrzuty ekranu), autotesty dla plurali i ICU, sprawdzanie długości linii/okrawań.</p> <p>5. Wersioning: „lang pack” jako artefakt, zgodność z poprzednim kontraktem; kanaryjski procent rollout na 5-10 miejscowej publiczności.</p> <p>6. Dostawa: Manifesty CDN + tag-purge (szybka publikacja bez zwolnienia backendu).</p> <hr> <h2>Strategia lokalna</h2> <p>Minimalny zestaw: EN + kluczowe rynki (np. "es-ES", "pt-BR", "tr-TR", "de-DE", "fr-FR", "pl-PL", "ru-RU", "uk-UA", "ar-AE", "ms-MY", "th-TH", "ja-JP ').</p> <p>Warianty językowe: „es-ES” i „es-MX” (terminy box office, sport, formuły prawne).</p> <p>Drabina awaryjna: „fr-CA → fr → en”. Gracz zawsze widzi poprawny tekst.</p> <p>Przypisanie geo i wybór gracza: auto-sugeruj lokalizację przez IP/przeglądarkę + wyraźny przełącznik w nagłówku i profilu.</p> <hr> <h2>Zgodność i wymogi prawne</h2> <p>Wiek/odpowiedzialne banery odpowiadają jurysdykcji: brzmienie, organizacje kontaktowe, linki.</p> <p>KYC/AML/KYT: dokładne terminy, jasne instrukcje (format dokumentów, tłumacz nie zastępuje!).</p> <p>Warunki promocji: warunki prawne promo w każdej lokalizacji (nie tłumaczenie maszynowe!).</p> <p>Geogrodzenie tekstów: w krajach objętych zakazem - odpowiednie powiadomienia/bloki, a nie 404 w języku angielskim.</p> <hr> <h2>Części UX, które najczęściej „łamią”</h2> <p>Plurale i liczby (języki słowiańskie mają 3-4 formy).</p> <p>Długie słowa/hipenalizacja (niemiecki/fiński) - elastyczna siatka, „łączniki: auto”.</p> <p>RTL i ikony - lustrzane strzałki/chevrony, wyrównać kwoty.</p> <p>Formaty pieniędzy: przestrzenie/separatory, pozycja znaków, zaokrąglanie, „cienkie przestrzenie” dla tysięcy.</p> <p>Błędy box office - zakaz „twardego” angielskiego tekstu z PSP; Mapowanie kodu → wiadomości lokalne</p> <hr> <h2>SEO i wydajność</h2> <p>Struktura adresu URL: podkatalogi ('/de/', '/fr/'), a nie subdomeny (łatwiejsze do zarządzania plikami cookie/locale).</p> <p>„hreflang” i kanoniczne między lokalizacjami; lokalna mapa strony.</p> <p>Pamięć podręczna CDN lobby JSON locale z „stale-while-revalidate”.</p> <p>Obrazy/banery - lokalne napisy/waluty; automatyczna konwersja formatu (WebP/AVIF).</p> <p>Pakiety tłumaczeń - dynamiczny import przez locale, nie przeciągnij wszystkich języków naraz.</p> <hr> <h2>Dostawcy gier i lokalizacja</h2> <p>Macierz obsługiwanych języków dla każdego dostawcy/gry; upadek na język lobby lub „angielski z zastrzeżeniem”.</p> <p>Płatność/Pomoc: jeśli tekst jest zamknięty, oddzielny overlay-guide Twojej lokalizacji.</p> <p>Zdarzenia i błędy dostawcy - normalizacja i mapa lokalna.</p> <hr> <h2>Telemetria i A/B</h2> <p>Lokalne mierniki: CR 'register → KYC → deposit', 'deposit → bet', NPS, churn, KYC speed, box office failure.</p> <p>Testy brzmienia: lokalne biurko/teksty promocyjne często dają + X% do konwersji.</p> <p>Wykrywanie „złamanych” tłumaczeń: wzrost kliknięć w „Pomoc”, nietypowo długi czas mieszkania w kasie.</p> <hr> <h2>Anty-wzory</h2> <p>Linie twarde w kodzie i mieszanie języka/logiki.</p> <p>Brak ICU → „2 zakład „/” 5 zakład ”zamiast poprawnych formularzy.</p> <p>Tłumaczenie maszynowe tekstów prawnych/kasy/płatności.</p> <p>Jeden język dla wszystkich krajów (na przykład „es-ES” w LATAM) - błędy kulturowe i terminologiczne.</p> <p>Globalne banery promo bez lokalnych warunków → roszczenia regulatora/graczy.</p> <p>Brak fallback → puste linie/angielski tekst „fish”.</p> <p>Pakiet wszystkich języków na każdej stronie → nadwaga i powolny TTFB.</p> <hr> <h2>Wielojęzyczna lista kontrolna kasyna</h2><p>Architektura i dane</p> <ul style="padding-left:0; list-style:none; margin:10px 0 14px;"> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Klucze i18n, formaty ICU, UTC w bazie danych, TZ z przodu/w literach.</li> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Waluty/formaty/delimitery pochodzą z lokalizacji, a nie z reguł „ręcznych”.</li> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Wsparcie RTL, lusterko ikonowe, automatyczna hiphenacja.</li> </ul> <h2>Treść i przepływ pracy</h2> <ul style="padding-left:0; list-style:none; margin:10px 0 14px;"> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Platforma CAT, słownik warunków, dostęp do zrzutów ekranu kontekstowego.</li> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Role: perevod → redaktura → yuridichesky review.</li> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Publikacja kanaryjska „lang pack”, dostawa CDN i tag-purge.</li> </ul> <h2>Domeny</h2> <ul style="padding-left:0; list-style:none; margin:10px 0 14px;"> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Lobby/games/box office/KYC/RG/legal/marketing/SEO - objęte i oddzielone.</li> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Mapowanie błędów PSP/ISP na wiadomości lokalne.</li> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Matryca językowa według dostawcy gier (fallback + overlay).</li> </ul> <h2>SEO/Perf</h2> <ul style="padding-left:0; list-style:none; margin:10px 0 14px;"> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>„/locale/” URL, „hreflang”, mapa lokalna.</li> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Dynamiczny import tłumaczeń, JSON lobby cache.</li> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Optymalizacja obrazu CDN/wideo dla locale.</li> </ul> <h2>Zgodność</h2> <ul style="padding-left:0; list-style:none; margin:10px 0 14px;"> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Teksty prawne i RG są sprawdzane lokalnie.</li> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Teksty dotyczące ogrodzenia geograficznego i zakazu/wieku.</li> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Cookie/zgoda w języku użytkownika.</li> </ul> <h2>Obserwowalność</h2> <ul style="padding-left:0; list-style:none; margin:10px 0 14px;"> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>CR/Failure/Latency metrics by locale.</li> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>Wpisy do „złamanych” klawiszy i pustych linii.</li> <li><span style="display:inline-flex; width:18px; height:18px; margin-right:8px; align-items:center; justify-content:center; flex:0 0 18px;;color:#c0cc4c"><svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" fill="currentColor"/><path d="M16.5 9.5l-5.1 5.1L7.5 10.7" fill="none" stroke="#000" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>A/B w wersji krytycznej (cash desk/CCM/promo).</li> </ul> <hr> <p>Wielojęzyczność w iGaming nie jest "przetłumaczyć kilka linii. "Jest to dyscyplina systemowa: architektura i18n, formaty ICU, ścisły przepływ tłumaczeń, zgodność, dostawa CDN i obserwowalność. Dzięki temu, że jest częścią platformy, zwiększysz konwersję, zmniejszysz tarcie przy realizacji transakcji i przekażesz wymagania prawne bez „ręcznych” pożarów - przy jednoczesnym przewidywalnym i szybkim skalowaniu treści i rynków.</p></div> <style> /* ===== Общая типографика ===== */ .geo-grid,.countries{ font-family: Segoe UI,system-ui,-apple-system,Roboto,Arial,sans-serif; } /* ========================================= L1 — ОСНОВНЫЕ РАЗДЕЛЫ (вертикальный список) ========================================= */ .geo-grid{ /* Был grid-карточек — делаем строго вертикальный список */ display: flex; flex-direction: column; gap: 0; /* без зазоров — как чистый список */ margin: 0; padding: 0; } /* Перестилизуем .geo-card под «элемент списка» */ .geo-card{ display: block; text-decoration: none; color: #eaf0ff; background: transparent; border: 0; border-left: 3px solid transparent; /* тонкий левый акцент по hover */ border-radius: 0; padding: 12px 10px 12px 14px; transition: background .12s ease, border-color .12s ease, transform .06s ease; } /* Межстрочные разделители */ .geo-card + .geo-card{ border-top: 1px solid rgba(148,163,184,.10); } /* Содержимое — компактно в колонку */ .geo-card__body{ display: flex; flex-direction: column; gap: 4px; min-width: 0; } /* Заголовок раздела — акцент */ .geo-card__title{ margin: 0; font-weight: 800; font-size: 17px; line-height: 1.2; color: #ffffff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* Короткое описание — в одну строку */ .geo-card__desc{ margin: 0; font-size: 13px; line-height: 1.35; color: #b8c4d9; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; /* вики-стиль: только одна строка */ overflow: hidden; } /* CTA превращаем в маленький чип-ярлык справа налево */ .geo-card__cta{ align-self: flex-start; margin-top: 2px; font-size: 12px; font-weight: 700; letter-spacing: .2px; color: #2a1b00; background: linear-gradient(180deg,#fff27a,#ffe85c 55%,#ffc933); border: 1px solid #e3b600; border-radius: 8px; padding: 4px 8px; box-shadow: 0 1px 0 rgba(0,0,0,.06) inset; } /* Hover — мягкий подсвет и левый акцент */ .geo-card:hover{ background: linear-gradient(180deg, rgba(255,255,255,.03), rgba(255,255,255,.01)); border-left-color: #ffe85c; } .geo-card:active{ transform: translateY(1px); } /* ========================================= L2 — СТАТЬИ (вертикальный список «каталог») ========================================= */ .countries-wrap{ margin-top: 16px; padding: 8px 10px; border: 1px solid rgba(148,163,184,.10); border-radius: 10px; background: linear-gradient(180deg, rgba(255,255,255,.015), rgba(255,255,255,.008)); } /* Список одной колонкой, без точек */ .countries{ list-style: none; margin: 0; padding: 0; display: block; } /* Элемент списка статьи */ .country-li{ margin: 0; } /* Сама ссылка — компактная строка с разделителем */ .country-link{ position: relative; display: grid; grid-template-columns: 1fr 18px; /* название | стрелка */ align-items: center; column-gap: 10px; padding: 9px 2px; text-decoration: none; color: #dfe7ff; transition: background .12s ease, color .12s ease, transform .06s ease; } /* Тонкий разделитель между строками */ .country-link + .country-link{ border-top: 1px dashed rgba(148,163,184,.15); } /* Название статьи */ .country-name{ font-weight: 600; letter-spacing: .2px; color: #eef3ff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 14px; } /* Стрелка справа */ .country-arrow{ display: flex; align-items: center; justify-content: center; color: rgba(255,255,255,.28); transition: color .12s ease, transform .12s ease; } /* Hover/Focus */ .country-link:hover{ color: #ffffff; background: rgba(255,255,255,.02); } .country-link:hover .country-arrow{ color: #ffe85c; transform: translateX(2px); } .country-link:active{ transform: translateY(1px); } .country-link:focus-visible{ outline: 2px solid #93c5fd; outline-offset: 2px; } /* ===== Адаптив ===== */ @media (max-width: 680px){ .geo-card{ padding: 10px 8px 10px 12px; } .geo-card__title{ font-size: 16px; } .geo-card__desc{ -webkit-line-clamp: 2; } /* на мобиле можно две строки */ .countries-wrap{ padding: 6px 8px; } } </style> </div> </div> </main> <footer> <div style="display: flex; justify-content: space-between; align-items:center; padding-top:20px;"> <div style="padding-left:5px;"> <div class="language-selector"> <button class="language-button"> <span style="display: inline-flex; align-items: center;"> <svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg" style="margin-right: 10px;"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.52 4.392A8.009 8.009 0 0 0 4.061 11h2.997c.227-2.363 1.078-4.627 2.46-6.608Zm4.96 0c1.383 1.981 2.234 4.245 2.461 6.608h2.997a8.009 8.009 0 0 0-5.457-6.608ZM14.93 11c-.269-2.373-1.28-4.642-2.93-6.54C10.35 6.357 9.339 8.626 9.07 11h5.86Zm-5.86 2h5.86c-.269 2.373-1.28 4.642-2.93 6.54-1.65-1.898-2.661-4.167-2.93-6.54Zm-2.011 0H4.062a8.009 8.009 0 0 0 5.457 6.608C8.137 17.627 7.286 15.363 7.06 13Zm7.422 6.608c1.382-1.981 2.233-4.245 2.46-6.608h2.997a8.008 8.008 0 0 1-5.457 6.608ZM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10S2 17.523 2 12Z" fill="#fff"></path> </svg> Polski </span> </button> <div class="language-menu"> <a hreflang="en" href="https://winupgo.com/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">English</a><a hreflang="es" href="https://winupgo.com/es/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Español</a><a hreflang="fr" href="https://winupgo.com/fr/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Français</a><a hreflang="pt" href="https://winupgo.com/pt/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Português</a><a hreflang="ru" href="https://winupgo.com/ru/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Русский</a><a hreflang="zh-Hans" href="https://winupgo.com/cn/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">简体中文</a><a hreflang="zh-Hant" href="https://winupgo.com/tw/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">繁體中文</a><a hreflang="ja" href="https://winupgo.com/jp/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">日本語</a><a hreflang="ko" href="https://winupgo.com/kr/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">한국어</a><a hreflang="hi" href="https://winupgo.com/hi/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">हिन्दी</a><a hreflang="fa" href="https://winupgo.com/fa/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">فارسی</a><a hreflang="ar" href="https://winupgo.com/ar/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">العربية</a><a hreflang="tr" href="https://winupgo.com/tr/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Türkçe</a><a hreflang="uz" href="https://winupgo.com/uz/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Oʻzbekcha</a><a hreflang="kk" href="https://winupgo.com/kz/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">қазақ</a><a hreflang="tk" href="https://winupgo.com/tk/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Türkmençe</a><a hreflang="ky" href="https://winupgo.com/ky/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Кыргызча</a><a hreflang="tg" href="https://winupgo.com/tg/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Тоҷикӣ</a><a hreflang="ka" href="https://winupgo.com/ka/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">ქართული</a><a hreflang="he" href="https://winupgo.com/he/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">עברית</a><a hreflang="az" href="https://winupgo.com/az/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Azərbaycan dili</a><a hreflang="hy" href="https://winupgo.com/hy/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Հայերեն</a><a hreflang="de" href="https://winupgo.com/de/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Deutsch</a><a hreflang="it" href="https://winupgo.com/it/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Italiano</a><a hreflang="pl" href="https://winupgo.com/pl/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Polski</a><a hreflang="ro" href="https://winupgo.com/ro/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Română</a><a hreflang="el" href="https://winupgo.com/el/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Ελληνικά</a><a hreflang="uk" href="https://winupgo.com/ua/wiki/casino-technology/how-multilingualism-is-implemented-on-casino-platforms/">Українська</a> </div> </div> </div> <div class="copy" style="flex: 1;text-align:right;padding-right:10px;"> © <b>Win<u>Up</u>Go</b> 2024 </div> <div style="width:70;padding-right:5px;"> <div style="display:flex;gap:10px;justify-content:flex-end;"> <a target="_blank" rel="noopener noreferrer nofollow sponsored" href="https://t.me/winupgo"><img width="30" height="30" alt="WinUpGo Channel" src="https://winupgo.com/images/telegram.svg"></a> <a href="/pl/feedback-form/"><img width="30" height="30" alt="Formularz opinii" src="https://winupgo.com/images/feedback.svg"></a> </div> </div> </div> </footer> </div> <script src="/js/jquery-3.6.0.min.js"></script> <script> function MyLoc(url) { document.location.href = url; } document.addEventListener('DOMContentLoaded', () => { const button = document.querySelector('.language-button'); const menu = document.querySelector('.language-menu'); const languageSelector = document.querySelector('.language-selector'); button.addEventListener('click', (e) => { e.stopPropagation(); // Предотвращение всплытия события menu.classList.toggle('show'); }); document.addEventListener('click', (e) => { // Проверка, был ли клик вне области кнопки и меню if (!languageSelector.contains(e.target)) { menu.classList.remove('show'); } }); }); //alert("Ширина экрана: " + window.innerWidth + " пикселей"); </script> <script> $(document).ready(function() { $('#changpwd').click(function(){ //$('#err').text(''); var hashkey = $('#hashkey').val(); var pass = $('#pass').val(); var pass2 = $('#pass2').val(); if(pass != pass2 || pass == ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Hasło nie pasuje lub jest puste", 'error'); exit; } $.ajax({ url: "/ajax.php", // куда отправляем type: "post", // метод передачи dataType: "json", // тип передачи данных data: { // что отправляем "action": "changpwd", "hashkey": hashkey, "pass": pass }, // после получения ответа сервера success: function(data){ //alert('yes'); if(data.result == "success"){ $('#main_fr').html("<div class=\"success\">Hasło zostało pomyślnie zmienione! <a href='/private/' class='const_link'>Zaloguj się</a></div>"); showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Hasło zmienione", 'success'); window.scrollTo({top: 0, behavior: 'smooth'}); exit; }else{ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Wystąpił błąd systemu, skontaktuj się z pomocą techniczną.", 'error'); exit; } } }); }); $('#respassword').click(function(){ //$('#err').text(''); var email = $('#email').val(); if(email == ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Wpisz e-mail", 'error'); exit; } if(!email.includes('@') || !email.includes('.')){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Nieprawidłowy format e-maila", 'error'); exit; } $.ajax({ url: "/ajax.php", // куда отправляем type: "post", // метод передачи dataType: "json", // тип передачи данных data: { // что отправляем "action": "respassword", "email": email }, // после получения ответа сервера success: function(data){ //alert('yes'); if(data.result == "success"){ $('#main_fr').html("<div class=\"success\">Instrukcja odzyskiwania hasła została wysłana na Twój e-mail. Jeśli nie otrzymałeś wiadomości, sprawdź folder SPAM.</div>"); showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Instrukcja została wysłana", 'success'); //window.scrollTo({top: 0, behavior: 'smooth'}); exit; }else{ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Wystąpił błąd systemu, skontaktuj się z pomocą techniczną.", 'error'); exit; } } }); }); $('#edit').click(function(){ var nickname = $('#nickname').val(); var pass = $('#pass').val(); var pass2 = $('#pass2').val(); if(nickname == ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Wpisz pseudonim", 'error'); exit; } /*if(pass != pass2 || pass == ""){ showNotification('Hasło nie pasuje lub jest puste', 'error'); exit; }*/ $.ajax({ url: "/ajax.php", // куда отправляем type: "post", // метод передачи dataType: "json", // тип передачи данных data: { // что отправляем "action": "edit", "nickname": nickname }, // после получения ответа сервера success: function(data){ //alert('yes'); if(data.result == "success"){ showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Profil został zmieniony", 'success'); //window.scrollTo({top: 0, behavior: 'smooth'}); exit; }else{ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Pseudonim jest zajęty", 'error'); exit; } } }); }); $('#log').click(function(){ //$('#err').text(''); //alert('ok'); var email = $('#email').val(); var pass = $('#pass').val(); if(email == ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Wpisz e-mail", 'error'); exit; } if(pass == ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Błąd logowania", 'error'); exit; } $.ajax({ url: "/ajax.php", // куда отправляем type: "post", // метод передачи dataType: "json", // тип передачи данных data: { // что отправляем "action": "login", "email": email, "pass": pass }, // после получения ответа сервера success: function(data){ if(data.result == "error"){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Błąd logowania", 'error'); exit; }else{ document.location.href = "/pl/private/"; exit; } } }); }); $('#reg').click(function(){ var email = $('#email').val(); var pass = $('#pass').val(); var pass2 = $('#pass2').val(); if(email == ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Wpisz e-mail", 'error'); exit; } if(!email.includes('@') || !email.includes('.')){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Nieprawidłowy format e-maila", 'error'); exit; } if(pass != pass2 || pass == ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Hasło nie pasuje lub jest puste", 'error'); exit; } $.ajax({ url: "/ajax.php", // куда отправляем type: "post", // метод передачи dataType: "json", // тип передачи данных data: { // что отправляем "action": "registration", "email": email, "pass": pass }, // после получения ответа сервера success: function(data){ //alert('yes'); if(data.result == "success"){ $('#main_fr').html("<div class=\"success\">Rejestracja zakończona sukcesem! Potwierdź swój adres e-mail, jeśli wiadomość nie dotarła, sprawdź folder SPAM. <a href='/private/' class='const_link'>Zaloguj się</a></div>"); showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Rejestracja zakończona sukcesem", 'success'); window.scrollTo({top: 0, behavior: 'smooth'}); exit; }else{ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Użytkownik już istnieje", 'error'); exit; } } }); }); $('#sendmessage').click(function(){ var email = $('#email').val(); var message = $('#message').val(); var token = $('#form_token').val(); if(email === ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Wpisz e-mail", 'error'); return; // <-- было 'exit' } if(!email.includes('@') || !email.includes('.')){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Nieprawidłowy format e-maila", 'error'); return; } if(message === ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Wpisz treść wiadomości", 'error'); return; } $.ajax({ url: "/ajax.php", type: "POST", dataType: "json", data: { action:'sendmessage', email: email, message: message, form_token: token }, success: function(data){ if(data.status === "success"){ $('#email').val(''); $('#message').val(''); //$('#main_fr').html("<div class=\"success\">Dziękujemy za kontakt.</div>"); showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Wiadomość wysłana", 'success'); //window.scrollTo({top: 0, behavior: 'smooth'}); } else { // покажем сообщение сервера, если есть showNotification(data.message || "Trwają prace techniczne", 'error'); } }, error: function(){ showNotification("Trwają prace techniczne", 'error'); } }); }); }); function Work(){ showNotification("<img src=\"https://winupgo.com/images/msg-warning.svg\" width=\"30\" height=\"30\" alt=\"Warning\">Trwają prace techniczne", 'warning'); } </script> <style> /* Контейнер чекбокса */ .chk-wrap { margin: 0 0 16px; } /* увеличенный отступ снизу */ .chk { display:block; /* кликабельна вся строка */ padding:10px 12px; /* комфортная хит-зона */ border-radius:10px; cursor:pointer; user-select:none; transition: background .18s ease, box-shadow .18s ease; } .chk:hover { background: rgba(255,255,255,.06); } .chk:active { background: rgba(255,255,255,.10); } /* Внутренности */ .chk-inner { display:flex; align-items:center; gap:10px; } .chk-input { position:absolute; opacity:0; width:1px; height:1px; pointer-events:none; } .chk-box { position:relative; width:18px; height:18px; border:1.6px solid rgba(255,255,255,.85); border-radius:5px; background:transparent; transition: border-color .18s ease, background-color .18s ease; flex:0 0 auto; } .chk-box::after { content:""; position:absolute; left:5px; top:2.5px; width:6px; height:10px; border-right:2.5px solid transparent; border-bottom:2.5px solid transparent; transform: rotate(45deg); transition: border-color .14s ease; } /* Checked */ .chk-input:checked + .chk-box { background:#fff; border-color:#fff; } .chk-input:checked + .chk-box::after { border-right-color:#0b0f1a; border-bottom-color:#0b0f1a; } /* Фокус с клавиатуры на весь блок */ .chk-input:focus-visible ~ .chk-label, .chk-input:focus-visible + .chk-box { box-shadow: 0 0 0 3px rgba(255,255,255,.18); outline: 2px solid #ffffff; outline-offset: 2px; } .chk-label { color:#eaeff7; font:600 14px/1.2 Segoe UI, system-ui; opacity:.95; } </style> <!-- Разметка --> <div id="searchModal" class="search-modal"> <div class="search-modal-content"> <span class="search-close-button">×</span> <span class="h1">Szukaj gier</span> <!-- Поле ввода --> <div style="margin:8px 0 6px;"> <input type="text" id="searchInput" class="search-input" placeholder="Wpisz nazwę gry" style="width:100%; display:block;"> </div> <!-- Чекбокс под полем (вся строка кликабельна) --> <div class="chk-wrap"> <label class="chk" for="onlyDemo"> <span class="chk-inner"> <input type="checkbox" id="onlyDemo" class="chk-input" /> <span class="chk-box" aria-hidden="true"></span> <span class="chk-label">Tylko demo</span> </span> </label> </div> <div id="searchResults" class="search-results"> <div style="padding:24px 12px; text-align:center; color:#c7cfe0; font:600 14px/1.4 Segoe UI,system-ui;"> Wprowadź co najmniej 3 znaki, aby rozpocząć wyszukiwanie. </div> </div> </div> </div> <script> // helpers function openSearchModal() { const m = document.getElementById("searchModal"); m.style.display = "flex"; document.getElementById("searchInput").focus(); document.body.style.overflow = 'hidden'; } function resetSearchForm() { const input = document.getElementById("searchInput"); const cb = document.getElementById("onlyDemo"); const res = document.getElementById("searchResults"); input.value = ""; cb.checked = false; res.innerHTML = ""; } function closeSearchModal() { document.getElementById("searchModal").style.display = "none"; document.body.style.overflow = ''; resetSearchForm(); } // Открытие модального окна document.getElementById("searchButton").onclick = openSearchModal; // Закрытие модального окна (крестик) document.querySelector(".search-close-button").onclick = closeSearchModal; // Закрытие при клике вне модального окна window.addEventListener("click", function(event) { const searchModal = document.getElementById("searchModal"); if (event.target === searchModal) closeSearchModal(); }); // Закрытие по ESC window.addEventListener("keydown", function(e){ if (e.key === "Escape") { const searchModal = document.getElementById("searchModal"); if (searchModal.style.display === "flex") closeSearchModal(); } }); // Хелпер: выполнение запроса function doSearch(query, page) { const demo = document.getElementById('onlyDemo').checked ? 1 : 0; const url = "/search.php?lang=/pl" + (page ? "&page=" + encodeURIComponent(page) : "") + "&query=" + encodeURIComponent(query) + "&demo=" + demo; const xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { document.getElementById("searchResults").innerHTML = xhr.responseText; } }; xhr.send(); } // Отправка запроса при вводе текста document.getElementById("searchInput").addEventListener("input", function() { const query = this.value.trim(); if (query.length > 2) { doSearch(query, 1); } else { document.getElementById("searchResults").innerHTML = "<div style=\"padding:24px 12px; text-align:center; color:#c7cfe0; font:600 14px/1.4 Segoe UI,system-ui;\">Wprowadź co najmniej 3 znaki, aby rozpocząć wyszukiwanie.</div>"; } }); // Триггерить поиск и по клику на чекбокс (если текста уже >=3) document.getElementById('onlyDemo').addEventListener('change', function() { const query = document.getElementById('searchInput').value.trim(); if (query.length > 2) doSearch(query, 1); }); // Пагинация function paginSearch(page){ const query = document.getElementById("searchInput").value.trim(); doSearch(query, page); if (window.$) { $('#searchResults').animate({ scrollTop: 0 }, 500); } else { document.getElementById('searchResults').scrollTo({ top: 0, behavior: 'smooth' }); } } </script> <!-- HTML для уведомления --> <div id="notification" class="notification"></div> <!-- Скрипт для управления уведомлением --> <script> function showNotification(message, type) { var notification = document.getElementById('notification'); // Сначала показываем уведомление notification.innerHTML = message; notification.classList.add(type); notification.classList.add('show'); // Убираем уведомление через 3 секунды setTimeout(function() { // Начинаем скрывать уведомление notification.classList.remove('show'); // После завершения анимации скрытия удаляем классы и готовим к следующему показу setTimeout(function() { notification.classList.remove(type); notification.innerHTML = ''; }, 300); // длительность анимации скрытия (равна времени transition) }, 3000); // убрать уведомление через 3 секунды } </script> <script> (function(){ var _fbIO = null; function initFloatingBanner(){ if (window.__fbInitOnce) return; // защита от повторной инициализации window.__fbInitOnce = true; var topBanner = document.getElementById('top-banner'); var floatingBanner = document.getElementById('floating-banner'); var closeBtn = document.getElementById('close-floating-banner'); var HIDE_KEY = 'floatingBannerHiddenUntil'; // ручное закрытие (кнопка) var HIDE_DURATION = 300 * 1000; // 300 сек var HIDE_TMP_KEY = 'floatingBannerHiddenTempUntil'; // закрытие вне/ESC/диммер var HIDE_TMP_MS = 30 * 1000; // 30 сек var TRANS_MS = 300; // длительность CSS-перехода var SHOW_DELAY_MS = 4 * 1000; // задержка показа 4 сек if (!floatingBanner) return; // === Диммер страницы === var dim = document.getElementById('floating-dim'); if (!dim) { dim = document.createElement('div'); dim.id = 'floating-dim'; dim.setAttribute('style', 'position:fixed;inset:0;'+ 'background:rgba(0,0,0,.45);opacity:0;'+ 'pointer-events:none;transition:opacity .15s ease;'+ 'z-index:1000;' ); document.body.appendChild(dim); } if (!floatingBanner.style.zIndex) floatingBanner.style.zIndex = '1001'; function showDim(){ dim.style.opacity = '1'; dim.style.pointerEvents = 'auto'; } function hideDim(){ dim.style.opacity = '0'; dim.style.pointerEvents = 'none'; } // Клик по диммеру = закрытие на HIDE_TMP_MS dim.addEventListener('click', function(){ setHideFor(HIDE_TMP_MS); wantHide(); }); function setHideFor(ms){ // universal setter: скрыть до now+ms var until = Date.now() + Math.max(0, ms|0); if (ms >= HIDE_DURATION) { localStorage.setItem(HIDE_KEY, String(until)); } else { localStorage.setItem(HIDE_TMP_KEY, String(until)); } } function canShowBanner() { var hiddenUntil = parseInt(localStorage.getItem(HIDE_KEY) || '0', 10); var hiddenTempUntil = parseInt(localStorage.getItem(HIDE_TMP_KEY) || '0', 10); var until = Math.max(hiddenUntil, hiddenTempUntil); return Date.now() > until; } function isVisible(){ return floatingBanner.classList.contains('is-visible') && getComputedStyle(floatingBanner).display !== 'none' && !floatingBanner.hasAttribute('aria-hidden'); } var busy = false; var debounceTimer = null; var showTimer = null; function clearShowTimer(){ if (showTimer) { clearTimeout(showTimer); showTimer = null; } } function setVisible(next) { if (busy) return; var current = isVisible(); if (next === current) return; busy = true; if (next) { // SHOW floatingBanner.style.display = 'block'; floatingBanner.style.pointerEvents = ''; floatingBanner.removeAttribute('aria-hidden'); floatingBanner.removeAttribute('inert'); void floatingBanner.offsetWidth; // форс-рефлоу floatingBanner.classList.add('is-visible'); showDim(); var onEndShow = function(){ floatingBanner.removeEventListener('transitionend', onEndShow); busy = false; }; floatingBanner.addEventListener('transitionend', onEndShow, { once:true }); setTimeout(function(){ floatingBanner.removeEventListener('transitionend', onEndShow); busy = false; }, TRANS_MS + 50); } else { // HIDE floatingBanner.classList.remove('is-visible'); floatingBanner.style.pointerEvents = 'none'; floatingBanner.setAttribute('aria-hidden','true'); floatingBanner.setAttribute('inert',''); var onEndHide = function(){ floatingBanner.removeEventListener('transitionend', onEndHide); floatingBanner.style.display = 'none'; hideDim(); busy = false; }; floatingBanner.addEventListener('transitionend', onEndHide, { once:true }); setTimeout(function(){ floatingBanner.removeEventListener('transitionend', onEndHide); floatingBanner.style.display = 'none'; hideDim(); busy = false; }, TRANS_MS + 80); } } function eligibleNow(){ // можно показывать и верхний баннер вне экрана if (!canShowBanner()) return false; if (!topBanner) return true; var rect = topBanner.getBoundingClientRect(); return rect.bottom <= 0; } function wantShow() { // планируем показ с задержкой clearTimeout(debounceTimer); clearShowTimer(); if (!canShowBanner()) return; showTimer = setTimeout(function(){ showTimer = null; if (eligibleNow()) setVisible(true); }, SHOW_DELAY_MS); } function wantHide() { clearTimeout(debounceTimer); clearShowTimer(); debounceTimer = setTimeout(function(){ setVisible(false); }, 120); } // Кнопка закрытия — скрываем на 300 сек if (closeBtn) { closeBtn.onclick = function (e) { e.preventDefault(); e.stopPropagation(); setHideFor(HIDE_DURATION); wantHide(); }; } // Закрытие при клике вне баннера и по Esc — на 60 сек (function initOutsideClose(){ if (window.__fbOutsideCloseInit) return; window.__fbOutsideCloseInit = true; function hideTemp(){ setHideFor(HIDE_TMP_MS); wantHide(); } function onDocPointer(e){ if (!isVisible()) return; if (!floatingBanner.contains(e.target)) hideTemp(); } document.addEventListener('mousedown', onDocPointer, true); document.addEventListener('touchstart', onDocPointer, {passive:true, capture:true}); document.addEventListener('keydown', function(e){ if (e.key === 'Escape' && isVisible()) hideTemp(); }); })(); // Если нет верхнего баннера — показываем с задержкой, когда можно if (!topBanner) { if (canShowBanner()) wantShow(); return; } // Обсервер верхнего баннера if (_fbIO) { try { _fbIO.disconnect(); } catch(e){} _fbIO = null; } _fbIO = new IntersectionObserver(function (entries) { var entry = entries[0]; if (entry.isIntersecting) { // верхний виден -> скрыть и отменить отложенный показ wantHide(); } else { // верхний ушёл -> планируем показ с задержкой if (canShowBanner()) wantShow(); } }, { root: null, rootMargin: '0px 0px -10% 0px', threshold: 0 }); _fbIO.observe(topBanner); // Стартовое состояние (учитываем задержку) (function(){ var rect = topBanner.getBoundingClientRect(); if (rect.bottom <= 0) { if (canShowBanner()) wantShow(); } else { setVisible(false); } })(); // Ресайз/поворот window.addEventListener('resize', function(){ clearTimeout(debounceTimer); debounceTimer = setTimeout(function(){ var rect = topBanner.getBoundingClientRect(); if (rect.bottom <= 0) { if (canShowBanner()) wantShow(); } else { wantHide(); } }, 120); }, { passive:true }); } document.addEventListener('DOMContentLoaded', initFloatingBanner); window.addEventListener('pageshow', initFloatingBanner); // BFCache })(); </script> <script> // Функция для учета кликов function trackClick(num) { fetch('/ajax-banner.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'click', num: num }) }).catch(console.error); } // Функция для учета показов function trackView(num) { fetch('/ajax-banner.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'show', num: num }) }).catch(console.error); } // Наблюдатель пересечения для отслеживания показов document.addEventListener("DOMContentLoaded", () => { const options = { root: null, rootMargin: "0px", threshold: 0.5 }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const num = entry.target.getAttribute("data-num"); // Получаем data-num из элемента <a> if (num) { trackView(num); } observer.unobserve(entry.target); // Отменяем наблюдение после первого показа } }); }, options); document.querySelectorAll("a[data-num]").forEach(banner => { // Наблюдатель пересечения для учета показа observer.observe(banner); // Событие click для учета клика banner.addEventListener("click", (event) => { const num = banner.getAttribute("data-num"); if (num) { trackClick(num); } }); }); }); </script> <script> document.querySelectorAll('a, button').forEach(el => { el.addEventListener('click', () => { if (typeof gtag === 'function') { gtag('event', 'click', { event_category: 'interaction', event_label: el.dataset.role || el.dataset.href || 'unknown', value: 1 }); } }); }); </script> <script> window.addEventListener('load', function() { const body = document.body; const bg = body.getAttribute('data-bg'); // Загружать фон ТОЛЬКО если экран меньше 1024px if (window.innerWidth < 1024 && bg) { body.style.backgroundImage = `url("${bg}")`; body.style.backgroundRepeat = 'no-repeat'; body.style.backgroundPosition = 'top center'; body.style.backgroundAttachment = 'scroll'; // лучше для мобильных } }); </script> </body> </html>