diff --git a/scripts/generate-locales.js b/scripts/generate-locales.js new file mode 100644 index 0000000..c27e4be --- /dev/null +++ b/scripts/generate-locales.js @@ -0,0 +1,856 @@ +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) + +const LOCALES_DIR = path.resolve(__dirname, '../src/locales') + +export const enLocale = { + navigation: { + brand: 'Aqila Admin Panel', + brandShort: 'Aqila', + dashboard: 'Dashboard', + dashboardTitle: 'Admin Dashboard', + tours: 'Tours', + allTours: 'All Tours', + ongoingTours: 'Ongoing Tours', + tourOrders: 'Orders & Bookings', + services: 'Services Center', + simcard: 'SIM Card', + zayerGuide: 'Zayer Guide', + exchange: 'Online Exchange', + duas: 'Duas & Ziyarat', + duasList: 'Duas & Ziyarat', + categories: 'Categories', + cities: 'Holy Cities', + store: 'Massoumah Store', + storeProducts: 'Products', + storeCategories: 'Categories', + costEstimate: 'Cost Estimate', + support: 'Support Center', + supporters: 'Support Staff', + faq: 'FAQ', + faqCategories: 'Subject Categories', + faqQuestions: 'Questions & Answers', + consultant: 'Support', + billing: 'Billing & Finance', + settings: 'Settings', + logout: 'Logout', + soon: 'Soon', + adminRole: 'System Administrator', + }, + topbar: { + serverOnline: 'Server is Online', + serverOffline: 'Server Disconnected', + theme: 'Theme', + language: 'Language', + selectLanguage: 'Select System Language', + search: 'Search...', + }, + auth: { + loginTitle: 'Login to Admin Dashboard', + loginDescription: 'Enter your credentials to access the management portal', + demoBoxTitle: 'Demo Ready Account:', + autoFill: 'Auto Fill', + emailLabel: 'Account Email', + emailPlaceholder: 'you@example.com', + passwordLabel: 'Password', + passwordPlaceholder: '••••••••', + showPassword: 'Show password', + hidePassword: 'Hide password', + submitLogin: 'Login to Account', + loggingIn: 'Logging in...', + loginFailed: 'Login failed. Please try again.', + footerNote: 'Supports custom templates and direct API connection', + }, + dashboard: { + welcome: 'Welcome, {name}', + readyBadge: 'Ready for Development', + welcomeSubtitle: 'Aqila admin panel is ready for your new widgets, tables, and modules.', + cleanBoardTitle: 'Clean Dashboard Ready for Development', + cleanBoardDescription: + 'All mock data and dummy UIs have been cleaned up. You can build your new modules using UI components and connect directly to Aqila database and backend.', + }, + serverStatus: { + title: 'System & Server Status', + description: 'Server connection summary, API configuration, and account details', + backendStatus: 'Django Server Status (Backend)', + connected: 'Online & Connected', + checking: 'Checking...', + disconnected: 'Disconnected', + recheck: 'Re-check', + rechecking: 'Testing...', + recheckFull: 'Re-check Server', + apiConfigTitle: 'API & Server Configuration', + targetServer: 'Target Server', + apiPrefix: 'API Prefix', + authHeader: 'Auth Header', + currentUserTitle: 'Current User Account', + roleSuperuser: 'Super Administrator (Superuser)', + roleStaff: 'System Administrator (Staff)', + roleUser: 'User', + fullName: 'Full Name:', + email: 'Email:', + userId: 'User ID:', + connectionStable: 'Connection to server is stable', + connectionTesting: 'Testing connection...', + connectionUnreachable: 'Server is unreachable', + }, + globalSearch: { + placeholder: 'Search pages, actions, or commands... (Ctrl+K)', + empty: 'No results found.', + systemSections: 'System Sections', + toggleTheme: 'Toggle Theme', + toggleThemeDesc: 'Switch theme between dark and light mode', + logoutAccount: 'Logout from account', + }, + common: { + save: 'Save Changes', + cancel: 'Cancel', + confirm: 'Confirm', + delete: 'Delete', + edit: 'Edit', + close: 'Close', + back: 'Back', + refresh: 'Refresh', + loading: 'Loading...', + status: 'Status', + actions: 'Actions', + all: 'All', + active: 'Active', + inactive: 'Inactive', + noData: 'No records found.', + pageOf: 'Page {current} of {total}', + success: 'Operation completed successfully.', + error: 'Server connection error.', + retry: 'Retry', + previous: 'Previous', + next: 'Next', + showing: 'Showing', + to: 'to', + of: 'of', + testSyncNotice: 'This is a test message for language synchronization verification.', + deleteConfirmTitle: 'Are you sure you want to delete this item?', + deleteConfirmDesc: 'This action cannot be undone and the record will be permanently deleted.', + yesDelete: 'Yes, Delete', + deleting: 'Deleting...', + filter: 'Filter', + search: 'Search...', + export: 'Export', + import: 'Import', + create: 'Create', + add: 'Add', + view: 'View', + details: 'Details', + operations: 'Operations', + enabled: 'Enabled', + disabled: 'Disabled', + unknown: 'Unknown', + days: '{count} Days', + dayOne: '1 Day', + }, + tours: { + title: 'Tour Management', + subtitle: 'Live monitoring of sales, travel itineraries, passengers, pricing, and multi-language translations', + totalRegistered: '{count} Tours Registered', + ongoingTitle: 'Ongoing Tours', + ongoingSubtitle: 'Live tracking of ongoing trips, daily itinerary schedules, current stage position, and passengers', + totalOngoing: '{count} Active Ongoing Tours', + ordersTitle: 'Tour Orders & Bookings', + ordersSubtitle: 'Order tracking, payment monitoring, document validation, and traveler deposit receipts', + totalOrders: 'Total Registered Orders', + approvedBookings: 'Approved Bookings', + pendingReviewOrders: 'Pending Receipt Review', + searchOrdersPlaceholder: 'Search orders (Passenger name, phone, order ID)...', + filterSaleStatus: 'Sale Status', + filterTripStatus: 'Trip Status', + filterOrderStatus: 'Order Status', + createTour: 'Create New Tour', + tourDetails: 'Tour Details', + manageTranslations: 'Manage Translations (5 Languages)', + tabOverview: 'Specifications', + tabItinerary: 'Itinerary', + tabPassengers: 'Passengers', + tabFeatures: 'Amenities', + saleAvailable: 'Available', + saleSoldOut: 'Sold Out', + saleNoShow: 'Hidden', + saleUnknown: 'Unknown', + tripPending: 'Upcoming', + tripTraveling: 'Ongoing', + tripFinished: 'Completed', + orderApproved: 'Approved', + orderAwaitingPayment: 'Awaiting Payment', + orderPending: 'Pending Receipt Review', + orderRejected: 'Rejected', + orderExpired: 'Expired', + countryIraq: 'Iraq', + countryIran: 'Iran', + countrySaudi: 'Saudi Arabia', + countrySyria: 'Syria', + countryOman: 'Oman', + }, + services: { + title: 'Services Center', + subtitle: 'Management of pilgrimage services, SIM cards, Zayer guide, exchange, store, and religious rituals', + allServices: 'All Services', + searchPlaceholder: 'Search services...', + simcardTitle: 'SIM Card', + simcardDesc: 'Internet packages, international SIM cards, and traveler orders (Zain, Asiacell, Korek, STC)', + zayerGuideTitle: 'Zayer Guide', + zayerGuideDesc: 'Holy shrines, historical sites, hospitals, mawakib, and city locations', + exchangeTitle: 'Online Exchange', + exchangeDesc: 'Exchange rates, currency requests, cash reserves, and traveler transfers (USD, IQD, IRR)', + duasTitle: 'Duas & Ziyarat', + duasDesc: 'Mafatih al-Jinan bank, audios, translations, and authentic ziyarats', + categoriesTitle: 'Categories', + categoriesDesc: 'Management of religious, shrine, store, and app content categories', + citiesTitle: 'Holy Cities', + citiesDesc: 'Pilgrimage cities (Najaf, Karbala, Kadhimiya, Samarra, Mashhad, Qom, Mecca, Medina)', + storeTitle: 'Massoumah Store', + storeDesc: 'Massoumah online store products, souvenirs, inventory, and order fulfillment', + costEstimateTitle: 'Cost Estimate', + costEstimateDesc: 'Estimation of total pilgrimage trip costs according to season, services, and hotel class', + supportTitle: 'Support', + supportDesc: 'Direct ticketing system, user requests, and operator responses', + faqTitle: 'FAQ', + faqDesc: 'Frequently asked questions bank, travel guides, and religious rules', + }, + billing: { + title: 'Invoices & Billing Management', + description: 'Review bank receipts, approve or reject payments, and track invoices across Aqila services', + totalInvoices: 'Total Invoices', + pendingReview: 'Pending Receipt Review', + awaitingPayment: 'Awaiting Customer Payment', + approvedPayments: 'Approved Payments', + rejectedOrExpired: 'Rejected / Expired', + searchPlaceholder: 'Search invoices (Customer name, email, card number, invoice ID)...', + statusFilter: 'Invoice Status', + serviceFilter: 'Service Type', + clearFilters: 'Clear Filters', + invoiceList: 'Invoice List', + customer: 'Customer', + amount: 'Amount', + service: 'Service', + date: 'Issue Date', + receipt: 'Payment Receipt', + hasReceipt: 'View Receipt', + noReceipt: 'None', + approve: 'Approve Payment', + reject: 'Reject Invoice', + rejectTitle: 'Reject Invoice', + rejectReason: 'Rejection Reason / Bank Receipt:', + rejectReasonPlaceholder: 'e.g., Unreadable receipt, amount mismatch, invalid transaction reference...', + rejectNotice: 'This explanation will be displayed to the traveler in their invoice details.', + submitReject: 'Submit & Reject Invoice', + submitting: 'Submitting...', + statusPending: 'Pending Receipt Review', + statusAwaiting: 'Awaiting Payment', + statusApproved: 'Payment Approved', + statusRejected: 'Rejected', + statusExpired: 'Expired', + invoice: 'Invoice', + invoices: 'Invoices', + id: 'ID', + viewDetails: 'View Details', + viewReceipt: 'View Receipt', + noReceiptUploaded: 'No receipt uploaded', + serviceTour: 'Pilgrimage Tours', + serviceSimcard: 'SIM Card', + serviceShop: 'Massoumah Store', + serviceExchange: 'Exchange (Tasreef)', + serviceCustomTrip: 'Custom Trip', + allStatuses: 'All Statuses', + allServices: 'All Services', + noFactorsFound: 'No invoices found.', + noFactorsFilter: 'No records match current filters. You can clear filters.', + noFactorsEmpty: 'No invoices have been issued in the system yet.', + confirmClearReceipt: 'Are you sure you want to remove the uploaded receipt image?', + receiptClearedSuccess: 'Payment receipt cleared successfully.', + tabAll: 'All Transactions', + tabTour: 'Tour Orders & Bookings', + tabSimcard: 'SIM Cards', + tabExchange: 'Currency & Exchange', + tabShop: 'Souvenir Store', + tabCustomTrip: 'Custom Trips', + coreTourBadge: 'Primary Core', + liveStatus: 'Live Status', + quickFilter: 'Status Filter', + }, + languages: { + fa: 'فارسی', + ar: 'العربية', + en: 'English', + }, +} + +export const faLocale = { + navigation: { + brand: 'پنل مدیریت عقیله', + brandShort: 'عقیله', + dashboard: 'داشبورد', + dashboardTitle: 'داشبورد مدیریت', + tours: 'تورها', + allTours: 'فهرست همه تورها', + ongoingTours: 'تورهای در حال برگزاری', + tourOrders: 'سفارشات و رزروها', + services: 'مرکز خدمات (همه)', + simcard: 'سیمکارت (Simcard)', + zayerGuide: 'راهنمای زائر (Zayer Guide)', + exchange: 'صرافی آنلاین (Exchange)', + duas: 'ادعیه و زیارات (Duas)', + duasList: 'ادعیه و زیارات', + categories: 'دستهبندیها', + cities: 'شهرهای زیارتی', + store: 'فروشگاه معصومه (Store)', + storeProducts: 'محصولات', + storeCategories: 'دستهبندیها', + costEstimate: 'تخمین هزینه (Cost Estimate)', + support: 'پشتیبانی (Support)', + supporters: 'پشتیبانها (Supporters)', + faq: 'سوالات متداول (FAQ)', + faqCategories: 'دستهبندیهای موضوعی', + faqQuestions: 'پرسش و پاسخها', + consultant: 'پشتیبانی (Support)', + billing: 'صورتحسابها و مالی', + settings: 'تنظیمات', + logout: 'خروج از سیستم', + soon: 'بهزودی', + adminRole: 'مدیر کل سیستم', + }, + topbar: { + serverOnline: 'سرور متصل است', + serverOffline: 'قطع ارتباط با سرور', + theme: 'تغییر تم', + language: 'تغییر زبان', + selectLanguage: 'انتخاب زبان سامانه', + search: 'جستجو...', + }, + auth: { + loginTitle: 'ورود به پنل مدیریت و داشبورد', + loginDescription: 'برای دسترسی به پرتال مدیریت، اطلاعات ورود خود را وارد نمایید', + demoBoxTitle: 'حساب آزمایشی آماده:', + autoFill: 'پر کردن خودکار', + emailLabel: 'ایمیل حساب کاربری', + emailPlaceholder: 'you@example.com', + passwordLabel: 'رمز عبور', + passwordPlaceholder: '••••••••', + showPassword: 'نمایش رمز', + hidePassword: 'مخفیکردن رمز', + submitLogin: 'ورود به حساب کاربری', + loggingIn: 'در حال ورود...', + loginFailed: 'ورود ناموفق بود. دوباره تلاش کنید.', + footerNote: 'پشتیبانی از قالبهای سفارشی و اتصال مستقیم به API', + }, + dashboard: { + welcome: 'خوش آمدید، {name}', + readyBadge: 'آماده توسعه', + welcomeSubtitle: 'پنل مدیریت عقیله آماده اضافه کردن ویجتها، جداول و ماژولهای جدید شماست.', + cleanBoardTitle: 'داشبورد تمیز و آماده توسعه', + cleanBoardDescription: + 'تمام اطلاعات و یوآیهای ساختگی حذف شدند. میتوانید ماژولهای جدید خود را با کامپوننتهای آماده UI پیادهسازی و مستقیماً به دیتابیس و بکاند عقیله متصل نمایید.', + }, + serverStatus: { + title: 'وضعیت سیستم و سرور', + description: 'خلاصه ارتباط سرور، پیکربندی API و اطلاعات حساب', + backendStatus: 'وضعیت سرور جنگو (Backend)', + connected: 'آنلاین و متصل', + checking: 'در حال بررسی...', + disconnected: 'قطع ارتباط', + recheck: 'بررسی مجدد', + rechecking: 'در حال تست...', + recheckFull: 'بررسی مجدد سرور', + apiConfigTitle: 'پیکربندی API و سرور', + targetServer: 'سرور هدف', + apiPrefix: 'پیشوند API', + authHeader: 'هدر احراز هویت', + currentUserTitle: 'اطلاعات حساب کاربری جاری', + roleSuperuser: 'مدیر ارشد (Superuser)', + roleStaff: 'مدیر سیستم (Staff)', + roleUser: 'کاربر', + fullName: 'نام و نام خانوادگی:', + email: 'ایمیل:', + userId: 'شناسه کاربری (ID):', + connectionStable: 'ارتباط با سرور پایدار است', + connectionTesting: 'در حال آزمایش اتصال...', + connectionUnreachable: 'سرور در دسترس نیست', + }, + globalSearch: { + placeholder: 'جستجوی صفحات، عملیاتها یا فرمانها... (Ctrl+K)', + empty: 'هیچ نتیجهای یافت نشد.', + systemSections: 'بخشهای سیستم', + toggleTheme: 'تغییر پوسته (Theme)', + toggleThemeDesc: 'تغییر تم به حالت تیره یا روشن', + logoutAccount: 'خروج از حساب کاربری', + }, + common: { + save: 'ذخیره تغییرات', + cancel: 'انصراف', + confirm: 'تایید', + delete: 'حذف', + edit: 'ویرایش', + close: 'بستن', + back: 'بازگشت', + refresh: 'بهروزرسانی', + loading: 'در حال بارگذاری...', + status: 'وضعیت', + actions: 'عملیات', + all: 'همه', + active: 'فعال', + inactive: 'غیرفعال', + noData: 'موردی برای نمایش یافت نشد.', + pageOf: 'صفحه {current} از {total}', + success: 'عملیات با موفقیت انجام شد.', + error: 'خطا در برقراری ارتباط با سرور.', + retry: 'تلاش مجدد', + previous: 'قبلی', + next: 'بعدی', + showing: 'نمایش', + to: 'تا', + of: 'از', + testSyncNotice: 'این یک پیام آزمایشی برای تست هماهنگی زبانهاست', + deleteConfirmTitle: 'آیا از حذف این مورد اطمینان دارید؟', + deleteConfirmDesc: 'این عملیات غیرقابل بازگشت است و رکورد مورد نظر به طور کامل حذف خواهد شد.', + yesDelete: 'بله، حذف شود', + deleting: 'در حال حذف...', + filter: 'فیلتر', + search: 'جستجو...', + export: 'خروجی اکسل', + import: 'ورود اطلاعات', + create: 'ایجاد جدید', + add: 'افزودن', + view: 'مشاهده', + details: 'جزئیات', + operations: 'عملیات', + enabled: 'فعال', + disabled: 'غیرفعال', + unknown: 'نامشخص', + days: '{count} روز', + dayOne: '۱ روز', + }, + tours: { + title: 'مدیریت تورها', + subtitle: 'پایش وضعیت زنده فروش، برنامههای سفر، مسافران، اطلاعات قیمتی و ترجمههای چندزبانه', + totalRegistered: '{count} تور ثبتشده', + ongoingTitle: 'تورهای در حال برگزاری', + ongoingSubtitle: 'پایش زنده وضعیت سفرهای جاری، زمانبندی روزانه (Itinerary)، موقعیت مرحله فعلی و وضعیت مسافران', + totalOngoing: '{count} تور فعال و در جریان', + ordersTitle: 'سفارشات و رزروهای تور', + ordersSubtitle: 'پیگیری سفارشات، نظارت بر پرداختها و اعتبارسنجی مدارک و فیشهای واریزی مسافران', + totalOrders: 'کل سفارشات ثبتشده', + approvedBookings: 'رزروهای تأییدشده', + pendingReviewOrders: 'در انتظار بررسی فیش', + searchOrdersPlaceholder: 'جستجوی سفارشات (نام مسافر، شماره تماس، کد سفارش)...', + filterSaleStatus: 'وضعیت فروش', + filterTripStatus: 'وضعیت سفر', + filterOrderStatus: 'وضعیت سفارش', + createTour: 'ایجاد تور جدید', + tourDetails: 'جزئیات تور', + manageTranslations: 'مدیریت ترجمهها (۵ زبان)', + tabOverview: 'مشخصات', + tabItinerary: 'برنامه سفر', + tabPassengers: 'مسافران', + tabFeatures: 'امکانات', + saleAvailable: 'در دسترس', + saleSoldOut: 'تکمیل ظرفیت', + saleNoShow: 'عدم نمایش', + saleUnknown: 'نامشخص', + tripPending: 'در انتظار اجرا', + tripTraveling: 'در حال برگزاری', + tripFinished: 'پایانیافته', + orderApproved: 'تایید شده', + orderAwaitingPayment: 'در انتظار پرداخت', + orderPending: 'در انتظار بررسی فیش', + orderRejected: 'رد شده', + orderExpired: 'منقضی شده', + countryIraq: 'عراق', + countryIran: 'ایران', + countrySaudi: 'عربستان', + countrySyria: 'سوریه', + countryOman: 'عمان', + }, + services: { + title: 'مرکز خدمات', + subtitle: 'مدیریت جامع خدمات زیارتی، سیمکارت، راهنمای زائر، صرافی، فروشگاه و مناسک', + allServices: 'همه خدمات', + searchPlaceholder: 'جستجوی خدمات...', + simcardTitle: 'سیمکارت', + simcardDesc: 'مدیریت بستههای اینترنت، سیمکارتهای بینالمللی و سفارشهای زائرین (زین، آسیاسل، کورک، STC)', + zayerGuideTitle: 'راهنمای زائر', + zayerGuideDesc: 'بانک جامع اماکن متبرکه، راهنمای اماکن تاریخی، بیمارستانها، مواکب و موقعیت مکانی شهرها', + exchangeTitle: 'صرافی آنلاین', + exchangeDesc: 'نرخ لحظهای ارزها، درخواستهای ارزی، مدیریت موجودی نقدی و حوالههای زائران (دلار، دینار، تومان)', + duasTitle: 'ادعیه و زیارات', + duasDesc: 'بانک مفاتیحالجنان، ادعیه صوتی، ترجمه و شرح متون ادعیه و زیارات معتبر', + categoriesTitle: 'دستهبندیها', + categoriesDesc: 'مدیریت دستهبندیهای موضوعی خدمات، اماکن، فروشگاه و محتواهای اپلیکیشن', + citiesTitle: 'شهرهای زیارتی', + citiesDesc: 'شهرهای زیارتی (نجف، کربلا، کاظمین، سامرا، مشهد، قم، مکه، مدینه)', + storeTitle: 'فروشگاه معصومه', + storeDesc: 'محصولات فروشگاه آنلاین معصومه، سوغات زیارتی، مدیریت انبار و سفارشات خرید', + costEstimateTitle: 'تخمین هزینه', + costEstimateDesc: 'محاسبه آنلاین هزینههای سفر انفرادی و خانوادگی به تفکیک فصل، خدمات و سطح هتل', + supportTitle: 'پشتیبانی', + supportDesc: 'سیستم تیکتینگ مستقیم، پشتیبانی از زائران و مدیریت پاسخگویی اپراتورها', + faqTitle: 'سوالات متداول', + faqDesc: 'بانک پرسش و پاسخهای پرتکرار زائرین، راهنمای سفر و احکام شرعی', + }, + billing: { + title: 'مدیریت صورتحسابها و فاکتورها', + description: 'بررسی فیشهای بانکی، تایید یا رد پرداختها و پیگیری ریز فاکتورهای ۵ سرویس سامانه عقیله', + totalInvoices: 'کل صورتحسابها', + pendingReview: 'در انتظار بررسی فیش', + awaitingPayment: 'در انتظار پرداخت مشتری', + approvedPayments: 'پرداختهای تایید شده', + rejectedOrExpired: 'رد شده / منقضی', + searchPlaceholder: 'جستجو در صورتحسابها (نام مشتری، ایمیل، شماره کارت، شماره فاکتور)...', + statusFilter: 'وضعیت صورتحساب', + serviceFilter: 'نوع سرویس', + clearFilters: 'پاک کردن فیلترها', + invoiceList: 'فهرست صورتحسابها', + customer: 'مشتری', + amount: 'مبلغ', + service: 'سرویس', + date: 'تاریخ صدور', + receipt: 'فیش پرداخت', + hasReceipt: 'مشاهده فیش', + noReceipt: 'ندارد', + approve: 'تایید پرداخت', + reject: 'رد فاکتور', + rejectTitle: 'رد صورتحساب', + rejectReason: 'علت رد فاکتور / فیش بانکی:', + rejectReasonPlaceholder: 'مثال: تصویر فیش ناخواناست، مبلغ فیش با فاکتور همخوانی ندارد، کد رهگیری نامعتبر است...', + rejectNotice: 'این توضیح به مسافر در بخش وضعیت فاکتور نمایش داده خواهد شد.', + submitReject: 'ثبت و رد فاکتور', + submitting: 'در حال ثبت...', + statusPending: 'در انتظار بررسی فیش', + statusAwaiting: 'در انتظار پرداخت', + statusApproved: 'پرداخت تایید شده', + statusRejected: 'رد شده', + statusExpired: 'منقضی شده', + invoice: 'صورتحساب', + invoices: 'صورتحسابها', + id: 'شناسه', + viewDetails: 'مشاهده جزئیات', + viewReceipt: 'مشاهده فیش', + noReceiptUploaded: 'فیشی بارگذاری نشده است', + serviceTour: 'تور زیارتی', + serviceSimcard: 'سیمکارت', + serviceShop: 'فروشگاه معصومه', + serviceExchange: 'صرافی (تصریف)', + serviceCustomTrip: 'سفر اختصاصی', + allStatuses: 'همه وضعیتها', + allServices: 'همه سرویسها', + noFactorsFound: 'هیچ صورتحسابی یافت نشد.', + noFactorsFilter: 'رکوردی با فیلترهای فعلی همخوانی ندارد. میتوانید فیلترها را پاک کنید.', + noFactorsEmpty: 'تاکنون هیچ صورتحسابی در سیستم صادر نشده است.', + confirmClearReceipt: 'آیا از حذف تصویر فیش بارگذاری شده اطمینان دارید؟', + receiptClearedSuccess: 'تصویر فیش پرداخت با موفقیت حذف شد.', + tabAll: 'کل تراکنشها', + tabTour: 'سفارشات و رزرو تور', + tabSimcard: 'سیمکارت', + tabExchange: 'ارز و صرافی', + tabShop: 'فروشگاه سوغات', + tabCustomTrip: 'سفرهای اختصاصی', + coreTourBadge: 'هسته اصلی', + liveStatus: 'وضعیت زنده', + quickFilter: 'فیلتر وضعیت', + }, + languages: { + fa: 'فارسی', + ar: 'العربية', + en: 'English', + }, +} + +export const arLocale = { + navigation: { + brand: 'لوحة تحكم عقيلة', + brandShort: 'عقيلة', + dashboard: 'الرئيسية', + dashboardTitle: 'لوحة التحكم', + tours: 'الرحلات', + allTours: 'جميع الرحلات', + ongoingTours: 'الرحلات الجارية', + tourOrders: 'الطلبات والحجوزات', + services: 'مركز الخدمات (الكل)', + simcard: 'شريحة الاتصال (Simcard)', + zayerGuide: 'دليل الزائر (Zayer Guide)', + exchange: 'الصرافة الإلكترونية (Exchange)', + duas: 'الأدعية والزيارات (Duas)', + duasList: 'الأدعية والزيارات', + categories: 'التصنيفات', + cities: 'المدن المقدسة', + store: 'متجر معصومة (Store)', + storeProducts: 'المنتجات', + storeCategories: 'التصنيفات', + costEstimate: 'تقدير التكلفة (Cost Estimate)', + support: 'الدعم الفني (Support)', + supporters: 'فريق الدعم (Supporters)', + faq: 'الأسئلة الشائعة (FAQ)', + faqCategories: 'التصنيفات الموضوعية', + faqQuestions: 'الأسئلة والأجوبة', + consultant: 'الدعم الفني (Support)', + billing: 'الفواتير والمالية', + settings: 'الإعدادات', + logout: 'تسجيل الخروج', + soon: 'قريباً', + adminRole: 'مدير النظام العام', + }, + topbar: { + serverOnline: 'الخادم متصل', + serverOffline: 'انقطع الاتصال بالخادم', + theme: 'المظهر', + language: 'اللغة', + selectLanguage: 'اختر لغة النظام', + search: 'بحث...', + }, + auth: { + loginTitle: 'تسجيل الدخول إلى لوحة الإدارة', + loginDescription: 'أدخل بيانات الاعتماد الخاصة بك للوصول إلى بوابة الإدارة', + demoBoxTitle: 'حساب تجريبي جاهز:', + autoFill: 'تعبئة تلقائية', + emailLabel: 'البريد الإلكتروني للحساب', + emailPlaceholder: 'you@example.com', + passwordLabel: 'كلمة المرور', + passwordPlaceholder: '••••••••', + showPassword: 'عرض كلمة المرور', + hidePassword: 'إخفاء كلمة المرور', + submitLogin: 'تسجيل الدخول إلى الحساب', + loggingIn: 'جاري تسجيل الدخول...', + loginFailed: 'فشل تسجيل الدخول. يرجى المحاولة مرة أخرى.', + footerNote: 'يدعم القوالب المخصصة والاتصال المباشر بواجهة برمجة التطبيقات (API)', + }, + dashboard: { + welcome: 'مرحباً، {name}', + readyBadge: 'جاهز للتطوير', + welcomeSubtitle: 'لوحة تحكم عقيلة جاهزة لإضافة أدواتك وجداولك ووحداتك الجديدة.', + cleanBoardTitle: 'لوحة تحكم نظيفة وجاهزة للتطوير', + cleanBoardDescription: + 'تم مسح جميع البيانات والواجهات الوهمية. يمكنك بناء وحداتك الجديدة باستخدام مكونات واجهة المستخدم الجاهزة والاتصال مباشرة بقاعدة البيانات وخادم عقيلة.', + }, + serverStatus: { + title: 'حالة النظام والخادم', + description: 'ملخص اتصال الخادم، وتكوين واجهة برمجة التطبيقات وبيانات الحساب', + backendStatus: 'حالة خادم جانغو (Backend)', + connected: 'متصل ونشط', + checking: 'جاري الفحص...', + disconnected: 'انقطع الاتصال', + recheck: 'إعادة الفحص', + rechecking: 'جاري الاختبار...', + recheckFull: 'إعادة فحص الخادم', + apiConfigTitle: 'تكوين واجهة برمجة التطبيقات والخادم', + targetServer: 'الخادم الهدف', + apiPrefix: 'بادئة API', + authHeader: 'ترويسة المصادقة', + currentUserTitle: 'بيانات الحساب الحالي', + roleSuperuser: 'المدير العام (Superuser)', + roleStaff: 'مدير النظام (Staff)', + roleUser: 'مستخدم', + fullName: 'الاسم الكامل:', + email: 'البريد الإلكتروني:', + userId: 'معرف المستخدم (ID):', + connectionStable: 'الاتصال بالخادم مستقر', + connectionTesting: 'جاري اختبار الاتصال...', + connectionUnreachable: 'الخادم غير متاح', + }, + globalSearch: { + placeholder: 'البحث في الصفحات والعمليات والأوامر... (Ctrl+K)', + empty: 'لم يتم العثور على أي نتائج.', + systemSections: 'أقسام النظام', + toggleTheme: 'تغيير السمة (Theme)', + toggleThemeDesc: 'تبديل المظهر بين الوضع الداكن والفاتح', + logoutAccount: 'تسجيل الخروج من الحساب', + }, + common: { + save: 'حفظ التغييرات', + cancel: 'إلغاء', + confirm: 'تأكيد', + delete: 'حذف', + edit: 'تعديل', + close: 'إغلاق', + back: 'رجوع', + refresh: 'تحديث', + loading: 'جاري التحميل...', + status: 'الحالة', + actions: 'الإجراءات', + all: 'الكل', + active: 'نشط', + inactive: 'غير نشط', + noData: 'لا توجد بيانات للعرض.', + pageOf: 'صفحة {current} من {total}', + success: 'تمت العملية بنجاح.', + error: 'حدث خطأ في الاتصال بالخادم.', + retry: 'إعادة المحاولة', + previous: 'السابق', + next: 'التالي', + showing: 'عرض', + to: 'إلى', + of: 'من', + testSyncNotice: 'هذه رسالة تجريبية لاختبار مزامنة اللغات.', + deleteConfirmTitle: 'هل أنت متأكد من حذف هذا العنصر؟', + deleteConfirmDesc: 'هذا الإجراء لا يمكن التراجع عنه وسيتم حذف السجل نهائياً.', + yesDelete: 'نعم، احذف', + deleting: 'جاري الحذف...', + filter: 'تصفية', + search: 'بحث...', + export: 'تصدير إكسل', + import: 'استيراد بيانات', + create: 'إنشاء جديد', + add: 'إضافة', + view: 'عرض', + details: 'تفاصيل', + operations: 'العمليات', + enabled: 'مفعل', + disabled: 'معطل', + unknown: 'غير محدد', + days: '{count} أيام', + dayOne: 'يوم واحد', + }, + tours: { + title: 'إدارة الرحلات', + subtitle: 'متابعة مباشرة لحالة المبيعات وجداول الرحلات والمسافرين وبيانات الأسعار والترجمات متعددة اللغات', + totalRegistered: '{count} رحلة مسجلة', + ongoingTitle: 'الرحلات الجارية', + ongoingSubtitle: 'متابعة مباشرة للرحلات الحالية والجدول اليومي والموقع الحالي وحالة المسافرين', + totalOngoing: '{count} رحلة نشطة وجارية', + ordersTitle: 'طلبات وحجوزات الرحلات', + ordersSubtitle: 'متابعة الطلبات ومراقبة المدفوعات والتحقق من وثائق وإيصالات التحويل للمسافرين', + totalOrders: 'إجمالي الطلبات المسجلة', + approvedBookings: 'الحجوزات المؤكدة', + pendingReviewOrders: 'بانتظار مراجعة الإيصال', + searchOrdersPlaceholder: 'البحث في الطلبات (اسم المسافر، الهاتف، معرف الطلب)...', + filterSaleStatus: 'حالة البيع', + filterTripStatus: 'حالة السفر', + filterOrderStatus: 'حالة الطلب', + createTour: 'إنشاء رحلة جديدة', + tourDetails: 'تفاصيل الرحلة', + manageTranslations: 'إدارة الترجمات (٥ لغات)', + tabOverview: 'المواصفات', + tabItinerary: 'برنامج الرحلة', + tabPassengers: 'المسافرون', + tabFeatures: 'المميزات', + saleAvailable: 'متاح', + saleSoldOut: 'اكتمل العدد', + saleNoShow: 'مخفي', + saleUnknown: 'غير محدد', + tripPending: 'بانتظار الانطلاق', + tripTraveling: 'جارية حالياً', + tripFinished: 'منتهية', + orderApproved: 'تمت الموافقة', + orderAwaitingPayment: 'بانتظار الدفع', + orderPending: 'بانتظار مراجعة الإيصال', + orderRejected: 'مرفوض', + orderExpired: 'منتهي الصلاحية', + countryIraq: 'العراق', + countryIran: 'إيران', + countrySaudi: 'السعودية', + countrySyria: 'سوريا', + countryOman: 'عمان', + }, + services: { + title: 'مركز الخدمات', + subtitle: 'إدارة شاملة لخدمات الزوار والشرائح ودليل الزائر والصرافة والمتجر والمناسك', + allServices: 'جميع الخدمات', + searchPlaceholder: 'البحث في الخدمات...', + simcardTitle: 'شريحة الاتصال', + simcardDesc: 'إدارة باقات الإنترنت والشرائح الدولية وطلبات الزوار (زين، آسیاسیل، كورك، STC)', + zayerGuideTitle: 'دليل الزائر', + zayerGuideDesc: 'دليل شامل للعتبات المقدسة والمعالم التاريخية والمستشفيات والمواكب ومواقع المدن', + exchangeTitle: 'الصرافة الإلكترونية', + exchangeDesc: 'أسعار الصرف المباشرة وطلبات العملات وإدارة السيولة النقدية وحوالات الزوار (دولار، دينار، تومان)', + duasTitle: 'الأدعية والزيارات', + duasDesc: 'بنك مفاتيح الجنان والتسجيلات الصوتية والترجمات وشروح الأدعية والزيارات المعتبرة', + categoriesTitle: 'التصنيفات', + categoriesDesc: 'إدارة التصنيفات الموضوعية للخدمات والأماكن والمتجر ومحتويات التطبيق', + citiesTitle: 'المدن المقدسة', + citiesDesc: 'المدن المقدسة (النجف، كربلاء، الكاظمية، سامراء، مشهد، قم، مكة، المدينة)', + storeTitle: 'متجر معصومة', + storeDesc: 'منتجات متجر معصومة الإلكتروني وهدايا الزيارة وإدارة المخزون وطلبات الشراء', + costEstimateTitle: 'تقدير التكلفة', + costEstimateDesc: 'حساب تكاليف الرحلات الفردية والعائلية حسب الموسم والخدمات ومستوى الفندق', + supportTitle: 'الدعم الفني', + supportDesc: 'نظام التذاكر المباشر ودعم الزوار وإدارة استجابات فريق العمل', + faqTitle: 'الأسئلة الشائعة', + faqDesc: 'بنك الأسئلة المتكررة للزوار وإرشادات السفر والأحكام الشرعية', + }, + billing: { + title: 'إدارة الفواتير والمدفوعات', + description: 'مراجعة إيصالات التحويل البنكي، واعتماد أو رفض المدفوعات ومتابعة تفاصيل فواتير خدمات عقيلة', + totalInvoices: 'إجمالي الفواتير', + pendingReview: 'بانتظار مراجعة الإيصال', + awaitingPayment: 'بانتظار دفع العميل', + approvedPayments: 'المدفوعات المعتمدة', + rejectedOrExpired: 'مرفوض / منتهي الصلاحية', + searchPlaceholder: 'البحث في الفواتير (اسم العميل، البريد، رقم البطاقة، رقم الفاتورة)...', + statusFilter: 'حالة الفاتورة', + serviceFilter: 'نوع الخدمة', + clearFilters: 'إعادة ضبط التصفية', + invoiceList: 'قائمة الفواتير', + customer: 'العميل', + amount: 'المبلغ', + service: 'الخدمة', + date: 'تاريخ الإصدار', + receipt: 'إيصال الدفع', + hasReceipt: 'عرض الإيصال', + noReceipt: 'لا يوجد', + approve: 'اعتماد الدفع', + reject: 'رفض الفاتورة', + rejectTitle: 'رفض الفاتورة', + rejectReason: 'سبب رفض الفاتورة / الإيصال البنكي:', + rejectReasonPlaceholder: 'مثال: صورة الإيصال غير واضحة، المبلغ غير متطابق، الرقم المرجعي غير صالح...', + rejectNotice: 'سيظهر هذا الشرح للمسافر في تفاصيل الفاتورة.', + submitReject: 'تأكيد ورفض الفاتورة', + submitting: 'جاري الإرسال...', + statusPending: 'بانتظار مراجعة الإيصال', + statusAwaiting: 'بانتظار الدفع', + statusApproved: 'تم اعتماد الدفع', + statusRejected: 'مرفوض', + statusExpired: 'منتهي الصلاحية', + invoice: 'فاتورة', + invoices: 'الفواتير', + id: 'المعرف', + viewDetails: 'عرض التفاصيل', + viewReceipt: 'عرض الإيصال', + noReceiptUploaded: 'لم يتم رفع إيصال', + serviceTour: 'رحلة زيارة', + serviceSimcard: 'شريحة اتصال', + serviceShop: 'متجر معصومة', + serviceExchange: 'صرافة (تصريف)', + serviceCustomTrip: 'رحلة مخصصة', + allStatuses: 'جميع الحالات', + allServices: 'جميع الخدمات', + noFactorsFound: 'لم يتم العثور على فواتير.', + noFactorsFilter: 'لا توجد نتائج تطابق معايير التصفية الحالية.', + noFactorsEmpty: 'لم يتم إصدار أي فواتير في النظام بعد.', + confirmClearReceipt: 'هل أنت متأكد من حذف صورة الإيصال المرفوعة؟', + receiptClearedSuccess: 'تم حذف صورة الإيصال بنجاح.', + tabAll: 'جميع المعاملات', + tabTour: 'طلبات وحجوزات الرحلات', + tabSimcard: 'شرائح الاتصال', + tabExchange: 'العملات والصرافة', + tabShop: 'متجر الهدايا', + tabCustomTrip: 'الرحلات الخاصة', + coreTourBadge: 'الخدمة الأساسية', + liveStatus: 'الحالة المباشرة', + quickFilter: 'تصفية الحالة', + }, + languages: { + fa: 'فارسی', + ar: 'العربية', + en: 'English', + }, +} + +function writeJson(filePath, data) { + fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8') + console.log(`✓ Generated: ${filePath}`) +} + +writeJson(path.join(LOCALES_DIR, 'en.json'), enLocale) +writeJson(path.join(LOCALES_DIR, 'fa.json'), faLocale) +writeJson(path.join(LOCALES_DIR, 'ar.json'), arLocale) + +console.log('\n🎉 Successfully synchronized all 3 locale files with en.json as Source of Truth!') diff --git a/src/components/layout/ServerStatusDialog.tsx b/src/components/layout/ServerStatusDialog.tsx index 0f30b5c..070b74c 100644 --- a/src/components/layout/ServerStatusDialog.tsx +++ b/src/components/layout/ServerStatusDialog.tsx @@ -14,6 +14,7 @@ import { Ic } from '@/icons' import { useServerHealthStore } from '@/stores/server-health' import { useAuthStore } from '@/stores/auth' import { cn } from '@/lib/utils' +import { useTranslation } from '@/i18n' interface ServerStatusDialogProps { open: boolean @@ -23,6 +24,7 @@ interface ServerStatusDialogProps { export default function ServerStatusDialog({ open, onOpenChange }: ServerStatusDialogProps) { const health = useServerHealthStore() const user = useAuthStore((s) => s.user) + const { t } = useTranslation() const [isRefreshing, setIsRefreshing] = useState(false) const handleRefresh = async () => { @@ -49,10 +51,10 @@ export default function ServerStatusDialog({ open, onOpenChange }: ServerStatusD
ورود به پنل مدیریت و داشبورد
+{t('auth.loginDescription')}
- پشتیبانی از قالبهای سفارشی و اتصال مستقیم به API + {t('auth.footerNote')}
- پنل مدیریت عقیله آماده اضافه کردن ویجتها، جداول و ماژولهای جدید شماست. -
-- {t('common.testSyncNotice')} + {t('dashboard.welcomeSubtitle')}
- تمام اطلاعات و یوآیهای ساختگی حذف شدند. میتوانید ماژولهای جدید خود را با کامپوننتهای آماده UI پیادهسازی و مستقیماً به دیتابیس و بکاند عقیله متصل نمایید. + {t('dashboard.cleanBoardDescription')}
diff --git a/src/features/global-search/GlobalSearchDialog.tsx b/src/features/global-search/GlobalSearchDialog.tsx index 87a153e..1365ccd 100644 --- a/src/features/global-search/GlobalSearchDialog.tsx +++ b/src/features/global-search/GlobalSearchDialog.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react' +import { useEffect, useMemo } from 'react' import { useNavigate } from 'react-router-dom' import { Ic } from '@/icons' import { @@ -11,13 +11,17 @@ import { CommandSeparator, } from '@/components/ui/command' import { useGlobalSearchStore } from '@/stores/global-search' -import { navigationConfig } from '@/config/navigation' +import { getNavigationConfig } from '@/config/navigation' import { useLogout } from '@/features/auth/use-auth' +import { useTranslation } from '@/i18n' export default function GlobalSearchDialog() { const { open, setOpen } = useGlobalSearchStore() const navigate = useNavigate() const logout = useLogout() + const { t } = useTranslation() + + const navConfig = useMemo(() => getNavigationConfig(t), [t]) // میانبر صفحهکلید Cmd+K یا Ctrl+K useEffect(() => { @@ -38,15 +42,15 @@ export default function GlobalSearchDialog() { return (+ {currentService.description} +
- {currentService.description} -
- شهرهای استاتیک اپلیکیشن عقیله؛ جهت تخصیص دستهبندیها و ادعیه از شناسههای زیر استفاده میشود. -
-هیچ شهری با این مشخصات یافت نشد
دعا یا زیارتی با این مشخصات یافت نشد
@@ -635,9 +907,18 @@ export function DuasServiceView() { paginatedDuas.map((dua) => { const secondaryTitle = getSecondaryTitle(dua) const cities = getDuaCities(dua) + const isDuaActive = dua.is_active !== false + const isToggling = togglingDuaIndex === dua.index return ( -- {location.description} +
+ {displayDesc}
میتوانید فیلترها را ریست کنید یا با کلیک روی «افزودن مکان جدید» موقعیت مکانی جدیدی به سامانه بیفزایید.
@@ -529,7 +492,6 @@ export function ZayerGuideServiceView({ service }: ZayerGuideServiceViewProps) { setSelectedCitySlug('ALL') setSelectedCountryCode('ALL') setSelectedCategorySlug('ALL') - setStatusFilter('ALL') }} className="text-xs rounded-xl" > @@ -537,19 +499,22 @@ export function ZayerGuideServiceView({ service }: ZayerGuideServiceViewProps) {{item.address}
- )} + ) : item.description ? ( ++ {item.description} +
+ ) : null}