diff --git a/apps/admin/src/app/dashboard/site-config/page.tsx b/apps/admin/src/app/dashboard/site-config/page.tsx
index 3214b19..0714095 100644
--- a/apps/admin/src/app/dashboard/site-config/page.tsx
+++ b/apps/admin/src/app/dashboard/site-config/page.tsx
@@ -94,12 +94,12 @@ export default function AdminSiteConfigPage() {
},
fr: {
title: 'Configuration du site',
- description: 'Modifiez ici la homepage principale de la marketplace, ou ouvrez une entreprise pour gérer sa homepage publique et son menu.',
- homepageTitle: 'Homepage du site principal',
- homepageDescription: 'Cette section contrôle la homepage marketplace affichée sur le site principal RentalDriveGo.',
- saveHomepage: 'Enregistrer la homepage',
+ description: 'Modifiez ici la page d’accueil principale de la marketplace, ou ouvrez une entreprise pour gérer sa page publique et son menu.',
+ homepageTitle: 'Page d’accueil du site principal',
+ homepageDescription: 'Cette section contrôle la page d’accueil marketplace affichée sur le site principal de RentalDriveGo.',
+ saveHomepage: 'Enregistrer la page d’accueil',
savingHomepage: 'Enregistrement…',
- homepageSaved: 'Homepage marketplace enregistrée.',
+ homepageSaved: 'Page d’accueil marketplace enregistrée.',
search: 'Rechercher par entreprise ou slug…',
loading: 'Chargement…',
empty: 'Aucune entreprise trouvée',
@@ -111,7 +111,7 @@ export default function AdminSiteConfigPage() {
manageCompany: 'Ouvrir l’entreprise',
companiesTitle: 'Sites de marque des entreprises',
languageLabel: 'Langue',
- hero: 'Hero',
+ hero: 'Bloc principal',
surface: 'Bloc marketplace',
companySection: 'Bloc opérateur',
renterSection: 'Bloc client',
@@ -121,8 +121,8 @@ export default function AdminSiteConfigPage() {
closingSection: 'Appel à l’action final',
previewTitle: 'Aperçu en direct',
previewDescription: 'Les brouillons apparaissent ici avant l’enregistrement.',
- homepageSections: 'Sections de la homepage',
- homepageSectionsDescription: 'Ajoutez ou retirez des blocs de la homepage marketplace principale.',
+ homepageSections: 'Sections de la page d’accueil',
+ homepageSectionsDescription: 'Ajoutez ou retirez des blocs de la page d’accueil marketplace principale.',
addSection: 'Ajouter',
removeSection: 'Retirer',
expand: 'Ouvrir',
diff --git a/apps/admin/src/components/PublicFooter.tsx b/apps/admin/src/components/PublicFooter.tsx
index fc5af98..00e993e 100644
--- a/apps/admin/src/components/PublicFooter.tsx
+++ b/apps/admin/src/components/PublicFooter.tsx
@@ -20,7 +20,7 @@ export default function PublicFooter() {
preferences: 'Admin preferences',
},
fr: {
- preferences: 'Preferences admin',
+ preferences: 'Préférences d’administration',
},
ar: {
preferences: 'تفضيلات الإدارة',
diff --git a/apps/api/src/data/platform-content.json b/apps/api/src/data/platform-content.json
index c3933fe..54b1a04 100644
--- a/apps/api/src/data/platform-content.json
+++ b/apps/api/src/data/platform-content.json
@@ -99,11 +99,11 @@
"closing"
],
"heroKicker": "RentalDriveGo",
- "heroTitle": "Une vitrine marketplace plus nette et plus forte.",
- "heroBody": "Les entreprises de location gèrent leurs opérations en privé, les clients parcourent une marketplace commune, et chaque réservation se termine sur le paiement de marque de la société.",
+ "heroTitle": "Une vitrine marketplace plus claire et plus percutante.",
+ "heroBody": "Les entreprises de location gèrent leurs opérations en privé, les clients parcourent une marketplace commune et chaque réservation se finalise sur le parcours de paiement aux couleurs de l'entreprise.",
"startTrial": "Commencer l’essai gratuit",
"exploreVehicles": "Explorer les véhicules",
- "surfaceLabel": "Surface marketplace",
+ "surfaceLabel": "Vitrine marketplace",
"surfaceTitle": "Pensée pour deux audiences à la fois.",
"surfaceBody": "Les opérateurs veulent du contrôle, les clients veulent de la confiance. La marketplace doit montrer les deux sans ressembler à un modèle générique.",
"liveLabel": "Réseau actif",
@@ -111,15 +111,15 @@
"brandedFlows": "Parcours de marque",
"multiTenant": "Opérations multi-tenant",
"companyKicker": "Flux opérateur",
- "companyTitle": "Pilotez inventaire, offres, facturation et équipe depuis une seule couche de commande.",
+ "companyTitle": "Pilotez l’inventaire, les offres, la facturation et l’équipe depuis un seul centre de contrôle.",
"companyBody": "Publiez une seule fois, choisissez ce qui apparaît publiquement, et gardez contrats, paiements et rapports isolés par entreprise.",
"renterKicker": "Expérience client",
- "renterTitle": "Laissez les clients comparer rapidement puis dirigez-les vers le bon site entreprise.",
- "renterBody": "La marketplace agit comme moteur de découverte, pas comme agrégateur sans suite. Recherche ici, réservation là-bas, paiement direct.",
+ "renterTitle": "Laissez les clients comparer rapidement, puis redirigez-les vers le bon site d’entreprise.",
+ "renterBody": "La marketplace sert de moteur de découverte, pas d’agrégateur sans suite. Recherche ici, réservation là-bas, paiement direct.",
"pillars": [
{
"title": "Publication unifiée",
- "body": "Les photos, tarifs et offres circulent depuis un seul flux admin vers la découverte marketplace et les pages de réservation de marque."
+ "body": "Les photos, tarifs et offres circulent depuis un seul flux d’administration vers la découverte marketplace et les pages de réservation de marque."
},
{
"title": "Découverte qualifiée",
@@ -127,7 +127,7 @@
},
{
"title": "Revenus en direct",
- "body": "Les réservations basculent vers le paiement propre à l’entreprise, pour garder la relation client et l’encaissement."
+ "body": "Les réservations basculent vers le paiement propre à l’entreprise afin de préserver la relation client et l’encaissement."
}
],
"metrics": [
@@ -141,12 +141,12 @@
},
{
"value": "03",
- "label": "Paiements détenus par la société"
+ "label": "Paiements gérés par l’entreprise"
}
],
"featureLabel": "Ce que couvre le produit",
"features": [
- "Gestion de flotte avec téléversement multi-photos",
+ "Gestion de flotte avec téléversement de plusieurs photos",
"Offres marketplace et redirection vers la réservation",
"Site public de réservation par entreprise",
"CRM client, analytics et contrôle de facturation"
@@ -171,8 +171,8 @@
],
"stepLabel": "Étape",
"readyKicker": "Prêt à démarrer",
- "readyTitle": "Une homepage marketplace doit vendre le système en quelques secondes.",
- "readyBody": "Utilisez la marketplace pour capter la demande, puis faites passer les clients vers une expérience de marque qui garde prix, paiements et confiance liés à votre entreprise.",
+ "readyTitle": "La page d’accueil marketplace doit présenter le produit en quelques secondes.",
+ "readyBody": "Utilisez la marketplace pour capter la demande, puis orientez les clients vers une expérience de marque où les prix, les paiements et la confiance restent attachés à votre entreprise.",
"viewPricing": "Voir les tarifs",
"createWorkspace": "Créer l’espace"
},
@@ -187,8 +187,8 @@
"closing"
],
"heroKicker": "RentalDriveGo",
- "heroTitle": "واجهة سوق أوضح وأقوى.",
- "heroBody": "شركات التأجير تدير عملياتها بشكل خاص، والمستأجرون يتصفحون سوقاً مشتركاً، وكل حجز ينتهي في صفحة دفع تحمل هوية الشركة نفسها.",
+ "heroTitle": "واجهة سوق أكثر وضوحاً وتأثيراً.",
+ "heroBody": "شركات التأجير تدير عملياتها بشكل خاص، والمستأجرون يتصفحون سوقاً مشتركاً، وكل حجز ينتهي في صفحة دفع تحمل هوية الشركة ذاتها.",
"startTrial": "ابدأ التجربة المجانية",
"exploreVehicles": "استكشف السيارات",
"surfaceLabel": "واجهة السوق",
@@ -198,16 +198,16 @@
"trustedFleets": "أساطيل موثوقة",
"brandedFlows": "مسارات حجز مخصصة",
"multiTenant": "عمليات متعددة الشركات",
- "companyKicker": "تدفق المشغل",
+ "companyKicker": "سير عمل المشغل",
"companyTitle": "تحكم في المخزون والعروض والفوترة والفريق من طبقة تشغيل واحدة.",
"companyBody": "انشر المخزون مرة واحدة، وحدد ما يظهر للعامة، واحتفظ بالعقود والمدفوعات والتقارير معزولة لكل شركة.",
"renterKicker": "تجربة المستأجر",
- "renterTitle": "دع المستأجر يقارن بسرعة ثم انقله إلى موقع الشركة المناسب.",
- "renterBody": "السوق هنا محرك اكتشاف وليس مجمعاً بلا نهاية. البحث هنا، الحجز هناك، والدفع مباشرة للشركة.",
+ "renterTitle": "دع المستأجرين يقارنون بسرعة ثم وجّههم إلى موقع الشركة المناسب.",
+ "renterBody": "هذه المنصة محرك لاكتشاف الخيارات، وليست مُجمِّعاً بلا مسار واضح. ابحث هنا، احجز هناك، وادفع مباشرة للشركة.",
"pillars": [
{
"title": "نشر موحد",
- "body": "صور السيارات والأسعار والعروض تنتقل من تدفق إدارة واحد إلى السوق وصفحات الحجز ذات الهوية الخاصة."
+ "body": "صور السيارات والأسعار والعروض تنتقل من سير إدارة واحد إلى السوق وصفحات الحجز ذات الهوية الخاصة."
},
{
"title": "اكتشاف مؤهل",
@@ -215,7 +215,7 @@
},
{
"title": "مسار إيراد مباشر",
- "body": "تنتقل الحجوزات إلى صفحة الدفع الخاصة بالشركة حتى تبقى الملكية المالية وعلاقة العميل مع النشاط نفسه."
+ "body": "تنتقل الحجوزات إلى صفحة الدفع الخاصة بالشركة حتى تبقى علاقة العميل والتحصيل المالي بيد الشركة نفسها."
}
],
"metrics": [
@@ -232,7 +232,7 @@
"label": "مدفوعات مملوكة للشركة"
}
],
- "featureLabel": "ما الذي يغطيه المنتج",
+ "featureLabel": "ما الذي يقدمه المنتج",
"features": [
"إدارة الأسطول مع رفع عدة صور",
"عروض السوق والتحويل إلى مسار الحجز",
@@ -243,8 +243,8 @@
"steps": [
{
"step": "1",
- "title": "أنشئ مساحة شركتك",
- "body": "اختر الخطة وابدأ تجربتك لمدة 14 يوماً ثم تحقق من حساب المالك."
+ "title": "أنشئ مساحة عمل شركتك",
+ "body": "اختر الخطة وابدأ تجربتك لمدة 14 يوماً ثم فعّل حساب المالك."
},
{
"step": "2",
@@ -260,9 +260,9 @@
"stepLabel": "الخطوة",
"readyKicker": "جاهز للانطلاق",
"readyTitle": "يجب أن تشرح الصفحة الرئيسية قيمة المنصة خلال ثوانٍ.",
- "readyBody": "استخدم السوق لجذب الطلب، ثم انقل المستأجرين إلى تجربة تحمل هوية شركتك وتحافظ على التسعير والمدفوعات والثقة داخل نشاطك.",
+ "readyBody": "استخدم السوق لجذب الطلب، ثم انقل المستأجرين إلى تجربة تحمل هوية شركتك، بحيث تبقى الأسعار والمدفوعات والثقة مرتبطة بنشاطك.",
"viewPricing": "عرض الأسعار",
"createWorkspace": "إنشاء المساحة"
}
}
-}
\ No newline at end of file
+}
diff --git a/apps/api/src/lib/emailTranslations.ts b/apps/api/src/lib/emailTranslations.ts
index f683baa..81aee34 100644
--- a/apps/api/src/lib/emailTranslations.ts
+++ b/apps/api/src/lib/emailTranslations.ts
@@ -104,7 +104,7 @@ export const resetPasswordEmail = {
مرحباً ${firstName}،
طلبت إعادة تعيين كلمة مرور حساب RentalDriveGo الخاص بك.
إعادة تعيين كلمة المرور
- ينتهي صلاحية هذا الرابط خلال ${expireMinutes} دقيقة. إذا لم تطلب ذلك، يمكنك تجاهل هذا البريد الإلكتروني بأمان.
+ تنتهي صلاحية هذا الرابط خلال ${expireMinutes} دقيقة. إذا لم تطلب ذلك، يمكنك تجاهل هذا البريد الإلكتروني بأمان.
RentalDriveGo
`,
}, lang)
@@ -255,7 +255,7 @@ export const reviewRequestEmail = {
},
ar: {
greeting: `مرحباً ${opts.firstName}،`,
- body1: `شكراً لاستئجارك مع ${opts.companyName}. نأمل أنك استمتعت بـ ${opts.vehicleLabel}.`,
+ body1: `شكراً لاختيار ${opts.companyName}. نأمل أنك استمتعت بـ ${opts.vehicleLabel}.`,
body2: 'تساعد ملاحظاتك الشركة على التحسين وتساعد العملاء الآخرين على اتخاذ قرارات مستنيرة. لا يستغرق الأمر سوى 30 ثانية.',
cta: 'اترك تقييماً',
disclaimer: 'هذا الرابط فريد لحجزك ولا يمكن استخدامه إلا مرة واحدة. إذا لم تستأجر مركبة مؤخراً، يمكنك تجاهل هذا البريد الإلكتروني.',
@@ -285,6 +285,6 @@ export const reviewRequestEmail = {
}, lang: Lang): string => t({
en: `Hi ${opts.firstName},\n\nThank you for renting with ${opts.companyName}. We hope you enjoyed your ${opts.vehicleLabel}.\n\nLeave a review here (one-time link):\n${opts.reviewUrl}\n\nThank you!`,
fr: `Bonjour ${opts.firstName},\n\nMerci d'avoir loué chez ${opts.companyName}. Nous espérons que vous avez apprécié votre ${opts.vehicleLabel}.\n\nLaissez un avis ici (lien unique) :\n${opts.reviewUrl}\n\nMerci !`,
- ar: `مرحباً ${opts.firstName}،\n\nشكراً لاستئجارك مع ${opts.companyName}. نأمل أنك استمتعت بـ ${opts.vehicleLabel}.\n\nاترك تقييماً هنا (رابط فريد):\n${opts.reviewUrl}\n\nشكراً!`,
+ ar: `مرحباً ${opts.firstName}،\n\nشكراً لاختيار ${opts.companyName}. نأمل أنك استمتعت بـ ${opts.vehicleLabel}.\n\nاترك تقييماً هنا (رابط فريد):\n${opts.reviewUrl}\n\nشكراً!`,
}, lang),
}
diff --git a/apps/api/src/modules/companies/company.presenter.ts b/apps/api/src/modules/companies/company.presenter.ts
index 54f0ddc..16d0498 100644
--- a/apps/api/src/modules/companies/company.presenter.ts
+++ b/apps/api/src/modules/companies/company.presenter.ts
@@ -3,5 +3,11 @@ export function presentCompany(company: any) {
}
export function presentBrand(brand: any) {
- return brand
+ if (!brand) return brand
+ const { amanpaySecretKey, amanpayMerchantId, paypalEmail, paypalMerchantId, ...safe } = brand
+ return {
+ ...safe,
+ amanpayConfigured: !!(amanpayMerchantId && amanpaySecretKey),
+ paypalConfigured: !!(paypalEmail || paypalMerchantId),
+ }
}
diff --git a/apps/api/src/modules/payments/payment.routes.ts b/apps/api/src/modules/payments/payment.routes.ts
index cb330d3..0b5df60 100644
--- a/apps/api/src/modules/payments/payment.routes.ts
+++ b/apps/api/src/modules/payments/payment.routes.ts
@@ -18,7 +18,7 @@ router.post('/webhooks/amanpay', async (req, res, next) => {
try {
const rawBody = JSON.stringify(req.body)
const signature = (req.headers['x-amanpay-signature'] as string) ?? ''
- if (amanpay.isConfigured() && !amanpay.verifyWebhookSignature(rawBody, signature)) {
+ if (!amanpay.isConfigured() || !amanpay.verifyWebhookSignature(rawBody, signature)) {
return res.status(401).json({ error: 'invalid_signature' })
}
await service.handleAmanpayWebhook(req.body)
@@ -30,7 +30,7 @@ router.post('/webhooks/paypal', async (req, res, next) => {
try {
const rawBody = JSON.stringify(req.body)
const isValid = await paypal.verifyWebhookEvent(req.headers as Record, rawBody)
- if (paypal.isConfigured() && !isValid) return res.status(401).json({ error: 'invalid_signature' })
+ if (!paypal.isConfigured() || !isValid) return res.status(401).json({ error: 'invalid_signature' })
await service.handlePaypalWebhook(req.body)
res.json({ received: true })
} catch (err) { next(err) }
diff --git a/apps/api/src/modules/subscriptions/subscription.routes.ts b/apps/api/src/modules/subscriptions/subscription.routes.ts
index 8aba292..ecb43f9 100644
--- a/apps/api/src/modules/subscriptions/subscription.routes.ts
+++ b/apps/api/src/modules/subscriptions/subscription.routes.ts
@@ -27,7 +27,7 @@ router.post('/webhooks/amanpay', async (req, res, next) => {
try {
const rawBody = JSON.stringify(req.body)
const signature = (req.headers['x-amanpay-signature'] as string) ?? ''
- if (amanpay.isConfigured() && !amanpay.verifyWebhookSignature(rawBody, signature)) {
+ if (!amanpay.isConfigured() || !amanpay.verifyWebhookSignature(rawBody, signature)) {
return res.status(401).json({ error: 'invalid_signature' })
}
await service.handleAmanpayWebhook(req.body)
@@ -39,7 +39,7 @@ router.post('/webhooks/paypal', async (req, res, next) => {
try {
const rawBody = JSON.stringify(req.body)
const isValid = await paypal.verifyWebhookEvent(req.headers as Record, rawBody)
- if (paypal.isConfigured() && !isValid) return res.status(401).json({ error: 'invalid_signature' })
+ if (!paypal.isConfigured() || !isValid) return res.status(401).json({ error: 'invalid_signature' })
await service.handlePaypalWebhook(req.body)
res.json({ received: true })
} catch (err) { next(err) }
diff --git a/apps/api/src/modules/vehicles/vehicle.routes.ts b/apps/api/src/modules/vehicles/vehicle.routes.ts
index 86b4ecf..b0e9b28 100644
--- a/apps/api/src/modules/vehicles/vehicle.routes.ts
+++ b/apps/api/src/modules/vehicles/vehicle.routes.ts
@@ -123,7 +123,7 @@ router.delete('/:id/calendar/blocks/:blockId', requireRole('MANAGER'), async (re
router.get('/:id/maintenance', async (req, res, next) => {
try {
const { id } = parseParams(idParamSchema, req)
- const logs = await service.getMaintenanceLogs(id)
+ const logs = await service.getMaintenanceLogs(id, req.companyId)
ok(res, logs)
} catch (err) { next(err) }
})
diff --git a/apps/api/src/modules/vehicles/vehicle.service.ts b/apps/api/src/modules/vehicles/vehicle.service.ts
index 4832ce1..c669ab8 100644
--- a/apps/api/src/modules/vehicles/vehicle.service.ts
+++ b/apps/api/src/modules/vehicles/vehicle.service.ts
@@ -110,7 +110,9 @@ export async function deleteCalendarBlock(vehicleId: string, companyId: string,
await repo.deleteCalendarBlock(blockId, vehicleId)
}
-export async function getMaintenanceLogs(id: string) {
+export async function getMaintenanceLogs(id: string, companyId: string) {
+ const vehicle = await repo.findById(id, companyId)
+ if (!vehicle) throw new NotFoundError('Vehicle not found')
return repo.findMaintenanceLogs(id)
}
diff --git a/apps/dashboard/src/app/(dashboard)/dashboard/contracts/[id]/page.tsx b/apps/dashboard/src/app/(dashboard)/dashboard/contracts/[id]/page.tsx
index 5112e35..972fbaf 100644
--- a/apps/dashboard/src/app/(dashboard)/dashboard/contracts/[id]/page.tsx
+++ b/apps/dashboard/src/app/(dashboard)/dashboard/contracts/[id]/page.tsx
@@ -641,7 +641,7 @@ export default function ContractDetailPage() {
damageTypeLabels: { SCRATCH: 'Rayure', DENT: 'Bosse', CRACK: 'Fissure', CHIP: 'Éclat', MISSING: 'Manquant', STAIN: 'Tache', OTHER: 'Autre' },
severityLabels: { MINOR: 'Léger', MODERATE: 'Modéré', MAJOR: 'Majeur' },
fuelLevelLabels: { FULL: 'Plein', SEVEN_EIGHTHS: '7/8', THREE_QUARTERS: '3/4', FIVE_EIGHTHS: '5/8', HALF: '1/2', THREE_EIGHTHS: '3/8', QUARTER: '1/4', ONE_EIGHTH: '1/8', EMPTY: 'Vide' },
- paymentProviderLabels: { CASH: 'Espèces', STRIPE: 'Stripe', BANK_TRANSFER: 'Virement bancaire', CHECK: 'Chèque', PAYPAL: 'PayPal', CREDIT_CARD: 'Carte crédit', DEBIT_CARD: 'Carte débit' },
+ paymentProviderLabels: { CASH: 'Espèces', STRIPE: 'Stripe', BANK_TRANSFER: 'Virement bancaire', CHECK: 'Chèque', PAYPAL: 'PayPal', CREDIT_CARD: 'Carte de crédit', DEBIT_CARD: 'Carte de débit' },
},
ar: {
back: 'العودة إلى العقود',
@@ -690,7 +690,7 @@ export default function ContractDetailPage() {
noAdditionalDrivers: 'لا يوجد سائقون إضافيون.',
noInsurance: 'لم يتم اختيار تأمين.',
noPayments: 'لا توجد مدفوعات مسجلة.',
- loading: 'جار تحميل العقد…',
+ loading: 'جارٍ تحميل العقد…',
yes: 'نعم',
no: 'لا',
agreementTitle: 'عقد تأجير',
@@ -769,8 +769,8 @@ export default function ContractDetailPage() {
contractStatusLabels: { DRAFT: 'مسودة', PENDING: 'قيد الانتظار', ACTIVE: 'نشط', COMPLETED: 'مكتمل', CANCELLED: 'ملغى' },
paymentStatusLabels: { UNPAID: 'غير مدفوع', PAID: 'مدفوع', PARTIAL: 'جزئي', REFUNDED: 'مسترد', OVERDUE: 'متأخر', PENDING: 'قيد الانتظار', COMPLETED: 'مكتمل', FAILED: 'فشل' },
chargeTypeLabels: { PER_DAY: 'يومي', FLAT: 'مقطوع', FLAT_RATE: 'مقطوع', PER_RENTAL: 'لكل إيجار' },
- damageTypeLabels: { SCRATCH: 'خدش', DENT: 'دهس', CRACK: 'تشقق', CHIP: 'تقشر', MISSING: 'مفقود', STAIN: 'بقعة', OTHER: 'أخرى' },
- severityLabels: { MINOR: 'طفيف', MODERATE: 'متوسط', MAJOR: 'خطير' },
+ damageTypeLabels: { SCRATCH: 'خدش', DENT: 'انبعاج', CRACK: 'تشقق', CHIP: 'تقشر', MISSING: 'مفقود', STAIN: 'بقعة', OTHER: 'أخرى' },
+ severityLabels: { MINOR: 'طفيف', MODERATE: 'متوسط', MAJOR: 'شديد' },
fuelLevelLabels: { FULL: 'ممتلئ', SEVEN_EIGHTHS: '7/8', THREE_QUARTERS: '3/4', FIVE_EIGHTHS: '5/8', HALF: '1/2', THREE_EIGHTHS: '3/8', QUARTER: '1/4', ONE_EIGHTH: '1/8', EMPTY: 'فارغ' },
paymentProviderLabels: { CASH: 'نقداً', STRIPE: 'Stripe', BANK_TRANSFER: 'تحويل بنكي', CHECK: 'شيك', PAYPAL: 'PayPal', CREDIT_CARD: 'بطاقة ائتمان', DEBIT_CARD: 'بطاقة خصم' },
},
diff --git a/apps/dashboard/src/app/(dashboard)/dashboard/settings/page.tsx b/apps/dashboard/src/app/(dashboard)/dashboard/settings/page.tsx
index 1a004aa..8b7f95e 100644
--- a/apps/dashboard/src/app/(dashboard)/dashboard/settings/page.tsx
+++ b/apps/dashboard/src/app/(dashboard)/dashboard/settings/page.tsx
@@ -171,7 +171,7 @@ export default function SettingsPage() {
saveAccounting: 'Enregistrer la comptabilité',
displayName: 'Nom affiché',
tagline: 'Slogan',
- publicEmail: 'Email public',
+ publicEmail: 'E-mail public',
publicPhone: 'Téléphone public',
city: 'Ville',
country: 'Pays',
@@ -179,14 +179,14 @@ export default function SettingsPage() {
contractLanguage: 'Langue du contrat',
whatsapp: 'Numéro WhatsApp',
brandColor: 'Couleur de marque',
- listedMarketplace: 'Listé sur la marketplace',
+ listedMarketplace: 'Publié sur la marketplace',
logoUpload: 'Logo',
- heroUpload: 'Image héro',
+ heroUpload: 'Image principale',
uploading: 'Téléversement…',
logoUploaded: 'Logo téléversé',
noLogo: 'Aucun logo téléversé',
- heroUploaded: 'Image héro téléversée',
- noHero: 'Aucune image héro téléversée',
+ heroUploaded: 'Image principale téléversée',
+ noHero: 'Aucune image principale téléversée',
subdomain: 'Sous-domaine',
customDomainLabel: 'Domaine personnalisé',
domainPlaceholder: 'voitures.exemple.com',
@@ -198,7 +198,7 @@ export default function SettingsPage() {
additionalDriverCharge: 'Supplément conducteur additionnel',
dailyDriverRate: 'Tarif conducteur/jour',
flatDriverRate: 'Tarif conducteur fixe',
- fuelPolicyNote: 'Note politique carburant',
+ fuelPolicyNote: 'Note sur la politique carburant',
damagePolicy: 'Politique dommages',
active: 'Actif',
inactive: 'Inactif',
@@ -213,7 +213,7 @@ export default function SettingsPage() {
reportingPeriod: 'Période de reporting',
reportFormat: 'Format de rapport',
accountantName: 'Nom du comptable',
- accountantEmail: 'Email du comptable',
+ accountantEmail: 'E-mail du comptable',
autoSend: 'Envoyer automatiquement les rapports au comptable',
amanpayMerchantId: 'ID marchand AmanPay',
amanpaySecretKey: 'Clé secrète AmanPay',
@@ -246,7 +246,7 @@ export default function SettingsPage() {
saveAccounting: 'حفظ المحاسبة',
displayName: 'اسم العرض',
tagline: 'الشعار',
- publicEmail: 'البريد العام',
+ publicEmail: 'البريد الإلكتروني العام',
publicPhone: 'الهاتف العام',
city: 'المدينة',
country: 'الدولة',
diff --git a/apps/dashboard/src/app/forgot-password/ForgotPasswordPageClient.tsx b/apps/dashboard/src/app/forgot-password/ForgotPasswordPageClient.tsx
index 671b910..5b2c148 100644
--- a/apps/dashboard/src/app/forgot-password/ForgotPasswordPageClient.tsx
+++ b/apps/dashboard/src/app/forgot-password/ForgotPasswordPageClient.tsx
@@ -39,7 +39,7 @@ export default function ForgotPasswordPageClient({ embedded = false }: { embedde
title: 'نسيت كلمة المرور؟',
subtitle: 'أدخل بريدك الإلكتروني وسنرسل لك رابط إعادة التعيين.',
email: 'البريد الإلكتروني',
- submit: 'إرسال رابط الإعادة',
+ submit: 'إرسال رابط إعادة التعيين',
submitting: 'جارٍ الإرسال…',
backToLogin: 'العودة إلى تسجيل الدخول',
successTitle: 'تحقق من بريدك الإلكتروني',
diff --git a/apps/dashboard/src/app/reset-password/ResetPasswordPageClient.tsx b/apps/dashboard/src/app/reset-password/ResetPasswordPageClient.tsx
index 1696ce7..19efd49 100644
--- a/apps/dashboard/src/app/reset-password/ResetPasswordPageClient.tsx
+++ b/apps/dashboard/src/app/reset-password/ResetPasswordPageClient.tsx
@@ -51,7 +51,7 @@ function ResetPasswordContent({ embedded = false }: { embedded?: boolean }) {
errorShort: 'Le mot de passe doit contenir au moins 8 caractères.',
errorInvalidToken: 'Ce lien est invalide ou a expiré. Veuillez en demander un nouveau.',
errorGeneric: 'Une erreur est survenue. Veuillez réessayer.',
- noToken: 'Aucun jeton trouvé. Veuillez demander une réinitialisation.',
+ noToken: 'Aucun jeton de réinitialisation trouvé. Veuillez demander un nouveau lien.',
requestNew: 'Demander un nouveau lien',
},
ar: {
@@ -69,7 +69,7 @@ function ResetPasswordContent({ embedded = false }: { embedded?: boolean }) {
errorShort: 'يجب أن تتكون كلمة المرور من 8 أحرف على الأقل.',
errorInvalidToken: 'رابط إعادة التعيين غير صالح أو منتهي الصلاحية.',
errorGeneric: 'حدث خطأ ما. يرجى المحاولة مرة أخرى.',
- noToken: 'لم يتم العثور على رمز. يرجى طلب إعادة تعيين.',
+ noToken: 'لم يتم العثور على رمز إعادة التعيين. يرجى طلب رابط جديد.',
requestNew: 'طلب رابط جديد',
},
}[language]
diff --git a/apps/dashboard/src/app/sign-in/[[...sign-in]]/SignInPageClient.tsx b/apps/dashboard/src/app/sign-in/[[...sign-in]]/SignInPageClient.tsx
index 81631cc..1587a2c 100644
--- a/apps/dashboard/src/app/sign-in/[[...sign-in]]/SignInPageClient.tsx
+++ b/apps/dashboard/src/app/sign-in/[[...sign-in]]/SignInPageClient.tsx
@@ -44,7 +44,7 @@ export default function SignInPageClient({ embedded = false }: { embedded?: bool
unexpectedError: 'Something went wrong. Please try again.',
},
fr: {
- brandName: 'Agence Espace',
+ brandName: 'Espace agence',
title: 'Connexion',
subtitle: 'Saisissez vos identifiants pour accéder à votre compte.',
email: 'Email',
@@ -57,12 +57,12 @@ export default function SignInPageClient({ embedded = false }: { embedded?: bool
enterCode: "Entrez le code à 6 chiffres de votre application d'authentification.",
back: 'Retour aux identifiants',
forgotPassword: 'Mot de passe oublié ?',
- invalidCredentials: 'Email ou mot de passe invalide.',
+ invalidCredentials: 'Adresse e-mail ou mot de passe invalide.',
passwordNotSet: `Aucun mot de passe défini. Vérifiez votre e-mail d'invitation ou utilisez « Mot de passe oublié ? »`,
unexpectedError: 'Une erreur est survenue. Veuillez réessayer.',
},
ar: {
- brandName: ' فضاء الوكالة ',
+ brandName: 'مساحة الوكالة',
title: 'تسجيل الدخول',
subtitle: 'أدخل بياناتك للوصول إلى حسابك.',
email: 'البريد الإلكتروني',
diff --git a/apps/dashboard/src/app/sign-up/[[...sign-up]]/page.tsx b/apps/dashboard/src/app/sign-up/[[...sign-up]]/page.tsx
index d270284..cf351a0 100644
--- a/apps/dashboard/src/app/sign-up/[[...sign-up]]/page.tsx
+++ b/apps/dashboard/src/app/sign-up/[[...sign-up]]/page.tsx
@@ -174,14 +174,14 @@ export default function SignUpPage() {
brand: 'RentalDriveGo',
pageTitle: 'Lancez votre espace de location',
pageSubtitle: 'Créez le compte utilisateur, complétez les informations de l’entreprise et lancez votre espace.',
- steps: ['Compte utilisateur', 'Infos entreprise', 'Plan', 'Vérifier'],
+ steps: ['Compte utilisateur', 'Infos entreprise', 'Plan', 'Vérification'],
ownerTitle: 'Compte utilisateur',
ownerBody: 'Créez le compte utilisateur principal qui gérera cet espace entreprise.',
partnerTitle: 'Infos entreprise',
partnerBody: 'Complétez les informations de l’entreprise requises pour créer l’espace.',
planTitle: 'Choisissez votre formule',
planBody: 'Votre espace démarre immédiatement avec un essai gratuit de 14 jours dans la devise choisie.',
- reviewTitle: 'Vérifier et lancer',
+ reviewTitle: 'Vérification et lancement',
reviewBody: 'Nous allons créer immédiatement l’espace entreprise et démarrer l’essai de 14 jours avec la formule choisie.',
firstName: 'Prénom du gérant/propriétaire',
lastName: 'Nom du gérant/propriétaire',
@@ -205,7 +205,7 @@ export default function SignUpPage() {
createWorkspace: 'Créer l’espace',
workspaceReady: 'Espace prêt',
workspaceReadyBody: 'est maintenant actif et l’e-mail propriétaire',
- enterDashboard: 'Entrer dans le dashboard',
+ enterDashboard: 'Accéder au tableau de bord',
signInAnotherDevice: 'Se connecter sur un autre appareil',
reviewWorkspace: 'Espace',
reviewPlan: 'Formule',
@@ -233,7 +233,7 @@ export default function SignUpPage() {
'': 'Sélectionner les années d’activité',
LESS_THAN_1: 'Moins de 1 an',
ONE_TO_FIVE: '1 an à 5 ans',
- MORE_THAN_5: 'Plus > 5 ans',
+ MORE_THAN_5: 'Plus de 5 ans',
} as Record,
planDescriptions: {
STARTER: 'Flotte, offres et réservations essentielles.',
diff --git a/apps/dashboard/src/components/I18nProvider.tsx b/apps/dashboard/src/components/I18nProvider.tsx
index 6e9af2c..53dd18a 100644
--- a/apps/dashboard/src/components/I18nProvider.tsx
+++ b/apps/dashboard/src/components/I18nProvider.tsx
@@ -1335,8 +1335,8 @@ const dictionaries: Record = {
damageMarkersHeading: 'علامات الضرر',
removeMarker: 'حذف',
noMarkers: 'لا توجد علامات ضرر محفوظة.',
- damageTypeLabels: { SCRATCH: 'خدش', DENT: 'دهس', CRACK: 'تشقق', CHIP: 'تقشر', MISSING: 'مفقود', STAIN: 'بقعة', OTHER: 'أخرى' },
- severityLabels: { MINOR: 'طفيف', MODERATE: 'متوسط', MAJOR: 'خطير' },
+ damageTypeLabels: { SCRATCH: 'خدش', DENT: 'انبعاج', CRACK: 'تشقق', CHIP: 'تقشر', MISSING: 'مفقود', STAIN: 'بقعة', OTHER: 'أخرى' },
+ severityLabels: { MINOR: 'طفيف', MODERATE: 'متوسط', MAJOR: 'شديد' },
},
},
}
diff --git a/apps/dashboard/src/components/layout/PublicFooter.tsx b/apps/dashboard/src/components/layout/PublicFooter.tsx
index 6915628..3b358bd 100644
--- a/apps/dashboard/src/components/layout/PublicFooter.tsx
+++ b/apps/dashboard/src/components/layout/PublicFooter.tsx
@@ -16,8 +16,8 @@ type FooterItem = {
const localeOptions: Array<{ value: DashboardLanguage; label: string; flag: string }> = [
{ value: 'en', label: 'Global (English)', flag: '🇺🇸' },
- { value: 'ar', label: 'NorthAfrica (Arabic)', flag: '🇲🇦' },
- { value: 'fr', label: 'Europ (French)', flag: '🇫🇷' },
+ { value: 'ar', label: 'North Africa (Arabic)', flag: '🇲🇦' },
+ { value: 'fr', label: 'Europe (French)', flag: '🇫🇷' },
]
function getFooterContent(language: DashboardLanguage): {
@@ -42,7 +42,7 @@ function getFooterContent(language: DashboardLanguage): {
{ label: 'Contacter les ventes', href: `${marketplaceUrl}/footer/contact-sales` },
{ label: 'Nos bureaux', href: `${marketplaceUrl}/footer/our-offices` },
],
- localeLabel: 'Europ (French)',
+ localeLabel: 'Europe (French)',
rightsLabel: 'Tous droits réservés.',
}
case 'ar':
@@ -60,7 +60,7 @@ function getFooterContent(language: DashboardLanguage): {
{ label: 'تواصل مع المبيعات', href: `${marketplaceUrl}/footer/contact-sales` },
{ label: 'مكاتبنا', href: `${marketplaceUrl}/footer/our-offices` },
],
- localeLabel: 'NorthAfrica (Arabic)',
+ localeLabel: 'North Africa (Arabic)',
rightsLabel: 'جميع الحقوق محفوظة.',
}
case 'en':
diff --git a/apps/dashboard/src/components/layout/PublicHeader.tsx b/apps/dashboard/src/components/layout/PublicHeader.tsx
index e8078bf..604f546 100644
--- a/apps/dashboard/src/components/layout/PublicHeader.tsx
+++ b/apps/dashboard/src/components/layout/PublicHeader.tsx
@@ -42,7 +42,7 @@ export default function PublicHeader() {
home: 'Accueil',
marketplace: 'Marketplace',
signIn: 'Connexion',
- createAccount: "Créer Espace d'Agence",
+ createAccount: 'Créer un espace d’agence',
theme: 'Mode',
light: 'Clair',
medium: 'Moyen',
diff --git a/apps/marketplace/src/app/explore/page.tsx b/apps/marketplace/src/app/explore/page.tsx
index 2ebcbb2..5126348 100644
--- a/apps/marketplace/src/app/explore/page.tsx
+++ b/apps/marketplace/src/app/explore/page.tsx
@@ -113,7 +113,7 @@ export default async function ExplorePage({ searchParams }: { searchParams?: Rec
kicker: 'Découverte uniquement',
title: "Trouvez votre prochaine location auprès d'entreprises locales fiables.",
body: "Parcourez, filtrez et réservez — l'entreprise confirme et vous contacte directement.",
- searchTitle: 'Réserver un véhicule',
+ searchTitle: 'Trouver un véhicule',
pickupLocation: 'Lieu de départ',
dropoffLocation: "Lieu de retour",
pickupDate: 'Date de départ',
diff --git a/apps/marketplace/src/app/features/page.tsx b/apps/marketplace/src/app/features/page.tsx
index cf2e634..3131fc2 100644
--- a/apps/marketplace/src/app/features/page.tsx
+++ b/apps/marketplace/src/app/features/page.tsx
@@ -19,13 +19,13 @@ const copy = {
fr: {
kicker: 'Fonctionnalités',
title: 'Opérations, découverte marketplace et réservation de marque.',
- body: 'RentalDriveGo combine des opérations privées pour l’entreprise avec une marketplace publique qui envoie les clients vers le flux de paiement propre à chaque société.',
+ body: 'RentalDriveGo combine des opérations privées pour l’entreprise avec une marketplace publique qui redirige les clients vers le parcours de paiement propre à chaque société.',
cards: [
['Tableau de bord privé', 'Flotte, réservations, CRM, permissions d’équipe, facturation et rapports restent isolés par entreprise.'],
['Découverte marketplace', 'Les véhicules publiés et les offres publiques apparaissent sur `/explore` pour une navigation multi-entreprises.'],
- ['Site de réservation de marque', 'Chaque entreprise dispose de son propre sous-domaine où les clients terminent réservation et paiement.'],
+ ['Site de réservation de marque', 'Chaque entreprise dispose de son propre sous-domaine où les clients finalisent la réservation et le paiement.'],
['Flexibilité de paiement', 'Utilisez AmanPay ou PayPal pour les abonnements et pour les paiements côté entreprise.'],
- ['Opérations avancées', 'Assurance, conducteurs supplémentaires, règles tarifaires et politiques carburant structurées vivent dans le dashboard.'],
+ ['Opérations avancées', 'Assurance, conducteurs supplémentaires, règles tarifaires et politiques carburant structurées sont gérés dans les paramètres du tableau de bord.'],
['Contrôle des notifications', 'Le personnel comme les clients peuvent gérer leurs préférences de notification par événement et canal.'],
],
},
diff --git a/apps/marketplace/src/components/MarketplaceShell.tsx b/apps/marketplace/src/components/MarketplaceShell.tsx
index 9c69dc9..6cce54b 100644
--- a/apps/marketplace/src/components/MarketplaceShell.tsx
+++ b/apps/marketplace/src/components/MarketplaceShell.tsx
@@ -41,7 +41,7 @@ const dictionaries: Record = {
marketplace: 'Accueil',
explore: 'Marketplace',
signIn: 'Connexion',
- ownerSignIn: "Créer Espace d'Agence",
+ ownerSignIn: 'Créer un espace d’agence',
language: 'Langue',
theme: 'Mode',
light: 'Clair',
@@ -75,8 +75,8 @@ const PreferencesContext = createContext(null)
const localeOptions: Array<{ value: MarketplaceLanguage; label: string; flag: string }> = [
{ value: 'en', label: 'Global (English)', flag: '🇺🇸' },
- { value: 'ar', label: 'NorthAfrica (Arabic)', flag: '🇲🇦' },
- { value: 'fr', label: 'Europ (French)', flag: '🇫🇷' },
+ { value: 'ar', label: 'North Africa (Arabic)', flag: '🇲🇦' },
+ { value: 'fr', label: 'Europe (French)', flag: '🇫🇷' },
]
function getFooterContent(language: MarketplaceLanguage): {
@@ -101,7 +101,7 @@ function getFooterContent(language: MarketplaceLanguage): {
{ label: 'Contacter les ventes', href: footerPageHref['contact-sales'] },
{ label: 'Nos bureaux', href: footerPageHref['our-offices'] },
],
- localeLabel: 'Europ (French)',
+ localeLabel: 'Europe (French)',
rightsLabel: 'Tous droits réservés.',
}
case 'ar':
@@ -119,7 +119,7 @@ function getFooterContent(language: MarketplaceLanguage): {
{ label: 'تواصل مع المبيعات', href: footerPageHref['contact-sales'] },
{ label: 'مكاتبنا', href: footerPageHref['our-offices'] },
],
- localeLabel: 'NorthAfrica (Arabic)',
+ localeLabel: 'North Africa (Arabic)',
rightsLabel: 'جميع الحقوق محفوظة.',
}
case 'en':
diff --git a/apps/marketplace/src/components/WorkspaceFrame.tsx b/apps/marketplace/src/components/WorkspaceFrame.tsx
index bcb978b..5585ea4 100644
--- a/apps/marketplace/src/components/WorkspaceFrame.tsx
+++ b/apps/marketplace/src/components/WorkspaceFrame.tsx
@@ -54,7 +54,7 @@ export default function WorkspaceFrame({ target }: { target: FrameId }) {
const frameHeight = isStandaloneAuthRoute ? '100vh' : 'calc(100vh - 56px)'
const loadingLabel = {
en: 'Loading',
- fr: 'Chargement de',
+ fr: 'Chargement',
ar: 'جارٍ تحميل',
}[language]
diff --git a/apps/marketplace/src/components/WorkspaceTabs.tsx b/apps/marketplace/src/components/WorkspaceTabs.tsx
index 42b81e5..db8b459 100644
--- a/apps/marketplace/src/components/WorkspaceTabs.tsx
+++ b/apps/marketplace/src/components/WorkspaceTabs.tsx
@@ -34,35 +34,35 @@ export default function WorkspaceTabs() {
workspaceC: 'Branded booking handoff begins only after a renter chooses a specific vehicle.',
},
fr: {
- badge: 'Espace unifie',
- title: 'Un point d\'entree sur le port 3000 pour la decouverte marketplace, les operations entreprise et l\'administration plateforme.',
+ badge: 'Espace unifié',
+ title: 'Un point d’entrée sur le port 3000 pour la découverte marketplace, les opérations de l’entreprise et l’administration de la plateforme.',
intro:
- 'Les applications restent des surfaces Next.js separees en interne, mais la barre de navigation mene directement vers chaque espace sans changer de port manuellement.',
+ 'Les applications restent des interfaces Next.js séparées en interne, mais la barre de navigation mène directement à chaque espace sans avoir à changer de port manuellement.',
sectionBadge: 'Marketplace RentalDriveGo',
- sectionTitle: 'Parcourez les flottes locales sans perdre l\'identite de l\'entreprise qui gere la location.',
- sectionBodyA: 'La decouverte commence ici. La reservation et le paiement se font sur le site de reservation propre a chaque entreprise.',
- sectionBodyB: 'Les clients accedent a ce site de reservation seulement apres avoir choisi un vehicule dans la flotte d\'une entreprise.',
- exploreVehicles: 'Explorer les vehicules',
+ sectionTitle: 'Parcourez les flottes locales sans perdre l’identité de l’entreprise qui gère la location.',
+ sectionBodyA: 'La découverte commence ici. La réservation et le paiement se font sur le site de réservation propre à chaque entreprise.',
+ sectionBodyB: 'Les clients accèdent à ce site de réservation seulement après avoir choisi un véhicule dans la flotte d’une entreprise.',
+ exploreVehicles: 'Explorer les véhicules',
viewPricing: 'Voir les tarifs',
nowServing: 'Disponible',
- promoTitle: 'La decouverte, les tarifs, la connexion proprietaire et l\'entree vers la reservation restent ancrees dans la marketplace.',
+ promoTitle: 'La découverte, les tarifs, la connexion propriétaire et l’accès à la réservation restent ancrés dans la marketplace.',
promoBody:
- 'Espace entreprise et Operations plateforme restent accessibles depuis la navigation, tandis que la reservation de marque commence apres le choix d\'un vehicule.',
+ 'L’espace entreprise et les opérations de la plateforme restent accessibles depuis la navigation, tandis que la réservation de marque commence après le choix d’un véhicule.',
customerPaths: 'Parcours client',
- ownerSignIn: 'Connexion proprietaire',
+ ownerSignIn: 'Connexion propriétaire',
pricing: 'Tarifs',
workspaceAreas: 'Espaces de travail',
- workspaceA: 'Espace entreprise pour la flotte, l\'equipe, la facturation et l\'analyse.',
- workspaceB: 'Operations plateforme pour le support global et la supervision des tenants.',
- workspaceC: 'Le transfert vers la reservation de marque commence seulement apres le choix d\'un vehicule precis.',
+ workspaceA: 'Espace entreprise pour la flotte, l’équipe, la facturation et l’analyse.',
+ workspaceB: 'Opérations plateforme pour le support global et la supervision multi-entreprises.',
+ workspaceC: 'Le transfert vers la réservation de marque commence seulement après le choix d’un véhicule précis.',
},
ar: {
badge: 'مساحة موحدة',
title: 'نقطة دخول واحدة على المنفذ 3000 لاكتشاف السوق وعمليات الشركات وإدارة المنصة.',
intro:
- 'ما زالت التطبيقات تعمل كأسطح Next.js منفصلة داخلياً، لكن شريط التنقل ينقلك مباشرة إلى كل مساحة عمل بدون البحث عن المنافذ.',
+ 'ما زالت التطبيقات تعمل كواجهات Next.js منفصلة داخلياً، لكن شريط التنقل ينقلك مباشرة إلى كل مساحة عمل من دون الحاجة إلى البحث عن المنافذ.',
sectionBadge: 'سوق RentalDriveGo',
- sectionTitle: 'تصفح أساطيل التأجير المحلية من دون فقدان هوية الشركة التي تدير الحجز.',
+ sectionTitle: 'تصفح أساطيل التأجير المحلية مع الحفاظ على هوية الشركة التي تدير الحجز.',
sectionBodyA: 'الاكتشاف يبدأ هنا. الحجز والدفع يتمان على موقع الحجز الخاص بكل شركة.',
sectionBodyB: 'لا يصل العميل إلى موقع الحجز الخاص بالشركة إلا بعد اختيار سيارة من أسطول تلك الشركة.',
exploreVehicles: 'استكشف السيارات',
@@ -76,7 +76,7 @@ export default function WorkspaceTabs() {
pricing: 'الأسعار',
workspaceAreas: 'مساحات العمل',
workspaceA: 'مساحة الشركة لإدارة الأسطول والفريق والفوترة والتحليلات.',
- workspaceB: 'عمليات المنصة للدعم والإشراف على المستأجرين على مستوى المنصة.',
+ workspaceB: 'عمليات المنصة للدعم والإشراف على الشركات على مستوى المنصة.',
workspaceC: 'الانتقال إلى موقع الحجز الخاص بالشركة يبدأ فقط بعد اختيار سيارة محددة.',
},
}[language]
diff --git a/packages/types/src/fuel.ts b/packages/types/src/fuel.ts
index 244cb3b..7b0545d 100644
--- a/packages/types/src/fuel.ts
+++ b/packages/types/src/fuel.ts
@@ -3,27 +3,27 @@ export type FuelPolicyType = 'FULL_TO_FULL' | 'FULL_TO_EMPTY' | 'SAME_TO_SAME' |
export const FUEL_POLICY_LABELS: Record> = {
FULL_TO_FULL: {
en: 'Full-to-Full: Return vehicle with a full tank. A refueling fee applies if returned with less fuel.',
- fr: "Plein-à-Plein: Retournez le véhicule avec le plein. Des frais de carburant s'appliquent sinon.",
+ fr: "Plein à plein : retournez le véhicule avec le plein. Des frais de ravitaillement s'appliquent sinon.",
ar: 'ممتلئ إلى ممتلئ: يجب إعادة السيارة بخزان ممتلئ. رسوم إضافية في حال الإعادة بمستوى أقل.',
},
FULL_TO_EMPTY: {
en: 'Full-to-Empty: Vehicle is provided with a full tank. No refund for unused fuel upon return.',
- fr: 'Plein-à-Vide: Le véhicule est fourni avec un plein. Aucun remboursement pour carburant non utilisé.',
+ fr: "Plein à vide : le véhicule est livré avec le plein. Aucun remboursement n'est accordé pour le carburant non utilisé.",
ar: 'ممتلئ إلى فارغ: تُسلَّم السيارة بخزان ممتلئ. لا استرداد للوقود غير المستخدم.',
},
SAME_TO_SAME: {
en: 'Same-to-Same: Return vehicle with the same fuel level as at pickup.',
- fr: "Même niveau: Retournez avec le même niveau de carburant qu'au départ.",
+ fr: "Même niveau : retournez le véhicule avec le même niveau de carburant qu'au départ.",
ar: 'نفس المستوى: أعد السيارة بنفس مستوى الوقود عند الاستلام.',
},
PREPAID: {
en: 'Prepaid Fuel: You pre-purchase a full tank at a fixed rate. Return at any fuel level.',
- fr: "Carburant prépayé: Vous prépayez un plein à tarif fixe. Retour à n'importe quel niveau.",
- ar: 'الوقود المدفوع مسبقاً: تدفع مقدماً لخزان كامل بسعر ثابت. العودة بأي مستوى.',
+ fr: "Carburant prépayé : vous achetez un plein à tarif fixe à l'avance. Retour possible avec n'importe quel niveau.",
+ ar: 'الوقود المدفوع مسبقاً: تدفع مقدماً ثمن خزان كامل بسعر ثابت. يمكن إعادة السيارة بأي مستوى.',
},
FREE: {
en: 'Fuel Included: Fuel cost is included in the rental price.',
- fr: 'Carburant inclus: Le coût du carburant est inclus dans le tarif de location.',
+ fr: 'Carburant inclus : le coût du carburant est inclus dans le tarif de location.',
ar: 'الوقود مشمول: تكلفة الوقود مشمولة في سعر الإيجار.',
},
}
diff --git a/packages/types/src/marketplace-homepage.ts b/packages/types/src/marketplace-homepage.ts
index 48bb018..ce16e42 100644
--- a/packages/types/src/marketplace-homepage.ts
+++ b/packages/types/src/marketplace-homepage.ts
@@ -130,12 +130,12 @@ export const defaultMarketplaceHomepageContent: MarketplaceHomepageConfig = {
fr: {
sections: defaultMarketplaceHomepageSections,
heroKicker: 'RentalDriveGo',
- heroTitle: 'Une vitrine marketplace plus nette et plus forte.',
+ heroTitle: 'Une vitrine marketplace plus claire et plus percutante.',
heroBody:
- 'Les entreprises de location gèrent leurs opérations en privé, les clients parcourent une marketplace commune, et chaque réservation se termine sur le paiement de marque de la société.',
+ "Les entreprises de location gèrent leurs opérations en privé, les clients parcourent une marketplace commune et chaque réservation se finalise sur le parcours de paiement aux couleurs de l'entreprise.",
startTrial: 'Commencer l’essai gratuit',
exploreVehicles: 'Explorer les véhicules',
- surfaceLabel: 'Surface marketplace',
+ surfaceLabel: 'Vitrine marketplace',
surfaceTitle: 'Pensée pour deux audiences à la fois.',
surfaceBody:
'Les opérateurs veulent du contrôle, les clients veulent de la confiance. La marketplace doit montrer les deux sans ressembler à un modèle générique.',
@@ -144,26 +144,26 @@ export const defaultMarketplaceHomepageContent: MarketplaceHomepageConfig = {
brandedFlows: 'Parcours de marque',
multiTenant: 'Opérations multi-tenant',
companyKicker: 'Flux opérateur',
- companyTitle: 'Pilotez inventaire, offres, facturation et équipe depuis une seule couche de commande.',
+ companyTitle: 'Pilotez l’inventaire, les offres, la facturation et l’équipe depuis un seul centre de contrôle.',
companyBody:
'Publiez une seule fois, choisissez ce qui apparaît publiquement, et gardez contrats, paiements et rapports isolés par entreprise.',
renterKicker: 'Expérience client',
- renterTitle: 'Laissez les clients comparer rapidement puis dirigez-les vers le bon site entreprise.',
+ renterTitle: 'Laissez les clients comparer rapidement, puis redirigez-les vers le bon site d’entreprise.',
renterBody:
- 'La marketplace agit comme moteur de découverte, pas comme agrégateur sans suite. Recherche ici, réservation là-bas, paiement direct.',
+ 'La marketplace sert de moteur de découverte, pas d’agrégateur sans suite. Recherche ici, réservation là-bas, paiement direct.',
pillars: [
- ['Publication unifiée', 'Les photos, tarifs et offres circulent depuis un seul flux admin vers la découverte marketplace et les pages de réservation de marque.'],
+ ['Publication unifiée', 'Les photos, tarifs et offres circulent depuis un seul flux d’administration vers la découverte marketplace et les pages de réservation de marque.'],
['Découverte qualifiée', 'Offres mises en avant, navigation par localisation et signaux de réputation aident les clients à filtrer rapidement.'],
- ['Revenus en direct', 'Les réservations basculent vers le paiement propre à l’entreprise, pour garder la relation client et l’encaissement.'],
+ ['Revenus en direct', 'Les réservations basculent vers le paiement propre à l’entreprise afin de préserver la relation client et l’encaissement.'],
].map(([title, body]) => ({ title: title!, body: body! })),
metrics: [
['01', 'Visibilité marketplace partagée'],
['02', 'Paiement direct entreprise'],
- ['03', 'Paiements détenus par la société'],
+ ['03', 'Paiements gérés par l’entreprise'],
].map(([value, label]) => ({ value: value!, label: label! })),
featureLabel: 'Ce que couvre le produit',
features: [
- 'Gestion de flotte avec téléversement multi-photos',
+ 'Gestion de flotte avec téléversement de plusieurs photos',
'Offres marketplace et redirection vers la réservation',
'Site public de réservation par entreprise',
'CRM client, analytics et contrôle de facturation',
@@ -176,18 +176,18 @@ export const defaultMarketplaceHomepageContent: MarketplaceHomepageConfig = {
].map(([step, title, body]) => ({ step: step!, title: title!, body: body! })),
stepLabel: 'Étape',
readyKicker: 'Prêt à démarrer',
- readyTitle: 'Une homepage marketplace doit vendre le système en quelques secondes.',
+ readyTitle: 'La page d’accueil marketplace doit présenter le produit en quelques secondes.',
readyBody:
- 'Utilisez la marketplace pour capter la demande, puis faites passer les clients vers une expérience de marque qui garde prix, paiements et confiance liés à votre entreprise.',
+ 'Utilisez la marketplace pour capter la demande, puis orientez les clients vers une expérience de marque où les prix, les paiements et la confiance restent attachés à votre entreprise.',
viewPricing: 'Voir les tarifs',
createWorkspace: 'Créer l’espace',
},
ar: {
sections: defaultMarketplaceHomepageSections,
heroKicker: 'RentalDriveGo',
- heroTitle: 'واجهة سوق أوضح وأقوى.',
+ heroTitle: 'واجهة سوق أكثر وضوحاً وتأثيراً.',
heroBody:
- 'شركات التأجير تدير عملياتها بشكل خاص، والمستأجرون يتصفحون سوقاً مشتركاً، وكل حجز ينتهي في صفحة دفع تحمل هوية الشركة نفسها.',
+ 'شركات التأجير تدير عملياتها بشكل خاص، والمستأجرون يتصفحون سوقاً مشتركاً، وكل حجز ينتهي في صفحة دفع تحمل هوية الشركة ذاتها.',
startTrial: 'ابدأ التجربة المجانية',
exploreVehicles: 'استكشف السيارات',
surfaceLabel: 'واجهة السوق',
@@ -198,25 +198,25 @@ export const defaultMarketplaceHomepageContent: MarketplaceHomepageConfig = {
trustedFleets: 'أساطيل موثوقة',
brandedFlows: 'مسارات حجز مخصصة',
multiTenant: 'عمليات متعددة الشركات',
- companyKicker: 'تدفق المشغل',
+ companyKicker: 'سير عمل المشغل',
companyTitle: 'تحكم في المخزون والعروض والفوترة والفريق من طبقة تشغيل واحدة.',
companyBody:
'انشر المخزون مرة واحدة، وحدد ما يظهر للعامة، واحتفظ بالعقود والمدفوعات والتقارير معزولة لكل شركة.',
renterKicker: 'تجربة المستأجر',
- renterTitle: 'دع المستأجر يقارن بسرعة ثم انقله إلى موقع الشركة المناسب.',
+ renterTitle: 'دع المستأجرين يقارنون بسرعة ثم وجّههم إلى موقع الشركة المناسب.',
renterBody:
- 'السوق هنا محرك اكتشاف وليس مجمعاً بلا نهاية. البحث هنا، الحجز هناك، والدفع مباشرة للشركة.',
+ 'هذه المنصة محرك لاكتشاف الخيارات، وليست مُجمِّعاً بلا مسار واضح. ابحث هنا، احجز هناك، وادفع مباشرة للشركة.',
pillars: [
- ['نشر موحد', 'صور السيارات والأسعار والعروض تنتقل من تدفق إدارة واحد إلى السوق وصفحات الحجز ذات الهوية الخاصة.'],
+ ['نشر موحد', 'صور السيارات والأسعار والعروض تنتقل من سير إدارة واحد إلى السوق وصفحات الحجز ذات الهوية الخاصة.'],
['اكتشاف مؤهل', 'العروض المميزة والتصفح حسب الموقع وإشارات السمعة تساعد المستأجرين على تضييق الخيارات بسرعة.'],
- ['مسار إيراد مباشر', 'تنتقل الحجوزات إلى صفحة الدفع الخاصة بالشركة حتى تبقى الملكية المالية وعلاقة العميل مع النشاط نفسه.'],
+ ['مسار إيراد مباشر', 'تنتقل الحجوزات إلى صفحة الدفع الخاصة بالشركة حتى تبقى علاقة العميل والتحصيل المالي بيد الشركة نفسها.'],
].map(([title, body]) => ({ title: title!, body: body! })),
metrics: [
['01', 'ظهور مشترك في السوق'],
['02', 'دفع مباشر للشركة'],
['03', 'مدفوعات مملوكة للشركة'],
].map(([value, label]) => ({ value: value!, label: label! })),
- featureLabel: 'ما الذي يغطيه المنتج',
+ featureLabel: 'ما الذي يقدمه المنتج',
features: [
'إدارة الأسطول مع رفع عدة صور',
'عروض السوق والتحويل إلى مسار الحجز',
@@ -225,7 +225,7 @@ export const defaultMarketplaceHomepageContent: MarketplaceHomepageConfig = {
],
stepsTitle: 'كيف تبدأ الشركات',
steps: [
- ['1', 'أنشئ مساحة شركتك', 'اختر الخطة وابدأ تجربتك لمدة 14 يوماً ثم تحقق من حساب المالك.'],
+ ['1', 'أنشئ مساحة عمل شركتك', 'اختر الخطة وابدأ تجربتك لمدة 14 يوماً ثم فعّل حساب المالك.'],
['2', 'انشر السيارات والعروض', 'ارفع الصور مرة واحدة وتحكم فيما يظهر في السوق وفي الموقع المخصص.'],
['3', 'استقبل الحجوزات على موقعك', 'يكتشف المستأجرون أسطولك على RentalDriveGo ثم يدفعون مباشرة عبر مسار الحجز الخاص بك.'],
].map(([step, title, body]) => ({ step: step!, title: title!, body: body! })),
@@ -233,7 +233,7 @@ export const defaultMarketplaceHomepageContent: MarketplaceHomepageConfig = {
readyKicker: 'جاهز للانطلاق',
readyTitle: 'يجب أن تشرح الصفحة الرئيسية قيمة المنصة خلال ثوانٍ.',
readyBody:
- 'استخدم السوق لجذب الطلب، ثم انقل المستأجرين إلى تجربة تحمل هوية شركتك وتحافظ على التسعير والمدفوعات والثقة داخل نشاطك.',
+ 'استخدم السوق لجذب الطلب، ثم انقل المستأجرين إلى تجربة تحمل هوية شركتك، بحيث تبقى الأسعار والمدفوعات والثقة مرتبطة بنشاطك.',
viewPricing: 'عرض الأسعار',
createWorkspace: 'إنشاء المساحة',
},