Files
gitlab-instance-0a899031_di…/app/context/LocaleContext.tsx
2026-03-08 04:30:57 -05:00

101 lines
2.4 KiB
TypeScript

"use client";
import {
createContext,
useContext,
useCallback,
type ReactNode,
} from "react";
export type Locale = "zh" | "en";
const LOCALES: Locale[] = ["zh", "en"];
const DEFAULT_LOCALE: Locale = "zh";
type Messages = Record<string, unknown>;
type LocaleContextValue = {
locale: Locale;
messages: Messages;
t: (key: string) => string;
setLocale: (locale: Locale) => void;
};
const LocaleContext = createContext<LocaleContextValue | null>(null);
function getNested(obj: unknown, path: string): string | undefined {
const keys = path.split(".");
let current: unknown = obj;
for (const key of keys) {
if (current == null || typeof current !== "object") return undefined;
current = (current as Record<string, unknown>)[key];
}
return typeof current === "string" ? current : undefined;
}
export function LocaleProvider({
locale,
messages,
children,
}: {
locale: Locale;
messages: Messages;
children: ReactNode;
}) {
const t = useCallback(
(key: string) => {
const value = getNested(messages, key);
return value ?? key;
},
[messages]
);
const setLocale = useCallback((newLocale: Locale) => {
const path = window.location.pathname;
const newPath = path.replace(/^\/(zh|en)/, `/${newLocale}`);
window.location.href = newPath || `/${newLocale}`;
}, []);
const value: LocaleContextValue = {
locale,
messages,
t,
setLocale,
};
return (
<LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>
);
}
export function useLocale() {
const ctx = useContext(LocaleContext);
if (!ctx) throw new Error("useLocale must be used within LocaleProvider");
return ctx.locale;
}
export function useTranslation(namespace?: string) {
const ctx = useContext(LocaleContext);
if (!ctx) throw new Error("useTranslation must be used within LocaleProvider");
return {
t: (key: string) => {
const fullKey = namespace ? `${namespace}.${key}` : key;
return ctx.t(fullKey);
},
};
}
export function useLocaleRouter() {
const locale = useLocale();
return {
replace: (pathname: string, opts?: { locale?: Locale }) => {
const newLocale = opts?.locale ?? locale;
const cleanPath = pathname.replace(/^\/(zh|en)/, "") || "/";
const newPath = `/${newLocale}${cleanPath === "/" ? "" : cleanPath}`;
window.location.href = newPath;
},
};
}
export { LOCALES, DEFAULT_LOCALE };