Fix landing locale toggle cache path
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import { redirect } from "next/navigation";
|
||||
import { InstitutionalLandingPage } from "@/components/landing/InstitutionalLandingPage";
|
||||
import { LANDING_LOCALE_QUERY_PARAM } from "@/components/landing/landingLocale";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "PolyWeather | Institutional Weather Signal Intelligence",
|
||||
@@ -32,6 +33,8 @@ export default async function HomePage({
|
||||
const qs = usp.toString();
|
||||
redirect(`/auth/callback${qs ? `?${qs}` : ""}`);
|
||||
}
|
||||
const rawLandingLocale = params[LANDING_LOCALE_QUERY_PARAM];
|
||||
const landingLocale = Array.isArray(rawLandingLocale) ? rawLandingLocale[0] : rawLandingLocale;
|
||||
const jsonLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebApplication",
|
||||
@@ -68,7 +71,7 @@ export default async function HomePage({
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
||||
/>
|
||||
<InstitutionalLandingPage />
|
||||
<InstitutionalLandingPage queryLocale={landingLocale} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -227,9 +227,10 @@ function WeatherWorkflowIllustration() {
|
||||
);
|
||||
}
|
||||
|
||||
async function resolveLandingLocale(): Promise<LandingLocale> {
|
||||
async function resolveLandingLocale(queryLocale?: string | null): Promise<LandingLocale> {
|
||||
const [cookieStore, headerStore] = await Promise.all([cookies(), headers()]);
|
||||
return pickLandingLocale(
|
||||
queryLocale,
|
||||
cookieStore.get(LANDING_LOCALE_COOKIE)?.value,
|
||||
headerStore.get("accept-language"),
|
||||
);
|
||||
@@ -829,7 +830,11 @@ function InstitutionalLandingScreen({ locale }: { locale: LandingLocale }) {
|
||||
);
|
||||
}
|
||||
|
||||
export async function InstitutionalLandingPage() {
|
||||
const locale = await resolveLandingLocale();
|
||||
export async function InstitutionalLandingPage({
|
||||
queryLocale,
|
||||
}: {
|
||||
queryLocale?: string | null;
|
||||
} = {}) {
|
||||
const locale = await resolveLandingLocale(queryLocale);
|
||||
return <InstitutionalLandingScreen locale={locale} />;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { useTransition } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import {
|
||||
LANDING_LOCALE_COOKIE,
|
||||
LANDING_LOCALE_QUERY_PARAM,
|
||||
nextLandingLocale,
|
||||
type LandingLocale,
|
||||
} from "@/components/landing/landingLocale";
|
||||
@@ -11,8 +10,6 @@ import {
|
||||
const ONE_YEAR_SECONDS = 60 * 60 * 24 * 365;
|
||||
|
||||
export function LandingLocaleToggle({ locale }: { locale: LandingLocale }) {
|
||||
const router = useRouter();
|
||||
const [isPending, startTransition] = useTransition();
|
||||
const isEn = locale === "en-US";
|
||||
|
||||
const toggleLocale = () => {
|
||||
@@ -24,16 +21,16 @@ export function LandingLocaleToggle({ locale }: { locale: LandingLocale }) {
|
||||
} catch {
|
||||
// Locale persistence is best-effort; the cookie is enough for SSR.
|
||||
}
|
||||
startTransition(() => {
|
||||
router.refresh();
|
||||
});
|
||||
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set(LANDING_LOCALE_QUERY_PARAM, nextLocale);
|
||||
window.location.assign(url.toString());
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={toggleLocale}
|
||||
disabled={isPending}
|
||||
className="inline-flex h-9 cursor-pointer items-center gap-1 rounded-md border border-slate-200 bg-white px-1 text-xs font-semibold text-slate-500 shadow-sm hover:border-slate-300 disabled:cursor-wait disabled:opacity-70"
|
||||
aria-label={isEn ? "Switch language" : "切换语言"}
|
||||
>
|
||||
|
||||
@@ -23,6 +23,10 @@ export function runTests() {
|
||||
path.join(root, "components", "landing", "LandingLocaleToggle.tsx"),
|
||||
"utf8",
|
||||
);
|
||||
const localeHelperSource = fs.readFileSync(
|
||||
path.join(root, "components", "landing", "landingLocale.ts"),
|
||||
"utf8",
|
||||
);
|
||||
const staticCitiesSource = fs.readFileSync(
|
||||
path.join(root, "lib", "static-cities.ts"),
|
||||
"utf8",
|
||||
@@ -48,6 +52,18 @@ export function runTests() {
|
||||
assert(!authActionsSource.includes("lucide-react"), "auth island must avoid shipping lucide-react");
|
||||
assert(!localeToggleSource.includes("lucide-react"), "locale island must avoid shipping lucide-react");
|
||||
assert(!analyticsSource.includes("lucide-react"), "analytics island must avoid shipping lucide-react");
|
||||
assert(
|
||||
localeToggleSource.includes("new URL(window.location.href)") &&
|
||||
localeToggleSource.includes("LANDING_LOCALE_QUERY_PARAM") &&
|
||||
localeToggleSource.includes("window.location.assign(url.toString())"),
|
||||
"landing locale toggle must navigate with an explicit locale query so CDN-cached HTML cannot ignore cookie-only changes",
|
||||
);
|
||||
assert(
|
||||
localeHelperSource.includes("queryLocale") &&
|
||||
source.includes("resolveLandingLocale(queryLocale") &&
|
||||
appPageSource.includes("<InstitutionalLandingPage queryLocale={landingLocale} />"),
|
||||
"landing route must prefer an explicit locale query before cookie or Accept-Language",
|
||||
);
|
||||
assert(source.includes("3 天免费试用"), "landing page must advertise the 3-day trial");
|
||||
assert(source.includes("试用期权益和 Pro 一致,除了不显示付费 Telegram 群链接"), "landing page must state trial access matches Pro except the paid group link");
|
||||
assert(!source.includes("高频刷新与 API 仍为 Pro 权益"), "landing page must not incorrectly exclude high-frequency refresh or API from trial access");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export type LandingLocale = "zh-CN" | "en-US";
|
||||
|
||||
export const LANDING_LOCALE_COOKIE = "polyweather.locale";
|
||||
export const LANDING_LOCALE_QUERY_PARAM = "locale";
|
||||
export const DEFAULT_LANDING_LOCALE: LandingLocale = "zh-CN";
|
||||
|
||||
export function normalizeLandingLocale(value: string | null | undefined): LandingLocale | null {
|
||||
@@ -16,9 +17,13 @@ export function normalizeLandingLocale(value: string | null | undefined): Landin
|
||||
}
|
||||
|
||||
export function pickLandingLocale(
|
||||
queryLocale: string | null | undefined,
|
||||
cookieLocale: string | null | undefined,
|
||||
acceptLanguage: string | null | undefined,
|
||||
): LandingLocale {
|
||||
const fromQuery = normalizeLandingLocale(queryLocale);
|
||||
if (fromQuery) return fromQuery;
|
||||
|
||||
const fromCookie = normalizeLandingLocale(cookieLocale);
|
||||
if (fromCookie) return fromCookie;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user