73 lines
2.9 KiB
TypeScript
73 lines
2.9 KiB
TypeScript
/**
|
||
* # 模块 后台 i18n 核心(React 上下文 + t 函数)
|
||
* 词典以中文源串为 key(各页面直接 t("中文字符串")),en 词典提供英文译文,
|
||
* 缺词回退源串(中文)。默认英文:localStorage 未设置时 locale=en。
|
||
*/
|
||
import { createContext, useContext, useEffect, useState, type ReactNode } from "react";
|
||
import {
|
||
getAdminLocalePref,
|
||
setAdminLocalePref,
|
||
type AdminDict,
|
||
type AdminLocaleDef,
|
||
} from "./shared";
|
||
import { en } from "./locales/en";
|
||
|
||
// 客户端安全部分原样转出
|
||
export { ADMIN_LOCALES, ADMIN_LOCALE_STORAGE_KEY, ADMIN_THEME_STORAGE_KEY, getAdminLocalePref, setAdminLocalePref, getAdminThemePref, setAdminThemePref } from "./shared";
|
||
export type { AdminDict, AdminLocaleDef, AdminTheme } from "./shared";
|
||
|
||
/** # 成员变量 词典注册表(locale → AdminDict;en 启动即注册) **/
|
||
const dicts = new Map<string, AdminDict>([["en", en]]);
|
||
|
||
/** # 函数 注册某语言的后台词典 */
|
||
export function registerAdminDict(code: string, dict: AdminDict): void {
|
||
dicts.set(code, dict);
|
||
}
|
||
|
||
/** # 函数 构造后台翻译函数:按词典查 key,缺词回退源串(中文),支持 {var} 插值 */
|
||
export function createAdminT(locale: string) {
|
||
const d = dicts.get(locale);
|
||
return (key: string, vars?: Record<string, string | number>): string => {
|
||
let s: string = d?.[key] ?? key;
|
||
if (vars) for (const [k, v] of Object.entries(vars)) s = s.replaceAll(`{${k}}`, String(v));
|
||
return s;
|
||
};
|
||
}
|
||
|
||
/** # 类型 后台 t 函数 **/
|
||
export type AdminT = ReturnType<typeof createAdminT>;
|
||
|
||
// ---- React 上下文 ----
|
||
/** # 成员变量 后台语言上下文(默认英文) **/
|
||
const AdminLocaleContext = createContext<{ locale: string; setLocale: (code: string) => void; t: AdminT }>({
|
||
locale: "en",
|
||
setLocale: () => {},
|
||
t: createAdminT("en"),
|
||
});
|
||
|
||
/** # 组件 后台语言提供者(纯客户端:SSR 渲染英文,水合后读 localStorage 切换,无水合不一致) */
|
||
export function AdminLocaleProvider(props: { children: ReactNode }) {
|
||
const [locale, setLocaleState] = useState("en");
|
||
// 水合后应用本地偏好(effect 中 setState 不触发水合校验)
|
||
useEffect(() => {
|
||
setLocaleState(getAdminLocalePref());
|
||
}, []);
|
||
/** # 函数 切换后台语言:写 localStorage → 重渲染(组件树即时切换,无需整页刷新) */
|
||
const setLocale = (code: string) => {
|
||
setAdminLocalePref(code);
|
||
setLocaleState(code);
|
||
};
|
||
const t = createAdminT(locale);
|
||
return <AdminLocaleContext.Provider value={{ locale, setLocale, t }}>{props.children}</AdminLocaleContext.Provider>;
|
||
}
|
||
|
||
/** # 函数 组件内取后台语言上下文(locale / setLocale / t) */
|
||
export function useAdminI18n() {
|
||
return useContext(AdminLocaleContext);
|
||
}
|
||
|
||
/** # 函数 组件内取后台翻译函数(便捷别名) */
|
||
export function useAdminT(): AdminT {
|
||
return useContext(AdminLocaleContext).t;
|
||
}
|