Some checks failed
lotteryfront CI / build (push) Has been cancelled
- Added captcha validation to the player login screen, requiring users to input a captcha code for authentication. - Implemented a new API call to fetch captcha images, improving security during login. - Updated wallet display logic to ensure accurate representation of available and total balances based on player funding modes. - Enhanced documentation in AGENTS.md to clarify changes in credit flow and login requirements.
108 lines
2.7 KiB
TypeScript
108 lines
2.7 KiB
TypeScript
"use client";
|
||
|
||
import i18n from "i18next";
|
||
import { initReactI18next } from "react-i18next";
|
||
|
||
import enCommon from "./locales/en/common.json";
|
||
import enEntry from "./locales/en/entry.json";
|
||
import enLayout from "./locales/en/layout.json";
|
||
import enPlayer from "./locales/en/player.json";
|
||
import neCommon from "./locales/ne/common.json";
|
||
import neEntry from "./locales/ne/entry.json";
|
||
import neLayout from "./locales/ne/layout.json";
|
||
import nePlayer from "./locales/ne/player.json";
|
||
import zhCommon from "./locales/zh/common.json";
|
||
import zhEntry from "./locales/zh/entry.json";
|
||
import zhLayout from "./locales/zh/layout.json";
|
||
import zhPlayer from "./locales/zh/player.json";
|
||
import {
|
||
DEFAULT_LANGUAGE,
|
||
normalizeLanguage,
|
||
type AppLanguage,
|
||
} from "@/i18n/language";
|
||
export {
|
||
DEFAULT_LANGUAGE,
|
||
normalizeLanguage,
|
||
SUPPORTED_LANGUAGES,
|
||
type AppLanguage,
|
||
} from "@/i18n/language";
|
||
|
||
const namespaces = ["common", "entry", "layout", "player"] as const;
|
||
|
||
const resources = {
|
||
en: {
|
||
common: enCommon,
|
||
entry: enEntry,
|
||
layout: enLayout,
|
||
player: enPlayer,
|
||
},
|
||
ne: {
|
||
common: neCommon,
|
||
entry: neEntry,
|
||
layout: neLayout,
|
||
player: nePlayer,
|
||
},
|
||
zh: {
|
||
common: zhCommon,
|
||
entry: zhEntry,
|
||
layout: zhLayout,
|
||
player: zhPlayer,
|
||
},
|
||
} satisfies Record<
|
||
AppLanguage,
|
||
Record<(typeof namespaces)[number], Record<string, unknown>>
|
||
>;
|
||
|
||
export function syncDocumentLanguage(lang: AppLanguage): void {
|
||
if (typeof document === "undefined") return;
|
||
|
||
document.documentElement.lang = lang;
|
||
}
|
||
|
||
export function syncPreferredLanguage(): void {
|
||
if (typeof window === "undefined") return;
|
||
|
||
const stored = window.localStorage.getItem("i18nextLng");
|
||
const preferred = normalizeLanguage(stored ?? window.navigator.language);
|
||
const current = normalizeLanguage(i18n.resolvedLanguage ?? i18n.language);
|
||
|
||
if (preferred !== current) {
|
||
void i18n.changeLanguage(preferred);
|
||
}
|
||
}
|
||
|
||
if (!i18n.isInitialized) {
|
||
i18n.use(initReactI18next).init({
|
||
resources,
|
||
fallbackLng: DEFAULT_LANGUAGE,
|
||
supportedLngs: ["en", "ne", "zh"],
|
||
defaultNS: "common",
|
||
ns: [...namespaces],
|
||
/** 与 SSR 一致:首屏固定默认语言,hydration 后再由 syncPreferredLanguage 切换 */
|
||
load: "languageOnly",
|
||
lng: DEFAULT_LANGUAGE,
|
||
initAsync: false,
|
||
|
||
interpolation: {
|
||
escapeValue: false,
|
||
},
|
||
|
||
react: {
|
||
useSuspense: false,
|
||
},
|
||
});
|
||
|
||
syncDocumentLanguage(normalizeLanguage(i18n.resolvedLanguage ?? i18n.language));
|
||
|
||
i18n.on("languageChanged", (lang) => {
|
||
const next = normalizeLanguage(lang);
|
||
syncDocumentLanguage(next);
|
||
|
||
if (typeof window !== "undefined") {
|
||
window.localStorage.setItem("i18nextLng", next);
|
||
}
|
||
});
|
||
}
|
||
|
||
export default i18n;
|