WinUpGo
Іздеу
CASWINO
SKYSLOTS
BRAMA
TETHERPAY
777 FREE SPINS + 300%
Cryptocurrency казино Крипто казино Torrent Gear - сіздің әмбебап торрент іздеу! Torrent Gear

Казино платформаларында көптілділік қалай іске асырылады

Не үшін казино көптілділік

Ойыншылар интерфейсті түсінетін, бағаны өз валютасынан көретін және жергілікті релеванттықты (спорт, мерекелер, төлем әдістері, заңды мәтіндер) сезінетін жерде депозиттер мен мөлшерлемелер жасайды. Дұрыс көптілділік CR тіркеу → депозитті арттырады, АКҚ/кассаның үйкелісін азайтады және ұстап қалуды жақсартады.


Негізгі терминология

i18n (Internationalization) - өнімді оқшаулауға дайындау: кілттер, плейсхолдерлер, күндерді/сандарды/валюталарды пішімдеу, RTL және клингтерді қолдау.

L10n (Localization) - аудармалардың өзі және жергілікті бейімделулер: мәтіндер, бейнелер, промо, заңды блоктар, RG (жауапты ойын).

Жергілікті - тіл + өңір (мысалы, 'pt-BR', 'fr-CA'), форматтарға, валютаға, заңнамалық баннерлерге және контентке әсер етеді.


i18n архитектурасы: нөлден қалай салу керек

1. «Қатты» жолдардың орнына кілттер.

('cashier. deposit. title ').

Жолдар - кодта емес, аударма файлдарында/кестелерінде.

2. ICU MessageFormat.

Плюралдар, түрі, септігі, валюта форматы/күні/пайызы:

{count, plural, one {# ставка} few {# ставка} many {# ставка} other {# ставка}}

3. Форматтар мен валюталар.

ISO-кодтар, жергілікті бөлгіштер, дат 'yyyy-MM-dd' форматы, БД-да локаль бойынша рендер.

Сервердегі бағамдарды конверсиялау, валюта ережелері бойынша көрсету (символ/бос орын/позиция).

4. Таймзондтар.

ДБ-ДА - UTC. Фронтта/хаттарда - ойыншының жергілікті TZ (профильде сақтаумен).

5. RTL/екі бағыттылық.

Қолдау 'dir = «rtl»' үшін 'ar', 'fa', 'he'; айналы иконалар, элементтер тәртібі, «хаксыз» каскадты стильдер.

6. Аударма домендерін бөлу.

`core` (навигация), `cashier`, `kyc`, `rg`, `promotions`, `games`, `email/push`, `seo`. Бөлікті барлығын қозғамай жаңартуға мүмкіндік береді.


Казино нені оқшаулайды

Лобби/ойын каталогы: атаулары, санаттары, баннерлері, іздеу тегтері, сипаттамалары.

Ойын және провайдерлер: атауы/толық ойын, paytable/ережелер, ескертулер. Егер провайдер қажетті тілді бермесе, fallback пен ескертуді дайындаңыз.

Касса: әдістердің атаулары (жергілікті APM), мәртебелер, PSP қателері, 3-D Secure, on/off-ramp крипта заңды мәтіндері.

KYC/AML/RG: құжаттар бойынша нұсқаулықтар, тайм-ауттар/лимиттер мәтіндері, өздігінен алып тастау, жас және жауапты баннерлер.

Заңды беттер: ToS, құпиялылық саясаты, лицензия, елдер бойынша тыйымдар, cookie-баннерлер.

Маркетинг: лендингтер, промо/миссиялар/турнирлер, мылтықтар, e-mail, CDN баннерлері.

SEO-мета: '', <meta description> ',' hreflang ', шағын белгілер.</p> <hr> <p>Аударма ағыны (L10n Workflow)</p> <p>1. Репозиторийден кілттерді алу (линтер + «қатты» жолдарға CI-тексерулер).</p> <p>2. CAT-жүйе/TS-платформа (Phrase/Smartling/Lokalise және т.б.): терминдер сөздігі, аудармалар жады, контекст-скриншоттар.</p> <p>3. Рөлдер: аудармашы → редактор → заңды тексеру (RG/ToS/касса үшін).</p> <p>4. Локальдардың QA: UI регрестері (скриншоттар), плюралдар мен ICU автотестері, жолдар/кесулердің ұзындығын тексеру.</p> <p>5. Нұсқалау: 'lang pack' артефакт ретінде, бұрынғы келісімшартпен сыйысымдылық; канареялық rollout жергілікті аудиторияның 5-10 пайызына.</p> <p>6. Жеткізу: CDN-манифесттер + tag-purge (бекендті шығармай жылдам жариялау).</p> <hr> <h2>Жергілікті жерлердің стратегиясы</h2> <p>Ең аз жиынтық: EN + негізгі нарықтар (мысалы, '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>Тілдің нұсқалары: 'es-ES' ≠ 'es-MX' (касса терминдері, спорт, заңды тұжырымдар).</p> <p>Fallback-орман: 'fr-CA → fr → en'. Ойыншы әрқашан дұрыс мәтінді көреді.</p> <p>Гео бойынша атрибуция және ойыншыны таңдау: IP/браузер бойынша локальдің авто-ұсынысы + хедердегі және профилдегі анық қосқыш.</p> <hr> <h2>Комплаенс және заңдық талаптар</h2> <p>Жас/жауапты баннерлер юрисдикцияға сәйкес келеді: тұжырымдар, байланыс ұйымдары, сілтемелер.</p> <p>KYC/AML/KYT: нақты терминдер, түсінікті нұсқаулар (құжат пішімі, аудармашыны алмастырмайды!).</p> <p>Акцияның терминдері: әр локальдағы жарнаманың заңды шарттары (машиналық аударма емес!).</p> <p>Geo-fencing мәтіндері: тыйым салынған елдерде - ағылшын тілінде 404 емес, тиісті хабарламалар/блоктар.</p> <hr> <h2>Жиі «бұзылатын» UX-бөлшектер</h2> <p>Плюралдар мен сан белгілері (славян тілдерінің 3-4 нысаны бар).</p> <p>Ұзын сөздер/аудармалар (неміс/фин) - икемді тор, 'hyphens: auto'.</p> <p>RTL және иконалар - бағыттамаларды/шеврондарды көрсету, сомаларды теңестіру.</p> <p>Ақша форматтары: бос орындар/бөлгіштер, символ позициясы, дөңгелектеу, мың үшін «жіңішке бос орындар».</p> <p>Кассалық қателер - PSP-нің «қатты» ағылшын тіліндегі мәтініне тыйым салу; маппинг кодтары → жергілікті хабарлар.</p> <hr> <h2>SEO және өнімділігі</h2> <p>URL құрылымы: субдомендер емес ('/de/', '/fr/') кіші каталогтары (cookies/локальді басқару оңай).</p> <p>'hreflang' және жергілікті жерлер арасындағы каноникал; жергілікті sitemap.</p> <p>CDN-кэш JSON жергілікті лобби 'stale-while-revalidate'.</p> <p>Бейнелер/баннерлер - жергілікті жазбалар/валюталар; (WebP/AVIF) пішімін автоматты түрде түрлендіру.</p> <p>Аударма бандалары - динамикалық импорт, барлық тілдерді бірден тартпау керек.</p> <hr> <h2>Ойын провайдерлері және оқшаулау</h2> <p>Әрбір провайдер/ойын бойынша қолдау көрсетілетін тілдер матрицасы; лобби тіліне fallback немесе «дисклейтері бар ағылшын тілі».</p> <p>Paytable/Help: егер мәтін жабық болса - жергілікті жеке overlay-гид.</p> <p>Провайдерден болған оқиғалар мен қателер - қалыпқа келтіру және жергілікті маппа.</p> <hr> <h2>Телеметрия және A/B</h2> <p>Жергілікті бойынша өлшемдер: CR 'register → KYC → deposit', 'deposit → bet', NPS, churn, KYC жылдамдығы, кассаның істен шығуы.</p> <p>Формулировка тестілері: кассаның/промо жергілікті мәтіндері жиі конверсияға + X% береді.</p> <p>«Сынған» аудармалар жобасы: «Көмек» кликтерінің өсуі, КБК/кассада әдеттегідей ұзын dwell-times.</p> <hr> <h2>Қарсы үлгілер</h2> <p>Кодтағы қатқыл жолдар және тіл/логика араласуы.</p> <p>Дұрыс нысандардың орнына ICU → «2 ставка »/» 5 ставка» болмауы.</p> <p>Заңды мәтіндерді/кассаны/төлемдерді машинамен аудару.</p> <p>Барлық елдер үшін бір тіл (мысалы, LATAM-да 'es-ES') - мәдени және терминологиялық қателер.</p> <p>Жергілікті шарттары жоқ жаһандық промо-баннерлер → реттеушінің/ойыншылардың талаптары.</p> <p>Жоқ fallback → бос жолдар/ағылшын «балық» мәтіні.</p> <p>Әрбір бетте барлық тілдердің бандлі → артық салмақ және баяу TTFB.</p> <hr> <h2>Казино көп тілділігін тексеру</h2><p>Сәулет және деректер</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, ICU-форматтары, DB-дегі UTC, фронттағы/хаттардағы TZ.</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>Валюталар/пішімдер/бөлгіштер - «қолмен» емес, жергілікті ережелерден.</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-қолдау, иконаларды айналау, авто тасымалдау.</li> </ul> <h2>Мазмұн және workflow</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 платформасы, терминдер глоссарийі, контексттік скриншоттарға қолжетімділік.</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>Рөлдер: аударма → редакция → заңды ревю.</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>Канареялық жарияланым 'lang pack', CDN-жеткізу және tag-purge.</li> </ul> <h2>Домендер</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>Лобби/ойындар/касса/KYC/RG/заңды/маркетинг/SEO - жабылған және бөлінген.</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/провайдерлердің қателерін жіберу.</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>Ойын провайдерлері бойынша тілдер матрицасы (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', жергілікті sitemap.</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>Динамикалық аударым импорты, JSON лобби кэші.</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>Жергілікті жерде CDN суреттерді/бейнелерді оңтайландыру.</li> </ul> <h2>Комплаенс</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>Заңды және RG-мәтіндер жергілікті түрде тексерілді.</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-fencing және тыйым салу/жас мәтіндері.</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/consent.</li> </ul> <h2>Бақылау мүмкіндігі</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/істен шығу/жасырындылық өлшемдері.</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>«Сынған» кілттерге және бос жолдарға алерттар.</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 (касса/АКҚ/промо).</li> </ul> <hr> <p>iGaming-тегі көптілділік - «екі жолды аудару» емес. Бұл жүйелік тәртіп: i18n-сәулет, ICU-форматтар, қатаң workflow аудармалар, комплаенс, CDN-жеткізу және бақылау. Оны платформаның бір бөлігіне айналдырсаңыз, конверсияны көбейтесіз, кассадағы үйкелісті азайтасыз және заңды талаптарды «қолмен» өртсіз өтесіз - контент пен нарықты болжамды және тез кеңейтесіз.</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> қазақ </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="/kz/feedback-form/"><img width="30" height="30" alt="Кері байланыс пішіні" 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\">Құпия сөз сәйкес келмейді немесе бос", '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\">Құпия сөз сәтті өзгертілді! <a href='/private/' class='const_link'>Кіруге</a></div>"); showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Құпия сөз өзгертілді", '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\">Жүйелік қате орын алды, қолдауға хабарласыңыз.", '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\">Электрондық поштаны енгізіңіз", 'error'); exit; } if(!email.includes('@') || !email.includes('.')){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Жарамсыз электрондық пошта пішімі", '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\">Құпия сөзді қалпына келтіру нұсқаулығы электрондық поштаға жіберілді, егер хат сізге жеткізілмесе, SPAM қалтасын тексеріңіз.</div>"); showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Нұсқау жіберілді", '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\">Жүйелік қате орын алды, қолдауға хабарласыңыз.", '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\">Бүркеншік атты енгізіңіз", 'error'); exit; } /*if(pass != pass2 || pass == ""){ showNotification('Құпия сөз сәйкес келмейді немесе бос', '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\">Профиль өзгертілді", '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\">Бүркеншік аты бос емес", '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\">Электрондық поштаны енгізіңіз", 'error'); exit; } if(pass == ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Авторландыру қатесі", '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\">Авторландыру қатесі", 'error'); exit; }else{ document.location.href = "/kz/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\">Электрондық поштаны енгізіңіз", 'error'); exit; } if(!email.includes('@') || !email.includes('.')){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Жарамсыз электрондық пошта пішімі", 'error'); exit; } if(pass != pass2 || pass == ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Құпия сөз сәйкес келмейді немесе бос", '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\">Тіркеу сәтті өтті! Электрондық пошта мекенжайын растаңыз, егер хат жеткізілмесе, SPAM қалтасын тексеріңіз. <a href='/private/' class='const_link'>Кіруге</a></div>"); showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Табысты тіркеу", '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\">Пайдаланушы тіркеліп қойған", '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\">Электрондық поштаны енгізіңіз", 'error'); return; // <-- было 'exit' } if(!email.includes('@') || !email.includes('.')){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Жарамсыз электрондық пошта пішімі", 'error'); return; } if(message === ""){ showNotification("<img src=\"https://winupgo.com/images/msg-error.svg\" width=\"30\" height=\"30\" alt=\"Error\">Хабарлама мәтінін енгізіңіз", '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\">Қол жеткізгеніңіз үшін рахмет.</div>"); showNotification("<img src=\"https://winupgo.com/images/msg-success.svg\" width=\"30\" height=\"30\" alt=\"Success\">Хабарлама жіберілді", 'success'); //window.scrollTo({top: 0, behavior: 'smooth'}); } else { // покажем сообщение сервера, если есть showNotification(data.message || "Техникалық жұмыстар жүргізілуде", 'error'); } }, error: function(){ showNotification("Техникалық жұмыстар жүргізілуде", 'error'); } }); }); }); function Work(){ showNotification("<img src=\"https://winupgo.com/images/msg-warning.svg\" width=\"30\" height=\"30\" alt=\"Warning\">Техникалық жұмыстар жүргізілуде", '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">Ойын бойынша іздеу</span> <!-- Поле ввода --> <div style="margin:8px 0 6px;"> <input type="text" id="searchInput" class="search-input" placeholder="Ойын атын енгізіңіз" 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">Тек демо</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;"> Іздеуді бастау үшін кемінде 3 таңба енгізіңіз. </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=/kz" + (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;\">Іздеуді бастау үшін кемінде 3 таңба енгізіңіз.</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>