diff --git a/backend/locale/ar_SA/LC_MESSAGES/django.mo b/backend/locale/ar_SA/LC_MESSAGES/django.mo new file mode 100644 index 0000000..1eb976c Binary files /dev/null and b/backend/locale/ar_SA/LC_MESSAGES/django.mo differ diff --git a/backend/locale/ar_SA/LC_MESSAGES/django.po b/backend/locale/ar_SA/LC_MESSAGES/django.po new file mode 100644 index 0000000..d34f320 --- /dev/null +++ b/backend/locale/ar_SA/LC_MESSAGES/django.po @@ -0,0 +1,251 @@ +# Arabic (Saudi Arabia) translations for Salon booking platform. +# Copyright (C) 2026 +# +msgid "" +msgstr "" +"Project-Id-Version: 1.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-03-02 00:45+0300\n" +"PO-Revision-Date: 2026-03-02 00:45+0300\n" +"Last-Translator: Claude\n" +"Language-Team: Arabic (Saudi Arabia)\n" +"Language: ar_SA\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" + +#: apps/accounts/services/otp.py:26 +msgid "Too many OTP requests. Try again later." +msgstr "طلبات رمز التحقق كثيرة جداً. حاول مرة أخرى لاحقاً." + +#: apps/accounts/services/otp.py:32 +msgid "Please wait before requesting another code." +msgstr "يرجى الانتظار قبل طلب رمز آخر." + +#: apps/accounts/services/otp.py:71 +msgid "Twilio credentials are not configured" +msgstr "لم يتم تكوين بيانات اعتماد Twilio" + +#: apps/accounts/services/otp.py:85 +msgid "Twilio WhatsApp sender is not configured" +msgstr "لم يتم تكوين مُرسِل WhatsApp لـ Twilio" + +#: apps/accounts/services/otp.py:100 +msgid "Unifonic credentials are not configured" +msgstr "لم يتم تكوين بيانات اعتماد Unifonic" + +#: apps/accounts/services/otp.py:104 +msgid "Unifonic SMS adapter not implemented yet" +msgstr "محول SMS لـ Unifonic لم يتم تنفيذه بعد" + +#: apps/accounts/services/otp.py:109 +msgid "Unifonic WhatsApp sender is not configured" +msgstr "لم يتم تكوين مُرسِل WhatsApp لـ Unifonic" + +#: apps/accounts/services/otp.py:110 +msgid "Unifonic WhatsApp adapter not implemented yet" +msgstr "محول WhatsApp لـ Unifonic لم يتم تنفيذه بعد" + +#: apps/accounts/services/otp.py:126 +msgid "Authentica API key is not configured" +msgstr "لم يتم تكوين مفتاح API لـ Authentica" + +#: apps/accounts/services/otp.py:149 apps/accounts/services/otp.py:162 +msgid "Authentica request failed" +msgstr "فشل طلب Authentica" + +#: apps/accounts/services/otp.py:159 +#, python-format +msgid "Authentica request failed: %(status)s %(body)s" +msgstr "فشل طلب Authentica: %(status)s %(body)s" + +#: apps/accounts/services/otp.py:168 apps/accounts/services/otp.py:276 +msgid "Unsupported OTP channel" +msgstr "قناة رمز التحقق غير مدعومة" + +#: apps/accounts/services/otp.py:179 +#, python-format +msgid "Authentica verify failed: %(response)s" +msgstr "فشل التحقق بـ Authentica: %(response)s" + +#: apps/accounts/services/otp.py:184 +msgid "Authentica sender name is not configured" +msgstr "لم يتم تكوين اسم مُرسِل Authentica" + +#: apps/accounts/services/otp.py:195 +msgid "Authentica WhatsApp messaging is not supported" +msgstr "مراسلة WhatsApp غير مدعومة لـ Authentica" + +#: apps/accounts/services/otp.py:209 +#, python-format +msgid "Unknown OTP provider: %(provider)s" +msgstr "مزود رمز التحقق غير معروف: %(provider)s" + +#: apps/accounts/services/otp.py:256 +#, python-format +msgid "Your verification code is %(code)s. It expires in %(minutes)s minutes." +msgstr "رمز التحقق الخاص بك هو %(code)s. ينتهي في %(minutes)s دقيقة." + +#: apps/accounts/services/phone.py:8 +msgid "Phone number is required" +msgstr "رقم الهاتف مطلوب" + +#: apps/accounts/services/phone.py:17 +msgid "Invalid phone number format" +msgstr "تنسيق رقم الهاتف غير صالح" + +#: apps/accounts/services/phone.py:28 +msgid "Phone number must be in E.164 format or a valid Saudi mobile" +msgstr "يجب أن يكون رقم الهاتف بصيغة E.164 أو رقم جوال سعودي صالح" + +#: apps/accounts/views.py:75 apps/accounts/views.py:138 +msgid "Invalid or expired code" +msgstr "الرمز غير صالح أو منتهي الصلاحية" + +#: apps/accounts/views.py:82 +msgid "Phone verified" +msgstr "تم التحقق من رقم الهاتف" + +#: apps/accounts/views.py:99 +msgid "Email already in use." +msgstr "البريد الإلكتروني مستخدم بالفعل." + +#: apps/accounts/views.py:142 +msgid "User not found" +msgstr "المستخدم غير موجود" + +#: apps/accounts/views.py:164 +msgid "Social login not configured yet. Add OAuth provider config." +msgstr "لم يتم تكوين تسجيل الدخول الاجتماعي بعد. أضف إعداد مزود OAuth." + +#: apps/bookings/serializers.py:54 +msgid "Only staff or managers can confirm bookings." +msgstr "يمكن للموظفين والمدراء فقط تأكيد الحجوزات." + +#: apps/bookings/serializers.py:56 +msgid "Only staff or managers can complete bookings." +msgstr "يمكن للموظفين والمدراء فقط إكمال الحجوزات." + +#: apps/bookings/serializers.py:58 +msgid "You are not allowed to cancel this booking." +msgstr "لا يُسمح لك بإلغاء هذا الحجز." + +#: apps/bookings/serializers.py:101 apps/bookings/services.py:49 +msgid "Booking overlaps an existing appointment" +msgstr "يتداخل الحجز مع موعد قائم" + +#: apps/bookings/services.py:13 +msgid "Staff is required for booking" +msgstr "يجب تحديد موظف للحجز" + +#: apps/bookings/services.py:16 +msgid "Selected staff does not belong to this salon" +msgstr "الموظف المختار لا ينتمي إلى هذا الصالون" + +#: apps/bookings/services.py:19 +msgid "End time must be after start time" +msgstr "يجب أن يكون وقت الانتهاء بعد وقت البدء" + +#: apps/bookings/services.py:23 +msgid "End time must match service duration" +msgstr "يجب أن يتطابق وقت الانتهاء مع مدة الخدمة" + +#: apps/bookings/services.py:40 +msgid "Booking is outside staff availability" +msgstr "الحجز خارج أوقات توفر الموظف" + +#: apps/notifications/services.py:31 +#, python-format +msgid "Unknown notification provider: %(provider)s" +msgstr "مزود الإشعارات غير معروف: %(provider)s" + +#: apps/notifications/services.py:47 +#, python-format +msgid "" +"Your booking request is received for %(service)s at %(salon)s on %(start)s." +msgstr "تم استلام طلب حجزك لخدمة %(service)s في %(salon)s بتاريخ %(start)s." + +#: apps/notifications/services.py:55 +#, python-format +msgid "Your booking is confirmed for %(service)s at %(salon)s on %(start)s." +msgstr "تم تأكيد حجزك لخدمة %(service)s في %(salon)s بتاريخ %(start)s." + +#: apps/notifications/services.py:63 +#, python-format +msgid "Your booking was cancelled for %(service)s at %(salon)s on %(start)s." +msgstr "تم إلغاء حجزك لخدمة %(service)s في %(salon)s بتاريخ %(start)s." + +#: apps/notifications/services.py:70 +#, python-format +msgid "Booking update for %(service)s at %(salon)s on %(start)s." +msgstr "تحديث الحجز لخدمة %(service)s في %(salon)s بتاريخ %(start)s." + +#: apps/notifications/services.py:85 +msgid "Unsupported notification channel" +msgstr "قناة الإشعارات غير مدعومة" + +#: apps/payments/serializers.py:49 +msgid "Booking not found" +msgstr "الحجز غير موجود" + +#: apps/payments/serializers.py:56 apps/payments/services/payments.py:79 +msgid "Provider integration not implemented" +msgstr "تكامل المزود غير مُنفَّذ" + +#: apps/payments/serializers.py:58 +msgid "Payment source is required" +msgstr "مصدر الدفع مطلوب" + +#: apps/payments/serializers.py:61 +msgid "Payment source type is required" +msgstr "نوع مصدر الدفع مطلوب" + +#: apps/payments/serializers.py:64 +msgid "Card data must not be sent to the backend; use frontend tokenization" +msgstr "لا يجب إرسال بيانات البطاقة إلى الخادم؛ استخدم التحويل إلى رمز في الواجهة الأمامية" + +#: apps/payments/serializers.py:67 +msgid "Callback URL is required for token payments" +msgstr "رابط الاستجابة مطلوب لمدفوعات الرمز" + +#: apps/payments/services/payments.py:84 +msgid "Idempotency key already used" +msgstr "مفتاح الإيدمبوتنسي مستخدم بالفعل" + +#: apps/payments/services/payments.py:89 +msgid "Unsupported payment source type" +msgstr "نوع مصدر الدفع غير مدعوم" + +#: apps/payments/services/payments.py:130 +#: apps/payments/services/payments.py:141 +msgid "Payment provider error" +msgstr "خطأ في مزود الدفع" + +#: apps/payments/views.py:50 +msgid "Not allowed" +msgstr "غير مسموح" + +#: apps/payments/views.py:70 +msgid "Webhook secret not configured" +msgstr "لم يتم تكوين رمز الـ webhook" + +#: apps/payments/views.py:73 +msgid "Invalid webhook signature" +msgstr "توقيع الـ webhook غير صالح" + +#: apps/payments/views.py:79 +msgid "Missing payment reference" +msgstr "مرجع الدفع مفقود" + +#: apps/payments/views.py:84 +msgid "Payment not found" +msgstr "لم يتم العثور على الدفعة" + +#: apps/payments/views.py:88 +msgid "Event ignored" +msgstr "تم تجاهل الحدث" + +#: apps/payments/views.py:89 +msgid "Webhook processed" +msgstr "تمت معالجة الـ webhook" diff --git a/frontend/src/components/ProtectedRoute.jsx b/frontend/src/components/ProtectedRoute.jsx index f8d5968..657c0c5 100644 --- a/frontend/src/components/ProtectedRoute.jsx +++ b/frontend/src/components/ProtectedRoute.jsx @@ -1,14 +1,16 @@ import { Navigate, useLocation } from "react-router-dom"; +import { useTranslation } from "react-i18next"; import { useAuth } from "../contexts/AuthContext"; export default function ProtectedRoute({ children }) { + const { t } = useTranslation(); const { isAuthenticated, loading } = useAuth(); const location = useLocation(); if (loading) { return (
Loading...
+{t("common.loading")}
{b.service_name}
- {formatDateTime(b.start_time)} – {formatDateTime(b.end_time)} + {formatDateTime(b.start_time, getActiveLocale())} – {formatDateTime(b.end_time, getActiveLocale())}
{b.price_amount} {b.currency} diff --git a/frontend/src/pages/SalonDetailPage.jsx b/frontend/src/pages/SalonDetailPage.jsx index ba6920f..801d6d4 100644 --- a/frontend/src/pages/SalonDetailPage.jsx +++ b/frontend/src/pages/SalonDetailPage.jsx @@ -43,7 +43,7 @@ export default function SalonDetailPage() {