Skip to content

Accessibility and Usability Enhancements for the VoiceCapture #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ function returnVoiceTranscript(transcript) {
:status="isVoiceCaptureExample"
:lang="langSelect"
:mode="modeSelect"
:clipboard="true"
@voiceTranscript="returnVoiceTranscript"
@onStatus="statusVoiceCapture"
/>
Expand Down
130 changes: 78 additions & 52 deletions src/components/VoiceCapture.translate.ts
Original file line number Diff line number Diff line change
@@ -1,80 +1,106 @@
export const translates = {
en: {
speakNow: 'Speak now',
noSpeech: 'No speech detected.',
audioCapture: 'Audio capture problem.',
enableMicrophone: 'Enable the microphone',
speakNow: "Speak now",
noSpeech: "No speech detected.",
audioCapture: "Audio capture problem.",
enableMicrophone: "Enable the microphone",
close: "Close voice capture",
open: "Start voice capture",
},
pt: {
speakNow: 'Fale agora',
noSpeech: 'Nenhuma fala detectada.',
audioCapture: 'Problema na captura de áudio.',
enableMicrophone: 'Ative o microfone',
speakNow: "Fale agora",
noSpeech: "Nenhuma fala detectada.",
audioCapture: "Problema na captura de áudio.",
enableMicrophone: "Ative o microfone",
close: "Fechar captura de voz",
open: "Iniciar captura de voz",
},
es: {
speakNow: 'Habla ahora',
noSpeech: 'No se detectó voz.',
audioCapture: 'Problema en la captura de audio.',
enableMicrophone: 'Activa el micrófono',
speakNow: "Habla ahora",
noSpeech: "No se detectó voz.",
audioCapture: "Problema en la captura de audio.",
enableMicrophone: "Activa el micrófono",
close: "Cerrar captura de voz",
open: "Iniciar captura de voz",
},
fr: {
speakNow: 'Parlez maintenant',
noSpeech: 'Aucune parole détectée.',
audioCapture: 'Problème de capture audio.',
enableMicrophone: 'Activez le microphone',
speakNow: "Parlez maintenant",
noSpeech: "Aucune parole détectée.",
audioCapture: "Problème de capture audio.",
enableMicrophone: "Activez le microphone",
close: "Fermer la capture vocale",
open: "Démarrer la capture vocale",
},
de: {
speakNow: 'Sprich jetzt',
noSpeech: 'Keine Sprache erkannt.',
audioCapture: 'Audioproblem.',
enableMicrophone: 'Aktivieren Sie das Mikrofon',
speakNow: "Sprich jetzt",
noSpeech: "Keine Sprache erkannt.",
audioCapture: "Audioproblem.",
enableMicrophone: "Aktivieren Sie das Mikrofon",
close: "Spracherfassung schließen",
open: "Spracherfassung starten",
},
it: {
speakNow: 'Parla ora',
noSpeech: 'Nessuna parola rilevata.',
audioCapture: 'Problema con la cattura audio.',
enableMicrophone: 'Abilita il microfono',
speakNow: "Parla ora",
noSpeech: "Nessuna parola rilevata.",
audioCapture: "Problema con la cattura audio.",
enableMicrophone: "Abilita il microfono",
close: "Chiudere la cattura vocale",
open: "Avviare la cattura vocale",
},
ja: {
speakNow: '今話してください',
noSpeech: '音声が検出されませんでした。',
audioCapture: 'オーディオキャプチャの問題。',
enableMicrophone: 'マイクを有効にしてください',
speakNow: "今話してください",
noSpeech: "音声が検出されませんでした。",
audioCapture: "オーディオキャプチャの問題。",
enableMicrophone: "マイクを有効にしてください",
close: "音声キャプチャを閉じる",
open: "音声キャプチャを開始",
},
zh: {
speakNow: '现在说话',
noSpeech: '没有检测到语音。',
audioCapture: '音频捕获问题。',
enableMicrophone: '启用麦克风',
speakNow: "现在说话",
noSpeech: "没有检测到语音。",
audioCapture: "音频捕获问题。",
enableMicrophone: "启用麦克风",
close: "关闭语音捕捉",
open: "开始语音捕捉",
},
ru: {
speakNow: 'Говорите сейчас',
noSpeech: 'Речь не обнаружена.',
audioCapture: 'Проблема с захватом звука.',
enableMicrophone: 'Включите микрофон',
speakNow: "Говорите сейчас",
noSpeech: "Речь не обнаружена.",
audioCapture: "Проблема с захватом звука.",
enableMicrophone: "Включите микрофон",
close: "Закрыть захват голоса",
open: "Начать захват голоса",
},
ar: {
speakNow: 'تحدث الآن',
noSpeech: 'لم يتم اكتشاف الكلام.',
audioCapture: 'مشكلة في التقاط الصوت.',
enableMicrophone: 'قم بتمكين الميكروفون',
speakNow: "تحدث الآن",
noSpeech: "لم يتم اكتشاف الكلام.",
audioCapture: "مشكلة في التقاط الصوت.",
enableMicrophone: "قم بتمكين الميكروفون",
close: "إغلاق التقاط الصوت",
open: "بدء التقاط الصوت",
},
ko: {
speakNow: '지금 말하세요',
noSpeech: '음성이 감지되지 않았습니다.',
audioCapture: '오디오 캡처 문제.',
enableMicrophone: '마이크를 활성화하세요',
speakNow: "지금 말하세요",
noSpeech: "음성이 감지되지 않았습니다.",
audioCapture: "오디오 캡처 문제.",
enableMicrophone: "마이크를 활성화하세요",
close: "음성 캡처 닫기",
open: "음성 캡처 시작",
},
nl: {
speakNow: 'Spreek nu',
noSpeech: 'Geen spraak gedetecteerd.',
audioCapture: 'Probleem met audiovangst.',
enableMicrophone: 'Activeer de microfoon',
speakNow: "Spreek nu",
noSpeech: "Geen spraak gedetecteerd.",
audioCapture: "Probleem met audiovangst.",
enableMicrophone: "Activeer de microfoon",
close: "Stemopname sluiten",
open: "Stemopname starten",
},
sv: {
speakNow: 'Tala nu',
noSpeech: 'Ingen tal upptäckt.',
audioCapture: 'Problem med ljudinspelning.',
enableMicrophone: 'Aktivera mikrofonen',
speakNow: "Tala nu",
noSpeech: "Ingen tal upptäckt.",
audioCapture: "Problem med ljudinspelning.",
enableMicrophone: "Aktivera mikrofonen",
close: "Stäng röstinspelning",
open: "Starta röstinspelning",
},
};
42 changes: 32 additions & 10 deletions src/components/VoiceCapture.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,26 @@
class="voicecapture"
:class="{ active: status, [mode]: mode }"
@click="deactivateVoice"
aria-modal="true"
role="dialog"
:aria-expanded="status ? 'true' : 'false'"
>
<button class="exit" type="button" @click="deactivateVoice">
<i class="icon icon-exit">X</i>
<button
class="exit"
@click="deactivateVoice"
:aria-label="getTranslation('close')"
type="button"
>
<i class="icon icon-exit" aria-hidden="true">X</i>
</button>
<p class="text-tip">{{ translatedText }}</p>
<p class="text-tip" aria-live="polite">{{ translatedText }}</p>
<button
type="button"
class="btn-voice"
:class="{ active: animationButton }"
:aria-label="getTranslation('open')"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
<path d="M17 11.998c0 2.76-2.23 5-4.99 5l-.002.002a4.994 4.994 0 01-4.979-5h-2c0 3.52 2.59 6.433 5.98 6.92v3.078h.01V22h2v-3.08h-.01A6.982 6.982 0 0019 11.998z" />
<path fill="none" d="M0 0h24v24H0z" />
<path d="M12 15c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v7c0 1.66 1.34 3 3 3z" />
Expand Down Expand Up @@ -41,6 +50,10 @@ export default {
type: String,
default: 'fullscreen',
},
clipboard: {
type: Boolean,
default: false,
},
},
emits: ['voiceTranscript', 'onStatus'],
setup(props, { emit }) {
Expand All @@ -62,12 +75,10 @@ export default {
};

const deactivateVoice = () => {
if (recognizing.value && recognition.value) {
recognizing.value = false;
animationButton.value = false;
recognition.value.stop();
emit('onStatus', false);
}
recognizing.value = false;
animationButton.value = false;
recognition.value.stop();
emit('onStatus', false);
};

const setupVoiceRecognition = () => {
Expand Down Expand Up @@ -123,6 +134,16 @@ export default {
translatedText.value = interimTranscript || finalTranscript.value;

if (finalTranscript.value) {
if(props.clipboard) {
navigator.clipboard.writeText(finalTranscript.value).then(
() => {
console.log('Text copied to clipboard');
},
(err) => {
console.error('Could not copy text to clipboard', err);
}
);
}
emit('voiceTranscript', finalTranscript.value);
deactivateVoice();
}
Expand Down Expand Up @@ -155,6 +176,7 @@ export default {
translatedText,
activateVoice,
deactivateVoice,
getTranslation
};
},
};
Expand Down