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) =>
|