feat(VocabLessonView, localization): add vocabulary review feature and update translations
All checks were successful
Deploy to production / deploy (push) Successful in 1m55s

- Implemented a new vocabulary review section in VocabLessonView to display the last incorrect answer, including the asked vocabulary, user answer, and correct answer.
- Added localization strings for the new review feature in Cebuano, German, English, Spanish, and French, enhancing user experience across multiple languages.
- Updated the UI to visually differentiate the review section, improving clarity and usability during vocabulary training sessions.
This commit is contained in:
Torsten Schulz (local)
2026-04-20 09:39:48 +02:00
parent dee4991be7
commit 5f13583e41
6 changed files with 75 additions and 0 deletions

View File

@@ -594,6 +594,9 @@
"checkAnswer": "Susihi Answer",
"correct": "Tama!",
"wrong": "Sayop",
"trainerWrongReviewTitle": "Tan-awa pag-usab",
"trainerAskedVocab": "Gipangutana",
"trainerYourAnswer": "Imong answer",
"explanation": "Pasabot",
"learn": "Learn",
"exercises": "Tsek sa kapitulo",

View File

@@ -576,6 +576,9 @@
"checkAnswer": "Antwort prüfen",
"correct": "Richtig!",
"wrong": "Falsch",
"trainerWrongReviewTitle": "Noch einmal ansehen",
"trainerAskedVocab": "Abgefragt",
"trainerYourAnswer": "Deine Antwort",
"explanation": "Erklärung",
"learn": "Lernen",
"exercises": "Kapitel-Prüfung",

View File

@@ -576,6 +576,9 @@
"checkAnswer": "Check Answer",
"correct": "Correct!",
"wrong": "Wrong",
"trainerWrongReviewTitle": "Review this again",
"trainerAskedVocab": "Asked",
"trainerYourAnswer": "Your answer",
"explanation": "Explanation",
"learn": "Learn",
"exercises": "Chapter Test",

View File

@@ -560,6 +560,9 @@
"checkAnswer": "Comprobar respuesta",
"correct": "¡Correcto!",
"wrong": "Incorrecto",
"trainerWrongReviewTitle": "Repasar de nuevo",
"trainerAskedVocab": "Preguntado",
"trainerYourAnswer": "Tu respuesta",
"explanation": "Explicación",
"learn": "Aprender",
"exercises": "Prueba del capítulo",

View File

@@ -560,6 +560,9 @@
"checkAnswer": "Vérifier la réponse",
"correct": "Correct!",
"wrong": "Incorrect",
"trainerWrongReviewTitle": "À revoir",
"trainerAskedVocab": "Demandé",
"trainerYourAnswer": "Votre réponse",
"explanation": "Explication",
"learn": "Apprendre",
"exercises": "Examen de chapitre",

View File

@@ -320,6 +320,23 @@
{{ $t('socialnetwork.vocab.courses.checkAnswer') }}
</button>
</div>
<div v-if="vocabTrainerLastWrongReview" class="vocab-wrong-review">
<strong>{{ $t('socialnetwork.vocab.courses.trainerWrongReviewTitle') }}</strong>
<dl>
<div>
<dt>{{ $t('socialnetwork.vocab.courses.trainerAskedVocab') }}</dt>
<dd>{{ vocabTrainerLastWrongReview.prompt }}</dd>
</div>
<div>
<dt>{{ $t('socialnetwork.vocab.courses.trainerYourAnswer') }}</dt>
<dd>{{ vocabTrainerLastWrongReview.userAnswer }}</dd>
</div>
<div>
<dt>{{ $t('socialnetwork.vocab.courses.correctAnswer') }}</dt>
<dd>{{ vocabTrainerLastWrongReview.answer }}</dd>
</div>
</dl>
</div>
<!-- "Weiter"-Button nur bei falscher Antwort (bei richtiger Antwort wird automatisch weiter gemacht) -->
<div v-if="vocabTrainerMode === 'multiple_choice' && vocabTrainerAnswered && !vocabTrainerLastCorrect" class="vocab-next">
<button @click="continueAfterVocabAnswer">{{ $t('socialnetwork.vocab.courses.next') }}</button>
@@ -1085,6 +1102,7 @@ export default {
vocabTrainerAnswered: false,
vocabTrainerLastCorrect: false,
vocabTrainerContinueTimer: null,
vocabTrainerLastWrongReview: null,
vocabTrainerDirection: 'L2R', // L2R: learning->reference, R2L: reference->learning
isCheckingLessonCompletion: false, // Flag um Endlosschleife zu verhindern
isNavigatingToNext: false, // Flag um mehrfache Navigation zu verhindern
@@ -3351,6 +3369,7 @@ export default {
this.vocabTrainerReviewAttempts = 0;
this.vocabTrainerStats = {};
this.vocabTrainerRepeatQueue = [];
this.vocabTrainerLastWrongReview = null;
// Bereite Mixed-Pool aus alten Vokabeln vor (ohne Duplikate aus aktueller Lektion)
this.vocabTrainerMixedPool = this._buildMixedPool();
this.vocabTrainerPhase = 'current';
@@ -3377,6 +3396,7 @@ export default {
this.vocabTrainerAnswer = '';
this.vocabTrainerSelectedChoice = null;
this.vocabTrainerAnswered = false;
this.vocabTrainerLastWrongReview = null;
},
/** Erstellt den Mixed-Pool aus vorherigen Lektions-Vokabeln (ohne Duplikate der aktuellen Lektion) */
_buildMixedPool() {
@@ -3945,10 +3965,16 @@ export default {
}
if (this.vocabTrainerLastCorrect) {
this.vocabTrainerLastWrongReview = null;
this.vocabTrainerCorrect++;
stats.correct++;
this.resolveRepeatedVocab(this.currentVocabQuestion.vocab);
} else {
this.vocabTrainerLastWrongReview = {
prompt: this.currentVocabQuestion.prompt,
userAnswer,
answer: this.currentVocabQuestion.answer
};
this.vocabTrainerWrong++;
stats.wrong++;
this.queueFailedVocab(this.currentVocabQuestion.vocab);
@@ -5537,6 +5563,40 @@ export default {
border: 1px solid #f5c6cb;
}
.vocab-wrong-review {
margin: 12px 0 15px;
padding: 14px 16px;
border: 1px solid #ef9a9a;
border-radius: 6px;
background: #fff1f1;
color: #4a1f1f;
}
.vocab-wrong-review strong {
display: block;
margin-bottom: 10px;
}
.vocab-wrong-review dl {
display: grid;
gap: 8px;
margin: 0;
}
.vocab-wrong-review dl > div {
display: grid;
grid-template-columns: minmax(120px, 0.3fr) 1fr;
gap: 10px;
}
.vocab-wrong-review dt {
font-weight: 700;
}
.vocab-wrong-review dd {
margin: 0;
}
.vocab-next {
margin-top: 15px;
}