diff --git a/backend/scripts/bisaya-course-phase5-extension.js b/backend/scripts/bisaya-course-phase5-extension.js index 4b19099..7183f81 100644 --- a/backend/scripts/bisaya-course-phase5-extension.js +++ b/backend/scripts/bisaya-course-phase5-extension.js @@ -52,7 +52,12 @@ export const BISAYA_PHASE5_DIDACTICS = { 'Nahe Bedeutungen in stabilere Antworten überführen.', 'Häufige Stolperstellen transparent machen.' ], - corePatterns: ['Palangga taka.', 'Mingaw ko nimo.', 'Magpahuway sa.', 'Andam na ka?'] + corePatterns: [ + { target: 'Palangga taka.', gloss: 'Ich hab dich lieb.' }, + { target: 'Mingaw ko nimo.', gloss: 'Ich vermisse dich.' }, + { target: 'Magpahuway sa.', gloss: 'Ruh dich aus.' }, + { target: 'Andam na ka?', gloss: 'Bist du fertig?' } + ] }, 'Freies Erzählen - Mein Alltag': { learningGoals: [ diff --git a/backend/scripts/update-food-care-exercises.js b/backend/scripts/update-food-care-exercises.js index a97d7d1..3355c6a 100755 --- a/backend/scripts/update-food-care-exercises.js +++ b/backend/scripts/update-food-care-exercises.js @@ -652,23 +652,43 @@ async function updateFoodCareExercises() { totalExercisesCreated++; } } else if (lesson.title === 'Essen & Trinken') { - // Vokabular-Übungen für "Essen & Trinken" - for (const vocab of conversations) { - // Multiple Choice: Muttersprache -> Bisaya + // Vokabular: keine strikte Paarung Deutsch→Bisaya direkt gefolgt von Rückrichtung (vermeidet Verräter-Effekt). + const n = conversations.length; + const offset = Math.max(1, Math.floor(n / 2)); + const revIdx = (i) => (i + offset) % Math.max(n, 1); + + const pickOtherBisaya = (correct, start) => { + for (let t = 1; t <= n; t++) { + const o = conversations[(start + t) % n]?.bisaya; + if (o && o !== correct) return o; + } + return 'Salamat'; + }; + const pickOtherNative = (correct, start) => { + for (let t = 1; t <= n; t++) { + const o = conversations[(start + t) % n]?.native; + if (o && o !== correct) return o; + } + return 'Danke'; + }; + + for (let i = 0; i < n; i++) { + const vocab = conversations[i]; await VocabGrammarExercise.create({ lessonId: lesson.id, - exerciseTypeId: 2, // multiple_choice + exerciseTypeId: 2, exerciseNumber: exerciseNumber++, title: `Wie sagt man "${vocab.native}"?`, instruction: 'Wähle die richtige Übersetzung.', questionData: JSON.stringify({ type: 'multiple_choice', + answerLanguage: 'target', question: `Wie sagt man "${vocab.native}" auf Bisaya?`, options: [ vocab.bisaya, - conversations[(exerciseNumber - 2 + 1) % conversations.length]?.bisaya || 'Salamat', - conversations[(exerciseNumber - 2 + 2) % conversations.length]?.bisaya || 'Maayo', - conversations[(exerciseNumber - 2 + 3) % conversations.length]?.bisaya || 'Palihug' + pickOtherBisaya(vocab.bisaya, i), + pickOtherBisaya(vocab.bisaya, i + 3), + pickOtherBisaya(vocab.bisaya, i + 6) ] }), answerData: JSON.stringify({ @@ -679,22 +699,25 @@ async function updateFoodCareExercises() { createdByUserId: course.owner_user_id || systemUser.id }); totalExercisesCreated++; + } - // Multiple Choice: Bisaya -> Muttersprache + for (let i = 0; i < n; i++) { + const vocab = conversations[revIdx(i)]; await VocabGrammarExercise.create({ lessonId: lesson.id, - exerciseTypeId: 2, // multiple_choice + exerciseTypeId: 2, exerciseNumber: exerciseNumber++, title: `Was bedeutet "${vocab.bisaya}"?`, instruction: 'Wähle die richtige Übersetzung.', questionData: JSON.stringify({ type: 'multiple_choice', + answerLanguage: 'native', question: `Was bedeutet "${vocab.bisaya}"?`, options: [ vocab.native, - conversations[(exerciseNumber - 3 + 1) % conversations.length]?.native || 'Danke', - conversations[(exerciseNumber - 3 + 2) % conversations.length]?.native || 'Bitte', - conversations[(exerciseNumber - 3 + 3) % conversations.length]?.native || 'Gut' + pickOtherNative(vocab.native, i), + pickOtherNative(vocab.native, i + 4), + pickOtherNative(vocab.native, i + 8) ] }), answerData: JSON.stringify({ @@ -706,6 +729,31 @@ async function updateFoodCareExercises() { }); totalExercisesCreated++; } + + for (let i = 0; i < n; i++) { + const vocab = conversations[i]; + await VocabGrammarExercise.create({ + lessonId: lesson.id, + exerciseTypeId: 4, + exerciseNumber: exerciseNumber++, + title: `Tippe auf Bisaya: "${vocab.native}"`, + instruction: 'Übersetze das Wort (Schreibtest).', + questionData: JSON.stringify({ + type: 'transformation', + text: vocab.native, + sourceLanguage: nativeLangName, + targetLanguage: 'Bisaya' + }), + answerData: JSON.stringify({ + type: 'transformation', + correct: vocab.bisaya, + alternatives: [] + }), + explanation: vocab.explanation, + createdByUserId: course.owner_user_id || systemUser.id + }); + totalExercisesCreated++; + } } } diff --git a/frontend/src/i18n/locales/de/socialnetwork.json b/frontend/src/i18n/locales/de/socialnetwork.json index 130bf6b..d6548b0 100644 --- a/frontend/src/i18n/locales/de/socialnetwork.json +++ b/frontend/src/i18n/locales/de/socialnetwork.json @@ -517,6 +517,12 @@ "exerciseProgressLabel": "Fortschritt", "exerciseTargetLabel": "Benötigt", "exerciseCardLabel": "Aufgabe {number}", + "exerciseSequentialProgress": "Frage {current} von {total}", + "exerciseSequentialBack": "Zurück", + "exerciseSequentialNext": "Weiter", + "exerciseWrongTitle": "Noch nicht richtig", + "exerciseReinforcementGoPractice": "Zum Üben wechseln", + "exerciseReinforcementStay": "Bei der Prüfung bleiben", "exerciseStatusOpen": "Offen", "exerciseStatusCorrect": "Erledigt", "exerciseStatusRetry": "Nochmal prüfen", @@ -548,6 +554,8 @@ "vocabPrepTitle": "Vorbereitung vor dem Vokabeltrainer", "vocabPrepStep1": "Lies Kernmuster und Wortliste (Deutsch ↔ Zielsprache) einmal in Ruhe durch.", "vocabPrepProgress": "Durchgang {pass}: Begriff {current} von {total}", + "vocabPrepTargetLabel": "Zielsprache", + "vocabPrepGlossLabel": "Deutsch", "vocabPrepNextItem": "Nächster Begriff", "vocabPrepConfirm1": "Erste Durchsicht erledigt", "vocabPrepStep2": "Gehe die gleichen Begriffe noch einmal durch (aktive Wiederholung, ohne zu üben).", diff --git a/frontend/src/i18n/locales/en/socialnetwork.json b/frontend/src/i18n/locales/en/socialnetwork.json index aafad72..b4cf391 100644 --- a/frontend/src/i18n/locales/en/socialnetwork.json +++ b/frontend/src/i18n/locales/en/socialnetwork.json @@ -517,6 +517,12 @@ "exerciseProgressLabel": "Progress", "exerciseTargetLabel": "Required", "exerciseCardLabel": "Task {number}", + "exerciseSequentialProgress": "Question {current} of {total}", + "exerciseSequentialBack": "Back", + "exerciseSequentialNext": "Next", + "exerciseWrongTitle": "Not quite right", + "exerciseReinforcementGoPractice": "Go to practice", + "exerciseReinforcementStay": "Stay on the test", "exerciseStatusOpen": "Open", "exerciseStatusCorrect": "Done", "exerciseStatusRetry": "Try again", @@ -548,6 +554,8 @@ "vocabPrepTitle": "Preparation before the vocabulary trainer", "vocabPrepStep1": "Read through core patterns and the word list (native language ↔ target language) once.", "vocabPrepProgress": "Pass {pass}: item {current} of {total}", + "vocabPrepTargetLabel": "Target language", + "vocabPrepGlossLabel": "Meaning", "vocabPrepNextItem": "Next item", "vocabPrepConfirm1": "First pass done", "vocabPrepStep2": "Go through the same items again (active review, not testing yet).", diff --git a/frontend/src/i18n/locales/es/socialnetwork.json b/frontend/src/i18n/locales/es/socialnetwork.json index 0a387de..90628e1 100644 --- a/frontend/src/i18n/locales/es/socialnetwork.json +++ b/frontend/src/i18n/locales/es/socialnetwork.json @@ -515,6 +515,12 @@ "exerciseProgressLabel": "Progreso", "exerciseTargetLabel": "Necesario", "exerciseCardLabel": "Tarea {number}", + "exerciseSequentialProgress": "Pregunta {current} de {total}", + "exerciseSequentialBack": "Atrás", + "exerciseSequentialNext": "Siguiente", + "exerciseWrongTitle": "Aún no es correcto", + "exerciseReinforcementGoPractice": "Ir a practicar", + "exerciseReinforcementStay": "Seguir en la prueba", "exerciseStatusOpen": "Pendiente", "exerciseStatusCorrect": "Hecha", "exerciseStatusRetry": "Revisar otra vez", @@ -546,6 +552,8 @@ "vocabPrepTitle": "Preparación antes del entrenador de vocabulario", "vocabPrepStep1": "Lee una vez los patrones clave y la lista de palabras (idioma nativo ↔ lengua meta).", "vocabPrepProgress": "Pasada {pass}: término {current} de {total}", + "vocabPrepTargetLabel": "Lengua meta", + "vocabPrepGlossLabel": "Significado", "vocabPrepNextItem": "Siguiente término", "vocabPrepConfirm1": "Primera lectura hecha", "vocabPrepStep2": "Repasa los mismos elementos otra vez (repaso activo, aún sin practicar).", diff --git a/frontend/src/views/social/VocabLessonView.vue b/frontend/src/views/social/VocabLessonView.vue index 2a7c781..6cd71f2 100644 --- a/frontend/src/views/social/VocabLessonView.vue +++ b/frontend/src/views/social/VocabLessonView.vue @@ -125,8 +125,14 @@ : $t('socialnetwork.vocab.courses.vocabPrepStep2') }}