This commit is contained in:
root
2026-05-22 02:43:13 -04:00
parent 191fb3cb4e
commit 99c429d69c
21 changed files with 276 additions and 94 deletions
@@ -128,7 +128,7 @@ export default function AdminBillingPage() {
eyebrow: 'Plateforme',
mrr: 'MRR (MAD)',
active: 'Actifs',
trialing: 'Essai',
trialing: 'En essai',
pastDue: 'En retard',
cancelled: 'Annulés',
company: 'Entreprise',
@@ -155,9 +155,9 @@ export default function AdminBillingPage() {
provider: 'Fournisseur',
paidAt: 'Payé le',
date: 'Date',
invoiceNo: 'Facture',
invoiceNo: 'Facture',
download: 'PDF',
cancelAtEnd: 'Annulé en fin de période',
cancelAtEnd: 'Sera annulé en fin de période',
},
ar: {
title: 'الفوترة',
@@ -193,7 +193,7 @@ export default function AdminBillingPage() {
date: 'التاريخ',
invoiceNo: 'رقم الفاتورة',
download: 'PDF',
cancelAtEnd: 'يُلغى في نهاية الفترة',
cancelAtEnd: 'سيُلغى في نهاية الفترة',
},
}[language]
@@ -58,7 +58,7 @@ export default function AdminCompaniesPage() {
},
ar: {
title: 'الشركات',
search: 'ابحث بالاسم أو الـ slug…',
search: 'ابحث بالاسم أو بالمُعرّف المختصر…',
loading: 'جارٍ التحميل…',
empty: 'لم يتم العثور على شركات',
company: 'الشركة',
@@ -66,7 +66,7 @@ export default function AdminCompaniesPage() {
status: 'الحالة',
plan: 'الخطة',
fleet: 'الأسطول',
vehicles: 'سيارات',
vehicles: 'مركبة',
view: 'عرض',
suspend: 'تعليق',
reactivate: 'إعادة التفعيل',
+7 -7
View File
@@ -27,20 +27,20 @@ export default function AdminDashboardPage() {
},
fr: {
kpis: ['Entreprises totales', 'Entreprises actives', 'Locataires totaux', 'Réservations totales'],
platformOverview: 'Vue plateforme',
platformOverview: 'Vue densemble de la plateforme',
cards: [
['Entreprises', 'Lister, rechercher, suspendre, réactiver et revoir l’état des abonnements.', 'Voir tout →'],
['Locataires', 'Flux de support pour bloquer et débloquer les locataires marketplace.', 'Voir tout →'],
['Journaux daudit', 'Trace complète de chaque action admin sur la plateforme.', 'Voir les journaux →'],
['Entreprises', 'Lister, rechercher, suspendre, réactiver et consulter l’état des abonnements.', 'Voir tout →'],
['Locataires', 'Gérer lassistance liée au blocage et au déblocage des locataires de la marketplace.', 'Voir tout →'],
['Journaux daudit', 'Consulter la trace complète de chaque action dadministration sur la plateforme.', 'Voir les journaux →'],
],
},
ar: {
kpis: ['إجمالي الشركات', 'الشركات النشطة', 'إجمالي المستأجرين', 'إجمالي الحجوزات'],
platformOverview: 'نظرة عامة على المنصة',
cards: [
['الشركات', 'اعرض وابحث وعلّق وأعد التفعيل وراجع حالة الاشتراك.', 'عرض الكل ←'],
['المستأجرون', 'مسارات دعم لحظر وفك حظر مستأجري السوق.', 'عرض الكل ←'],
['سجلات التدقيق', 'تتبع كامل لكل إجراء إداري تم على المنصة.', 'عرض السجلات ←'],
['الشركات', 'اعرض الشركات وابحث عنها وعلّقها وأعد تفعيلها وراجع حالة الاشتراك.', 'عرض الكل ←'],
['المستأجرون', 'إدارة طلبات الدعم الخاصة بحظر مستأجري السوق وفك الحظر عنهم.', 'عرض الكل ←'],
['سجلات التدقيق', 'مراجعة السجل الكامل لكل إجراء إداري تم على المنصة.', 'عرض السجلات ←'],
],
},
}[language]
@@ -36,10 +36,10 @@ export default function AdminRentersPage() {
title: 'Locataires',
search: 'Rechercher des locataires…',
name: 'Nom',
email: 'Email',
email: 'E-mail',
phone: 'Téléphone',
status: 'Statut',
joined: 'Inscrit',
joined: 'Date dinscription',
loading: 'Chargement…',
empty: 'Aucun locataire trouvé',
blocked: 'Bloqué',
@@ -54,7 +54,7 @@ export default function AdminRentersPage() {
email: 'البريد الإلكتروني',
phone: 'الهاتف',
status: 'الحالة',
joined: 'تاريخ الانضمام',
joined: 'تاريخ التسجيل',
loading: 'جارٍ التحميل…',
empty: 'لم يتم العثور على مستأجرين',
blocked: 'محظور',
+5 -5
View File
@@ -12,7 +12,7 @@
],
"heroKicker": "RentalDriveGo",
"heroTitle": "Marketplace discovery with a sharper front door.",
"heroBody": "Rental companies run private operations, renters browse a shared marketplace, and every booking still lands on the companys own branded checkout.",
"heroBody": "Rental companies run private operations, renters browse a shared marketplace, and every booking ends on the companys own branded checkout.",
"startTrial": "Start free trial",
"exploreVehicles": "Explore vehicles",
"surfaceLabel": "Marketplace surface",
@@ -23,11 +23,11 @@
"brandedFlows": "Branded booking flows",
"multiTenant": "Multi-tenant operations",
"companyKicker": "Operator workflow",
"companyTitle": "Control inventory, offers, billing, and staff from one command layer.",
"companyTitle": "Manage inventory, offers, billing, and staff from one control layer.",
"companyBody": "Publish inventory once, decide what appears publicly, and keep contracts, payments, and reporting isolated per company.",
"renterKicker": "Renter experience",
"renterTitle": "Let renters compare quickly, then hand them off to the right company site.",
"renterBody": "The marketplace works as a discovery engine, not a dead-end aggregator. Search here, reserve there, pay direct.",
"renterBody": "The marketplace works as a discovery engine, not a dead-end aggregator. Search here, reserve there, and pay direct.",
"pillars": [
{
"title": "Unified publishing",
@@ -83,8 +83,8 @@
],
"stepLabel": "Step",
"readyKicker": "Ready to launch",
"readyTitle": "A marketplace homepage should sell the system in seconds.",
"readyBody": "Use the marketplace to attract demand, then move renters into a branded experience that keeps pricing, payments, and trust attached to your company.",
"readyTitle": "The marketplace homepage should explain the product in seconds.",
"readyBody": "Use the marketplace to attract demand, then move renters into a branded experience that keeps pricing, payments, and trust tied to your company.",
"viewPricing": "View pricing",
"createWorkspace": "Create workspace"
},
@@ -182,8 +182,8 @@ export default function BillingPage() {
cancel: 'Annuler',
savingPayment: 'Enregistrement…',
savePayment: 'Enregistrer le paiement',
chargeHelp: 'Paiement enregistre un règlement sur le solde de la réservation.',
depositHelp: 'Dépôt enregistre lencaissement du dépôt de garantie remboursable.',
chargeHelp: 'Le paiement enregistre un règlement sur le solde de la réservation.',
depositHelp: 'Le dépôt enregistre lencaissement du dépôt de garantie remboursable.',
invalidAmount: 'Saisissez un montant valide dans la limite du solde restant.',
paymentActionDisabled: 'Aucun solde dû',
paymentsRecorded: (count: number) => `${count} paiement(s)`,
@@ -257,7 +257,7 @@ export default function BillingPage() {
cancel: 'إلغاء',
savingPayment: 'جارٍ الحفظ…',
savePayment: 'حفظ الدفعة',
chargeHelp: 'الدفعة تسجل مبلغاً مستلماً على رصيد الحجز.',
chargeHelp: 'تسجّل الدفعة مبلغاً مستلماً على رصيد الحجز.',
depositHelp: 'العربون يسجل مبلغ التأمين القابل للاسترداد المستلم.',
invalidAmount: 'أدخل مبلغاً صحيحاً ضمن الرصيد المتبقي.',
paymentActionDisabled: 'لا يوجد رصيد مستحق',
@@ -22,7 +22,7 @@ export default function CustomersPage() {
const copy = {
en: {
title: 'Customers',
subtitle: 'Company-scoped CRM with license validation and risk flags.',
subtitle: 'A company CRM with license validation and risk flags.',
customer: 'Customer',
contact: 'Contact',
license: 'License',
@@ -36,13 +36,13 @@ export default function CustomersPage() {
},
fr: {
title: 'Clients',
subtitle: 'CRM de lentreprise avec validation de permis et indicateurs de risque.',
subtitle: 'CRM de lentreprise avec validation des permis et indicateurs de risque.',
customer: 'Client',
contact: 'Contact',
license: 'Permis',
flags: 'Signalements',
imageUploaded: 'Image téléversée',
imageMissing: 'Pas dimage',
imageMissing: 'Aucune image',
noPhone: 'Pas de téléphone',
flagged: 'Signalé',
clear: 'Aucun risque',
@@ -50,16 +50,16 @@ export default function CustomersPage() {
},
ar: {
title: 'العملاء',
subtitle: 'نظام CRM خاص بالشركة مع التحقق من الرخصة ومؤشرات المخاطر.',
subtitle: 'نظام إدارة عملاء خاص بالشركة مع التحقق من الرخص ومؤشرات المخاطر.',
customer: 'العميل',
contact: 'التواصل',
license: 'الرخصة',
flags: 'الإشارات',
flags: 'العلامات',
imageUploaded: 'تم رفع الصورة',
imageMissing: 'لا توجد صورة',
noPhone: 'لا يوجد هاتف',
flagged: 'مُعلّم',
clear: 'سليم',
flagged: 'تم تمييزه',
clear: 'لا توجد مخاطر',
empty: 'لا يوجد عملاء حتى الآن.',
},
}[language]
@@ -93,7 +93,7 @@ export default function OnlineReservationsPage() {
refresh: 'Actualiser',
pendingApproval: 'En attente de validation',
loading: 'Chargement…',
allCaughtUp: 'Tout est à jour, aucune demande en attente.',
allCaughtUp: 'Tout est à jour. Aucune demande en attente.',
customer: 'Client',
vehicle: 'Véhicule',
dates: 'Dates',
@@ -102,9 +102,9 @@ export default function OnlineReservationsPage() {
},
ar: {
title: 'الحجوزات الإلكترونية',
subtitle: 'طلبات مقدمة من العملاء عبر السوق. قم بالتأكيد أو الرفض لكل طلب.',
subtitle: 'طلبات أرسلها العملاء عبر السوق. أكّد كل طلب أو ارفضه.',
refresh: 'تحديث',
pendingApproval: 'بانتظار الموافقة',
pendingApproval: 'في انتظار الموافقة',
loading: 'جارٍ التحميل…',
allCaughtUp: 'لا توجد طلبات معلقة حالياً.',
customer: 'العميل',
@@ -40,7 +40,7 @@ export default function ReportsPage() {
const copy = {
en: {
title: 'Reports',
subtitle: 'Accountant-ready exports with insurance, additional-driver, and pricing-rule totals.',
subtitle: 'Accountant-ready exports with totals for insurance, additional drivers, and pricing rules.',
exportCsv: 'Export CSV',
exporting: 'Exporting…',
bookings: 'Bookings',
@@ -60,15 +60,15 @@ export default function ReportsPage() {
},
fr: {
title: 'Rapports',
subtitle: 'Exports prêts pour le comptable avec totaux assurance, conducteurs supplémentaires et règles tarifaires.',
exportCsv: 'Exporter CSV',
subtitle: 'Exports prêts pour la comptabilité avec les totaux dassurance, de conducteurs supplémentaires et de règles tarifaires.',
exportCsv: 'Exporter en CSV',
exporting: 'Export en cours…',
bookings: 'Réservations',
rental: 'Location',
insurance: 'Assurance',
drivers: 'Conducteurs',
discounts: 'Remises',
collected: 'Collecté',
collected: 'Encaissé',
reservation: 'Réservation',
vehicle: 'Véhicule',
period: 'Période',
@@ -80,7 +80,7 @@ export default function ReportsPage() {
},
ar: {
title: 'التقارير',
subtitle: 'تصدير جاهز للمحاسبة مع إجماليات التأمين والسائقين الإضافيين وقواعد التسعير.',
subtitle: 'ملفات تصدير جاهزة للمحاسبة تشمل إجماليات التأمين والسائقين الإضافيين وقواعد التسعير.',
exportCsv: 'تصدير CSV',
exporting: 'جارٍ التصدير…',
bookings: 'الحجوزات',
@@ -13,7 +13,7 @@ interface Props {
const copy = {
en: {
title: 'Invite a team member',
subtitle: "They'll receive an email invitation to join your dashboard",
subtitle: "They'll receive an email invitation to join your workspace.",
firstName: 'First name',
lastName: 'Last name',
email: 'Email address',
@@ -27,7 +27,7 @@ const copy = {
{
value: 'MANAGER' as const,
label: 'Manager',
description: 'Full fleet ops — no billing or team settings',
description: 'Full fleet operations, without billing or team settings',
permissions: ['Vehicles', 'Reservations', 'CRM', 'Offers', 'Reports', 'License approval'],
},
{
@@ -40,10 +40,10 @@ const copy = {
},
fr: {
title: 'Inviter un membre',
subtitle: "Il recevra un email d'invitation pour rejoindre votre tableau de bord",
subtitle: "Cette personne recevra un e-mail d'invitation pour rejoindre votre espace de travail.",
firstName: 'Prénom',
lastName: 'Nom',
email: 'Adresse email',
email: 'Adresse e-mail',
role: 'Rôle',
cancel: 'Annuler',
sending: 'Envoi…',
@@ -54,8 +54,8 @@ const copy = {
{
value: 'MANAGER' as const,
label: 'Manager',
description: 'Opérations complètes sans facturation ni paramètres équipe',
permissions: ['Véhicules', 'Réservations', 'CRM', 'Offres', 'Rapports', 'Validation permis'],
description: 'Opérations complètes, sans accès à la facturation ni aux paramètres de léquipe',
permissions: ['Véhicules', 'Réservations', 'CRM', 'Offres', 'Rapports', 'Validation des permis'],
},
{
value: 'AGENT' as const,
@@ -67,7 +67,7 @@ const copy = {
},
ar: {
title: 'دعوة عضو في الفريق',
subtitle: 'سيتلقى بريداً إلكترونياً للانضمام إلى لوحة التحكم',
subtitle: 'سيتلقى رسالة بريد إلكتروني للانضمام إلى مساحة العمل.',
firstName: 'الاسم الأول',
lastName: 'اسم العائلة',
email: 'البريد الإلكتروني',
@@ -81,7 +81,7 @@ const copy = {
{
value: 'MANAGER' as const,
label: 'مدير',
description: 'عمليات أسطول كاملة — بدون الفوترة أو إعدادات الفريق',
description: 'صلاحيات تشغيل كاملة للأسطول، من دون الفوترة أو إعدادات الفريق',
permissions: ['المركبات', 'الحجوزات', 'CRM', 'العروض', 'التقارير', 'الموافقة على الرخص'],
},
{
@@ -68,9 +68,9 @@ const copy = {
],
agentNotes: ['', '', '', '', '', '', 'Own only', '', '', '', 'Notes only', '', '', '', '', '', '', '', '', ''],
},
fr: {
heading: 'Permissions par rôle',
subtitle: 'Ce que chaque rôle peut faire dans le tableau de bord. Les propriétaires ont un accès complet.',
fr: {
heading: 'Permissions par rôle',
subtitle: 'Ce que chaque rôle peut faire dans lespace de travail. Les propriétaires ont un accès complet à lensemble du système.',
colFeature: 'Fonctionnalité',
colManager: 'Manager',
colAgent: 'Agent',
@@ -81,7 +81,7 @@ const copy = {
'Voir la flotte et les véhicules',
'Ajouter / modifier des véhicules',
'Publier / dépublier un véhicule',
'Télécharger des photos de véhicule',
'Téléverser des photos de véhicule',
'Voir les réservations',
'Créer des réservations',
'Annuler des réservations',
@@ -90,20 +90,20 @@ const copy = {
'CRM clients — consultation',
'CRM clients — modification',
'Approuver les permis de conduire',
'Signaler / blacklister un client',
'Signaler / bloquer un client',
'Offres et promotions',
'Analyses et rapports',
'Contrat et facture PDF',
'Facturation et abonnement',
'Inviter / supprimer du personnel',
'Inviter / supprimer des membres de l’équipe',
'Paramètres marque et site',
'Paramètres de paiement',
],
agentNotes: ['', '', '', '', '', '', 'Les siennes', '', '', '', 'Notes uniquement', '', '', '', '', '', '', '', '', ''],
agentNotes: ['', '', '', '', '', '', 'Les siennes uniquement', '', '', '', 'Notes uniquement', '', '', '', '', '', '', '', '', ''],
},
ar: {
heading: 'صلاحيات الأدوار',
subtitle: 'ما يمكن لكل دور القيام به في لوحة التحكم. يملك الملاك وصولاً كاملاً لكل شيء.',
subtitle: 'ما يمكن لكل دور القيام به داخل مساحة العمل. يملك المالكون صلاحية كاملة على كل شيء.',
colFeature: 'الميزة',
colManager: 'المدير',
colAgent: 'الوكيل',
@@ -120,13 +120,13 @@ const copy = {
'إلغاء الحجوزات',
'الاستلام / الإرجاع',
'فحص الأضرار',
'CRM العملاء — عرض',
'CRM العملاء — تعديل',
'إدارة العملاء — عرض',
'إدارة العملاء — تعديل',
'الموافقة على رخص القيادة',
عليم / حظر العميل',
'العروض والترويجات',
مييز العميل / حظره',
'العروض والحملات الترويجية',
'التحليلات والتقارير',
'العقد وفاتورة PDF',
'العقد والفاتورة بصيغة PDF',
'الفوترة والاشتراك',
'دعوة / إزالة الموظفين',
'إعدادات العلامة والموقع',
@@ -45,7 +45,7 @@ export default async function CompanyProfilePage({ params }: { params: { slug: s
unavailable: 'Marketplace indisponible',
unavailableTitle: "Les détails de l'entreprise sont temporairement indisponibles.",
unavailableBody: "L'API marketplace fonctionne, mais la base de données n'est pas accessible dans cet environnement local.",
backToExplore: 'Retour à explorer',
backToExplore: 'Retour à lexploration',
partner: 'Partenaire marketplace',
vehicles: 'véhicules',
offers: 'offres actives',
@@ -62,10 +62,10 @@ export default async function CompanyProfilePage({ params }: { params: { slug: s
ar: {
unavailable: 'السوق غير متاح',
unavailableTitle: 'تفاصيل الشركة غير متاحة مؤقتاً.',
unavailableBody: 'واجهة marketplace تعمل، لكن قاعدة البيانات غير متاحة في هذا البيئة المحلية.',
unavailableBody: 'واجهة السوق تعمل، لكن قاعدة البيانات غير متاحة في هذه البيئة المحلية.',
backToExplore: 'العودة إلى الاستكشاف',
partner: 'شريك في السوق',
vehicles: 'سيارات',
vehicles: 'مركبات',
offers: 'عروض نشطة',
rating: 'التقييم',
new: 'جديد',
@@ -60,7 +60,7 @@ export default async function VehicleDetailPage({ params }: { params: { slug: st
unavailableTitle: 'Les détails du véhicule sont temporairement indisponibles.',
unavailableBody: "Le frontend marketplace fonctionne, mais la base de données n'est pas accessible pour le moment.",
backToFleet: 'Retour à la flotte',
backToExplore: 'Retour à explorer',
backToExplore: 'Retour à lexploration',
noPhotos: 'Aucune photo disponible.',
rentalCompany: 'Société de location',
perDay: '/ jour',
@@ -81,7 +81,7 @@ export default async function VehicleDetailPage({ params }: { params: { slug: st
ar: {
unavailable: 'السوق غير متاح',
unavailableTitle: 'تفاصيل السيارة غير متاحة مؤقتاً.',
unavailableBody: 'واجهة السوق تعمل، لكن قاعدة البيانات الخلفية غير متاحة حالياً.',
unavailableBody: 'واجهة السوق تعمل، لكن قاعدة البيانات في الخلفية غير متاحة حالياً.',
backToFleet: 'العودة إلى الأسطول',
backToExplore: 'العودة إلى الاستكشاف',
noPhotos: 'لا توجد صور متاحة.',
@@ -87,24 +87,24 @@ const copy = {
annual: 'Annuel',
yearly: '/ an',
youSave: 'Vous économisez',
withAnnual: 'avec la facturation annuelle prélevée en un seul paiement par an.',
withAnnual: 'avec la facturation annuelle, prélevée en un seul paiement par an.',
mostPopular: 'Le plus populaire',
perMonth: '/mois',
billedAs: 'Facturé à',
getStarted: 'Commencer',
footer: 'Tous les plans incluent un essai gratuit de 14 jours. Aucune carte bancaire requise.',
footer: 'Toutes les formules incluent un essai gratuit de 14 jours. Aucune carte bancaire nest requise.',
},
ar: {
monthly: 'شهري',
annual: 'سنوي',
yearly: '/ سنة',
youSave: 'توفر',
withAnnual: 'مع الفوترة السنوية دفعة واحدة كل سنة.',
withAnnual: 'مع الفوترة السنوية، تُسدد دفعة واحدة كل سنة.',
mostPopular: 'الأكثر شيوعاً',
perMonth: '/شهر',
billedAs: 'يتم الفوترة بمبلغ',
getStarted: 'ابدأ الآن',
footer: 'جميع الخطط تشمل تجربة مجانية لمدة 14 يوماً. لا حاجة إلى بطاقة ائتمان.',
footer: 'تشمل جميع الخطط تجربة مجانية لمدة 14 يوماً. لا حاجة إلى بطاقة ائتمان.',
},
} as const
@@ -19,24 +19,24 @@ const copy = {
fr: {
kicker: 'Tarifs',
title: 'Une seule plateforme pour toutes les tailles de flotte.',
body: 'Commencez gratuitement pendant 14 jours puis choisissez le plan qui accompagne votre activité. Changez ou annulez à tout moment.',
body: 'Commencez gratuitement pendant 14 jours, puis choisissez la formule qui accompagne votre activité. Vous pouvez changer de formule ou annuler à tout moment.',
faq: 'Questions fréquentes',
items: [
['Puis-je changer de plan plus tard ?', 'Oui. Vous pouvez monter ou descendre à tout moment — les changements prennent effet au prochain cycle de facturation.'],
['Quest-ce qui compte comme véhicule ?', 'Tout véhicule ajouté à votre tableau de bord flotte, actif ou non.'],
['Puis-je changer de formule plus tard ?', 'Oui. Vous pouvez passer à une formule supérieure ou inférieure à tout moment. Les changements prennent effet au cycle de facturation suivant.'],
['Quest-ce qui compte comme véhicule ?', 'Tout véhicule ajouté à votre tableau de bord de flotte, quil soit actif ou non.'],
['Y a-t-il des frais dinstallation ?', 'Aucun frais dinstallation. Vous payez uniquement labonnement mensuel ou annuel.'],
['Comment fonctionne la visibilité marketplace ?', 'Tous les plans payants incluent une présence publique sur RentalDriveGo. Les clients découvrent votre flotte puis sont redirigés vers votre site de réservation.'],
['Comment fonctionne la visibilité marketplace ?', 'Toutes les formules payantes incluent une présence publique sur RentalDriveGo. Les clients découvrent votre flotte puis sont redirigés vers votre site de réservation.'],
],
},
ar: {
kicker: 'الأسعار',
title: 'منصة واحدة لكل أحجام الأساطيل.',
body: 'ابدأ مجاناً لمدة 14 يوماً ثم اختر الخطة التي تنمو مع نشاطك. يمكنك تغيير الخطة أو الإلغاء في أي وقت.',
body: 'ابدأ مجاناً لمدة 14 يوماً، ثم اختر الخطة التي تناسب نمو نشاطك. يمكنك تغيير الخطة أو إلغاءها في أي وقت.',
faq: 'الأسئلة الشائعة',
items: [
['هل يمكنني تغيير الخطة لاحقاً؟', 'نعم. يمكنك الترقية أو التخفيض في أي وقت — وتدخل التغييرات حيز التنفيذ في دورة الفوترة التالية.'],
['ما الذي يُحتسب كسيارة؟', 'أي سجل سيارة تتم إضافته إلى لوحة الأسطول سواء كان نشطاً أم لا.'],
['هل توجد رسوم إعداد؟', 'لا توجد أي رسوم إعداد. أنت تدفع فقط الاشتراك الشهري أو السنوي.'],
['هل توجد رسوم إعداد؟', 'لا توجد أي رسوم إعداد. أنت تدفع فقط قيمة الاشتراك الشهري أو السنوي.'],
['كيف تعمل قائمة السوق؟', 'كل الخطط المدفوعة تشمل الظهور العام على RentalDriveGo. يكتشف المستأجرون أسطولك ثم يتم تحويلهم إلى موقع الحجز الخاص بك.'],
],
},
@@ -59,7 +59,7 @@ export default function RenterDashboardPage() {
fr: {
loadProfile: 'Impossible de charger le profil.',
reachServer: 'Impossible de joindre le serveur.',
backToExplore: 'Retour à explorer',
backToExplore: 'Retour à lexploration',
renterDashboard: 'Espace client',
welcome: 'Bon retour,',
exploreVehicles: 'Explorer les véhicules',
@@ -72,7 +72,7 @@ export default function RenterDashboardPage() {
yourProfile: 'Votre profil',
firstName: 'Prénom',
lastName: 'Nom',
email: 'Email',
email: 'E-mail',
phone: 'Téléphone',
savedCompanies: 'Entreprises sauvegardées',
noneSaved: 'Aucune pour le moment',
@@ -85,7 +85,7 @@ export default function RenterDashboardPage() {
loadProfile: 'تعذر تحميل الملف الشخصي.',
reachServer: 'تعذر الوصول إلى الخادم.',
backToExplore: 'العودة إلى الاستكشاف',
renterDashboard: 'لوحة المستأجر',
renterDashboard: 'بوابة المستأجر',
welcome: 'مرحباً بعودتك،',
exploreVehicles: 'استكشف السيارات',
logout: 'تسجيل الخروج',
@@ -35,7 +35,7 @@ export default function RenterNotificationsPage() {
renter: 'Client',
title: 'Notifications',
markAll: 'Tout marquer comme lu',
back: 'Retour au dashboard',
back: 'Retour au tableau de bord',
loading: 'Chargement des notifications…',
empty: 'Aucune notification client pour le moment.',
read: 'Lu',
@@ -47,12 +47,12 @@ export default function RenterNotificationsPage() {
updateAll: 'تعذر تحديث الإشعارات.',
renter: 'المستأجر',
title: 'الإشعارات',
markAll: حديد الكل كمقروء',
back: 'العودة إلى اللوحة',
markAll: عيين الكل كمقروء',
back: 'العودة إلى بوابة المستأجر',
loading: 'جارٍ تحميل الإشعارات…',
empty: 'لا توجد إشعارات للمستأجر حالياً.',
read: 'مقروء',
markRead: حديد كمقروء',
markRead: عيين كمقروء',
},
}[language]
const [notifications, setNotifications] = useState<RenterNotification[]>([])
@@ -24,7 +24,7 @@ export default function RenterSavedCompaniesPage() {
load: 'Impossible de charger les entreprises sauvegardées.',
renter: 'Client',
title: 'Entreprises sauvegardées',
back: 'Retour au dashboard',
back: 'Retour au tableau de bord',
loading: 'Chargement des entreprises sauvegardées…',
empty: 'Vous navez encore enregistré aucune entreprise.',
browse: 'Parcourir la marketplace',
@@ -34,7 +34,7 @@ export default function RenterSavedCompaniesPage() {
load: 'تعذر تحميل الشركات المحفوظة.',
renter: 'المستأجر',
title: 'الشركات المحفوظة',
back: 'العودة إلى اللوحة',
back: 'العودة إلى بوابة المستأجر',
loading: 'جارٍ تحميل الشركات المحفوظة…',
empty: 'لم تقم بحفظ أي شركة بعد.',
browse: 'تصفح السوق',
@@ -23,18 +23,19 @@ const copy = {
submit: 'Request reservation',
submitting: 'Sending…',
successTitle: 'Request received!',
successBody: 'Your reservation request has been sent. The company will review it and get in touch with you shortly.',
successBody: 'Your reservation request has been sent. The company will review it and contact you shortly.',
invalidDates: 'Return date must be after pick-up date.',
required: 'Please fill in all required fields.',
perDay: '/ day',
estimatedTotal: 'Estimated total',
days: 'day(s)',
genericError: 'Something went wrong. Please try again.',
},
fr: {
title: 'Réserver ce véhicule',
firstName: 'Prénom',
lastName: 'Nom',
email: 'Email',
email: 'E-mail',
phone: 'Téléphone',
startDate: 'Date de départ',
endDate: 'Date de retour',
@@ -42,12 +43,13 @@ const copy = {
submit: 'Demander une réservation',
submitting: 'Envoi…',
successTitle: 'Demande reçue !',
successBody: "Votre demande de réservation a été envoyée. La société va l'examiner et vous contactera prochainement.",
successBody: "Votre demande de réservation a été envoyée. Lentreprise va lexaminer et vous contactera prochainement.",
invalidDates: 'La date de retour doit être après la date de départ.',
required: 'Veuillez remplir tous les champs obligatoires.',
perDay: '/ jour',
estimatedTotal: 'Total estimé',
days: 'jour(s)',
genericError: 'Une erreur est survenue. Veuillez réessayer.',
},
ar: {
title: 'احجز هذه السيارة',
@@ -56,7 +58,7 @@ const copy = {
email: 'البريد الإلكتروني',
phone: 'الهاتف',
startDate: 'تاريخ الاستلام',
endDate: 'تاريخ الإعادة',
endDate: 'تاريخ الإرجاع',
notes: 'ملاحظات (اختيارية)',
submit: 'طلب حجز',
submitting: 'جارٍ الإرسال…',
@@ -67,6 +69,7 @@ const copy = {
perDay: '/ يوم',
estimatedTotal: 'الإجمالي التقديري',
days: 'يوم',
genericError: 'حدث خطأ ما. يرجى المحاولة مرة أخرى.',
},
} as const
@@ -123,7 +126,7 @@ export default function BookingForm({ vehicleId, companySlug, dailyRate }: Props
})
setSuccess(true)
} catch (err: any) {
setError(err.message ?? 'Something went wrong. Please try again.')
setError(err.message ?? t.genericError)
} finally {
setSubmitting(false)
}