Files
Sansheng-Intelligence/public/assets/js/visitor-region.js
T

75 lines
2.9 KiB
JavaScript
Raw Normal View History

let visitorCountryPromise = null;
const IP_LOOKUP_TIMEOUT_MS = 3500;
async function fetchWithTimeout(url, options = {}) {
const controller = new AbortController();
const timeout = window.setTimeout(() => controller.abort(), IP_LOOKUP_TIMEOUT_MS);
try {
return await fetch(url, { ...options, signal: controller.signal });
} finally {
window.clearTimeout(timeout);
}
}
async function countryFromCloudflare() {
for (const url of ["/cdn-cgi/trace", "https://www.cloudflare.com/cdn-cgi/trace"]) {
try {
const response = await fetchWithTimeout(url, { credentials: "omit", headers: { Accept: "text/plain" }, mode: "cors" });
if (!response.ok) continue;
const country = String((await response.text()).match(/^loc=([A-Z]{2})$/m)?.[1] || "").toUpperCase();
if (country) return country;
} catch {}
}
return "";
}
async function countryFromCountryIs() {
const response = await fetchWithTimeout("https://api.country.is/", { credentials: "omit", mode: "cors" });
if (!response.ok) return "";
return String((await response.json())?.country || "").toUpperCase();
}
async function countryFromIpWho() {
const response = await fetchWithTimeout("https://ipwho.is/?fields=success,country_code", {
credentials: "omit",
headers: { Accept: "application/json" },
mode: "cors",
});
if (!response.ok) return "";
const payload = await response.json();
return payload?.success ? String(payload.country_code || "").toUpperCase() : "";
}
export function detectVisitorCountry() {
if (visitorCountryPromise) return visitorCountryPromise;
if (typeof window === "undefined" || typeof fetch !== "function") return Promise.resolve("");
visitorCountryPromise = (async () => {
for (const detector of [countryFromCloudflare, countryFromCountryIs, countryFromIpWho]) {
try {
const country = await detector();
if (/^[A-Z]{2}$/.test(country)) return country;
} catch (error) {
console.debug("[家纺跨境情报] IP 区域检测源不可用,继续尝试备用源:", error);
}
}
return "UNKNOWN";
})();
return visitorCountryPromise;
}
export function visitorCanUseGoogleFallback() {
if (typeof navigator === "undefined" || typeof Intl === "undefined") return false;
const language = String(navigator.languages?.[0] || navigator.language || "").toLowerCase();
const timeZone = String(Intl.DateTimeFormat().resolvedOptions().timeZone || "");
const nonChineseLanguage = Boolean(language) && !language.startsWith("zh");
const outsideChinaTimeZone = Boolean(timeZone) && !["Asia/Shanghai", "Asia/Urumqi"].includes(timeZone);
return nonChineseLanguage || outsideChinaTimeZone;
}
export function translationProvider(countryCode, googleFallback = visitorCanUseGoogleFallback()) {
if (countryCode === "CN") return "yandex";
if (countryCode && countryCode !== "UNKNOWN") return "google";
if ((!countryCode || countryCode === "UNKNOWN") && googleFallback) return "google";
return "yandex";
}