Waseel: driver capture, chat/calls, dispatch, and session fixes
Driver onboarding now photographs the licence, ID card and vehicle
registration and reads the credential fields off them, plus a camera-only
profile selfie riders check the arriving driver against. Adds in-app chat
and WebRTC calls, push-backed ride offers, ratings, cancellation and
payment sheets, settlement, and the owner dashboard endpoints behind them.
Camera permission on Android:
- Declare CAMERA and READ_MEDIA_IMAGES in the manifest. expo-image-picker's
own plugin never declares CAMERA, and Android denies a request for an
undeclared permission instantly and silently — no dialog is ever shown,
which is indistinguishable from the app not asking at all.
- Handle canAskAgain: once Android stops showing the dialog, repeating why
we need it is a dead end, so offer Open Settings instead (lib/capture-
permission.ts), matching what the location flow already did.
Session: a 401 on a request that carried a token now ends the session
instead of being reinterpreted per-screen — driver-home had been reading it
as "this user has no driver profile" and showing an onboarding form to an
already-onboarded driver. Requests without a token are exempt so a failed
sign-in doesn't sign you out, and the notification is latched per token so
concurrent polls tear the session down once. (root) gains the auth guard
that turns that into the sign-in screen; app/index.tsx only guarded the way
in, leaving a session that ended mid-screen with nowhere to go.
Also ignore .uploads/ — it holds driver licence, ID and vehicle scans plus
profile photos, which are personal data and must not be committed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1d84003e0a
commit
8807ff41c5
+314
-3
@@ -135,6 +135,9 @@ export const ar = {
|
||||
recentRides: "الرحلات الأخيرة",
|
||||
noRecent: "لا توجد رحلات حديثة.",
|
||||
noRecentAlt: "لا توجد رحلات حديثة",
|
||||
activeRideWithDriver: "{name} في الطريق",
|
||||
rateLastRide: "كيف كانت رحلتك الأخيرة؟",
|
||||
rate: "قيّم",
|
||||
},
|
||||
|
||||
rides: {
|
||||
@@ -155,7 +158,38 @@ export const ar = {
|
||||
title: "الدردشة",
|
||||
messageAlt: "رسالة",
|
||||
noMessages: "لا توجد رسائل بعد",
|
||||
startConversation: "ابدأ محادثة مع أصدقائك وعائلتك",
|
||||
startConversation: "تفتح المحادثة مع سائقك بمجرد مطابقة الرحلة.",
|
||||
inputPlaceholder: "رسالة…",
|
||||
send: "إرسال",
|
||||
loadError: "تعذّر تحميل الرسائل. اسحب للأسفل لإعادة المحاولة.",
|
||||
sendError: "تعذّر إرسال الرسالة. حاول مرة أخرى.",
|
||||
cannotMessage: "لم تعد هذه الرحلة نشطة.",
|
||||
call: "اتصال",
|
||||
},
|
||||
|
||||
call: {
|
||||
incoming: "مكالمة واردة",
|
||||
outgoing: "جارٍ الاتصال…",
|
||||
connecting: "جارٍ التوصيل…",
|
||||
inCall: "أثناء المكالمة",
|
||||
ended: "انتهت المكالمة",
|
||||
missed: "مكالمة فائتة",
|
||||
declined: "تم رفض المكالمة",
|
||||
failed: "فشل الاتصال",
|
||||
unavailable: "لا توجد رحلة نشطة للاتصال.",
|
||||
accept: "قبول",
|
||||
decline: "رفض",
|
||||
end: "إنهاء المكالمة",
|
||||
mute: "كتم",
|
||||
unmute: "إلغاء الكتم",
|
||||
speaker: "مكبر الصوت",
|
||||
speakerOff: "إيقاف مكبر الصوت",
|
||||
cancel: "إلغاء",
|
||||
connectingWith: "جارٍ الاتصال بـ {name}…",
|
||||
micDeniedTitle: "الميكروفون محظور",
|
||||
micDeniedBody:
|
||||
"يحتاج وسيط إلى ميكروفون لإجراء المكالمات. فعّله من الإعدادات.",
|
||||
audioFailed: "تعذّر بدء الصوت. حاول مرة أخرى.",
|
||||
},
|
||||
|
||||
profile: {
|
||||
@@ -169,14 +203,34 @@ export const ar = {
|
||||
emailPlaceholder: "بريدك الإلكتروني",
|
||||
},
|
||||
|
||||
adjustPin: {
|
||||
pickupLabel: "نقطة الصعود",
|
||||
destinationLabel: "نقطة النزول",
|
||||
locating: "جارٍ تحديد المكان…",
|
||||
hint: "حرّك الخريطة لوضع الدبوس في المكان الذي تريده تمامًا.",
|
||||
confirmPickup: "تأكيد نقطة الصعود",
|
||||
confirmDestination: "تأكيد نقطة النزول",
|
||||
recenter: "الذهاب إلى موقعي",
|
||||
},
|
||||
|
||||
findRide: {
|
||||
adjustOnMap: "حدّدها على الخريطة",
|
||||
title: "الرحلة",
|
||||
from: "من",
|
||||
to: "إلى",
|
||||
findNow: "ابحث الآن",
|
||||
service: "نوع الرحلة",
|
||||
nAvailable: "{n} قريب",
|
||||
estimatedFare: "الأجرة التقديرية",
|
||||
setBothPoints: "حدّد نقطة الانطلاق والوجهة",
|
||||
payLaterHint:
|
||||
"سيرى السائقون القريبون طلبك. أنت تختار من يأخذه، وتدفع بعد ذلك.",
|
||||
sending: "جارٍ إرسال طلبك…",
|
||||
},
|
||||
|
||||
confirmRide: {
|
||||
noDriversInRadius: "لا يوجد سائقو {service} ضمن {km} كم",
|
||||
tryInstead: "المتاح قربك الآن:",
|
||||
title: "طلب رحلة",
|
||||
yourTrip: "رحلتك",
|
||||
pickup: "نقطة الصعود",
|
||||
@@ -189,6 +243,13 @@ export const ar = {
|
||||
lbpEstimate: "≈ {lbp}",
|
||||
noDrivers: "لا يوجد سائقو {service} متصلون الآن",
|
||||
findingDrivers: "جارٍ البحث عن سائقين قريبين…",
|
||||
driversNearby: {
|
||||
one: "سائق واحد قريب",
|
||||
other: "{n} سائقين قريبين",
|
||||
zero: "لا سائقين قريبين",
|
||||
},
|
||||
withinRadius: "ضمن {km} كم منك",
|
||||
searchingRadius: "البحث ضمن {km} كم…",
|
||||
nearestDriver: "أقرب سائق ≈ {eta} دقيقة",
|
||||
requesting: "جارٍ الطلب…",
|
||||
noDriversOnline: "لا يوجد سائقون متصلون",
|
||||
@@ -202,20 +263,60 @@ export const ar = {
|
||||
alertErrorFallback: "حدث خطأ أثناء حجز رحلتك. حاول مرة أخرى.",
|
||||
alertPayCardTitle: "الدفع بالبطاقة",
|
||||
alertPayCardBody: "سيتم خصم ${fare} من بطاقتك.",
|
||||
alertInProgressTitle: "لديك رحلة جارية",
|
||||
alertInProgressBody: "لديك رحلة جارية. أنهِها أو ألغِها قبل حجز رحلة أخرى.",
|
||||
viewRide: "عرض الرحلة",
|
||||
},
|
||||
|
||||
bookRide: {
|
||||
status: {
|
||||
requested: "جارٍ البحث عن سائقك…",
|
||||
choosing: "اختر سائقك",
|
||||
accepted: "تم تعيين سائق — في طريقه إليك",
|
||||
enRoute: "أنت في الرحلة",
|
||||
completed: "وصلت!",
|
||||
cancelled: "تم إلغاء الرحلة",
|
||||
arrived: "سائقك وصل",
|
||||
expired: "لا يوجد سائق متاح",
|
||||
},
|
||||
rideNotFound: "الرحلة غير موجودة.",
|
||||
couldNotLoad: "تعذّر تحميل هذه الرحلة.",
|
||||
backHome: "العودة للرئيسية",
|
||||
matchingDriver: "نطابقك مع أقرب سائق {service}.",
|
||||
searchingFor: "جارٍ البحث منذ {seconds} ثانية",
|
||||
match: {
|
||||
driverFallback: "سائقك",
|
||||
alertBody: "حدث خطأ ما. حاول مرة أخرى.",
|
||||
},
|
||||
offers: {
|
||||
title: "سائقون متاحون",
|
||||
count: {
|
||||
one: "عرض واحد",
|
||||
other: "{n} عروض",
|
||||
zero: "لا عروض بعد",
|
||||
},
|
||||
away: "{eta} دقيقة · {distance}",
|
||||
seats: {
|
||||
one: "مقعد واحد",
|
||||
other: "{n} مقاعد",
|
||||
zero: "",
|
||||
},
|
||||
pick: "اختر",
|
||||
goneTitle: "لم يعد هذا السائق متاحًا",
|
||||
goneBody: "ارتبط برحلة أخرى. اختر سائقًا آخر من القائمة.",
|
||||
goneBodyPaid:
|
||||
"ارتبط برحلة أخرى. لم يُستخدم دفعك — اختر سائقًا آخر وسيذهب المبلغ إليه.",
|
||||
},
|
||||
payment: {
|
||||
title: "كيف تريد الدفع؟",
|
||||
titleNamed: "رحلة مع {name}",
|
||||
subtitle: "الأجرة ${fare}",
|
||||
cash: "الدفع نقدًا",
|
||||
cashHint: "سلّم الأجرة للسائق عند الوصول.",
|
||||
card: "الدفع بالبطاقة",
|
||||
cardHint: "يُخصم الآن، قبل انطلاق السائق.",
|
||||
working: "جارٍ التنفيذ…",
|
||||
},
|
||||
ratingFallback: "—",
|
||||
paymentCash: "💵 نقدًا للسائق",
|
||||
paymentCard: "💳 مدفوع بالبطاقة",
|
||||
@@ -226,10 +327,25 @@ export const ar = {
|
||||
cancelling: "جارٍ الإلغاء…",
|
||||
alertErrorTitle: "خطأ",
|
||||
alertErrorBody: "تعذّر إلغاء هذه الرحلة. حاول مرة أخرى.",
|
||||
pickupCodeLabel: "رمز الصعود",
|
||||
pickupCodeHint: "أعطِ هذا الرمز للسائق لبدء الرحلة.",
|
||||
driverHere: "سائقك في الخارج",
|
||||
cashDue: "ادفع ${amount} نقدًا للسائق.",
|
||||
youRated: "قيّمت هذه الرحلة {n}★",
|
||||
rateDriver: "قيّم سائقك",
|
||||
noDriversFound:
|
||||
"لم يقبل أي سائق طلبك. لم يتم خصم أي مبلغ — حاول مرة أخرى بعد قليل.",
|
||||
cancelledByDriver: "ألغى السائق هذه الرحلة.",
|
||||
enRouteNotice: "رحلة سعيدة — سينهي السائق الرحلة عند الوصول.",
|
||||
},
|
||||
|
||||
driver: {
|
||||
home: {
|
||||
owesCompany: "العمولة المستحقة عليك",
|
||||
owesCompanyHint: "من رحلاتك النقدية — سلّمها في المكتب.",
|
||||
owedToDriver: "الشركة مدينة لك",
|
||||
owedToDriverHint: "رحلات البطاقة، تُدفع لك.",
|
||||
afterFee: "بعد عمولة ${fee}",
|
||||
signOutAlt: "تسجيل الخروج",
|
||||
driverMode: "وضع السائق",
|
||||
online: "● متصل — يتلقّى طلبات الرحلات",
|
||||
@@ -238,6 +354,7 @@ export const ar = {
|
||||
completedToday: "المكتملة اليوم",
|
||||
incomingRequests: "الطلبات الواردة",
|
||||
incomingRequestsOffline: "الطلبات الواردة (غير متصل)",
|
||||
finishCurrentRide: "أنهِ رحلتك الحالية لرؤية الطلبات الجديدة.",
|
||||
waitingRequests: "بانتظار طلبات الرحلات…",
|
||||
goOnlineStart: "اتصل لبدء القيادة.",
|
||||
welcome: "أهلاً {name}",
|
||||
@@ -256,35 +373,216 @@ export const ar = {
|
||||
alertCreateBody: "تعذّر إنشاء ملف السائق. حاول مرة أخرى.",
|
||||
alertToggleBody: "تعذّر تغيير حالتك. حاول مرة أخرى.",
|
||||
noRequestsAlt: "لا توجد رحلات حديثة",
|
||||
cashInHand: "النقد المحصّل اليوم",
|
||||
uncollected: "أجرة غير محصّلة اليوم",
|
||||
ratingCount: "{n} تقييم",
|
||||
ratingNew: "سائق جديد",
|
||||
alertOfflineBlocked: "أنهِ رحلتك الحالية أو ألغِها قبل قطع الاتصال.",
|
||||
},
|
||||
credentials: {
|
||||
title: "أوراقك الثبوتية",
|
||||
intro:
|
||||
"ندقّق في أوراق كل سائق قبل أن يبدأ العمل. سيراجع فريقنا هذه المعلومات.",
|
||||
licenseNumber: "رقم رخصة السوق",
|
||||
licenseNumberPlaceholder: "كما هو مدوّن على الرخصة",
|
||||
licenseExpiry: "تاريخ انتهاء الرخصة",
|
||||
nationalId: "رقم الهوية",
|
||||
nationalIdPlaceholder: "رقم بطاقة الهوية",
|
||||
plateNumber: "رقم اللوحة",
|
||||
plateNumberPlaceholder: "مثال: 123456/B",
|
||||
reviewNote:
|
||||
"يبقى حسابك غير متصل إلى أن تتم الموافقة عليه، وعادةً ما يستغرق ذلك أقل من يوم.",
|
||||
submit: "إرسال للمراجعة",
|
||||
errorTitle: "راجع معلوماتك",
|
||||
errorMissing: "رقم الرخصة ورقم الهوية ورقم اللوحة كلها مطلوبة.",
|
||||
errorExpiryFormat: "أدخل تاريخ انتهاء الرخصة بصيغة YYYY-MM-DD.",
|
||||
errorExpired: "هذه الرخصة منتهية الصلاحية.",
|
||||
errorScanRequired: "صوّر رخصة السوق قبل الإرسال.",
|
||||
alertResubmitBody: "تعذّر إعادة إرسال معلوماتك. حاول مرة أخرى.",
|
||||
},
|
||||
captureUnavailable:
|
||||
"التقاط الصور غير متوفّر في هذه النسخة من التطبيق. حدّث التطبيق إلى آخر إصدار وحاول مجددًا.",
|
||||
photo: {
|
||||
title: "صورتك",
|
||||
hint: "تُلتقط الآن بالكاميرا، لا من معرض الصور. يراها الركاب بجانب اسمك عند اختيار السائق، ويتأكدون بها أنك أنت عند نقطة الانطلاق. انظر إلى الكاميرا في إضاءة جيدة.",
|
||||
take: "التقط صورة",
|
||||
retake: "أعد الالتقاط",
|
||||
required: "التقط صورة شخصية قبل الإرسال.",
|
||||
permissionTitle: "الإذن مطلوب",
|
||||
permissionCamera:
|
||||
"يحتاج وصيل إلى الكاميرا لالتقاط صورتك. اسمح بالوصول إلى الكاميرا للمتابعة.",
|
||||
permissionCameraBlocked:
|
||||
"الوصول إلى الكاميرا معطّل لتطبيق وصيل، ولن يسألك أندرويد مرة أخرى من هنا. افتح الإعدادات ثم فعّل «الكاميرا» ضمن الأذونات.",
|
||||
errorTitle: "تعذّر حفظ الصورة",
|
||||
errorBody: "حدث خطأ ما. حاول مرة أخرى.",
|
||||
errorTooLarge: "الصورة كبيرة جدًا. جرّب التقاط صورة جديدة.",
|
||||
errorRateLimit: "عدد المحاولات كبير. انتظر بضع دقائق وحاول مجددًا.",
|
||||
errorUnsupported: "استخدم صورة بصيغة JPEG أو PNG أو WebP.",
|
||||
},
|
||||
scan: {
|
||||
licenseLabel: "رخصة السوق",
|
||||
licenseHint:
|
||||
"ضعها على سطح مستوٍ واملأ بها الإطار. نقرأ منها الرقم وتاريخ الانتهاء.",
|
||||
idLabel: "بطاقة الهوية",
|
||||
idHint: "الوجه الذي يظهر فيه رقم الهوية.",
|
||||
vehicle_regLabel: "رخصة سير السيارة",
|
||||
vehicle_regHint: "الصفحة التي يظهر فيها رقم اللوحة ونوع السيارة.",
|
||||
optional: "اختياري",
|
||||
take: "التقط صورة",
|
||||
retake: "أعد التصوير",
|
||||
choose: "اختر صورة",
|
||||
reading: "نقرأ المستند…",
|
||||
filled: {
|
||||
one: "عبّأنا معلومة واحدة — راجعها أدناه.",
|
||||
other: "عبّأنا {n} معلومات — راجعها أدناه.",
|
||||
},
|
||||
savedNoFields:
|
||||
"حفظنا الصورة، لكن تعذّرت قراءة المعلومات. أدخلها يدويًا أدناه.",
|
||||
savedUnreadable:
|
||||
"حفظنا الصورة. خدمة القراءة غير متوفّرة حاليًا — أدخل المعلومات يدويًا أدناه.",
|
||||
alreadyOnFile: "لدينا صورة محفوظة مسبقًا. أعد التصوير عند الحاجة فقط.",
|
||||
allRead: "قرأناها من أوراقك",
|
||||
missingPrompt:
|
||||
"تعذّرت قراءة هذه المعلومات من أوراقك. أضفها وينتهي الأمر.",
|
||||
edit: "راجع المعلومات أو عدّلها",
|
||||
done: "تم",
|
||||
checkPrompt: "صحّح أي معلومة قُرئت خطأً، ثم اضغط تم.",
|
||||
permissionTitle: "الإذن مطلوب",
|
||||
permissionCamera:
|
||||
"اسمح بالوصول إلى الكاميرا لتصوير أوراقك، أو اختر صورة موجودة بدلًا من ذلك.",
|
||||
permissionCameraBlocked:
|
||||
"الوصول إلى الكاميرا معطّل لتطبيق وصيل، ولن يسألك أندرويد مرة أخرى من هنا. افتح الإعدادات وفعّل «الكاميرا» ضمن الأذونات، أو اختر صورة موجودة بدلًا من ذلك.",
|
||||
permissionLibrary: "اسمح بالوصول إلى الصور لاختيار صورة لأوراقك.",
|
||||
permissionLibraryBlocked:
|
||||
"الوصول إلى الصور معطّل لتطبيق وصيل، ولن يسألك أندرويد مرة أخرى من هنا. افتح الإعدادات وفعّل «الصور» ضمن الأذونات، أو التقط صورة بالكاميرا بدلًا من ذلك.",
|
||||
errorTitle: "تعذّرت القراءة",
|
||||
errorBody: "حدث خطأ ما. حاول مجددًا أو أدخل المعلومات يدويًا أدناه.",
|
||||
errorTooLarge: "الصورة كبيرة جدًا. جرّب التقاط صورة جديدة.",
|
||||
errorRateLimit: "عدد المحاولات كبير. انتظر بضع دقائق وحاول مجددًا.",
|
||||
errorUnsupported: "استخدم صورة بصيغة JPEG أو PNG أو WebP.",
|
||||
errorRetry: "لم يتم الرفع. حاول مجددًا أو أدخل المعلومات يدويًا أدناه.",
|
||||
},
|
||||
review: {
|
||||
pendingTitle: "قيد المراجعة",
|
||||
pendingBody:
|
||||
"نراجع معلوماتك الآن. ستتمكّن من الاتصال فور الموافقة على حسابك.",
|
||||
rejectedTitle: "لم تتم الموافقة",
|
||||
rejectedBody: "لم تجتز معلوماتك المراجعة. صحّحها أدناه وأعد إرسالها.",
|
||||
suspendedTitle: "الحساب موقوف",
|
||||
suspendedBody:
|
||||
"تم إيقاف حساب السائق الخاص بك. تواصل مع الدعم لمعالجة الأمر.",
|
||||
approvedTitle: "تمت الموافقة",
|
||||
approvedBody: "أنت جاهز للعمل.",
|
||||
reasonLabel: "السبب",
|
||||
checkAgain: "تحقّق مجددًا",
|
||||
resubmitTitle: "صحّح معلوماتك",
|
||||
resubmitIntro: "صحّح ما هو خاطئ وسنراجعه من جديد.",
|
||||
resubmit: "إعادة الإرسال",
|
||||
},
|
||||
offerCard: {
|
||||
youEarn: "أرباحك",
|
||||
newRequest: "طلب جديد · {service}",
|
||||
openFor: "متاح لمدة",
|
||||
seconds: "{n} ث",
|
||||
awayFromPickup: "{km} كم عن نقطة الصعود",
|
||||
firstIn: "ستكون الأول",
|
||||
rivals: {
|
||||
one: "سائق آخر تقدّم",
|
||||
other: "{n} سائقين آخرين تقدّموا",
|
||||
zero: "ستكون الأول",
|
||||
},
|
||||
cash: "💵 نقدًا",
|
||||
card: "💳 بطاقة",
|
||||
fromAlt: "من",
|
||||
toAlt: "إلى",
|
||||
tripTime: "زمن الرحلة",
|
||||
fare: "الأجرة",
|
||||
decline: "رفض",
|
||||
accept: "قبول",
|
||||
offer: "تقدّم لهذه الرحلة",
|
||||
withdraw: "سحب عرضي",
|
||||
waitingOnRider: "تم التقديم — بانتظار اختيار الراكب",
|
||||
lostTitle: "أُغلق الطلب",
|
||||
lostBody:
|
||||
"اختار الراكب سائقًا آخر، أو انتهت مهلة الطلب. أنت متاح للطلب التالي.",
|
||||
alertOfferBody: "تعذّر إرسال عرضك. حاول مرة أخرى.",
|
||||
alertWithdrawBody: "تعذّر سحب عرضك. حاول مرة أخرى.",
|
||||
},
|
||||
activeRide: {
|
||||
youEarn: "أرباحك",
|
||||
headToPickup: "اتجه إلى نقطة الصعود",
|
||||
tripInProgress: "الرحلة جارية",
|
||||
rider: "{name}",
|
||||
pickupPin: "موقع صعود الراكب",
|
||||
dropoffPin: "نقطة النزول",
|
||||
navigateToPickup: "التوجّه إلى نقطة الصعود",
|
||||
navigateToDropoff: "التوجّه إلى نقطة النزول",
|
||||
alertNavigateBody: "تعذّر فتح تطبيق ملاحة على هذا الهاتف.",
|
||||
fromAlt: "من",
|
||||
toAlt: "إلى",
|
||||
fare: "الأجرة",
|
||||
message: "رسالة",
|
||||
call: "اتصال",
|
||||
startTrip: "ابدأ الرحلة",
|
||||
completeTrip: "أنهِ الرحلة",
|
||||
cancelRide: "إلغاء الرحلة",
|
||||
cancelConfirmTitle: "إلغاء هذه الرحلة؟",
|
||||
cancelConfirmBody: "سيتم إخطار الراكب وستُعلَّم الرحلة كملغاة.",
|
||||
cancelConfirmDismiss: "الاحتفاظ بالرحلة",
|
||||
cancelConfirmConfirm: "إلغاء الرحلة",
|
||||
alertErrorTitle: "خطأ",
|
||||
alertAcceptBody: "تعذّر قبول هذه الرحلة. ربما حُجزت أو انتهت صلاحيتها.",
|
||||
alertDeclineBody: "تعذّر رفض هذه الرحلة. حاول مرة أخرى.",
|
||||
alertUpdateBody: "تعذّر تحديث الرحلة. حاول مرة أخرى.",
|
||||
alertCancelBody: "تعذّر إلغاء الرحلة. حاول مرة أخرى.",
|
||||
imHere: "لقد وصلت",
|
||||
atPickup: "عند نقطة الصعود — بانتظار الراكب",
|
||||
askForCode: "اطلب من الراكب رمز الصعود المكوّن من 4 أرقام.",
|
||||
cashConfirmTitle: "تحصيل الأجرة",
|
||||
cashConfirmBody: "هل حصّلت ${amount} نقدًا من الراكب؟",
|
||||
cashCollected: "نعم، حصّلتها",
|
||||
cashNotCollected: "لم أحصّلها",
|
||||
},
|
||||
},
|
||||
|
||||
rating: {
|
||||
rateDriverTitle: "كيف كانت رحلتك مع {name}؟",
|
||||
rateRiderTitle: "كيف كان {name} كراكب؟",
|
||||
subtitle: "تقييمك يبقى خاصًا ولا يُعرض للطرف الآخر.",
|
||||
starLabel: "{n} نجوم",
|
||||
commentPlaceholder: "أضف تعليقًا (اختياري)",
|
||||
submit: "إرسال التقييم",
|
||||
notNow: "ليس الآن",
|
||||
error: "تعذّر إرسال تقييمك. حاول مرة أخرى.",
|
||||
},
|
||||
|
||||
cancelSheet: {
|
||||
title: "إلغاء هذه الرحلة؟",
|
||||
subtitleRider: "أخبرنا بالسبب لتحسين المطابقة.",
|
||||
subtitleDriver: "سيتم إخطار الراكب وستُعلَّم الرحلة كملغاة.",
|
||||
confirm: "إلغاء الرحلة",
|
||||
keepRide: "الاحتفاظ بالرحلة",
|
||||
cancelling: "جارٍ الإلغاء…",
|
||||
reasons: {
|
||||
changed_mind: "غيّرت رأيي",
|
||||
wait_too_long: "الانتظار طويل جدًا",
|
||||
wrong_address: "عنوان صعود خاطئ",
|
||||
driver_no_show: "السائق لم يصل",
|
||||
rider_no_show: "الراكب لم يحضر",
|
||||
unreachable: "تعذّر التواصل معه",
|
||||
vehicle_issue: "مشكلة في المركبة",
|
||||
other: "سبب آخر",
|
||||
},
|
||||
},
|
||||
|
||||
pickupCode: {
|
||||
title: "ابدأ الرحلة",
|
||||
subtitle: "أدخل الرمز المكوّن من 4 أرقام من شاشة الراكب.",
|
||||
startTrip: "ابدأ الرحلة",
|
||||
wrongCode: "الرمز غير مطابق. تحقّق مع الراكب.",
|
||||
},
|
||||
|
||||
services: {
|
||||
nearbyCount: "{n} قريب",
|
||||
noneNearby: "لا يوجد قريب",
|
||||
car: { label: "سيارة", tagline: "رحلة يومية، حتى 4 مقاعد." },
|
||||
moto: { label: "موتور", tagline: "تجنّب الزحام — راكب واحد، بدون أمتعة." },
|
||||
courier: {
|
||||
@@ -374,6 +672,16 @@ export const ar = {
|
||||
"الخريطة غير متاحة على الويب.\nافتح التطبيق على أندرويد أو iOS للتجربة الكاملة.",
|
||||
},
|
||||
rideCard: {
|
||||
outcomeCompleted: "مكتملة",
|
||||
outcomeCancelled: "ملغاة",
|
||||
outcomeExpired: "لم يتم العثور على سائق",
|
||||
cancelledByYou: "ألغيتها",
|
||||
cancelledByDriver: "ألغاها السائق",
|
||||
cancelledBySystem: "لا يوجد سائق متاح",
|
||||
noDriver: "لم يُعيَّن سائق",
|
||||
paymentNotCharged: "لم يتم الخصم",
|
||||
paymentRefundDue: "مستحق الاسترداد",
|
||||
paymentCashCollected: "دُفعت نقدًا",
|
||||
mapAlt: "خريطة",
|
||||
originAlt: "المصدر",
|
||||
destinationAlt: "الوجهة",
|
||||
@@ -470,6 +778,9 @@ export const ar = {
|
||||
rtlRestartBody:
|
||||
"سيُطبَّق التخطيط العربي بالكامل في المرة القادمة التي تفتح فيها التطبيق.",
|
||||
},
|
||||
general: {
|
||||
title: "عام",
|
||||
},
|
||||
keepAwake: {
|
||||
title: "عدم قفل الشاشة",
|
||||
description: "إبقاء الشاشة مضاءة أثناء فتح التطبيق.",
|
||||
|
||||
Reference in New Issue
Block a user