Start · Sprachen · JavaScript · Referenz · SpeechSynthesis: voiceschanged

SpeechSynthesis: voiceschanged

Ereignis

Wird ausgelöst, wenn sich die Liste der von <code>speechSynthesis.getVoices()</code> gelieferten Stimmen ändert, etwa weil die Stimmen asynchron fertig geladen wurden.

seit JavaScript Baseline: alle modernen Browser (seit 2018) Kategorie: webapi

Signatur

speechSynthesis.addEventListener("voiceschanged", handler)

Beschreibung

Das Ereignis voiceschanged gehört zur Web Speech API und wird am globalen SpeechSynthesis-Objekt (window.speechSynthesis) ausgelöst. Das passiert, wenn sich die Liste der SpeechSynthesisVoice-Objekte ändert, die getVoices() zurückgibt. Meist geschieht das kurz nach dem Laden der Seite, weil viele Browser (vor allem Chrome) die Stimmen asynchron laden. Direkt nach dem Seitenaufruf liefert getVoices() dort oft noch ein leeres Array.

Registrieren kannst du das Ereignis mit speechSynthesis.addEventListener("voiceschanged", handler) oder über die Eigenschaft speechSynthesis.onvoiceschanged = handler. Der Handler bekommt ein einfaches Event-Objekt ohne eigene Zusatzdaten. Die aktuelle Liste holst du im Handler erneut mit getVoices().

Typische Einsatzfälle sind das Füllen eines Auswahlmenüs mit Stimmen, das Auswählen einer bestimmten Stimme (z. B. deutsch, lang === "de-DE") vor dem ersten Vorlesen und das Aktualisieren der Oberfläche, wenn das Betriebssystem Stimmen nachinstalliert oder entfernt.

Wichtig: Das Ereignis kommt nicht in jedem Browser zuverlässig. In manchen Browsern ist die Liste sofort verfügbar, dann wird voiceschanged eventuell gar nicht ausgelöst. Robuster Code liest die Liste deshalb einmal sofort und zusätzlich im Handler.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Name des Ereignisses: "voiceschanged".
$handler Pflicht (event: Event) => void Callback, der bei jeder Änderung der Stimmenliste aufgerufen wird. Er erhält ein einfaches Event-Objekt ohne eigene Zusatzdaten.
$options boolean | AddEventListenerOptions false Optionen wie bei addEventListener, z. B. { once: true } oder { signal }.

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Die neue Stimmenliste liest du im Handler mit speechSynthesis.getVoices().

Beispiele

Stimmen robust laden (sofort und bei Änderung)

const loadVoices = () => {
  const voices = speechSynthesis.getVoices();
  console.log(`${voices.length} Stimmen verfügbar`);
  return voices;
};

// Sofort versuchen – manche Browser liefern die Liste direkt
loadVoices();

// Zusätzlich auf asynchrones Nachladen reagieren (z. B. Chrome)
speechSynthesis.addEventListener("voiceschanged", loadVoices);
0 Stimmen verfügbar 23 Stimmen verfügbar

Auswahlmenü mit Stimmen füllen (on-Property)

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

const populateVoiceList = () => {
  const voices = speechSynthesis.getVoices();
  select.replaceChildren(
    ...voices.map((voice) => {
      const option = document.createElement("option");
      option.value = voice.name;
      option.textContent = `${voice.name} (${voice.lang})${voice.default ? " – Standard" : ""}`;
      return option;
    })
  );
};

populateVoiceList();
if ("onvoiceschanged" in speechSynthesis) {
  speechSynthesis.onvoiceschanged = populateVoiceList;
}

Promise-Helfer: auf deutsche Stimme warten und vorlesen

const getVoicesAsync = (timeout = 2000) =>
  new Promise((resolve) => {
    const voices = speechSynthesis.getVoices();
    if (voices.length) return resolve(voices);

    const onChange = () => {
      clearTimeout(timer);
      resolve(speechSynthesis.getVoices());
    };
    // Fallback, falls das Ereignis nie ausgelöst wird
    const timer = setTimeout(() => {
      speechSynthesis.removeEventListener("voiceschanged", onChange);
      resolve(speechSynthesis.getVoices());
    }, timeout);

    speechSynthesis.addEventListener("voiceschanged", onChange, { once: true });
  });

const speakGerman = async (text) => {
  const voices = await getVoicesAsync();
  const utterance = new SpeechSynthesisUtterance(text);
  utterance.voice = voices.find((v) => v.lang.startsWith("de")) ?? null;
  utterance.lang = "de-DE";
  speechSynthesis.speak(utterance);
  console.log("Stimme:", utterance.voice?.name ?? "Standard");
};

speakGerman("Hallo und willkommen!");
Stimme: Google Deutsch

Listener wieder entfernen

const logVoices = () => console.log(speechSynthesis.getVoices().length);

speechSynthesis.addEventListener("voiceschanged", logVoices);

// Später, z. B. beim Abbau einer Komponente:
speechSynthesis.removeEventListener("voiceschanged", logVoices);
// bzw. bei der on-Property:
speechSynthesis.onvoiceschanged = null;

// Wichtig · Fallstricke

  • Nicht auf das Ereignis allein verlassen: In Firefox und Safari ist die Liste oft sofort verfügbar, dann wird voiceschanged eventuell nie ausgelöst. Lies die Liste daher immer auch direkt einmal mit getVoices().
  • Mehrfaches Auslösen: Chrome kann das Ereignis mehrmals auslösen, etwa wenn lokale Stimmen und Netzwerkstimmen nacheinander eintreffen. Handler sollten deshalb idempotent sein, also die Liste komplett neu aufbauen statt Einträge anzuhängen.
  • Safari: Ältere Safari-Versionen hatten keine onvoiceschanged-Eigenschaft. Prüfe sie vorher mit "onvoiceschanged" in speechSynthesis.
  • Keine Zusatzdaten: Das Event-Objekt enthält die Stimmen nicht. Du musst getVoices() erneut aufrufen.
  • Datenschutz: Die Stimmenliste kann zum Fingerprinting genutzt werden. Manche Browser schränken sie deshalb ein oder liefern nur wenige Stimmen.
  • Prüfe vor der Nutzung, ob die API überhaupt vorhanden ist: if ("speechSynthesis" in window). In Web Workers und Node.js gibt es sie nicht.