WinUpGo
Aramak
CASWINO
SKYSLOTS
BRAMA
TETHERPAY
777 FREE SPINS + 300%
Cryptocurrency casino Crypto Casino Torrent Gear, çok amaçlı torrent aramanızdır! Torrent Dişli

Çok dillilik casino platformlarında nasıl uygulanır

Neden casino çok dillilik

Oyuncular arayüzü anladıkları, para biriminde fiyatları gördükleri ve yerel alaka düzeyini (spor, tatil, ödeme yöntemleri, yasal metinler) hissettikleri bahisleri yatırır ve yerleştirir. Doğru çokdillilik registratsii ​ ​ depozit CR artırır, CCG/kutu sürtünme azaltır ve tutma artırır.


Temel terminoloji

I18n (Internationalization) - ürünü yerelleştirme için hazırlama: anahtarlar, yer tutucular, biçimlendirme tarihleri/sayılar/para birimleri, RTL ve tutunmalar için destek.

L10n (Yerelleştirme) - gerçek çeviriler ve yerel uyarlamalar: metinler, resimler, tanıtım, yasal bloklar, RG (sorumlu oyun).

Yerel - dil + bölge (örn. 'pt-BR', 'fr-CA'), formatları, para birimini, yasal afişleri ve içeriği etkiler.


i18n mimarisi: sıfırdan nasıl döşenir

1. "Sert" dizeler yerine tuşlar.

Anlamdaki anahtar isimler ('kasiyer. depozito. title ') ekran karşısında değil.

Satırlar - çeviri dosyalarında/tablolarda, kodda değil.

2. ICU MessageFormat.

Çoğullar, cinsiyet, vakalar, para birimi/tarih/yüzde biçimi:

{count, çoğul, one {# bet} few {# bets} many {# bets} other {# bets}}

3. Formatlar ve para birimleri.

ISO kodları, yerel sınırlayıcılar, veritabanında 'yyyy-MM-dd' tarih biçimi, ön tarafta yerel ayar oluşturma.

Sunucudaki döviz kurlarının dönüştürülmesi, para birimi kurallarına göre görüntülenmesi (karakter/boşluk/konum).

4. Zaman dilimleri.

VERITABANINDA - UTC. Önde/harflerle - oyuncunun yerel TZ'si (profilde kaydedilir).

5. RTL/çift yönlülük.

Destek'dir = 'rtl''ar ',' fa ','o' için; Ayna simgeleri, eleman düzeni, hack'siz basamaklı stiller.

6. Çeviri alanlarının ayrılması.

'çekirdek' (навигация), 'kasiyer', 'kyc','rg ',' promosyonlar ',' oyunlar ','e-posta/push', 'seo'. Her şeyi etkilemeden bir parçayı güncellemenizi sağlar.


Kumarhanede tam olarak lokalize olan nedir

Lobi/oyun kataloğu: isimler, kategoriler, afişler, arama etiketleri, açıklamalar.

Oyun ve sağlayıcılar: isim/oyunlar, ödeme tablosu/kurallar, uyarılar. Sağlayıcı gerekli dili sağlamazsa, bir geri dönüş ve bir uyarı hazırlayın.

Kasiyer: yöntem adları (yerel APM), durumlar, PSP hataları, yasal metinler 3-D Güvenli, açık/kapalı rampa kriptoları.

KYC/AML/RG: belge talimatları, zaman aşımı/sınırlama metinleri, kendini dışlama, yaş ve sorumlu afişler.

Yasal sayfalar: ToS, gizlilik politikası, lisans, ülke yasakları, çerez afişleri.

Pazarlama: açılış sayfaları, promosyon/görevler/turnuvalar, kabartmalar, e-posta, CDN'deki afişler.

SEO meta: '', '<meta description>', 'hreflang', mikro işaretleme.</p> <hr> <p>L10n İş Akışı</p> <p>1. Depodan anahtarların çıkarılması (linter + CI "sabit" dizeleri kontrol eder).</p> <p>2. CAT sistemi/TS platformu (Cümle/Smartling/Lokalise, vb.): Terimler sözlüğü, çeviri belleği, bağlam ekran görüntüleri.</p> <p>3. Rolleri: çevirmen - editör - yasal inceleme (RG/ToS/nakit masası için).</p> <p>4. Yerellerin KG'si: UI regresyonları (ekran görüntüleri), çoğullar ve YBÜ için ototestler, çizgilerin/kesilmelerin uzunluğunu kontrol etme.</p> <p>5. Sürüm oluşturma: Eser olarak 'lang paketi', geçmiş sözleşmeyle uyumluluk; 5-10 yerel izleyici kitlesinde kanarya sunumu yüzde.</p> <p>6. Teslimat: CDN, + tag-purge (arka uç yayınlanmadan hızlı yayın) gösterir.</p> <hr> <h2>Yerel strateji</h2> <p><b>Minimum set:</b> EN + anahtar pazarlar (örn. '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>Dil seçenekleri:'es-ES '≠'es-MX' (gişe terimleri, spor, yasal formülasyonlar).</p> <p>Fallback merdiveni: 'fr-CA ^ fr ^ en'. Oyuncu her zaman geçerli metni görür.</p> <p>Coğrafi atıf ve oyuncu seçimi: IP/tarayıcı ile yerel otomatik önerme + üstbilgi ve profilde açık anahtar.</p> <hr> <h2>Uyumluluk ve yasal gereklilikler</h2> <p>Yaş/sorumlu afişler yargı yetkisine karşılık gelir: ifadeler, iletişim kuruluşları, bağlantılar.</p> <p>KYC/AML/KYT: kesin terimler, açık talimatlar (belgelerin biçimi, çevirmen yerini almaz!).</p> <p>Promosyon terimleri: Her yerelde yasal terimler promosyonu (makine çevirisi değil!).</p> <p>Metinlerin coğrafi eskrimi: yasak ülkelerde - karşılık gelen bildirimler/bloklar ve İngilizce değil 404.</p> <hr> <h2>En sık "kırılan" UX parçaları</h2> <p>Çoğullar ve rakamlar (Slav dilleri 3-4 forma sahiptir).</p> <p>Uzun kelimeler/tireleme (Almanca/Fince) - esnek ızgara, 'tireler: otomatik'.</p> <p>RTL ve simgeler - ayna okları/chevronlar, miktarları hizalayın.</p> <p>Para biçimleri: boşluklar/ayırıcılar, karakter konumu, yuvarlama, binlerce'ince boşluk ".</p> <p>Gişe hataları - PSP'den "sert" İngilizce metnin yasaklanması; Kod eşleme - yerel mesajlar</p> <hr> <h2>SEO ve performans</h2> <p>URL yapısı: alt dizinler ('/de/','/fr/'), alt alanlar değil (çerezleri/yerel ayarları yönetmek daha kolay).</p> <p>'hreflang've yerel arasında kanonik; Yerel site haritası.</p> <p>'Bayat-while-revalidate'ile yerel ayarlarla JSON lobisinin CDN önbelleği.</p> <p>Görüntüler/afişler - yerel yazıtlar/para birimleri; Otomatik biçim dönüştürme (WebP/AVIF).</p> <p>Çeviri paketleri - yerel ayarlara göre dinamik içe aktarma, tüm dilleri aynı anda sürüklemeyin.</p> <hr> <h2>Oyun sağlayıcıları ve yerelleştirme</h2> <p>Her sağlayıcı/oyun için desteklenen dillerin matrisi; Lobi diline veya "feragatnameli İngilizce'ye geri dönün.</p> <p>Ödeme Tablosu/Yardım: metin kapalıysa, yerel ayarınızın ayrı bir kaplama kılavuzu.</p> <p>Sağlayıcıdan olaylar ve hatalar - normalleştirme ve yerel mappa.</p> <hr> <h2>Telemetri ve A/B</h2> <p>Yerel metrikler: CR 'register> KYC> deposit', 'deposit - bet', NPS, churn, KYC speed, gişe başarısızlığı.</p> <p>Kelime testleri: Yerel nakit masası/promosyon metinleri genellikle dönüşüme + % X verir.</p> <p>"Kırık" çevirilerin tespiti: "Yardım'daki tıklamaların büyümesi, yazar kasada atipik olarak uzun süre kalma süreleri.</p> <hr> <h2>Anti-desenler</h2> <p>Koddaki sabit çizgiler ve karıştırma dili/mantığı.</p> <p>Yoğun bakım eksikliği: Doğru formlar yerine "2 bahis "/" 5 bahis ".</p> <p>Yasal metinlerin/nakit masaların/ödemelerin makine çevirisi.</p> <p>Tüm ülkeler için bir dil (örneğin, LATAM'daki'es-ES ') - kültürel ve terminolojik hatalar.</p> <p>Yerel koşullar olmadan küresel promosyon afişleri - düzenleyicinin/oyuncuların iddiaları.</p> <p>Geri dönüş yok - boş satırlar/İngilizce "balık" metni.</p> <p>Her sayfadaki tüm dillerin paketi - aşırı kilolu ve yavaş TTFB.</p> <hr> <h2>Casino Çok Dilli Kontrol Listesi</h2><p>Mimari ve veri</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>i18n tuşları, ICU formatları, veritabanında UTC, önde TZ/harflerle.</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>Para birimleri/formatlar/sınırlayıcılar "manuel" kurallar değil, yerel ayarlardandır.</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>RTL desteği, simge yansıtma, otomatik tireleme.</li> </ul> <h2>İçerik ve iş akışı</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>CAT platformu, terimler sözlüğü, bağlam ekran görüntülerine erişim.</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>Roller: perevod ^ redaktura ^ yuridichesky incelemesi.</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>Kanarya yayın 'lang paketi', CDN teslimat ve etiket temizleme.</li> </ul> <h2>Etki alanları</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>Lobi/oyunlar/gişe/KYC/RG/yasal/pazarlama/SEO - kapalı ve ayrılmış.</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>PSP/ISS hatalarını yerel iletilerle eşleme.</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>Oyun sağlayıcısına göre dil matrisi (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', yerel site haritası.</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>Çevirilerin dinamik içe aktarımı, JSON lobi önbelleği.</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>Yerel ayar için CDN görüntü/video optimizasyonu.</li> </ul> <h2>Uyumluluk</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>Yasal ve RG metinleri yerel olarak kontrol edilir.</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>Geo-eskrim ve yasaklama/yaş metinleri.</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>Kullanıcının dilinde çerez/onay.</li> </ul> <h2>Gözlemlenebilirlik</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>Yerel ayara göre CR/Failure/Latency metrikleri.</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>"Kırık" tuşlara ve boş satırlara uyarılar.</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>Kritik ifadeler üzerine A/B (nakit masası/CCM/promosyon).</li> </ul> <hr> <p>IGaming'de çok dillilik "birkaç satırı çevirmek" değildir. "Bu bir sistem disiplinidir: i18n mimarisi, ICU formatları, katı çeviri iş akışı, uyumluluk, CDN dağıtımı ve gözlemlenebilirlik. Platformun bir parçası haline getirerek, dönüşümü artıracak, kasada sürtünmeyi azaltacak ve "manuel" yangınlar olmadan yasal gereklilikleri yerine getireceksiniz - içeriği ve pazarları tahmin edilebilir ve hızlı bir şekilde ölçeklendirirken.</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> Türkçe </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="/tr/feedback-form/"><img width="30" height="30" alt="Geri bildirim formu" 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\">Parola eşleşmiyor veya boş", '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\">Parola başarılı bir şekilde değişti! <a href='/private/' class='const_link'>Giriş yap</a></div>"); showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Şifre değiştirildi", '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\">Sistem hatası oluştu, lütfen desteğinize başvurun.", '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\">E-postayı girin", 'error'); exit; } if(!email.includes('@') || !email.includes('.')){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Geçersiz e-posta biçimi", '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\">E-posta size teslim edilmemişse, e-posta yoluyla size şifre kurtarma talimatları gönderilmiştir, lütfen SPAM klasörünü kontrol edin.</div>"); showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Talimat gönderildi", '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\">Sistem hatası oluştu, lütfen desteğinize başvurun.", '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\">Takma ad girin", 'error'); exit; } /*if(pass != pass2 || pass == ""){ showNotification('Parola eşleşmiyor veya boş', '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 değişti", '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\">Takma ad meşgul", '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\">E-postayı girin", 'error'); exit; } if(pass == ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Yetkilendirme hatası", '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\">Yetkilendirme hatası", 'error'); exit; }else{ document.location.href = "/tr/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\">E-postayı girin", 'error'); exit; } if(!email.includes('@') || !email.includes('.')){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Geçersiz e-posta biçimi", 'error'); exit; } if(pass != pass2 || pass == ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Parola eşleşmiyor veya boş", '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\">Kayıt başarılı oldu! E-posta size teslim edilmediyse e-posta adresinizi onaylayın, lütfen SPAM klasörünüzü kontrol edin. <a href='/private/' class='const_link'>Giriş yap</a></div>"); showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Başarılı kayıt", '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\">Kullanıcı zaten kayıtlı", '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\">E-postayı girin", 'error'); return; // <-- было 'exit' } if(!email.includes('@') || !email.includes('.')){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Geçersiz e-posta biçimi", 'error'); return; } if(message === ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Mesaj metnini girin", '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\">Ulaştığınız için teşekkür ederiz.</div>"); showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Mesaj gönderildi", 'success'); //window.scrollTo({top: 0, behavior: 'smooth'}); } else { // покажем сообщение сервера, если есть showNotification(data.message || "Teknik çalışmalar sürüyor", 'error'); } }, error: function(){ showNotification("Teknik çalışmalar sürüyor", 'error'); } }); }); }); function Work(){ showNotification("<img src=\"https://winupgo.com/images/msg-warning.svg\" width=\"30\" height=\"30\" alt=\"Warning\">Teknik çalışmalar sürüyor", '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">Oyuna göre ara</span> <!-- Поле ввода --> <div style="margin:8px 0 6px;"> <input type="text" id="searchInput" class="search-input" placeholder="Oyunun adını girin" 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">Sadece demolar</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;"> Aramaya başlamak için en az 3 karakter girin. </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=/tr" + (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;\">Aramaya başlamak için en az 3 karakter girin.</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>