Files
multica/apps/web/features/landing/i18n/context.tsx
devv-eve fbf41bde73 feat(selfhost): ship public GHCR deployment flow
Publish stable GHCR self-host images, switch self-host deploys to official image pulls with a source-build fallback, and move self-host signup / Google OAuth config onto runtime /api/config.
2026-04-22 16:58:42 +08:00

58 lines
1.5 KiB
TypeScript

"use client";
import { createContext, useContext, useState, useCallback, useMemo } from "react";
import { useConfigStore } from "@multica/core/config";
import { createEnDict } from "./en";
import { createZhDict } from "./zh";
import type { LandingDict, Locale } from "./types";
const dictionaryFactories: Record<Locale, (allowSignup: boolean) => LandingDict> = {
en: createEnDict,
zh: createZhDict,
};
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 allowSignup = useConfigStore((state) => state.allowSignup);
const t = useMemo(
() => dictionaryFactories[locale](allowSignup),
[allowSignup, locale],
);
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, setLocale }}
>
{children}
</LocaleContext.Provider>
);
}
export function useLocale() {
const ctx = useContext(LocaleContext);
if (!ctx) throw new Error("useLocale must be used within LocaleProvider");
return ctx;
}