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>
821 lines
28 KiB
TypeScript
821 lines
28 KiB
TypeScript
export const en = {
|
||
common: {
|
||
cancel: "Cancel",
|
||
continue: "Continue",
|
||
back: "Back",
|
||
retry: "Try Again",
|
||
loading: "Loading…",
|
||
saving: "Saving…",
|
||
error: "Error",
|
||
save: "Save",
|
||
or: "Or",
|
||
browseHome: "Browse Home",
|
||
backHome: "Back Home",
|
||
openSettings: "Open Settings",
|
||
yourLocation: "Your location",
|
||
},
|
||
|
||
onboarding: {
|
||
skip: "Skip",
|
||
next: "Next",
|
||
getStarted: "Get Started",
|
||
slide1: {
|
||
title: "The perfect ride is just a tap away!",
|
||
desc: "Your journey begins with Waseel. Find your ideal ride effortlessly.",
|
||
},
|
||
slide2: {
|
||
title: "Best car in your hands with Waseel",
|
||
desc: "Discover the convenience of finding your perfect ride with Waseel",
|
||
},
|
||
slide3: {
|
||
title: "Your ride, your way. Let's go!",
|
||
desc: "Enter your destination, sit back, and let us take care of the rest.",
|
||
},
|
||
},
|
||
|
||
auth: {
|
||
signIn: {
|
||
welcome: "Welcome 👋",
|
||
email: "Email",
|
||
emailPlaceholder: "karim@email.com",
|
||
password: "Password",
|
||
passwordPlaceholder: "••••••••",
|
||
keepSignedIn: "Keep me signed in",
|
||
signingIn: "Signing in…",
|
||
signInBtn: "Sign In",
|
||
signInGoogle: "Sign in with Google",
|
||
forgotPassword: "Forgot password?",
|
||
noAccount: "Don't have an account? ",
|
||
signUpLink: "Sign up",
|
||
carAlt: "Car",
|
||
reset: {
|
||
title: "Reset password",
|
||
requestBody:
|
||
"Enter your email and we'll send you a 6-digit reset code.",
|
||
emailPlaceholder: "karim@email.com",
|
||
sending: "Sending…",
|
||
sendCode: "Send Code",
|
||
newPassTitle: "Enter new password",
|
||
resetBody: "We've sent a reset code to {email}",
|
||
devBanner:
|
||
"Email delivery is not configured on this server. Your reset code is ",
|
||
newPassLabel: "New password",
|
||
newPasswordPlaceholder: "••••••••",
|
||
resetting: "Resetting…",
|
||
resetBtn: "Reset Password",
|
||
},
|
||
alertMissingTitle: "Missing information",
|
||
alertMissingBody: "Enter both your email and your password.",
|
||
alertErrorTitle: "Error",
|
||
alertErrorFallback: "Could not sign in. Please try again.",
|
||
errEmail: "Enter your email address.",
|
||
errCode: "Enter the 6-digit code.",
|
||
errPassword: "Password must be at least 8 characters.",
|
||
errReset: "Could not reset your password. Please try again.",
|
||
},
|
||
signUp: {
|
||
createAccount: "Create Your Account",
|
||
howUse: "How will you use Waseel?",
|
||
riderTitle: "I need a ride",
|
||
riderDesc: "Book rides and get where you're going",
|
||
driverTitle: "I want to drive",
|
||
driverDesc: "Offer rides and earn money with your car",
|
||
carAlt: "Car",
|
||
name: "Name",
|
||
namePlaceholder: "Karim Haddad",
|
||
email: "Email",
|
||
emailPlaceholder: "karim@email.com",
|
||
phoneOptional: "Phone (optional)",
|
||
phonePlaceholder: "70 123 456",
|
||
password: "Password",
|
||
passwordPlaceholder: "••••••••",
|
||
signUpBtn: "Sign Up",
|
||
signUpGoogle: "Sign up with Google",
|
||
haveAccount: "Already have an account? ",
|
||
signInLink: "Sign in",
|
||
verify: {
|
||
title: "Verification",
|
||
body: "We've sent a verification code to {email}",
|
||
devBanner:
|
||
"Email delivery is not configured on this server. Your verification code is ",
|
||
verifying: "Verifying…",
|
||
verifyBtn: "Verify Email",
|
||
checkAlt: "Check",
|
||
},
|
||
verified: {
|
||
title: "Verified",
|
||
body: "You've successfully verified your account.",
|
||
},
|
||
alertMissingTitle: "Missing information",
|
||
alertMissingBody: "Please fill in your name, email and password.",
|
||
alertPhoneTitle: "Invalid phone number",
|
||
alertPhoneBody: "Enter a valid Lebanese number, e.g. 70 123 456.",
|
||
alertErrorTitle: "Error",
|
||
alertErrorFallback: "Could not create your account.",
|
||
errCode: "Enter the 6-digit code.",
|
||
errVerify: "Verification failed. Please try again.",
|
||
},
|
||
role: {
|
||
title: "How will you use Waseel?",
|
||
subtitle: "You can change this later by contacting support.",
|
||
riderTitle: "I'm a Rider",
|
||
riderDesc: "Book rides and get around Lebanon",
|
||
driverTitle: "I'm a Driver",
|
||
driverDesc: "Give rides and earn money",
|
||
alertErrorTitle: "Error",
|
||
alertErrorBody: "Could not save your choice. Please try again.",
|
||
},
|
||
},
|
||
|
||
home: {
|
||
welcome: "Welcome {name} 👋",
|
||
logoutAlt: "Logout",
|
||
currentLocation: "Your Current Location",
|
||
findingLocation: "Finding your location…",
|
||
whatNeed: "What do you need?",
|
||
recentRides: "Recent Rides",
|
||
noRecent: "No recent rides found.",
|
||
noRecentAlt: "No recent rides found",
|
||
activeRideWithDriver: "{name} is on the way",
|
||
rateLastRide: "How was your last ride?",
|
||
rate: "Rate",
|
||
},
|
||
|
||
rides: {
|
||
allRides: "All rides",
|
||
noRecent: "No recent rides found.",
|
||
noRecentAlt: "No recent rides found",
|
||
},
|
||
|
||
tabs: {
|
||
home: "Home",
|
||
rides: "Rides",
|
||
chat: "Chat",
|
||
profile: "Profile",
|
||
settings: "Settings",
|
||
},
|
||
|
||
chat: {
|
||
title: "Chat",
|
||
messageAlt: "message",
|
||
noMessages: "No Messages Yet",
|
||
startConversation: "Messages open with your driver once a ride is matched.",
|
||
inputPlaceholder: "Message…",
|
||
send: "Send",
|
||
loadError: "Couldn't load messages. Pull to retry.",
|
||
sendError: "Couldn't send message. Try again.",
|
||
cannotMessage: "This ride is no longer active.",
|
||
call: "Call",
|
||
},
|
||
|
||
call: {
|
||
incoming: "Incoming call",
|
||
outgoing: "Calling…",
|
||
connecting: "Connecting…",
|
||
inCall: "In call",
|
||
ended: "Call ended",
|
||
missed: "Missed call",
|
||
declined: "Call declined",
|
||
failed: "Call failed",
|
||
unavailable: "No active ride to call.",
|
||
accept: "Accept",
|
||
decline: "Decline",
|
||
end: "End call",
|
||
mute: "Mute",
|
||
unmute: "Unmute",
|
||
speaker: "Speaker",
|
||
speakerOff: "Speaker off",
|
||
cancel: "Cancel",
|
||
connectingWith: "Connecting with {name}…",
|
||
micDeniedTitle: "Microphone blocked",
|
||
micDeniedBody:
|
||
"Waseel needs microphone access to make calls. Enable it in Settings.",
|
||
audioFailed: "Couldn't start audio. Please try again.",
|
||
},
|
||
|
||
profile: {
|
||
title: "My Profile",
|
||
avatarAlt: "Your Avatar",
|
||
firstName: "First name",
|
||
firstNamePlaceholder: "Your First name",
|
||
lastName: "Last name",
|
||
lastNamePlaceholder: "Your Last name",
|
||
email: "Email",
|
||
emailPlaceholder: "Your Email address",
|
||
},
|
||
|
||
adjustPin: {
|
||
pickupLabel: "Pickup point",
|
||
destinationLabel: "Drop-off point",
|
||
locating: "Finding this place…",
|
||
hint: "Drag the map to move the pin exactly where you want it.",
|
||
confirmPickup: "Confirm pickup point",
|
||
confirmDestination: "Confirm drop-off point",
|
||
recenter: "Go to my location",
|
||
},
|
||
|
||
findRide: {
|
||
adjustOnMap: "Set it on the map",
|
||
title: "Ride",
|
||
from: "From",
|
||
to: "To",
|
||
findNow: "Find now",
|
||
service: "Ride type",
|
||
nAvailable: "{n} nearby",
|
||
estimatedFare: "Estimated fare",
|
||
setBothPoints: "Set a pickup and destination",
|
||
payLaterHint:
|
||
"Drivers nearby will see your request. You choose who takes it, and pay after.",
|
||
sending: "Sending your request…",
|
||
},
|
||
|
||
confirmRide: {
|
||
noDriversInRadius: "No {service} drivers within {km} km",
|
||
tryInstead: "Available near you right now:",
|
||
title: "Request Ride",
|
||
yourTrip: "Your trip",
|
||
pickup: "Pickup",
|
||
destination: "Destination",
|
||
tripTime: "Trip time {time}",
|
||
paymentMethod: "Payment Method",
|
||
cash: "💵 Cash",
|
||
card: "💳 Card",
|
||
fareDisplay: "${fare}",
|
||
lbpEstimate: "≈ {lbp}",
|
||
noDrivers: "No {service} drivers online right now",
|
||
findingDrivers: "Finding drivers nearby…",
|
||
driversNearby: {
|
||
one: "1 driver nearby",
|
||
other: "{n} drivers nearby",
|
||
zero: "No drivers nearby",
|
||
},
|
||
withinRadius: "Within {km} km of you",
|
||
searchingRadius: "Searching within {km} km…",
|
||
nearestDriver: "Nearest driver ≈ {eta} min away",
|
||
requesting: "Requesting…",
|
||
noDriversOnline: "No drivers online",
|
||
requestCash: "Request Ride · Pay cash to driver",
|
||
requestCard: "Request Ride · Pay by card",
|
||
alertMissingRouteTitle: "Missing route",
|
||
alertMissingRouteBody: "Please set a pickup and destination first.",
|
||
alertNoEstimateTitle: "No estimate",
|
||
alertNoEstimateBody: "We couldn't estimate this fare. Please try again.",
|
||
alertErrorTitle: "Error",
|
||
alertErrorFallback:
|
||
"Something went wrong while booking your ride. Please try again.",
|
||
alertPayCardTitle: "Pay by card",
|
||
alertPayCardBody: "Your card will be charged ${fare}.",
|
||
alertInProgressTitle: "Ride already in progress",
|
||
alertInProgressBody:
|
||
"You have a ride in progress. Finish or cancel it before booking another.",
|
||
viewRide: "View ride",
|
||
},
|
||
|
||
bookRide: {
|
||
status: {
|
||
requested: "Finding your driver…",
|
||
choosing: "Choose your driver",
|
||
accepted: "Driver assigned — heading to you",
|
||
enRoute: "On your trip",
|
||
completed: "You've arrived!",
|
||
cancelled: "Ride cancelled",
|
||
arrived: "Your driver is here",
|
||
expired: "No driver available",
|
||
},
|
||
rideNotFound: "Ride not found.",
|
||
couldNotLoad: "Could not load this ride.",
|
||
backHome: "Back Home",
|
||
matchingDriver: "We're matching you with the nearest {service} driver.",
|
||
searchingFor: "Searching for {seconds}s",
|
||
match: {
|
||
driverFallback: "Your driver",
|
||
alertBody: "Something went wrong. Please try again.",
|
||
},
|
||
offers: {
|
||
title: "Drivers available",
|
||
count: {
|
||
one: "1 offer",
|
||
other: "{n} offers",
|
||
zero: "No offers yet",
|
||
},
|
||
away: "{eta} min away · {distance}",
|
||
seats: {
|
||
one: "1 seat",
|
||
other: "{n} seats",
|
||
zero: "",
|
||
},
|
||
pick: "Choose",
|
||
goneTitle: "That driver is gone",
|
||
goneBody: "They took another ride. Pick someone else from the list.",
|
||
goneBodyPaid:
|
||
"They took another ride. Your payment hasn't been used — pick someone else and it will go to them.",
|
||
},
|
||
payment: {
|
||
title: "How would you like to pay?",
|
||
titleNamed: "Ride with {name}",
|
||
subtitle: "Fare ${fare}",
|
||
cash: "Pay cash",
|
||
cashHint: "Hand the fare to your driver at drop-off.",
|
||
card: "Pay by card",
|
||
cardHint: "Charged now, before your driver sets off.",
|
||
working: "Working…",
|
||
},
|
||
ratingFallback: "—",
|
||
paymentCash: "💵 Cash to driver",
|
||
paymentCard: "💳 Paid by card",
|
||
fare: "Fare: ${fare}",
|
||
tripTime: "Trip time {time}",
|
||
rideCancelled: "This ride was cancelled.",
|
||
cancelRide: "Cancel Ride",
|
||
cancelling: "Cancelling…",
|
||
alertErrorTitle: "Error",
|
||
alertErrorBody: "Could not cancel this ride. Please try again.",
|
||
pickupCodeLabel: "Your pickup code",
|
||
pickupCodeHint: "Give this to your driver to start the trip.",
|
||
driverHere: "Your driver is outside",
|
||
cashDue: "Pay ${amount} in cash to your driver.",
|
||
youRated: "You rated this ride {n}★",
|
||
rateDriver: "Rate your driver",
|
||
noDriversFound:
|
||
"No driver picked up your request. Nothing was charged — try again in a moment.",
|
||
cancelledByDriver: "Your driver cancelled this ride.",
|
||
enRouteNotice:
|
||
"Enjoy your ride — your driver will end the trip on arrival.",
|
||
},
|
||
|
||
driver: {
|
||
home: {
|
||
owesCompany: "Commission you owe",
|
||
owesCompanyHint: "Your cash rides — hand this in at the office.",
|
||
owedToDriver: "The company owes you",
|
||
owedToDriverHint: "Card rides, paid out to you.",
|
||
afterFee: "after ${fee} platform fee",
|
||
signOutAlt: "Sign out",
|
||
driverMode: "Driver mode",
|
||
online: "● Online — receiving ride requests",
|
||
goOnline: "○ Go online to drive",
|
||
todaysEarnings: "Today's earnings",
|
||
completedToday: "Completed today",
|
||
incomingRequests: "Incoming requests",
|
||
incomingRequestsOffline: "Incoming requests (offline)",
|
||
finishCurrentRide: "Finish your current ride to see new requests.",
|
||
waitingRequests: "Waiting for ride requests…",
|
||
goOnlineStart: "Go online to start driving.",
|
||
welcome: "Welcome, {name}",
|
||
welcomeFallback: "driver",
|
||
setupIntro:
|
||
"Set up your driver profile to start receiving ride requests.",
|
||
whatDrive: "What will you drive?",
|
||
carModel: "Car model",
|
||
carModelPlaceholder: "e.g. Toyota Camry",
|
||
carSeats: "Car seats",
|
||
carSeatsPlaceholder: "4",
|
||
saving: "Saving…",
|
||
startDriving: "Start driving",
|
||
alertSeatsTitle: "Invalid seats",
|
||
alertSeatsBody: "Car seats must be a whole number 1–8.",
|
||
alertErrorTitle: "Error",
|
||
alertCreateBody:
|
||
"Could not create your driver profile. Please try again.",
|
||
alertToggleBody: "Could not change your status. Please try again.",
|
||
noRequestsAlt: "No recent rides found",
|
||
cashInHand: "Cash collected today",
|
||
uncollected: "Uncollected fares today",
|
||
ratingCount: "{n} ratings",
|
||
ratingNew: "New driver",
|
||
alertOfflineBlocked:
|
||
"Finish or cancel your current ride before going offline.",
|
||
},
|
||
credentials: {
|
||
title: "Your credentials",
|
||
intro:
|
||
"We check every driver before they can take a ride. These details are reviewed by our team.",
|
||
licenseNumber: "Driving licence number",
|
||
licenseNumberPlaceholder: "As printed on your licence",
|
||
licenseExpiry: "Licence expiry",
|
||
nationalId: "National ID number",
|
||
nationalIdPlaceholder: "Your ID card number",
|
||
plateNumber: "Plate number",
|
||
plateNumberPlaceholder: "e.g. 123456/B",
|
||
reviewNote:
|
||
"Your account stays offline until a reviewer approves it. This usually takes less than a day.",
|
||
submit: "Submit for review",
|
||
errorTitle: "Check your details",
|
||
errorMissing:
|
||
"Licence number, national ID and plate number are all required.",
|
||
errorExpiryFormat: "Enter the licence expiry as YYYY-MM-DD.",
|
||
errorExpired: "That licence has already expired.",
|
||
errorScanRequired: "Scan your driving licence before submitting.",
|
||
alertResubmitBody: "Could not resubmit your details. Please try again.",
|
||
},
|
||
captureUnavailable:
|
||
"Photo capture isn't available in this version of the app. Please update to the latest version and try again.",
|
||
photo: {
|
||
title: "Your photo",
|
||
hint: "Taken now with the camera, not from your gallery. Riders see it next to your name when they pick a driver, and use it to check it's you at pickup. Face the camera in good light.",
|
||
take: "Take photo",
|
||
retake: "Retake",
|
||
required: "Take a profile photo before submitting.",
|
||
permissionTitle: "Permission needed",
|
||
permissionCamera:
|
||
"Waseel needs the camera to take your photo. Allow camera access to continue.",
|
||
permissionCameraBlocked:
|
||
"Camera access is turned off for Waseel, and Android won't ask again from here. Open Settings, then turn on Camera under Permissions.",
|
||
errorTitle: "Couldn't save that photo",
|
||
errorBody: "Something went wrong. Please try again.",
|
||
errorTooLarge: "That photo is too large. Try taking a new one.",
|
||
errorRateLimit: "Too many uploads. Wait a few minutes and try again.",
|
||
errorUnsupported: "Use a JPEG, PNG or WebP photo.",
|
||
},
|
||
scan: {
|
||
licenseLabel: "Driving licence",
|
||
licenseHint:
|
||
"Lay it flat and fill the frame. We read the number and expiry off it.",
|
||
idLabel: "ID card",
|
||
idHint: "The side showing your ID number.",
|
||
vehicle_regLabel: "Vehicle registration",
|
||
vehicle_regHint: "The page showing the plate number and the car model.",
|
||
optional: "Optional",
|
||
take: "Take photo",
|
||
retake: "Rescan",
|
||
choose: "Choose photo",
|
||
reading: "Reading your document…",
|
||
filled: {
|
||
one: "Filled in 1 detail — check it below.",
|
||
other: "Filled in {n} details — check them below.",
|
||
},
|
||
savedNoFields:
|
||
"Photo saved, but we couldn't read the details. Type them in below.",
|
||
savedUnreadable:
|
||
"Photo saved. Scanning is unavailable right now — type the details in below.",
|
||
alreadyOnFile: "A scan is already on file. Rescan only if you need to.",
|
||
allRead: "Read from your documents",
|
||
missingPrompt:
|
||
"We couldn't read these off your documents. Please add them and you're done.",
|
||
edit: "Check or edit details",
|
||
done: "Done",
|
||
checkPrompt: "Correct anything that was read wrongly, then tap Done.",
|
||
permissionTitle: "Permission needed",
|
||
permissionCamera:
|
||
"Allow camera access to photograph your documents, or choose a photo instead.",
|
||
permissionCameraBlocked:
|
||
"Camera access is turned off for Waseel, and Android won't ask again from here. Open Settings and turn on Camera under Permissions — or choose an existing photo instead.",
|
||
permissionLibrary:
|
||
"Allow photo access to pick a picture of your documents.",
|
||
permissionLibraryBlocked:
|
||
"Photo access is turned off for Waseel, and Android won't ask again from here. Open Settings and turn on Photos under Permissions — or take a photo with the camera instead.",
|
||
errorTitle: "Couldn't scan that",
|
||
errorBody:
|
||
"Something went wrong. Try again, or type the details in below.",
|
||
errorTooLarge: "That photo is too large. Try taking a new one.",
|
||
errorRateLimit: "Too many scans. Wait a few minutes and try again.",
|
||
errorUnsupported: "Use a JPEG, PNG or WebP photo.",
|
||
errorRetry: "Not uploaded. Try again, or type the details in below.",
|
||
},
|
||
review: {
|
||
pendingTitle: "Under review",
|
||
pendingBody:
|
||
"We're checking your details. You'll be able to go online as soon as you're approved.",
|
||
rejectedTitle: "Not approved",
|
||
rejectedBody:
|
||
"Your details didn't pass review. Correct them below and submit again.",
|
||
suspendedTitle: "Account suspended",
|
||
suspendedBody:
|
||
"Your driver account has been suspended. Contact support to sort this out.",
|
||
approvedTitle: "Approved",
|
||
approvedBody: "You're cleared to drive.",
|
||
reasonLabel: "Reason",
|
||
checkAgain: "Check again",
|
||
resubmitTitle: "Correct your details",
|
||
resubmitIntro: "Fix what's wrong and we'll review it again.",
|
||
resubmit: "Submit again",
|
||
},
|
||
offerCard: {
|
||
youEarn: "You earn",
|
||
newRequest: "New request · {service}",
|
||
openFor: "On the board for",
|
||
seconds: "{n}s",
|
||
awayFromPickup: "{km} km from pickup",
|
||
firstIn: "You'd be first",
|
||
rivals: {
|
||
one: "1 other driver offered",
|
||
other: "{n} other drivers offered",
|
||
zero: "You'd be first",
|
||
},
|
||
cash: "💵 Cash",
|
||
card: "💳 Card",
|
||
fromAlt: "From",
|
||
toAlt: "To",
|
||
tripTime: "Trip time",
|
||
fare: "Fare",
|
||
offer: "Offer this ride",
|
||
withdraw: "Withdraw my offer",
|
||
waitingOnRider: "Offered — waiting for the rider to choose",
|
||
lostTitle: "Request closed",
|
||
lostBody:
|
||
"The rider went with another driver, or the request timed out. You're free for the next one.",
|
||
alertOfferBody: "Could not send your offer. Please try again.",
|
||
alertWithdrawBody: "Could not withdraw your offer. Please try again.",
|
||
},
|
||
activeRide: {
|
||
youEarn: "You earn",
|
||
headToPickup: "Head to pickup",
|
||
tripInProgress: "Trip in progress",
|
||
rider: "{name}",
|
||
pickupPin: "Rider pickup",
|
||
dropoffPin: "Drop-off",
|
||
navigateToPickup: "Navigate to pickup",
|
||
navigateToDropoff: "Navigate to drop-off",
|
||
alertNavigateBody: "Could not open a navigation app on this phone.",
|
||
fromAlt: "From",
|
||
toAlt: "To",
|
||
fare: "Fare",
|
||
message: "Message",
|
||
call: "Call",
|
||
startTrip: "Start trip",
|
||
completeTrip: "Complete trip",
|
||
cancelRide: "Cancel ride",
|
||
cancelConfirmTitle: "Cancel this ride?",
|
||
cancelConfirmBody:
|
||
"The rider will be notified and the ride will be marked as cancelled.",
|
||
cancelConfirmDismiss: "Keep ride",
|
||
cancelConfirmConfirm: "Cancel ride",
|
||
alertErrorTitle: "Error",
|
||
alertAcceptBody:
|
||
"Could not accept this ride. It may have been taken or expired.",
|
||
alertDeclineBody: "Could not decline this ride. Please try again.",
|
||
alertUpdateBody: "Could not update the ride. Please try again.",
|
||
alertCancelBody: "Could not cancel the ride. Please try again.",
|
||
imHere: "I've arrived",
|
||
atPickup: "At pickup — waiting for rider",
|
||
askForCode: "Ask the rider for their 4-digit pickup code.",
|
||
cashConfirmTitle: "Collect the fare",
|
||
cashConfirmBody: "Did you collect ${amount} in cash from the rider?",
|
||
cashCollected: "Yes, collected",
|
||
cashNotCollected: "Not collected",
|
||
},
|
||
},
|
||
|
||
rating: {
|
||
rateDriverTitle: "How was your ride with {name}?",
|
||
rateRiderTitle: "How was {name} as a passenger?",
|
||
subtitle: "Your rating stays private to the other person.",
|
||
starLabel: "{n} stars",
|
||
commentPlaceholder: "Add a comment (optional)",
|
||
submit: "Submit rating",
|
||
notNow: "Not now",
|
||
error: "Could not submit your rating. Please try again.",
|
||
},
|
||
|
||
cancelSheet: {
|
||
title: "Cancel this ride?",
|
||
subtitleRider: "Tell us why so we can improve matching.",
|
||
subtitleDriver: "The rider will be notified and the ride marked cancelled.",
|
||
confirm: "Cancel ride",
|
||
keepRide: "Keep ride",
|
||
cancelling: "Cancelling…",
|
||
reasons: {
|
||
changed_mind: "I changed my mind",
|
||
wait_too_long: "The wait is too long",
|
||
wrong_address: "Wrong pickup address",
|
||
driver_no_show: "The driver never arrived",
|
||
rider_no_show: "The rider never showed up",
|
||
unreachable: "I couldn't reach them",
|
||
vehicle_issue: "Vehicle problem",
|
||
other: "Another reason",
|
||
},
|
||
},
|
||
|
||
pickupCode: {
|
||
title: "Start the trip",
|
||
subtitle: "Enter the 4-digit code from the rider's screen.",
|
||
startTrip: "Start trip",
|
||
wrongCode: "That code doesn't match. Check with the rider.",
|
||
},
|
||
|
||
services: {
|
||
nearbyCount: "{n} nearby",
|
||
noneNearby: "None nearby",
|
||
car: { label: "Car", tagline: "An everyday ride, up to 4 seats." },
|
||
moto: {
|
||
label: "Moto",
|
||
tagline: "Beat the traffic — one passenger, no luggage.",
|
||
},
|
||
courier: {
|
||
label: "Courier",
|
||
tagline: "Send a parcel across town without riding along.",
|
||
},
|
||
chauffeur: {
|
||
label: "My Car",
|
||
tagline: "A driver comes to you and drives your own car.",
|
||
},
|
||
},
|
||
|
||
pois: {
|
||
nearbyTitle: "Nearby suggestions",
|
||
mall: "Mall",
|
||
hospital: "Hospital",
|
||
pharmacy: "Pharmacy",
|
||
restaurant: "Restaurant",
|
||
searching: "searching…",
|
||
noneNearby: "none nearby",
|
||
kmAway: "{km} km away",
|
||
routeAway: "{km} km · {min} min",
|
||
nearbyPlace: "Nearby place",
|
||
},
|
||
|
||
units: {
|
||
min: { zero: "0 min", one: "{n} min", other: "{n} min" },
|
||
h: "{n}h",
|
||
m: "{n}m",
|
||
hoursMinutes: "{h}h {m}m",
|
||
seats: { zero: "{n} seats", one: "{n} seat", other: "{n} seats" },
|
||
lbpSuffix: " L.B.P.",
|
||
},
|
||
|
||
months: {
|
||
jan: "Jan",
|
||
feb: "Feb",
|
||
mar: "Mar",
|
||
apr: "Apr",
|
||
may: "May",
|
||
jun: "Jun",
|
||
jul: "Jul",
|
||
aug: "Aug",
|
||
sep: "Sep",
|
||
oct: "Oct",
|
||
nov: "Nov",
|
||
dec: "Dec",
|
||
},
|
||
|
||
components: {
|
||
oauth: {
|
||
or: "Or",
|
||
googleLogoAlt: "Google logo",
|
||
alertFailTitle: "Google sign-in failed",
|
||
alertFailNoToken: "No token returned. Try again.",
|
||
alertFailFallback: "Please try again.",
|
||
},
|
||
otp: {
|
||
code: "Code",
|
||
codePlaceholder: "123456",
|
||
pasteCode: "Paste code from Gmail",
|
||
},
|
||
googleTextInput: {
|
||
searchAlt: "Search",
|
||
placeholder: "Where do you want to go?",
|
||
},
|
||
inputField: {
|
||
labelIconAlt: "{label} icon",
|
||
},
|
||
locationNotice: {
|
||
denied: {
|
||
title: "Location access is off",
|
||
body: "Waseel needs your location to show nearby drivers and set your pickup point.",
|
||
action: "Open Settings",
|
||
},
|
||
servicesOff: {
|
||
title: "Location services are off",
|
||
body: "Turn on location on your device, then try again.",
|
||
action: "Try Again",
|
||
},
|
||
unavailable: {
|
||
title: "Couldn't find your location",
|
||
body: "Move somewhere with a clearer signal, or set your pickup point manually.",
|
||
action: "Try Again",
|
||
},
|
||
},
|
||
map: {
|
||
destination: "Destination",
|
||
webUnavailable:
|
||
"Map is not available on web.\nRun on Android/iOS for the full experience.",
|
||
},
|
||
rideCard: {
|
||
outcomeCompleted: "Completed",
|
||
outcomeCancelled: "Cancelled",
|
||
outcomeExpired: "No driver found",
|
||
cancelledByYou: "You cancelled",
|
||
cancelledByDriver: "Driver cancelled",
|
||
cancelledBySystem: "No driver available",
|
||
noDriver: "No driver assigned",
|
||
paymentNotCharged: "Not charged",
|
||
paymentRefundDue: "Refund due",
|
||
paymentCashCollected: "Cash paid",
|
||
mapAlt: "Map",
|
||
originAlt: "Origin",
|
||
destinationAlt: "Destination",
|
||
dateTime: "Date & Time",
|
||
driver: "Driver",
|
||
carSeats: "Car Seats",
|
||
fare: "Fare",
|
||
paymentStatus: "Payment Status",
|
||
paymentCash: "Cash · Pay to driver",
|
||
paymentPaid: "Paid by card",
|
||
paymentOther: "{status}",
|
||
},
|
||
rideLayout: {
|
||
goBack: "Go Back",
|
||
backArrowAlt: "Back arrow",
|
||
},
|
||
payment: {
|
||
paymentMethod: "Payment Method",
|
||
cash: "💵 Cash",
|
||
card: "💳 Card",
|
||
processing: "Processing...",
|
||
bookCash: "Book ride · Pay cash to driver",
|
||
confirmCard: "Confirm & Pay by Card",
|
||
checkAlt: "Check",
|
||
rideBooked: "Ride Booked!",
|
||
successBody:
|
||
"Thank you for your booking.\n Your reservation has been placed.\n",
|
||
cashInstruction: "Please have {lbp} ready.",
|
||
backHome: "Back Home",
|
||
alertPayCardTitle: "Pay by card",
|
||
alertPayCardBody: "Your card will be charged ${amount}.",
|
||
alertErrorTitle: "Error",
|
||
alertErrorBody:
|
||
"Something went wrong while booking your ride. Please try again.",
|
||
alertPaymentNotCompletedTitle: "Payment not completed",
|
||
alertPaymentNotCompletedBody:
|
||
"Your payment was cancelled or could not be verified. Please try again.",
|
||
alertProcessingTitle: "Error",
|
||
alertProcessingBody:
|
||
"Something went wrong while processing your payment. Please try again.",
|
||
},
|
||
driverCard: {
|
||
avatarAlt: "Driver Avatar",
|
||
starAlt: "Star",
|
||
dollarAlt: "Dollar",
|
||
carAlt: "Car",
|
||
seats: "{n} seats",
|
||
},
|
||
},
|
||
|
||
settings: {
|
||
title: "Settings",
|
||
maps: {
|
||
title: "Maps & Navigation",
|
||
description:
|
||
"Waseel uses your location to show nearby drivers and navigate to your pickup.",
|
||
statusGranted: "Granted",
|
||
statusDenied: "Not allowed",
|
||
statusBlocked: "Blocked",
|
||
statusUnknown: "Checking…",
|
||
openSettings: "Open Settings",
|
||
},
|
||
appearance: {
|
||
title: "Appearance",
|
||
description: "Choose how Waseel looks.",
|
||
light: "Light",
|
||
dark: "Dark",
|
||
system: "System",
|
||
},
|
||
safety: {
|
||
title: "Safety",
|
||
call112: "Call 112 — Emergency",
|
||
call112Description:
|
||
"Call Lebanon's emergency number for law enforcement, ambulance, or fire.",
|
||
callFailedTitle: "Could not place a call",
|
||
callFailedBody:
|
||
"No dialer is available on this device. Call 112 manually.",
|
||
proactive: {
|
||
title: "Proactive safety",
|
||
body: "Share your trip status and live location with trusted contacts, and ride with confidence knowing help is one tap away.",
|
||
},
|
||
verification: {
|
||
title: "Passenger verification",
|
||
body: "Riders and drivers verify their phone number and identity, so you always know who you're riding with.",
|
||
},
|
||
privacy: {
|
||
title: "Protecting your privacy",
|
||
body: "Your phone number and contact details stay hidden in chat. Messages are visible only between you and your driver for this ride.",
|
||
},
|
||
},
|
||
language: {
|
||
title: "Language",
|
||
description: "App language.",
|
||
en: "English",
|
||
ar: "العربية",
|
||
fr: "Français",
|
||
rtlRestartTitle: "Restart for Arabic",
|
||
rtlRestartBody:
|
||
"Arabic layout will apply fully the next time you open the app.",
|
||
},
|
||
general: {
|
||
title: "General",
|
||
},
|
||
keepAwake: {
|
||
title: "Do not lock screen",
|
||
description: "Keep the display on while the app is open.",
|
||
},
|
||
overlay: {
|
||
title: "Display over other apps",
|
||
description:
|
||
"Required so incoming ride alerts can appear over other apps.",
|
||
allow: "Allow display over other apps",
|
||
openedHint: "Opened system settings",
|
||
notAndroid: "Only available on Android.",
|
||
},
|
||
},
|
||
};
|