fix languages
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -20,7 +20,7 @@ export default function PublicFooter() {
|
||||
preferences: 'Admin preferences',
|
||||
},
|
||||
fr: {
|
||||
preferences: 'Preferences admin',
|
||||
preferences: 'Préférences d’administration',
|
||||
},
|
||||
ar: {
|
||||
preferences: 'تفضيلات الإدارة',
|
||||
|
||||
@@ -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": "إنشاء المساحة"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ export const resetPasswordEmail = {
|
||||
<p>مرحباً ${firstName}،</p>
|
||||
<p>طلبت إعادة تعيين كلمة مرور حساب RentalDriveGo الخاص بك.</p>
|
||||
<p><a href="${resetUrl}" style="background:#1d4ed8;color:#fff;padding:12px 24px;border-radius:8px;text-decoration:none;display:inline-block;font-weight:600;">إعادة تعيين كلمة المرور</a></p>
|
||||
<p>ينتهي صلاحية هذا الرابط خلال ${expireMinutes} دقيقة. إذا لم تطلب ذلك، يمكنك تجاهل هذا البريد الإلكتروني بأمان.</p>
|
||||
<p>تنتهي صلاحية هذا الرابط خلال ${expireMinutes} دقيقة. إذا لم تطلب ذلك، يمكنك تجاهل هذا البريد الإلكتروني بأمان.</p>
|
||||
<p>RentalDriveGo</p>
|
||||
</div>`,
|
||||
}, lang)
|
||||
@@ -255,7 +255,7 @@ export const reviewRequestEmail = {
|
||||
},
|
||||
ar: {
|
||||
greeting: `مرحباً ${opts.firstName}،`,
|
||||
body1: `شكراً لاستئجارك مع <strong>${opts.companyName}</strong>. نأمل أنك استمتعت بـ <strong>${opts.vehicleLabel}</strong>.`,
|
||||
body1: `شكراً لاختيار <strong>${opts.companyName}</strong>. نأمل أنك استمتعت بـ <strong>${opts.vehicleLabel}</strong>.`,
|
||||
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),
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<string, string>, 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) }
|
||||
|
||||
@@ -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<string, string>, 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) }
|
||||
|
||||
@@ -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) }
|
||||
})
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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: 'بطاقة خصم' },
|
||||
},
|
||||
|
||||
@@ -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: 'الدولة',
|
||||
|
||||
@@ -39,7 +39,7 @@ export default function ForgotPasswordPageClient({ embedded = false }: { embedde
|
||||
title: 'نسيت كلمة المرور؟',
|
||||
subtitle: 'أدخل بريدك الإلكتروني وسنرسل لك رابط إعادة التعيين.',
|
||||
email: 'البريد الإلكتروني',
|
||||
submit: 'إرسال رابط الإعادة',
|
||||
submit: 'إرسال رابط إعادة التعيين',
|
||||
submitting: 'جارٍ الإرسال…',
|
||||
backToLogin: 'العودة إلى تسجيل الدخول',
|
||||
successTitle: 'تحقق من بريدك الإلكتروني',
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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: 'البريد الإلكتروني',
|
||||
|
||||
@@ -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<string, string>,
|
||||
planDescriptions: {
|
||||
STARTER: 'Flotte, offres et réservations essentielles.',
|
||||
|
||||
@@ -1335,8 +1335,8 @@ const dictionaries: Record<DashboardLanguage, DashboardDictionary> = {
|
||||
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: 'شديد' },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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.'],
|
||||
],
|
||||
},
|
||||
|
||||
@@ -41,7 +41,7 @@ const dictionaries: Record<MarketplaceLanguage, Dictionary> = {
|
||||
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<PreferencesContextValue | null>(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':
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -3,27 +3,27 @@ export type FuelPolicyType = 'FULL_TO_FULL' | 'FULL_TO_EMPTY' | 'SAME_TO_SAME' |
|
||||
export const FUEL_POLICY_LABELS: Record<FuelPolicyType, Record<'en' | 'fr' | 'ar', string>> = {
|
||||
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: 'الوقود مشمول: تكلفة الوقود مشمولة في سعر الإيجار.',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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: 'إنشاء المساحة',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user