"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> >; 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;