商店审核需要独立的隐私、用户协议和注销页;运营后台也要按应用包名启用或停用价格。 Co-authored-by: Cursor <cursoragent@cursor.com>
167 lines
7.0 KiB
JavaScript
167 lines
7.0 KiB
JavaScript
(() => {
|
|
const LANGS = [
|
|
"zh-Hans", "zh-Hant", "en-US", "ja", "ko", "es-MX", "fr-FR",
|
|
"de-DE", "pt-BR", "ru", "ar-SA", "it", "th", "vi", "id",
|
|
];
|
|
|
|
const UI = {
|
|
"zh-Hans": { home: "首页", privacy: "隐私政策", terms: "用户协议", toDark: "暗黑", toLight: "日间" },
|
|
"zh-Hant": { home: "首頁", privacy: "隱私政策", terms: "使用者協議", toDark: "深色", toLight: "日間" },
|
|
"en-US": { home: "Home", privacy: "Privacy Policy", terms: "Terms of Use", toDark: "Dark", toLight: "Light" },
|
|
ja: { home: "ホーム", privacy: "プライバシー", terms: "利用規約", toDark: "ダーク", toLight: "ライト" },
|
|
ko: { home: "홈", privacy: "개인정보", terms: "이용약관", toDark: "어둡게", toLight: "밝게" },
|
|
"es-MX": { home: "Inicio", privacy: "Privacidad", terms: "Condiciones", toDark: "Oscuro", toLight: "Claro" },
|
|
"fr-FR": { home: "Accueil", privacy: "Confidentialité", terms: "Conditions", toDark: "Sombre", toLight: "Clair" },
|
|
"de-DE": { home: "Start", privacy: "Datenschutz", terms: "Nutzung", toDark: "Dunkel", toLight: "Hell" },
|
|
"pt-BR": { home: "Início", privacy: "Privacidade", terms: "Termos", toDark: "Escuro", toLight: "Claro" },
|
|
ru: { home: "Главная", privacy: "Конфиденциальность", terms: "Условия", toDark: "Тёмная", toLight: "Светлая" },
|
|
"ar-SA": { home: "الرئيسية", privacy: "الخصوصية", terms: "الشروط", toDark: "داكن", toLight: "فاتح" },
|
|
it: { home: "Home", privacy: "Privacy", terms: "Condizioni", toDark: "Scuro", toLight: "Chiaro" },
|
|
th: { home: "หน้าแรก", privacy: "ความเป็นส่วนตัว", terms: "ข้อกำหนด", toDark: "มืด", toLight: "สว่าง" },
|
|
vi: { home: "Trang chủ", privacy: "Quyền riêng tư", terms: "Điều khoản", toDark: "Tối", toLight: "Sáng" },
|
|
id: { home: "Beranda", privacy: "Privasi", terms: "Ketentuan", toDark: "Gelap", toLight: "Terang" },
|
|
};
|
|
|
|
const HTML_LANG = {
|
|
"zh-Hans": "zh-CN",
|
|
"zh-Hant": "zh-TW",
|
|
"en-US": "en",
|
|
ja: "ja",
|
|
ko: "ko",
|
|
"es-MX": "es-MX",
|
|
"fr-FR": "fr",
|
|
"de-DE": "de",
|
|
"pt-BR": "pt-BR",
|
|
ru: "ru",
|
|
"ar-SA": "ar",
|
|
it: "it",
|
|
th: "th",
|
|
vi: "vi",
|
|
id: "id",
|
|
};
|
|
|
|
function norm(tag) {
|
|
if (!tag) return "";
|
|
const raw = String(tag).trim().replace(/_/g, "-");
|
|
if (LANGS.includes(raw)) return raw;
|
|
const lower = raw.toLowerCase();
|
|
if (lower === "zh" || lower === "zh-cn" || lower === "zh-sg" || lower === "zh-hans") return "zh-Hans";
|
|
if (lower === "zh-tw" || lower === "zh-hk" || lower === "zh-mo" || lower === "zh-hant") return "zh-Hant";
|
|
if (lower.startsWith("en")) return "en-US";
|
|
if (lower.startsWith("ja")) return "ja";
|
|
if (lower.startsWith("ko")) return "ko";
|
|
if (lower.startsWith("es")) return "es-MX";
|
|
if (lower.startsWith("fr")) return "fr-FR";
|
|
if (lower.startsWith("de")) return "de-DE";
|
|
if (lower.startsWith("pt")) return "pt-BR";
|
|
if (lower.startsWith("ru")) return "ru";
|
|
if (lower.startsWith("ar")) return "ar-SA";
|
|
if (lower.startsWith("it")) return "it";
|
|
if (lower.startsWith("th")) return "th";
|
|
if (lower.startsWith("vi")) return "vi";
|
|
if (lower === "id" || lower.startsWith("id-") || lower.startsWith("in")) return "id";
|
|
return "";
|
|
}
|
|
|
|
function detectLang() {
|
|
const query = new URLSearchParams(location.search).get("lang");
|
|
if (query) return norm(query) || "zh-Hans";
|
|
try {
|
|
const saved = norm(localStorage.getItem("spark-legal-lang"));
|
|
if (saved) return saved;
|
|
} catch (_) { /* ignore */ }
|
|
const list = navigator.languages && navigator.languages.length
|
|
? navigator.languages
|
|
: [navigator.language || ""];
|
|
for (const item of list) {
|
|
const code = norm(item);
|
|
if (code) return code;
|
|
}
|
|
return "zh-Hans";
|
|
}
|
|
|
|
function effectiveTheme() {
|
|
const chosen = document.documentElement.getAttribute("data-theme");
|
|
if (chosen === "dark" || chosen === "light") return chosen;
|
|
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
}
|
|
|
|
function applyTheme(mode) {
|
|
if (mode === "light" || mode === "dark") {
|
|
document.documentElement.setAttribute("data-theme", mode);
|
|
} else {
|
|
document.documentElement.removeAttribute("data-theme");
|
|
}
|
|
paintThemeButton();
|
|
}
|
|
|
|
function paintThemeButton() {
|
|
const button = document.getElementById("theme");
|
|
const lang = document.documentElement.getAttribute("data-lang") || "zh-Hans";
|
|
const ui = UI[lang] || UI["zh-Hans"];
|
|
if (!button) return;
|
|
const dark = effectiveTheme() === "dark";
|
|
button.textContent = dark ? ui.toLight : ui.toDark;
|
|
button.setAttribute("aria-pressed", dark ? "true" : "false");
|
|
}
|
|
|
|
function applyLang(code) {
|
|
const safe = LANGS.includes(code) ? code : "zh-Hans";
|
|
document.querySelectorAll("article[data-lang]").forEach((node) => {
|
|
node.hidden = node.getAttribute("data-lang") !== safe;
|
|
});
|
|
document.documentElement.lang = HTML_LANG[safe] || "zh-CN";
|
|
document.documentElement.dir = safe === "ar-SA" ? "rtl" : "ltr";
|
|
document.documentElement.setAttribute("data-lang", safe);
|
|
const heading = document.querySelector(`article[data-lang="${safe}"] h1`);
|
|
if (heading && heading.textContent) {
|
|
document.title = `${heading.textContent.trim()} — Spark Messenger`;
|
|
}
|
|
const ui = UI[safe];
|
|
document.querySelectorAll("[data-i18n]").forEach((node) => {
|
|
const key = node.getAttribute("data-i18n");
|
|
if (ui[key]) node.textContent = ui[key];
|
|
});
|
|
const select = document.getElementById("lang");
|
|
if (select) select.value = safe;
|
|
paintThemeButton();
|
|
}
|
|
|
|
applyLang(detectLang());
|
|
|
|
try {
|
|
const savedTheme = localStorage.getItem("spark-legal-theme");
|
|
if (savedTheme === "light" || savedTheme === "dark") applyTheme(savedTheme);
|
|
else paintThemeButton();
|
|
} catch (_) {
|
|
paintThemeButton();
|
|
}
|
|
|
|
const select = document.getElementById("lang");
|
|
if (select) {
|
|
select.addEventListener("change", () => {
|
|
applyLang(select.value);
|
|
try { localStorage.setItem("spark-legal-lang", select.value); } catch (_) { /* ignore */ }
|
|
const url = new URL(location.href);
|
|
url.searchParams.set("lang", select.value);
|
|
history.replaceState(null, "", url);
|
|
});
|
|
}
|
|
|
|
const themeButton = document.getElementById("theme");
|
|
if (themeButton) {
|
|
themeButton.addEventListener("click", () => {
|
|
const next = effectiveTheme() === "dark" ? "light" : "dark";
|
|
applyTheme(next);
|
|
try { localStorage.setItem("spark-legal-theme", next); } catch (_) { /* ignore */ }
|
|
});
|
|
}
|
|
|
|
const media = window.matchMedia("(prefers-color-scheme: dark)");
|
|
const onScheme = () => {
|
|
if (!document.documentElement.getAttribute("data-theme")) paintThemeButton();
|
|
};
|
|
if (typeof media.addEventListener === "function") media.addEventListener("change", onScheme);
|
|
else if (typeof media.addListener === "function") media.addListener(onScheme);
|
|
})();
|