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>
797 lines
36 KiB
TypeScript
797 lines
36 KiB
TypeScript
export const ar = {
|
|
common: {
|
|
cancel: "إلغاء",
|
|
continue: "متابعة",
|
|
back: "رجوع",
|
|
retry: "حاول مجددًا",
|
|
loading: "جارٍ التحميل…",
|
|
saving: "جارٍ الحفظ…",
|
|
error: "خطأ",
|
|
save: "حفظ",
|
|
or: "أو",
|
|
browseHome: "الصفحة الرئيسية",
|
|
backHome: "العودة للرئيسية",
|
|
openSettings: "فتح الإعدادات",
|
|
yourLocation: "موقعك",
|
|
},
|
|
|
|
onboarding: {
|
|
skip: "تخطٍّ",
|
|
next: "التالي",
|
|
getStarted: "ابدأ الآن",
|
|
slide1: {
|
|
title: "رحلتك المثالية على بُعد نقرة واحدة!",
|
|
desc: "تبدأ رحلتك مع وصّيل. اعثر على رحلتك المثالية بكل سهولة.",
|
|
},
|
|
slide2: {
|
|
title: "أفضل سيارة بين يديك مع وصّيل",
|
|
desc: "اكتشف سهولة العثور على رحلتك المثالية مع وصّيل",
|
|
},
|
|
slide3: {
|
|
title: "رحلتك بطريقتك. لننطلق!",
|
|
desc: "أدخل وجهتك، وارتَح، ودعنا نتولّى الباقي.",
|
|
},
|
|
},
|
|
|
|
auth: {
|
|
signIn: {
|
|
welcome: "أهلاً 👋",
|
|
email: "البريد الإلكتروني",
|
|
emailPlaceholder: "karim@email.com",
|
|
password: "كلمة المرور",
|
|
passwordPlaceholder: "••••••••",
|
|
keepSignedIn: "إبقائي مسجّلاً",
|
|
signingIn: "جارٍ تسجيل الدخول…",
|
|
signInBtn: "تسجيل الدخول",
|
|
signInGoogle: "تسجيل الدخول عبر Google",
|
|
forgotPassword: "نسيت كلمة المرور؟",
|
|
noAccount: "ليس لديك حساب؟ ",
|
|
signUpLink: "إنشاء حساب",
|
|
carAlt: "سيارة",
|
|
reset: {
|
|
title: "إعادة تعيين كلمة المرور",
|
|
requestBody:
|
|
"أدخل بريدك الإلكتروني وسنرسل لك رمز إعادة تعيين مكوّن من 6 أرقام.",
|
|
emailPlaceholder: "karim@email.com",
|
|
sending: "جارٍ الإرسال…",
|
|
sendCode: "إرسال الرمز",
|
|
newPassTitle: "أدخل كلمة المرور الجديدة",
|
|
resetBody: "أرسلنا رمز إعادة التعيين إلى {email}",
|
|
devBanner:
|
|
"إرسال البريد غير مُفعّل على هذا الخادم. رمز إعادة التعيين هو ",
|
|
newPassLabel: "كلمة المرور الجديدة",
|
|
newPasswordPlaceholder: "••••••••",
|
|
resetting: "جارٍ إعادة التعيين…",
|
|
resetBtn: "إعادة تعيين كلمة المرور",
|
|
},
|
|
alertMissingTitle: "معلومات ناقصة",
|
|
alertMissingBody: "أدخل بريدك الإلكتروني وكلمة المرور.",
|
|
alertErrorTitle: "خطأ",
|
|
alertErrorFallback: "تعذّر تسجيل الدخول. حاول مرة أخرى.",
|
|
errEmail: "أدخل بريدك الإلكتروني.",
|
|
errCode: "أدخل الرمز المكوّن من 6 أرقام.",
|
|
errPassword: "يجب أن تكون كلمة المرور 8 أحرف على الأقل.",
|
|
errReset: "تعذّر إعادة تعيين كلمة المرور. حاول مرة أخرى.",
|
|
},
|
|
signUp: {
|
|
createAccount: "أنشئ حسابك",
|
|
howUse: "كيف ستستخدم وصّيل؟",
|
|
riderTitle: "أحتاج رحلة",
|
|
riderDesc: "احجز رحلات وصل إلى وجهتك",
|
|
driverTitle: "أريد القيادة",
|
|
driverDesc: "قدّم رحلات واكسب المال بسيارتك",
|
|
carAlt: "سيارة",
|
|
name: "الاسم",
|
|
namePlaceholder: "كريم حداد",
|
|
email: "البريد الإلكتروني",
|
|
emailPlaceholder: "karim@email.com",
|
|
phoneOptional: "الهاتف (اختياري)",
|
|
phonePlaceholder: "70 123 456",
|
|
password: "كلمة المرور",
|
|
passwordPlaceholder: "••••••••",
|
|
signUpBtn: "إنشاء حساب",
|
|
signUpGoogle: "التسجيل عبر Google",
|
|
haveAccount: "هل لديك حساب بالفعل؟ ",
|
|
signInLink: "تسجيل الدخول",
|
|
verify: {
|
|
title: "التحقق",
|
|
body: "أرسلنا رمز تحقق إلى {email}",
|
|
devBanner: "إرسال البريد غير مُفعّل على هذا الخادم. رمز التحقق هو ",
|
|
verifying: "جارٍ التحقق…",
|
|
verifyBtn: "تحقق من البريد",
|
|
checkAlt: "تحقق",
|
|
},
|
|
verified: {
|
|
title: "تم التحقق",
|
|
body: "تم التحقق من حسابك بنجاح.",
|
|
},
|
|
alertMissingTitle: "معلومات ناقصة",
|
|
alertMissingBody: "يرجى ملء الاسم والبريد الإلكتروني وكلمة المرور.",
|
|
alertPhoneTitle: "رقم هاتف غير صالح",
|
|
alertPhoneBody: "أدخل رقمًا لبنانيًا صالحًا، مثلاً 70 123 456.",
|
|
alertErrorTitle: "خطأ",
|
|
alertErrorFallback: "تعذّر إنشاء حسابك.",
|
|
errCode: "أدخل الرمز المكوّن من 6 أرقام.",
|
|
errVerify: "فشل التحقق. حاول مرة أخرى.",
|
|
},
|
|
role: {
|
|
title: "كيف ستستخدم وصّيل؟",
|
|
subtitle: "يمكنك تغيير ذلك لاحقًا بالتواصل مع الدعم.",
|
|
riderTitle: "أنا راكب",
|
|
riderDesc: "احجز رحلات وتنقّل في لبنان",
|
|
driverTitle: "أنا سائق",
|
|
driverDesc: "قدّم رحلات واكسب المال",
|
|
alertErrorTitle: "خطأ",
|
|
alertErrorBody: "تعذّر حفظ اختيارك. حاول مرة أخرى.",
|
|
},
|
|
},
|
|
|
|
home: {
|
|
welcome: "أهلاً {name} 👋",
|
|
logoutAlt: "تسجيل الخروج",
|
|
currentLocation: "موقعك الحالي",
|
|
findingLocation: "جارٍ العثور على موقعك…",
|
|
whatNeed: "بماذا تحتاج؟",
|
|
recentRides: "الرحلات الأخيرة",
|
|
noRecent: "لا توجد رحلات حديثة.",
|
|
noRecentAlt: "لا توجد رحلات حديثة",
|
|
activeRideWithDriver: "{name} في الطريق",
|
|
rateLastRide: "كيف كانت رحلتك الأخيرة؟",
|
|
rate: "قيّم",
|
|
},
|
|
|
|
rides: {
|
|
allRides: "كل الرحلات",
|
|
noRecent: "لا توجد رحلات حديثة.",
|
|
noRecentAlt: "لا توجد رحلات حديثة",
|
|
},
|
|
|
|
tabs: {
|
|
home: "الرئيسية",
|
|
rides: "الرحلات",
|
|
chat: "الدردشة",
|
|
profile: "الملف",
|
|
settings: "الإعدادات",
|
|
},
|
|
|
|
chat: {
|
|
title: "الدردشة",
|
|
messageAlt: "رسالة",
|
|
noMessages: "لا توجد رسائل بعد",
|
|
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: {
|
|
title: "ملفي الشخصي",
|
|
avatarAlt: "صورتك الشخصية",
|
|
firstName: "الاسم الأول",
|
|
firstNamePlaceholder: "اسمك الأول",
|
|
lastName: "اسم العائلة",
|
|
lastNamePlaceholder: "اسم عائلتك",
|
|
email: "البريد الإلكتروني",
|
|
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: "نقطة الصعود",
|
|
destination: "الوجهة",
|
|
tripTime: "زمن الرحلة {time}",
|
|
paymentMethod: "طريقة الدفع",
|
|
cash: "💵 نقدًا",
|
|
card: "💳 بطاقة",
|
|
fareDisplay: "${fare}",
|
|
lbpEstimate: "≈ {lbp}",
|
|
noDrivers: "لا يوجد سائقو {service} متصلون الآن",
|
|
findingDrivers: "جارٍ البحث عن سائقين قريبين…",
|
|
driversNearby: {
|
|
one: "سائق واحد قريب",
|
|
other: "{n} سائقين قريبين",
|
|
zero: "لا سائقين قريبين",
|
|
},
|
|
withinRadius: "ضمن {km} كم منك",
|
|
searchingRadius: "البحث ضمن {km} كم…",
|
|
nearestDriver: "أقرب سائق ≈ {eta} دقيقة",
|
|
requesting: "جارٍ الطلب…",
|
|
noDriversOnline: "لا يوجد سائقون متصلون",
|
|
requestCash: "اطلب رحلة · ادفع نقدًا للسائق",
|
|
requestCard: "اطلب رحلة · ادفع بالبطاقة",
|
|
alertMissingRouteTitle: "المسار ناقص",
|
|
alertMissingRouteBody: "يرجى تحديد نقطة الصعود والوجهة أولاً.",
|
|
alertNoEstimateTitle: "لا يوجد تقدير",
|
|
alertNoEstimateBody: "تعذّر تقدير الأجرة. حاول مرة أخرى.",
|
|
alertErrorTitle: "خطأ",
|
|
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: "💳 مدفوع بالبطاقة",
|
|
fare: "الأجرة: ${fare}",
|
|
tripTime: "زمن الرحلة {time}",
|
|
rideCancelled: "تم إلغاء هذه الرحلة.",
|
|
cancelRide: "إلغاء الرحلة",
|
|
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: "● متصل — يتلقّى طلبات الرحلات",
|
|
goOnline: "○ اتصل لتقديم الرحلات",
|
|
todaysEarnings: "أرباح اليوم",
|
|
completedToday: "المكتملة اليوم",
|
|
incomingRequests: "الطلبات الواردة",
|
|
incomingRequestsOffline: "الطلبات الواردة (غير متصل)",
|
|
finishCurrentRide: "أنهِ رحلتك الحالية لرؤية الطلبات الجديدة.",
|
|
waitingRequests: "بانتظار طلبات الرحلات…",
|
|
goOnlineStart: "اتصل لبدء القيادة.",
|
|
welcome: "أهلاً {name}",
|
|
welcomeFallback: "سائق",
|
|
setupIntro: "أكمل ملف السائق لبدء تلقّي طلبات الرحلات.",
|
|
whatDrive: "ماذا ستقود؟",
|
|
carModel: "موديل السيارة",
|
|
carModelPlaceholder: "مثال: Toyota Camry",
|
|
carSeats: "عدد المقاعد",
|
|
carSeatsPlaceholder: "4",
|
|
saving: "جارٍ الحفظ…",
|
|
startDriving: "ابدأ القيادة",
|
|
alertSeatsTitle: "عدد مقاعد غير صالح",
|
|
alertSeatsBody: "يجب أن يكون عدد المقاعد عددًا صحيحًا بين 1 و8.",
|
|
alertErrorTitle: "خطأ",
|
|
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: "الأجرة",
|
|
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: {
|
|
label: "توصيل طرود",
|
|
tagline: "أرسل طردًا عبر المدينة دون ركوب.",
|
|
},
|
|
chauffeur: { label: "سائق خاص", tagline: "يأتيك سائق ويقود سيارتك أنت." },
|
|
},
|
|
|
|
pois: {
|
|
nearbyTitle: "اقتراحات قريبة",
|
|
mall: "مركز تسوّق",
|
|
hospital: "مستشفى",
|
|
pharmacy: "صيدلية",
|
|
restaurant: "مطعم",
|
|
searching: "جارٍ البحث…",
|
|
noneNearby: "لا يوجد قريب",
|
|
kmAway: "{km} كم",
|
|
routeAway: "{km} كم · {min} دقيقة",
|
|
nearbyPlace: "مكان قريب",
|
|
},
|
|
|
|
units: {
|
|
min: { zero: "0 دقيقة", one: "{n} دقيقة", other: "{n} دقائق" },
|
|
h: "{n} س",
|
|
m: "{n} د",
|
|
hoursMinutes: "{h}س {m}د",
|
|
seats: { zero: "{n} مقاعد", one: "مقعد", other: "{n} مقاعد" },
|
|
lbpSuffix: " ل.ل.",
|
|
},
|
|
|
|
months: {
|
|
jan: "يناير",
|
|
feb: "فبراير",
|
|
mar: "مارس",
|
|
apr: "أبريل",
|
|
may: "مايو",
|
|
jun: "يونيو",
|
|
jul: "يوليو",
|
|
aug: "أغسطس",
|
|
sep: "سبتمبر",
|
|
oct: "أكتوبر",
|
|
nov: "نوفمبر",
|
|
dec: "ديسمبر",
|
|
},
|
|
|
|
components: {
|
|
oauth: {
|
|
or: "أو",
|
|
googleLogoAlt: "شعار Google",
|
|
alertFailTitle: "فشل تسجيل الدخول عبر Google",
|
|
alertFailNoToken: "لم يُعَد أي رمز. حاول مرة أخرى.",
|
|
alertFailFallback: "حاول مرة أخرى.",
|
|
},
|
|
otp: {
|
|
code: "الرمز",
|
|
codePlaceholder: "123456",
|
|
pasteCode: "لصق الرمز من Gmail",
|
|
},
|
|
googleTextInput: {
|
|
searchAlt: "بحث",
|
|
placeholder: "إلى أين تريد الذهاب؟",
|
|
},
|
|
inputField: {
|
|
labelIconAlt: "أيقونة {label}",
|
|
},
|
|
locationNotice: {
|
|
denied: {
|
|
title: "الوصول إلى الموقع مُيقَف",
|
|
body: "يحتاج وصّيل إلى موقعك لإظهار السائقين القريبين وتحديد نقطة الصعود.",
|
|
action: "فتح الإعدادات",
|
|
},
|
|
servicesOff: {
|
|
title: "خدمات الموقع مُيقَفة",
|
|
body: "فعّل الموقع على جهازك ثم حاول مجددًا.",
|
|
action: "حاول مجددًا",
|
|
},
|
|
unavailable: {
|
|
title: "تعذّر العثور على موقعك",
|
|
body: "انتقل إلى مكان بإشارة أوضح، أو حدّد نقطة الصعود يدويًا.",
|
|
action: "حاول مجددًا",
|
|
},
|
|
},
|
|
map: {
|
|
destination: "الوجهة",
|
|
webUnavailable:
|
|
"الخريطة غير متاحة على الويب.\nافتح التطبيق على أندرويد أو iOS للتجربة الكاملة.",
|
|
},
|
|
rideCard: {
|
|
outcomeCompleted: "مكتملة",
|
|
outcomeCancelled: "ملغاة",
|
|
outcomeExpired: "لم يتم العثور على سائق",
|
|
cancelledByYou: "ألغيتها",
|
|
cancelledByDriver: "ألغاها السائق",
|
|
cancelledBySystem: "لا يوجد سائق متاح",
|
|
noDriver: "لم يُعيَّن سائق",
|
|
paymentNotCharged: "لم يتم الخصم",
|
|
paymentRefundDue: "مستحق الاسترداد",
|
|
paymentCashCollected: "دُفعت نقدًا",
|
|
mapAlt: "خريطة",
|
|
originAlt: "المصدر",
|
|
destinationAlt: "الوجهة",
|
|
dateTime: "التاريخ والوقت",
|
|
driver: "السائق",
|
|
carSeats: "المقاعد",
|
|
fare: "الأجرة",
|
|
paymentStatus: "حالة الدفع",
|
|
paymentCash: "نقدًا · ادفع للسائق",
|
|
paymentPaid: "مدفوع بالبطاقة",
|
|
paymentOther: "{status}",
|
|
},
|
|
rideLayout: {
|
|
goBack: "رجوع",
|
|
backArrowAlt: "سهم الرجوع",
|
|
},
|
|
payment: {
|
|
paymentMethod: "طريقة الدفع",
|
|
cash: "💵 نقدًا",
|
|
card: "💳 بطاقة",
|
|
processing: "جارٍ المعالجة...",
|
|
bookCash: "احجز رحلة · ادفع نقدًا للسائق",
|
|
confirmCard: "تأكيد والدفع بالبطاقة",
|
|
checkAlt: "تحقق",
|
|
rideBooked: "تم حجز الرحلة!",
|
|
successBody: "شكرًا لحجزك.\n تم تسجيل حجزك.\n",
|
|
cashInstruction: "يرجى تجهيز {lbp}.",
|
|
backHome: "العودة للرئيسية",
|
|
alertPayCardTitle: "الدفع بالبطاقة",
|
|
alertPayCardBody: "سيتم خصم ${amount} من بطاقتك.",
|
|
alertErrorTitle: "خطأ",
|
|
alertErrorBody: "حدث خطأ أثناء حجز رحلتك. حاول مرة أخرى.",
|
|
alertPaymentNotCompletedTitle: "لم يكتمل الدفع",
|
|
alertPaymentNotCompletedBody:
|
|
"أُلغي الدفع أو تعذّر التحقق منه. حاول مرة أخرى.",
|
|
alertProcessingTitle: "خطأ",
|
|
alertProcessingBody: "حدث خطأ أثناء معالجة الدفع. حاول مرة أخرى.",
|
|
},
|
|
driverCard: {
|
|
avatarAlt: "صورة السائق",
|
|
starAlt: "نجمة",
|
|
dollarAlt: "دولار",
|
|
carAlt: "سيارة",
|
|
seats: "{n} مقاعد",
|
|
},
|
|
},
|
|
|
|
settings: {
|
|
title: "الإعدادات",
|
|
maps: {
|
|
title: "الخرائط والتنقّل",
|
|
description:
|
|
"يستخدم وصّيل موقعك لإظهار السائقين القريبين والتنقّل إلى نقطة الصعود.",
|
|
statusGranted: "مُتاح",
|
|
statusDenied: "غير مسموح",
|
|
statusBlocked: "محظور",
|
|
statusUnknown: "جارٍ التحقق…",
|
|
openSettings: "فتح الإعدادات",
|
|
},
|
|
appearance: {
|
|
title: "المظهر",
|
|
description: "اختر شكل وصّيل.",
|
|
light: "فاتح",
|
|
dark: "داكن",
|
|
system: "النظام",
|
|
},
|
|
safety: {
|
|
title: "الأمان",
|
|
call112: "اتصل بـ 112 — الطوارئ",
|
|
call112Description:
|
|
"اتصل برقم الطوارئ في لبنان للشرطة أو الإسعاف أو الإطفاء.",
|
|
callFailedTitle: "تعذّر إجراء المكالمة",
|
|
callFailedBody: "لا يوجد هاتف على هذا الجهاز. اتصل بـ 112 يدويًا.",
|
|
proactive: {
|
|
title: "الأمان الاستباقي",
|
|
body: "شارك حالة رحلتك وموقعك المباشر مع جهات موثوقة، وامتحن بثقة مع وجود المساعدة على بُعد نقرة.",
|
|
},
|
|
verification: {
|
|
title: "التحقق من الركاب",
|
|
body: "يتحقق الركاب والسائقون من أرقام هواتفهم وهويتهم، فتعرف دائمًا مع من تركب.",
|
|
},
|
|
privacy: {
|
|
title: "حماية خصوصيتك",
|
|
body: "يبقى رقم هاتفك وبياناتك مخفية في الدردشة. الرسائل ظاهرة فقط بينك وبين سائقك لهذه الرحلة.",
|
|
},
|
|
},
|
|
language: {
|
|
title: "اللغة",
|
|
description: "لغة التطبيق.",
|
|
en: "English",
|
|
ar: "العربية",
|
|
fr: "Français",
|
|
rtlRestartTitle: "إعادة التشغيل للعربية",
|
|
rtlRestartBody:
|
|
"سيُطبَّق التخطيط العربي بالكامل في المرة القادمة التي تفتح فيها التطبيق.",
|
|
},
|
|
general: {
|
|
title: "عام",
|
|
},
|
|
keepAwake: {
|
|
title: "عدم قفل الشاشة",
|
|
description: "إبقاء الشاشة مضاءة أثناء فتح التطبيق.",
|
|
},
|
|
overlay: {
|
|
title: "العرض فوق التطبيقات الأخرى",
|
|
description: "مطلوب لتظهر تنبيهات الرحلات فوق التطبيقات الأخرى.",
|
|
allow: "السماح بالعرض فوق التطبيقات الأخرى",
|
|
openedHint: "تم فتح إعدادات النظام",
|
|
notAndroid: "متاح على أندرويد فقط.",
|
|
},
|
|
},
|
|
};
|