diff --git a/lightrag_webui/src/components/Root.tsx b/lightrag_webui/src/components/Root.tsx
new file mode 100644
index 00000000..6191ace8
--- /dev/null
+++ b/lightrag_webui/src/components/Root.tsx
@@ -0,0 +1,24 @@
+import { StrictMode, useEffect, useState } from 'react'
+import { initializeI18n } from '@/i18n'
+import App from '@/App'
+
+export const Root = () => {
+ const [isI18nInitialized, setIsI18nInitialized] = useState(false)
+
+ useEffect(() => {
+ // Initialize i18n immediately with persisted language
+ initializeI18n().then(() => {
+ setIsI18nInitialized(true)
+ })
+ }, [])
+
+ if (!isI18nInitialized) {
+ return null // or a loading spinner
+ }
+
+ return (
+
+
+
+ )
+}
diff --git a/lightrag_webui/src/i18n.js b/lightrag_webui/src/i18n.js
deleted file mode 100644
index 428cba1e..00000000
--- a/lightrag_webui/src/i18n.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import i18n from 'i18next';
-import { initReactI18next } from 'react-i18next';
-
-import en from './locales/en.json';
-import zh from './locales/zh.json';
-
-i18n
- .use(initReactI18next)
- .init({
- resources: {
- en: { translation: en },
- zh: { translation: zh }
- },
- lng: 'en', // default
- fallbackLng: 'en',
- interpolation: {
- escapeValue: false
- }
- });
-
-export default i18n;
diff --git a/lightrag_webui/src/i18n.ts b/lightrag_webui/src/i18n.ts
new file mode 100644
index 00000000..85ed13e5
--- /dev/null
+++ b/lightrag_webui/src/i18n.ts
@@ -0,0 +1,37 @@
+import i18n from 'i18next'
+import { initReactI18next } from 'react-i18next'
+import { useSettingsStore } from '@/stores/settings'
+
+import en from './locales/en.json'
+import zh from './locales/zh.json'
+
+// Function to sync i18n with store state
+export const initializeI18n = async (): Promise => {
+ // Get initial language from store
+ const initialLanguage = useSettingsStore.getState().language
+
+ // Initialize with store language
+ await i18n.use(initReactI18next).init({
+ resources: {
+ en: { translation: en },
+ zh: { translation: zh }
+ },
+ lng: initialLanguage,
+ fallbackLng: 'en',
+ interpolation: {
+ escapeValue: false
+ }
+ })
+
+ // Subscribe to language changes
+ useSettingsStore.subscribe((state) => {
+ const currentLanguage = state.language
+ if (i18n.language !== currentLanguage) {
+ i18n.changeLanguage(currentLanguage)
+ }
+ })
+
+ return i18n
+}
+
+export default i18n
diff --git a/lightrag_webui/src/main.tsx b/lightrag_webui/src/main.tsx
index 6cf8a1e5..fd8f90e1 100644
--- a/lightrag_webui/src/main.tsx
+++ b/lightrag_webui/src/main.tsx
@@ -1,12 +1,5 @@
-import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
-import App from './App.tsx'
-import "./i18n";
+import { Root } from '@/components/Root'
-
-createRoot(document.getElementById('root')!).render(
-
-
-
-)
+createRoot(document.getElementById('root')!).render()
diff --git a/lightrag_webui/src/stores/settings.ts b/lightrag_webui/src/stores/settings.ts
index 6ff61f1a..bbacd1ad 100644
--- a/lightrag_webui/src/stores/settings.ts
+++ b/lightrag_webui/src/stores/settings.ts
@@ -59,11 +59,27 @@ interface SettingsState {
setCurrentTab: (tab: Tab) => void
}
+// Helper to get initial state from localStorage
+const getInitialState = () => {
+ try {
+ const stored = localStorage.getItem('settings-storage')
+ if (stored) {
+ const { state } = JSON.parse(stored)
+ return {
+ theme: state?.theme || 'system',
+ language: state?.language || 'zh'
+ }
+ }
+ } catch (e) {
+ console.error('Failed to parse settings from localStorage:', e)
+ }
+ return { theme: 'system', language: 'zh' }
+}
+
const useSettingsStoreBase = create()(
persist(
(set) => ({
- theme: 'system',
- language: 'zh',
+ ...getInitialState(),
refreshLayout: () => {
const graphState = useGraphStore.getState();
const currentGraph = graphState.sigmaGraph;
@@ -116,10 +132,13 @@ const useSettingsStoreBase = create()(
setTheme: (theme: Theme) => set({ theme }),
setLanguage: (language: Language) => {
+ set({ language })
+ // Update i18n after state is updated
import('i18next').then(({ default: i18n }) => {
- i18n.changeLanguage(language);
- });
- set({ language });
+ if (i18n.language !== language) {
+ i18n.changeLanguage(language)
+ }
+ })
},
setGraphLayoutMaxIterations: (iterations: number) =>