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

@@ -437,6 +437,8 @@
"recordingError": "Aufnahme-Fehler",
"recognizedText": "Erkannter Text",
"speechRecognitionNotSupported": "Speech Recognition wird von diesem Browser nicht unterstützt. Bitte verwende Chrome oder Edge.",
"speakingFallbackInstruction": "Dein Browser unterstützt hier keine Spracheingabe. Schreibe deine gesprochene Antwort stattdessen als Text auf und prüfe sie dann normal.",
"speakingFallbackPlaceholder": "Schreibe hier, was du sagen würdest ...",
"keywords": "Schlüsselwörter",
"switchBackToMultipleChoice": "Zurück zu Multiple Choice",
"languageAssistantEyebrow": "Sprachassistent",

View File

@@ -437,6 +437,8 @@
"recordingError": "Recording error",
"recognizedText": "Recognized Text",
"speechRecognitionNotSupported": "Speech Recognition is not supported by this browser. Please use Chrome or Edge.",
"speakingFallbackInstruction": "Your browser does not support speech input here. Write down what you would say instead and check it normally.",
"speakingFallbackPlaceholder": "Write what you would say here ...",
"keywords": "Keywords",
"switchBackToMultipleChoice": "Switch back to Multiple Choice",
"languageAssistantEyebrow": "Language assistant",

View File

@@ -434,6 +434,8 @@
"recordingError": "Error de grabación",
"recognizedText": "Texto reconocido",
"speechRecognitionNotSupported": "El reconocimiento de voz no es compatible con este navegador. Usa Chrome o Edge.",
"speakingFallbackInstruction": "Tu navegador no admite entrada de voz aquí. Escribe en su lugar lo que dirías y compruébalo normalmente.",
"speakingFallbackPlaceholder": "Escribe aquí lo que dirías ...",
"keywords": "Palabras clave",
"switchBackToMultipleChoice": "Volver a opción múltiple",
"languageAssistantEyebrow": "Asistente de idiomas",

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"
>