Public Access
Add internationalization support with English and Dutch translations
- Integrated i18next for language detection and translation support. - Added English and Dutch JSON translation files for various app sections. - Updated TweaksPanel and Workspace components to use translated strings. - Imported i18n configuration in main entry file.
This commit is contained in:
1 parent
c64cdcd9e3
commit
6277826472
19 files changed
+1193
-369
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import * as examApi from '../api/examApi'
|
||||
|
||||
interface SavedExam {
|
||||
@@ -12,6 +13,7 @@ interface SavedExam {
|
||||
}
|
||||
|
||||
export default function MyExams() {
|
||||
const { t } = useTranslation()
|
||||
const navigate = useNavigate()
|
||||
const [exams, setExams] = useState<SavedExam[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
@@ -58,11 +60,11 @@ export default function MyExams() {
|
||||
<div className="workspace-section fade-in">
|
||||
<div className="workspace-section-header">
|
||||
<div>
|
||||
<div className="workspace-section-eyebrow">My Workspace</div>
|
||||
<h2 className="workspace-section-title">My Exams</h2>
|
||||
<div className="workspace-section-eyebrow">{t('workspace.myWorkspace')}</div>
|
||||
<h2 className="workspace-section-title">{t('workspace.myExams')}</h2>
|
||||
</div>
|
||||
<button className="btn btn-primary btn-sm" onClick={createNewExam}>
|
||||
+ New Exam
|
||||
+ {t('workspace.newExam')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -74,16 +76,16 @@ export default function MyExams() {
|
||||
)}
|
||||
|
||||
{loading ? (
|
||||
<div className="workspace-empty">Loading…</div>
|
||||
<div className="workspace-empty">{t('common.loading')}</div>
|
||||
) : exams.length === 0 ? (
|
||||
<div className="workspace-empty">
|
||||
<div className="workspace-empty-icon">◇</div>
|
||||
<div className="workspace-empty-title">No saved exams yet</div>
|
||||
<div className="workspace-empty-title">{t('workspace.noSavedExams')}</div>
|
||||
<div className="workspace-empty-desc">
|
||||
Upload an exam from the home page, or create a new one to get started.
|
||||
{t('workspace.noSavedExamsDesc')}
|
||||
</div>
|
||||
<button className="btn btn-primary" onClick={createNewExam} style={{ marginTop: 16 }}>
|
||||
Create Your First Exam
|
||||
{t('workspace.createFirstExam')}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
@@ -96,9 +98,9 @@ export default function MyExams() {
|
||||
<div className="workspace-card-sub">{exam.subtitle}</div>
|
||||
)}
|
||||
<div className="workspace-card-meta">
|
||||
<span>{exam.question_count} question{exam.question_count !== 1 ? 's' : ''}</span>
|
||||
<span>{exam.question_count} {exam.question_count === 1 ? t('common.question') : t('common.questions')}</span>
|
||||
<span>·</span>
|
||||
<span>Updated {formatDate(exam.updated_at)}</span>
|
||||
<span>{t('workspace.updated')} {formatDate(exam.updated_at)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="workspace-card-actions">
|
||||
@@ -106,22 +108,22 @@ export default function MyExams() {
|
||||
className="btn btn-sm"
|
||||
onClick={() => navigate(`/exam-editor/${exam.id}`)}
|
||||
>
|
||||
Edit
|
||||
{t('common.edit')}
|
||||
</button>
|
||||
{deleteConfirm === exam.id ? (
|
||||
<div className="workspace-delete-confirm">
|
||||
<button className="btn btn-sm admin-btn-danger" onClick={() => void deleteExam(exam.id)}>
|
||||
Confirm
|
||||
{t('common.confirm')}
|
||||
</button>
|
||||
<button className="btn btn-ghost btn-sm" onClick={() => setDeleteConfirm(null)}>
|
||||
Cancel
|
||||
{t('common.cancel')}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
className="btn btn-ghost btn-sm admin-btn-danger-ghost"
|
||||
onClick={() => setDeleteConfirm(exam.id)}
|
||||
title="Delete exam"
|
||||
title={t('common.delete')}
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
Reference in new issue
Block a user