feat(i18n,rtl): full Arabic localization + RTL sweep across all layouts
Frontend - i18n: install tailwindcss-rtl, Cairo font, RTL-aware direction in index.css. - Language toggle: localize aria-label / menu label, persist choice, update document dir synchronously. - Sidebar: add `side` prop so the drawer pins to the right in RTL; wire up AdminLmsLayout, RoleLayout (student/teacher) and AppSidebar to pass side = i18n.dir() === 'rtl' ? 'right' : 'left'. - AdminLmsLayout: convert every nav item from hard-coded title to titleKey, translate group labels (incl. the collapsible Training), breadcrumbs, user menu (Profile / Settings / Logout), help button and toggle aria labels; replace physical mr-/right- utilities with logical me-/end-. - AI components (AiTipBanner, AiInsightsPanel, AiAlertBanner, AiSearchBar, AiAssistantDrawer): apply dir="auto" at the container level, localize titles, loading / error / empty states. - Dashboards (admin / student / teacher): wrap numeric values in <bdi>, localize dates via ar-EG, fix flex direction for KPI and assignment cards. - UI primitives (breadcrumb, calendar, carousel, dropdown-menu, menubar, context-menu, pagination, sidebar): flip chevrons in RTL via a scoped CSS rule, swap pl-/pr-/ml-/mr- for ps-/pe-/ms-/me-. - Add logical-direction helpers and bidirectional isolation classes. Locales - Expand en.ts and ar.ts with full `nav`, `sidebarGroup`, `breadcrumb`, `userMenu`, `chrome`, `ai`, and dashboard key sets; keep key parity. API client - `api-client.ts` reads the active language from localStorage/i18n and sends `Accept-Language` on every request so the backend can localize AI output. Backend (encoach_ai) - openai_service: add _LANGUAGE_NAMES, normalize_language, language-aware system prompt injection for every OpenAI call. - coach_service + controllers (coach_controller, ai_controller): thread the requested language from headers / user locale down to OpenAIService. - ai_feedback: fix latent registry error by pointing course_id at op.course instead of the non-existent encoach.course. Other - .gitignore: ignore runtime odoo logs and local caches. Made-with: Cursor
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import type { Translations } from "./en";
|
||||
|
||||
/** Arabic (RTL) translations. */
|
||||
/** Arabic (RTL) translations. Keep key parity with `en.ts`. */
|
||||
const ar: Translations = {
|
||||
common: {
|
||||
cancel: "إلغاء",
|
||||
@@ -20,30 +20,293 @@ const ar: Translations = {
|
||||
status: "الحالة",
|
||||
settings: "الإعدادات",
|
||||
signOut: "تسجيل الخروج",
|
||||
viewAll: "عرض الكل",
|
||||
dismiss: "تجاهل",
|
||||
pending: "قيد الانتظار",
|
||||
active: "نشط",
|
||||
inactive: "غير نشط",
|
||||
available: "متاح",
|
||||
unavailable: "غير متاح",
|
||||
name: "الاسم",
|
||||
email: "البريد الإلكتروني",
|
||||
user: "المستخدم",
|
||||
home: "الرئيسية",
|
||||
},
|
||||
auth: {
|
||||
signIn: "تسجيل الدخول",
|
||||
signInTitle: "تسجيل الدخول إلى EnCoach",
|
||||
welcomeBack: "مرحباً بعودتك",
|
||||
signInDescription: "سجّل الدخول إلى حسابك للمتابعة",
|
||||
email: "البريد الإلكتروني",
|
||||
emailPlaceholder: "you@example.com",
|
||||
password: "كلمة المرور",
|
||||
rememberMe: "تذكرني",
|
||||
forgotPassword: "هل نسيت كلمة المرور؟",
|
||||
needAccount: "ليس لديك حساب؟",
|
||||
signUp: "إنشاء حساب",
|
||||
invalidCredentials: "البريد الإلكتروني أو كلمة المرور غير صحيحة",
|
||||
missingCredentials: "يرجى إدخال البريد الإلكتروني وكلمة المرور",
|
||||
loginFailedTitle: "فشل تسجيل الدخول",
|
||||
errorTitle: "خطأ",
|
||||
},
|
||||
nav: {
|
||||
adminDashboard: "لوحة الإدارة",
|
||||
platformDashboard: "لوحة المنصّة",
|
||||
dashboard: "لوحة التحكم",
|
||||
courses: "الدورات",
|
||||
myCourses: "دوراتي",
|
||||
students: "الطلاب",
|
||||
teachers: "المعلمون",
|
||||
exams: "الاختبارات",
|
||||
batches: "الدفعات",
|
||||
timetable: "الجدول الدراسي",
|
||||
reports: "التقارير",
|
||||
settings: "الإعدادات",
|
||||
profile: "الملف الشخصي",
|
||||
privacy: "مركز الخصوصية",
|
||||
assignments: "الواجبات",
|
||||
examsList: "قائمة الاختبارات",
|
||||
examStructures: "هياكل الاختبارات",
|
||||
rubrics: "معايير التقييم",
|
||||
generation: "التوليد",
|
||||
reviewQueue: "قائمة المراجعة",
|
||||
aiPrompts: "تعليمات الذكاء الاصطناعي",
|
||||
aiFeedback: "ملاحظات الذكاء الاصطناعي",
|
||||
approvalWorkflows: "سير عمل الموافقات",
|
||||
taxonomy: "التصنيف",
|
||||
resources: "الموارد",
|
||||
resourceLibrary: "مكتبة الموارد",
|
||||
academicYears: "السنوات الأكاديمية",
|
||||
departments: "الأقسام",
|
||||
admissions: "القبول",
|
||||
admissionRegister: "سجل القبول",
|
||||
examSessions: "جلسات الاختبارات",
|
||||
marksheets: "كشوفات الدرجات",
|
||||
studentLeave: "إجازات الطلاب",
|
||||
fees: "الرسوم والمدفوعات",
|
||||
lessons: "الدروس",
|
||||
gradebook: "سجل الدرجات",
|
||||
studentProgress: "تقدم الطالب",
|
||||
library: "المكتبة",
|
||||
activities: "الأنشطة",
|
||||
facilities: "المرافق",
|
||||
users: "المستخدمون",
|
||||
entities: "الكيانات",
|
||||
classrooms: "الفصول",
|
||||
userRoles: "أدوار المستخدمين",
|
||||
rolesPermissions: "الأدوار والصلاحيات",
|
||||
authorityMatrix: "مصفوفة الصلاحيات",
|
||||
studentPerformance: "أداء الطلاب",
|
||||
statsCorporate: "إحصاءات الشركات",
|
||||
record: "السجل",
|
||||
vocabulary: "المفردات",
|
||||
grammar: "القواعد",
|
||||
faqManager: "إدارة الأسئلة الشائعة",
|
||||
notificationRules: "قواعد الإشعارات",
|
||||
approvalConfig: "إعدادات الموافقات",
|
||||
paymentRecord: "سجل المدفوعات",
|
||||
tickets: "التذاكر",
|
||||
settings: "الإعدادات",
|
||||
profile: "الملف الشخصي",
|
||||
privacy: "مركز الخصوصية",
|
||||
subjectRegistration: "تسجيل المواد",
|
||||
mySubjects: "موادي",
|
||||
grades: "الدرجات",
|
||||
attendance: "الحضور",
|
||||
myJourney: "رحلتي",
|
||||
discussions: "المناقشات",
|
||||
messages: "الرسائل",
|
||||
announcements: "الإعلانات",
|
||||
},
|
||||
sidebarGroup: {
|
||||
overview: "نظرة عامة",
|
||||
lms: "نظام التعلم",
|
||||
adaptiveLearning: "التعلم التكيّفي",
|
||||
institutional: "المؤسسي",
|
||||
academic: "الأكاديمي",
|
||||
management: "الإدارة",
|
||||
reports: "التقارير",
|
||||
configuration: "الإعدادات",
|
||||
training: "التدريب",
|
||||
support: "الدعم",
|
||||
learning: "التعلم",
|
||||
progress: "التقدم",
|
||||
communication: "التواصل",
|
||||
account: "الحساب",
|
||||
teaching: "التدريس",
|
||||
},
|
||||
breadcrumb: {
|
||||
home: "الرئيسية",
|
||||
admin: "الإدارة",
|
||||
dashboard: "لوحة التحكم",
|
||||
platform: "المنصّة",
|
||||
exam: "الاختبار",
|
||||
review: "مراجعة",
|
||||
ai: "الذكاء الاصطناعي",
|
||||
feedback: "ملاحظات",
|
||||
},
|
||||
userMenu: {
|
||||
profile: "الملف الشخصي",
|
||||
settings: "الإعدادات",
|
||||
logout: "تسجيل الخروج",
|
||||
userFallback: "مستخدم",
|
||||
},
|
||||
chrome: {
|
||||
needHelp: "هل تحتاج مساعدة؟",
|
||||
ticketsTooltip: "تذاكر الدعم",
|
||||
aiSearchPlaceholder: "اسأل عن أي شيء… مثال: «اعرض الطلاب ذوي الحضور المنخفض»",
|
||||
aiSearching: "الذكاء الاصطناعي يبحث…",
|
||||
aiRelatedQueries: "استفسارات ذات صلة",
|
||||
aiNoResults: "لا توجد نتائج لـ «{{q}}». جرّب سؤالاً أو كلمة مفتاحية مختلفة.",
|
||||
aiSearchFailedTitle: "فشل البحث",
|
||||
aiSearchFailedDesc: "تعذّر إكمال بحث الذكاء الاصطناعي.",
|
||||
portalSuffix: "البوابة",
|
||||
adminAlt: "EnCoach",
|
||||
adminAltLong: "EnCoach — أطلق إمكاناتك مع منصّة مدعومة بالذكاء الاصطناعي",
|
||||
toggleSidebar: "إظهار/إخفاء الشريط الجانبي",
|
||||
},
|
||||
notifications: {
|
||||
title: "الإشعارات",
|
||||
empty: "ليست لديك إشعارات جديدة.",
|
||||
ariaLabel: "الإشعارات",
|
||||
},
|
||||
theme: {
|
||||
title: "المظهر",
|
||||
light: "فاتح",
|
||||
dark: "داكن",
|
||||
system: "النظام",
|
||||
toggleLabel: "تبديل المظهر",
|
||||
},
|
||||
language: {
|
||||
change: "تغيير اللغة",
|
||||
label: "اللغة",
|
||||
},
|
||||
roles: {
|
||||
student: "طالب",
|
||||
teacher: "معلّم",
|
||||
admin: "مسؤول",
|
||||
developer: "مطوّر",
|
||||
corporate: "شركة",
|
||||
mastercorporate: "شركة رئيسية",
|
||||
agent: "وكيل",
|
||||
},
|
||||
dashboard: {
|
||||
greetingFallback: "الطالب",
|
||||
},
|
||||
studentDash: {
|
||||
welcome: "مرحباً بعودتك، {{name}}!",
|
||||
subtitle: "إليك نظرة عامة على تقدّمك الدراسي.",
|
||||
enrolledCourses: "الدورات المسجّلة",
|
||||
overallProgress: "التقدم العام",
|
||||
averageGrade: "متوسط الدرجات",
|
||||
totalChapters: "إجمالي الفصول",
|
||||
myCourses: "دوراتي",
|
||||
noEnrolledCourses: "لم تسجّل في أي دورة بعد.",
|
||||
chaptersMaterials: "{{chapters}} فصل · {{materials}} مادة",
|
||||
quickActions: "إجراءات سريعة",
|
||||
enrollToStart: "سجّل في دورة للبدء.",
|
||||
continue: "متابعة",
|
||||
start: "ابدأ",
|
||||
chaptersDone: "{{done}}/{{total}} فصل مكتمل",
|
||||
recentGrades: "آخر الدرجات",
|
||||
noGradesYet: "لا توجد درجات بعد.",
|
||||
},
|
||||
teacherDash: {
|
||||
title: "لوحة المعلّم",
|
||||
subtitle: "نظرة عامة على نشاطك التدريسي.",
|
||||
activeCourses: "الدورات النشطة",
|
||||
totalStudents: "إجمالي الطلاب",
|
||||
pendingGrading: "تقييمات قيد الانتظار",
|
||||
avgPassRate: "متوسط نسبة النجاح",
|
||||
myCourses: "دوراتي",
|
||||
colCourse: "الدورة",
|
||||
colStudents: "الطلاب",
|
||||
colStatus: "الحالة",
|
||||
recentActivity: "النشاط الأخير",
|
||||
submitted: "تم الإرسال {{when}}",
|
||||
pending: "قيد الانتظار",
|
||||
},
|
||||
adminDash: {
|
||||
title: "لوحة الإدارة",
|
||||
subtitle: "نظرة عامة على المنصّة والمؤشرات الرئيسية.",
|
||||
addStudent: "إضافة طالب",
|
||||
newCourse: "دورة جديدة",
|
||||
totalStudents: "إجمالي الطلاب",
|
||||
activeCourses: "الدورات النشطة",
|
||||
teachers: "المعلمون",
|
||||
activeBatches: "الدفعات النشطة",
|
||||
openTickets: "تذاكر مفتوحة",
|
||||
revenue: "الإيرادات",
|
||||
departments: "الأقسام",
|
||||
classrooms: "الفصول",
|
||||
subjects: "المواد",
|
||||
resources: "الموارد",
|
||||
coursesOverview: "نظرة عامة على الدورات",
|
||||
batchCapacity: "سعة الدفعات",
|
||||
noCourseData: "لا توجد بيانات دورات متاحة.",
|
||||
noBatchData: "لا توجد بيانات دفعات متاحة.",
|
||||
quickSummary: "ملخّص سريع",
|
||||
colModule: "الوحدة",
|
||||
colCount: "العدد",
|
||||
colStatus: "الحالة",
|
||||
exams: "الاختبارات",
|
||||
examSessionsCount: "{{n}} جلسة",
|
||||
assignments: "الواجبات",
|
||||
acrossCourses: "عبر جميع الدورات",
|
||||
supportTickets: "تذاكر الدعم",
|
||||
ticketsOpenCount: "{{n}} مفتوحة",
|
||||
payments: "المدفوعات",
|
||||
revenueTotal: "{{amount}} إجمالاً",
|
||||
chartCapacity: "السعة",
|
||||
chartEnrolled: "المسجّلون",
|
||||
},
|
||||
examPopup: {
|
||||
title: "اختبارات قادمة ({{n}})",
|
||||
activeNow: "متاح الآن",
|
||||
from: "من:",
|
||||
to: "إلى:",
|
||||
startExam: "ابدأ الاختبار",
|
||||
notAvailableYet: "غير متاح بعد",
|
||||
willBeAvailable: "سيتاح الاختبار عندما يصبح نشطاً",
|
||||
notActive: "الاختبار غير نشط حالياً",
|
||||
},
|
||||
errors: {
|
||||
somethingWrong: "حدث خطأ ما",
|
||||
unexpectedDescription: "حدث خطأ غير متوقع. يرجى تحديث الصفحة والمحاولة مرة أخرى.",
|
||||
errorDetails: "تفاصيل الخطأ",
|
||||
refreshPage: "تحديث الصفحة",
|
||||
notFoundCode: "404",
|
||||
notFoundMessage: "عذراً! الصفحة غير موجودة",
|
||||
returnHome: "العودة إلى الرئيسية",
|
||||
},
|
||||
ai: {
|
||||
assistantLabel: "مساعد الذكاء الاصطناعي",
|
||||
assistantTitle: "مساعد EnCoach الذكي",
|
||||
placeholder: "اسأل عن أي شيء…",
|
||||
send: "إرسال",
|
||||
thinking: "يفكّر…",
|
||||
emptyLine1: "اسألني عن أي شيء يخص المنصّة،",
|
||||
emptyLine2: "أو اختر إجراءً سريعاً من الأعلى.",
|
||||
fallbackReply: "عذراً، تعذّر الوصول إلى المساعد. يرجى المحاولة مرة أخرى بعد قليل.",
|
||||
replyErrorTitle: "تعذّر الحصول على ردّ",
|
||||
replyErrorDesc: "حدث خطأ ما. يرجى المحاولة مرة أخرى.",
|
||||
quickHealth: "ملخّص حالة المنصّة",
|
||||
quickDropouts: "عرض مخاطر التسرّب",
|
||||
quickCompare: "مقارنة أداء الدورات",
|
||||
quickBatch: "اقتراحات لتحسين الدفعات",
|
||||
tipLabel: "نصيحة الذكاء الاصطناعي",
|
||||
insightLabel: "رؤية الذكاء الاصطناعي",
|
||||
recommendationLabel: "توصية الذكاء الاصطناعي",
|
||||
categoryTipLabel: "نصيحة {{category}} من الذكاء الاصطناعي",
|
||||
loadingTip: "جارٍ تحميل النصيحة…",
|
||||
loadingInsights: "جارٍ تحميل الرؤى…",
|
||||
loadingAlerts: "جارٍ تحميل التنبيهات…",
|
||||
couldNotLoadTip: "تعذّر تحميل النصيحة.",
|
||||
couldNotLoadInsights: "تعذّر تحميل الرؤى.",
|
||||
couldNotLoadAlerts: "تعذّر تحميل التنبيهات.",
|
||||
noTipAvailable: "لا توجد نصيحة متاحة.",
|
||||
noTipForContext: "لا توجد نصيحة لهذا السياق بعد.",
|
||||
noInsightsAvailable: "لا توجد رؤى متاحة لهذا العرض.",
|
||||
noAlertsRightNow: "لا توجد تنبيهات ذكاء اصطناعي حالياً.",
|
||||
alertsUnavailable: "التنبيهات غير متاحة",
|
||||
insightsUnavailable: "الرؤى غير متاحة",
|
||||
platformInsightsTitle: "رؤى المنصّة من الذكاء الاصطناعي",
|
||||
},
|
||||
privacy: {
|
||||
title: "مركز الخصوصية",
|
||||
@@ -74,12 +337,6 @@ const ar: Translations = {
|
||||
commentRequired: "من فضلك أخبرنا بالخطأ.",
|
||||
submit: "إرسال الملاحظات",
|
||||
},
|
||||
theme: {
|
||||
title: "المظهر",
|
||||
light: "فاتح",
|
||||
dark: "داكن",
|
||||
system: "النظام",
|
||||
},
|
||||
};
|
||||
|
||||
export default ar;
|
||||
|
||||
Reference in New Issue
Block a user