diff --git a/backend/scripts/bisaya-course-phase1.js b/backend/scripts/bisaya-course-phase1.js index fd25254..af29eed 100644 --- a/backend/scripts/bisaya-course-phase1.js +++ b/backend/scripts/bisaya-course-phase1.js @@ -140,5 +140,49 @@ export const BISAYA_DIDACTICS_FRAGMENTS = { text: 'Baue einen Mini-Dialog mit Zielort, Uhrzeit und Rückkehr in mindestens vier Sätzen.' } ] + }, + 'Ort & Richtung': { + learningGoals: [ + 'Fragen nach Ort und Richtung sicher stellen und beantworten.', + '„hier“, „dort“ und „unterwegs nach …“ im Alltag unterscheiden.', + 'Kurze Weg- und Zielangaben mit bekannten Ortswörtern verbinden.' + ], + corePatterns: [ + { target: 'Asa ka?', gloss: 'Wo bist du? / Wohin gehst du?' }, + { target: 'Asa ang merkado?', gloss: 'Wo ist der Markt?' }, + { target: 'Asa ang simbahan?', gloss: 'Wo ist die Kirche?' }, + { target: 'Dinhi ko.', gloss: 'Ich bin hier.' }, + { target: 'Naa ko dinhi.', gloss: 'Ich bin hier.' }, + { target: 'Didto siya.', gloss: 'Er/sie ist dort.' }, + { target: 'Adto ta didto.', gloss: 'Lass uns dorthin gehen.' }, + { target: 'Padulong ko sa merkado.', gloss: 'Ich bin auf dem Weg zum Markt.' }, + { target: 'Padulong ta didto.', gloss: 'Lass uns dorthin aufbrechen.' }, + { target: 'Naa ko sa balay.', gloss: 'Ich bin zu Hause.' } + ], + grammarFocus: [ + { + title: 'Asa = Wo / Wohin', + text: '„Asa“ fragt nach Ort oder Ziel. Mit „ang“ kannst du nach einem bestimmten Ort fragen.', + example: 'Asa ka? Asa ang merkado?' + }, + { + title: 'dinhi / didto', + text: '„dinhi“ = hier, „didto“ = dort (weg vom Sprecher).', + example: 'Naa ko dinhi. Didto ang simbahan.' + } + ], + speakingPrompts: [ + { + title: 'Weg fragen', + prompt: 'Frage, wo der Markt ist, und sage dann, dass du dorthin unterwegs bist.', + cue: 'Asa ang merkado? Padulong ko sa merkado.' + } + ], + practicalTasks: [ + { + title: 'Mini-Route', + text: 'Bilde drei Sätze: wo du bist, wohin du willst, und dass du unterwegs bist.' + } + ] } }; diff --git a/backend/scripts/update-bisaya-didactics.js b/backend/scripts/update-bisaya-didactics.js index 083d519..3c50217 100644 --- a/backend/scripts/update-bisaya-didactics.js +++ b/backend/scripts/update-bisaya-didactics.js @@ -166,6 +166,7 @@ export const LESSON_DIDACTICS = { 'Alltagsgespräche - Teil 1': BISAYA_DIDACTICS_FRAGMENTS['Alltagsgespräche - Teil 1'], 'Haus & Familie': BISAYA_DIDACTICS_FRAGMENTS['Haus & Familie'], 'Alltagsgespräche - Teil 2': BISAYA_DIDACTICS_FRAGMENTS['Alltagsgespräche - Teil 2'], + 'Ort & Richtung': BISAYA_DIDACTICS_FRAGMENTS['Ort & Richtung'], 'Gefühle & Zuneigung': { learningGoals: [ 'Wichtige Gefühle und Zuneigungsformeln sicher unterscheiden.', diff --git a/frontend/src/i18n/locales/de/socialnetwork.json b/frontend/src/i18n/locales/de/socialnetwork.json index a0a5b63..ff5d2b3 100644 --- a/frontend/src/i18n/locales/de/socialnetwork.json +++ b/frontend/src/i18n/locales/de/socialnetwork.json @@ -707,6 +707,8 @@ "quickReviewIntro": "Kurze Session mit {count} Begriffen. Nach Abschluss wird die geplante Wiederholung als erledigt markiert.", "quickReviewDoneTitle": "Geschafft", "quickReviewDoneScore": "Richtig: {correct} / {total}", + "quickReviewNoTermsTitle": "Keine Begriffe für die Kurz-Wiederholung", + "quickReviewNoTermsBody": "Für diese Lektion sind keine Kernmuster (core patterns) hinterlegt oder sie konnten nicht geladen werden. Bitte Kursinhalt aktualisieren (Sync) oder die Lektion in der Vollansicht öffnen — danach sollte die Kurz-Wiederholung wieder funktionieren.", "quickReviewBackToCourse": "Zurück zum Kurs", "quickReviewProgress": "Begriff {current} von {total}", "quickReviewPromptMeaning": "Was bedeutet \"{term}\"?", diff --git a/frontend/src/i18n/locales/en/socialnetwork.json b/frontend/src/i18n/locales/en/socialnetwork.json index a197950..fe32bc7 100644 --- a/frontend/src/i18n/locales/en/socialnetwork.json +++ b/frontend/src/i18n/locales/en/socialnetwork.json @@ -707,6 +707,8 @@ "quickReviewIntro": "Short session with {count} terms. After completion, the scheduled review is marked as done.", "quickReviewDoneTitle": "Done", "quickReviewDoneScore": "Correct: {correct} / {total}", + "quickReviewNoTermsTitle": "No terms for quick review", + "quickReviewNoTermsBody": "This lesson has no core patterns loaded, or they could not be read. Please sync course content or open the full lesson — then quick review should work again.", "quickReviewBackToCourse": "Back to course", "quickReviewProgress": "Term {current} of {total}", "quickReviewPromptMeaning": "What does \"{term}\" mean?", diff --git a/frontend/src/views/social/VocabLessonReviewView.vue b/frontend/src/views/social/VocabLessonReviewView.vue index b9f57cc..120ed1e 100644 --- a/frontend/src/views/social/VocabLessonReviewView.vue +++ b/frontend/src/views/social/VocabLessonReviewView.vue @@ -15,7 +15,13 @@ {{ $t('socialnetwork.vocab.courses.quickReviewIntro', { count: reviewQueue.length }) }}

-
+
+

{{ $t('socialnetwork.vocab.courses.quickReviewNoTermsTitle') }}

+

{{ $t('socialnetwork.vocab.courses.quickReviewNoTermsBody') }}

+ +
+ +

{{ $t('socialnetwork.vocab.courses.quickReviewDoneTitle') }}

{{ $t('socialnetwork.vocab.courses.quickReviewDoneScore', { correct: correctCount, total: reviewQueue.length }) }}

@@ -91,6 +97,8 @@ export default { needsFeedbackAck: false, correctCount: 0, reviewDone: false, + /** Keine Kernmuster geladen — nicht mit normalem Abschluss verwechseln */ + reviewEmptyNoPatterns: false, weakVocabMap: {} }; }, @@ -280,6 +288,7 @@ export default { this.lesson = data; this.reviewQueue = this.buildQueue(); if (this.reviewQueue.length === 0) { + this.reviewEmptyNoPatterns = true; this.reviewDone = true; } else { this.setupCurrent(); diff --git a/frontend/src/views/social/VocabLessonView.vue b/frontend/src/views/social/VocabLessonView.vue index a5e0d45..5b96d35 100644 --- a/frontend/src/views/social/VocabLessonView.vue +++ b/frontend/src/views/social/VocabLessonView.vue @@ -239,10 +239,18 @@ {{ $t('socialnetwork.vocab.courses.mixedReview') }} - + {{ $t('socialnetwork.vocab.courses.modeMultipleChoice') }} - + {{ $t('socialnetwork.vocab.courses.modeTyping') }} @@ -280,7 +288,7 @@
-
+
@@ -3396,9 +3404,9 @@ export default { const isReviewLesson = ['review', 'vocab_review'].includes(lessonType) || ['review', 'vocab_review', 'intensive_review'].includes(didacticMode); const switchAfterAttempts = isReviewLesson - ? Math.max(8, Math.ceil(this.trainerExerciseUnlockAttempts * 0.35)) + ? Math.max(4, Math.ceil(this.trainerExerciseUnlockAttempts * 0.25)) : this.trainerExerciseUnlockAttempts; - const requiredSuccessRate = isReviewLesson ? 75 : 80; + const requiredSuccessRate = isReviewLesson ? 70 : 80; if (this.vocabTrainerMode === 'multiple_choice' && this.vocabTrainerTotalAttempts >= switchAfterAttempts) { const successRate = (this.vocabTrainerCorrect / this.vocabTrainerTotalAttempts) * 100; @@ -3427,6 +3435,15 @@ export default { // Starte neue Frage im Multiple Choice Modus this.nextVocabQuestion(); }, + switchToTyping() { + if (!this.vocabTrainerActive || this.vocabTrainerMode === 'typing') { + return; + } + this.vocabTrainerMode = 'typing'; + this.vocabTrainerAutoSwitchedToTyping = false; + this.vocabTrainerPool = [...this.trainableLessonVocab, ...this.vocabTrainerMixedPool]; + this.nextVocabQuestion(); + }, getEquivalentVocabAnswers(prompt, direction, allVocabs) { const normalizedPrompt = this.normalizeVocab(prompt); const matches = []; @@ -5077,6 +5094,14 @@ export default { color: #6c757d; } +.mode-badge.mode-clickable { + cursor: pointer; +} + +.mode-badge.mode-clickable:hover { + filter: brightness(0.98); +} + .mode-badge.mode-active { background: var(--color-primary); color: #2b1f14;