forked from hikmet4434/winninghunter
184 lines
5.5 KiB
TypeScript
184 lines
5.5 KiB
TypeScript
"use client";
|
||
import { useEffect, useState } from "react";
|
||
|
||
const KEY = "ui_lang";
|
||
const IP_CACHE_KEY = "ip_country_cache";
|
||
const IP_DETECTION_DONE_KEY = "ip_detection_done";
|
||
|
||
export type Lang = "tr" | "en";
|
||
|
||
/**
|
||
* IP bazlı ülke tespiti ile otomatik dil seçimi
|
||
* Türkiye'den gelen ziyaretçiler için TR, diğerleri için EN
|
||
* Fallback chain: ipwho.is → ipapi.co → navigator.language → varsayılan TR
|
||
*/
|
||
async function detectCountryFromIP(): Promise<string | null> {
|
||
if (typeof window === "undefined") return null;
|
||
|
||
// Önce cache kontrolü (24 saat)
|
||
const cached = sessionStorage.getItem(IP_CACHE_KEY);
|
||
if (cached) {
|
||
const { country, timestamp } = JSON.parse(cached);
|
||
const isRecent = Date.now() - timestamp < 24 * 60 * 60 * 1000; // 24 saat
|
||
if (isRecent) return country;
|
||
}
|
||
|
||
// IP API sırası: ipwho.is → ipapi.co → fallback
|
||
const apis = [
|
||
{
|
||
url: "https://ipwho.is/",
|
||
timeout: 2500,
|
||
getCountry: (data: any) => data.country_code
|
||
},
|
||
{
|
||
url: "https://ipapi.co/json/",
|
||
timeout: 2500,
|
||
getCountry: (data: any) => data.country_code
|
||
}
|
||
];
|
||
|
||
for (const api of apis) {
|
||
try {
|
||
const controller = new AbortController();
|
||
const timeoutId = setTimeout(() => controller.abort(), api.timeout);
|
||
|
||
const response = await fetch(api.url, {
|
||
signal: controller.signal,
|
||
headers: { 'Accept': 'application/json' }
|
||
});
|
||
clearTimeout(timeoutId);
|
||
|
||
if (!response.ok) continue;
|
||
|
||
const data = await response.json();
|
||
const country = api.getCountry(data);
|
||
|
||
if (country && typeof country === 'string') {
|
||
// Cache'e kaydet
|
||
sessionStorage.setItem(IP_CACHE_KEY, JSON.stringify({
|
||
country,
|
||
timestamp: Date.now()
|
||
}));
|
||
return country;
|
||
}
|
||
} catch (error) {
|
||
// Hata olursa sonraki API'ye geç
|
||
continue;
|
||
}
|
||
}
|
||
|
||
// Tüm API'ler başarısız olursa navigator.language fallback
|
||
try {
|
||
const browserLang = navigator.language || navigator.languages?.[0];
|
||
if (browserLang) {
|
||
const isTurkish = browserLang.toLowerCase().startsWith('tr');
|
||
const country = isTurkish ? 'TR' : null;
|
||
|
||
if (country) {
|
||
sessionStorage.setItem(IP_CACHE_KEY, JSON.stringify({
|
||
country,
|
||
timestamp: Date.now()
|
||
}));
|
||
}
|
||
return country;
|
||
}
|
||
} catch (error) {
|
||
// En son fallback olarak TR döndür (Türkiye proj için varsayılan)
|
||
return 'TR';
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Geliştirilmiş dil state'i — IP tabanlı otomatik tespit + kullanıcı tercihi
|
||
* Kullanıcı manuel dil değiştirdiğinde bu tercih her zaman öncelikli olur
|
||
*/
|
||
export function useLang(): [Lang, (l: Lang) => void] {
|
||
const [lang, setLang] = useState<Lang>("tr");
|
||
|
||
useEffect(() => {
|
||
if (typeof window === "undefined") return;
|
||
|
||
// 1. Önce manuel kullanıcı tercihine bak (localStorage)
|
||
const userPreference = window.localStorage.getItem(KEY);
|
||
if (userPreference === "tr" || userPreference === "en") {
|
||
setLang(userPreference);
|
||
return; // Kullanıcı tercihi varsa, IP tespiti yapma
|
||
}
|
||
|
||
// 2. Kullanıcı tercihi yoksa ve henüz IP tespiti yapılmadıysa
|
||
const detectionDone = sessionStorage.getItem(IP_DETECTION_DONE_KEY);
|
||
if (!detectionDone) {
|
||
detectCountryFromIP().then(country => {
|
||
if (country === 'TR') {
|
||
setLang("tr");
|
||
} else {
|
||
setLang("en");
|
||
}
|
||
// Tekrar tespit yapmamak için işaretle
|
||
sessionStorage.setItem(IP_DETECTION_DONE_KEY, "true");
|
||
}).catch(() => {
|
||
// Herhangi bir hata durumunda varsayılan TR
|
||
setLang("tr");
|
||
sessionStorage.setItem(IP_DETECTION_DONE_KEY, "true");
|
||
});
|
||
} else {
|
||
// Daha önce tespit yapılmışsa, localStorage'daki tercihi kullan
|
||
if (userPreference === "tr" || userPreference === "en") {
|
||
setLang(userPreference);
|
||
}
|
||
}
|
||
}, []);
|
||
|
||
const updateLang = (newLang: Lang) => {
|
||
setLang(newLang);
|
||
if (typeof window !== "undefined") {
|
||
// Manuel tercihi kaydet (her zaman IP tespitinden öncelikli)
|
||
window.localStorage.setItem(KEY, newLang);
|
||
|
||
// Server component'lerin de dili okuyabilmesi için cookie yaz (1 yıl)
|
||
document.cookie = `${KEY}=${newLang}; path=/; max-age=31536000; SameSite=Lax`;
|
||
|
||
// Diğer tab/component'leri tetikle
|
||
window.dispatchEvent(new Event("ui_lang_change"));
|
||
}
|
||
};
|
||
|
||
// İlk yüklemede localStorage ↔ cookie senkronizasyonu (server ile tutarlılık)
|
||
useEffect(() => {
|
||
if (typeof window === "undefined") return;
|
||
const saved = window.localStorage.getItem(KEY);
|
||
if ((saved === "tr" || saved === "en") && !document.cookie.includes(`${KEY}=${saved}`)) {
|
||
document.cookie = `${KEY}=${saved}; path=/; max-age=31536000; SameSite=Lax`;
|
||
}
|
||
}, []);
|
||
|
||
// Diğer component'lerden dil değiştirildiğinde sync ol
|
||
useEffect(() => {
|
||
if (typeof window === "undefined") return;
|
||
const handler = () => {
|
||
const saved = window.localStorage.getItem(KEY);
|
||
if (saved === "tr" || saved === "en") setLang(saved);
|
||
};
|
||
window.addEventListener("ui_lang_change", handler);
|
||
return () => window.removeEventListener("ui_lang_change", handler);
|
||
}, []);
|
||
|
||
return [lang, updateLang];
|
||
}
|
||
|
||
/**
|
||
* Dil tercihine göre başlık/özet seç.
|
||
* tr → Türkçe varsa onu, yoksa İngilizce
|
||
* en → İngilizce varsa onu, yoksa Türkçe
|
||
*/
|
||
export function pickByLang(
|
||
lang: Lang,
|
||
tr: string | null | undefined,
|
||
en: string | null | undefined
|
||
): string {
|
||
if (lang === "tr") return tr || en || "";
|
||
return en || tr || "";
|
||
}
|