feat: Erweiterung der Bisaya-Kursinhalte um neue Lektionen und Aktualisierung der Titel in den didaktischen Feldern
All checks were successful
Deploy to production / deploy (push) Successful in 2m11s

This commit is contained in:
Torsten Schulz (local)
2026-05-19 11:04:52 +02:00
parent 3c92e1005a
commit ba70c706c8
3 changed files with 446 additions and 1 deletions

View File

@@ -13,7 +13,7 @@ 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';
import { BISAYA_DIDACTICS_24_43, BISAYA_RELATIONSHIP_ANCHOR_DIDACTICS } from './bisaya-course-plan-24-43.js';
import { BISAYA_DIDACTICS_24_43, BISAYA_LESSONS_24_43_BY_NUMBER, BISAYA_RELATIONSHIP_ANCHOR_DIDACTICS } from './bisaya-course-plan-24-43.js';
import { BISAYA_PHASE3_DIDACTICS, BISAYA_PHASE3_LESSONS } from './bisaya-course-phase3-extension.js';
import { BISAYA_PHASE4_DIDACTICS, BISAYA_PHASE4_LESSONS } from './bisaya-course-phase4-extension.js';
import { BISAYA_PHASE5_DIDACTICS, BISAYA_PHASE5_LESSONS } from './bisaya-course-phase5-extension.js';
@@ -36,6 +36,14 @@ const GENERATED_BISAYA_DIDACTICS = {
const SAFE_EXERCISE_UPDATE_TITLES = new Set([
'Gefühle im Alltag',
'Gefühlswortschatz & Reaktionen',
'Gesundheit & Wohlbefinden',
'Körper & Symptome',
'Höflichkeitsformen praktisch',
'Bitten & Nachfragen',
'Kinder & Familie',
'Körper & Gesundheit',
'Höflichkeitsformen',
'Bitten & Fragen',
...BISAYA_PHASE3_LESSONS.map((lesson) => lesson.title),
...BISAYA_PHASE4_LESSONS.map((lesson) => lesson.title),
...BISAYA_PHASE5_LESSONS.map((lesson) => lesson.title)
@@ -956,6 +964,394 @@ const BISAYA_EXERCISES = {
}
],
// Lektion 26: Gesundheit & Wohlbefinden
'Gesundheit & Wohlbefinden': [
{
exerciseTypeId: 2,
title: 'Beschwerde erkennen',
instruction: 'Wähle die richtige Bedeutung.',
questionData: {
type: 'multiple_choice',
question: 'Was bedeutet "Sakit akong ulo."?',
options: ['Mein Kopf tut weh.', 'Mein Bauch tut weh.', 'Ich habe Fieber.', 'Ich bin müde.']
},
answerData: {
type: 'multiple_choice',
correctAnswer: 0
},
explanation: '"akong ulo" bedeutet "mein Kopf".'
},
{
exerciseTypeId: 1,
title: 'Gesundheitsfrage ergänzen',
instruction: 'Fülle die Lücken mit den passenden Bisaya-Wörtern.',
questionData: {
type: 'gap_fill',
text: 'Sakit imong {gap}? Mas maayo na {gap}?',
gaps: 2
},
answerData: {
type: 'gap_fill',
answers: ['tiyan', 'ka']
},
explanation: '"Sakit imong tiyan?" fragt nach Bauchschmerzen; "ka" bezieht sich auf die andere Person.'
},
{
exerciseTypeId: 4,
title: 'Fürsorge anbieten',
instruction: 'Übersetze ins Bisaya.',
questionData: {
type: 'transformation',
text: 'Ruh dich erst einmal aus. Trink Wasser.',
sourceLanguage: 'Deutsch',
targetLanguage: 'Bisaya'
},
answerData: {
type: 'transformation',
correct: 'Magpahuway sa. Uminom og tubig.',
alternatives: ['Pahuway sa. Uminom og tubig.', 'Magpahuway usa. Uminom og tubig.']
},
explanation: 'Die beiden kurzen Sätze klingen fürsorglich und praktisch.'
},
{
exerciseTypeId: 3,
title: 'Pflege-Mini-Dialog bauen',
instruction: 'Ordne die Sätze zu einem natürlichen Mini-Dialog.',
questionData: {
type: 'sentence_building',
question: 'Baue: Frage nach Schmerz, schlage Ruhe vor, frage nach Medizin.',
tokens: ['Sakit imong ulo?', 'Magpahuway sa.', 'Niinom ka og tambal?']
},
answerData: {
correct: ['Sakit imong ulo? Magpahuway sa. Niinom ka og tambal?']
},
explanation: 'Gesundheitssprache funktioniert gut in kurzen Abfolgen.'
},
{
exerciseTypeId: 10,
title: 'Gesundheitssituation',
instruction: 'Antworte kurz und fürsorglich.',
questionData: {
type: 'situational_response',
question: 'Ein Kind sagt, dass der Kopf weh tut. Frage nach und biete Wasser oder Ruhe an.',
keywords: ['sakit', 'ulo', 'pahuway', 'tubig']
},
answerData: {
modelAnswer: 'Sakit imong ulo? Magpahuway sa. Uminom og tubig.',
keywords: ['sakit', 'ulo', 'pahuway', 'tubig']
},
explanation: 'Die Antwort fragt nach und gibt direkt eine einfache Pflegehandlung.'
}
],
// Lektion 27: Körper & Symptome
'Körper & Symptome': [
{
exerciseTypeId: 2,
title: 'Körperwort erkennen',
instruction: 'Wähle die richtige Bedeutung.',
questionData: {
type: 'multiple_choice',
question: 'Was bedeutet "tiyan"?',
options: ['Bauch', 'Kopf', 'Zahn', 'Husten']
},
answerData: {
type: 'multiple_choice',
correctAnswer: 0
},
explanation: '"tiyan" bedeutet "Bauch".'
},
{
exerciseTypeId: 2,
title: 'Symptom erkennen',
instruction: 'Wähle die richtige Bedeutung.',
questionData: {
type: 'multiple_choice',
question: 'Was bedeutet "hilanat"?',
options: ['Fieber', 'Medizin', 'Schmerz', 'Arzt']
},
answerData: {
type: 'multiple_choice',
correctAnswer: 0
},
explanation: '"hilanat" bedeutet "Fieber".'
},
{
exerciseTypeId: 1,
title: 'Symptom-Satz ergänzen',
instruction: 'Fülle die Lücke.',
questionData: {
type: 'gap_fill',
text: 'Sakit akong {gap}. (Mein Hals tut weh.)',
gaps: 1
},
answerData: {
type: 'gap_fill',
answers: ['tutunlan']
},
explanation: '"tutunlan" bedeutet "Hals / Kehle".'
},
{
exerciseTypeId: 4,
title: 'Nach Medizin fragen',
instruction: 'Übersetze ins Bisaya.',
questionData: {
type: 'transformation',
text: 'Wo ist die Medizin?',
sourceLanguage: 'Deutsch',
targetLanguage: 'Bisaya'
},
answerData: {
type: 'transformation',
correct: 'Asa ang tambal?',
alternatives: ['Hain ang tambal?']
},
explanation: '"tambal" ist das Kernwort für Medizin.'
}
],
// Lektion 28: Höflichkeitsformen praktisch
'Höflichkeitsformen praktisch': [
{
exerciseTypeId: 2,
title: 'Höfliche Bitte erkennen',
instruction: 'Wähle die richtige Bedeutung.',
questionData: {
type: 'multiple_choice',
question: 'Was bedeutet "Pwede ko mangutana?"?',
options: ['Darf ich fragen?', 'Kannst du warten?', 'Schon okay.', 'Danke fürs Verstehen.']
},
answerData: {
type: 'multiple_choice',
correctAnswer: 0
},
explanation: '"Pwede ko mangutana?" ist eine höfliche Erlaubnisfrage.'
},
{
exerciseTypeId: 1,
title: 'Weich ablehnen',
instruction: 'Fülle die Lücken.',
questionData: {
type: 'gap_fill',
text: 'Dili lang sa {gap}. Sunod na {gap}.',
gaps: 2
},
answerData: {
type: 'gap_fill',
answers: ['karon', 'lang']
},
explanation: 'Die Kombination lehnt weich ab und bietet später an.'
},
{
exerciseTypeId: 4,
title: 'Entschuldigung formulieren',
instruction: 'Übersetze ins Bisaya.',
questionData: {
type: 'transformation',
text: 'Entschuldige mich. Bitte wiederhole es.',
sourceLanguage: 'Deutsch',
targetLanguage: 'Bisaya'
},
answerData: {
type: 'transformation',
correct: 'Pasayloa ko. Palihug ka mubalik?',
alternatives: ['Pasayloa ko. Balika palihug.', 'Pasayloa ko. Palihug balika.']
},
explanation: 'Erst entschuldigen, dann höflich um Wiederholung bitten.'
},
{
exerciseTypeId: 10,
title: 'Höflich reagieren',
instruction: 'Antworte weich und höflich.',
questionData: {
type: 'situational_response',
question: 'Du möchtest jetzt lieber nicht. Lehn höflich ab und bedanke dich fürs Verständnis.',
keywords: ['dili', 'karon', 'salamat', 'pagsabot']
},
answerData: {
modelAnswer: 'Dili lang sa karon. Salamat sa pagsabot.',
keywords: ['dili', 'karon', 'salamat', 'pagsabot']
},
explanation: 'Diese Antwort bleibt klar, aber nicht hart.'
},
{
exerciseTypeId: 11,
title: 'Höflichkeitsmuster üben',
instruction: 'Bilde eine höfliche Reparatur in zwei kurzen Sätzen.',
questionData: {
type: 'pattern_drill',
question: 'Entschuldige dich und bitte um Wiederholung.',
pattern: 'Pasayloa ko. ...',
prompt: 'Bitte wiederhole es.'
},
answerData: {
modelAnswer: 'Pasayloa ko. Palihug ka mubalik?',
correct: ['Pasayloa ko. Palihug ka mubalik?', 'Pasayloa ko. Balika palihug.']
},
explanation: 'Das Muster ist besonders nützlich, wenn du etwas nicht verstanden hast.'
}
],
// Lektion 29: Bitten & Nachfragen
'Bitten & Nachfragen': [
{
exerciseTypeId: 2,
title: 'Verständnisproblem erkennen',
instruction: 'Wähle die richtige Bedeutung.',
questionData: {
type: 'multiple_choice',
question: 'Was bedeutet "Wala ko kasabot."?',
options: ['Ich verstehe nicht.', 'Bitte langsam.', 'Hilf mir bitte.', 'Was kommt als Nächstes?']
},
answerData: {
type: 'multiple_choice',
correctAnswer: 0
},
explanation: '"Wala ko kasabot" ist der wichtigste Satz bei Verständnisproblemen.'
},
{
exerciseTypeId: 1,
title: 'Nachfragen ergänzen',
instruction: 'Fülle die Lücken.',
questionData: {
type: 'gap_fill',
text: 'Hinay-hinay {gap}. Unsay pasabot {gap}?',
gaps: 2
},
answerData: {
type: 'gap_fill',
answers: ['lang', 'ani']
},
explanation: 'Damit bittest du um langsamere Sprache und fragst nach Bedeutung.'
},
{
exerciseTypeId: 4,
title: 'Um Hilfe bitten',
instruction: 'Übersetze ins Bisaya.',
questionData: {
type: 'transformation',
text: 'Hilf mir bitte.',
sourceLanguage: 'Deutsch',
targetLanguage: 'Bisaya'
},
answerData: {
type: 'transformation',
correct: 'Tabangi ko, palihug.',
alternatives: ['Tabangi ko palihug.', 'Palihug tabangi ko.']
},
explanation: '"palihug" macht die Bitte höflicher.'
},
{
exerciseTypeId: 3,
title: 'Reparaturdialog bauen',
instruction: 'Ordne die Sätze zu einer sinnvollen Reihenfolge.',
questionData: {
type: 'sentence_building',
question: 'Baue: Nicht verstehen, langsam bitten, Bedeutung fragen.',
tokens: ['Wala ko kasabot.', 'Hinay-hinay lang.', 'Unsay pasabot ani?']
},
answerData: {
correct: ['Wala ko kasabot. Hinay-hinay lang. Unsay pasabot ani?']
},
explanation: 'Diese Reihenfolge löst viele echte Gesprächsprobleme.'
},
{
exerciseTypeId: 10,
title: 'Nachfragen in der Situation',
instruction: 'Reagiere auf ein Verständnisproblem.',
questionData: {
type: 'situational_response',
question: 'Jemand spricht zu schnell. Sag, dass du nicht verstehst, und bitte um langsames Wiederholen.',
keywords: ['wala', 'kasabot', 'hinay', 'mubalik']
},
answerData: {
modelAnswer: 'Wala ko kasabot. Hinay-hinay lang. Palihug ka mubalik?',
keywords: ['wala', 'kasabot', 'hinay', 'mubalik']
},
explanation: 'Du signalisierst das Problem und gibst direkt die gewünschte Lösung.'
}
],
// Lektion 30: Kinder & Familie
'Kinder & Familie': [
{
exerciseTypeId: 2,
title: 'Kinderfrage erkennen',
instruction: 'Wähle die richtige Bedeutung.',
questionData: {
type: 'multiple_choice',
question: 'Was bedeutet "Andam na ka?"?',
options: ['Bist du fertig?', 'Wo ist deine Tasche?', 'Hast du gegessen?', 'Komm her.']
},
answerData: {
type: 'multiple_choice',
correctAnswer: 0
},
explanation: '"Andam na ka?" fragt, ob jemand bereit oder fertig ist.'
},
{
exerciseTypeId: 1,
title: 'Kindersatz ergänzen',
instruction: 'Fülle die Lücken.',
questionData: {
type: 'gap_fill',
text: 'Asa imong {gap}? Kuhaa imong {gap}.',
gaps: 2
},
answerData: {
type: 'gap_fill',
answers: ['bag', 'bag']
},
explanation: 'Die Tasche ist ein typisches Wort in Schul- und Morgenroutinen.'
},
{
exerciseTypeId: 4,
title: 'Essen fragen',
instruction: 'Übersetze ins Bisaya.',
questionData: {
type: 'transformation',
text: 'Hast du schon gegessen?',
sourceLanguage: 'Deutsch',
targetLanguage: 'Bisaya'
},
answerData: {
type: 'transformation',
correct: 'Nikaon na ka?',
alternatives: ['Nakaon na ka?']
},
explanation: 'Das ist eine sehr häufige fürsorgliche Familienfrage.'
},
{
exerciseTypeId: 3,
title: 'Morgenszene bauen',
instruction: 'Ordne die Sätze zu einer kurzen Szene.',
questionData: {
type: 'sentence_building',
question: 'Baue: Komm her, frag nach Essen, frag nach Tasche, frag ob fertig.',
tokens: ['Ali diri.', 'Nikaon na ka?', 'Asa imong bag?', 'Andam na ka?']
},
answerData: {
correct: ['Ali diri. Nikaon na ka? Asa imong bag? Andam na ka?']
},
explanation: 'Die Szene bleibt kurz und funktioniert im Alltag mit Kindern.'
},
{
exerciseTypeId: 10,
title: 'Kind ansprechen',
instruction: 'Reagiere mit kurzen klaren Sätzen.',
questionData: {
type: 'situational_response',
question: 'Vor der Schule soll ein Kind Tasche holen und fertig werden. Sprich freundlich und klar.',
keywords: ['kuhaa', 'bag', 'andam']
},
answerData: {
modelAnswer: 'Kuhaa imong bag. Andam na ka?',
keywords: ['kuhaa', 'bag', 'andam']
},
explanation: 'Kurze Sätze sind in Kindersituationen natürlicher.'
}
],
// Lektion 1: Begrüßungen & Höflichkeit
'Begrüßungen & Höflichkeit': [
{
@@ -5413,6 +5809,14 @@ const PLACEHOLDER_REBUILD_TITLES = new Set([
'Gefühle & Emotionen',
'Gefühle im Alltag',
'Gefühlswortschatz & Reaktionen',
'Gesundheit & Wohlbefinden',
'Körper & Symptome',
'Höflichkeitsformen praktisch',
'Bitten & Nachfragen',
'Kinder & Familie',
'Körper & Gesundheit',
'Höflichkeitsformen',
'Bitten & Fragen',
'Familie - Verwandte & Stieffamilie',
'Rollenspiele - echte Situationen'
]);
@@ -5444,6 +5848,10 @@ function getExercisesForLesson(lesson) {
return BISAYA_EXERCISES['Gefühlswortschatz & Reaktionen'];
}
}
const plannedTitle = BISAYA_LESSONS_24_43_BY_NUMBER[Number(lesson.lessonNumber)]?.title;
if (plannedTitle && BISAYA_EXERCISES[plannedTitle]) {
return BISAYA_EXERCISES[plannedTitle];
}
// Suche nach exaktem Titel
if (BISAYA_EXERCISES[lessonTitle]) {
return BISAYA_EXERCISES[lessonTitle];
@@ -5508,6 +5916,21 @@ async function createBisayaCourseContent() {
console.log(` ${lessons.length} Lektionen gefunden\n`);
for (const lesson of lessons) {
const plannedLesson = BISAYA_LESSONS_24_43_BY_NUMBER[Number(lesson.lessonNumber)];
if (plannedLesson) {
await lesson.update({
title: plannedLesson.title,
description: plannedLesson.desc,
weekNumber: plannedLesson.week,
dayNumber: plannedLesson.day,
lessonType: plannedLesson.type,
culturalNotes: plannedLesson.cultural,
targetMinutes: plannedLesson.targetMin,
targetScorePercent: plannedLesson.targetScore,
requiresReview: plannedLesson.review
});
}
const exercises = getExercisesForLesson(lesson);
if (exercises.length === 0) {
const existingCount = await VocabGrammarExercise.count({ where: { lessonId: lesson.id } });

View File

@@ -23,7 +23,9 @@ import { BISAYA_PHASE4_DIDACTICS } from './bisaya-course-phase4-extension.js';
export const LEGACY_DIDACTICS_TITLE_MAP = {
'Zahlen & Preise': 'Zahlen 120',
'Gefühle & Emotionen': 'Gefühle im Alltag',
'Körper & Gesundheit': 'Körper & Symptome',
'Höflichkeitsformen': 'Höflichkeitsformen praktisch',
'Bitten & Fragen': 'Bitten & Nachfragen',
'Kinder & Spiel': 'Kinder, Spiel & Routine',
'Woche 3 - Wiederholung': 'Woche 3 - Intensivwiederholung',
'Woche 3 - Vokabeltest': 'Woche 3 - Checkpoint',

View File

@@ -730,6 +730,26 @@ export default class VocabService {
if (content) variants.add(content);
});
// Splitte auf Schrägstriche, Semikolons oder Pipes, damit z.B. "A / B" als "A" und "B" gilt
const slashParts = raw.split(/\s*[\/|;]\s*/);
if (slashParts.length > 1) {
slashParts.forEach((p) => {
const pp = String(p || '').trim();
if (pp) variants.add(pp);
});
}
// Auch Varianten trennen, die mit '/' in der ohneParentheses-Version vorkommen
if (withoutParentheses) {
const parts2 = withoutParentheses.split(/\s*[\/|;]\s*/);
if (parts2.length > 1) {
parts2.forEach((p) => {
const pp = String(p || '').trim();
if (pp) variants.add(pp);
});
}
}
return Array.from(variants);
}