Files
Arkie-Library-Frontend/src/i18n.tsx
2026-06-01 16:36:55 +08:00

91 lines
2.4 KiB
TypeScript

import React, {
createContext,
useCallback,
useContext,
useMemo,
useState,
} from "react";
import {
languageForHomePathname,
languageFromPathname,
langPathPrefix,
} from "./languageRoutes";
import type { Dict } from "./locales/types";
import { zhDict } from "./locales/zh-CN";
import { enDict } from "./locales/en";
import { jaDict } from "./locales/ja";
import { koDict } from "./locales/ko";
import { viDict } from "./locales/vi";
import { idDict } from "./locales/id";
import { msDict } from "./locales/ms";
export type Lang = "zh-CN" | "en" | "ja" | "ko" | "vi" | "id" | "ms";
const dict: Record<Lang, Dict> = {
"zh-CN": zhDict,
en: enDict,
ja: jaDict,
ko: koDict,
vi: viDict,
id: idDict,
ms: msDict,
};
/** Fixed locale lookup (admin UI uses Simplified Chinese). */
export function tLang(lang: Lang, key: string): string {
return dict[lang][key] || dict.en[key] || key;
}
type Ctx = { lang: Lang; setLang: (l: Lang) => void; t: (k: string) => string };
const I18nCtx = createContext<Ctx | null>(null);
const LANG_KEY = "ark_lang";
export function I18nProvider({ children }: { children: React.ReactNode }) {
const [lang, setLangState] = useState<Lang>(() => {
const path = window.location.pathname;
// Any URL whose first path segment is a known language prefix wins
// (covers /malay, /malay/browse, /korean/category/foo, etc.).
const homeLang = languageForHomePathname(path);
if (homeLang) return homeLang;
const deepLang = languageFromPathname(path);
if (langPathPrefix(deepLang)) return deepLang;
if (path === "/") return "en";
const s = localStorage.getItem(LANG_KEY);
if (s === "zh" || s === "zh-TW") return "zh-CN";
if (
s === "zh-CN" ||
s === "en" ||
s === "ja" ||
s === "ko" ||
s === "vi" ||
s === "id" ||
s === "ms"
)
return s;
return "en";
});
const setLang = useCallback((l: Lang) => {
localStorage.setItem(LANG_KEY, l);
setLangState(l);
}, []);
const t = useCallback(
(k: string) => dict[lang][k] || dict.en[k] || k,
[lang],
);
const v = useMemo(() => ({ lang, setLang, t }), [lang, t]);
return <I18nCtx.Provider value={v}>{children}</I18nCtx.Provider>;
}
export function useI18n() {
const v = useContext(I18nCtx);
if (!v) throw new Error("I18nProvider missing");
return v;
}
export function langQuery(lang: Lang) {
return lang;
}