feat(shared): add UI components, hooks, form fields, and action utils

- Add UI components: confirm-delete-dialog, empty-table-row, list-pagination, pagination, status-badge

- Add form-fields directory for reusable form field components

- Add hooks: use-action-mutation, use-action-query for server action integration

- Add action-utils lib for action state helpers

- Update a11y components, charts, global-search, onboarding-gate, question components

- Update UI components: chip-nav, filter-bar, page-header, stat-card, stat-item, switch, table

- Update hooks: use-action-with-toast, use-aria-live, use-debounce, use-local-storage, use-media-query, use-permission

- Update lib: a11y, ai, audit-logger, auth-guard, bcrypt-utils, change-logger, download, excel, file-storage, http-utils, login-logger, password-policy, password-security-service, permissions, rate-limit, role-utils, search-params, session, storage-provider

- Update types: action-state, permissions

- Update i18n messages (en, zh-CN) for dashboard, diagnostic, grades, lesson-preparation, settings
This commit is contained in:
SpecialX
2026-06-23 17:38:14 +08:00
parent 9ceb2b7b67
commit c4d3433cc9
25 changed files with 1986 additions and 28 deletions

View File

@@ -46,7 +46,13 @@
"publishedAndOngoing": "Published and ongoing",
"submissionRate": "Submission Rate",
"overallCompletionRate": "Overall completion rate",
"acrossRecentAssignments": "Across recent assignments"
"acrossRecentAssignments": "Across recent assignments",
"textbooks": "Textbooks",
"chapters": "Chapters",
"questions": "Questions",
"exams": "Exams",
"totalAssignments": "Total assignments",
"totalSubmissions": "Total submissions"
},
"quickActions": {
"importUsers": "Import Users",

View File

@@ -34,9 +34,17 @@
"chart": {
"radarTitle": "Knowledge Point Mastery",
"radarDescription": "Radar chart of mastery level (student vs class average)",
"radarDescriptionNonEmpty": "Radar chart of mastery level (0-100) across knowledge points.",
"heatmapTitle": "Knowledge Point Mastery Heatmap",
"rankingTitle": "Knowledge Point Ranking",
"noMasteryData": "No knowledge point mastery records found."
"noMasteryData": "No knowledge point mastery records found.",
"noMasteryDataForStudent": "No knowledge point mastery records found for this student.",
"radarEmptyTitle": "No mastery data",
"radarAriaLabelEmpty": "Knowledge point mastery radar chart: no data",
"radarAriaLabelNonEmpty": "Knowledge point mastery radar chart: {count} knowledge points{withClassAverage}",
"withClassAverage": " (with class average comparison)",
"studentSeries": "Student",
"classAvgSeries": "Class Avg"
},
"report": {
"generate": "Generate Diagnostic Report",
@@ -44,6 +52,7 @@
"generateClass": "Generate Class Diagnostic Report",
"publish": "Publish",
"delete": "Delete",
"export": "Export",
"publishTitle": "Publish Report",
"publishConfirmation": "Are you sure you want to publish this report? It will be visible to relevant users.",
"deleteTitle": "Delete Report",
@@ -82,6 +91,99 @@
"publishFailed": "Failed to publish",
"deleteFailed": "Failed to delete",
"loadFailed": "Failed to load",
"exportFailed": "Export failed",
"retry": "Retry"
},
"classDiagnostic": {
"noClassDataTitle": "No class data",
"heatmapDescription": "Average mastery level per knowledge point (green >=80%, yellow 60-79%, orange 40-59%, red <40%).",
"noKnowledgePointData": "No knowledge point data available.",
"heatmapAriaLabel": "Knowledge point mastery heatmap, {count} knowledge points. Color indicates mastery level: green >=80% excellent, yellow 60-79% good, orange 40-59% needs improvement, red <40% weak",
"masteryLevelExcellent": "Excellent",
"masteryLevelGood": "Good",
"masteryLevelNeedsImprovement": "Needs Improvement",
"masteryLevelWeak": "Weak",
"legendLabel": "Color Legend",
"noRankingData": "No data.",
"knowledgePointColumn": "Knowledge Point",
"avgMasteryColumn": "Avg Mastery",
"masteredColumn": "Mastered (≥80%)",
"notMasteredColumn": "Not Mastered (<60%)",
"studentsNeedingAttentionTitle": "Students Needing Attention (avg <60%)",
"studentsNeedingAttentionDescription": "Students with low overall mastery.",
"allStudentsAboveThreshold": "All students are above the attention threshold.",
"weakPointsColumn": "Weak Points",
"viewAction": "View",
"viewAriaLabel": "View {studentName}'s diagnostic details",
"filterByKpTitle": "Filter Students by Knowledge Point",
"filterByKpDescription": "Select a knowledge point to view all students' mastery levels for targeted tutoring.",
"kpFilterLabel": "Select knowledge point",
"kpFilterPlaceholder": "Select a knowledge point",
"kpFilterAll": "All knowledge points",
"filtering": "Filtering...",
"totalQuestionsColumn": "Total Questions",
"correctQuestionsColumn": "Correct",
"statusColumn": "Status",
"needsAttention": "Needs Attention",
"mastered": "Mastered",
"noStudentsForKp": "No mastery data available for this knowledge point.",
"generateDescription": "Generate a class-level diagnostic report with aggregated analysis.",
"periodLabel": "Period (YYYY-MM)",
"generating": "Generating...",
"generateButton": "Generate Class Report"
},
"reportList": {
"caption": "Diagnostic reports list",
"typeColumn": "Type",
"studentTargetColumn": "Student / Target",
"periodColumn": "Period",
"scoreColumn": "Score",
"statusColumn": "Status",
"generatedByColumn": "Generated By",
"dateColumn": "Date",
"actionsColumn": "Actions",
"classReportPlaceholder": "(Class report)",
"gradeReportPlaceholder": "(Grade report)",
"noReportsDescription": "Generate diagnostic reports to see them here.",
"publishConfirmation": "Once published, the report will be visible to students. Continue?",
"publishAriaLabel": "Publish report {studentName}",
"deleteAriaLabel": "Delete report {studentName}",
"exportAriaLabel": "Export report {studentName}",
"exportSuccess": "Report exported",
"share": "Share",
"shareAriaLabel": "Share report {studentName}",
"shareTitle": "Share Report",
"shareDescription": "Copy the report link to share with students or parents.",
"shareLinkLabel": "Report Link",
"copyLink": "Copy Link",
"copyLinkSuccess": "Link copied",
"copyLinkFailed": "Failed to copy link",
"shareLinkAriaLabel": "Report share link",
"confidenceColumn": "Confidence",
"confidenceHigh": "High",
"confidenceMedium": "Medium",
"confidenceLow": "Low",
"confidenceInsufficient": "Insufficient Data",
"confidenceHighHint": "Sufficient data, conclusions are reliable",
"confidenceMediumHint": "Limited data, consider with other information",
"confidenceLowHint": "Little data, conclusions are for reference only",
"confidenceAriaLabel": "Data confidence: {level}"
},
"studentDiagnostic": {
"noDataDescription": "Unable to load student mastery data.",
"strengthsDescription": "Knowledge points with high mastery.",
"weaknessesDescription": "Knowledge points needing attention.",
"diagnosticReportTitle": "Diagnostic Report",
"overallLabel": "Overall",
"historyDescription": "Past diagnostic reports (newest first).",
"untitledPeriod": "Untitled period",
"strengthsListAriaLabel": "Strengths knowledge points list",
"weaknessesListAriaLabel": "Weaknesses knowledge points list",
"recommendationsListAriaLabel": "Recommendations list",
"practiceAriaLabel": "Practice knowledge point: {name}",
"noStrengths": "No strengths identified yet.",
"noWeaknesses": "No weaknesses identified.",
"reportMeta": "Period: {period} · Overall: {score}%",
"historyReportMeta": "{date} · Overall: {score}%"
}
}

View File

@@ -30,6 +30,17 @@
},
"list": {
"empty": "No grade records found.",
"caption": "Grade records list",
"deleteAriaLabel": "Delete {studentName}'s {subjectName} grade record",
"editAriaLabel": "Edit {studentName}'s {subjectName} grade record",
"bulkDelete": "Bulk Delete",
"bulkDeleteConfirmation": "Are you sure you want to delete the {count} selected grade record(s)? This action cannot be undone.",
"bulkDeleteSelected": "{count} record(s) selected",
"bulkDeleteSuccess": "Deleted {count} grade record(s)",
"bulkDeleteFailed": "Bulk delete failed",
"selectAll": "Select all",
"selectRow": "Select {name}'s grade record",
"clearSelection": "Clear selection",
"columns": {
"student": "Student",
"class": "Class",
@@ -39,7 +50,8 @@
"type": "Type",
"semester": "Semester",
"recordedBy": "Recorded By",
"date": "Date"
"date": "Date",
"actions": "Actions"
}
},
"form": {
@@ -55,7 +67,9 @@
"fullScore": "Full Score",
"remark": "Remark (optional)",
"remarkPlaceholder": "Notes about this grade...",
"selectPrompt": "Please select class, subject and student"
"selectPrompt": "Please select class, subject and student",
"student": "Student",
"titleLabel": "Title"
},
"delete": {
"title": "Delete Grade Record",
@@ -64,11 +78,63 @@
"cancel": "Cancel",
"deleting": "Deleting..."
},
"edit": {
"title": "Edit Grade Record",
"confirm": "Save Changes",
"saving": "Saving...",
"cancel": "Cancel",
"score": "Score",
"fullScore": "Full Score",
"titleLabel": "Title",
"remark": "Remark (optional)",
"remarkPlaceholder": "Notes about this grade...",
"success": "Grade record updated",
"failed": "Update failed"
},
"export": {
"detail": "Export Grade Details",
"classReport": "Export Class Grade Report",
"success": "Export succeeded",
"failed": "Export failed"
"failed": "Export failed",
"exporting": "Exporting...",
"selectClassFirst": "Please select a class first",
"detailItem": "Grade Details",
"classReportItem": "Class Grade Report",
"defaultLabel": "Export",
"sheets": {
"detail": "Grade Details",
"summary": "Statistics Summary",
"classReport": "{className}_Grade Report"
},
"columns": {
"studentName": "Student Name",
"class": "Class",
"subject": "Subject",
"title": "Title",
"score": "Score",
"fullScore": "Full Score",
"type": "Type",
"semester": "Semester",
"recorder": "Recorder",
"remark": "Remark",
"date": "Date",
"metric": "Metric",
"value": "Value",
"total": "Total",
"average": "Average",
"rank": "Rank"
},
"metrics": {
"average": "Average",
"median": "Median",
"max": "Max",
"min": "Min",
"stdDev": "Std Dev",
"passRate": "Pass Rate (%)",
"excellentRate": "Excellent Rate (%)",
"count": "Count",
"noData": "No Data"
}
},
"stats": {
"title": "Statistics",
@@ -80,7 +146,11 @@
"variance": "Variance",
"passRate": "Pass Rate",
"excellentRate": "Excellent Rate",
"count": "Count"
"count": "Count",
"noData": "No data available for statistics.",
"stdDevHint": "Standard deviation",
"passRateHint": "Score >= 60% of full",
"excellentRateHint": "Score >= 85% of full"
},
"analytics": {
"trend": "Grade Trend",
@@ -95,12 +165,22 @@
"averageScore": "Average score, pass rate, excellent rate",
"passRate": "Pass Rate",
"excellentRate": "Excellent Rate",
"studentCount": "Student Count"
"studentCount": "Student Count",
"classComparisonLabel": "Grade (for class comparison)",
"allOption": "All",
"semester": "Semester",
"semesterAll": "All Semesters",
"semester1": "Semester 1",
"semester2": "Semester 2",
"exam": "Exam",
"examAll": "All Exams",
"noExams": "No linked exams"
},
"batch": {
"title": "Batch Grade Entry",
"saving": "Saving...",
"restored": "Restored unsaved grade draft",
"restoredFromServer": "Restored grade draft from server (cross-device sync)",
"invalidScores": "Invalid scores found",
"fullScoreRequired": "Full score is required",
"saved": "Saved",
@@ -109,7 +189,45 @@
"fullScore": "Full Score",
"type": "Type",
"saveAll": "Save All",
"cancel": "Cancel"
"cancel": "Cancel",
"saveAllGrades": "Save All Grades",
"savingGrades": "Saving grades...",
"selectClassAndSubject": "Please select class and subject",
"invalidScoresError": "Invalid scores found (exceeding full score or wrong format). Please check and retry.",
"enterAtLeastOne": "Please enter at least one score",
"noStudentsInClass": "No students in this class.",
"entered": "Entered",
"average": "Avg",
"max": "Max",
"min": "Min",
"searchStudent": "Search student...",
"examQuizTitle": "Exam / Quiz Title",
"fullScoreHint": "Full score is {max}. Press Enter to move to the next student. Drafts are auto-saved every 30 seconds and valid for 2 hours.",
"confirmSwitchClass": "There are unsaved grade records for the current class. Are you sure you want to switch?",
"invalidScoresBadge": "Invalid scores found",
"emailColumn": "Email",
"pasteApplied": "Pasted {count} scores from clipboard",
"pasteNoMatch": "Clipboard content could not be parsed as a score column",
"pasteHint": "Tip: copy a column of scores from Excel and paste here",
"undo": "Undo",
"undoNoRecord": "No recent batch entry to undo",
"undoExpired": "Undo expired (more than 5 minutes)",
"undoFailed": "Undo failed, please try again",
"downloadTemplate": "Download Template",
"templateAriaLabel": "Download grade entry template",
"templateStudentName": "Student Name",
"templateScore": "Score",
"templateRemark": "Remark",
"templateFilename": "grade-entry-template.csv",
"guide": {
"title": "Grade Entry Guide",
"step1": "Select the class and subject for grade entry, and fill in the exam or quiz title.",
"step2": "Enter scores directly in the score column, or copy a column of scores from Excel and paste here.",
"step3": "Drafts are auto-saved every 30 seconds (2 hours locally, 24 hours on server for cross-device sync).",
"step4": "After saving, you can undo the entry within 5 minutes by clicking the undo button.",
"dismiss": "Got it",
"dismissAriaLabel": "Close entry guide"
}
},
"trend": {
"title": "Grade Trend",
@@ -118,12 +236,20 @@
"date": "Date"
},
"summary": {
"caption": "Student Grade Summary",
"title": "Grade Summary",
"averageScore": "Average Score",
"classRank": "Class Rank",
"rankValue": "#{rank}",
"totalRecords": "Total Records",
"highestScore": "Highest Score",
"lowestScore": "Lowest Score"
"lowestScore": "Lowest Score",
"student": "Student",
"gradeHistory": "Grade History",
"noGradesTitle": "No grades yet",
"noGradesDescription": "There are no grade records for this student.",
"noDataTitle": "No data",
"noDataDescription": "Student grade summary is not available."
},
"empty": {
"noRecords": "No grade records found.",
@@ -139,5 +265,90 @@
"failedToCreate": "Failed to create",
"failedToDelete": "Failed to delete",
"retry": "Retry"
},
"widget": {
"error": "Widget Error",
"retry": "Retry",
"loading": "Loading...",
"block": "Widget",
"loadFailed": "{title} failed to load",
"defaultFallback": "Please retry or refresh the page",
"retryAriaLabel": "Retry loading {title}",
"loadingAriaLabel": "{title} is loading"
},
"chart": {
"scorePercent": "Score (%)",
"students": "Students",
"averagePercent": "Average (%)",
"passRatePercent": "Pass Rate (%)",
"excellentPercent": "Excellent (%)",
"average": "Average",
"passRate": "Pass Rate",
"classAverage": "Class Average"
},
"distribution": {
"title": "Score Distribution",
"descriptionEmpty": "Number of students in each score range (normalized to 0-100).",
"descriptionNonEmpty": "{count} grade record(s) across score ranges.",
"emptyTitle": "No distribution data",
"emptyDescription": "Select a class and subject to view score distribution.",
"ariaLabelEmpty": "Score distribution bar chart: no data",
"ariaLabelNonEmpty": "Score distribution bar chart: {count} grade records across 5 score ranges",
"tooltipStudents": "{count} student(s)",
"tooltipOfTotal": "{percentage}% of total"
},
"subjectComparison": {
"descriptionEmpty": "Compare performance across subjects for the selected class.",
"descriptionNonEmpty": "Average score and pass rate per subject (normalized to 0-100).",
"emptyTitle": "No comparison data",
"emptyDescription": "Select a class to compare subject performance.",
"ariaLabelEmpty": "Subject comparison radar chart: no data",
"ariaLabelNonEmpty": "Subject comparison radar chart: comparing average and pass rate across {count} subjects"
},
"classComparison": {
"descriptionEmpty": "Compare average, pass rate, and excellent rate across classes.",
"descriptionNonEmpty": "Average score, pass rate (>=60%), and excellent rate (>=85%) per class.",
"emptyTitle": "No comparison data",
"emptyDescription": "Select a grade and subject to compare classes.",
"ariaLabelEmpty": "Class comparison bar chart: no data",
"ariaLabelNonEmpty": "Class comparison bar chart: comparing average, pass rate, and excellent rate across {count} classes",
"significanceTitle": "Significance Analysis",
"significanceRange": "Max difference between classes: {range} points",
"significanceHigh": "Significant difference",
"significanceMedium": "Possible difference",
"significanceLow": "No significant difference",
"significanceHighHint": "The range is large and each class has sufficient sample size (>=30), so the performance gap is statistically meaningful.",
"significanceMediumHint": "Some difference exists, but it may be affected by sample size or random fluctuation. Further analysis is recommended.",
"significanceLowHint": "The range is small and class performance is close; the difference is not statistically meaningful.",
"significanceAriaLabel": "Significance analysis: {level}",
"significanceDetails": "View detailed analysis",
"significanceTopClass": "Top class: {name} ({score} points)",
"significanceBottomClass": "Bottom class: {name} ({score} points)"
},
"trendChart": {
"descriptionEmpty": "Score progression over time (normalized to 0-100).",
"descriptionNonEmpty": "{label} · avg {average}%",
"emptyTitle": "No trend data",
"emptyDescription": "Select a class and subject to view the grade trend.",
"ariaLabelEmpty": "Grade trend chart: no data",
"ariaLabelNonEmpty": "Grade trend chart: {label}, average {average}%"
},
"trendCard": {
"emptyDescription": "Your grade trend will appear here once records are added.",
"ariaLabelEmpty": "Grade trend chart: no data",
"ariaLabelNonEmpty": "Grade trend chart: {count} grade records",
"rangeAriaLabel": "Select date range"
},
"rankingTrend": {
"ariaLabelEmpty": "Ranking trend chart: no data",
"ariaLabelNonEmpty": "Ranking trend chart: {count} ranking records"
},
"classReport": {
"noDataTitle": "No data",
"noDataDescription": "No grade records found for this class.",
"classRanking": "Class Ranking",
"rankColumn": "Rank",
"recordsColumn": "Records",
"studentCountInfo": "{studentCount} students · {recordCount} grade records"
}
}

View File

@@ -93,7 +93,34 @@
"unknownBlockType": "Unknown node type",
"nodeSummaryEmpty": "Empty",
"questionCount": "{count} questions",
"charCount": "{count} chars"
"charCount": "{count} chars",
"itemCount": "{count} items",
"pointCount": "{count} points",
"assignmentCount": "{count} assignments",
"durationMin": "{count} min",
"textbookContent": "Textbook Content",
"textbookContentMissing": "Content node missing",
"textbookContentEmpty": "(No content loaded)",
"zoomIn": "Zoom In",
"zoomOut": "Zoom Out",
"rangeAnchorTitle": "Link selection to a node",
"pointAnchorTitle": "Insert placeholder {number} here",
"anchorToSelectedNode": "Link to selected node",
"anchorToNewNode": "Link to a new node"
},
"picker": {
"textbookLabel": "Select Textbook",
"chapterLabel": "Select Chapter",
"selectTextbook": "Select a textbook...",
"selectChapter": "Select a chapter...",
"selectTextbookFirst": "Please select a textbook first",
"loadingTextbooks": "Loading textbooks...",
"loadingChapters": "Loading chapters...",
"noTextbooks": "No textbooks available. Please create one in the textbook module first",
"noChapters": "No chapters in this textbook",
"selectedChapter": "Selected: {chapter}",
"skeletonHint": "A lesson skeleton centered on the textbook content will be generated (10 teaching nodes)",
"errorTextbookChapterRequired": "Please select a textbook and chapter"
},
"filters": {
"searchPlaceholder": "Search title...",
@@ -126,13 +153,15 @@
"linked": "Linked to {count} knowledge points",
"annotate": "Annotate Knowledge Points",
"select": "Select Knowledge Points",
"selected": "{count} selected"
"selected": "{count} selected",
"loading": "Loading..."
},
"questionBank": {
"title": "Select Questions from Bank",
"add": "Add",
"insert": "Insert",
"selected": "{count} questions selected",
"loading": "Loading...",
"source": {
"bank": "Bank",
"inline": "New"

View File

@@ -11,6 +11,18 @@
"profile": {
"title": "Profile Information",
"description": "Update your personal information.",
"avatar": {
"upload": "Upload Avatar",
"remove": "Remove",
"hint": "Supports JPG, PNG, WebP, GIF. Max 2MB.",
"uploadSuccess": "Avatar updated successfully",
"uploadFailure": "Failed to upload avatar",
"removeSuccess": "Avatar removed",
"removeFailure": "Failed to remove avatar",
"invalidType": "Only JPG, PNG, WebP, and GIF formats are supported",
"tooLarge": "File size must not exceed 2MB",
"tooLongName": "Filename is too long, please rename it (max 255 characters)"
},
"fields": {
"name": "Full Name",
"namePlaceholder": "Your name",
@@ -68,7 +80,10 @@
"save": "Save Preferences",
"saving": "Saving...",
"success": "Preferences updated",
"failure": "Failed to update preferences"
"failure": "Failed to update preferences",
"test": "Test",
"testSuccess": "Test notification sent",
"testFailure": "Failed to send test notification"
},
"appearance": {
"theme": {
@@ -120,6 +135,63 @@
"tip2": "Avoid common words, names, or sequential patterns.",
"tip3": "Change your password periodically.",
"tip4": "Your account will be temporarily locked after multiple failed login attempts."
},
"center": {
"title": "Security Center",
"description": "Manage two-factor authentication and review login activity.",
"twoFactor": {
"title": "Two-Factor Authentication (2FA)",
"description": "When enabled, login requires a one-time code from your authenticator app.",
"enabled": "Enabled",
"hint": "Enabling 2FA significantly improves account security and prevents unauthorized access from leaked passwords.",
"enable": "Enable",
"disable": "Disable",
"enableSuccess": "Two-factor authentication enabled",
"disableSuccess": "Two-factor authentication disabled",
"toggleFailure": "Operation failed, please try again later",
"setupFailure": "Failed to generate QR code, please try again later",
"verifyFailure": "Verification failed, please try again later",
"disableFailure": "Failed to disable 2FA, please try again later",
"regenerateFailure": "Failed to regenerate backup codes, please try again later",
"regenerateSuccess": "Backup codes regenerated",
"invalidCode": "Invalid verification code, please try again",
"scanQr": "Scan the QR code above with your authenticator app (e.g. Google Authenticator, Microsoft Authenticator)",
"manualEntry": "Can't scan? Enter this key manually",
"enterCode": "Enter the 6-digit code from your authenticator",
"enterCodeDisable": "Enter a one-time code or backup code to confirm disabling 2FA",
"enterCodeRegen": "Enter your current one-time code to regenerate backup codes",
"verify": "Verify & Enable",
"cancel": "Cancel",
"done": "Done",
"backupCodes": "Backup Codes",
"backupHint": "Used to recover your account when you can't access your authenticator",
"backupRemaining": "{count} backup codes remaining",
"backupWarning": "Save these backup codes securely. Each code can only be used once. Lost codes cannot be recovered, only regenerated.",
"copy": "Copy all",
"copied": "Copied",
"regenerate": "Regenerate",
"disableTitle": "Disable Two-Factor Authentication",
"disableDescription": "After disabling, login will no longer require a one-time code. To confirm this is you, please enter your current one-time code or a backup code.",
"regenerateTitle": "Regenerate Backup Codes",
"regenerateDescription": "This will invalidate all old backup codes and generate 10 new ones. Please enter your current one-time code to confirm."
},
"recentLogins": {
"title": "Recent Logins",
"showingLatest": "Latest {count} records",
"empty": "No login records",
"failed": "Failed",
"current": "Current session",
"revokeAll": "Sign out all other sessions",
"revoking": "Processing...",
"revokeSuccess": "Revoked {count} session(s)",
"revokeSuccessEmpty": "No other active sessions to revoke",
"revokeFailure": "Failed to revoke sessions, please try again later",
"actions": {
"signin": "Sign in",
"signout": "Sign out",
"signup": "Sign up"
}
}
}
},
"ai": {

View File

@@ -46,7 +46,13 @@
"publishedAndOngoing": "已发布且进行中",
"submissionRate": "提交率",
"overallCompletionRate": "总体完成率",
"acrossRecentAssignments": "近期作业平均"
"acrossRecentAssignments": "近期作业平均",
"textbooks": "教材数",
"chapters": "章节数",
"questions": "题目数",
"exams": "考试数",
"totalAssignments": "作业总数",
"totalSubmissions": "提交总数"
},
"quickActions": {
"importUsers": "批量导入用户",

View File

@@ -34,9 +34,17 @@
"chart": {
"radarTitle": "知识点掌握度",
"radarDescription": "掌握度雷达图(学生 vs 班级平均)",
"radarDescriptionNonEmpty": "各知识点掌握度0-100雷达图。",
"heatmapTitle": "知识点掌握度热力图",
"rankingTitle": "知识点排名",
"noMasteryData": "暂无知识点掌握度记录"
"noMasteryData": "暂无知识点掌握度记录",
"noMasteryDataForStudent": "暂无该学生的知识点掌握度记录。",
"radarEmptyTitle": "暂无掌握度数据",
"radarAriaLabelEmpty": "知识点掌握度雷达图:暂无数据",
"radarAriaLabelNonEmpty": "知识点掌握度雷达图:共 {count} 个知识点的掌握度{withClassAverage}",
"withClassAverage": "(含班级平均对比)",
"studentSeries": "学生",
"classAvgSeries": "班级平均"
},
"report": {
"generate": "生成诊断报告",
@@ -44,6 +52,7 @@
"generateClass": "生成班级诊断报告",
"publish": "发布",
"delete": "删除",
"export": "导出",
"publishTitle": "发布报告",
"publishConfirmation": "确定要发布此报告吗?发布后将对相关人员可见。",
"deleteTitle": "删除报告",
@@ -82,6 +91,99 @@
"publishFailed": "发布失败",
"deleteFailed": "删除失败",
"loadFailed": "加载失败",
"exportFailed": "导出失败",
"retry": "重试"
},
"classDiagnostic": {
"noClassDataTitle": "暂无班级数据",
"heatmapDescription": "各知识点平均掌握度绿色≥80%优秀黄色60-79%良好橙色40-59%待提升,红色<40%薄弱)。",
"noKnowledgePointData": "暂无知识点数据。",
"heatmapAriaLabel": "知识点掌握度热力图,共 {count} 个知识点颜色表示掌握度等级绿色≥80%优秀黄色60-79%良好橙色40-59%待提升,红色<40%薄弱",
"masteryLevelExcellent": "优秀",
"masteryLevelGood": "良好",
"masteryLevelNeedsImprovement": "待提升",
"masteryLevelWeak": "薄弱",
"legendLabel": "颜色图例",
"noRankingData": "暂无数据。",
"knowledgePointColumn": "知识点",
"avgMasteryColumn": "平均掌握度",
"masteredColumn": "已掌握≥80%",
"notMasteredColumn": "未掌握(<60%",
"studentsNeedingAttentionTitle": "需重点关注的学生(平均<60%",
"studentsNeedingAttentionDescription": "掌握度较低的学生。",
"allStudentsAboveThreshold": "所有学生的掌握度均高于关注阈值。",
"weakPointsColumn": "薄弱点",
"viewAction": "查看",
"viewAriaLabel": "查看 {studentName} 的诊断详情",
"filterByKpTitle": "按知识点筛选学生",
"filterByKpDescription": "选择知识点查看班级所有学生在此知识点上的掌握度,便于针对性辅导。",
"kpFilterLabel": "选择知识点",
"kpFilterPlaceholder": "请选择知识点",
"kpFilterAll": "全部知识点",
"filtering": "筛选中...",
"totalQuestionsColumn": "总题数",
"correctQuestionsColumn": "正确数",
"statusColumn": "状态",
"needsAttention": "需关注",
"mastered": "已掌握",
"noStudentsForKp": "该知识点暂无学生掌握度数据。",
"generateDescription": "生成包含汇总分析的班级诊断报告。",
"periodLabel": "周期YYYY-MM",
"generating": "生成中...",
"generateButton": "生成班级报告"
},
"reportList": {
"caption": "学情诊断报告列表",
"typeColumn": "类型",
"studentTargetColumn": "学生 / 目标",
"periodColumn": "周期",
"scoreColumn": "得分",
"statusColumn": "状态",
"generatedByColumn": "生成者",
"dateColumn": "日期",
"actionsColumn": "操作",
"classReportPlaceholder": "(班级报告)",
"gradeReportPlaceholder": "(年级报告)",
"noReportsDescription": "生成诊断报告后将显示在此处。",
"publishConfirmation": "发布后报告将对相关学生可见。确定要发布吗?",
"publishAriaLabel": "发布报告 {studentName}",
"deleteAriaLabel": "删除报告 {studentName}",
"exportAriaLabel": "导出报告 {studentName}",
"exportSuccess": "报告已导出",
"share": "分享",
"shareAriaLabel": "分享报告 {studentName}",
"shareTitle": "分享报告",
"shareDescription": "复制报告链接分享给学生或家长。",
"shareLinkLabel": "报告链接",
"copyLink": "复制链接",
"copyLinkSuccess": "链接已复制",
"copyLinkFailed": "复制链接失败",
"shareLinkAriaLabel": "报告分享链接",
"confidenceColumn": "置信度",
"confidenceHigh": "高",
"confidenceMedium": "中",
"confidenceLow": "低",
"confidenceInsufficient": "数据不足",
"confidenceHighHint": "数据充足,报告结论可靠",
"confidenceMediumHint": "数据量一般,建议结合其他信息参考",
"confidenceLowHint": "数据量较少,结论仅供参考",
"confidenceAriaLabel": "数据置信度:{level}"
},
"studentDiagnostic": {
"noDataDescription": "无法加载学生掌握度数据。",
"strengthsDescription": "掌握度较高的知识点。",
"weaknessesDescription": "需要关注的知识点。",
"diagnosticReportTitle": "诊断报告",
"overallLabel": "总体",
"historyDescription": "历史诊断报告(按时间倒序)。",
"untitledPeriod": "未命名周期",
"strengthsListAriaLabel": "优势知识点列表",
"weaknessesListAriaLabel": "薄弱知识点列表",
"recommendationsListAriaLabel": "学习建议列表",
"practiceAriaLabel": "练习知识点:{name}",
"noStrengths": "暂无强项知识点。",
"noWeaknesses": "暂无弱项知识点。",
"reportMeta": "周期:{period} · 总体:{score}%",
"historyReportMeta": "{date} · 总体:{score}%"
}
}

View File

@@ -30,6 +30,17 @@
},
"list": {
"empty": "暂无成绩记录",
"caption": "成绩记录列表",
"deleteAriaLabel": "删除 {studentName} 的 {subjectName} 成绩记录",
"editAriaLabel": "编辑 {studentName} 的 {subjectName} 成绩记录",
"bulkDelete": "批量删除",
"bulkDeleteConfirmation": "确定要删除选中的 {count} 条成绩记录吗?此操作不可撤销。",
"bulkDeleteSelected": "已选中 {count} 条记录",
"bulkDeleteSuccess": "已删除 {count} 条成绩记录",
"bulkDeleteFailed": "批量删除失败",
"selectAll": "全选",
"selectRow": "选择 {name} 的成绩记录",
"clearSelection": "取消选择",
"columns": {
"student": "学生",
"class": "班级",
@@ -39,7 +50,8 @@
"type": "类型",
"semester": "学期",
"recordedBy": "录入人",
"date": "日期"
"date": "日期",
"actions": "操作"
}
},
"form": {
@@ -55,7 +67,9 @@
"fullScore": "满分",
"remark": "备注(可选)",
"remarkPlaceholder": "关于此成绩的备注...",
"selectPrompt": "请选择班级、科目和学生"
"selectPrompt": "请选择班级、科目和学生",
"student": "学生",
"titleLabel": "标题"
},
"delete": {
"title": "删除成绩记录",
@@ -64,11 +78,63 @@
"cancel": "取消",
"deleting": "删除中..."
},
"edit": {
"title": "编辑成绩记录",
"confirm": "保存修改",
"saving": "保存中...",
"cancel": "取消",
"score": "分数",
"fullScore": "满分",
"titleLabel": "标题",
"remark": "备注(可选)",
"remarkPlaceholder": "关于此成绩的备注...",
"success": "成绩记录已更新",
"failed": "更新失败"
},
"export": {
"detail": "导出成绩明细",
"classReport": "导出班级成绩总表",
"success": "导出成功",
"failed": "导出失败"
"failed": "导出失败",
"exporting": "导出中...",
"selectClassFirst": "请先选择班级",
"detailItem": "成绩明细",
"classReportItem": "班级成绩总表",
"defaultLabel": "导出",
"sheets": {
"detail": "成绩明细",
"summary": "统计汇总",
"classReport": "{className}_成绩总表"
},
"columns": {
"studentName": "学生姓名",
"class": "班级",
"subject": "科目",
"title": "标题",
"score": "分数",
"fullScore": "满分",
"type": "类型",
"semester": "学期",
"recorder": "录入人",
"remark": "备注",
"date": "录入日期",
"metric": "指标",
"value": "数值",
"total": "总分",
"average": "平均分",
"rank": "排名"
},
"metrics": {
"average": "均分",
"median": "中位数",
"max": "最高分",
"min": "最低分",
"stdDev": "标准差",
"passRate": "及格率(%)",
"excellentRate": "优秀率(%)",
"count": "参考人数",
"noData": "无数据"
}
},
"stats": {
"title": "统计",
@@ -80,7 +146,11 @@
"variance": "方差",
"passRate": "及格率",
"excellentRate": "优秀率",
"count": "人数"
"count": "人数",
"noData": "暂无统计数据。",
"stdDevHint": "标准差",
"passRateHint": "分数 ≥ 满分的 60%",
"excellentRateHint": "分数 ≥ 满分的 85%"
},
"analytics": {
"trend": "成绩趋势",
@@ -95,12 +165,22 @@
"averageScore": "平均分",
"passRate": "及格率",
"excellentRate": "优秀率",
"studentCount": "学生数"
"studentCount": "学生数",
"classComparisonLabel": "年级(用于班级对比)",
"allOption": "全部",
"semester": "学期",
"semesterAll": "全部学期",
"semester1": "第一学期",
"semester2": "第二学期",
"exam": "考试",
"examAll": "全部考试",
"noExams": "暂无关联考试"
},
"batch": {
"title": "批量录入",
"saving": "保存中...",
"restored": "已恢复未保存的成绩草稿",
"restoredFromServer": "已从服务端恢复成绩草稿(跨设备同步)",
"invalidScores": "存在无效分数",
"fullScoreRequired": "满分必填",
"saved": "已录入",
@@ -109,7 +189,45 @@
"fullScore": "满分",
"type": "类型",
"saveAll": "全部保存",
"cancel": "取消"
"cancel": "取消",
"saveAllGrades": "保存全部成绩",
"savingGrades": "保存成绩中...",
"selectClassAndSubject": "请选择班级和科目",
"invalidScoresError": "存在无效分数(超过满分或格式错误),请检查后重试",
"enterAtLeastOne": "请至少输入一个分数",
"noStudentsInClass": "该班级暂无学生。",
"entered": "已录入",
"average": "均分",
"max": "最高",
"min": "最低",
"searchStudent": "搜索学生...",
"examQuizTitle": "考试 / 测验标题",
"fullScoreHint": "满分 {max} 分。输入分数后按 Enter 跳到下一位学生。草稿每 30 秒自动保存2 小时内有效。",
"confirmSwitchClass": "当前班级有未保存的成绩记录,确认切换班级?",
"invalidScoresBadge": "存在无效分数",
"emailColumn": "邮箱",
"pasteApplied": "已从剪贴板粘贴 {count} 个分数",
"pasteNoMatch": "剪贴板内容无法识别为分数列",
"pasteHint": "提示:可从 Excel 复制一列分数粘贴到此处",
"undo": "撤销",
"undoNoRecord": "无可撤销的录入记录",
"undoExpired": "撤销已过期(超过 5 分钟)",
"undoFailed": "撤销失败,请重试",
"downloadTemplate": "下载模板",
"templateAriaLabel": "下载成绩录入模板",
"templateStudentName": "学生姓名",
"templateScore": "分数",
"templateRemark": "备注",
"templateFilename": "成绩录入模板.csv",
"guide": {
"title": "成绩录入指引",
"step1": "选择要录入成绩的班级和科目,填写考试或测验标题。",
"step2": "在分数列直接输入成绩,也可从 Excel 复制一列分数粘贴到此处。",
"step3": "系统每 30 秒自动保存草稿(本地 2 小时有效,服务端 24 小时跨设备同步)。",
"step4": "保存成功后可在 5 分钟内点击撤销按钮撤销本次录入。",
"dismiss": "知道了",
"dismissAriaLabel": "关闭录入指引"
}
},
"trend": {
"title": "成绩趋势",
@@ -118,12 +236,20 @@
"date": "日期"
},
"summary": {
"caption": "学生成绩汇总",
"title": "成绩摘要",
"averageScore": "平均分",
"classRank": "班级排名",
"rankValue": "第 {rank} 名",
"totalRecords": "总记录数",
"highestScore": "最高分",
"lowestScore": "最低分"
"lowestScore": "最低分",
"student": "学生",
"gradeHistory": "成绩历史",
"noGradesTitle": "暂无成绩",
"noGradesDescription": "该学生暂无成绩记录。",
"noDataTitle": "暂无数据",
"noDataDescription": "学生成绩摘要不可用。"
},
"empty": {
"noRecords": "暂无成绩记录",
@@ -139,5 +265,90 @@
"failedToCreate": "创建失败",
"failedToDelete": "删除失败",
"retry": "重试"
},
"widget": {
"error": "组件加载失败",
"retry": "重试",
"loading": "加载中...",
"block": "区块",
"loadFailed": "{title}加载失败",
"defaultFallback": "请重试或刷新页面",
"retryAriaLabel": "重试加载{title}",
"loadingAriaLabel": "{title}加载中"
},
"chart": {
"scorePercent": "分数 (%)",
"students": "学生数",
"averagePercent": "平均分 (%)",
"passRatePercent": "及格率 (%)",
"excellentPercent": "优秀率 (%)",
"average": "平均分",
"passRate": "及格率",
"classAverage": "班级平均"
},
"distribution": {
"title": "分数分布",
"descriptionEmpty": "每个分数区间内的学生人数(标准化为 0-100。",
"descriptionNonEmpty": "{count} 条成绩记录分布在各分数区间。",
"emptyTitle": "暂无分布数据",
"emptyDescription": "请选择班级和科目查看分数分布。",
"ariaLabelEmpty": "分数分布柱状图:暂无数据",
"ariaLabelNonEmpty": "分数分布柱状图:共 {count} 条成绩记录分布在 5 个分数区间",
"tooltipStudents": "{count} 名学生",
"tooltipOfTotal": "占总数的 {percentage}%"
},
"subjectComparison": {
"descriptionEmpty": "对比所选班级各科目的表现。",
"descriptionNonEmpty": "各科目的平均分和及格率(标准化为 0-100。",
"emptyTitle": "暂无对比数据",
"emptyDescription": "请选择班级对比科目表现。",
"ariaLabelEmpty": "科目对比雷达图:暂无数据",
"ariaLabelNonEmpty": "科目对比雷达图:共 {count} 个科目的均分与及格率对比"
},
"classComparison": {
"descriptionEmpty": "对比各班级的平均分、及格率和优秀率。",
"descriptionNonEmpty": "各班级的平均分、及格率≥60%和优秀率≥85%)。",
"emptyTitle": "暂无对比数据",
"emptyDescription": "请选择年级和科目对比班级。",
"ariaLabelEmpty": "班级对比柱状图:暂无数据",
"ariaLabelNonEmpty": "班级对比柱状图:共 {count} 个班级的均分、及格率与优秀率对比",
"significanceTitle": "显著性分析",
"significanceRange": "班级间最大差异为 {range} 分",
"significanceHigh": "差异显著",
"significanceMedium": "可能存在差异",
"significanceLow": "差异不显著",
"significanceHighHint": "极差较大且各班样本量充足≥30班级间表现差异具有统计意义。",
"significanceMediumHint": "存在一定差异,但可能受样本量或随机波动影响,建议进一步分析。",
"significanceLowHint": "极差较小,班级间表现接近,差异不具统计意义。",
"significanceAriaLabel": "显著性分析:{level}",
"significanceDetails": "查看详细分析",
"significanceTopClass": "最高分班级:{name}{score} 分)",
"significanceBottomClass": "最低分班级:{name}{score} 分)"
},
"trendChart": {
"descriptionEmpty": "随时间变化的分数趋势(标准化为 0-100。",
"descriptionNonEmpty": "{label} · 平均 {average}%",
"emptyTitle": "暂无趋势数据",
"emptyDescription": "请选择班级和科目查看成绩趋势。",
"ariaLabelEmpty": "成绩趋势图:暂无数据",
"ariaLabelNonEmpty": "成绩趋势图:{label},平均 {average}%"
},
"trendCard": {
"emptyDescription": "添加成绩记录后,成绩趋势将显示在此处。",
"ariaLabelEmpty": "成绩趋势图:暂无数据",
"ariaLabelNonEmpty": "成绩趋势图:共 {count} 次成绩记录",
"rangeAriaLabel": "选择日期范围"
},
"rankingTrend": {
"ariaLabelEmpty": "排名趋势图:暂无数据",
"ariaLabelNonEmpty": "排名趋势图:共 {count} 次排名记录"
},
"classReport": {
"noDataTitle": "暂无数据",
"noDataDescription": "该班级暂无成绩记录。",
"classRanking": "班级排名",
"rankColumn": "排名",
"recordsColumn": "记录数",
"studentCountInfo": "{studentCount} 名学生 · {recordCount} 条成绩记录"
}
}

View File

@@ -93,7 +93,34 @@
"unknownBlockType": "未知节点类型",
"nodeSummaryEmpty": "空",
"questionCount": "{count} 道题",
"charCount": "{count} 字"
"charCount": "{count} 字",
"itemCount": "{count} 项",
"pointCount": "{count} 个要点",
"assignmentCount": "{count} 个作业",
"durationMin": "{count} 分钟",
"textbookContent": "课文正文",
"textbookContentMissing": "正文节点缺失",
"textbookContentEmpty": "(未加载课文内容)",
"zoomIn": "放大",
"zoomOut": "缩小",
"rangeAnchorTitle": "为选中文本关联节点",
"pointAnchorTitle": "在此位置插入占位符 {number}",
"anchorToSelectedNode": "关联到当前选中节点",
"anchorToNewNode": "关联到新节点"
},
"picker": {
"textbookLabel": "选择教材",
"chapterLabel": "选择课文",
"selectTextbook": "请选择教材...",
"selectChapter": "请选择课文...",
"selectTextbookFirst": "请先选择教材",
"loadingTextbooks": "加载教材中...",
"loadingChapters": "加载章节中...",
"noTextbooks": "暂无可用教材,请先在教材模块创建",
"noChapters": "该教材暂无章节",
"selectedChapter": "已选课文:{chapter}",
"skeletonHint": "将自动生成以课文正文为核心的备课骨架(含 10 个教学节点)",
"errorTextbookChapterRequired": "请选择教材和课文"
},
"filters": {
"searchPlaceholder": "搜索标题...",
@@ -126,13 +153,15 @@
"linked": "已关联 {count} 个知识点",
"annotate": "标注知识点",
"select": "选择知识点",
"selected": "已选 {count} 个"
"selected": "已选 {count} 个",
"loading": "加载中..."
},
"questionBank": {
"title": "从题库选择题目",
"add": "添加",
"insert": "插入",
"selected": "已选 {count} 题",
"loading": "加载中...",
"source": {
"bank": "题库",
"inline": "新建"

View File

@@ -11,6 +11,18 @@
"profile": {
"title": "个人信息",
"description": "更新您的个人资料。",
"avatar": {
"upload": "上传头像",
"remove": "移除",
"hint": "支持 JPG、PNG、WebP、GIF最大 2MB",
"uploadSuccess": "头像更新成功",
"uploadFailure": "头像上传失败",
"removeSuccess": "头像已移除",
"removeFailure": "移除头像失败",
"invalidType": "仅支持 JPG、PNG、WebP、GIF 格式",
"tooLarge": "文件大小不能超过 2MB",
"tooLongName": "文件名过长,请重命名后再上传(最多 255 字符)"
},
"fields": {
"name": "姓名",
"namePlaceholder": "您的姓名",
@@ -68,7 +80,10 @@
"save": "保存偏好",
"saving": "保存中...",
"success": "通知偏好已更新",
"failure": "通知偏好更新失败"
"failure": "通知偏好更新失败",
"test": "测试",
"testSuccess": "测试通知已发送",
"testFailure": "测试通知发送失败"
},
"appearance": {
"theme": {
@@ -120,6 +135,63 @@
"tip2": "避免使用常见词汇、姓名或连续模式。",
"tip3": "定期更换密码。",
"tip4": "多次登录失败后账户将被临时锁定。"
},
"center": {
"title": "安全中心",
"description": "管理两步验证和查看登录活动。",
"twoFactor": {
"title": "两步验证2FA",
"description": "启用后,登录时需要输入手机验证器生成的一次性码。",
"enabled": "已启用",
"hint": "启用 2FA 可显著提升账户安全性,防止密码泄露导致的未授权访问。",
"enable": "启用",
"disable": "关闭",
"enableSuccess": "两步验证已启用",
"disableSuccess": "两步验证已关闭",
"toggleFailure": "操作失败,请稍后重试",
"setupFailure": "生成二维码失败,请稍后重试",
"verifyFailure": "验证失败,请稍后重试",
"disableFailure": "关闭失败,请稍后重试",
"regenerateFailure": "重新生成备份码失败,请稍后重试",
"regenerateSuccess": "备份码已重新生成",
"invalidCode": "验证码无效,请重新输入",
"scanQr": "使用验证器 App如 Google Authenticator、Microsoft Authenticator扫描上方二维码",
"manualEntry": "无法扫码?手动输入此密钥",
"enterCode": "输入验证器显示的 6 位数字",
"enterCodeDisable": "输入一次性码或备份码以确认关闭 2FA",
"enterCodeRegen": "输入当前的一次性码以重新生成备份码",
"verify": "验证并启用",
"cancel": "取消",
"done": "完成",
"backupCodes": "备份码",
"backupHint": "无法访问验证器时用于恢复账户",
"backupRemaining": "剩余 {count} 个备份码",
"backupWarning": "请妥善保存这些备份码。每个备份码只能使用一次。丢失后无法找回,只能重新生成。",
"copy": "复制全部",
"copied": "已复制",
"regenerate": "重新生成",
"disableTitle": "关闭两步验证",
"disableDescription": "关闭后,登录将不再需要一次性码。为确认是本人操作,请输入当前的一次性码或备份码。",
"regenerateTitle": "重新生成备份码",
"regenerateDescription": "此操作将使所有旧备份码失效,并生成 10 个新备份码。请输入当前的一次性码以确认。"
},
"recentLogins": {
"title": "最近登录",
"showingLatest": "最近 {count} 条记录",
"empty": "暂无登录记录",
"failed": "失败",
"current": "当前会话",
"revokeAll": "登出所有其他会话",
"revoking": "处理中...",
"revokeSuccess": "已登出 {count} 个会话",
"revokeSuccessEmpty": "无其他活跃会话需要登出",
"revokeFailure": "登出会话失败,请稍后重试",
"actions": {
"signin": "登录",
"signout": "退出",
"signup": "注册"
}
}
}
},
"ai": {