Start · Sprachen · JavaScript · Referenz · SpeechSynthesisVoice

SpeechSynthesisVoice

Schnittstelle

Das <code>SpeechSynthesisVoice</code>-Interface der Web Speech API steht für eine Stimme, die das System für die Sprachausgabe bereitstellt, samt Sprache, Name und Herkunft.

seit JavaScript Baseline: alle modernen Browser (Chrome 33+, Edge Kategorie: webapi

Signatur

interface SpeechSynthesisVoice

Beschreibung

SpeechSynthesisVoice beschreibt eine einzelne Stimme, die der Browser oder das Betriebssystem für die Sprachsynthese (Text-to-Speech) anbietet. Eigene Instanzen kann man nicht erzeugen, denn es gibt keinen öffentlichen Konstruktor. Die Objekte bekommt man ausschließlich über speechSynthesis.getVoices(). Danach weist man eine Stimme der Eigenschaft voice eines SpeechSynthesisUtterance zu.

Jede Stimme hat nur schreibgeschützte Eigenschaften:

  • name (string): lesbarer Name, z. B. "Google Deutsch" oder "Anna".
  • lang (string): BCP-47-Sprachcode, z. B. "de-DE".
  • voiceURI (string): eindeutige Kennung der Stimme für den jeweiligen Sprachdienst.
  • localService (boolean): true, wenn die Synthese lokal läuft, false bei einem entfernten Dienst (Cloud).
  • default (boolean): true, wenn das die Standardstimme der aktuellen Sprache bzw. des Systems ist.

Das Interface braucht man immer dann, wenn eine bestimmte Stimme gewählt werden soll, etwa eine deutsche Stimme für Vorlesefunktionen, eine Offline-Stimme für den Datenschutz oder eine Stimmauswahl, die der Nutzer selbst trifft. Ohne ausdrückliche Zuweisung nimmt der Browser eine Standardstimme, die zur Eigenschaft lang der Äußerung passt.

Rückgabewert

Typ
SpeechSynthesisVoice
Beschreibung
Wird nicht direkt erzeugt. Instanzen stehen im Array, das speechSynthesis.getVoices() zurückgibt.

Beispiele

Verfügbare Stimmen zuverlässig laden

// getVoices() liefert beim ersten Aufruf oft ein leeres Array,
// deshalb auf das Event voiceschanged warten
const loadVoices = () => new Promise((resolve) => {
  const voices = speechSynthesis.getVoices();
  if (voices.length) return resolve(voices);
  speechSynthesis.addEventListener('voiceschanged', () => {
    resolve(speechSynthesis.getVoices());
  }, { once: true });
});

const voices = await loadVoices();
voices.forEach((v) => {
  console.log(`${v.name} (${v.lang})${v.default ? ' – Standard' : ''}${v.localService ? ' [lokal]' : ' [remote]'}`);
});
Anna (de-DE) [lokal] Google Deutsch (de-DE) [remote] Samantha (en-US) – Standard [lokal] …

Deutsche Stimme auswählen und Text vorlesen

const speakGerman = (text) => {
  const voices = speechSynthesis.getVoices();
  // lokale deutsche Stimme bevorzugen, sonst irgendeine deutsche
  const voice =
    voices.find((v) => v.lang.startsWith('de') && v.localService) ??
    voices.find((v) => v.lang.startsWith('de'));

  const utterance = new SpeechSynthesisUtterance(text);
  utterance.lang = 'de-DE';
  if (voice) utterance.voice = voice;
  speechSynthesis.speak(utterance);
  return voice?.name ?? 'Standardstimme';
};

console.log(speakGerman('Willkommen auf programmierung.net!'));
Anna

Stimmauswahl als Dropdown mit gespeicherter Präferenz

const select = document.querySelector('#voice-select');

const fillVoices = () => {
  const voices = speechSynthesis.getVoices();
  const saved = localStorage.getItem('voiceURI');
  select.replaceChildren(...voices.map((v) => {
    const opt = new Option(`${v.name} (${v.lang})`, v.voiceURI);
    opt.selected = v.voiceURI === saved || (!saved && v.default);
    return opt;
  }));
};

fillVoices();
speechSynthesis.onvoiceschanged = fillVoices;

select.addEventListener('change', () => {
  localStorage.setItem('voiceURI', select.value);
  const voice = speechSynthesis.getVoices().find((v) => v.voiceURI === select.value);
  const u = new SpeechSynthesisUtterance('Das ist die ausgewählte Stimme.');
  u.voice = voice;
  speechSynthesis.speak(u);
});

// Wichtig · Fallstricke

  • Stimmen werden asynchron geladen: Vor allem in Chrome gibt getVoices() anfangs ein leeres Array zurück. Auf das Event voiceschanged warten, das Safari allerdings nicht in jeder Version zuverlässig auslöst. Als Rückfall hilft ein erneuter Aufruf nach kurzer Verzögerung.
  • Welche Stimmen es gibt, hängt von der Plattform ab: Namen, Anzahl und voiceURI unterscheiden sich je nach Betriebssystem, Browser und installierten Sprachpaketen. Stimmnamen deshalb nie fest im Code verdrahten, sondern nach lang filtern und einen Rückfall vorsehen.
  • Remote-Stimmen und Datenschutz: Bei localService === false kann der Text an einen Cloud-Dienst geschickt werden, z. B. bei den Google-Stimmen in Chrome. Für sensible Inhalte lokale Stimmen bevorzugen. Remote-Stimmen brauchen außerdem eine Netzwerkverbindung.
  • Fingerprinting: Die Liste der Stimmen verrät etwas über das System. Manche Browser schränken sie deshalb ein, etwa Firefox mit privacy.resistFingerprinting.
  • Format von lang: Auf manchen Android-Versionen kommt "de_DE" mit Unterstrich statt Bindestrich. Beim Vergleich darum am besten startsWith('de') verwenden.
  • Stimmobjekte nicht dauerhaft speichern. Nur die voiceURI ablegen und die Stimme später wieder aus getVoices() heraussuchen.