- Split landing pages into Server/Client Components to enable Next.js metadata exports - Add robots.ts, sitemap.ts, JSON-LD structured data, OpenGraph and viewport config - Fix i18n hydration mismatch: detect locale server-side via cookie/Accept-Language header - Replace localStorage with cookie for locale persistence (SSR-readable) - Dynamic <html lang> based on locale cookie - Optimize images with next/image (avif/webp formats, quality config) - Add /homepage route as always-visible landing page (no auth redirect) - Auth-aware CTA buttons: show "Dashboard"/"进入工作台" for logged-in users - Login page redirects authenticated users to dashboard - Unify logout/401 redirect to "/" instead of "/login" - Fix title template to avoid double "Multica" suffix on homepage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
48 lines
1.2 KiB
TypeScript
48 lines
1.2 KiB
TypeScript
"use client";
|
|
|
|
import { createContext, useContext, useState, useCallback } from "react";
|
|
import { en } from "./en";
|
|
import { zh } from "./zh";
|
|
import type { LandingDict, Locale } from "./types";
|
|
|
|
const dictionaries: Record<Locale, LandingDict> = { en, zh };
|
|
|
|
const COOKIE_NAME = "multica-locale";
|
|
const COOKIE_MAX_AGE = 60 * 60 * 24 * 365; // 1 year
|
|
|
|
type LocaleContextValue = {
|
|
locale: Locale;
|
|
t: LandingDict;
|
|
setLocale: (locale: Locale) => void;
|
|
};
|
|
|
|
const LocaleContext = createContext<LocaleContextValue | null>(null);
|
|
|
|
export function LocaleProvider({
|
|
children,
|
|
initialLocale = "en",
|
|
}: {
|
|
children: React.ReactNode;
|
|
initialLocale?: Locale;
|
|
}) {
|
|
const [locale, setLocaleState] = useState<Locale>(initialLocale);
|
|
|
|
const setLocale = useCallback((l: Locale) => {
|
|
setLocaleState(l);
|
|
document.cookie = `${COOKIE_NAME}=${l}; path=/; max-age=${COOKIE_MAX_AGE}; SameSite=Lax`;
|
|
}, []);
|
|
|
|
return (
|
|
<LocaleContext.Provider
|
|
value={{ locale, t: dictionaries[locale], setLocale }}
|
|
>
|
|
{children}
|
|
</LocaleContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useLocale() {
|
|
const ctx = useContext(LocaleContext);
|
|
if (!ctx) throw new Error("useLocale must be used within LocaleProvider");
|
|
return ctx;
|
|
}
|