From dcbb6bf8cf5522ae69e890cb8ab10b787d30972c Mon Sep 17 00:00:00 2001 From: yangdx Date: Sat, 22 Mar 2025 00:31:18 +0800 Subject: [PATCH] Add French and Arabic language support --- lightrag_webui/src/components/AppSettings.tsx | 4 +- lightrag_webui/src/i18n.js | 35 -------------- lightrag_webui/src/i18n.ts | 46 +++++++++++-------- lightrag_webui/src/locales/ar.json | 27 ++++++++++- lightrag_webui/src/locales/fr.json | 27 ++++++++++- lightrag_webui/src/main.tsx | 2 +- lightrag_webui/src/stores/settings.ts | 2 +- 7 files changed, 83 insertions(+), 60 deletions(-) delete mode 100644 lightrag_webui/src/i18n.js diff --git a/lightrag_webui/src/components/AppSettings.tsx b/lightrag_webui/src/components/AppSettings.tsx index a1ac1403..6e312e0e 100644 --- a/lightrag_webui/src/components/AppSettings.tsx +++ b/lightrag_webui/src/components/AppSettings.tsx @@ -22,7 +22,7 @@ export default function AppSettings({ className }: AppSettingsProps) { const setTheme = useSettingsStore.use.setTheme() const handleLanguageChange = useCallback((value: string) => { - setLanguage(value as 'en' | 'zh') + setLanguage(value as 'en' | 'zh' | 'fr' | 'ar') }, [setLanguage]) const handleThemeChange = useCallback((value: string) => { @@ -47,6 +47,8 @@ export default function AppSettings({ className }: AppSettingsProps) { English 中文 + Français + العربية diff --git a/lightrag_webui/src/i18n.js b/lightrag_webui/src/i18n.js deleted file mode 100644 index be364b2c..00000000 --- a/lightrag_webui/src/i18n.js +++ /dev/null @@ -1,35 +0,0 @@ -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"; - -const getStoredLanguage = () => { - try { - const settingsString = localStorage.getItem('settings-storage'); - if (settingsString) { - const settings = JSON.parse(settingsString); - return settings.state?.language || 'en'; - } - } catch (e) { - console.error('Failed to get stored language:', e); - } - return 'en'; -}; - -i18n - .use(initReactI18next) - .init({ - resources: { - en: { translation: en }, - zh: { translation: zh } - }, - lng: getStoredLanguage(), // 使用存储的语言设置 - fallbackLng: "en", - interpolation: { - escapeValue: false - } - }); - -export default i18n; diff --git a/lightrag_webui/src/i18n.ts b/lightrag_webui/src/i18n.ts index 85ed13e5..d2753a0e 100644 --- a/lightrag_webui/src/i18n.ts +++ b/lightrag_webui/src/i18n.ts @@ -4,34 +4,44 @@ import { useSettingsStore } from '@/stores/settings' import en from './locales/en.json' import zh from './locales/zh.json' +import fr from './locales/fr.json' +import ar from './locales/ar.json' -// Function to sync i18n with store state -export const initializeI18n = async (): Promise => { - // Get initial language from store - const initialLanguage = useSettingsStore.getState().language +const getStoredLanguage = () => { + try { + const settingsString = localStorage.getItem('settings-storage') + if (settingsString) { + const settings = JSON.parse(settingsString) + return settings.state?.language || 'en' + } + } catch (e) { + console.error('Failed to get stored language:', e) + } + return 'en' +} - // Initialize with store language - await i18n.use(initReactI18next).init({ +i18n + .use(initReactI18next) + .init({ resources: { en: { translation: en }, - zh: { translation: zh } + zh: { translation: zh }, + fr: { translation: fr }, + ar: { translation: ar } }, - lng: initialLanguage, + lng: getStoredLanguage(), // 使用存储的语言设置 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 -} +// Subscribe to language changes +useSettingsStore.subscribe((state) => { + const currentLanguage = state.language + if (i18n.language !== currentLanguage) { + i18n.changeLanguage(currentLanguage) + } +}) export default i18n diff --git a/lightrag_webui/src/locales/ar.json b/lightrag_webui/src/locales/ar.json index 6b0234cf..fb415363 100644 --- a/lightrag_webui/src/locales/ar.json +++ b/lightrag_webui/src/locales/ar.json @@ -12,11 +12,26 @@ "retrieval": "الاسترجاع", "api": "واجهة برمجة التطبيقات", "projectRepository": "مستودع المشروع", + "logout": "تسجيل الخروج", "themeToggle": { "switchToLight": "التحويل إلى السمة الفاتحة", "switchToDark": "التحويل إلى السمة الداكنة" } }, + "login": { + "description": "الرجاء إدخال حسابك وكلمة المرور لتسجيل الدخول إلى النظام", + "username": "اسم المستخدم", + "usernamePlaceholder": "الرجاء إدخال اسم المستخدم", + "password": "كلمة المرور", + "passwordPlaceholder": "الرجاء إدخال كلمة المرور", + "loginButton": "تسجيل الدخول", + "loggingIn": "جاري تسجيل الدخول...", + "successMessage": "تم تسجيل الدخول بنجاح", + "errorEmptyFields": "الرجاء إدخال اسم المستخدم وكلمة المرور", + "errorInvalidCredentials": "فشل تسجيل الدخول، يرجى التحقق من اسم المستخدم وكلمة المرور", + "authDisabled": "تم تعطيل المصادقة. استخدام وضع بدون تسجيل دخول.", + "guestMode": "وضع بدون تسجيل دخول" + }, "documentPanel": { "clearDocuments": { "button": "مسح", @@ -96,7 +111,9 @@ "zoomControl": { "zoomIn": "تكبير", "zoomOut": "تصغير", - "resetZoom": "إعادة تعيين التكبير" + "resetZoom": "إعادة تعيين التكبير", + "rotateCamera": "تدوير في اتجاه عقارب الساعة", + "rotateCameraCounterClockwise": "تدوير عكس اتجاه عقارب الساعة" }, "layoutsControl": { "startAnimation": "بدء حركة التخطيط", @@ -148,6 +165,11 @@ "degree": "الدرجة", "properties": "الخصائص", "relationships": "العلاقات", + "expandNode": "توسيع العقدة", + "pruneNode": "تقليم العقدة", + "deleteAllNodesError": "رفض حذف جميع العقد في الرسم البياني", + "nodesRemoved": "تم إزالة {{count}} عقدة، بما في ذلك العقد اليتيمة", + "noNewNodes": "لم يتم العثور على عقد قابلة للتوسيع", "propertyNames": { "description": "الوصف", "entity_id": "الاسم", @@ -174,7 +196,8 @@ "noLabels": "لم يتم العثور على تسميات", "label": "التسمية", "placeholder": "ابحث في التسميات...", - "andOthers": "و {{count}} آخرون" + "andOthers": "و {{count}} آخرون", + "refreshTooltip": "إعادة تحميل بيانات الرسم البياني" } }, "retrievePanel": { diff --git a/lightrag_webui/src/locales/fr.json b/lightrag_webui/src/locales/fr.json index 5de47e50..3b4a0b32 100644 --- a/lightrag_webui/src/locales/fr.json +++ b/lightrag_webui/src/locales/fr.json @@ -12,11 +12,26 @@ "retrieval": "Récupération", "api": "API", "projectRepository": "Référentiel du projet", + "logout": "Déconnexion", "themeToggle": { "switchToLight": "Passer au thème clair", "switchToDark": "Passer au thème sombre" } }, + "login": { + "description": "Veuillez entrer votre compte et mot de passe pour vous connecter au système", + "username": "Nom d'utilisateur", + "usernamePlaceholder": "Veuillez saisir un nom d'utilisateur", + "password": "Mot de passe", + "passwordPlaceholder": "Veuillez saisir un mot de passe", + "loginButton": "Connexion", + "loggingIn": "Connexion en cours...", + "successMessage": "Connexion réussie", + "errorEmptyFields": "Veuillez saisir votre nom d'utilisateur et mot de passe", + "errorInvalidCredentials": "Échec de la connexion, veuillez vérifier le nom d'utilisateur et le mot de passe", + "authDisabled": "L'authentification est désactivée. Utilisation du mode sans connexion.", + "guestMode": "Mode sans connexion" + }, "documentPanel": { "clearDocuments": { "button": "Effacer", @@ -96,7 +111,9 @@ "zoomControl": { "zoomIn": "Zoom avant", "zoomOut": "Zoom arrière", - "resetZoom": "Réinitialiser le zoom" + "resetZoom": "Réinitialiser le zoom", + "rotateCamera": "Rotation horaire", + "rotateCameraCounterClockwise": "Rotation antihoraire" }, "layoutsControl": { "startAnimation": "Démarrer l'animation de mise en page", @@ -148,6 +165,11 @@ "degree": "Degré", "properties": "Propriétés", "relationships": "Relations", + "expandNode": "Développer le nœud", + "pruneNode": "Élaguer le nœud", + "deleteAllNodesError": "Refus de supprimer tous les nœuds du graphe", + "nodesRemoved": "{{count}} nœuds supprimés, y compris les nœuds orphelins", + "noNewNodes": "Aucun nœud développable trouvé", "propertyNames": { "description": "Description", "entity_id": "Nom", @@ -174,7 +196,8 @@ "noLabels": "Aucune étiquette trouvée", "label": "Étiquette", "placeholder": "Rechercher des étiquettes...", - "andOthers": "Et {{count}} autres" + "andOthers": "Et {{count}} autres", + "refreshTooltip": "Recharger les données du graphe" } }, "retrievePanel": { diff --git a/lightrag_webui/src/main.tsx b/lightrag_webui/src/main.tsx index 4c613602..081fef26 100644 --- a/lightrag_webui/src/main.tsx +++ b/lightrag_webui/src/main.tsx @@ -2,7 +2,7 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import './index.css' import AppRouter from './AppRouter' -import './i18n'; +import './i18n.ts'; diff --git a/lightrag_webui/src/stores/settings.ts b/lightrag_webui/src/stores/settings.ts index 72df7351..2344ea13 100644 --- a/lightrag_webui/src/stores/settings.ts +++ b/lightrag_webui/src/stores/settings.ts @@ -5,7 +5,7 @@ import { defaultQueryLabel } from '@/lib/constants' import { Message, QueryRequest } from '@/api/lightrag' type Theme = 'dark' | 'light' | 'system' -type Language = 'en' | 'zh' +type Language = 'en' | 'zh' | 'fr' | 'ar' type Tab = 'documents' | 'knowledge-graph' | 'retrieval' | 'api' interface SettingsState {