diff --git a/backend/services/vocabService.js b/backend/services/vocabService.js index 6ebbe0d..7ebde2a 100644 --- a/backend/services/vocabService.js +++ b/backend/services/vocabService.js @@ -345,7 +345,7 @@ export default class VocabService { return String(text || '') .trim() .toLowerCase() - .replace(/[.,!?;:¿¡"]/g, '') + .replace(/[\p{P}]+/gu, ' ') .replace(/\s+/g, ' '); } @@ -2689,7 +2689,7 @@ export default class VocabService { const correctTexts = correctIndices .map((i) => options[i]) .filter((opt) => opt !== undefined && opt !== null); - const norm = (s) => String(s).trim().toLowerCase(); + const norm = (s) => this._normalizeTextAnswer(s); // Nach zufälligen Distraktoren: Client sendet gewählten Optionstext statt Index if (typeof userAnswer === 'string') { diff --git a/frontend/src/views/social/VocabLessonView.vue b/frontend/src/views/social/VocabLessonView.vue index c9c270a..d94c24a 100644 --- a/frontend/src/views/social/VocabLessonView.vue +++ b/frontend/src/views/social/VocabLessonView.vue @@ -2041,7 +2041,7 @@ export default { const totalSlots = options.length; const need = totalSlots - correctTexts.length; if (need <= 0) return null; - const norm = (s) => String(s).trim().toLowerCase(); + const norm = (s) => this.normalizeComparableText(s); const correctSet = new Set(correctTexts.map(norm)); const poolRaw = side === 'target' ? this.distractorPool.target : this.distractorPool.native; let poolFiltered = poolRaw.filter((w) => w && !correctSet.has(norm(w))); @@ -2700,8 +2700,15 @@ export default { this.checkVocabAnswer(); } }, + normalizeComparableText(value) { + return String(value || '') + .trim() + .toLowerCase() + .replace(/[\p{P}]+/gu, ' ') + .replace(/\s+/g, ' '); + }, normalizeVocab(s) { - return String(s || '').trim().toLowerCase().replace(/\s+/g, ' '); + return this.normalizeComparableText(s); }, checkVocabAnswer() { if (!this.currentVocabQuestion) return;