b0896dc777
CI/CD / CI · API (dotnet build + test) (push) Successful in 40s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 31s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m8s
CI/CD / CI · Admin Web (tsc) (push) Successful in 38s
CI/CD / CI · Website (tsc) (push) Successful in 46s
CI/CD / CI · Koja (tsc) (push) Successful in 50s
CI/CD / Deploy · all services (push) Successful in 3m29s
The card-terminal integration only ever worked when the API could reach the terminal's IP directly — impossible for the cloud deployment, where the terminal sits on the café LAN (the same wall the Print Agent already climbs for printers). And the terminal IP had to be typed by hand. Both fixed by reusing the agent. Cloud→LAN relay: - PrintAgentRegistry.SendPaymentAsync sends a PaymentRequest to the café's online agent and awaits its ack (PaymentResult on the hub); 95s window for the customer. - PosDeviceService now prefers an online agent (branch-matched, else any café agent) to relay POST /pay over the LAN, and falls back to the direct HTTP call only when no agent is connected (on-prem). Agent errors map back to POS_DEVICE_*. - Agent (Program.cs + PosTerminal.cs) handles PaymentRequest → POSTs the amount to the terminal's local http://ip:port/pay and reports approval/decline/timeout. Auto-detect: - Registry.ScanAsync + hub ReportScan; POST /print-agents/scan asks online agents to scan their /24 for given ports and merges the hosts found. - Agent NetworkScanner scans the LAN (:9100 printers, :8088 terminals) with a short per-host TCP probe. - Dashboard: a "تشخیص خودکار" (auto-detect) button on the POS-device, receipt and kitchen IP fields scans via the agent and fills the IP:port from a found host. Backend + agent build clean; dashboard tsc clean. NOTE: the agent app is not in CI — it must be rebuilt and redeployed on the café PC to gain these handlers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2065 lines
73 KiB
JSON
2065 lines
73 KiB
JSON
{
|
||
"common": {
|
||
"save": "Save",
|
||
"close": "Close",
|
||
"cancel": "Cancel",
|
||
"confirm": "Confirm",
|
||
"delete": "Delete",
|
||
"search": "Search",
|
||
"loading": "Loading...",
|
||
"logout": "Log out",
|
||
"language": "Language",
|
||
"comingSoon": "Coming soon",
|
||
"edit": "Edit"
|
||
},
|
||
"confirm": {
|
||
"title": "Confirm action",
|
||
"confirm": "Confirm",
|
||
"cancel": "Cancel"
|
||
},
|
||
"notify": {
|
||
"saved": "Saved",
|
||
"errorGeneric": "Something went wrong. Please try again."
|
||
},
|
||
"errors": {
|
||
"planLimit": "Plan limit reached. Please upgrade.",
|
||
"notFound": "Not found",
|
||
"unauthorized": "Unauthorized",
|
||
"network": "Network error",
|
||
"generic": "Something went wrong. Please try again.",
|
||
"OFFLINE_UNAVAILABLE": "This action needs an internet connection. Please try again once you are back online."
|
||
},
|
||
"brand": {
|
||
"name": "Meezi"
|
||
},
|
||
"languages": {
|
||
"fa": "فارسی",
|
||
"ar": "العربية",
|
||
"en": "English"
|
||
},
|
||
"auth": {
|
||
"title": "Sign in to Meezi",
|
||
"subtitle": "We will send a verification code to your phone",
|
||
"redirecting": "Already signed in — redirecting…",
|
||
"phone": "Mobile number",
|
||
"phonePlaceholder": "09121234567",
|
||
"sendOtp": "Send code",
|
||
"otp": "Verification code",
|
||
"otpPlaceholder": "6 digits",
|
||
"verify": "Sign in",
|
||
"resend": "Resend",
|
||
"rateLimited": "Too many code requests. Wait up to one hour or contact support.",
|
||
"notFound": "No account found for this mobile number.",
|
||
"smsFailed": "Could not send SMS. Please try again.",
|
||
"invalidOtp": "Invalid or expired verification code.",
|
||
"register": "Create account",
|
||
"registerSubtitle": "Register your cafe on Meezi",
|
||
"cafeName": "Cafe or restaurant name",
|
||
"cafeNamePlaceholder": "e.g. Roya Cafe",
|
||
"createAccount": "Create account",
|
||
"alreadyHaveAccount": "Already have an account?",
|
||
"loginLink": "Sign in",
|
||
"noAccount": "Don't have an account?",
|
||
"registerLink": "Register",
|
||
"alreadyRegistered": "This phone is already registered. Please sign in.",
|
||
"registrationExpired": "Registration session expired. Please try again.",
|
||
"chooseCafe": "Choose a café",
|
||
"chooseCafeSubtitle": "This number has access to several cafés. Pick one to continue.",
|
||
"createNewCafe": "Create a new café",
|
||
"createNewCafeHint": "Want to start your own café with this number?",
|
||
"tabOtp": "One-time code",
|
||
"tabPassword": "Password",
|
||
"username": "Username",
|
||
"usernamePlaceholder": "Username",
|
||
"password": "Password",
|
||
"passwordPlaceholder": "Password",
|
||
"invalidCredentials": "Incorrect username or password.",
|
||
"invalidKey": "Invalid recovery key.",
|
||
"recoveryKey": "Recovery key",
|
||
"keyHint": "Enter the recovery key you received from Meezi support.",
|
||
"useRecoveryKey": "Lost access? Sign in with a recovery key",
|
||
"backToNormalLogin": "Back to normal sign-in",
|
||
"kojaSlug": "Koja profile address",
|
||
"kojaSlugHint": "Customers will find your cafe at this address",
|
||
"kojaSlugPlaceholder": "e.g. my-cafe"
|
||
},
|
||
"roles": {
|
||
"owner": "Owner",
|
||
"manager": "Manager",
|
||
"cashier": "Cashier",
|
||
"waiter": "Waiter",
|
||
"chef": "Chef",
|
||
"delivery": "Delivery",
|
||
"unknown": "User"
|
||
},
|
||
"branchSwitcher": {
|
||
"title": "Active branch",
|
||
"allBranches": "All branches",
|
||
"selectBranch": "Select branch"
|
||
},
|
||
"branchAccess": {
|
||
"title": "Branch access",
|
||
"staff": "Staff",
|
||
"noStaff": "No staff yet",
|
||
"selectStaff": "Select a staff member to manage access",
|
||
"ownerNote": "The owner has access to all branches and does not need per-branch roles.",
|
||
"noAssignments": "No branch roles assigned yet",
|
||
"loading": "Loading...",
|
||
"branch": "Branch",
|
||
"role": "Role",
|
||
"selectBranch": "Select branch",
|
||
"add": "Add",
|
||
"remove": "Remove"
|
||
},
|
||
"access": {
|
||
"deniedTitle": "No access to this page",
|
||
"deniedBody": "Your role doesn't have permission to view this page. Contact a manager or owner if you need access."
|
||
},
|
||
"nav": {
|
||
"aria": "Main navigation",
|
||
"collapseSidebar": "Collapse sidebar",
|
||
"expandSidebar": "Expand sidebar",
|
||
"groups": {
|
||
"customers": "Customers & marketing",
|
||
"management": "Café management"
|
||
},
|
||
"home": "Dashboard",
|
||
"pos": "POS",
|
||
"tables": "Tables",
|
||
"crm": "CRM",
|
||
"coupons": "Coupons",
|
||
"menu": "Menu",
|
||
"orders": "Orders",
|
||
"inventory": "Inventory",
|
||
"hr": "HR",
|
||
"reports": "Reports",
|
||
"expenses": "Expenses",
|
||
"shifts": "Shift close",
|
||
"reviews": "Reviews",
|
||
"reservations": "Reservations",
|
||
"sms": "SMS",
|
||
"taxes": "Taxes",
|
||
"branches": "Branches",
|
||
"subscription": "Plan & billing",
|
||
"support": "Support",
|
||
"settings": "Settings",
|
||
"kds": "Kitchen",
|
||
"notifications": "Notifications",
|
||
"queue": "Daily queue",
|
||
"discover": "Discover cafés"
|
||
},
|
||
"dashboard": {
|
||
"cafeName": "Demo Cafe",
|
||
"planPro": "Pro",
|
||
"online": "Online",
|
||
"offline": "Offline",
|
||
"activePlan": "Active plan",
|
||
"editCafeSettings": "Café settings",
|
||
"viewSubscription": "Plan & billing",
|
||
"switchCafe": "Switch café",
|
||
"currentCafe": "Current café",
|
||
"otherCafes": "Other cafés",
|
||
"createNewCafe": "Create a new café",
|
||
"openMenu": "Menu",
|
||
"switchCafeError": "Could not switch café. Please try again."
|
||
},
|
||
"overview": {
|
||
"title": "Home",
|
||
"greeting": "Welcome back",
|
||
"todayRevenue": "Today's revenue",
|
||
"todayOrders": "Today's orders",
|
||
"netIncome": "Net income",
|
||
"avgOrder": "Avg. order value",
|
||
"revenueChart": "7-day revenue trend",
|
||
"tableStatus": "Table status",
|
||
"tableFree": "Free",
|
||
"tableBusy": "Busy",
|
||
"tableCleaning": "Cleaning",
|
||
"tableTotal": "Total tables",
|
||
"topProducts": "Top sellers",
|
||
"vsYesterday": "vs yesterday",
|
||
"noData": "No data available",
|
||
"quickLinks": "Quick access",
|
||
"unit": "items"
|
||
},
|
||
"pos": {
|
||
"order": "Order",
|
||
"table": "Table",
|
||
"total": "Total",
|
||
"subtotal": "Subtotal",
|
||
"tax": "Tax",
|
||
"discount": "Discount",
|
||
"confirmOrder": "Confirm & pay",
|
||
"modeOrder": "Take order",
|
||
"modePay": "Pay",
|
||
"takeOrder": "Order taking",
|
||
"submitOrder": "Submit order",
|
||
"submitOrderAndPay": "Submit order & pay",
|
||
"orderPaidNew": "Order submitted and paid",
|
||
"orderPaidAdd": "Items added and paid",
|
||
"posDeviceSent": "Amount sent to POS terminal",
|
||
"posDeviceError": "Could not send amount to POS terminal",
|
||
"posDeviceNotConfigured": "POS terminal not configured — payment recorded in Meezi only",
|
||
"posDeviceConnectionFailed": "Could not connect to POS terminal",
|
||
"posDeviceTimeout": "POS terminal timed out",
|
||
"posDeviceRejected": "POS terminal rejected the payment",
|
||
"posDeviceNoBranch": "No branch selected for POS payment",
|
||
"kitchenSlip": "Kitchen ticket (preview & print)",
|
||
"queueNumber": "Queue #{number}",
|
||
"orderPlaced": "Order saved — go to Pay to collect payment",
|
||
"guestName": "Guest name",
|
||
"guestNamePlaceholder": "e.g. Ali",
|
||
"needTableOrName": "Select a table, customer, or guest name",
|
||
"openOrders": "Open orders",
|
||
"openOrdersHint": "Orders not paid yet",
|
||
"noOpenOrders": "No orders waiting for payment",
|
||
"payOrder": "Payment",
|
||
"payFor": "Pay for",
|
||
"selectOrderToPay": "Select an order from the list",
|
||
"confirmPay": "Collect payment",
|
||
"confirmPayCash": "Collect payment (cash)",
|
||
"confirmPayCard": "Collect payment (card)",
|
||
"confirmPayCredit": "Collect payment (credit)",
|
||
"confirmPaySplit": "Collect payment (split)",
|
||
"previewBill": "Preview & print bill",
|
||
"paySuccess": "Payment recorded",
|
||
"payError": "Payment failed",
|
||
"payNeedsOpenShift": "Open the register shift for this branch before taking payment",
|
||
"cancelOrder": "Cancel order (no payment)",
|
||
"cancelOrderConfirm": "Customer left without paying? The order will be cancelled and the table freed.",
|
||
"cancelOrderSuccess": "Order cancelled",
|
||
"cancelOrderError": "Could not cancel order",
|
||
"cancelReasonPlaceholder": "Cancellation reason (optional)",
|
||
"cancelOrderHasPayments": "Refund the recorded payments first, then cancel the order",
|
||
"itemsCount": "items",
|
||
"applyCoupon": "Apply coupon",
|
||
"couponPlaceholder": "Coupon code",
|
||
"couponCode": "Coupon code",
|
||
"selectTable": "Table",
|
||
"emptyCart": "Cart is empty",
|
||
"cash": "Cash",
|
||
"card": "Card",
|
||
"clearCart": "Clear",
|
||
"allCategories": "All",
|
||
"searchItems": "Search items",
|
||
"searchItemsPlaceholder": "Search by item name…",
|
||
"searchNoResults": "No items match your search",
|
||
"reservationBanner": "Reservation: {name} — add items and tap Confirm & pay",
|
||
"orderSuccess": "Order placed",
|
||
"orderError": "Failed to place order",
|
||
"orderInvalid": "Invalid order (check menu items or table)",
|
||
"orderNotOpen": "This order is no longer open",
|
||
"orderValidation": "Invalid order details",
|
||
"nothingPending": "No new items to send to the kitchen",
|
||
"couponApplied": "Coupon «{code}» applied — {amount} off",
|
||
"couponActive": "Coupon {code}",
|
||
"couponRemoved": "Coupon removed",
|
||
"removeCoupon": "Remove",
|
||
"couponInvalid": "Invalid coupon code",
|
||
"couponExpired": "This coupon has expired",
|
||
"couponNotStarted": "This coupon is not active yet",
|
||
"couponLimitReached": "This coupon has reached its usage limit",
|
||
"couponMinOrder": "Minimum order amount not met",
|
||
"couponCartEmpty": "Add items to the cart first",
|
||
"couponRequired": "Enter a coupon code",
|
||
"guestPhone": "Guest phone",
|
||
"guestPhonePlaceholder": "09121234567",
|
||
"selectTableBoard": "Select table",
|
||
"loadingTables": "Loading tables...",
|
||
"selectBranchForTables": "Select a branch first",
|
||
"noTablesOnBoard": "No tables for this branch. Add tables in the Tables screen.",
|
||
"tablesLoadError": "Could not load tables",
|
||
"retryTables": "Try again",
|
||
"manageTablesLink": "Go to Tables",
|
||
"sessionActive": "Active table session",
|
||
"addToOrder": "Added to table order",
|
||
"void": "Void",
|
||
"voidItem": "Void item",
|
||
"voided": "Voided",
|
||
"itemNotePlaceholder": "Note for kitchen/bar (optional)",
|
||
"confirmVoid": "Are you sure you want to void this item?",
|
||
"voidError": "Could not void item",
|
||
"transferTable": "Transfer table",
|
||
"selectTargetTable": "Select destination table",
|
||
"transferSuccess": "Order transferred successfully",
|
||
"transferError": "Could not transfer table",
|
||
"tableNotAvailable": "Table is being cleaned",
|
||
"tableOccupied": "Table is already occupied",
|
||
"searchOpenOrder": "Table, name, phone, or order ID...",
|
||
"paidSoFar": "Paid",
|
||
"remaining": "Remaining",
|
||
"loyaltyBalance": "Customer points: {points}",
|
||
"loyaltyUseMax": "Max",
|
||
"loyaltyRedeemHint": "1 point = 100 T discount on this payment",
|
||
"loyaltyRedeemApplied": "Points discount",
|
||
"loyaltyNoCustomer": "Attach a customer to the order to redeem points",
|
||
"loyaltyInsufficient": "Not enough points",
|
||
"splitPayments": "Split payment",
|
||
"addPaymentRow": "Add payment row",
|
||
"credit": "Credit",
|
||
"paySelectTable": "Pick table (occupied)",
|
||
"payPickByName": "Or pick by name / open order list",
|
||
"payOpenOrdersHint": "Tap an occupied table, use the table dropdown, or search by name/phone",
|
||
"allTables": "All tables",
|
||
"noOrderOnTable": "No open order on this table",
|
||
"noOpenOrdersOnTable": "No open orders for this table",
|
||
"customerSection": "Customer",
|
||
"existingCustomer": "Existing",
|
||
"newCustomer": "New guest",
|
||
"customerSearchPlaceholder": "Name, phone, or national ID...",
|
||
"customerSearchHint": "Type at least 2 characters to search",
|
||
"customerNotFound": "No customer found — add as new guest",
|
||
"customerSaved": "Customer saved to CRM",
|
||
"customerSaveError": "Could not save customer",
|
||
"customerPhoneExists": "Phone already registered — search and select",
|
||
"newCustomerHint": "Use for this order only, or tap Add customer to save to CRM",
|
||
"offlineQueueNotice": "Offline — order saved in queue and will sync when connected",
|
||
"orderTypePicker": "How would you like to take this order?",
|
||
"orderTypeTable": "Table",
|
||
"orderTypeTableDesc": "Seat guest at a specific table",
|
||
"orderTypeCounter": "Counter",
|
||
"orderTypeCounterDesc": "Walk-in, no table yet",
|
||
"orderTypeTakeaway": "Takeaway",
|
||
"orderTypeTakeawayDesc": "Order to go",
|
||
"counterBadge": "Counter",
|
||
"takeawayBadge": "Takeaway",
|
||
"assignTable": "Assign table",
|
||
"newOrder": "New order"
|
||
},
|
||
"print": {
|
||
"printReceipt": "Print receipt",
|
||
"printKitchen": "Send to kitchen",
|
||
"success": "Receipt printed successfully",
|
||
"notConfigured": "Printer IP is not configured",
|
||
"connectionFailed": "Could not connect to printer",
|
||
"testPrint": "Test print",
|
||
"printerSettings": "Printer settings",
|
||
"receiptPrinter": "Receipt printer",
|
||
"kitchenPrinter": "Kitchen printer",
|
||
"paperWidth": "Paper width",
|
||
"autoCut": "Auto cut",
|
||
"port": "Port",
|
||
"receiptHeader": "Receipt header",
|
||
"receiptFooter": "Receipt footer",
|
||
"wifiOnReceipt": "WiFi password on receipt",
|
||
"saveSettings": "Save settings",
|
||
"settingsSaved": "Printer settings saved",
|
||
"noBranchForPrinter": "Add a branch before configuring printers.",
|
||
"testPageHint": "Sends a test ticket to your saved printers. Configure IP and port under Printer settings first.",
|
||
"testPrintReceipt": "Test receipt printer",
|
||
"testPrintKitchen": "Test kitchen printer",
|
||
"configurePrinters": "Open printer settings",
|
||
"posDeviceSection": "Card POS terminal",
|
||
"posDeviceHint": "On card payment, the amount is sent via HTTP (POST /pay) to the device on your LAN.",
|
||
"posDeviceIp": "POS device IP address",
|
||
"detect": "Auto-detect",
|
||
"detecting": "Scanning the network…",
|
||
"detectNone": "No devices found on the network",
|
||
"detectOffline": "A print server must be online to auto-detect",
|
||
"detectHint": "The print server scans your LAN to find the device.",
|
||
"testSent": "Test sent to the printer.",
|
||
"sent": "Sent to the printer.",
|
||
"noStationItems": "This order has no items for that station.",
|
||
"printFailed": "Print failed.",
|
||
"stations": {
|
||
"title": "Kitchen & bar print stations",
|
||
"subtitle": "Give each prep area its own printer and route menu categories to it.",
|
||
"help": "Create a station (e.g. Kitchen, Bar) with its own printer, then in Menu set each category’s print station — food → Kitchen, drinks → Bar. Items in a category with no station fall back to the branch kitchen printer. The customer receipt always prints to the receipt printer.",
|
||
"add": "Add station",
|
||
"name": "Station name",
|
||
"namePlaceholder": "e.g. Kitchen, Bar",
|
||
"printerIp": "Printer IP",
|
||
"noPrinter": "No printer — uses the kitchen printer",
|
||
"categoryCount": "{count} categories",
|
||
"test": "Test",
|
||
"empty": "No stations yet. Add Kitchen and Bar to print their items separately.",
|
||
"deleteConfirm": "Delete station “{name}”? Its categories will fall back to the kitchen printer.",
|
||
"saveError": "Failed to save the station."
|
||
},
|
||
"agents": {
|
||
"title": "Print servers (auto-discovery)",
|
||
"hint": "Install the Meezi print agent on the cash PC to auto-detect its USB & network printers and print through it.",
|
||
"add": "Add print server",
|
||
"pairingTitle": "Enter this code in the print agent on the cash PC:",
|
||
"pairingSteps": "Install and run the Meezi Print Agent on the PC connected to the printers, then enter this code. It is valid for 15 minutes.",
|
||
"empty": "No print server connected yet.",
|
||
"online": "Online",
|
||
"offline": "Offline",
|
||
"noDevices": "Discovering printers…",
|
||
"test": "Test",
|
||
"receiptVia": "Receipt printer (via server)",
|
||
"kitchenVia": "Kitchen printer (via server)",
|
||
"viaServer": "Printer (via server)",
|
||
"useIpInstead": "— Use manual IP —",
|
||
"revokeConfirm": "Remove print server “{name}”? It will no longer be able to print.",
|
||
"codeError": "Could not create code."
|
||
}
|
||
},
|
||
"receipt": {
|
||
"table": "Table",
|
||
"order": "Order",
|
||
"guest": "Guest",
|
||
"total": "Total",
|
||
"print": "Print",
|
||
"close": "Close",
|
||
"thankYou": "Thank you for your visit",
|
||
"kitchenTitle": "Kitchen / bar ticket",
|
||
"billTitle": "Customer bill",
|
||
"kitchenFooter": "— For kitchen —",
|
||
"payment": {
|
||
"cash": "Cash",
|
||
"card": "Card",
|
||
"credit": "Credit"
|
||
}
|
||
},
|
||
"crm": {
|
||
"title": "Customers",
|
||
"searchPlaceholder": "Name, phone, or national ID...",
|
||
"addCustomer": "Add customer",
|
||
"name": "Name",
|
||
"phone": "Phone",
|
||
"nationalId": "National ID",
|
||
"birthDate": "Birth date (Jalali)",
|
||
"group": "Group",
|
||
"loyaltyPoints": "Points",
|
||
"noCustomers": "No customers found",
|
||
"groups": {
|
||
"Regular": "Regular",
|
||
"Vip": "VIP",
|
||
"New": "New",
|
||
"Employee": "Employee"
|
||
},
|
||
"wizard": {
|
||
"titleCreate": "Add customer",
|
||
"titleEdit": "Edit customer",
|
||
"stepOf": "Step {current} of {total}",
|
||
"steps": {
|
||
"contact": "Contact",
|
||
"profile": "Profile",
|
||
"loyalty": "Group & points",
|
||
"confirm": "Review"
|
||
},
|
||
"back": "Back",
|
||
"next": "Next",
|
||
"birthHint": "Jalali format, e.g. 1400/01/01",
|
||
"referredBy": "Referred by (optional)",
|
||
"loyaltyCreateHint": "Loyalty points can be adjusted after the customer is created.",
|
||
"errors": {
|
||
"duplicatePhone": "This phone number is already registered.",
|
||
"generic": "Could not save. Please try again."
|
||
}
|
||
},
|
||
"deleted": "Customer deleted",
|
||
"deleteConfirmTitle": "Delete customer",
|
||
"deleteConfirmDesc": "Delete “{name}”?"
|
||
},
|
||
"coupons": {
|
||
"title": "Coupons",
|
||
"addCoupon": "New coupon",
|
||
"code": "Code",
|
||
"type": "Type",
|
||
"value": "Value",
|
||
"usage": "Usage",
|
||
"active": "Active",
|
||
"inactive": "Inactive",
|
||
"types": {
|
||
"Percentage": "Percentage",
|
||
"FixedAmount": "Fixed amount",
|
||
"FreeItem": "Free item"
|
||
},
|
||
"noCoupons": "No coupons yet",
|
||
"deleted": "Coupon deleted",
|
||
"deleteConfirmTitle": "Delete coupon",
|
||
"deleteConfirmDesc": "Delete coupon “{code}”?"
|
||
},
|
||
"hr": {
|
||
"title": "Human resources",
|
||
"tabs": {
|
||
"attendance": "Attendance",
|
||
"leave": "Leave",
|
||
"payroll": "Payroll",
|
||
"access": "Branch access",
|
||
"credentials": "Login credentials",
|
||
"team": "Team",
|
||
"roles": "Roles & permissions"
|
||
},
|
||
"myAttendance": "My attendance",
|
||
"clockIn": "Clock in",
|
||
"clockOut": "Clock out",
|
||
"approve": "Approve",
|
||
"noLeave": "No pending leave requests",
|
||
"paid": "Paid",
|
||
"markPaid": "Mark paid",
|
||
"employeeCount": "Employees",
|
||
"monthYear": "Payroll month",
|
||
"credentials": {
|
||
"title": "Employee login credentials",
|
||
"subtitle": "Set a username and password for each employee so they can sign in without an OTP.",
|
||
"selectEmployee": "Select an employee first",
|
||
"username": "Username",
|
||
"usernamePlaceholder": "e.g. ali_barista",
|
||
"password": "Password (min 8 characters)",
|
||
"passwordPlaceholder": "New password",
|
||
"set": "Save credentials",
|
||
"remove": "Remove credentials",
|
||
"removeConfirm": "Are you sure? The employee will no longer be able to sign in with a password.",
|
||
"saved": "Credentials saved.",
|
||
"removed": "Credentials removed.",
|
||
"usernameTaken": "This username is already taken."
|
||
},
|
||
"addEmployee": "Add employee",
|
||
"noEmployees": "No employees yet.",
|
||
"employeeCreated": "Employee added",
|
||
"employeeDetails": "Employee details",
|
||
"employeeNotFound": "This user is no longer active.",
|
||
"openInHr": "Open in HR",
|
||
"save": "Save",
|
||
"cancel": "Cancel",
|
||
"fields": {
|
||
"name": "Name",
|
||
"phone": "Mobile",
|
||
"role": "Role",
|
||
"branch": "Branch",
|
||
"branchOptional": "optional",
|
||
"noBranch": "No branch",
|
||
"baseSalary": "Base salary (Toman)",
|
||
"optional": "optional",
|
||
"enableLogin": "Create username & password",
|
||
"username": "Username",
|
||
"password": "Password",
|
||
"passwordHint": "At least 8 characters"
|
||
},
|
||
"roles": {
|
||
"Owner": "Owner",
|
||
"Manager": "Manager",
|
||
"Cashier": "Cashier",
|
||
"Waiter": "Waiter",
|
||
"Chef": "Chef",
|
||
"Delivery": "Delivery"
|
||
}
|
||
},
|
||
"reviews": {
|
||
"title": "Customer reviews",
|
||
"summary": "Average rating",
|
||
"reviewCount": "{count} reviews",
|
||
"empty": "No reviews yet.",
|
||
"ownerReply": "Cafe reply",
|
||
"reply": "Reply",
|
||
"replyPlaceholder": "Write your reply..."
|
||
},
|
||
"sms": {
|
||
"title": "SMS marketing",
|
||
"message": "Message",
|
||
"messagePlaceholder": "Write your SMS text...",
|
||
"targetGroup": "Target group",
|
||
"allCustomers": "All customers",
|
||
"send": "Send",
|
||
"usage": "Sent this month",
|
||
"unlimited": "Unlimited",
|
||
"sent": "Sent",
|
||
"failed": "Failed",
|
||
"charCount": "{count} chars",
|
||
"smsPartsHint": "{parts} SMS",
|
||
"balance": "Your account credit",
|
||
"balanceAmount": "{amount} Rials",
|
||
"balanceNotConfigured": "SMS service not set up",
|
||
"sender": "Sender line",
|
||
"recipientsCount": "{count} recipients",
|
||
"sendConfirm": "Send to {count} people?",
|
||
"sending": "Sending...",
|
||
"byoHint": "SMS is sent through your OWN provider account and line — sending costs are billed directly by your SMS provider.",
|
||
"notConfiguredOwner": "To send SMS, first save your Kavenegar API key and sender line in the settings above.",
|
||
"notConfiguredStaff": "The SMS service has not been set up by the café manager yet.",
|
||
"settings": {
|
||
"title": "SMS provider settings",
|
||
"hint": "Create an API key in your Kavenegar panel (kavenegar.com) and enter it with your sender line number.",
|
||
"apiKey": "Kavenegar API key",
|
||
"apiKeyPlaceholder": "API Key",
|
||
"senderNumber": "Sender line number",
|
||
"senderPlaceholder": "10004346...",
|
||
"configured": "SMS service is active.",
|
||
"notConfigured": "Not set up yet.",
|
||
"save": "Save",
|
||
"saving": "Verifying…",
|
||
"saved": "SMS settings saved.",
|
||
"saveFailed": "The API key is invalid or saving failed."
|
||
}
|
||
},
|
||
"reports": {
|
||
"title": "Reports & analytics",
|
||
"subtitle": "Sales summary from daily snapshots",
|
||
"exportCsv": "Download CSV",
|
||
"fromDate": "From",
|
||
"toDate": "To",
|
||
"branch": "Branch",
|
||
"allBranches": "All branches",
|
||
"preset": {
|
||
"7d": "7 days",
|
||
"30d": "30 days",
|
||
"90d": "90 days"
|
||
},
|
||
"kpiTotalRevenue": "Total revenue",
|
||
"kpiTotalOrders": "Orders",
|
||
"kpiAvgOrder": "Avg. order value",
|
||
"kpiNetIncome": "Net income",
|
||
"kpiTotalExpenses": "Total expenses",
|
||
"vsPrevious": "vs previous period",
|
||
"revenueChartTitle": "Daily revenue trend",
|
||
"paymentMixTitle": "Payment methods",
|
||
"branchCompareTitle": "Branch comparison",
|
||
"topProductsTitle": "Top products",
|
||
"colProduct": "Product",
|
||
"colQuantity": "Qty",
|
||
"colRevenue": "Revenue",
|
||
"revenue": "Revenue",
|
||
"cash": "Cash",
|
||
"card": "Card",
|
||
"credit": "Credit",
|
||
"noData": "No data",
|
||
"loading": "Loading...",
|
||
"csvDate": "Date",
|
||
"csvBranch": "Branch",
|
||
"csvTotalRevenue": "Total revenue",
|
||
"csvTotalOrders": "Orders",
|
||
"csvAvgOrder": "Avg order",
|
||
"csvCash": "Cash",
|
||
"csvCard": "Card",
|
||
"csvCredit": "Credit",
|
||
"csvNetIncome": "Net income",
|
||
"csvVoids": "Voids",
|
||
"csvVoidAmount": "Void amount",
|
||
"csvExpenses": "Expenses",
|
||
"tabs": {
|
||
"performance": "Performance & profit",
|
||
"corrections": "Payment corrections",
|
||
"auditLog": "Activity log"
|
||
},
|
||
"dailyBreakdownTitle": "Daily breakdown — sales, expenses & profit",
|
||
"colDate": "Date",
|
||
"colOrders": "Orders",
|
||
"colExpenses": "Expenses",
|
||
"colNet": "Net profit",
|
||
"corrections": {
|
||
"date": "Date",
|
||
"branch": "Branch",
|
||
"allBranches": "All branches",
|
||
"hint": "Find the order with the wrongly-recorded payment and hit “Correct”.",
|
||
"loadFailed": "Failed to load orders.",
|
||
"retry": "Retry",
|
||
"empty": "No closed orders on this day.",
|
||
"colOrder": "Order",
|
||
"colTime": "Time",
|
||
"colStatus": "Status",
|
||
"colTotal": "Total",
|
||
"colPayments": "Payments",
|
||
"table": "Table",
|
||
"statusPaid": "Settled",
|
||
"statusCancelled": "Cancelled",
|
||
"correctAction": "Correct",
|
||
"prevPage": "Previous",
|
||
"nextPage": "Next",
|
||
"dialogTitle": "Payment correction",
|
||
"orderTotal": "Order total",
|
||
"voidSection": "Wrong payments (select to void)",
|
||
"replacementSection": "Replacement payments",
|
||
"addReplacement": "Add",
|
||
"noReplacements": "Leave empty if you are only voiding.",
|
||
"method": "Method",
|
||
"amount": "Amount",
|
||
"removeReplacement": "Remove row",
|
||
"reason": "Reason (required)",
|
||
"reasonPlaceholder": "e.g. recorded as cash by mistake, was paid by card",
|
||
"paidAfter": "Paid total after correction",
|
||
"shortBy": "Short of order total by",
|
||
"overBy": "Over order total by",
|
||
"cancel": "Cancel",
|
||
"submit": "Submit correction",
|
||
"saved": "Correction recorded.",
|
||
"saveFailed": "Failed to record correction."
|
||
},
|
||
"auditLog": {
|
||
"category": "Category",
|
||
"allCategories": "All",
|
||
"categories": {
|
||
"Payment": "Payment",
|
||
"Order": "Order",
|
||
"Register": "Register",
|
||
"Staff": "Staff"
|
||
},
|
||
"fromDate": "From",
|
||
"toDate": "To",
|
||
"branch": "Branch",
|
||
"allBranches": "All branches",
|
||
"loadFailed": "Failed to load the activity log.",
|
||
"retry": "Retry",
|
||
"empty": "Nothing recorded.",
|
||
"colTime": "Time",
|
||
"colCategory": "Category",
|
||
"colActor": "User",
|
||
"colSummary": "Summary",
|
||
"details": "Details",
|
||
"systemActor": "System",
|
||
"unknownActor": "Unknown user",
|
||
"prevPage": "Previous",
|
||
"nextPage": "Next"
|
||
}
|
||
},
|
||
"shifts": {
|
||
"title": "Cash shift",
|
||
"subtitle": "Open and close the register daily",
|
||
"branch": "Branch",
|
||
"openShift": "Open shift",
|
||
"shiftOpen": "Shift is open",
|
||
"startShift": "Start shift",
|
||
"closeShift": "Close shift",
|
||
"confirmClose": "Confirm close",
|
||
"openingCash": "Opening float",
|
||
"expectedCash": "Expected cash",
|
||
"countedCash": "Counted cash",
|
||
"opened": "Shift opened",
|
||
"closed": "Shift closed"
|
||
},
|
||
"expenses": {
|
||
"title": "Expenses",
|
||
"subtitle": "Log and track branch expenses",
|
||
"addExpense": "Log expense",
|
||
"listTitle": "Expense log",
|
||
"branch": "Branch",
|
||
"fromDate": "From",
|
||
"toDate": "To",
|
||
"periodTotal": "Period total",
|
||
"category": "Category",
|
||
"amount": "Amount",
|
||
"note": "Note",
|
||
"notePlaceholder": "Optional",
|
||
"linkOpenShift": "Deduct from open register (cash withdrawal)",
|
||
"noOpenShift": "No open shift — expense will not link to a register",
|
||
"colDate": "Date",
|
||
"colCategory": "Category",
|
||
"colNote": "Note",
|
||
"colAmount": "Amount",
|
||
"loading": "Loading...",
|
||
"empty": "No expenses logged",
|
||
"rowCount": "{count} rows",
|
||
"categories": {
|
||
"Supplies": "Supplies",
|
||
"Utilities": "Utilities",
|
||
"Salary": "Salary",
|
||
"Rent": "Rent",
|
||
"Maintenance": "Maintenance",
|
||
"Other": "Other"
|
||
}
|
||
},
|
||
"queue": {
|
||
"title": "Daily queue",
|
||
"subtitle": "Ticket numbers restart at 1 each day (Iran calendar)",
|
||
"nowServing": "Now serving",
|
||
"lastIssued": "Last issued",
|
||
"waitingCount": "{count} waiting",
|
||
"issueNext": "New number",
|
||
"callNext": "Call next",
|
||
"customerLabelPlaceholder": "Guest name (optional)",
|
||
"dailyResetHint": "Numbers reset at midnight Iran time.",
|
||
"empty": "No tickets issued today yet.",
|
||
"issuedOnOrder": "Queue #{number}",
|
||
"openDisplay": "TV display",
|
||
"displayMode": "Fullscreen",
|
||
"exitDisplay": "Back to panel",
|
||
"displayWaitingLabel": "In queue",
|
||
"displayUpNext": "Up next",
|
||
"status": {
|
||
"Waiting": "Waiting",
|
||
"Called": "Called",
|
||
"Done": "Done",
|
||
"Cancelled": "Cancelled"
|
||
}
|
||
},
|
||
"kds": {
|
||
"title": "Kitchen display",
|
||
"pending": "Pending",
|
||
"preparing": "Preparing",
|
||
"ready": "Ready",
|
||
"table": "Table",
|
||
"noOrders": "No orders",
|
||
"loading": "Loading...",
|
||
"live": "Live",
|
||
"polling": "Polling",
|
||
"allStations": "All",
|
||
"defaultStation": "Kitchen",
|
||
"advance": "Next step",
|
||
"status": {
|
||
"Pending": "Pending",
|
||
"Confirmed": "Confirmed",
|
||
"Preparing": "Preparing",
|
||
"Ready": "Ready",
|
||
"Delivered": "Delivered",
|
||
"Cancelled": "Cancelled"
|
||
},
|
||
"advanceTo": {
|
||
"Confirmed": "Confirm order",
|
||
"Preparing": "Start preparing",
|
||
"Ready": "Mark ready",
|
||
"Delivered": "Mark delivered"
|
||
}
|
||
},
|
||
"tables": {
|
||
"title": "Table management",
|
||
"addTable": "Add table",
|
||
"number": "Table number",
|
||
"capacity": "Capacity",
|
||
"floor": "Floor",
|
||
"floorPlan": "Floor plan",
|
||
"empty": "No tables yet.",
|
||
"emptyBranch": "No tables for this branch.",
|
||
"allBranches": "All branches",
|
||
"branchFilter": "Branch filter",
|
||
"branch": "Branch",
|
||
"branchUnassigned": "No branch",
|
||
"branchHint": "Tables belong to your café; branch is optional for POS and reports.",
|
||
"tableLabel": "Table {number}",
|
||
"meta": "Cap. {capacity} · Floor {floor}",
|
||
"status": {
|
||
"Free": "Free",
|
||
"Busy": "Occupied",
|
||
"Reserved": "Reserved",
|
||
"Cleaning": "Cleaning",
|
||
"free": "Available",
|
||
"occupied": "Occupied",
|
||
"reserved": "Reserved",
|
||
"cleaning": "Cleaning"
|
||
},
|
||
"markCleaning": "Needs cleaning",
|
||
"markReady": "Ready for guests",
|
||
"activeOrder": "Active order",
|
||
"reserved": "Reserved",
|
||
"printQr": "Print QR",
|
||
"qrMenuUrl": "Guest menu link",
|
||
"openQrUrl": "Open",
|
||
"copyQrUrl": "Copy link",
|
||
"qrUrlCopied": "Link copied",
|
||
"qrUrlCopyFailed": "Could not copy link",
|
||
"reprintHint": "Lost QR? Same button — code never changes.",
|
||
"deactivate": "Deactivate",
|
||
"inactive": "Inactive",
|
||
"edit": "Edit",
|
||
"editTable": "Edit table",
|
||
"reactivate": "Reactivate",
|
||
"saveTable": "Save table",
|
||
"media": "Table image & video",
|
||
"section": "Section",
|
||
"sections": "Sections",
|
||
"addSection": "Add section",
|
||
"noSection": "No section",
|
||
"noSectionsYet": "No sections defined yet.",
|
||
"sectionTableCount": "{count} tables",
|
||
"sectionHasTables": "This section has tables and cannot be deleted",
|
||
"tableHasOpenOrder": "This table has an open order",
|
||
"deleteTable": "Delete table",
|
||
"deleteTableConfirm": "Permanently delete this table? (Only when it has no open order)",
|
||
"deleteError": "Could not delete table",
|
||
"createError": "Could not add table",
|
||
"cleaningError": "Could not update cleaning status"
|
||
},
|
||
"menuAdmin": {
|
||
"title": "Menu management",
|
||
"subtitle": "Images, prices, and per-item discounts",
|
||
"categories": "Categories",
|
||
"items": "Items",
|
||
"addCategory": "New category",
|
||
"addItem": "Add item",
|
||
"name": "Name",
|
||
"nameEn": "English name (for international guests)",
|
||
"price": "Price (T)",
|
||
"category": "Category",
|
||
"available": "Available",
|
||
"unavailable": "Unavailable",
|
||
"discountPercent": "Discount (%)",
|
||
"discountBadge": "off",
|
||
"uploadImage": "Upload image",
|
||
"imageReady": "Image ready",
|
||
"empty": "No menu items yet.",
|
||
"editItem": "Edit",
|
||
"editCategory": "Edit category",
|
||
"categoryIcon": "Icon (emoji)",
|
||
"categoryImage": "Category image",
|
||
"iconTabPreset": "Preset icons",
|
||
"iconTabEmoji": "Emoji",
|
||
"iconTabImage": "Upload image",
|
||
"iconStyleLabel": "Design style",
|
||
"iconPreview": "Preview:",
|
||
"clearIconPreset": "Clear icon",
|
||
"clearIconEmoji": "Clear emoji",
|
||
"categoryIconCustom": "Or custom emoji",
|
||
"iconPresetGroupDrinks": "Drinks",
|
||
"iconPresetGroupFood": "Food",
|
||
"iconStyles": {
|
||
"flat": "Flat",
|
||
"modern": "Modern",
|
||
"real": "Real",
|
||
"minimal": "Minimal",
|
||
"outline": "Outline",
|
||
"soft": "Soft",
|
||
"bold": "Bold",
|
||
"gradient": "Gradient",
|
||
"pastel": "Pastel",
|
||
"duotone": "Duotone"
|
||
},
|
||
"iconEmojiGroups": {
|
||
"hotDrinks": "Hot drinks",
|
||
"coldDrinks": "Cold drinks",
|
||
"breakfast": "Breakfast",
|
||
"mains": "Main dishes",
|
||
"pastaPizza": "Pasta & pizza",
|
||
"desserts": "Desserts",
|
||
"salads": "Salads",
|
||
"seafoodGrill": "Grill & seafood",
|
||
"snacks": "Snacks & fast food",
|
||
"vegan": "Plant-based",
|
||
"specials": "Specials",
|
||
"general": "General"
|
||
},
|
||
"iconPresets": {
|
||
"drinks-hot": "Hot coffee",
|
||
"drinks-cold": "Cold drinks",
|
||
"drinks-tea": "Tea",
|
||
"drinks-juice": "Juice",
|
||
"drinks-milkshake": "Milk & smoothies",
|
||
"drinks-alcohol": "Wine",
|
||
"drinks-beer": "Beer",
|
||
"breakfast": "Breakfast",
|
||
"food-mains": "Main dishes",
|
||
"food-fastfood": "Fast food",
|
||
"food-rice": "Rice dishes",
|
||
"pasta-pizza": "Pasta & pizza",
|
||
"dessert": "Dessert",
|
||
"ice-cream": "Ice cream",
|
||
"bakery": "Bakery",
|
||
"salad": "Salad",
|
||
"grill": "Grill",
|
||
"seafood": "Seafood",
|
||
"snacks": "Sandwich",
|
||
"snacks-sweet": "Pastries",
|
||
"appetizers": "Appetizers",
|
||
"vegan": "Plant-based",
|
||
"fruits": "Fruits",
|
||
"specials": "Specials",
|
||
"chef-special": "Chef's pick",
|
||
"generic": "General"
|
||
},
|
||
"media": "Image & video",
|
||
"tabCatalog": "Catalog",
|
||
"tabBranch": "Branch settings",
|
||
"selectBranchForOverrides": "Select a branch above to manage its menu overrides.",
|
||
"allItems": "All items",
|
||
"searchItemsPlaceholder": "Search items…",
|
||
"itemCount": "{count} items",
|
||
"noItemsInCategory": "No items in this category yet",
|
||
"noItemsMatchSearch": "No items match your search",
|
||
"outOfStock": "Out of stock",
|
||
"newItem": "New item",
|
||
"newCategory": "New category",
|
||
"editCategoryTitle": "Edit category",
|
||
"printStation": "Print station",
|
||
"printStationNone": "Kitchen printer (default)",
|
||
"close": "Close",
|
||
"saving": "Saving…",
|
||
"model3d": "3D model",
|
||
"nameEnOptional": "English name (optional)",
|
||
"addItemSuccess": "Item added",
|
||
"updateItemSuccess": "Item updated",
|
||
"addCategorySuccess": "Category added",
|
||
"updateCategorySuccess": "Category updated",
|
||
"deleteItemConfirmTitle": "Delete item",
|
||
"deleteItemConfirmDesc": "Are you sure you want to delete “{name}”? This can't be undone.",
|
||
"deleteItemSuccess": "Item deleted",
|
||
"deleteCategoryConfirmTitle": "Delete category",
|
||
"deleteCategoryConfirmDesc": "Are you sure you want to delete the “{name}” category?",
|
||
"deleteCategorySuccess": "Category deleted",
|
||
"printStationInherit": "Same as category"
|
||
},
|
||
"branchMenu": {
|
||
"title": "Branch Menu",
|
||
"name": "Name",
|
||
"masterPrice": "Master Price",
|
||
"branchPrice": "Branch Price",
|
||
"availability": "Status",
|
||
"available": "Active",
|
||
"unavailable": "Hidden",
|
||
"resetOverride": "Reset",
|
||
"savePrice": "Save",
|
||
"actions": "Actions",
|
||
"priceOverridePro": "Price overrides require Pro plan",
|
||
"overrideActive": "Branch override active",
|
||
"confirmReset": "Reset this item to catalog defaults?",
|
||
"loading": "Loading..."
|
||
},
|
||
"media": {
|
||
"uploadImage": "Upload image",
|
||
"uploadVideo": "Upload video",
|
||
"removeImage": "Remove image",
|
||
"removeVideo": "Remove video",
|
||
"upload3dTitle": "3D view (optional)",
|
||
"upload3dHint": "GLB file up to {maxMb} MB — guests can rotate the item on touch",
|
||
"upload3dPhotoCount": "Besides cover photo: one GLB is enough. For photo-based 360° (future): {min}–{ideal} photos from different angles",
|
||
"upload3d": "Upload 3D model",
|
||
"remove3d": "Remove model",
|
||
"upload3dReady": "3D model will show on the QR menu",
|
||
"ai3dTitle": "AI 3D generation",
|
||
"ai3dHint": "Build a GLB from the product photo for the QR menu (Business plan and above).",
|
||
"ai3dGenerate": "Generate 3D with AI",
|
||
"ai3dGenerating": "Generating…",
|
||
"ai3dUsage": "Monthly quota: {used} of {limit}",
|
||
"ai3dSuccess": "3D model generated.",
|
||
"ai3dFailed": "3D generation failed.",
|
||
"ai3dLimitReached": "Monthly AI quota (100) is used up.",
|
||
"ai3dNoImage": "Upload a product photo first."
|
||
},
|
||
"taxes": {
|
||
"title": "Taxes",
|
||
"subtitle": "Rates applied to menu categories",
|
||
"addTax": "Add tax",
|
||
"name": "Name (e.g. VAT)",
|
||
"rate": "Rate (%)",
|
||
"hint": "Default tax applies to new categories. Taraz submission is in Settings.",
|
||
"empty": "No taxes defined.",
|
||
"default": "Default",
|
||
"setDefault": "Set default",
|
||
"delete": "Remove",
|
||
"deleteConfirm": "Remove \"{name}\" from the list? Menu categories using this tax will switch to the next default tax (or no tax).",
|
||
"required": "Required",
|
||
"optional": "Optional",
|
||
"ownerOnly": "Only the café owner can change taxes."
|
||
},
|
||
"branches": {
|
||
"label": "Branch"
|
||
},
|
||
"inventory": {
|
||
"title": "Inventory",
|
||
"subtitle": "Materials, menu recipes, and auto-deduction on orders",
|
||
"description": "Track ingredient quantities and reorder levels.",
|
||
"tabMaterials": "Materials",
|
||
"tabRecipes": "Menu recipes",
|
||
"addIngredient": "New ingredient",
|
||
"name": "Name",
|
||
"unit": "Unit",
|
||
"unitHint": "g, ml, pcs...",
|
||
"unitCustom": "Other (custom)",
|
||
"unitCustomPlaceholder": "e.g. cup, shot",
|
||
"unitsHelp": "Unit for stock and recipes: pcs, g, ml, etc. Change on-hand qty with +/- on each card.",
|
||
"units": {
|
||
"piece": "Piece (pcs)",
|
||
"gram": "Gram (g)",
|
||
"kilogram": "Kilogram (kg)",
|
||
"milliliter": "Milliliter (ml)",
|
||
"liter": "Liter (l)",
|
||
"cc": "cc",
|
||
"pack": "Pack",
|
||
"can": "Can",
|
||
"bag": "Bag"
|
||
},
|
||
"editIngredient": "Edit material",
|
||
"updated": "Material updated",
|
||
"quantityEditHint": "on-hand qty changes via +/- on this card only",
|
||
"quantity": "On hand",
|
||
"parLevel": "Full stock (e.g. 500 g)",
|
||
"unitCost": "Unit cost (Toman)",
|
||
"warningPercent": "Warning %",
|
||
"reorderLevel": "Reorder level",
|
||
"reorder": "Reorder at",
|
||
"warningAt": "Warn below",
|
||
"stockValue": "Stock value",
|
||
"lowStock": "Low",
|
||
"lowStockAlert": "Below warning level — refill these materials",
|
||
"adjust": "Apply",
|
||
"adjustDelta": "+/- qty",
|
||
"adjustNote": "Manual adjustment",
|
||
"adjusted": "Stock updated",
|
||
"created": "Ingredient added",
|
||
"empty": "No ingredients yet.",
|
||
"defaultUnit": "pcs",
|
||
"selectMenuItem": "Menu item",
|
||
"selectMenuItemPlaceholder": "Select...",
|
||
"recipeLines": "Per sold unit",
|
||
"perUnit": "Qty",
|
||
"pickIngredient": "Ingredient",
|
||
"addLine": "Add",
|
||
"saveRecipe": "Save recipe",
|
||
"recipeSaved": "Recipe saved",
|
||
"materialCostPerUnit": "Material cost / unit",
|
||
"recipeHint": "Example: 10 g coffee per espresso — 10 orders use 100 g.",
|
||
"totalPaid": "Amount paid (Toman)",
|
||
"impliedUnitCost": "Calculated unit cost",
|
||
"purchaseNote": "Stock purchase",
|
||
"purchaseHint": "For stock in (+), enter amount paid — recorded in expenses and reports.",
|
||
"purchaseRequired": "Amount paid and branch are required to add stock.",
|
||
"purchasesThisMonth": "Material purchases this month",
|
||
"purchaseCount": "{count} purchases",
|
||
"viewInExpenses": "View in expenses",
|
||
"selectBranchForPurchases": "Select a branch in the top bar to record warehouse purchases.",
|
||
"deleted": "Material deleted",
|
||
"deleteConfirmTitle": "Delete material",
|
||
"deleteConfirmDesc": "Delete “{name}”? This can’t be undone."
|
||
},
|
||
"qr": {
|
||
"brand": "Meezi",
|
||
"notFound": "Table not found",
|
||
"loadError": "Failed to load",
|
||
"tableLabel": "Table {number}",
|
||
"hint": "Open the Meezi app to order, or ask at the counter.",
|
||
"discoverCta": "Discover cafés on Meezi"
|
||
},
|
||
"qrMenu": {
|
||
"loading": "Loading...",
|
||
"welcome": "Welcome",
|
||
"tableLabel": "Table",
|
||
"tableNotFound": "Table not found or menu unavailable",
|
||
"tableCleaning": "This table is being cleaned — please ask staff",
|
||
"loadError": "Could not load menu",
|
||
"scanAgain": "Please scan the QR code again",
|
||
"addToCart": "Add",
|
||
"viewCart": "View cart",
|
||
"cartTitle": "Your cart",
|
||
"placeOrder": "Place order",
|
||
"orderPlaced": "Order placed!",
|
||
"orderNumber": "Order #: {number}",
|
||
"orderHint": "Staff will prepare your order shortly",
|
||
"guestName": "Your name (optional)",
|
||
"guestPhone": "Mobile (optional)",
|
||
"itemNote": "Note (e.g. no tomato, less sugar)",
|
||
"addMoreItems": "Add more items",
|
||
"orderError": "Could not place order. Try again.",
|
||
"rateLimited": "Too many requests — please wait a few minutes",
|
||
"captchaRequired": "Please complete the security check",
|
||
"cafeUnavailable": "This café is temporarily unavailable",
|
||
"subtotal": "Total",
|
||
"searchPlaceholder": "Search menu...",
|
||
"allCategories": "All",
|
||
"searchNoResults": "No items match your search",
|
||
"clearSearch": "Clear search",
|
||
"emptyCategory": "No items in this category",
|
||
"view3d": "3D",
|
||
"view3dHint": "Drag to rotate — model spins live",
|
||
"close3d": "Close",
|
||
"emptyMenu": "This branch menu is empty or unavailable",
|
||
"guestQrBadge": "QR guest",
|
||
"tabMenu": "Menu",
|
||
"tabOrders": "My orders",
|
||
"callWaiter": "Call waiter",
|
||
"callWaiterSent": "Waiter is on the way!",
|
||
"callWaiterCooldown": "Please wait 60 seconds",
|
||
"callWaiterError": "Error — please try again",
|
||
"myOrders": "Orders at this table",
|
||
"noOrders": "No orders yet",
|
||
"tracking": {
|
||
"back": "Back to menu",
|
||
"orderNumber": "Order number",
|
||
"table": "Table",
|
||
"loadError": "Could not load tracking",
|
||
"currentStep": "In progress",
|
||
"readyHint": "Your order is ready — pick it up at the counter or table",
|
||
"status": {
|
||
"pending": "Waiting for the café",
|
||
"seen": "Seen by staff",
|
||
"preparing": "Kitchen is preparing",
|
||
"ready": "Ready for pickup",
|
||
"done": "Delivered",
|
||
"cancelled": "Cancelled"
|
||
},
|
||
"steps": {
|
||
"submitted": "Order submitted",
|
||
"seen": "Seen by restaurant",
|
||
"preparing": "Preparing",
|
||
"ready": "Ready",
|
||
"done": "Completed",
|
||
"cancelled": "Cancelled"
|
||
}
|
||
}
|
||
},
|
||
"recentOrders": {
|
||
"title": "Recent orders",
|
||
"subtitle": "Browse closed orders and reprint the customer receipt and the kitchen / bar tickets.",
|
||
"date": "Date",
|
||
"branch": "Branch",
|
||
"allBranches": "All branches",
|
||
"empty": "No orders for this day.",
|
||
"loadFailed": "Could not load orders.",
|
||
"retry": "Retry",
|
||
"prevPage": "Previous",
|
||
"nextPage": "Next",
|
||
"table": "Table",
|
||
"statusPaid": "Paid",
|
||
"statusCancelled": "Cancelled",
|
||
"receipt": "Receipt",
|
||
"kitchen": "Kitchen ticket"
|
||
},
|
||
"notifications": {
|
||
"title": "Notifications",
|
||
"pageTitle": "Notifications",
|
||
"empty": "No notifications",
|
||
"emptyUnread": "No unread notifications",
|
||
"markAllRead": "Mark all read",
|
||
"unreadCount": "{count} unread",
|
||
"filterLabel": "Filter notifications",
|
||
"filterAll": "All",
|
||
"filterUnread": "Unread",
|
||
"loading": "Loading...",
|
||
"refreshing": "Updating...",
|
||
"backToList": "Back to list"
|
||
},
|
||
"reservations": {
|
||
"title": "Reservations",
|
||
"guest": "Guest",
|
||
"phone": "Phone",
|
||
"date": "Date",
|
||
"time": "Time",
|
||
"party": "Guests",
|
||
"table": "Table",
|
||
"tableOptional": "No specific table",
|
||
"tableNumber": "Table {number}",
|
||
"notes": "Notes",
|
||
"confirm": "Confirm",
|
||
"cancel": "Cancel",
|
||
"create": "Create reservation",
|
||
"newReservation": "Manual reservation",
|
||
"newReservationHint": "Pick table and time. When the guest arrives, use “Order & pay” at POS.",
|
||
"openPos": "Order & pay",
|
||
"markCompleted": "Mark completed",
|
||
"empty": "No reservations",
|
||
"status": {
|
||
"Pending": "Pending",
|
||
"Confirmed": "Confirmed",
|
||
"Cancelled": "Cancelled",
|
||
"Seated": "Seated",
|
||
"Completed": "Completed"
|
||
},
|
||
"deleted": "Reservation deleted",
|
||
"deleteConfirmTitle": "Delete reservation",
|
||
"deleteConfirmDesc": "Delete the reservation for “{name}”?"
|
||
},
|
||
"branchesPage": {
|
||
"title": "Branches",
|
||
"subtitle": "Each branch has its own login mobile under the café master plan",
|
||
"listTitle": "Branch list",
|
||
"newName": "Branch name",
|
||
"loginPhone": "Branch login mobile",
|
||
"managerName": "Branch manager name",
|
||
"managerNamePlaceholder": "Optional — defaults to branch name",
|
||
"addSection": "New branch",
|
||
"add": "Add branch",
|
||
"empty": "No branches yet.",
|
||
"created": "Branch and login account created.",
|
||
"createError": "Could not add branch (duplicate phone or plan limit)",
|
||
"branchSelectHint": "Pick the active branch on POS and queue.",
|
||
"masterPlanHint": "Billing and taxes are managed only by the café owner.",
|
||
"ownerOnly": "Only the café owner can manage branches.",
|
||
"delete": "Delete branch",
|
||
"deleteTitle": "Delete this branch?",
|
||
"deleteWarning": "Tables, staff, branch menu overrides, and related data will be removed. You can restore within 7 days; after that the branch is permanently deleted.",
|
||
"deleteConfirm": "Yes, delete branch",
|
||
"deleteScheduled": "Branch scheduled for deletion. You can restore it within 7 days.",
|
||
"deleteError": "Could not delete branch (maybe it is the last active branch).",
|
||
"restore": "Restore",
|
||
"restored": "Branch restored.",
|
||
"restoreError": "Could not restore branch.",
|
||
"pendingTitle": "Pending permanent deletion",
|
||
"pendingHint": "These branches are inactive. They will be permanently removed when the timer ends.",
|
||
"purgeInDays": "Permanent delete in {days} days",
|
||
"purgeInOneDay": "Permanent delete tomorrow",
|
||
"purgeToday": "Permanent delete today",
|
||
"review": "Review",
|
||
"reviewTitle": "Branch details",
|
||
"location": "Location"
|
||
},
|
||
"subscription": {
|
||
"title": "Plan & billing",
|
||
"subtitle": "Current plan, usage, and upgrades",
|
||
"currentPlan": "Current plan",
|
||
"expires": "Expires",
|
||
"noExpiry": "—",
|
||
"refresh": "Refresh",
|
||
"ordersToday": "Orders today",
|
||
"customers": "Customers",
|
||
"smsUsage": "SMS this month",
|
||
"paymentSuccess": "Payment successful. Your plan was updated.",
|
||
"paymentFailed": "Payment failed.",
|
||
"loading": "Loading...",
|
||
"ownerOnly": "Only the café owner can manage billing. Branches use the master café plan.",
|
||
"paymentMethod": "Payment method",
|
||
"planExpired": "Subscription expired",
|
||
"featureMenu3d": "3D menu",
|
||
"featureDiscover": "Discover profile (AI)",
|
||
"featureOn": "Enabled",
|
||
"featureOff": "Not included — upgrade",
|
||
"featureMenu3dUpgrade": "3D menu is available on Pro and higher plans.",
|
||
"featureMenuAi3d": "AI 3D generation",
|
||
"featureMenuAi3dUpgrade": "AI 3D generation is on Business and Enterprise (100 per month).",
|
||
"checkout": {
|
||
"title": "Invoice & Payment",
|
||
"subtitle": "Review your order and pay",
|
||
"backToPlans": "Back to plans",
|
||
"invalidPlan": "The selected plan is not available for online purchase.",
|
||
"invoiceLabel": "Proforma invoice",
|
||
"invoiceNo": "Invoice no.",
|
||
"issuedAt": "Issued",
|
||
"billingPeriod": "Billing period",
|
||
"monthsCount": "{count} mo",
|
||
"description": "Description",
|
||
"qty": "Qty",
|
||
"unitPrice": "Unit price",
|
||
"amount": "Amount",
|
||
"planLine": "{plan} plan subscription",
|
||
"subtotal": "Subtotal",
|
||
"total": "Amount due",
|
||
"secureNote": "Payment is processed through a secure bank gateway.",
|
||
"payTotal": "Pay {total}",
|
||
"redirecting": "Redirecting to gateway...",
|
||
"paymentFailed": "Payment failed. Please try again.",
|
||
"queuedNotice": "You already have an active subscription. This purchase will be queued and start on {date}."
|
||
},
|
||
"queued": {
|
||
"title": "Queued subscriptions",
|
||
"subtitle": "These start automatically when your current subscription ends.",
|
||
"months": "{count} months",
|
||
"window": "From {from} to {to}",
|
||
"cancel": "Cancel",
|
||
"cancelled": "Queued subscription cancelled",
|
||
"cancelConfirmTitle": "Cancel queued subscription",
|
||
"cancelConfirmDesc": "Cancel the {plan} subscription scheduled to start on {from}? Your current subscription is unaffected."
|
||
}
|
||
},
|
||
"settings": {
|
||
"title": "Settings",
|
||
"subtitle": "Shop profile, printers, and integrations",
|
||
"terminals": {
|
||
"title": "Active terminals",
|
||
"hint": "Your plan allows up to {max} concurrent terminals.",
|
||
"thisDevice": "This device",
|
||
"empty": "No terminals registered",
|
||
"revoke": "Remove",
|
||
"revoked": "Terminal removed",
|
||
"loading": "Loading…"
|
||
},
|
||
"nav": {
|
||
"aria": "Settings menu",
|
||
"shop": "Shop & café",
|
||
"shopGeneral": "Profile & integrations",
|
||
"shopAppearance": "Appearance & colors",
|
||
"shopNotifications": "Notifications & sound",
|
||
"printer": "Printer",
|
||
"printerSettings": "Printer settings",
|
||
"printerStations": "Kitchen & bar printers",
|
||
"printTest": "Print test page",
|
||
"shopDiscover": "Discover & AI",
|
||
"team": "Team & Staff",
|
||
"customRoles": "Custom Roles"
|
||
},
|
||
"notifPrefs": {
|
||
"soundSection": "Sound",
|
||
"soundEnabled": "Play a sound for new notifications",
|
||
"soundEnabledHint": "Chimes when a new order, waiter call, or alert arrives.",
|
||
"soundChoice": "Notification sound",
|
||
"preview": "Preview",
|
||
"volume": "Volume",
|
||
"soundClassic": "Classic",
|
||
"soundDing": "Ding",
|
||
"soundBell": "Bell",
|
||
"soundChime": "Chime",
|
||
"soundMarimba": "Marimba",
|
||
"soundAlert": "Alert",
|
||
"desktopSection": "Desktop notifications",
|
||
"desktopHint": "Show a Windows/desktop popup even when the dashboard is in another tab or minimized.",
|
||
"enableDesktop": "Enable desktop notifications",
|
||
"desktopEnabled": "Desktop popups",
|
||
"desktopEnabledHint": "Pop up only when this tab is not focused.",
|
||
"desktopGranted": "Desktop notifications enabled",
|
||
"desktopDenied": "Permission denied by the browser",
|
||
"desktopBlocked": "Notifications are blocked for this site. Allow them in your browser's site settings, then reload.",
|
||
"desktopUnsupported": "This browser does not support desktop notifications.",
|
||
"desktopFocusNote": "A test popup only appears if you switch to another window first.",
|
||
"sendTest": "Send a test notification",
|
||
"testTitle": "Meezi",
|
||
"testBody": "This is a test notification.",
|
||
"testToast": "Test sent",
|
||
"inAppSection": "In-app",
|
||
"tabBadge": "Unread count on the browser tab",
|
||
"tabBadgeHint": "Shows the number of unread notifications in the tab title and favicon.",
|
||
"toast": "In-app toast",
|
||
"toastHint": "Show a small banner inside the dashboard for new notifications.",
|
||
"promptTitle": "Turn on notifications?",
|
||
"promptBody": "Get a popup + sound for new orders and waiter calls — even when this tab is in the background.",
|
||
"later": "Later"
|
||
},
|
||
"customRoles": {
|
||
"title": "Custom Roles",
|
||
"subtitle": "Define roles with tailored permissions for your staff",
|
||
"newRole": "New Role",
|
||
"editRole": "Edit Role",
|
||
"name": "Role Name",
|
||
"namePlaceholder": "e.g. Barista, Floor Supervisor",
|
||
"description": "Description (optional)",
|
||
"descriptionPlaceholder": "Brief description of this role",
|
||
"color": "Color",
|
||
"permissions": "Permissions",
|
||
"empty": "No custom roles defined yet",
|
||
"saveError": "Failed to save role",
|
||
"deleteConfirm": "Delete role '{name}'? Employees will revert to their base role permissions.",
|
||
"groupAdmin": "Café Administration",
|
||
"groupBranches": "Branches",
|
||
"groupMenu": "Menu",
|
||
"groupInventory": "Inventory",
|
||
"groupTaxes": "Taxes",
|
||
"groupStaff": "Staff & HR",
|
||
"groupTables": "Tables & Reservations",
|
||
"groupOrders": "Orders & POS",
|
||
"groupRegister": "Register & Cash",
|
||
"groupQueueKitchen": "Queue & Kitchen",
|
||
"groupDelivery": "Delivery",
|
||
"groupCustomers": "Customers",
|
||
"groupCoupons": "Coupons",
|
||
"groupMarketing": "Marketing & Reviews",
|
||
"groupReports": "Reports & Finance",
|
||
"groupExpenses": "Expenses",
|
||
"perm": {
|
||
"ViewCafeSettings": "View café settings",
|
||
"ManageCafeSettings": "Edit café settings",
|
||
"ManageDiscoverProfile": "Discover & public profile",
|
||
"ViewBilling": "View billing",
|
||
"ManageBilling": "Manage billing & subscription",
|
||
"ManageRoles": "Manage roles",
|
||
"ViewPrintSettings": "View print settings",
|
||
"ManagePrintSettings": "Edit print settings",
|
||
"ViewBranches": "View branches",
|
||
"CreateBranch": "Create branch",
|
||
"EditBranch": "Edit branch",
|
||
"DeleteBranch": "Delete branch",
|
||
"ViewMenu": "View menu",
|
||
"CreateMenuItem": "Add menu items",
|
||
"EditMenuItem": "Edit menu items",
|
||
"DeleteMenuItem": "Delete menu items",
|
||
"ViewInventory": "View inventory",
|
||
"CreateInventory": "Add inventory",
|
||
"EditInventory": "Edit inventory & stock",
|
||
"DeleteInventory": "Delete inventory",
|
||
"ViewTaxes": "View taxes",
|
||
"CreateTax": "Create tax",
|
||
"EditTax": "Edit tax",
|
||
"DeleteTax": "Delete tax",
|
||
"ViewStaff": "View staff",
|
||
"CreateStaff": "Add staff",
|
||
"EditStaff": "Edit staff",
|
||
"DeleteStaff": "Remove staff",
|
||
"ManageStaff": "Assign branch roles",
|
||
"ManageStaffCredentials": "Manage login credentials",
|
||
"ViewAttendance": "View attendance",
|
||
"ManageAttendance": "Manage attendance",
|
||
"ViewSchedules": "View schedules",
|
||
"ManageSchedules": "Manage schedules",
|
||
"ViewLeave": "View leave requests",
|
||
"ReviewLeave": "Approve leave requests",
|
||
"ViewSalaries": "View salaries",
|
||
"ManageSalaries": "Manage salaries",
|
||
"ViewTables": "View tables",
|
||
"ManageTables": "Manage tables & sections",
|
||
"ViewReservations": "View reservations",
|
||
"CreateReservation": "Create reservation",
|
||
"EditReservation": "Edit reservation",
|
||
"DeleteReservation": "Delete reservation",
|
||
"ViewOrders": "View orders",
|
||
"ProcessOrders": "Take orders",
|
||
"EditOrder": "Edit orders",
|
||
"VoidOrder": "Void / cancel orders",
|
||
"RefundOrder": "Refund orders",
|
||
"ApplyDiscount": "Apply discounts",
|
||
"CompOrder": "Comp (free) orders",
|
||
"HandlePayments": "Take payments",
|
||
"UpdateOrderStatus": "Update order status",
|
||
"OperateRegister": "Open / close register",
|
||
"OpenCashDrawer": "Open cash drawer (no-sale)",
|
||
"ViewQueue": "View queue",
|
||
"ManageQueue": "Manage queue",
|
||
"ViewKitchen": "Kitchen display",
|
||
"ManageKitchenStations": "Manage kitchen stations",
|
||
"ViewDelivery": "View delivery",
|
||
"HandleDelivery": "Handle delivery",
|
||
"AssignDelivery": "Assign delivery",
|
||
"ViewCustomers": "View customers",
|
||
"CreateCustomer": "Add customers",
|
||
"EditCustomer": "Edit customers",
|
||
"DeleteCustomer": "Delete customers",
|
||
"ViewCoupons": "View coupons",
|
||
"CreateCoupon": "Create coupon",
|
||
"EditCoupon": "Edit coupon",
|
||
"DeleteCoupon": "Delete coupon",
|
||
"ViewSms": "View SMS",
|
||
"SendSms": "Send SMS campaigns",
|
||
"ManageSmsSettings": "SMS settings",
|
||
"ViewReviews": "View reviews",
|
||
"ManageReviews": "Reply & moderate reviews",
|
||
"ViewReports": "View reports",
|
||
"ExportReports": "Export reports",
|
||
"ViewAuditLog": "View audit log",
|
||
"ViewFinancials": "View financials (P&L)",
|
||
"ManageFinancials": "Payment corrections",
|
||
"ViewExpenses": "View expenses",
|
||
"CreateExpense": "Add expense",
|
||
"EditExpense": "Edit expense",
|
||
"DeleteExpense": "Delete expense"
|
||
}
|
||
},
|
||
"appearance": {
|
||
"paletteSection": "Color palette",
|
||
"paletteTitle": "Choose a preset palette",
|
||
"paletteHint": "Palette colors apply to the dashboard and the guest QR menu.",
|
||
"dashboardSection": "Dashboard",
|
||
"dashboardTitle": "Dashboard look",
|
||
"dashboardDesc": "How admin pages look (POS, inventory, reports) — separate from the table QR menu.",
|
||
"dashboardPreviewSection": "Preview",
|
||
"dashboardPreviewTitle": "Dashboard sample",
|
||
"dashboardPreviewHint": "Sample sidebar and item card in this panel; updates with panel style, density, and corners.",
|
||
"panelStyle": "Dashboard panel style",
|
||
"guestMenuStyle": "QR menu layout",
|
||
"menuTexture": "QR menu background texture",
|
||
"guestMenuSection": "Table QR menu",
|
||
"guestMenuTitle": "Guest menu template",
|
||
"guestMenuDesc": "What guests see when scanning the table QR — separate from your dashboard.",
|
||
"guestMenuPreviewSection": "Preview",
|
||
"guestMenuPreviewHint": "Mobile preview (QR menu)",
|
||
"density": "Density",
|
||
"radius": "Corner radius",
|
||
"customSection": "Custom colors",
|
||
"customTitle": "Your café brand colors",
|
||
"customHint": "Leave empty to use the selected palette. Opacity applies to custom or palette colors.",
|
||
"colorOpacity": "Opacity",
|
||
"resetCustom": "Reset custom colors",
|
||
"previewSection": "Preview",
|
||
"previewTitle": "Panel & menu sample",
|
||
"previewNav": "Menu",
|
||
"previewItem": "Latte",
|
||
"previewCta": "Add",
|
||
"saved": "Appearance saved.",
|
||
"palettes": {
|
||
"meezi-green": "Meezi green",
|
||
"ocean-blue": "Ocean blue",
|
||
"royal-purple": "Royal purple",
|
||
"sunset-orange": "Sunset orange",
|
||
"rose-blush": "Rose blush",
|
||
"charcoal-gold": "Charcoal gold",
|
||
"espresso": "Espresso",
|
||
"forest": "Forest",
|
||
"midnight": "Midnight",
|
||
"coral": "Coral",
|
||
"gold-luxury": "Gold luxury",
|
||
"mint-fresh": "Mint fresh",
|
||
"wine-bar": "Wine bar",
|
||
"slate-modern": "Slate modern",
|
||
"cherry": "Cherry",
|
||
"teal-wave": "Teal wave",
|
||
"sand-cafe": "Sand café"
|
||
},
|
||
"panelStyles": {
|
||
"flat": "Flat",
|
||
"modern": "Modern",
|
||
"glass": "Glass",
|
||
"minimal": "Minimal",
|
||
"bold": "Bold",
|
||
"soft": "Soft",
|
||
"elevated": "Elevated",
|
||
"outline": "Outline"
|
||
},
|
||
"menuStyles": {
|
||
"cards": "Cards",
|
||
"compact": "Compact",
|
||
"grid": "Grid",
|
||
"list": "List",
|
||
"magazine": "Magazine",
|
||
"classic": "Classic"
|
||
},
|
||
"menuTextures": {
|
||
"none": "Plain",
|
||
"paper": "Paper",
|
||
"linen": "Linen",
|
||
"dots": "Dots",
|
||
"grid": "Grid",
|
||
"marble": "Marble",
|
||
"wood": "Wood",
|
||
"warm": "Warm café"
|
||
},
|
||
"densities": {
|
||
"compact": "Compact",
|
||
"comfortable": "Comfortable",
|
||
"spacious": "Spacious"
|
||
},
|
||
"radiusOptions": {
|
||
"none": "Sharp",
|
||
"sm": "Small",
|
||
"md": "Medium",
|
||
"lg": "Large",
|
||
"full": "Round"
|
||
},
|
||
"colors": {
|
||
"primary": "Primary",
|
||
"secondary": "Secondary",
|
||
"accent": "Accent / promo",
|
||
"background": "Background",
|
||
"surface": "Card / surface",
|
||
"text": "Text",
|
||
"textMuted": "Muted text",
|
||
"destructive": "Error / delete",
|
||
"success": "Success"
|
||
}
|
||
},
|
||
"snappfoodVendor": "Snappfood vendor ID",
|
||
"saveProfile": "Save profile",
|
||
"profile": {
|
||
"title": "Café profile",
|
||
"name": "Café name",
|
||
"city": "City",
|
||
"phone": "Phone",
|
||
"address": "Address",
|
||
"description": "Description",
|
||
"logo": "Logo",
|
||
"uploadLogo": "Upload logo",
|
||
"uploadCover": "Upload cover",
|
||
"saved": "Profile saved.",
|
||
"reloginHint": "Plan updated; sign out and in again if the badge looks wrong.",
|
||
"slug": "Koja profile address",
|
||
"slugHint": "Your cafe page on Koja — lowercase letters, digits, hyphens only",
|
||
"slugPlaceholder": "my-cafe",
|
||
"slugTaken": "This address is already taken. Please choose another.",
|
||
"slugInvalid": "Invalid address. Use lowercase letters, digits, and hyphens only.",
|
||
"kojaUrl": "Koja URL"
|
||
},
|
||
"taraz": "Taraz (tax system)",
|
||
"tarazHint": "Submit yesterday's invoices to Taraz (demo mode logs only).",
|
||
"tarazSubmit": "Submit to Taraz",
|
||
"tarazQueued": "Submission queued.",
|
||
"plans": {
|
||
"compareLabel": "Compare plans",
|
||
"compareHint": "Compare features and pick the right plan for your café.",
|
||
"featureColumn": "Features",
|
||
"popular": "Popular",
|
||
"current": "Current",
|
||
"perMonth": "/ month",
|
||
"freePrice": "Free",
|
||
"customPrice": "Contact us",
|
||
"unlimited": "Unlimited",
|
||
"included": "Included",
|
||
"currentPlanBtn": "Your plan",
|
||
"contactSales": "Contact sales",
|
||
"subscribe": "Get {plan}",
|
||
"names": {
|
||
"Free": "Free",
|
||
"Pro": "Pro",
|
||
"Business": "Business",
|
||
"Enterprise": "Enterprise"
|
||
},
|
||
"limits": {
|
||
"maxOrdersPerDay": "Orders per day",
|
||
"maxBranches": "Branches",
|
||
"maxTerminals": "POS terminals",
|
||
"maxTables": "Tables",
|
||
"maxCustomers": "CRM customers",
|
||
"maxSmsPerMonth": "SMS per month",
|
||
"maxMenuItems": "Menu items",
|
||
"maxReportHistoryDays": "Report history (days)",
|
||
"maxMenuAi3dPerMonth": "AI 3D images per month"
|
||
},
|
||
"features": {
|
||
"ordersPerDay": "Orders per day",
|
||
"terminals": "POS terminals",
|
||
"crmCustomers": "CRM customers",
|
||
"smsPerMonth": "Marketing SMS",
|
||
"branches": "Branches",
|
||
"posKds": "POS & kitchen display",
|
||
"tablesQr": "Tables & QR ordering",
|
||
"menuReservations": "Menu & reservations",
|
||
"reports": "Reports",
|
||
"hrModule": "HR module",
|
||
"snappfoodDelivery": "Snappfood / delivery",
|
||
"tarazTax": "Taraz tax integration",
|
||
"badges": "Trust badges",
|
||
"whiteLabel": "White label",
|
||
"apiAccess": "Public API"
|
||
},
|
||
"levels": {
|
||
"basic": "Basic",
|
||
"full": "Full"
|
||
}
|
||
},
|
||
"discoverProfile": {
|
||
"title": "Discover & AI profile",
|
||
"subtitle": "Tags for matching guests to cafés",
|
||
"save": "Save",
|
||
"saved": "Saved",
|
||
"loading": "Loading..."
|
||
}
|
||
},
|
||
"support": {
|
||
"title": "Meezi support",
|
||
"subtitle": "Open a ticket for platform help",
|
||
"newTicket": "New ticket",
|
||
"subject": "Subject",
|
||
"message": "Your message",
|
||
"submit": "Submit ticket",
|
||
"myTickets": "My tickets",
|
||
"messages": "messages",
|
||
"created": "Ticket created",
|
||
"createFailed": "Could not create ticket",
|
||
"empty": "No tickets yet",
|
||
"loadFailed": "Could not load tickets.",
|
||
"retry": "Try again",
|
||
"loading": "Loading...",
|
||
"notFound": "Ticket not found",
|
||
"back": "Back",
|
||
"reply": "Your reply",
|
||
"send": "Send",
|
||
"replySent": "Reply sent",
|
||
"replyFailed": "Could not send reply",
|
||
"fromAdmin": "Meezi support",
|
||
"fromYou": "You",
|
||
"closedHint": "This ticket is closed — no new replies.",
|
||
"status": {
|
||
"open": "Open",
|
||
"inProgress": "In progress",
|
||
"waitingMerchant": "Awaiting your reply",
|
||
"resolved": "Resolved",
|
||
"closed": "Closed"
|
||
}
|
||
},
|
||
"admin": {
|
||
"nav": {
|
||
"title": "Platform admin",
|
||
"dashboard": "Dashboard",
|
||
"plans": "Plans & pricing",
|
||
"integrations": "Payments & SMS",
|
||
"notifications": "Notifications",
|
||
"settings": "App settings",
|
||
"features": "Features",
|
||
"cafes": "Cafes",
|
||
"tickets": "Tickets",
|
||
"logout": "Log out"
|
||
},
|
||
"auth": {
|
||
"title": "System admin login",
|
||
"subtitle": "Authorized Meezi staff only",
|
||
"phone": "Phone",
|
||
"sendOtp": "Send code",
|
||
"otp": "Verification code",
|
||
"login": "Sign in",
|
||
"error": "Login failed",
|
||
"devHint": "In development the OTP is logged by Admin API (DEV admin OTP)."
|
||
},
|
||
"dashboard": {
|
||
"title": "Platform overview",
|
||
"totalCafes": "Total cafes",
|
||
"activeCafes": "Active",
|
||
"openTickets": "Open tickets",
|
||
"plans": "Plans configured"
|
||
},
|
||
"plans": {
|
||
"title": "Subscription plans",
|
||
"monthlyPrice": "Monthly price (Toman)",
|
||
"maxOrders": "Max orders per day",
|
||
"saved": "Plan saved"
|
||
},
|
||
"settings": {
|
||
"title": "Application settings",
|
||
"saved": "Saved"
|
||
},
|
||
"features": {
|
||
"title": "Feature flags",
|
||
"enabled": "On",
|
||
"disabled": "Off"
|
||
},
|
||
"cafes": {
|
||
"title": "Registered cafes",
|
||
"suspended": "Suspended",
|
||
"suspend": "Suspend",
|
||
"activate": "Activate",
|
||
"discoverProfile": {
|
||
"edit": "Discover profile",
|
||
"title": "Discover & AI profile",
|
||
"subtitle": "Tags for matching guests to cafés",
|
||
"save": "Save",
|
||
"saved": "Saved",
|
||
"loading": "Loading..."
|
||
}
|
||
},
|
||
"integrations": {
|
||
"title": "Payment gateways & Kavenegar",
|
||
"save": "Save settings",
|
||
"saved": "Settings saved",
|
||
"paymentTitle": "Payment gateways",
|
||
"kavenegarTitle": "Kavenegar (SMS)",
|
||
"active": "Active for billing",
|
||
"enabled": "Enabled",
|
||
"sandbox": "Sandbox mode",
|
||
"merchantId": "Merchant ID",
|
||
"apiKey": "API token",
|
||
"username": "Username",
|
||
"password": "Password",
|
||
"branchCode": "Branch code",
|
||
"terminalCode": "Terminal code (optional)",
|
||
"clientId": "Client ID",
|
||
"clientSecret": "Client Secret",
|
||
"baseUrl": "API base URL (optional)",
|
||
"taraHint": "Tara credit pay — API: api.tara-club.ir/club/api/v1 (login, trace, request, verify)",
|
||
"snappPayHint": "Snapp Pay BNPL — OAuth + payment token from Snapp Pay merchant panel",
|
||
"otpTemplate": "OTP template name (Kavenegar panel)"
|
||
},
|
||
"notifications": {
|
||
"title": "Notification center",
|
||
"broadcastTitle": "Broadcast to all cafes",
|
||
"broadcastTitlePlaceholder": "Notification title",
|
||
"broadcastBodyPlaceholder": "Body (optional)",
|
||
"sendBroadcast": "Send to all",
|
||
"broadcastSent": "Sent to {count} cafes",
|
||
"allNotifications": "All notifications",
|
||
"empty": "No notifications yet"
|
||
},
|
||
"tickets": {
|
||
"title": "Support tickets",
|
||
"messages": "messages",
|
||
"loading": "Loading...",
|
||
"empty": "No tickets",
|
||
"notFound": "Ticket not found",
|
||
"back": "All tickets",
|
||
"replyPlaceholder": "Reply to merchant...",
|
||
"sendReply": "Send reply",
|
||
"replySent": "Reply sent",
|
||
"replyFailed": "Could not send reply",
|
||
"resolve": "Mark resolved",
|
||
"close": "Close ticket",
|
||
"statusUpdated": "Ticket status updated",
|
||
"closedHint": "Ticket is closed — replies disabled.",
|
||
"fromAdmin": "Meezi support",
|
||
"fromCafe": "Cafe",
|
||
"filter": {
|
||
"all": "All",
|
||
"open": "Open",
|
||
"closed": "Closed"
|
||
}
|
||
}
|
||
},
|
||
"discoverPublic": {
|
||
"brand": "Meezi",
|
||
"title": "Discover cafés",
|
||
"subtitle": "Find the right café in Tehran and Karaj",
|
||
"searchPlaceholder": "Type: quiet, date night, Wi-Fi, roastery, book café…",
|
||
"searchHint": "Smart search — filters are auto-detected from your text",
|
||
"aiDetectedLabel": "Detected filters:",
|
||
"aiDetectedClear": "Clear",
|
||
"loading": "Loading…",
|
||
"empty": "No cafés match these filters",
|
||
"resultCount": "{count} cafés",
|
||
"applyFilters": "Apply filters",
|
||
"clearFilters": "Clear",
|
||
"viewCafe": "View café",
|
||
"backToList": "Back to list",
|
||
"notFound": "Café not found",
|
||
"exploreMore": "Explore more cafés",
|
||
"reviewCount": "{count} reviews",
|
||
"mapTitle": "Map",
|
||
"openInNeshan": "Open in Neshan",
|
||
"reviewsTitle": "Guest reviews",
|
||
"ownerReply": "Cafe reply",
|
||
"coffeeAdvisor": {
|
||
"title": "Drink advisor",
|
||
"subtitle": "Tell us your purpose and get tailored suggestions",
|
||
"placeholder": "e.g. group work, date night, exam energy…",
|
||
"submit": "Suggest",
|
||
"loading": "Thinking…",
|
||
"notConfigured": "Smart advisor is not enabled for this café yet",
|
||
"failed": "Suggestions unavailable. Try again later"
|
||
},
|
||
"cities": {
|
||
"tehran": "Tehran",
|
||
"karaj": "Karaj"
|
||
},
|
||
"sort": {
|
||
"rating": "Top rated",
|
||
"reviews": "Most reviews",
|
||
"name": "Name"
|
||
},
|
||
"openNow": "Open now",
|
||
"openNowLabel": "Open now",
|
||
"closedLabel": "Closed",
|
||
"galleryTitle": "Gallery",
|
||
"workingHoursTitle": "Working hours",
|
||
"instagramLabel": "Instagram",
|
||
"websiteLabel": "Website",
|
||
"days": {
|
||
"sat": "Sat",
|
||
"sun": "Sun",
|
||
"mon": "Mon",
|
||
"tue": "Tue",
|
||
"wed": "Wed",
|
||
"thu": "Thu",
|
||
"fri": "Fri"
|
||
},
|
||
"filters": {
|
||
"themes": "Theme",
|
||
"vibes": "Vibe",
|
||
"occasions": "Good for",
|
||
"spaceFeatures": "Space",
|
||
"noise": "Noise",
|
||
"priceTier": "Price",
|
||
"size": "Size"
|
||
}
|
||
},
|
||
"cafePublicProfile": {
|
||
"title": "Public profile",
|
||
"subtitle": "Information shown to guests on the discovery page",
|
||
"tabs": {
|
||
"info": "Info",
|
||
"gallery": "Gallery",
|
||
"hours": "Hours",
|
||
"social": "Social"
|
||
},
|
||
"description": "About your café",
|
||
"descriptionPlaceholder": "Describe your café, its ambiance, specialty drinks, and the experience you offer…",
|
||
"instagram": "Instagram handle (without @)",
|
||
"instagramPlaceholder": "mycafe.tehran",
|
||
"website": "Website URL",
|
||
"websitePlaceholder": "https://mycafe.ir",
|
||
"gallery": "Photo gallery (max 8)",
|
||
"galleryHint": "Upload quality photos of your space — JPEG, PNG or WebP up to 5 MB",
|
||
"uploadPhoto": "Upload photo",
|
||
"uploading": "Uploading…",
|
||
"uploadFailed": "Upload failed",
|
||
"galleryFull": "Gallery is full. Remove a photo first",
|
||
"removePhoto": "Remove",
|
||
"workingHours": "Daily working hours",
|
||
"isOpen": "Open",
|
||
"openTime": "Opens at",
|
||
"closeTime": "Closes at",
|
||
"days": {
|
||
"sat": "Saturday",
|
||
"sun": "Sunday",
|
||
"mon": "Monday",
|
||
"tue": "Tuesday",
|
||
"wed": "Wednesday",
|
||
"thu": "Thursday",
|
||
"fri": "Friday"
|
||
},
|
||
"save": "Save",
|
||
"saved": "Saved",
|
||
"saveFailed": "Save failed",
|
||
"loading": "Loading…",
|
||
"showOnKoja": "Show on Koja",
|
||
"showOnKojaHint": "List your café in the public Koja directory (koja.meezi.ir). On by default."
|
||
},
|
||
"discoverProfile": {
|
||
"sections": {
|
||
"themes": "Theme & style",
|
||
"occasions": "Good for (multi)",
|
||
"spaceFeatures": "Space features",
|
||
"vibes": "Vibe",
|
||
"size": "Size",
|
||
"floors": "Floors",
|
||
"noiseLevel": "Noise",
|
||
"priceTier": "Price tier"
|
||
},
|
||
"hints": {
|
||
"themes": "For AI recommendations",
|
||
"occasions": "Dates, family, friends, meeting someone new…",
|
||
"spaceFeatures": "Indoor, outdoor, terrace, plants…",
|
||
"vibes": "Quiet, lively, romantic…"
|
||
},
|
||
"themes": {
|
||
"modern": "Modern",
|
||
"minimal": "Minimal",
|
||
"vintage": "Vintage",
|
||
"industrial": "Industrial",
|
||
"scandi": "Scandi",
|
||
"persian_traditional": "Persian traditional",
|
||
"book_cafe": "Book café",
|
||
"roastery": "Roastery",
|
||
"dessert_focus": "Dessert focus",
|
||
"brunch": "Brunch",
|
||
"late_night": "Late night",
|
||
"plants_heavy": "Plant-heavy",
|
||
"instagrammable": "Instagrammable",
|
||
"heritage": "Heritage",
|
||
"luxury": "Luxury",
|
||
"specialty_coffee": "Specialty coffee",
|
||
"tea_house": "Tea house",
|
||
"art_gallery": "Art gallery",
|
||
"sport_cafe": "Sport café",
|
||
"gaming_cafe": "Gaming café"
|
||
},
|
||
"occasions": {
|
||
"date": "Date",
|
||
"family": "Family",
|
||
"friends": "Friends",
|
||
"finding_someone": "Meeting someone new",
|
||
"solo": "Solo",
|
||
"business_meeting": "Business",
|
||
"study_work": "Study & work",
|
||
"celebration": "Celebration",
|
||
"quick_coffee": "Quick coffee",
|
||
"breakfast": "Breakfast",
|
||
"brunch": "Brunch",
|
||
"after_dinner": "After dinner",
|
||
"group_large": "Large group"
|
||
},
|
||
"spaceFeatures": {
|
||
"indoor": "Indoor",
|
||
"outdoor": "Outdoor",
|
||
"terrace": "Terrace",
|
||
"rooftop": "Rooftop",
|
||
"garden": "Garden",
|
||
"plants": "Plants",
|
||
"wifi": "Wi‑Fi",
|
||
"parking": "Parking",
|
||
"wheelchair": "Wheelchair access",
|
||
"kids_friendly": "Kid-friendly",
|
||
"pet_friendly": "Pet-friendly",
|
||
"smoking_area": "Smoking area",
|
||
"live_music": "Live music",
|
||
"private_room": "Private room",
|
||
"counter_only": "Counter only",
|
||
"takeaway": "Takeaway",
|
||
"hookah": "Hookah",
|
||
"board_games": "Board games",
|
||
"no_smoking": "Non-smoking",
|
||
"prayer_room": "Prayer room"
|
||
},
|
||
"vibes": {
|
||
"quiet": "Quiet",
|
||
"lively": "Lively",
|
||
"romantic": "Romantic",
|
||
"cozy": "Cozy",
|
||
"trendy": "Trendy",
|
||
"traditional": "Traditional",
|
||
"artistic": "Artistic",
|
||
"luxury": "Luxury",
|
||
"casual": "Casual",
|
||
"study_friendly": "Study-friendly"
|
||
},
|
||
"sizes": {
|
||
"tiny": "Tiny",
|
||
"cozy": "Cozy",
|
||
"medium": "Medium",
|
||
"large": "Large",
|
||
"spacious": "Spacious"
|
||
},
|
||
"floors": {
|
||
"one": "1 floor",
|
||
"two": "2 floors",
|
||
"three": "3 floors",
|
||
"multi": "Multi-floor"
|
||
},
|
||
"noiseLevels": {
|
||
"quiet": "Quiet",
|
||
"moderate": "Moderate",
|
||
"lively": "Lively"
|
||
},
|
||
"priceTiers": {
|
||
"budget": "Budget",
|
||
"mid": "Mid",
|
||
"premium": "Premium"
|
||
}
|
||
}
|
||
}
|