/** * Detect whether the environment has Chinese language signals. * Used to show/hide the 中文 UI option — English-only otherwise. */ const ZH_TAG = /^(zh|yue|cmn)([-_]|$)/i; export const ZH_OK_COOKIE = "cyd-zh-ok"; export function isChineseLanguageTag(tag: string | null | undefined): boolean { if (!tag) return false; const primary = tag.trim().replace("_", "-"); return ZH_TAG.test(primary); } /** Parse Accept-Language / comma-separated locale list. */ export function acceptLanguageHasChinese( header: string | null | undefined ): boolean { if (!header) return false; return header .split(",") .map((part) => part.split(";")[0]?.trim()) .some((tag) => isChineseLanguageTag(tag)); } export type ChineseSignal = | "navigator.language" | "navigator.languages" | "intl.locale" | "accept-language" | "cookie"; export type ChineseDetection = { likely: boolean; signals: ChineseSignal[]; }; function readCookie(name: string): string | null { if (typeof document === "undefined") return null; const match = document.cookie.match( new RegExp(`(?:^|; )${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}=([^;]*)`) ); return match ? decodeURIComponent(match[1]) : null; } function writeCookie(name: string, value: string) { if (typeof document === "undefined") return; const maxAge = 60 * 60 * 24 * 365; document.cookie = `${name}=${encodeURIComponent(value)}; Path=/; Max-Age=${maxAge}; SameSite=Lax`; } /** * Client-side detection (browser / OS language prefs exposed to the page). */ export function detectChineseClient(): ChineseDetection { const signals: ChineseSignal[] = []; if (typeof navigator !== "undefined") { if (isChineseLanguageTag(navigator.language)) { signals.push("navigator.language"); } if (navigator.languages?.some((l) => isChineseLanguageTag(l))) { signals.push("navigator.languages"); } const legacy = (navigator as Navigator & { userLanguage?: string }) .userLanguage; if (isChineseLanguageTag(legacy) && !signals.includes("navigator.language")) { signals.push("navigator.language"); } } try { const intlLocale = Intl.DateTimeFormat().resolvedOptions().locale; if (isChineseLanguageTag(intlLocale)) { signals.push("intl.locale"); } } catch { /* ignore */ } if (readCookie(ZH_OK_COOKIE) === "1") { signals.push("cookie"); } return { likely: signals.length > 0, signals }; } /** Persist so middleware allows /zh after client-side Chinese detection. */ export function markChineseLocaleAllowed() { if (typeof window === "undefined") return; try { writeCookie(ZH_OK_COOKIE, "1"); window.localStorage.setItem(ZH_OK_COOKIE, "1"); } catch { /* ignore */ } }