Files
encoach_frontend_v4/src/i18n/locales/en.ts
Yamen Ahmad 45408acd5c feat(ai): LangGraph as core runtime + AI Agents/Tools console + full-demo seed
Core AI runtime
- New encoach.ai.agent + encoach.ai.tool models with M2M tool binding,
  graph topology (simple|plan_review_revise|rag|react), model + fallback,
  temperature, max_tokens, response_format, max_revisions, quality checks
  and system prompt fields.
- services/agent_runtime.py compiles a langgraph.StateGraph per agent
  and caches the build per (key, write_date). Emits a structured trace
  (output, tool_calls, retrieval_hits, revisions, quality_issues,
  ms, model_used, fallback_used) and auto-falls-back on rate-limit/5xx.
- services/agent_tools.py registers 11 tool handlers wrapping existing
  services: resources.search, rubric.fetch, outcomes.fetch,
  student.profile, quality.cefr_check, quality.ai_detect,
  quality.content_gate, course_plan.save (mutates),
  course_plan.save_materials (mutates), scoring.grade_writing,
  scoring.grade_speaking.
- 7 default agents seeded via data/agents_defaults.xml: course_planner,
  course_week_materials, exam_generator, exercise_generator, lms_tutor,
  writing_grader, speaking_grader.
- Feature flag encoach_ai.use_langgraph_runtime (default True).
- encoach_ai_course pipeline now routes through AgentRuntime when on,
  legacy SDK path kept as fallback.

Admin UI
- /admin/ai/prompts is now a tabbed Agents | Tools | Prompts console.
- AIAgentsPanel: card grid + config dialog (model/temp/graph/tools/
  system prompt) + built-in Test Runner showing live trace.
- AIToolsPanel: registry table with category badges, mutates flag,
  schema viewer, edit dialog.
- New /api/ai/agents* and /api/ai/tools* controller (list/get/update/
  test, list-tools, toggle-tool).
- Sidebar label nav.aiPrompts -> nav.aiAgents (AI Agents and Tools).
- EN + AR (RTL) translations for ~80 new keys.

Smart Wizard pages
- /admin/quick-setup hub + CourseWizard, CoursePlanWizard,
  RubricWizard, ExamStructureWizard step-by-step flows.
- /admin/course-plans list + detail pages.
- /teacher/quick-setup mirror.

Full demo seed + 8-role E2E
- seed_full_demo.py adds the 5 missing user_types (approver, corporate,
  mastercorporate, agent, developer), activates a 2-stage exam-approval
  workflow with one pending request, creates a GE1-aligned 12-week B1
  course plan with 6 detailed Week-1 materials (reading 400w, writing,
  listening 4-min script, speaking, grammar present simple vs continuous,
  vocabulary), and inserts sample ai.log + ai.feedback rows.
- reset_demo_passwords.py forces every demo login back to canonical
  passwords (admin123/teacher123/student123/approver123/corporate123/
  master123/agent123/dev123).
- e2e_full_scenario.py: 46/46 PASS read-only API smoke across all
  8 roles, including a live LangGraph round-trip on writing_grader.
- e2e_approval_chain.py: 6/6 PASS mutation E2E - approver approves
  stage 1, admin approves stage 2, linked encoach.exam.custom flips
  to status=published, verified via psql.

Docs
- docs/PROJECT_SUMMARY.md updated to 2026-04-25: new Latest events
  bullets, refreshed credentials table, full sections 22 (LangGraph
  runtime) and 23 (full demo seed + 8-role E2E).
- docs/ENCOACH_FULL_DEMO_QA_REPORT.md added with credentials,
  per-endpoint PASS/FAIL, mutation chain proof, LangGraph live output.
- backend/GE1 Course Outline_ Fall AY25-26.pdf vendored as the
  reference outline the GE1 plan/materials are aligned to.

Dependencies
- requirements.txt: langgraph>=0.2.0, langchain-core>=0.3.0.
- encoach_ai/__manifest__.py: external_dependencies updated.

Made-with: Cursor
2026-04-25 03:14:22 +04:00

935 lines
34 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** English translations. Keep keys nested by feature area.
*
* We deliberately annotate the literal with `Translations` (not `as const`)
* so sibling locale files can widen their string values without fighting
* literal-string type mismatches.
*
* Adding a new key: add it here FIRST (English is the source of truth), then
* mirror it in `ar.ts`. The `Translations` interface is intentionally
* permissive (`Record<string, string>` per group) so we don't have to update
* a giant type every time we add a string.
*/
export interface Translations {
common: Record<string, string>;
auth: Record<string, string>;
nav: Record<string, string>;
sidebarGroup: Record<string, string>;
breadcrumb: Record<string, string>;
userMenu: Record<string, string>;
chrome: Record<string, string>;
notifications: Record<string, string>;
theme: Record<string, string>;
language: Record<string, string>;
roles: Record<string, string>;
dashboard: Record<string, string>;
studentDash: Record<string, string>;
teacherDash: Record<string, string>;
adminDash: Record<string, string>;
examPopup: Record<string, string>;
errors: Record<string, string>;
ai: Record<string, string>;
privacy: Record<string, string>;
feedback: Record<string, string>;
// quickSetup mixes flat strings (page chrome) and nested blocks
// ("admin.step1.title", "teacher.quick.discussion.title") so its values
// can be either strings or nested records. We intentionally use a loose
// shape here rather than maintain a hand-authored deep type.
quickSetup: Record<string, unknown>;
/** Smart Wizard Hub + per-scenario step-by-step wizards. */
wizardHub: Record<string, unknown>;
wizard: Record<string, unknown>;
/** AI course-plan generator — list, detail, wizard. */
coursePlan: Record<string, unknown>;
/** AI Agents & Tools configurator (the /admin/ai/prompts page). */
aiAdmin: Record<string, unknown>;
agents: Record<string, unknown>;
tools: Record<string, unknown>;
}
const en: Translations = {
common: {
cancel: "Cancel",
save: "Save",
delete: "Delete",
edit: "Edit",
close: "Close",
back: "Back",
next: "Next",
search: "Search",
loading: "Loading…",
error: "Error",
retry: "Retry",
yes: "Yes",
no: "No",
actions: "Actions",
status: "Status",
settings: "Settings",
signOut: "Sign out",
viewAll: "View All",
dismiss: "Dismiss",
pending: "Pending",
active: "Active",
inactive: "Inactive",
available: "Available",
unavailable: "Unavailable",
name: "Name",
email: "Email",
user: "User",
home: "Home",
saving: "Saving…",
disabled: "Disabled",
},
auth: {
signIn: "Sign in",
signInTitle: "Sign in to EnCoach",
welcomeBack: "Welcome back",
signInDescription: "Sign in to your account to continue",
email: "Email",
emailPlaceholder: "you@example.com",
password: "Password",
rememberMe: "Remember me",
forgotPassword: "Forgot password?",
needAccount: "Don't have an account?",
signUp: "Sign up",
invalidCredentials: "Invalid email or password",
missingCredentials: "Please enter email and password",
loginFailedTitle: "Login Failed",
errorTitle: "Error",
},
nav: {
smartWizard: "Smart Wizard",
quickSetup: "Smart Setup",
coursePlans: "Course Plans (AI)",
adminDashboard: "Admin Dashboard",
platformDashboard: "Platform Dashboard",
dashboard: "Dashboard",
courses: "Courses",
myCourses: "My Courses",
students: "Students",
teachers: "Teachers",
batches: "Batches",
timetable: "Timetable",
reports: "Reports",
assignments: "Assignments",
examsList: "Exams List",
examStructures: "Exam Structures",
rubrics: "Rubrics",
generation: "Generation",
reviewQueue: "Review Queue",
aiPrompts: "AI Agents & Tools",
aiFeedback: "AI Feedback",
approvalWorkflows: "Approval Workflows",
taxonomy: "Taxonomy",
resources: "Resources",
resourceLibrary: "Resource Library",
academicYears: "Academic Years",
departments: "Departments",
admissions: "Admissions",
admissionRegister: "Admission Register",
examSessions: "Exam Sessions",
marksheets: "Marksheets",
studentLeave: "Student Leave",
fees: "Fees & Payments",
lessons: "Lessons",
gradebook: "Gradebook",
studentProgress: "Student Progress",
library: "Library",
activities: "Activities",
facilities: "Facilities",
users: "Users",
entities: "Entities",
classrooms: "Classrooms",
userRoles: "User Roles",
rolesPermissions: "Roles & Permissions",
authorityMatrix: "Authority Matrix",
studentPerformance: "Student Performance",
statsCorporate: "Stats Corporate",
record: "Record",
vocabulary: "Vocabulary",
grammar: "Grammar",
faqManager: "FAQ Manager",
notificationRules: "Notification Rules",
approvalConfig: "Approval Config",
paymentRecord: "Payment Record",
tickets: "Tickets",
settings: "Settings",
profile: "Profile",
privacy: "Privacy Center",
subjectRegistration: "Subject Registration",
mySubjects: "My Subjects",
grades: "Grades",
attendance: "Attendance",
myJourney: "My Journey",
discussions: "Discussions",
messages: "Messages",
announcements: "Announcements",
},
sidebarGroup: {
overview: "Overview",
lms: "LMS",
adaptiveLearning: "Adaptive Learning",
institutional: "Institutional",
academic: "Academic",
management: "Management",
reports: "Reports",
configuration: "Configuration",
training: "Training",
support: "Support",
learning: "Learning",
progress: "Progress",
communication: "Communication",
account: "Account",
teaching: "Teaching",
},
breadcrumb: {
home: "Home",
admin: "Admin",
dashboard: "Dashboard",
platform: "Platform",
exam: "Exam",
review: "Review",
ai: "AI",
feedback: "Feedback",
},
userMenu: {
profile: "Profile",
settings: "Settings",
logout: "Logout",
userFallback: "User",
},
chrome: {
needHelp: "Need help?",
ticketsTooltip: "Support tickets",
aiSearchPlaceholder: "Ask anything... e.g. 'Show students with low attendance'",
aiSearching: "AI is searching…",
aiRelatedQueries: "Related queries",
aiNoResults: "No results for \"{{q}}\". Try a different question or keyword.",
aiSearchFailedTitle: "Search failed",
aiSearchFailedDesc: "Could not complete AI search.",
portalSuffix: "Portal",
adminAlt: "EnCoach",
adminAltLong: "EnCoach — Unlock your potential with AI powered platform",
toggleSidebar: "Toggle sidebar",
},
notifications: {
title: "Notifications",
empty: "You're all caught up.",
ariaLabel: "Notifications",
},
theme: {
title: "Theme",
light: "Light",
dark: "Dark",
system: "System",
toggleLabel: "Toggle theme",
},
language: {
change: "Change language",
label: "Language",
},
roles: {
student: "student",
teacher: "teacher",
admin: "admin",
developer: "developer",
corporate: "corporate",
mastercorporate: "master corporate",
agent: "agent",
},
dashboard: {
greetingFallback: "Student",
},
studentDash: {
welcome: "Welcome back, {{name}}!",
subtitle: "Here's an overview of your learning progress.",
enrolledCourses: "Enrolled Courses",
overallProgress: "Overall Progress",
averageGrade: "Average Grade",
totalChapters: "Total Chapters",
myCourses: "My Courses",
noEnrolledCourses: "No enrolled courses yet.",
chaptersMaterials: "{{chapters}} chapters · {{materials}} materials",
quickActions: "Quick Actions",
enrollToStart: "Enroll in a course to get started.",
continue: "Continue",
start: "Start",
chaptersDone: "{{done}}/{{total}} chapters done",
recentGrades: "Recent Grades",
noGradesYet: "No grades yet.",
},
teacherDash: {
title: "Teacher Dashboard",
subtitle: "Overview of your teaching activities.",
activeCourses: "Active Courses",
totalStudents: "Total Students",
pendingGrading: "Pending Grading",
avgPassRate: "Avg. Pass Rate",
myCourses: "My Courses",
colCourse: "Course",
colStudents: "Students",
colStatus: "Status",
recentActivity: "Recent Activity",
submitted: "Submitted {{when}}",
pending: "Pending",
},
adminDash: {
title: "Admin Dashboard",
subtitle: "Platform overview and key metrics.",
addStudent: "Add Student",
newCourse: "New Course",
totalStudents: "Total Students",
activeCourses: "Active Courses",
teachers: "Teachers",
activeBatches: "Active Batches",
openTickets: "Open Tickets",
revenue: "Revenue",
departments: "Departments",
classrooms: "Classrooms",
subjects: "Subjects",
resources: "Resources",
coursesOverview: "Courses Overview",
batchCapacity: "Batch Capacity",
noCourseData: "No course data available.",
noBatchData: "No batch data available.",
quickSummary: "Quick Summary",
colModule: "Module",
colCount: "Count",
colStatus: "Status",
exams: "Exams",
examSessionsCount: "{{n}} sessions",
assignments: "Assignments",
acrossCourses: "across courses",
supportTickets: "Support Tickets",
ticketsOpenCount: "{{n}} open",
payments: "Payments",
revenueTotal: "{{amount}} total",
chartCapacity: "Capacity",
chartEnrolled: "Enrolled",
},
examPopup: {
title: "Upcoming Exams ({{n}})",
activeNow: "Active Now",
from: "From:",
to: "To:",
startExam: "Start Exam",
notAvailableYet: "Not Available Yet",
willBeAvailable: "Exam will be available once it becomes active",
notActive: "Exam is not currently active",
},
errors: {
somethingWrong: "Something went wrong",
unexpectedDescription: "An unexpected error occurred. Please try refreshing the page.",
errorDetails: "Error details",
refreshPage: "Refresh Page",
notFoundCode: "404",
notFoundMessage: "Oops! Page not found",
returnHome: "Return to Home",
},
ai: {
assistantLabel: "AI Assistant",
assistantTitle: "EnCoach AI Assistant",
placeholder: "Ask anything...",
send: "Send",
thinking: "Thinking…",
emptyLine1: "Ask me anything about the platform,",
emptyLine2: "or click a quick action above.",
fallbackReply: "Sorry, I could not reach the assistant. Please try again in a moment.",
replyErrorTitle: "Could not get a reply",
replyErrorDesc: "Something went wrong. Try again.",
quickHealth: "Platform health summary",
quickDropouts: "Show dropout risks",
quickCompare: "Compare course performance",
quickBatch: "Suggest batch improvements",
tipLabel: "AI Tip",
insightLabel: "AI Insight",
recommendationLabel: "AI Recommendation",
categoryTipLabel: "AI {{category}} Tip",
loadingTip: "Loading AI tip…",
loadingInsights: "Loading insights…",
loadingAlerts: "Loading alerts…",
couldNotLoadTip: "Could not load tip.",
couldNotLoadInsights: "Could not load insights.",
couldNotLoadAlerts: "Could not load alerts.",
noTipAvailable: "No tip available.",
noTipForContext: "No tip for this context yet.",
noInsightsAvailable: "No insights available for this view.",
noAlertsRightNow: "No AI alerts right now.",
alertsUnavailable: "Alerts unavailable",
insightsUnavailable: "Insights unavailable",
platformInsightsTitle: "AI Platform Insights",
},
privacy: {
title: "Privacy Center",
description:
"Manage your personal data held by EnCoach under GDPR and equivalent regulations.",
exportTitle: "Download your data",
exportDescription:
"We'll package your profile, entity memberships, exam attempts, answers, AI feedback, and tickets into a single JSON file.",
exportButton: "Download my data",
exportPreparing: "Preparing export…",
exportSuccess: "Data export downloaded",
deleteTitle: "Delete my account",
deleteDescription:
"This anonymises your profile and removes personal fields from our records. Exam attempts are retained (without identifying information) for statistical integrity. This action cannot be undone.",
deleteButton: "Erase my account",
deleteErasing: "Erasing…",
confirmTitle: "Erase your account?",
confirmDescription:
"We'll anonymise your personal data and deactivate your login. Aggregate analytics will remain but will no longer be linked to you.",
confirmTypeDelete: "Type DELETE to confirm",
confirmErased: "Your account has been erased. Signing out…",
},
feedback: {
thumbsUp: "Thumbs up",
thumbsDown: "Thumbs down",
whatWentWrong: "What went wrong?",
commentPlaceholder: "e.g. Wrong answer, confusing wording, off-topic…",
commentRequired: "Please tell us what was wrong.",
submit: "Submit feedback",
},
// Smart-setup wizard. Nested so i18next's default "." key separator
// resolves e.g. t("quickSetup.admin.step1.title").
quickSetup: {
adminTitle: "Smart Setup",
adminSubtitle:
"Everything you need to launch an exam-ready platform, in the recommended order. Tick each step off as you go — the wizard auto-detects progress.",
teacherTitle: "Smart Setup",
teacherSubtitle:
"Launch a new course end-to-end, then jump to common day-to-day tasks.",
progressLabel: "Progress",
recommendedFlow: "Recommended flow",
otherQuickCreates: "Other quick creates",
ready: "Ready",
start: "Start",
review: "Review",
open: "Open",
helpAria: "Show help",
admin: {
step1: {
title: "Create a rubric",
description:
"Define the grading criteria for Writing and Speaking tasks. Rubrics are referenced later when generating or approving exams.",
help: "A rubric is a scoring grid (bands × criteria). You can start from a template or compose one from predefined criteria.",
},
step2: {
title: "Define an exam structure",
description:
"Blueprint the sections, tasks, and parts that every generated or custom exam of this type must contain.",
help: "Structures enforce consistency. E.g. an IELTS Writing structure has Task 1 (150w) + Task 2 (250w); generation will refuse to submit if either is missing.",
},
step3: {
title: "Generate or create an exam",
description:
"Use AI generation (fastest) or hand-build a custom exam. Save as draft or submit for approval.",
help: "Generation picks a structure + rubric and produces questions. The custom builder gives you full control for pilot/test exams.",
},
step4: {
title: "Review & approve",
description:
"Approvers sign off on exams before students can see them. Configure the workflow once, then route submissions automatically.",
help: "The approval queue lists every exam waiting for sign-off. Reject sends it back to the author; approve publishes it.",
},
step5: {
title: "Assign to students",
description:
"Schedule the published exam, pick a cohort, and send it out. Students see it immediately in their portal.",
help: "Assignments can target individual students, batches, or classrooms. Timezone-aware windows are supported.",
},
quick: {
course: { title: "New course", description: "Stand up a course shell for teachers to fill with chapters." },
resource: { title: "Upload resource", description: "Add PDFs, audio, video, or links to the shared library." },
student: { title: "Add student", description: "Create a student account and assign them to a batch." },
teacher: { title: "Add teacher", description: "Invite a teacher and grant teaching permissions." },
classroom: { title: "New classroom", description: "Group students for scheduling and attendance." },
examSession: { title: "Schedule exam session", description: "Create a proctored sitting for an institutional exam." },
customExam: { title: "Custom exam", description: "Hand-build an exam from scratch with full control." },
ticket: { title: "Open ticket", description: "Raise a support ticket on behalf of a user." },
},
},
teacher: {
step1: {
title: "Create a course",
description: "Give your course a name, pick a subject, and set its level. You can edit chapters after creation.",
help: "Courses are the container for chapters, materials, and assignments.",
},
step2: {
title: "Add chapters & content",
description: "Open your course and add chapters with lessons, videos, quizzes, and practice tasks.",
help: "Chapters organise learning objectives. Use the AI workbench to auto-draft content.",
},
step3: {
title: "Upload resources",
description: "Share supporting PDFs, audio, or video with your students via the library.",
help: "Large files are fine — the server accepts up to 128 MB per upload.",
},
step4: {
title: "Create an assignment",
description: "Turn a published exam or task into an assignment with a due date and target cohort.",
help: "Assignments auto-surface in each student's dashboard and on their timetable.",
},
step5: {
title: "Track student progress",
description: "Monitor submissions, attendance, and adaptive learning insights for your class.",
help: "The adaptive engine flags at-risk students so you can intervene early.",
},
quick: {
discussion: { title: "New discussion", description: "Start a topic thread for your class." },
announcement: { title: "New announcement", description: "Broadcast a message to all your students." },
attendance: { title: "Mark attendance", description: "Record today's attendance for a session." },
},
},
},
wizardHub: {
title: "Smart Wizard",
subtitle:
"Pick any scenario and the wizard will walk you through it step by step. No need to hunt through settings — every Next button moves you closer to done.",
recommendedOrder: "Recommended order",
order: {
rubric: "Create rubrics (Writing / Speaking)",
structure: "Define exam structures (sections, tasks, durations)",
generate: "Generate or create exams",
approve: "Review & approve pending exams",
assign: "Assign exams to students",
},
guided: "Guided wizards",
advanced: "Full pages (advanced)",
advancedBadge: "Advanced",
aiBadge: "AI",
startWizard: "Start wizard",
openPage: "Open page",
cards: {
rubric: {
title: "Create a rubric",
description: "Name → skill → criteria → descriptors → review. Writing and Speaking only.",
},
examStructure: {
title: "Define an exam structure",
description: "Name → modules → writing tasks → review. Reusable blueprint for generation.",
},
course: {
title: "Create a course",
description: "Title → level & capacity → review. Chapters can be added from the course page.",
},
coursePlan: {
title: "Generate a course plan (AI)",
description: "Describe the course → AI writes objectives, per-skill outcomes, grammar scope and a week-by-week delivery plan, then produces real teaching materials per week.",
},
generation: {
title: "Generate an exam",
description: "Full AI generation page with rubric/structure pickers and per-module controls.",
},
approval: {
title: "Approval workflows",
description: "Configure who reviews which exams and see pending requests.",
},
assign: {
title: "Assign to students",
description: "Full scheduling page with student picker, windows, and timezone support.",
},
resource: {
title: "Upload resource",
description: "Add PDFs, audio, video, or links to the shared library.",
},
student: {
title: "Add student",
description: "Create a student account and enroll them in a batch.",
},
},
},
wizard: {
back: "Back",
next: "Next",
finish: "Finish",
backToHub: "Back to wizards",
stepOf: "Step {{current}} of {{total}}",
rubric: {
title: "Create a rubric",
subtitle: "Grading grid for Writing or Speaking tasks. Referenced later when generating or approving exams.",
finish: "Create rubric",
toastSuccess: "Rubric created",
toastError: "Could not create rubric",
addCriterion: "Add criterion",
removeCriterion: "Remove criterion",
unnamedCriterion: "(unnamed criterion)",
descriptorHint: "Descriptors are optional. They appear to graders as guidance for each criterion.",
maxLabel: "Max",
moduleHint:
"Rubrics only apply to Writing and Speaking. Listening and Reading are auto-graded and don't need one.",
step1: {
title: "Basics",
description: "Give the rubric a name and pick the skill it applies to.",
},
step2: {
title: "Criteria",
description: "Add the criteria you want graders to score. Each criterion has a max score (e.g. 9 for IELTS).",
},
step3: {
title: "Descriptors",
description: "Optional: describe what each criterion measures. Graders see these as hints.",
},
step4: {
title: "Review",
description: "Double-check and create.",
},
labels: {
name: "Rubric name",
module: "Skill",
description: "Description",
criterionName: "Criterion name",
maxScore: "Max score",
},
placeholders: {
name: "e.g. IELTS Writing Task 2",
description: "Short description shown to graders.",
criterionName: "e.g. Task Response",
descriptor: "What graders should check for this criterion.",
},
modules: {
writing: "Writing",
speaking: "Speaking",
},
errors: {
nameRequired: "Please enter a name for this rubric.",
moduleRestricted: "Rubrics apply only to Writing or Speaking.",
criterionRequired: "Add at least one criterion.",
criterionName: "Every criterion needs a name.",
criterionScore: "Max score must be between 1 and 100.",
},
},
structure: {
title: "Define an exam structure",
subtitle: "Blueprint the sections, tasks, and parts every generated or custom exam of this type must contain.",
finish: "Create structure",
toastSuccess: "Exam structure created",
toastError: "Could not create exam structure",
industryHint: "Optional: e.g. 'Business English', 'Healthcare'.",
writingSkipped: "Writing is not in the selected modules — this step is skipped.",
wordsSuffix: "words",
addTask: "Add task",
removeTask: "Remove task",
step1: {
title: "Basics",
description: "Name the structure and pick its exam type.",
},
step2: {
title: "Modules",
description: "Select which modules this structure covers. Students will see these sections.",
},
step3: {
title: "Writing tasks",
description: "For writing, define each task's minimum word count.",
},
step4: {
title: "Review",
description: "Double-check and create.",
},
labels: {
name: "Structure name",
industry: "Industry / context",
examType: "Exam type",
modules: "Modules",
taskLabel: "Task label",
minWords: "Min words",
},
placeholders: {
name: "e.g. IELTS Academic Writing",
industry: "e.g. Business English",
},
examTypes: {
academic: "Academic",
general: "General",
},
modules: {
listening: {
title: "Listening",
description: "Audio-based questions (auto-graded).",
},
reading: {
title: "Reading",
description: "Passage-based questions (auto-graded).",
},
writing: {
title: "Writing",
description: "Essay tasks graded with a rubric.",
},
speaking: {
title: "Speaking",
description: "Oral tasks graded with a rubric.",
},
},
errors: {
nameRequired: "Please enter a name for this structure.",
moduleRequired: "Select at least one module.",
writingTaskRequired: "Writing needs at least one task.",
writingTaskLabel: "Each writing task needs a label.",
writingTaskWords: "Minimum words must be at least 1.",
},
},
course: {
title: "Create a course",
subtitle: "A lightweight course skeleton. You can add chapters, materials and enroll students after creation.",
finish: "Create course",
toastSuccess: "Course created",
toastError: "Could not create course",
codeHint: "Leave blank to auto-generate from the title.",
difficultyHint: "How challenging is this course overall? Used for search & filtering.",
cefrHint: "If this course targets a specific CEFR band, pick it here.",
step1: {
title: "Basics",
description: "Give your course a name and a short description.",
},
step2: {
title: "Level & capacity",
description: "Set difficulty, target CEFR level, and how many students can enroll.",
},
step3: {
title: "Review",
description: "Double-check and create.",
},
labels: {
title: "Course title",
code: "Course code",
description: "Description",
difficulty: "Difficulty",
cefrLevel: "CEFR level",
capacity: "Max capacity",
},
placeholders: {
title: "e.g. Foundation English Level 1",
code: "Auto-generated if empty",
description: "Who is this course for? What will they learn?",
difficulty: "Select a difficulty",
cefr: "Select a CEFR level",
},
difficulty: {
beginner: "Beginner",
intermediate: "Intermediate",
advanced: "Advanced",
},
errors: {
titleRequired: "Please enter a course title.",
capacityRequired: "Max capacity must be at least 1.",
},
},
},
coursePlan: {
listTitle: "Course Plans",
listSubtitle:
"AI-generated curriculum outlines: objectives, per-skill learning outcomes, grammar scope, a week-by-week delivery plan, and on-demand teaching materials for each week.",
generateNew: "Generate new plan",
searchPlaceholder: "Search plans by name…",
loadFailed: "Couldn't load course plans.",
deleted: "Plan deleted.",
deleteFailed: "Couldn't delete plan.",
delete: "Delete",
confirmDelete: "Delete plan \"{{name}}\"? This removes all weeks and materials.",
emptyTitle: "No course plans yet",
emptySubtitle:
"Use the AI wizard to generate your first plan — it only takes about a minute.",
open: "Open",
backToList: "Back to course plans",
noDescription: "No description.",
weeksCount_one: "{{count}} week",
weeksCount_other: "{{count}} weeks",
materialsCount_one: "{{count}} material",
materialsCount_other: "{{count}} materials",
hoursPerWeek: "{{count}} hrs/week",
weekN: "Week {{n}}",
generateMaterials: "Generate Week materials (AI)",
regenerateMaterials: "Regenerate Week materials",
generating: "Generating…",
generateHint:
"AI will produce a reading text, listening script, speaking prompts, writing prompt, grammar mini-lesson and vocabulary for this week.",
weekMaterialsGenerated: "Week materials generated.",
weekMaterialsFailed: "Couldn't generate week materials.",
generateSuccess: "Course plan generated.",
generateFailed: "Couldn't generate course plan.",
deliveryHint:
"Expand any week to view the planned outcomes and generate ready-to-use teaching materials.",
status: {
draft: "Draft",
generated: "Generated",
approved: "Approved",
archived: "Archived",
},
sections: {
objectives: "Course objectives",
outcomes: "Learning outcomes by skill",
grammar: "Grammar scope",
assessment: "Assessment",
resources: "Resources",
delivery: "Weekly delivery plan",
},
skill: {
reading: "Reading",
writing: "Writing",
listening: "Listening",
speaking: "Speaking",
grammar: "Grammar",
vocabulary: "Vocabulary",
integrated: "Integrated",
},
materialType: {
reading_text: "Reading text",
listening_script: "Listening script",
speaking_prompt: "Speaking prompt",
writing_prompt: "Writing prompt",
grammar_lesson: "Grammar lesson",
vocabulary_list: "Vocabulary list",
practice: "Practice",
other: "Material",
},
table: {
skill: "Skill",
outcomes: "Outcomes",
remarks: "Remarks",
},
wizard: {
title: "Generate a course plan",
subtitle:
"Describe the course once. The AI writes the full outline — objectives, outcomes, grammar, weekly plan — and you can generate Week 1 teaching material in one click afterwards.",
finish: "Generate plan",
reviewHint:
"Click Generate plan to start the AI. This usually takes 3060 seconds; you'll land on the plan page once it's done.",
steps: {
basics: "Basics",
basicsDesc: "Name the course and set level, duration, and weekly hours.",
coverage: "Coverage",
coverageDesc: "Tell the AI how hours split across skills and who the learners are.",
scope: "Scope",
scopeDesc: "Optional: grammar focus, resources to reference, free-form notes.",
review: "Review",
reviewDesc: "Double-check your brief before kicking off the generation.",
},
fields: {
title: "Course title",
cefr: "CEFR level",
cefrPlaceholder: "Pick a level",
totalWeeks: "Total weeks",
contactHours: "Contact hours / week",
skillsDivision: "Skills division",
skillsDivisionHint:
"Free-form — e.g. \"10 hrs/wk Reading & Writing + 8 hrs/wk Listening & Speaking\". Leave blank to let the AI decide.",
learnerProfile: "Learner profile",
learnerProfilePlaceholder:
"Who are the learners? Age range, L1, prior study, goals…",
grammarFocus: "Grammar focus (press Enter to add)",
grammarFocusPlaceholder: "e.g. present simple",
resources: "Resources to reference (press Enter to add)",
resourcesPlaceholder: "e.g. Pathways 1 (National Geographic)",
notes: "Additional notes",
notesPlaceholder: "Anything else the AI should know.",
},
errors: {
titleRequired: "Please enter a course title.",
cefrRequired: "Please pick a CEFR level.",
weeksRange: "Total weeks must be at least 1.",
},
},
},
aiAdmin: {
title: "AI Agents & Tools",
subtitle:
"Configure the LangGraph-backed agents that power course planning, exam generation, exercise generation, the LMS tutor, and grading. Defaults are pre-seeded and ready to use.",
tabs: {
agents: "Agents",
tools: "Tools",
prompts: "Prompts",
},
},
agents: {
list: {
title: "Agents",
subtitle: "Pre-configured for every platform pillar — edit defaults below.",
search: "Search agents…",
empty: "No agents match your search.",
},
detail: {
configure: "Configure",
empty: "Select an agent to inspect its configuration.",
graph: "Graph",
model: "Model",
temperature: "Temperature",
tokens: "Max tokens",
format: "Output format",
fallback: "Fallback",
revisions: "Max revisions",
promptKey: "Prompt key",
toolsTitle: "Enabled tools",
noTools: "This agent has no tools enabled.",
systemPrompt: "System prompt",
noPrompt: "(empty)",
},
config: {
title: "Configure",
saved: "Agent configuration saved",
name: "Display name",
promptKey: "Prompt key (versioned)",
description: "Description",
systemPrompt: "System prompt",
systemPromptHint:
"If a prompt key is set above, the active version of that prompt overrides this field at runtime.",
model: "Model",
fallbackModel: "Fallback model",
responseFormat: "Output format",
text: "Text",
temperature: "Temperature",
maxTokens: "Max tokens",
maxRevisions: "Max revisions",
graphType: "Graph topology",
qualityChecks: "Quality checks (comma-separated tool keys)",
tools: "Enabled tools",
mutates: "writes",
active: "Agent is active",
},
test: {
title: "Test runner",
subtitle:
"Send a small payload and inspect the agent's output, tool calls, and quality issues.",
variables: "Variables (JSON)",
payload: "Payload (text or JSON)",
payloadPlaceholder:
"What should the agent do? e.g. 'Generate 5 MCQ for B1 reading.'",
run: "Run agent",
running: "Running…",
ok: "Agent ran successfully",
output: "Output",
toolTrace: "Tool trace",
iterations: "Iterations",
revisions: "Revisions",
toolCalls: "Tool calls",
retrievalHits: "Retrieval hits",
qualityIssues: "Quality issues",
badVarsJson: "Variables must be valid JSON.",
},
graph: {
simple: "Simple",
planReviewRevise: "Plan • Review • Revise",
rag: "RAG",
react: "ReAct (tool-calling)",
},
},
tools: {
title: "Agent tools",
subtitle:
"Capabilities your agents can call. Toggle a tool off to take it out of every agent without editing each one.",
search: "Search tools…",
empty: "No tools match your search.",
writes: "writes",
toggle: {
enabled: "Tool enabled",
disabled: "Tool disabled",
},
col: {
key: "Key",
name: "Name",
category: "Category",
description: "Description",
params: "Params",
active: "Active",
},
},
};
export default en;