Enhance speech input handling in VocabLessonView: Introduce fallback instructions and placeholders for unsupported speech recognition in English, German, and Spanish. Update exercise instructions to dynamically display fallback options, improving user experience for speech-related exercises.

This commit is contained in:
Torsten Schulz (local)
2026-03-25 18:07:01 +01:00
parent 2e6eb53918
commit 01849c8ffe
4 changed files with 30 additions and 6 deletions

View File

@@ -478,8 +478,10 @@
<!-- Reading Aloud Übung -->
<div v-else-if="getExerciseType(exercise) === 'reading_aloud'" class="reading-aloud-exercise">
<p class="exercise-question">{{ getQuestionText(exercise) }}</p>
<p class="exercise-instruction">{{ $t('socialnetwork.vocab.courses.readingAloudInstruction') }}</p>
<div class="reading-aloud-controls">
<p class="exercise-instruction">
{{ isSpeechRecognitionSupported ? $t('socialnetwork.vocab.courses.readingAloudInstruction') : $t('socialnetwork.vocab.courses.speakingFallbackInstruction') }}
</p>
<div v-if="isSpeechRecognitionSupported" class="reading-aloud-controls">
<button
v-if="!isRecording(exercise.id)"
@click="startReadingAloud(exercise.id)"
@@ -496,6 +498,13 @@
{{ $t('socialnetwork.vocab.courses.stopRecording') }}
</button>
</div>
<div v-else class="speech-fallback">
<textarea
v-model="exerciseAnswers[exercise.id]"
:placeholder="$t('socialnetwork.vocab.courses.speakingFallbackPlaceholder')"
class="response-textarea"
/>
</div>
<div v-if="recordingStatus[exercise.id]" class="recording-status" :class="{ 'recording': isRecording(exercise.id) }">
<span v-if="isRecording(exercise.id)">{{ $t('socialnetwork.vocab.courses.recording') }}...</span>
<span v-else>{{ recordingStatus[exercise.id] }}</span>
@@ -505,7 +514,7 @@
<p>{{ recognizedText[exercise.id] }}</p>
</div>
<button
v-if="recognizedText[exercise.id] && !isRecording(exercise.id)"
v-if="(recognizedText[exercise.id] && !isRecording(exercise.id)) || (!isSpeechRecognitionSupported && exerciseAnswers[exercise.id])"
@click="checkAnswer(exercise.id)"
class="btn-check"
>
@@ -526,12 +535,14 @@
<!-- Speaking From Memory Übung -->
<div v-else-if="getExerciseType(exercise) === 'speaking_from_memory'" class="speaking-from-memory-exercise">
<p class="exercise-question">{{ getQuestionText(exercise) }}</p>
<p class="exercise-instruction">{{ $t('socialnetwork.vocab.courses.speakingFromMemoryInstruction') }}</p>
<p class="exercise-instruction">
{{ isSpeechRecognitionSupported ? $t('socialnetwork.vocab.courses.speakingFromMemoryInstruction') : $t('socialnetwork.vocab.courses.speakingFallbackInstruction') }}
</p>
<div v-if="getQuestionData(exercise)?.keywords" class="keywords-hint">
<strong>{{ $t('socialnetwork.vocab.courses.keywords') }}:</strong>
<span v-for="(keyword, idx) in getQuestionData(exercise).keywords" :key="idx" class="keyword-tag">{{ keyword }}</span>
</div>
<div class="speaking-controls">
<div v-if="isSpeechRecognitionSupported" class="speaking-controls">
<button
v-if="!isRecording(exercise.id)"
@click="startSpeakingFromMemory(exercise.id)"
@@ -548,6 +559,13 @@
{{ $t('socialnetwork.vocab.courses.stopRecording') }}
</button>
</div>
<div v-else class="speech-fallback">
<textarea
v-model="exerciseAnswers[exercise.id]"
:placeholder="$t('socialnetwork.vocab.courses.speakingFallbackPlaceholder')"
class="response-textarea"
/>
</div>
<div v-if="recordingStatus[exercise.id]" class="recording-status" :class="{ 'recording': isRecording(exercise.id) }">
<span v-if="isRecording(exercise.id)">{{ $t('socialnetwork.vocab.courses.recording') }}...</span>
<span v-else>{{ recordingStatus[exercise.id] }}</span>
@@ -557,7 +575,7 @@
<p>{{ recognizedText[exercise.id] }}</p>
</div>
<button
v-if="recognizedText[exercise.id] && !isRecording(exercise.id)"
v-if="(recognizedText[exercise.id] && !isRecording(exercise.id)) || (!isSpeechRecognitionSupported && exerciseAnswers[exercise.id])"
@click="checkAnswer(exercise.id)"
class="btn-check"
>