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:
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -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": "تم الإنشاء بنجاح"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,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 />);
|
||||||
|
|||||||
Generated
+111
-12
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user