- Replaced static family vocabulary exercises with a dynamic structure that generates exercises based on native language input, enhancing adaptability for different languages. - Introduced a mapping for family words and their translations, allowing for a more comprehensive and organized approach to exercise creation. - Updated logging to include native language context during exercise generation, improving clarity for developers and users. - Streamlined the gap fill and transformation exercises to ensure accurate and relevant content for learners.
294 lines
8.4 KiB
JavaScript
Executable File
294 lines
8.4 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
/**
|
|
* Script zum Aktualisieren der "Familienwörter"-Übungen in Bisaya-Kursen
|
|
*
|
|
* Verwendung:
|
|
* node backend/scripts/update-family-words-exercises.js
|
|
*
|
|
* Ersetzt bestehende Dummy-Übungen durch spezifische Familienwörter-Übungen.
|
|
*/
|
|
|
|
import { sequelize } from '../utils/sequelize.js';
|
|
import VocabCourseLesson from '../models/community/vocab_course_lesson.js';
|
|
import VocabGrammarExercise from '../models/community/vocab_grammar_exercise.js';
|
|
import VocabCourse from '../models/community/vocab_course.js';
|
|
import User from '../models/community/user.js';
|
|
|
|
// Familienwörter-Übersetzungen in verschiedene Muttersprachen
|
|
const FAMILY_WORDS = {
|
|
Mutter: {
|
|
de: 'Mutter',
|
|
en: 'Mother',
|
|
es: 'Madre',
|
|
fr: 'Mère',
|
|
it: 'Madre',
|
|
pt: 'Mãe'
|
|
},
|
|
Vater: {
|
|
de: 'Vater',
|
|
en: 'Father',
|
|
es: 'Padre',
|
|
fr: 'Père',
|
|
it: 'Padre',
|
|
pt: 'Pai'
|
|
},
|
|
'älterer Bruder': {
|
|
de: 'älterer Bruder',
|
|
en: 'older brother',
|
|
es: 'hermano mayor',
|
|
fr: 'frère aîné',
|
|
it: 'fratello maggiore',
|
|
pt: 'irmão mais velho'
|
|
},
|
|
'ältere Schwester': {
|
|
de: 'ältere Schwester',
|
|
en: 'older sister',
|
|
es: 'hermana mayor',
|
|
fr: 'sœur aînée',
|
|
it: 'sorella maggiore',
|
|
pt: 'irmã mais velha'
|
|
},
|
|
Großmutter: {
|
|
de: 'Großmutter',
|
|
en: 'Grandmother',
|
|
es: 'Abuela',
|
|
fr: 'Grand-mère',
|
|
it: 'Nonna',
|
|
pt: 'Avó'
|
|
},
|
|
Großvater: {
|
|
de: 'Großvater',
|
|
en: 'Grandfather',
|
|
es: 'Abuelo',
|
|
fr: 'Grand-père',
|
|
it: 'Nonno',
|
|
pt: 'Avô'
|
|
}
|
|
};
|
|
|
|
// Bisaya-Übersetzungen
|
|
const BISAYA_TRANSLATIONS = {
|
|
'Mutter': 'Nanay',
|
|
'Vater': 'Tatay',
|
|
'älterer Bruder': 'Kuya',
|
|
'ältere Schwester': 'Ate',
|
|
'Großmutter': 'Lola',
|
|
'Großvater': 'Lolo'
|
|
};
|
|
|
|
// Sprach-Codes für Mapping
|
|
const LANGUAGE_CODES = {
|
|
'Deutsch': 'de',
|
|
'English': 'en',
|
|
'Español': 'es',
|
|
'Français': 'fr',
|
|
'Italiano': 'it',
|
|
'Português': 'pt',
|
|
'Spanish': 'es',
|
|
'French': 'fr',
|
|
'Italian': 'it',
|
|
'Portuguese': 'pt'
|
|
};
|
|
|
|
// Erstelle Übungen basierend auf Muttersprache
|
|
function createFamilyWordsExercises(nativeLanguageName) {
|
|
const langCode = LANGUAGE_CODES[nativeLanguageName] || 'de'; // Fallback zu Deutsch
|
|
|
|
const exercises = [];
|
|
|
|
// Multiple Choice Übungen für jedes Familienwort
|
|
const familyWords = Object.keys(FAMILY_WORDS);
|
|
const bisayaWords = ['Nanay', 'Tatay', 'Kuya', 'Ate', 'Lola', 'Lolo'];
|
|
|
|
familyWords.forEach((key, index) => {
|
|
const nativeWord = FAMILY_WORDS[key][langCode];
|
|
const bisayaWord = BISAYA_TRANSLATIONS[key];
|
|
|
|
// Erstelle Multiple Choice mit falschen Antworten
|
|
const wrongAnswers = bisayaWords.filter(w => w !== bisayaWord);
|
|
const shuffledWrong = wrongAnswers.sort(() => Math.random() - 0.5).slice(0, 3);
|
|
const options = [bisayaWord, ...shuffledWrong].sort(() => Math.random() - 0.5);
|
|
const correctIndex = options.indexOf(bisayaWord);
|
|
|
|
exercises.push({
|
|
exerciseTypeId: 2, // multiple_choice
|
|
title: `Wie sagt man "${nativeWord}" auf Bisaya?`,
|
|
instruction: 'Wähle die richtige Übersetzung.',
|
|
questionData: {
|
|
type: 'multiple_choice',
|
|
question: `Wie sagt man "${nativeWord}" auf Bisaya?`,
|
|
options: options
|
|
},
|
|
answerData: {
|
|
type: 'multiple_choice',
|
|
correctAnswer: correctIndex
|
|
},
|
|
explanation: `"${bisayaWord}" bedeutet "${nativeWord}" auf Bisaya.`
|
|
});
|
|
});
|
|
|
|
// Gap Fill Übung
|
|
const nativeWords = familyWords.map(key => FAMILY_WORDS[key][langCode]);
|
|
exercises.push({
|
|
exerciseTypeId: 1, // gap_fill
|
|
title: 'Familienwörter vervollständigen',
|
|
instruction: `Fülle die Lücken mit den richtigen Bisaya-Familienwörtern.`,
|
|
questionData: {
|
|
type: 'gap_fill',
|
|
text: familyWords.map((key, i) => `{gap} (${nativeWords[i]})`).join(' | '),
|
|
gaps: familyWords.length
|
|
},
|
|
answerData: {
|
|
type: 'gap_fill',
|
|
answers: bisayaWords
|
|
},
|
|
explanation: bisayaWords.map((bw, i) => `${bw} = ${nativeWords[i]}`).join(', ') + '.'
|
|
});
|
|
|
|
// Transformation Übung
|
|
exercises.push({
|
|
exerciseTypeId: 4, // transformation
|
|
title: 'Familienwörter übersetzen',
|
|
instruction: `Übersetze das Familienwort ins Bisaya.`,
|
|
questionData: {
|
|
type: 'transformation',
|
|
text: nativeWords[0], // Erste Muttersprache als Beispiel
|
|
sourceLanguage: nativeLanguageName || 'Deutsch',
|
|
targetLanguage: 'Bisaya'
|
|
},
|
|
answerData: {
|
|
type: 'transformation',
|
|
correct: bisayaWords[0],
|
|
alternatives: [bisayaWords[0]] // Nur die korrekte Antwort
|
|
},
|
|
explanation: `"${bisayaWords[0]}" bedeutet "${nativeWords[0]}" auf Bisaya.`
|
|
});
|
|
|
|
return exercises;
|
|
}
|
|
|
|
async function findOrCreateSystemUser() {
|
|
let systemUser = await User.findOne({
|
|
where: {
|
|
username: 'system'
|
|
}
|
|
});
|
|
|
|
if (!systemUser) {
|
|
systemUser = await User.findOne({
|
|
where: {
|
|
username: 'admin'
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!systemUser) {
|
|
console.error('❌ System-Benutzer nicht gefunden.');
|
|
throw new Error('System user not found');
|
|
}
|
|
|
|
return systemUser;
|
|
}
|
|
|
|
async function updateFamilyWordsExercises() {
|
|
await sequelize.authenticate();
|
|
console.log('Datenbankverbindung erfolgreich hergestellt.\n');
|
|
|
|
const systemUser = await findOrCreateSystemUser();
|
|
console.log(`Verwende System-Benutzer: ${systemUser.username} (ID: ${systemUser.id})\n`);
|
|
|
|
// Finde alle Bisaya-Kurse
|
|
const [bisayaLanguage] = await sequelize.query(
|
|
`SELECT id FROM community.vocab_language WHERE name = 'Bisaya' LIMIT 1`,
|
|
{
|
|
type: sequelize.QueryTypes.SELECT
|
|
}
|
|
);
|
|
|
|
if (!bisayaLanguage) {
|
|
console.error('❌ Bisaya-Sprache nicht gefunden.');
|
|
return;
|
|
}
|
|
|
|
const courses = await sequelize.query(
|
|
`SELECT c.id, c.title, c.owner_user_id, c.native_language_id, nl.name as native_language_name
|
|
FROM community.vocab_course c
|
|
LEFT JOIN community.vocab_language nl ON c.native_language_id = nl.id
|
|
WHERE c.language_id = :languageId`,
|
|
{
|
|
replacements: { languageId: bisayaLanguage.id },
|
|
type: sequelize.QueryTypes.SELECT
|
|
}
|
|
);
|
|
|
|
console.log(`Gefunden: ${courses.length} Bisaya-Kurse\n`);
|
|
|
|
let totalExercisesUpdated = 0;
|
|
let totalLessonsUpdated = 0;
|
|
|
|
for (const course of courses) {
|
|
const nativeLangName = course.native_language_name || 'Deutsch'; // Fallback zu Deutsch
|
|
console.log(`📚 Kurs: ${course.title} (ID: ${course.id}, Muttersprache: ${nativeLangName})`);
|
|
|
|
// Erstelle Übungen für diese Muttersprache
|
|
const exercises = createFamilyWordsExercises(nativeLangName);
|
|
|
|
// Finde "Familienwörter"-Lektionen
|
|
const lessons = await VocabCourseLesson.findAll({
|
|
where: {
|
|
courseId: course.id,
|
|
title: 'Familienwörter'
|
|
},
|
|
order: [['lessonNumber', 'ASC']]
|
|
});
|
|
|
|
console.log(` ${lessons.length} "Familienwörter"-Lektionen gefunden\n`);
|
|
|
|
for (const lesson of lessons) {
|
|
// Lösche bestehende Übungen (inkl. Dummy-Übungen)
|
|
const deletedCount = await VocabGrammarExercise.destroy({
|
|
where: { lessonId: lesson.id }
|
|
});
|
|
|
|
console.log(` 🗑️ Lektion ${lesson.lessonNumber}: "${lesson.title}" - ${deletedCount} alte Übung(en) gelöscht`);
|
|
|
|
// Erstelle neue Übungen
|
|
let exerciseNumber = 1;
|
|
for (const exerciseData of exercises) {
|
|
await VocabGrammarExercise.create({
|
|
lessonId: lesson.id,
|
|
exerciseTypeId: exerciseData.exerciseTypeId,
|
|
exerciseNumber: exerciseNumber++,
|
|
title: exerciseData.title,
|
|
instruction: exerciseData.instruction,
|
|
questionData: JSON.stringify(exerciseData.questionData),
|
|
answerData: JSON.stringify(exerciseData.answerData),
|
|
explanation: exerciseData.explanation,
|
|
createdByUserId: course.owner_user_id || systemUser.id
|
|
});
|
|
totalExercisesUpdated++;
|
|
}
|
|
|
|
console.log(` ✅ Lektion ${lesson.lessonNumber}: "${lesson.title}" - ${exercises.length} neue Übung(en) erstellt (${nativeLangName} → Bisaya)`);
|
|
totalLessonsUpdated++;
|
|
}
|
|
|
|
console.log('');
|
|
}
|
|
|
|
console.log(`\n🎉 Zusammenfassung:`);
|
|
console.log(` ${totalLessonsUpdated} Lektionen aktualisiert`);
|
|
console.log(` ${totalExercisesUpdated} neue Grammatik-Übungen erstellt`);
|
|
}
|
|
|
|
updateFamilyWordsExercises()
|
|
.then(() => {
|
|
sequelize.close();
|
|
process.exit(0);
|
|
})
|
|
.catch((error) => {
|
|
console.error('❌ Fehler:', error);
|
|
sequelize.close();
|
|
process.exit(1);
|
|
});
|