yangdx
commited on
Commit
·
219639b
1
Parent(s):
144edae
Resolve the language setting persistence issue
Browse files- Move i18n initialization to async function
- Sync i18n with settings store language
- Add Root component for i18n loading state
- Convert i18n.js to TypeScript
lightrag_webui/src/components/Root.tsx
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { StrictMode, useEffect, useState } from 'react'
|
2 |
+
import { initializeI18n } from '@/i18n'
|
3 |
+
import App from '@/App'
|
4 |
+
|
5 |
+
export const Root = () => {
|
6 |
+
const [isI18nInitialized, setIsI18nInitialized] = useState(false)
|
7 |
+
|
8 |
+
useEffect(() => {
|
9 |
+
// Initialize i18n immediately with persisted language
|
10 |
+
initializeI18n().then(() => {
|
11 |
+
setIsI18nInitialized(true)
|
12 |
+
})
|
13 |
+
}, [])
|
14 |
+
|
15 |
+
if (!isI18nInitialized) {
|
16 |
+
return null // or a loading spinner
|
17 |
+
}
|
18 |
+
|
19 |
+
return (
|
20 |
+
<StrictMode>
|
21 |
+
<App />
|
22 |
+
</StrictMode>
|
23 |
+
)
|
24 |
+
}
|
lightrag_webui/src/i18n.js
DELETED
@@ -1,21 +0,0 @@
|
|
1 |
-
import i18n from 'i18next';
|
2 |
-
import { initReactI18next } from 'react-i18next';
|
3 |
-
|
4 |
-
import en from './locales/en.json';
|
5 |
-
import zh from './locales/zh.json';
|
6 |
-
|
7 |
-
i18n
|
8 |
-
.use(initReactI18next)
|
9 |
-
.init({
|
10 |
-
resources: {
|
11 |
-
en: { translation: en },
|
12 |
-
zh: { translation: zh }
|
13 |
-
},
|
14 |
-
lng: 'en', // default
|
15 |
-
fallbackLng: 'en',
|
16 |
-
interpolation: {
|
17 |
-
escapeValue: false
|
18 |
-
}
|
19 |
-
});
|
20 |
-
|
21 |
-
export default i18n;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lightrag_webui/src/i18n.ts
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import i18n from 'i18next'
|
2 |
+
import { initReactI18next } from 'react-i18next'
|
3 |
+
import { useSettingsStore } from '@/stores/settings'
|
4 |
+
|
5 |
+
import en from './locales/en.json'
|
6 |
+
import zh from './locales/zh.json'
|
7 |
+
|
8 |
+
// Function to sync i18n with store state
|
9 |
+
export const initializeI18n = async (): Promise<typeof i18n> => {
|
10 |
+
// Get initial language from store
|
11 |
+
const initialLanguage = useSettingsStore.getState().language
|
12 |
+
|
13 |
+
// Initialize with store language
|
14 |
+
await i18n.use(initReactI18next).init({
|
15 |
+
resources: {
|
16 |
+
en: { translation: en },
|
17 |
+
zh: { translation: zh }
|
18 |
+
},
|
19 |
+
lng: initialLanguage,
|
20 |
+
fallbackLng: 'en',
|
21 |
+
interpolation: {
|
22 |
+
escapeValue: false
|
23 |
+
}
|
24 |
+
})
|
25 |
+
|
26 |
+
// Subscribe to language changes
|
27 |
+
useSettingsStore.subscribe((state) => {
|
28 |
+
const currentLanguage = state.language
|
29 |
+
if (i18n.language !== currentLanguage) {
|
30 |
+
i18n.changeLanguage(currentLanguage)
|
31 |
+
}
|
32 |
+
})
|
33 |
+
|
34 |
+
return i18n
|
35 |
+
}
|
36 |
+
|
37 |
+
export default i18n
|
lightrag_webui/src/main.tsx
CHANGED
@@ -1,12 +1,5 @@
|
|
1 |
-
import { StrictMode } from 'react'
|
2 |
import { createRoot } from 'react-dom/client'
|
3 |
import './index.css'
|
4 |
-
import
|
5 |
-
import "./i18n";
|
6 |
|
7 |
-
|
8 |
-
createRoot(document.getElementById('root')!).render(
|
9 |
-
<StrictMode>
|
10 |
-
<App />
|
11 |
-
</StrictMode>
|
12 |
-
)
|
|
|
|
|
1 |
import { createRoot } from 'react-dom/client'
|
2 |
import './index.css'
|
3 |
+
import { Root } from '@/components/Root'
|
|
|
4 |
|
5 |
+
createRoot(document.getElementById('root')!).render(<Root />)
|
|
|
|
|
|
|
|
|
|
lightrag_webui/src/stores/settings.ts
CHANGED
@@ -59,11 +59,27 @@ interface SettingsState {
|
|
59 |
setCurrentTab: (tab: Tab) => void
|
60 |
}
|
61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
const useSettingsStoreBase = create<SettingsState>()(
|
63 |
persist(
|
64 |
(set) => ({
|
65 |
-
|
66 |
-
language: 'zh',
|
67 |
refreshLayout: () => {
|
68 |
const graphState = useGraphStore.getState();
|
69 |
const currentGraph = graphState.sigmaGraph;
|
@@ -116,10 +132,13 @@ const useSettingsStoreBase = create<SettingsState>()(
|
|
116 |
setTheme: (theme: Theme) => set({ theme }),
|
117 |
|
118 |
setLanguage: (language: Language) => {
|
|
|
|
|
119 |
import('i18next').then(({ default: i18n }) => {
|
120 |
-
i18n.
|
121 |
-
|
122 |
-
|
|
|
123 |
},
|
124 |
|
125 |
setGraphLayoutMaxIterations: (iterations: number) =>
|
|
|
59 |
setCurrentTab: (tab: Tab) => void
|
60 |
}
|
61 |
|
62 |
+
// Helper to get initial state from localStorage
|
63 |
+
const getInitialState = () => {
|
64 |
+
try {
|
65 |
+
const stored = localStorage.getItem('settings-storage')
|
66 |
+
if (stored) {
|
67 |
+
const { state } = JSON.parse(stored)
|
68 |
+
return {
|
69 |
+
theme: state?.theme || 'system',
|
70 |
+
language: state?.language || 'zh'
|
71 |
+
}
|
72 |
+
}
|
73 |
+
} catch (e) {
|
74 |
+
console.error('Failed to parse settings from localStorage:', e)
|
75 |
+
}
|
76 |
+
return { theme: 'system', language: 'zh' }
|
77 |
+
}
|
78 |
+
|
79 |
const useSettingsStoreBase = create<SettingsState>()(
|
80 |
persist(
|
81 |
(set) => ({
|
82 |
+
...getInitialState(),
|
|
|
83 |
refreshLayout: () => {
|
84 |
const graphState = useGraphStore.getState();
|
85 |
const currentGraph = graphState.sigmaGraph;
|
|
|
132 |
setTheme: (theme: Theme) => set({ theme }),
|
133 |
|
134 |
setLanguage: (language: Language) => {
|
135 |
+
set({ language })
|
136 |
+
// Update i18n after state is updated
|
137 |
import('i18next').then(({ default: i18n }) => {
|
138 |
+
if (i18n.language !== language) {
|
139 |
+
i18n.changeLanguage(language)
|
140 |
+
}
|
141 |
+
})
|
142 |
},
|
143 |
|
144 |
setGraphLayoutMaxIterations: (iterations: number) =>
|