Nessun oggetto della modifica
Etichetta: Annullato
Nessun oggetto della modifica
Etichetta: Ripristino manuale
Riga 1: Riga 1:
/* ======================= CommonTranslate.js (versione stabile precedente) ======================= */
/* ======================= CommonTranslate.js ======================= */
console.log("🔄 Caricamento CommonTranslate.js…");
console.log("🔄 Caricamento CommonTranslate.js...");


// Evita doppio caricamento
// Evita ricaricamento multiplo
if (window.__CommonTranslateLoaded) {
if (window.CommonTranslateLoaded) {
  console.warn("⚠️ CommonTranslate.js è già stato caricato.");
    console.warn("⚠️ CommonTranslate.js è già stato caricato.");
} else {
} else {
  window.__CommonTranslateLoaded = true;
    window.CommonTranslateLoaded = true;


  // Manteniamo la vecchia struttura con pulsante
    // ✅ Imposta lingua di origine (fallback su HTML lang o en)
  const DEFAULT_MODEL = (window.openaiModel || "gpt-4o");
    window.linguaOrigine = document.documentElement.lang || "en";
  const LINGUA_ORIGINE = document.documentElement.lang || "en";


  // 🔑 QUI usi ancora la chiave diretta (come avevi prima) → se preferisci il proxy si cambia solo questo pezzo
    // ✅ Imposta API key se non esiste
  const API_URL = "https://api.openai.com/v1/chat/completions";
    if (!window.apiKey) {
  const API_KEY = window.apiKey || "INSERISCI_LA_TUA_API_KEY";
        window.apiKey = "XXXXX";  // <--- Inserisci la tua API Key qui
    }
 
    // ✅ Definizione modello OpenAI
    window.openaiModel = "gpt-4o-2024-05-13";
 
    console.log("✅ CommonTranslate.js caricato correttamente!");
}


  console.log("✅ CommonTranslate.js caricato. Modello:", DEFAULT_MODEL);


  function getEditor() {
/* ======================= Funzione principale ======================= */
    return document.getElementById("wpTextbox1");
async function traduciTesto() {
  const area = document.getElementById("wpTextbox1");
  const start = area.selectionStart;
  const end = area.selectionEnd;
  const testoSelezionato = area.value.slice(start, end).trim();
  const tutto = !testoSelezionato;
 
  // ✅ Chiedi cosa tradurre
  const conferma = confirm("📝 Vuoi tradurre SOLO il testo selezionato?\n\n✅ OK = solo selezione\n❌ Annulla = tutto il testo");
  if (conferma && !testoSelezionato) {
    alert("⚠️ Nessuna parte selezionata. Se vuoi tradurre tutto, premi Annulla.");
    return;
   }
   }


   function getSelectedTextInfo() {
   const testo = tutto ? area.value : testoSelezionato;
    const area = getEditor();
 
    if (!area) return { text: "", start: 0, end: 0 };
  // ✅ STEP 1: Lingua
     const start = area.selectionStart;
  const lingueDisponibili = ["it", "en", "fr", "es", "de"];
     const end = area.selectionEnd;
  let linguaScelta = prompt(
     const text = area.value.slice(start, end);
     "🌍 Scegli la lingua di traduzione:\n\nit = Italiano\nen = Inglese\nfr = Francese\nes = Spagnolo\nde = Tedesco",
     return { text, start, end };
     "it"
  );
  if (!linguaScelta) {
     console.warn("⚠️ Nessuna lingua selezionata.");
     return;
   }
   }


  function segmentaTesto(testo, maxChars = 3000) {
 
    const re = new RegExp(`.{1,${maxChars}}(?=\\s|$)`, "gs");
// ✅ STEP 2: Segmentazione
     return testo.match(re) || [];
const blocchi = segmentaTesto(testo);
console.log(`🧩 Segmentazione: ${blocchi.length} blocchi trovati`);
 
if (tutto) {
  // 🔍 STEP 3: Analisi segmentazione + popup
  const errori = analizzaErroriSegmentazione(blocchi);
  sostituisciTestoSegmentato(blocchi, errori);
  mostraPopupConferma(blocchi, errori, [linguaScelta], tutto);
  return; // ⛔️ blocco qui: la traduzione partirà dal popup
}
 
  // ✅ STEP 3: Traduzione (passa il parametro `tutto`)
  const tradotto = await inviaTraduzione(blocchi, linguaScelta, tutto);
 
  // ✅ STEP 4: Inserimento nel campo editor
  if (tutto) {
    area.value = tradotto;
  } else {
    const prima = area.value.slice(0, start);
     const dopo = area.value.slice(end);
    area.value = prima + tradotto + dopo;
    area.selectionStart = start;
    area.selectionEnd = start + tradotto.length;
   }
   }


   async function traduciBlocco(blocco, lingua, model = DEFAULT_MODEL) {
   // ✅ STEP 5: Notifica
     try {
  area.dispatchEvent(new Event("input", { bubbles: true }));
      const res = await fetch(API_URL, {
  area.dispatchEvent(new Event("change", { bubbles: true }));
        method: "POST",
 
        headers: {
  console.log("✅ Traduzione completata e inserita correttamente.");
          "Content-Type": "application/json",
}
          "Authorization": `Bearer ${API_KEY}`
 
        },
 
        body: JSON.stringify({
/* ======================= Funzioni di supporto ======================= */
          model,
function ottieniTestoDaEditor() {
          messages: [
     const area = document.getElementById("wpTextbox1");
            {
    return area ? area.value.trim() : null;
              role: "system",
}
              content:
 
                "You are a professional MediaWiki translator. Translate preserving templates, links, headings, lists and any wiki syntax. Do not add explanations."
function ottieniTestoSelezionato() {
             },
    const area = document.getElementById("wpTextbox1");
             {
    if (!area) return null;
              role: "user",
    return area.value.substring(area.selectionStart, area.selectionEnd).trim() || null;
              content: `Translate the following text from ${LINGUA_ORIGINE} to ${lingua}:\n\n${blocco}`
}
 
function segmentaTesto(testo, maxToken = 3000) {
    console.log("📌 Segmentazione in corso con max", maxToken, "tokens...");
    const blocchi = testo.match(new RegExp(`.{1,${maxToken}}(?=\\s|$)`, "gs")) || [];
    return blocchi;
}
 
function analizzaErroriSegmentazione(blocchi) {
    let errori = [];
    blocchi.forEach((blocco, i) => {
        let err = [];
        const count = (s, c) => (s.match(new RegExp(`\\${c}`, 'g')) || []).length;
        const parentesi = [["[", "]"], ["{", "}"], ["<", ">"]];
        parentesi.forEach(([open, close]) => {
            let openCount = count(blocco, open);
             let closeCount = count(blocco, close);
             if (openCount !== closeCount) {
                err.push(`Parentesi ${open}${close} non bilanciate: ${openCount} ${open}, ${closeCount} ${close}`);
             }
             }
          ],
        });
          temperature: 0
        if (err.length > 0) {
         })
            errori.push({ index: i + 1, dettagli: err });
      });
         }
    });
    return errori;
}


      const data = await res.json();
function sostituisciTestoSegmentato(blocchi, errori) {
      if (!res.ok) {
    const area = document.getElementById("wpTextbox1");
        const msg = data?.error?.message || `HTTP ${res.status}`;
     if (!area) {
        throw new Error(msg);
        console.warn("⚠️ Campo wpTextbox1 non trovato per sostituzione.");
      }
        return;
      return data?.choices?.[0]?.message?.content ?? "[Traduzione vuota]";
     } catch (err) {
      console.error("❌ Errore traduzione:", err);
      return "[Errore Traduzione]";
     }
     }
  }
    const blocchiSegnalati = blocchi.map((b, i) => {
        const err = errori.find(e => e.index === i + 1);
        const erroreText = err ? `⚠️ ERRORI:\n- ${err.dettagli.join("\n- ")}\n\n` : "";
        return `${erroreText}🔹 BLOCCO ${i + 1}\n` + b;
    });
    area.value = blocchiSegnalati.join("\n\n==============================\n\n");
    console.log("✍️ Testo segmentato sostituito nel campo wpTextbox1");
}


  async function inviaTraduzione(blocchi, lingua, sostituisciTutto) {
function mostraPopupConferma(blocchi, errori, lingueDaTradurre, tutto) {
     const area = getEditor();
     const popup = document.createElement("div");
     if (!area) {
     popup.id = "popup-conferma-traduzione";
      alert("❌ Campo editor non trovato (wpTextbox1).");
    popup.style = `
      return;
        position: fixed; bottom: 20px; right: 20px;
     }
        background: white; padding: 15px; border: 2px solid #444;
        box-shadow: 4px 4px 10px rgba(0,0,0,0.3); z-index: 9999;
        resize: both; overflow: auto; cursor: move;
    `;
    popup.innerHTML = `
        <b>✅ Segmentazione completata</b><br>
        🧠 Token stimati: ~${blocchi.length * 3000}<br>
        💰 Costo approssimativo: ~$${(blocchi.length * 3000 * 0.00002).toFixed(2)}<br>
        ${errori.length > 0 ? `❗ <span style='color:red;'>${errori.length} errori rilevati. Procedere comunque?</span><br>` : `<span style='color:green;'>✅ Nessun errore rilevato</span><br>`}
        <button id="btn-invia-traduzione">✅ Invia</button>
        <button onclick="this.parentNode.remove()">❌ Annulla</button>
    `;
     document.body.appendChild(popup);


     let risultato = "";
     dragElement(popup);
    for (let i = 0; i < blocchi.length; i++) {
      console.log(`🚀 Invio blocco ${i + 1}/${blocchi.length}…`);
      const tradotto = await traduciBlocco(blocchi[i], lingua);
      risultato += tradotto.trim() + "\n\n";
    }
    risultato = risultato.trim();


    if (sostituisciTutto) {
  document.getElementById("btn-invia-traduzione").onclick = async () => {
      area.value = risultato;
    popup.remove();
     } else {
     console.log("📤 Invio confermato: avvio traduzione...");
      const { start, end } = getSelectedTextInfo();
    try {
      const prima = area.value.slice(0, start);
        await inviaTraduzione(blocchi, lingueDaTradurre[0], tutto);
      const dopo = area.value.slice(end);
    } catch (e) {
      area.value = prima + risultato + dopo;
        console.error("❌ Errore nell'invio della traduzione:", e);
      area.selectionStart = start;
        alert("Errore durante l'invio a OpenAI:\n" + e.message);
      area.selectionEnd = start + risultato.length;
     }
     }
};


    area.dispatchEvent(new Event("input", { bubbles: true }));
}
    area.dispatchEvent(new Event("change", { bubbles: true }));


    console.log("✅ Traduzione completata.");
function dragElement(elmnt) {
  }
    let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
 
    elmnt.onmousedown = dragMouseDown;
  async function traduciTesto() {
    function dragMouseDown(e) {
    const area = getEditor();
        e = e || window.event;
    if (!area) {
        e.preventDefault();
      alert("❌ Editor non trovato.");
        pos3 = e.clientX;
      return;
        pos4 = e.clientY;
        document.onmouseup = closeDragElement;
        document.onmousemove = elementDrag;
     }
     }
 
     function elementDrag(e) {
     const { text: selezione } = getSelectedTextInfo();
        e = e || window.event;
    const conferma = confirm(
        e.preventDefault();
      "Vuoi tradurre SOLO il testo selezionato?\n\n✅ OK = solo selezione\n❌ Annulla = tutto il testo"
        pos1 = pos3 - e.clientX;
    );
        pos2 = pos4 - e.clientY;
    if (conferma && !selezione) {
        pos3 = e.clientX;
      alert("⚠️ Nessuna selezione trovata.");
        pos4 = e.clientY;
      return;
        elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
        elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
     }
     }
     const testo = conferma ? selezione : area.value;
     function closeDragElement() {
    if (!testo.trim()) {
        document.onmouseup = null;
      alert("⚠️ Niente da tradurre.");
        document.onmousemove = null;
      return;
     }
     }
}
// ✅ Traduzione parziale o totale
async function inviaTraduzione(blocchi, lingua, tutto = true) {
  const model = window.openaiModel || "gpt-4o-2024-05-13";
  let testoTradotto = "";


    const lingua = prompt("🌍 Scegli lingua di traduzione (es: it, en, fr, es, de):", "it");
  console.log("🧪 Avvio inviaTraduzione()");
    if (!lingua) return;
  console.log("📦 Blocchi ricevuti:", blocchi);
  console.log("🌍 Lingua richiesta:", lingua);


    const blocchi = segmentaTesto(testo);
  for (let i = 0; i < blocchi.length; i++) {
     console.log("🧩 Segmenti:", blocchi.length);
     console.log(`🚀 Invio blocco ${i + 1}/${blocchi.length}...`);
     await inviaTraduzione(blocchi, lingua, !conferma);
     let tradotto = await traduciBlocco(blocchi[i], lingua);
    testoTradotto += tradotto + "\n\n";
   }
   }


   // Pulsante sotto editor
   const area = document.getElementById("wpTextbox1");
  function addTranslateButton() {
  if (!area) {
    const area = getEditor();
     console.warn("❌ Campo wpTextbox1 non trovato!");
    if (!area) return;
    return;
     if (document.getElementById("btnCommonTranslate")) return;
  }


    const btn = document.createElement("button");
  const start = area.selectionStart;
    btn.id = "btnCommonTranslate";
  const end = area.selectionEnd;
    btn.className = "mw-ui-button";
    btn.textContent = "🧠 Traduci contenuto";
    btn.style.margin = "8px 0";
    btn.addEventListener("click", traduciTesto);


     area.parentNode.insertBefore(btn, area.nextSibling);
  if (tutto) {
    area.value = testoTradotto.trim();
  } else {
     const prima = area.value.slice(0, start);
    const dopo = area.value.slice(end);
    area.value = prima + testoTradotto.trim() + dopo;
    area.selectionStart = start;
    area.selectionEnd = start + testoTradotto.trim().length;
   }
   }


   if (typeof $ !== "undefined") {
   area.dispatchEvent(new Event("input", { bubbles: true }));
     $(addTranslateButton);
  area.dispatchEvent(new Event("change", { bubbles: true }));
  } else {
 
    document.addEventListener("DOMContentLoaded", addTranslateButton);
  console.log("✅ Traduzione completata.");
  }
  return testoTradotto.trim();
}
 
 
 
// ✅  Traduzione  blocco
async function traduciBlocco(blocco, lingua) {
     try {
        let response = await fetch("https://api.openai.com/v1/chat/completions", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                "Authorization": `Bearer ${window.apiKey}`
            },
            body: JSON.stringify({
                model: window.openaiModel,
                messages: [
                    { role: "system", content: "You are a professional MediaWiki translator. Preserve all formatting, templates, and syntax." },
                    { role: "user", content: `Translate this text into ${lingua}:\n\n` + blocco }
                ],
                temperature: 0
            })
        });
 
        let data = await response.json();
        if (!response.ok) {
            throw new Error(data.error?.message || "Errore API generico");
        }
        return data.choices[0].message.content;
    } catch (error) {
        console.error("❌ Errore durante traduzione:", error);
        return "[Errore Traduzione]";
    }
}
}
// ✅ Aggiungi pulsante per avviare
$(function () {
    $("#wpTextbox1").after('<button id="pulsanteTraduci" class="btn">🧠 Traduci contenuto</button>');
    $("#pulsanteTraduci").on("click", traduciTesto);
});

Versione delle 14:20, 18 ago 2025

/* ======================= CommonTranslate.js ======================= */
console.log("🔄 Caricamento CommonTranslate.js...");

// ✅ Evita ricaricamento multiplo
if (window.CommonTranslateLoaded) {
    console.warn("⚠️ CommonTranslate.js è già stato caricato.");
} else {
    window.CommonTranslateLoaded = true;

    // ✅ Imposta lingua di origine (fallback su HTML lang o en)
    window.linguaOrigine = document.documentElement.lang || "en";

    // ✅ Imposta API key se non esiste
    if (!window.apiKey) {
        window.apiKey = "XXXXX";  // <--- Inserisci la tua API Key qui
    }

    // ✅ Definizione modello OpenAI
    window.openaiModel = "gpt-4o-2024-05-13";

    console.log("✅ CommonTranslate.js caricato correttamente!");
}


/* ======================= Funzione principale ======================= */
async function traduciTesto() {
  const area = document.getElementById("wpTextbox1");
  const start = area.selectionStart;
  const end = area.selectionEnd;
  const testoSelezionato = area.value.slice(start, end).trim();
  const tutto = !testoSelezionato;

  // ✅ Chiedi cosa tradurre
  const conferma = confirm("📝 Vuoi tradurre SOLO il testo selezionato?\n\n✅ OK = solo selezione\n❌ Annulla = tutto il testo");
  if (conferma && !testoSelezionato) {
    alert("⚠️ Nessuna parte selezionata. Se vuoi tradurre tutto, premi Annulla.");
    return;
  }

  const testo = tutto ? area.value : testoSelezionato;

  // ✅ STEP 1: Lingua
  const lingueDisponibili = ["it", "en", "fr", "es", "de"];
  let linguaScelta = prompt(
    "🌍 Scegli la lingua di traduzione:\n\nit = Italiano\nen = Inglese\nfr = Francese\nes = Spagnolo\nde = Tedesco",
    "it"
  );
  if (!linguaScelta) {
    console.warn("⚠️ Nessuna lingua selezionata.");
    return;
  }


 // ✅ STEP 2: Segmentazione
const blocchi = segmentaTesto(testo);
console.log(`🧩 Segmentazione: ${blocchi.length} blocchi trovati`);

if (tutto) {
  // 🔍 STEP 3: Analisi segmentazione + popup
  const errori = analizzaErroriSegmentazione(blocchi);
  sostituisciTestoSegmentato(blocchi, errori);
  mostraPopupConferma(blocchi, errori, [linguaScelta], tutto);
  return; // ⛔️ blocco qui: la traduzione partirà dal popup
}

  // ✅ STEP 3: Traduzione (passa il parametro `tutto`)
  const tradotto = await inviaTraduzione(blocchi, linguaScelta, tutto);

  // ✅ STEP 4: Inserimento nel campo editor
  if (tutto) {
    area.value = tradotto;
  } else {
    const prima = area.value.slice(0, start);
    const dopo = area.value.slice(end);
    area.value = prima + tradotto + dopo;
    area.selectionStart = start;
    area.selectionEnd = start + tradotto.length;
  }

  // ✅ STEP 5: Notifica
  area.dispatchEvent(new Event("input", { bubbles: true }));
  area.dispatchEvent(new Event("change", { bubbles: true }));

  console.log("✅ Traduzione completata e inserita correttamente.");
}


/* ======================= Funzioni di supporto ======================= */
function ottieniTestoDaEditor() {
    const area = document.getElementById("wpTextbox1");
    return area ? area.value.trim() : null;
}

function ottieniTestoSelezionato() {
    const area = document.getElementById("wpTextbox1");
    if (!area) return null;
    return area.value.substring(area.selectionStart, area.selectionEnd).trim() || null;
}

function segmentaTesto(testo, maxToken = 3000) {
    console.log("📌 Segmentazione in corso con max", maxToken, "tokens...");
    const blocchi = testo.match(new RegExp(`.{1,${maxToken}}(?=\\s|$)`, "gs")) || [];
    return blocchi;
}

function analizzaErroriSegmentazione(blocchi) {
    let errori = [];
    blocchi.forEach((blocco, i) => {
        let err = [];
        const count = (s, c) => (s.match(new RegExp(`\\${c}`, 'g')) || []).length;
        const parentesi = [["[", "]"], ["{", "}"], ["<", ">"]];
        parentesi.forEach(([open, close]) => {
            let openCount = count(blocco, open);
            let closeCount = count(blocco, close);
            if (openCount !== closeCount) {
                err.push(`Parentesi ${open}${close} non bilanciate: ${openCount} ${open}, ${closeCount} ${close}`);
            }
        });
        if (err.length > 0) {
            errori.push({ index: i + 1, dettagli: err });
        }
    });
    return errori;
}

function sostituisciTestoSegmentato(blocchi, errori) {
    const area = document.getElementById("wpTextbox1");
    if (!area) {
        console.warn("⚠️ Campo wpTextbox1 non trovato per sostituzione.");
        return;
    }
    const blocchiSegnalati = blocchi.map((b, i) => {
        const err = errori.find(e => e.index === i + 1);
        const erroreText = err ? `⚠️ ERRORI:\n- ${err.dettagli.join("\n- ")}\n\n` : "";
        return `${erroreText}🔹 BLOCCO ${i + 1}\n` + b;
    });
    area.value = blocchiSegnalati.join("\n\n==============================\n\n");
    console.log("✍️ Testo segmentato sostituito nel campo wpTextbox1");
}

function mostraPopupConferma(blocchi, errori, lingueDaTradurre, tutto) {
    const popup = document.createElement("div");
    popup.id = "popup-conferma-traduzione";
    popup.style = `
        position: fixed; bottom: 20px; right: 20px;
        background: white; padding: 15px; border: 2px solid #444;
        box-shadow: 4px 4px 10px rgba(0,0,0,0.3); z-index: 9999;
        resize: both; overflow: auto; cursor: move;
    `;
    popup.innerHTML = `
        <b>✅ Segmentazione completata</b><br>
        🧠 Token stimati: ~${blocchi.length * 3000}<br>
        💰 Costo approssimativo: ~$${(blocchi.length * 3000 * 0.00002).toFixed(2)}<br>
        ${errori.length > 0 ? `❗ <span style='color:red;'>${errori.length} errori rilevati. Procedere comunque?</span><br>` : `<span style='color:green;'>✅ Nessun errore rilevato</span><br>`}
        <button id="btn-invia-traduzione">✅ Invia</button>
        <button onclick="this.parentNode.remove()">❌ Annulla</button>
    `;
    document.body.appendChild(popup);

    dragElement(popup);

   document.getElementById("btn-invia-traduzione").onclick = async () => {
    popup.remove();
    console.log("📤 Invio confermato: avvio traduzione...");
    try {
        await inviaTraduzione(blocchi, lingueDaTradurre[0], tutto);
    } catch (e) {
        console.error("❌ Errore nell'invio della traduzione:", e);
        alert("Errore durante l'invio a OpenAI:\n" + e.message);
    }
};

}

function dragElement(elmnt) {
    let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
    elmnt.onmousedown = dragMouseDown;
    function dragMouseDown(e) {
        e = e || window.event;
        e.preventDefault();
        pos3 = e.clientX;
        pos4 = e.clientY;
        document.onmouseup = closeDragElement;
        document.onmousemove = elementDrag;
    }
    function elementDrag(e) {
        e = e || window.event;
        e.preventDefault();
        pos1 = pos3 - e.clientX;
        pos2 = pos4 - e.clientY;
        pos3 = e.clientX;
        pos4 = e.clientY;
        elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
        elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
    }
    function closeDragElement() {
        document.onmouseup = null;
        document.onmousemove = null;
    }
}
// ✅ Traduzione parziale o totale
async function inviaTraduzione(blocchi, lingua, tutto = true) {
  const model = window.openaiModel || "gpt-4o-2024-05-13";
  let testoTradotto = "";

  console.log("🧪 Avvio inviaTraduzione()");
  console.log("📦 Blocchi ricevuti:", blocchi);
  console.log("🌍 Lingua richiesta:", lingua);

  for (let i = 0; i < blocchi.length; i++) {
    console.log(`🚀 Invio blocco ${i + 1}/${blocchi.length}...`);
    let tradotto = await traduciBlocco(blocchi[i], lingua);
    testoTradotto += tradotto + "\n\n";
  }

  const area = document.getElementById("wpTextbox1");
  if (!area) {
    console.warn("❌ Campo wpTextbox1 non trovato!");
    return;
  }

  const start = area.selectionStart;
  const end = area.selectionEnd;

  if (tutto) {
    area.value = testoTradotto.trim();
  } else {
    const prima = area.value.slice(0, start);
    const dopo = area.value.slice(end);
    area.value = prima + testoTradotto.trim() + dopo;
    area.selectionStart = start;
    area.selectionEnd = start + testoTradotto.trim().length;
  }

  area.dispatchEvent(new Event("input", { bubbles: true }));
  area.dispatchEvent(new Event("change", { bubbles: true }));

  console.log("✅ Traduzione completata.");
  return testoTradotto.trim();
}



// ✅  Traduzione  blocco
async function traduciBlocco(blocco, lingua) {
    try {
        let response = await fetch("https://api.openai.com/v1/chat/completions", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                "Authorization": `Bearer ${window.apiKey}`
            },
            body: JSON.stringify({
                model: window.openaiModel,
                messages: [
                    { role: "system", content: "You are a professional MediaWiki translator. Preserve all formatting, templates, and syntax." },
                    { role: "user", content: `Translate this text into ${lingua}:\n\n` + blocco }
                ],
                temperature: 0
            })
        });

        let data = await response.json();
        if (!response.ok) {
            throw new Error(data.error?.message || "Errore API generico");
        }
        return data.choices[0].message.content;
    } catch (error) {
        console.error("❌ Errore durante traduzione:", error);
        return "[Errore Traduzione]";
    }
}

// ✅ Aggiungi pulsante per avviare
$(function () {
    $("#wpTextbox1").after('<button id="pulsanteTraduci" class="btn">🧠 Traduci contenuto</button>');
    $("#pulsanteTraduci").on("click", traduciTesto);
});