Enable users to switch seamlessly between English and Arabic languages

Adds i18next, LanguageDetector, locales (en.json, ar.json), and LanguageSwitcher component for internationalization.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: ff0be73b-afdd-4747-978b-bb8301fb0a82
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/9777c70b-fc38-4831-8d6b-78dfffe041b0/d552135c-0e60-4fc7-98a2-0e9cddf2b4b3.jpg
This commit is contained in:
ghaddaditw
2025-06-08 06:40:22 +00:00
parent 823de76f48
commit 5cae99424f
7 changed files with 600 additions and 12 deletions
@@ -0,0 +1,50 @@
import { useTranslation } from 'react-i18next';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Languages } from 'lucide-react';
export function LanguageSwitcher() {
const { i18n } = useTranslation();
const languages = [
{ code: 'en', name: 'English', flag: '🇺🇸' },
{ code: 'ar', name: 'العربية', flag: '🇸🇦' }
];
const changeLanguage = (langCode: string) => {
i18n.changeLanguage(langCode);
// Update document direction for Arabic
document.documentElement.dir = langCode === 'ar' ? 'rtl' : 'ltr';
document.documentElement.lang = langCode;
};
const currentLanguage = languages.find(lang => lang.code === i18n.language) || languages[0];
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm" className="gap-2">
<Languages className="h-4 w-4" />
<span className="hidden sm:inline">{currentLanguage.flag} {currentLanguage.name}</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{languages.map((language) => (
<DropdownMenuItem
key={language.code}
onClick={() => changeLanguage(language.code)}
className={`gap-2 ${i18n.language === language.code ? 'bg-accent' : ''}`}
>
<span>{language.flag}</span>
<span>{language.name}</span>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
);
}
+36
View File
@@ -0,0 +1,36 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
// Import translation files
import enTranslations from './locales/en.json';
import arTranslations from './locales/ar.json';
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources: {
en: {
translation: enTranslations
},
ar: {
translation: arTranslations
}
},
lng: 'en', // default language
fallbackLng: 'en',
debug: false,
interpolation: {
escapeValue: false, // React already does escaping
},
detection: {
order: ['localStorage', 'navigator', 'htmlTag'],
lookupLocalStorage: 'language',
caches: ['localStorage'],
},
});
export default i18n;
+199
View File
@@ -0,0 +1,199 @@
{
"common": {
"save": "حفظ",
"cancel": "إلغاء",
"delete": "حذف",
"edit": "تعديل",
"add": "إضافة",
"create": "إنشاء",
"update": "تحديث",
"search": "بحث",
"filter": "تصفية",
"loading": "جاري التحميل...",
"error": "خطأ",
"success": "نجح",
"confirm": "تأكيد",
"back": "رجوع",
"next": "التالي",
"previous": "السابق",
"close": "إغلاق",
"open": "فتح",
"yes": "نعم",
"no": "لا"
},
"navigation": {
"dashboard": "لوحة التحكم",
"tasks": "المهام",
"finances": "الماليات",
"ai": "المساعد الذكي",
"voice": "الصوت",
"analytics": "التحليلات",
"settings": "الإعدادات",
"logout": "تسجيل الخروج",
"profile": "الملف الشخصي"
},
"tasks": {
"title": "المهام",
"createTask": "إنشاء مهمة",
"editTask": "تعديل المهمة",
"taskTitle": "عنوان المهمة",
"description": "الوصف",
"priority": "الأولوية",
"dueDate": "تاريخ الاستحقاق",
"status": "الحالة",
"category": "الفئة",
"project": "المشروع",
"assignee": "المكلف",
"tags": "العلامات",
"subtasks": "المهام الفرعية",
"attachments": "المرفقات",
"timeTracking": "تتبع الوقت",
"completed": "مكتمل",
"inProgress": "قيد التنفيذ",
"todo": "للعمل",
"high": "عالية",
"medium": "متوسطة",
"low": "منخفضة",
"addSubtask": "إضافة مهمة فرعية",
"addAttachment": "إضافة مرفق",
"startTimer": "بدء المؤقت",
"stopTimer": "إيقاف المؤقت",
"totalTime": "إجمالي الوقت",
"noTasks": "لا توجد مهام",
"taskCreated": "تم إنشاء المهمة بنجاح",
"taskUpdated": "تم تحديث المهمة بنجاح",
"taskDeleted": "تم حذف المهمة بنجاح"
},
"finances": {
"title": "الماليات",
"overview": "نظرة عامة مالية",
"income": "الدخل",
"expenses": "المصروفات",
"balance": "الرصيد",
"budget": "الميزانية",
"categories": "الفئات",
"transactions": "المعاملات",
"recurring": "متكررة",
"reports": "التقارير",
"addTransaction": "إضافة معاملة",
"editTransaction": "تعديل المعاملة",
"amount": "المبلغ",
"type": "النوع",
"date": "التاريخ",
"description": "الوصف",
"category": "الفئة",
"tags": "العلامات",
"recurring": "متكررة",
"frequency": "التكرار",
"budgetPlanning": "تخطيط الميزانية",
"budgetLimit": "حد الميزانية",
"budgetUsed": "الميزانية المستخدمة",
"budgetRemaining": "الميزانية المتبقية",
"monthlyBudget": "الميزانية الشهرية",
"yearlyBudget": "الميزانية السنوية",
"exportData": "تصدير البيانات",
"billReminders": "تذكيرات الفواتير",
"upcomingBills": "الفواتير القادمة",
"overdueBills": "الفواتير المتأخرة"
},
"ai": {
"title": "المساعد الذكي",
"chat": "المحادثة",
"history": "تاريخ المحادثات",
"dailyJoke": "نكتة اليوم",
"insights": "رؤى ذكية",
"askAnything": "اسأل عن أي شيء...",
"generating": "جاري إنشاء الرد...",
"voiceCommand": "أمر صوتي",
"personalizedResponse": "رد شخصي",
"conversationSaved": "تم حفظ المحادثة",
"noHistory": "لا يوجد تاريخ محادثات"
},
"voice": {
"title": "الأوامر الصوتية",
"listening": "جاري الاستماع...",
"notListening": "غير مفعل",
"startListening": "بدء الاستماع",
"stopListening": "إيقاف الاستماع",
"voiceSettings": "إعدادات الصوت",
"language": "اللغة",
"microphone": "الميكروفون",
"speakers": "السماعات",
"voiceCommands": "الأوامر المتاحة",
"customCommands": "أوامر مخصصة",
"voiceTraining": "تدريب الصوت",
"accuracy": "الدقة",
"confidence": "الثقة",
"transcript": "النص المكتوب",
"voiceActivated": "مفعل صوتياً",
"speakingRate": "معدل الكلام",
"voicePitch": "نبرة الصوت",
"voiceVolume": "مستوى الصوت"
},
"settings": {
"title": "الإعدادات",
"general": "عام",
"appearance": "المظهر",
"language": "اللغة",
"notifications": "الإشعارات",
"privacy": "الخصوصية",
"account": "الحساب",
"advanced": "متقدم",
"theme": "السمة",
"lightMode": "الوضع الفاتح",
"darkMode": "الوضع الداكن",
"systemTheme": "سمة النظام",
"fontSize": "حجم الخط",
"accessibility": "إمكانية الوصول",
"dataExport": "تصدير البيانات",
"dataImport": "استيراد البيانات",
"changePassword": "تغيير كلمة المرور",
"deleteAccount": "حذف الحساب",
"backup": "نسخ احتياطي",
"restore": "استعادة"
},
"auth": {
"login": "تسجيل الدخول",
"register": "تسجيل جديد",
"logout": "تسجيل الخروج",
"email": "البريد الإلكتروني",
"password": "كلمة المرور",
"confirmPassword": "تأكيد كلمة المرور",
"firstName": "الاسم الأول",
"lastName": "الاسم الأخير",
"username": "اسم المستخدم",
"forgotPassword": "نسيت كلمة المرور؟",
"resetPassword": "إعادة تعيين كلمة المرور",
"loginSuccess": "تم تسجيل الدخول بنجاح",
"registerSuccess": "تم التسجيل بنجاح",
"invalidCredentials": "بيانات اعتماد غير صحيحة",
"passwordMismatch": "كلمات المرور غير متطابقة"
},
"dashboard": {
"title": "لوحة التحكم",
"welcome": "مرحباً",
"quickStats": "إحصائيات سريعة",
"recentTasks": "المهام الأخيرة",
"recentTransactions": "المعاملات الأخيرة",
"todaysTasks": "مهام اليوم",
"weeklyOverview": "نظرة أسبوعية",
"monthlyOverview": "نظرة شهرية",
"productivity": "الإنتاجية",
"financial": "الملخص المالي"
},
"errors": {
"general": "حدث خطأ",
"networkError": "خطأ في الشبكة",
"unauthorized": "وصول غير مصرح",
"notFound": "غير موجود",
"serverError": "خطأ في الخادم",
"validationError": "خطأ في التحقق",
"tryAgain": "حاول مرة أخرى"
},
"success": {
"saved": "تم الحفظ بنجاح",
"deleted": "تم الحذف بنجاح",
"updated": "تم التحديث بنجاح",
"created": "تم الإنشاء بنجاح"
}
}
+199
View File
@@ -0,0 +1,199 @@
{
"common": {
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"edit": "Edit",
"add": "Add",
"create": "Create",
"update": "Update",
"search": "Search",
"filter": "Filter",
"loading": "Loading...",
"error": "Error",
"success": "Success",
"confirm": "Confirm",
"back": "Back",
"next": "Next",
"previous": "Previous",
"close": "Close",
"open": "Open",
"yes": "Yes",
"no": "No"
},
"navigation": {
"dashboard": "Dashboard",
"tasks": "Tasks",
"finances": "Finances",
"ai": "AI Assistant",
"voice": "Voice",
"analytics": "Analytics",
"settings": "Settings",
"logout": "Logout",
"profile": "Profile"
},
"tasks": {
"title": "Tasks",
"createTask": "Create Task",
"editTask": "Edit Task",
"taskTitle": "Task Title",
"description": "Description",
"priority": "Priority",
"dueDate": "Due Date",
"status": "Status",
"category": "Category",
"project": "Project",
"assignee": "Assignee",
"tags": "Tags",
"subtasks": "Subtasks",
"attachments": "Attachments",
"timeTracking": "Time Tracking",
"completed": "Completed",
"inProgress": "In Progress",
"todo": "To Do",
"high": "High",
"medium": "Medium",
"low": "Low",
"addSubtask": "Add Subtask",
"addAttachment": "Add Attachment",
"startTimer": "Start Timer",
"stopTimer": "Stop Timer",
"totalTime": "Total Time",
"noTasks": "No tasks found",
"taskCreated": "Task created successfully",
"taskUpdated": "Task updated successfully",
"taskDeleted": "Task deleted successfully"
},
"finances": {
"title": "Finances",
"overview": "Financial Overview",
"income": "Income",
"expenses": "Expenses",
"balance": "Balance",
"budget": "Budget",
"categories": "Categories",
"transactions": "Transactions",
"recurring": "Recurring",
"reports": "Reports",
"addTransaction": "Add Transaction",
"editTransaction": "Edit Transaction",
"amount": "Amount",
"type": "Type",
"date": "Date",
"description": "Description",
"category": "Category",
"tags": "Tags",
"recurring": "Recurring",
"frequency": "Frequency",
"budgetPlanning": "Budget Planning",
"budgetLimit": "Budget Limit",
"budgetUsed": "Budget Used",
"budgetRemaining": "Budget Remaining",
"monthlyBudget": "Monthly Budget",
"yearlyBudget": "Yearly Budget",
"exportData": "Export Data",
"billReminders": "Bill Reminders",
"upcomingBills": "Upcoming Bills",
"overdueBills": "Overdue Bills"
},
"ai": {
"title": "AI Assistant",
"chat": "Chat",
"history": "Conversation History",
"dailyJoke": "Daily Joke",
"insights": "AI Insights",
"askAnything": "Ask me anything...",
"generating": "Generating response...",
"voiceCommand": "Voice Command",
"personalizedResponse": "Personalized Response",
"conversationSaved": "Conversation saved",
"noHistory": "No conversation history"
},
"voice": {
"title": "Voice Commands",
"listening": "Listening...",
"notListening": "Not Listening",
"startListening": "Start Listening",
"stopListening": "Stop Listening",
"voiceSettings": "Voice Settings",
"language": "Language",
"microphone": "Microphone",
"speakers": "Speakers",
"voiceCommands": "Available Commands",
"customCommands": "Custom Commands",
"voiceTraining": "Voice Training",
"accuracy": "Accuracy",
"confidence": "Confidence",
"transcript": "Transcript",
"voiceActivated": "Voice Activated",
"speakingRate": "Speaking Rate",
"voicePitch": "Voice Pitch",
"voiceVolume": "Voice Volume"
},
"settings": {
"title": "Settings",
"general": "General",
"appearance": "Appearance",
"language": "Language",
"notifications": "Notifications",
"privacy": "Privacy",
"account": "Account",
"advanced": "Advanced",
"theme": "Theme",
"lightMode": "Light Mode",
"darkMode": "Dark Mode",
"systemTheme": "System Theme",
"fontSize": "Font Size",
"accessibility": "Accessibility",
"dataExport": "Data Export",
"dataImport": "Data Import",
"changePassword": "Change Password",
"deleteAccount": "Delete Account",
"backup": "Backup",
"restore": "Restore"
},
"auth": {
"login": "Login",
"register": "Register",
"logout": "Logout",
"email": "Email",
"password": "Password",
"confirmPassword": "Confirm Password",
"firstName": "First Name",
"lastName": "Last Name",
"username": "Username",
"forgotPassword": "Forgot Password?",
"resetPassword": "Reset Password",
"loginSuccess": "Login successful",
"registerSuccess": "Registration successful",
"invalidCredentials": "Invalid credentials",
"passwordMismatch": "Passwords do not match"
},
"dashboard": {
"title": "Dashboard",
"welcome": "Welcome",
"quickStats": "Quick Stats",
"recentTasks": "Recent Tasks",
"recentTransactions": "Recent Transactions",
"todaysTasks": "Today's Tasks",
"weeklyOverview": "Weekly Overview",
"monthlyOverview": "Monthly Overview",
"productivity": "Productivity",
"financial": "Financial Summary"
},
"errors": {
"general": "An error occurred",
"networkError": "Network error",
"unauthorized": "Unauthorized access",
"notFound": "Not found",
"serverError": "Server error",
"validationError": "Validation error",
"tryAgain": "Please try again"
},
"success": {
"saved": "Successfully saved",
"deleted": "Successfully deleted",
"updated": "Successfully updated",
"created": "Successfully created"
}
}
+1
View File
@@ -1,5 +1,6 @@
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import App from "./App"; import App from "./App";
import "./index.css"; import "./index.css";
import "./i18n/config";
createRoot(document.getElementById("root")!).render(<App />); createRoot(document.getElementById("root")!).render(<App />);
+111 -12
View File
@@ -53,6 +53,9 @@
"express": "^4.21.2", "express": "^4.21.2",
"express-session": "^1.18.1", "express-session": "^1.18.1",
"framer-motion": "^11.13.1", "framer-motion": "^11.13.1",
"i18next": "^25.2.1",
"i18next-browser-languagedetector": "^8.1.0",
"i18next-http-backend": "^3.0.2",
"input-otp": "^1.4.2", "input-otp": "^1.4.2",
"lucide-react": "^0.453.0", "lucide-react": "^0.453.0",
"memorystore": "^1.6.7", "memorystore": "^1.6.7",
@@ -66,6 +69,7 @@
"react-day-picker": "^8.10.1", "react-day-picker": "^8.10.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-hook-form": "^7.55.0", "react-hook-form": "^7.55.0",
"react-i18next": "^15.5.2",
"react-icons": "^5.4.0", "react-icons": "^5.4.0",
"react-resizable-panels": "^2.1.7", "react-resizable-panels": "^2.1.7",
"recharts": "^2.15.2", "recharts": "^2.15.2",
@@ -385,12 +389,10 @@
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.27.0", "version": "7.27.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
"integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==",
"dependencies": { "license": "MIT",
"regenerator-runtime": "^0.14.0"
},
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@@ -4225,6 +4227,15 @@
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/cross-fetch": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
"integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==",
"license": "MIT",
"dependencies": {
"node-fetch": "^2.6.12"
}
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.6", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -5808,6 +5819,15 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/html-parse-stringify": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
"license": "MIT",
"dependencies": {
"void-elements": "3.1.0"
}
},
"node_modules/http-errors": { "node_modules/http-errors": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@@ -5833,6 +5853,55 @@
"ms": "^2.0.0" "ms": "^2.0.0"
} }
}, },
"node_modules/i18next": {
"version": "25.2.1",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-25.2.1.tgz",
"integrity": "sha512-+UoXK5wh+VlE1Zy5p6MjcvctHXAhRwQKCxiJD8noKZzIXmnAX8gdHX5fLPA3MEVxEN4vbZkQFy8N0LyD9tUqPw==",
"funding": [
{
"type": "individual",
"url": "https://locize.com"
},
{
"type": "individual",
"url": "https://locize.com/i18next.html"
},
{
"type": "individual",
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
}
],
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.27.1"
},
"peerDependencies": {
"typescript": "^5"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/i18next-browser-languagedetector": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.1.0.tgz",
"integrity": "sha512-mHZxNx1Lq09xt5kCauZ/4bsXOEA2pfpwSoU11/QTJB+pD94iONFwp+ohqi///PwiFvjFOxe1akYCdHyFo1ng5Q==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.2"
}
},
"node_modules/i18next-http-backend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.2.tgz",
"integrity": "sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g==",
"license": "MIT",
"dependencies": {
"cross-fetch": "4.0.0"
}
},
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.4.24", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -7395,6 +7464,32 @@
"react": "^16.8.0 || ^17 || ^18 || ^19" "react": "^16.8.0 || ^17 || ^18 || ^19"
} }
}, },
"node_modules/react-i18next": {
"version": "15.5.2",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.5.2.tgz",
"integrity": "sha512-ePODyXgmZQAOYTbZXQn5rRsSBu3Gszo69jxW6aKmlSgxKAI1fOhDwSu6bT4EKHciWPKQ7v7lPrjeiadR6Gi+1A==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.25.0",
"html-parse-stringify": "^3.0.1"
},
"peerDependencies": {
"i18next": ">= 23.2.3",
"react": ">= 16.8.0",
"typescript": "^5"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
},
"typescript": {
"optional": true
}
}
},
"node_modules/react-icons": { "node_modules/react-icons": {
"version": "5.4.0", "version": "5.4.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.4.0.tgz", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.4.0.tgz",
@@ -7597,11 +7692,6 @@
"decimal.js-light": "^2.4.1" "decimal.js-light": "^2.4.1"
} }
}, },
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"node_modules/regexparam": { "node_modules/regexparam": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/regexparam/-/regexparam-3.0.0.tgz", "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-3.0.0.tgz",
@@ -8719,7 +8809,7 @@
"version": "5.6.3", "version": "5.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"dev": true, "devOptional": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
@@ -9385,6 +9475,15 @@
"@esbuild/win32-x64": "0.21.5" "@esbuild/win32-x64": "0.21.5"
} }
}, },
"node_modules/void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/web-streams-polyfill": { "node_modules/web-streams-polyfill": {
"version": "4.0.0-beta.3", "version": "4.0.0-beta.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
+4
View File
@@ -55,6 +55,9 @@
"express": "^4.21.2", "express": "^4.21.2",
"express-session": "^1.18.1", "express-session": "^1.18.1",
"framer-motion": "^11.13.1", "framer-motion": "^11.13.1",
"i18next": "^25.2.1",
"i18next-browser-languagedetector": "^8.1.0",
"i18next-http-backend": "^3.0.2",
"input-otp": "^1.4.2", "input-otp": "^1.4.2",
"lucide-react": "^0.453.0", "lucide-react": "^0.453.0",
"memorystore": "^1.6.7", "memorystore": "^1.6.7",
@@ -68,6 +71,7 @@
"react-day-picker": "^8.10.1", "react-day-picker": "^8.10.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-hook-form": "^7.55.0", "react-hook-form": "^7.55.0",
"react-i18next": "^15.5.2",
"react-icons": "^5.4.0", "react-icons": "^5.4.0",
"react-resizable-panels": "^2.1.7", "react-resizable-panels": "^2.1.7",
"recharts": "^2.15.2", "recharts": "^2.15.2",