mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-25 05:52:34 +00:00
feat: add internationalization (i18n) to web dashboard — English + Chinese (#9453)
Add a lightweight i18n system to the web dashboard with English (default) and Chinese language support. A language switcher with flag icons is placed in the header bar, allowing users to toggle between languages. The choice persists to localStorage. Implementation: - src/i18n/ — types, translation files (en.ts, zh.ts), React context + hook - LanguageSwitcher component shows the *other* language's flag as the toggle - I18nProvider wraps the app in main.tsx - All 8 pages + OAuth components updated to use t() translation calls - Zero new dependencies — pure React context + localStorage
This commit is contained in:
parent
19199cd38d
commit
a2ea237db2
19 changed files with 1715 additions and 977 deletions
58
web/src/i18n/context.tsx
Normal file
58
web/src/i18n/context.tsx
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { createContext, useContext, useState, useCallback, type ReactNode } from "react";
|
||||
import type { Locale, Translations } from "./types";
|
||||
import { en } from "./en";
|
||||
import { zh } from "./zh";
|
||||
|
||||
const TRANSLATIONS: Record<Locale, Translations> = { en, zh };
|
||||
const STORAGE_KEY = "hermes-locale";
|
||||
|
||||
function getInitialLocale(): Locale {
|
||||
try {
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
if (stored === "en" || stored === "zh") return stored;
|
||||
} catch {
|
||||
// SSR or privacy mode
|
||||
}
|
||||
return "en";
|
||||
}
|
||||
|
||||
interface I18nContextValue {
|
||||
locale: Locale;
|
||||
setLocale: (l: Locale) => void;
|
||||
t: Translations;
|
||||
}
|
||||
|
||||
const I18nContext = createContext<I18nContextValue>({
|
||||
locale: "en",
|
||||
setLocale: () => {},
|
||||
t: en,
|
||||
});
|
||||
|
||||
export function I18nProvider({ children }: { children: ReactNode }) {
|
||||
const [locale, setLocaleState] = useState<Locale>(getInitialLocale);
|
||||
|
||||
const setLocale = useCallback((l: Locale) => {
|
||||
setLocaleState(l);
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, l);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}, []);
|
||||
|
||||
const value: I18nContextValue = {
|
||||
locale,
|
||||
setLocale,
|
||||
t: TRANSLATIONS[locale],
|
||||
};
|
||||
|
||||
return (
|
||||
<I18nContext.Provider value={value}>
|
||||
{children}
|
||||
</I18nContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useI18n() {
|
||||
return useContext(I18nContext);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue