feat: 添加国际化支持,优化语言切换器和登录界面,增强用户体验
Some checks failed
lotteryfront CI / build (push) Has been cancelled
Some checks failed
lotteryfront CI / build (push) Has been cancelled
This commit is contained in:
46
src/i18n/hydration-t.ts
Normal file
46
src/i18n/hydration-t.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
"use client";
|
||||
|
||||
import type { TFunction } from "i18next";
|
||||
import { useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { useI18nHydrated } from "@/components/i18n-hydration-provider";
|
||||
import { DEFAULT_LANGUAGE, type AppLanguage } from "@/i18n/language";
|
||||
import enEntry from "@/i18n/locales/en/entry.json";
|
||||
import neEntry from "@/i18n/locales/ne/entry.json";
|
||||
import zhEntry from "@/i18n/locales/zh/entry.json";
|
||||
|
||||
const STATIC_ENTRY: Record<AppLanguage, typeof zhEntry> = {
|
||||
zh: zhEntry,
|
||||
en: enEntry,
|
||||
ne: neEntry,
|
||||
};
|
||||
|
||||
function getStaticValue(obj: Record<string, unknown>, key: string): string {
|
||||
const parts = key.split(".");
|
||||
let cur: unknown = obj;
|
||||
for (const part of parts) {
|
||||
if (cur == null || typeof cur !== "object") return key;
|
||||
cur = (cur as Record<string, unknown>)[part];
|
||||
}
|
||||
return typeof cur === "string" ? cur : key;
|
||||
}
|
||||
|
||||
function createStaticEntryT(): TFunction<"entry"> {
|
||||
const fn = ((key: string) =>
|
||||
getStaticValue(STATIC_ENTRY[DEFAULT_LANGUAGE] as Record<string, unknown>, key)) as TFunction<
|
||||
"entry"
|
||||
>;
|
||||
return fn;
|
||||
}
|
||||
|
||||
/** entry 命名空间:hydration 前固定 DEFAULT_LANGUAGE 文案,避免 SSR/客户端首屏不一致。 */
|
||||
export function useHydrationSafeEntryT(): TFunction<"entry"> {
|
||||
const hydrated = useI18nHydrated();
|
||||
const { t } = useTranslation("entry");
|
||||
|
||||
return useMemo(
|
||||
() => (hydrated ? t : createStaticEntryT()),
|
||||
[hydrated, t],
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user