Veus. JavaScript completament documentat

Aquest script s’executa automàticament a cada recàrrega de la pàgina.
El seu objectiu principal és activar la funcionalitat de “llegir en veu alta”, el contingut del camp de cerca (#cercar) quan l’usuari prem el botó 🔊 (#speakButton).
També prepara el sistema de veus del navegador segons l’idioma triat per l’usuari
(desat a $_SESSION[‘lang_audio’]).

<script>
  // Aquest script s'executa automàticament a cada recàrrega de la pàgina.
  // El seu objectiu principal és activar la funcionalitat de "llegir en veu alta"
  // el contingut del camp de cerca (#cercar) quan l'usuari prem el botó 🔊 (#speakButton).
  // També prepara el sistema de veus del navegador segons l'idioma triat per l'usuari
  // (desat a $_SESSION['lang_audio']).

  document.addEventListener('DOMContentLoaded', () => {
    // Obtenim referències als elements HTML que necessitarem:
    const inputElement = document.getElementById('cercar');        // Camp de text on l'usuari escriu
    const speakBtn = document.getElementById('speakButton');       // Botó 🔊 per llegir el text
    let voices = [];                                              // Array per emmagatzemar les veus disponibles al navegador

    // 🔴 Carreguem dinàmicament l'idioma d'àudio desat a la sessió PHP.
    // Aquest valor ve de $_SESSION['lang_audio'] i pot ser, per exemple, 'ca-ES', 'es-ES', etc.
    const userLang = '<?php echo addslashes($_SESSION["lang_audio"]); ?>';

    // Funció que omple l'array 'voices' amb totes les veus disponibles al sistema.
    // Aquesta funció cal cridar-la almenys un cop, i també quan el navegador
    // notifica que la llista de veus ha canviat (veure més avall).
    function loadVoices() {
      voices = speechSynthesis.getVoices();
    }

    // El navegador pot trigar a carregar la llista de veus.
    // Per això, li afegim un esdeveniment 'onvoiceschanged' que es dispararà
    // quan les veus estiguin disponibles. Així assegurem que 'voices' no estigui buit.
    speechSynthesis.onvoiceschanged = loadVoices;

    // Fem una primera crida a loadVoices() per si les veus ja estan carregades.
    loadVoices();

    // Funció que reprodueix en veu alta el text actual del camp de cerca.
    function speakText() {
      // Obtenim el text i eliminem espais innecessaris als extrems.
      const text = inputElement.value.trim();
      
      // Si el text és buit, no fem res.
      if (!text) return;

      // Creem un objecte 'SpeechSynthesisUtterance' amb el text a pronunciar.
      const utterance = new SpeechSynthesisUtterance(text);

      // 🔴 Intentem trobar una veu que coincideixi exactament amb l'idioma de la sessió (ex: 'ca-ES').
      let selectedVoice = voices.find(v => v.lang === userLang);

      // Si no trobem una veu amb coincidència exacta, provem amb el codi base de l'idioma (ex: 'ca').
      if (!selectedVoice) {
        const baseLang = userLang.split('-')[0]; // Ex: 'ca-ES' → 'ca'
        selectedVoice = voices.find(v => v.lang.startsWith(baseLang));
      }

      // Si hem trobat una veu adequada, l'assignem a l'utterance.
      if (selectedVoice) {
        utterance.voice = selectedVoice;
        utterance.lang = selectedVoice.lang; // Assegurem coherència d'idioma
      } else {
        // Si no hi ha cap veu compatible, assignem només l'idioma.
        // El navegador triarà automàticament una veu (potser en un altre idioma).
        utterance.lang = userLang;
      }

      // Configuració addicional de la pronunciació:
      utterance.rate = 1;   // Velocitat normal (1.0 = per defecte)
      utterance.pitch = 1;  // To normal

      // Cancel·lem qualsevol altra reproducció en curs i iniciem aquesta.
      speechSynthesis.cancel();
      speechSynthesis.speak(utterance);
    }

    // Afegim un esdeveniment de clic al botó 🔊.
    // Quan l'usuari prem el botó, es crida la funció speakText().
    speakBtn.addEventListener('click', (e) => {
      e.preventDefault(); // Evitem comportaments per defecte (ex: submit del formulari)
      speakText();        // Llegim el text en veu alta
    });
  });
</script>