// Country pricing + local currency display function pooliva_language_catalog(): array { // ISO-style language catalog for global auto-language. Labels are English admin labels; UI strings can be AI-translated and cached. return [ 'af'=>'Afrikaans','sq'=>'Albanian','am'=>'Amharic','ar'=>'Arabic','hy'=>'Armenian','az'=>'Azerbaijani','eu'=>'Basque','be'=>'Belarusian','bn'=>'Bengali','bs'=>'Bosnian','bg'=>'Bulgarian','my'=>'Burmese','ca'=>'Catalan','ceb'=>'Cebuano','zh'=>'Chinese','zh-CN'=>'Chinese Simplified','zh-TW'=>'Chinese Traditional','co'=>'Corsican','hr'=>'Croatian','cs'=>'Czech','da'=>'Danish','nl'=>'Dutch','en'=>'English','eo'=>'Esperanto','et'=>'Estonian','fi'=>'Finnish','fr'=>'French','fy'=>'Frisian','gl'=>'Galician','ka'=>'Georgian','de'=>'German','el'=>'Greek','gu'=>'Gujarati','ht'=>'Haitian Creole','ha'=>'Hausa','haw'=>'Hawaiian','he'=>'Hebrew','hi'=>'Hindi','hmn'=>'Hmong','hu'=>'Hungarian','is'=>'Icelandic','ig'=>'Igbo','id'=>'Indonesian','ga'=>'Irish','it'=>'Italian','ja'=>'Japanese','jv'=>'Javanese','kn'=>'Kannada','kk'=>'Kazakh','km'=>'Khmer','rw'=>'Kinyarwanda','ko'=>'Korean','ku'=>'Kurdish','ky'=>'Kyrgyz','lo'=>'Lao','la'=>'Latin','lv'=>'Latvian','lt'=>'Lithuanian','lb'=>'Luxembourgish','mk'=>'Macedonian','mg'=>'Malagasy','ms'=>'Malay','ml'=>'Malayalam','mt'=>'Maltese','mi'=>'Maori','mr'=>'Marathi','mn'=>'Mongolian','ne'=>'Nepali','no'=>'Norwegian','ny'=>'Nyanja','or'=>'Odia','ps'=>'Pashto','fa'=>'Persian','pl'=>'Polish','pt'=>'Portuguese','pa'=>'Punjabi','ro'=>'Romanian','ru'=>'Russian','sm'=>'Samoan','gd'=>'Scots Gaelic','sr'=>'Serbian','st'=>'Sesotho','sn'=>'Shona','sd'=>'Sindhi','si'=>'Sinhala','sk'=>'Slovak','sl'=>'Slovenian','so'=>'Somali','es'=>'Spanish','su'=>'Sundanese','sw'=>'Swahili','sv'=>'Swedish','tl'=>'Tagalog','tg'=>'Tajik','ta'=>'Tamil','tt'=>'Tatar','te'=>'Telugu','th'=>'Thai','tr'=>'Turkish','tk'=>'Turkmen','uk'=>'Ukrainian','ur'=>'Urdu','ug'=>'Uyghur','uz'=>'Uzbek','vi'=>'Vietnamese','cy'=>'Welsh','xh'=>'Xhosa','yi'=>'Yiddish','yo'=>'Yoruba','zu'=>'Zulu' ]; } function pooliva_language_is_rtl(string $lang): bool { $base = strtolower(explode('-', $lang)[0]); return in_array($base, ['ar','fa','he','ur','ps','sd','ug','ku'], true); } function pooliva_country_language_map(): array { // Covers virtually all ISO-3166 countries with a practical default language for auto-language. return [ 'US'=>'en','CA'=>'en','GB'=>'en','AU'=>'en','NZ'=>'en','IE'=>'en','ZA'=>'en','NG'=>'en','KE'=>'sw','TZ'=>'sw','UG'=>'en','GH'=>'en','PH'=>'en','IN'=>'hi','PK'=>'ur','BD'=>'bn','LK'=>'si','NP'=>'ne', 'SA'=>'ar','AE'=>'ar','QA'=>'ar','KW'=>'ar','BH'=>'ar','OM'=>'ar','YE'=>'ar','JO'=>'ar','LB'=>'ar','SY'=>'ar','IQ'=>'ar','EG'=>'ar','SD'=>'ar','LY'=>'ar','TN'=>'ar','DZ'=>'ar','MA'=>'ar','PS'=>'ar', 'BR'=>'pt','PT'=>'pt','AO'=>'pt','MZ'=>'pt','CV'=>'pt','GW'=>'pt','ST'=>'pt','TL'=>'pt', 'ES'=>'es','MX'=>'es','AR'=>'es','CO'=>'es','PE'=>'es','CL'=>'es','VE'=>'es','EC'=>'es','BO'=>'es','PY'=>'es','UY'=>'es','CR'=>'es','PA'=>'es','GT'=>'es','HN'=>'es','SV'=>'es','NI'=>'es','DO'=>'es','CU'=>'es','PR'=>'es', 'FR'=>'fr','BE'=>'fr','CH'=>'de','LU'=>'fr','MC'=>'fr','CI'=>'fr','SN'=>'fr','CM'=>'fr','ML'=>'fr','NE'=>'fr','BF'=>'fr','BJ'=>'fr','TG'=>'fr','GA'=>'fr','CG'=>'fr','CD'=>'fr','RW'=>'rw','BI'=>'fr','DJ'=>'fr','KM'=>'fr','MG'=>'mg', 'DE'=>'de','AT'=>'de','NL'=>'nl','SE'=>'sv','NO'=>'no','DK'=>'da','FI'=>'fi','IS'=>'is','IT'=>'it','SM'=>'it','VA'=>'it','GR'=>'el','CY'=>'el','MT'=>'mt','PL'=>'pl','CZ'=>'cs','SK'=>'sk','HU'=>'hu','RO'=>'ro','MD'=>'ro','BG'=>'bg','HR'=>'hr','SI'=>'sl','RS'=>'sr','BA'=>'bs','ME'=>'sr','MK'=>'mk','AL'=>'sq','XK'=>'sq','TR'=>'tr','RU'=>'ru','UA'=>'uk','BY'=>'be','EE'=>'et','LV'=>'lv','LT'=>'lt','GE'=>'ka','AM'=>'hy','AZ'=>'az','KZ'=>'kk','KG'=>'ky','TJ'=>'tg','TM'=>'tk','UZ'=>'uz', 'CN'=>'zh-CN','TW'=>'zh-TW','HK'=>'zh-TW','MO'=>'zh-TW','JP'=>'ja','KR'=>'ko','KP'=>'ko','VN'=>'vi','TH'=>'th','ID'=>'id','MY'=>'ms','SG'=>'en','KH'=>'km','LA'=>'lo','MM'=>'my','MN'=>'mn','BN'=>'ms', 'IR'=>'fa','AF'=>'fa','IL'=>'he','ET'=>'am','SO'=>'so','ER'=>'ti','ZW'=>'sn','ZM'=>'en','MW'=>'ny','MZ'=>'pt','BW'=>'en','NA'=>'en','LS'=>'st','SZ'=>'en','MG'=>'mg','MU'=>'en','SC'=>'en', 'JM'=>'en','HT'=>'ht','BZ'=>'en','GY'=>'en','SR'=>'nl','TT'=>'en','BB'=>'en','BS'=>'en','AG'=>'en','DM'=>'en','GD'=>'en','KN'=>'en','LC'=>'en','VC'=>'en','AW'=>'nl','CW'=>'nl' ]; } function pooliva_country_currency_map(): array { // Currency/language defaults for the most important ad/payment countries. Missing countries safely fall back to USD + country language. $m = [ 'US'=>['USD','$',1.00,'en'], 'CA'=>['CAD','C$',1.36,'en'], 'GB'=>['GBP','£',0.79,'en'], 'AU'=>['AUD','A$',1.52,'en'], 'NZ'=>['NZD','NZ$',1.64,'en'], 'SA'=>['SAR','ر.س',3.75,'ar'], 'AE'=>['AED','د.إ',3.67,'ar'], 'QA'=>['QAR','ر.ق',3.64,'ar'], 'KW'=>['KWD','د.ك',0.31,'ar'], 'BH'=>['BHD','BD',0.38,'ar'], 'OM'=>['OMR','OMR',0.38,'ar'], 'EG'=>['EGP','E£',48.00,'ar'], 'MA'=>['MAD','DH',10.00,'ar'], 'BR'=>['BRL','R$',5.15,'pt'], 'MX'=>['MXN','$',17.00,'es'], 'AR'=>['ARS','$',900.00,'es'], 'CO'=>['COP','$',3900.00,'es'], 'CL'=>['CLP','$',920.00,'es'], 'PE'=>['PEN','S/',3.75,'es'], 'TR'=>['TRY','₺',32.50,'tr'], 'IN'=>['INR','₹',83.00,'hi'], 'ID'=>['IDR','Rp',16000,'id'], 'PH'=>['PHP','₱',56.00,'en'], 'TH'=>['THB','฿',36.00,'th'], 'MY'=>['MYR','RM',4.70,'ms'], 'SG'=>['SGD','S$',1.35,'en'], 'JP'=>['JPY','¥',155.00,'ja'], 'KR'=>['KRW','₩',1360.00,'ko'], 'CN'=>['CNY','¥',7.20,'zh-CN'], 'TW'=>['TWD','NT$',32.00,'zh-TW'], 'HK'=>['HKD','HK$',7.80,'zh-TW'], 'FR'=>['EUR','€',0.92,'fr'], 'DE'=>['EUR','€',0.92,'de'], 'ES'=>['EUR','€',0.92,'es'], 'IT'=>['EUR','€',0.92,'it'], 'NL'=>['EUR','€',0.92,'nl'], 'BE'=>['EUR','€',0.92,'fr'], 'AT'=>['EUR','€',0.92,'de'], 'IE'=>['EUR','€',0.92,'en'], 'PT'=>['EUR','€',0.92,'pt'], 'GR'=>['EUR','€',0.92,'el'], 'FI'=>['EUR','€',0.92,'fi'], 'SE'=>['SEK','kr',10.60,'sv'], 'NO'=>['NOK','kr',10.70,'no'], 'DK'=>['DKK','kr',6.90,'da'], 'PL'=>['PLN','zł',4.00,'pl'], 'CZ'=>['CZK','Kč',23.00,'cs'], 'RO'=>['RON','lei',4.60,'ro'], 'HU'=>['HUF','Ft',360.00,'hu'], 'BG'=>['BGN','лв',1.80,'bg'], 'RU'=>['RUB','₽',92.00,'ru'], 'UA'=>['UAH','₴',39.00,'uk'], 'ZA'=>['ZAR','R',18.50,'en'], 'NG'=>['NGN','₦',1500.00,'en'], 'KE'=>['KES','KSh',130.00,'sw'] ]; $langMap = pooliva_country_language_map(); foreach ($langMap as $cc=>$lang) if (!isset($m[$cc])) $m[$cc]=['USD','$',1.00,$lang]; return $m; } function pooliva_geo_profile(?string $cc=null): array { $cc = strtoupper($cc ?: country_code()); $map = pooliva_country_currency_map(); $d = $map[$cc] ?? ['USD','$',1.00,(pooliva_country_language_map()[$cc] ?? 'en')]; return ['country_code'=>$cc,'currency_code'=>$d[0],'currency_symbol'=>$d[1],'fx_rate'=>(float)$d[2],'language'=>$d[3]]; } function pooliva_country_price_row(string $cc): ?array { global $pdo; try { $st=$pdo->prepare('SELECT * FROM country_pricing WHERE country_code=? AND is_active=1 LIMIT 1'); $st->execute([strtoupper($cc)]); $r=$st->fetch(); return $r ?: null; } catch(Throwable $e){ return null; } } function pooliva_pricing_for_country(?string $cc=null): array { $geo = pooliva_geo_profile($cc); $row = pooliva_country_price_row($geo['country_code']); $credits = (float)($row['pack_credits'] ?? setting_value('min_credit_pack','20')); $bonus = (float)($row['bonus_credits'] ?? setting_value('default_bonus_credits','0')); $usd = (float)($row['pack_price_usd'] ?? ((float)setting_value('credit_price','0.50') * $credits)); $prevUsd = (float)($row['previous_price_usd'] ?? 0); if ($prevUsd <= $usd) $prevUsd = round($usd * 1.9, 2); $rate = (float)($row['fx_rate_override'] ?? 0); if ($rate <= 0) $rate = (float)$geo['fx_rate']; $symbol = $row['currency_symbol'] ?? $geo['currency_symbol']; $code = $row['currency_code'] ?? $geo['currency_code']; $local = $usd * $rate; $prevLocal = $prevUsd * $rate; $totalCredits = $credits + $bonus; $badge = trim((string)($row['badge_text'] ?? setting_value('default_pack_badge','MOST POPULAR'))); $savingsPct = ($prevUsd > 0) ? max(0, min(95, round((1 - ($usd / $prevUsd)) * 100))) : 0; return [ 'country_code'=>$geo['country_code'], 'language'=>$geo['language'], 'credits'=>$credits, 'bonus_credits'=>$bonus, 'total_credits'=>$totalCredits, 'pay_usd'=>round($usd,2), 'paypal_amount_usd'=>round($usd,2), 'previous_price_usd'=>round($prevUsd,2), 'local_amount'=>round($local,2), 'previous_local_amount'=>round($prevLocal,2), 'currency_code'=>$code, 'currency_symbol'=>$symbol, 'badge_text'=>$badge, 'savings_percent'=>$savingsPct, 'matches'=>$totalCredits, 'featured'=> (int)($row['is_featured'] ?? 1), // Local currency is DISPLAY ONLY. PayPal/order amount remains exactly the USD value below. 'display_text'=>trim($symbol.' '.number_format($local, ($local>=1000?0:2))).' ≈ $'.number_format($usd,2).' USD', 'previous_display_text'=>trim($symbol.' '.number_format($prevLocal, ($prevLocal>=1000?0:2))).' ≈ $'.number_format($prevUsd,2).' USD', 'small_paypal_text'=>'PayPal checkout amount: $'.number_format($usd,2).' USD', 'paypal_notice'=>'You will pay exactly $'.number_format($usd,2).' USD in PayPal. Local currency is only an estimated display using FX rate '.number_format($rate,4).'.', 'fx_rate_used'=>round($rate,6), 'local_display_only'=>true ]; } function pooliva_language_for_country(?string $cc=null): string { $geo = pooliva_geo_profile($cc); $force = setting_value('force_language','auto'); if ($force && $force !== 'auto') return $force; if (setting_value('auto_language_enabled','1') !== '1') return 'en'; // Browser language gets priority when the visitor's device clearly asks for it. $accept = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? ''; if ($accept) { $first = strtolower(trim(explode(',', $accept)[0])); $first = str_replace('_','-', $first); $catalog = pooliva_language_catalog(); if (isset($catalog[$first])) return $first; $base = explode('-', $first)[0]; if (isset($catalog[$base])) return $base; } return $geo['language'] ?: 'en'; } function pooliva_base_translation_en(): array { return [ 'enter_title'=>'Enter Pooliva','enter_desc'=>'Write your player name first. No signup. Your game profile stays linked to this device/IP.','name_placeholder'=>'Your player name','terms'=>'I agree to the name rules, privacy policy, and fair play terms.','start'=>'Start Playing','optional_photo'=>'Profile photo is optional after you enter.','tag'=>'🎱 First match free • instant device profile','hero_title'=>'Instant Pool Battles','hero_desc'=>'Enter in seconds, beat global players, build streaks, and push your country up the City Wars board.','play_free'=>'Play Free Match','play_next'=>'Play Next Match','buy'=>'Buy Credits','edit_profile'=>'Edit Name / Photo','city_theme'=>'🏙️ City Table Theme','leaderboard'=>'Global Leaderboard','city_wars'=>'🌍 City Wars' ]; } function pooliva_static_translations(): array { return [ 'en'=>pooliva_base_translation_en(), 'ar'=>['enter_title'=>'ادخل Pooliva','enter_desc'=>'اكتب اسم اللاعب أولاً. بدون تسجيل. ملفك يبقى مربوط بجهازك.','name_placeholder'=>'اسم اللاعب','terms'=>'أوافق على شروط الاسم والخصوصية واللعب العادل.','start'=>'ابدأ اللعب','optional_photo'=>'صورة البروفايل اختيارية بعد الدخول.','tag'=>'🎱 أول مباراة مجانية • ملف فوري للجهاز','hero_title'=>'تحديات بلياردو فورية','hero_desc'=>'ادخل خلال ثواني، اهزم لاعبين عالميين، ارفع الستريك وادفع بلدك في ترتيب City Wars.','play_free'=>'العب مباراة مجانية','play_next'=>'العب المباراة التالية','buy'=>'شراء كريدت','edit_profile'=>'تعديل الاسم / الصورة','city_theme'=>'🏙️ ثيم طاولة المدينة','leaderboard'=>'الترتيب العالمي','city_wars'=>'🌍 حروب المدن'], 'es'=>['enter_title'=>'Entra a Pooliva','enter_desc'=>'Escribe tu nombre primero. Sin registro. Tu perfil queda ligado a este dispositivo.','name_placeholder'=>'Tu nombre','terms'=>'Acepto las reglas del nombre, privacidad y juego limpio.','start'=>'Empezar','optional_photo'=>'La foto de perfil es opcional después.','tag'=>'🎱 Primera partida gratis • perfil instantáneo','hero_title'=>'Batallas de pool instantáneas','hero_desc'=>'Entra en segundos, vence jugadores globales y sube tu país en City Wars.','play_free'=>'Jugar gratis','play_next'=>'Siguiente partida','buy'=>'Comprar créditos','edit_profile'=>'Editar nombre / foto','city_theme'=>'🏙️ Tema de mesa','leaderboard'=>'Ranking global','city_wars'=>'🌍 City Wars'], 'pt'=>['enter_title'=>'Entre no Pooliva','enter_desc'=>'Digite seu nome primeiro. Sem cadastro. Seu perfil fica ligado a este dispositivo.','name_placeholder'=>'Seu nome','terms'=>'Aceito as regras de nome, privacidade e jogo justo.','start'=>'Começar','optional_photo'=>'Foto de perfil é opcional depois.','tag'=>'🎱 Primeira partida grátis • perfil instantâneo','hero_title'=>'Batalhas instantâneas de sinuca','hero_desc'=>'Entre em segundos, vença jogadores globais e leve seu país ao topo.','play_free'=>'Jogar grátis','play_next'=>'Próxima partida','buy'=>'Comprar créditos','edit_profile'=>'Editar nome / foto','city_theme'=>'🏙️ Tema da mesa','leaderboard'=>'Ranking global','city_wars'=>'🌍 City Wars'] ]; } function pooliva_ai_translate_bundle(string $lang): ?array { if (setting_value('ai_translation_enabled','0') !== '1') return null; $key = trim(setting_value('openai_api_key','')); if (!$key || strtolower($key)==='null') return null; $catalog = pooliva_language_catalog(); $target = $catalog[$lang] ?? $lang; $base = pooliva_base_translation_en(); $model = setting_value('translation_model','gpt-4o-mini'); $note = setting_value('translation_quality_note','short, natural mobile pool game UI text. Keep Pooliva, City Wars, Credits as brand/game terms when natural. Return JSON only.'); $payload = json_encode([ 'model'=>$model, 'messages'=>[ ['role'=>'system','content'=>'You translate short mobile game UI strings. Return only valid compact JSON object with the same keys. No markdown.'], ['role'=>'user','content'=>'Translate this Pooliva game UI into '.$target.' ('.$lang.'). '.$note.' JSON: '.json_encode($base, JSON_UNESCAPED_UNICODE)] ], 'temperature'=>0.2 ], JSON_UNESCAPED_UNICODE); try { $ch = curl_init('https://api.openai.com/v1/chat/completions'); curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_POST=>true,CURLOPT_HTTPHEADER=>['Content-Type: application/json','Authorization: Bearer '.$key],CURLOPT_POSTFIELDS=>$payload,CURLOPT_TIMEOUT=>18]); $res = curl_exec($ch); $code = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if (!$res || $code < 200 || $code >= 300) return null; $j=json_decode($res,true); $txt=$j['choices'][0]['message']['content'] ?? ''; $arr=json_decode($txt,true); if (!is_array($arr)) return null; return array_intersect_key($arr, $base) + $base; } catch(Throwable $e){ return null; } } function pooliva_translations(string $lang): array { global $pdo; $lang = str_replace('_','-', trim($lang ?: 'en')); $static = pooliva_static_translations(); $base = pooliva_base_translation_en(); $out = $static[$lang] ?? $static[explode('-', $lang)[0] ?? 'en'] ?? $base; try { $st=$pdo->prepare('SELECT text_key,text_value FROM translations WHERE lang_code=?'); $st->execute([$lang]); $rows=$st->fetchAll(); if (!$rows && !isset($static[$lang]) && setting_value('ai_translation_enabled','0')==='1') { $ai = pooliva_ai_translate_bundle($lang); if ($ai) { $ins=$pdo->prepare('INSERT INTO translations(lang_code,text_key,text_value,source) VALUES(?,?,?,?) ON DUPLICATE KEY UPDATE text_value=VALUES(text_value),source=VALUES(source),updated_at=NOW()'); foreach($ai as $k=>$v){ $ins->execute([$lang,$k,$v,'ai-cache']); } $out = $ai; } } else { foreach($rows as $r){ $out[$r['text_key']]=$r['text_value']; } } } catch(Throwable $e) {} return $out + $base; } Pooliva.net - Instant Online Pool Battles
Credits: --
🎱 First match free • instant device profile

Instant Pool Battles

Enter in seconds, beat global players, build streaks, and push your country up the City Wars board.

Player🌐 Loading🔥 Streak: 0

🏙️ City Table Theme

Your table theme changes by city/country. Admin can tune colors and names.

Loading...

Global Leaderboard

🌍 City Wars

Every win adds points to your country.

🏆 Pooliva Clubs

Create or join a club. Every win adds Club War points.

🎬 Viral Shot Replays

Save crazy shots and share them as short links.

👑 Steal The Crown

Beat the current King and steal the crown instantly.

🎁 Rare Cue Drops

Win matches to unlock rare cue skins and flex your inventory.

📺 Live Queue Spectating

While waiting, watch live match activity so the app always feels alive.

🌎 Global Event

Limited-time country battles and weekly events.

😈 Your Rivals

Pooliva automatically detects repeat opponents, revenge matches, and heated battles.

🔥 Rival Leaderboard

The hottest rivalries across Pooliva.