Nessun oggetto della modifica
Etichetta: Annullato
Nessun oggetto della modifica
Etichetta: Ripristino manuale
 
(5 versioni intermedie di uno stesso utente non sono mostrate)
Riga 1: Riga 1:
/* ======================= CommonTranslate.js (server-proxy) ======================= */
/* ======================= CommonTranslate.js (versione con proxy, stesso flusso) ======================= */
console.log("🔄 Caricamento CommonTranslate.js…");
console.log("🔄 Caricamento CommonTranslate.js...");


/* Evita doppi caricamenti */
// ✅ 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;


  /* === Config di base (senza API key nel client) === */
    // ✅ Lingua origine (fallback su html lang o en)
  window.linguaOrigine = document.documentElement.lang || "en";
    window.linguaOrigine = document.documentElement.lang || "en";
  const API_PROXY = "/dashboard/api/openai_project_gpt.php";   // il “cameriere”
 
  const MODEL_DEFAULT = "gpt-4o";                               // il server userà questo
    // ❌ Niente API key nel browser
  console.log("✅ CommonTranslate.js pronto (via proxy).");
    // ✅ Definisci solo il modello (verrà usato dal proxy; se vuoto userà il default server)
    window.openaiModel = window.openaiModel || "gpt-4o";
 
    // ✅ Endpoint proxy sul server (cameriere)
    window.OPENAI_PROXY_URL = "/dashboard/api/openai_project_gpt.php";
 
    console.log("✅ CommonTranslate.js caricato correttamente (via proxy).");
}
}


/* ======================= Azione principale ======================= */
/* ======================= Funzione principale ======================= */
async function traduciTesto() {
async function traduciTesto() {
   const area = document.getElementById("wpTextbox1");
   const area = document.getElementById("wpTextbox1");
   if (!area) { alert("Campo editor non trovato."); return; }
   if (!area) { alert("❌ Editor non trovato."); return; }


   const start = area.selectionStart;
   const start = area.selectionStart;
   const end  = area.selectionEnd;
   const end  = area.selectionEnd;
   const sel  = area.value.slice(start, end).trim();
   const testoSelezionato = area.value.slice(start, end).trim();
   const tutto = !sel;
   const tutto = !testoSelezionato;


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


   // 2) lingua di destinazione
  const testo = tutto ? area.value : testoSelezionato;
   const lingua = prompt(
  if (!testo.trim()) { alert("⚠️ Niente da tradurre."); return; }
     "🌍 Scegli la lingua di traduzione (it, en, fr, es, de):",
 
   // ✅ 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"
     "it"
   );
   );
   if (!lingua) { console.warn("⚠️ Lingua non indicata."); return; }
   if (!linguaScelta) {
    console.warn("⚠️ Nessuna lingua selezionata.");
    return;
  }


   // 3) segmentazione e (se tutto) pre-check
   // ✅ STEP 2: Segmentazione
   const blocchi = segmentaTesto(testo);
   const blocchi = segmentaTesto(testo);
   console.log(`🧩 Segmentazione: ${blocchi.length} blocchi`);
   console.log(`🧩 Segmentazione: ${blocchi.length} blocchi trovati`);


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


   // 4) traduzione diretta (solo selezione)
   // ✅ STEP 3: Traduzione (passa il parametro `tutto`)
   const tradotto = await inviaTraduzione(blocchi, lingua, tutto);
   const tradotto = await inviaTraduzione(blocchi, linguaScelta, tutto);


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


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


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


/* ======================= Utility ======================= */
/* ======================= Funzioni di supporto ======================= */
function segmentaTesto(testo, maxChars = 6000) {
function ottieniTestoDaEditor() {
   // segmentazione semplice per blocchi “morbidi” su spazi
  const area = document.getElementById("wpTextbox1");
   const re = new RegExp(`.{1,${maxChars}}(?=\\s|$)`, "gs");
  return area ? area.value.trim() : null;
  return testo.match(re) || [testo];
}
 
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) {
function analizzaErroriSegmentazione(blocchi) {
   const errors = [];
   let errori = [];
   const count = (s, ch) => (s.match(new RegExp(`\\${ch}`, "g")) || []).length;
   blocchi.forEach((blocco, i) => {
  const braces = [["[", "]"], ["{", "}"], ["<", ">"]];
    let err = [];
  blocchi.forEach((b, i) => {
    const count = (s, c) => (s.match(new RegExp(`\\${c}`, 'g')) || []).length;
    const e = [];
    const parentesi = [["[", "]"], ["{", "}"], ["<", ">"]];
     braces.forEach(([o, c]) => {
     parentesi.forEach(([open, close]) => {
       const co = count(b, o), cc = count(b, c);
       let openCount = count(blocco, open);
       if (co !== cc) e.push(`Parentesi ${o}${c} non bilanciate: ${co} ${o}, ${cc} ${c}`);
      let closeCount = count(blocco, close);
       if (openCount !== closeCount) {
        err.push(`Parentesi ${open}${close} non bilanciate: ${openCount} ${open}, ${closeCount} ${close}`);
      }
     });
     });
     if (e.length) errors.push({ index: i + 1, dettagli: e });
     if (err.length > 0) {
      errori.push({ index: i + 1, dettagli: err });
    }
   });
   });
   return errors;
   return errori;
}
}


function sostituisciTestoSegmentato(blocchi, errori) {
function sostituisciTestoSegmentato(blocchi, errori) {
   const area = document.getElementById("wpTextbox1");
   const area = document.getElementById("wpTextbox1");
   if (!area) return;
   if (!area) {
   const text = blocchi.map((b, i) => {
    console.warn("⚠️ Campo wpTextbox1 non trovato per sostituzione.");
     const err = errori.find(x => x.index === i + 1);
    return;
     const head = err ? `⚠️ ERRORI:\n- ${err.dettagli.join("\n- ")}\n\n` : "";
  }
     return `${head}🔹 BLOCCO ${i + 1}\n` + b;
   const blocchiSegnalati = blocchi.map((b, i) => {
   }).join("\n\n==============================\n\n");
     const err = errori.find(e => e.index === i + 1);
  area.value = text;
     const erroreText = err ? `⚠️ ERRORI:\n- ${err.dettagli.join("\n- ")}\n\n` : "";
   console.log("✍️ Testo segmentato inserito nel campo.");
     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, lingua, tutto) {
function mostraPopupConferma(blocchi, errori, lingueDaTradurre, tutto) {
   const popup = document.createElement("div");
   const popup = document.createElement("div");
   popup.id = "popup-conferma-traduzione";
   popup.id = "popup-conferma-traduzione";
   popup.style = `
   popup.style = `
     position: fixed; bottom: 20px; right: 20px;
     position: fixed; bottom: 20px; right: 20px;
     background: #fff; padding: 15px; border: 2px solid #444;
     background: white; padding: 15px; border: 2px solid #444;
     box-shadow: 4px 4px 10px rgba(0,0,0,.3); z-index: 9999;
     box-shadow: 4px 4px 10px rgba(0,0,0,0.3); z-index: 9999;
    resize: both; overflow: auto; cursor: move;
   `;
   `;
   popup.innerHTML = `
   popup.innerHTML = `
     <b>✅ Segmentazione completata</b><br>
     <b>✅ Segmentazione completata</b><br>
     Blocchi: ${blocchi.length}<br>
     🧠 Token stimati: ~${blocchi.length * 3000}<br>
     ${errori.length ? `<span style="color:#c00;">${errori.length} blocchi con parentesi non bilanciate</span><br>` : `✅ Nessun errore strutturale<br>`}
    💰 Costo approssimativo: ~$${(blocchi.length * 3000 * 0.00002).toFixed(2)}<br>
     <button id="btn-invia-traduzione">✅ Invia traduzione</button>
     ${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-close-popup">❌ Annulla</button>
     <button id="btn-invia-traduzione">✅ Invia</button>
     <button onclick="this.parentNode.remove()">❌ Annulla</button>
   `;
   `;
   document.body.appendChild(popup);
   document.body.appendChild(popup);


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


/* ======================= Traduzione via “cameriere” ======================= */
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;
  }
}
 
/* ======================= Invio traduzione (usa il CAMERIERE) ======================= */
async function inviaTraduzione(blocchi, lingua, tutto = true) {
async function inviaTraduzione(blocchi, lingua, tutto = true) {
   const area = document.getElementById("wpTextbox1");
   const model = window.openaiModel || "gpt-4o";
   if (!area) return "";
   let testoTradotto = "";


   let risultato = "";
   console.log("🧪 Avvio inviaTraduzione() via proxy");
   console.log("🧪 inviaTraduzione() → blocchi:", blocchi.length, "lingua:", lingua);
   console.log("📦 Blocchi ricevuti:", blocchi.length, "| 🌍 Lingua:", lingua);


   for (let i = 0; i < blocchi.length; i++) {
   for (let i = 0; i < blocchi.length; i++) {
     console.log(`🚀 Invio blocco ${i + 1}/${blocchi.length}…`);
     console.log(`🚀 Invio blocco ${i + 1}/${blocchi.length}…`);
     const trad = await traduciBloccoProxy(blocchi[i], lingua);
     let tradotto = await traduciBloccoProxy(blocchi[i], lingua, model);
     risultato += (trad || "[Errore Traduzione]") + "\n\n";
     testoTradotto += (tradotto || "[Errore Traduzione]") + "\n\n";
   }
   }


   const tradotto = risultato.trim();
   const area = document.getElementById("wpTextbox1");
  if (!area) { console.warn("❌ Campo wpTextbox1 non trovato!"); return ""; }
 
  const start = area.selectionStart;
  const end  = area.selectionEnd;
 
   if (tutto) {
   if (tutto) {
     area.value = tradotto;
     area.value = testoTradotto.trim();
   } else {
   } else {
    const start = area.selectionStart;
    const end  = area.selectionEnd;
     const prima = area.value.slice(0, start);
     const prima = area.value.slice(0, start);
     const dopo  = area.value.slice(end);
     const dopo  = area.value.slice(end);
     area.value = prima + tradotto + dopo;
     area.value = prima + testoTradotto.trim() + dopo;
     area.selectionStart = start;
     area.selectionStart = start;
     area.selectionEnd  = start + tradotto.length;
     area.selectionEnd  = start + testoTradotto.trim().length;
   }
   }


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


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


async function traduciBloccoProxy(blocco, lingua) {
/* ======================= Traduzione BLOCCO → via proxy ======================= */
   // Prompt “sicuro”: il server riceve solo il prompt, non la key
async function traduciBloccoProxy(blocco, lingua, model) {
  const system = "You are a professional MediaWiki translator. Preserve all templates, links, tags and wiki syntax exactly; translate only human-readable text. Keep headings and parameters unchanged.";
   try {
  const user  = `Translate the following MediaWiki wikitext into ${lingua}. Keep formatting/templates/links untouched:\n\n${blocco}`;
    const istruzioni = [
      "You are a professional MediaWiki translator.",
      "Translate the text preserving templates, links, headings, lists and any wiki syntax.",
      "Do not add comments or explanations.",
      `Source language: ${window.linguaOrigine}. Target language: ${lingua}.`
    ].join(" ");


  const prompt = [
    const prompt = `${istruzioni}\n\n--- TEXT START ---\n${blocco}\n--- TEXT END ---`;
    { role: "system", content: system },
    { role: "user",  content: user  }
  ];


  try {
     const res = await fetch(window.OPENAI_PROXY_URL, {
     const res = await fetch(API_PROXY, {
       method: "POST",
       method: "POST",
       headers: { "Content-Type": "application/json" },
       headers: { "Content-Type": "application/json" },
       body: JSON.stringify({
       body: JSON.stringify({ prompt, model })
        prompt: JSON.stringify(prompt), // il “cameriere” inoltra come chat
        model:  MODEL_DEFAULT
      })
     });
     });


     const data = await res.json().catch(() => ({}));
     const data = await res.json().catch(() => ({}));
     if (!res.ok || data.status !== "ok") {
     if (!res.ok || data.status === "error") {
       const msg = data?.error || `HTTP ${res.status}`;
       const msg = data?.error || `HTTP ${res.status}`;
       throw new Error(msg);
       console.error("❌ Errore da proxy:", msg);
      return "[Errore Traduzione]";
     }
     }
 
     return data.result || "";
    // Il cameriere risponde con {status:"ok", result:"…"}
     return (data.result || "").trim();
   } catch (err) {
   } catch (err) {
     console.error("❌ Errore da proxy:", err);
     console.error("❌ Errore durante traduzione (proxy):", err);
     return "[Errore Traduzione]";
     return "[Errore Traduzione]";
   }
   }
}
}


/* ======================= UI: pulsante in editor ======================= */
/* ======================= Pulsante sotto editor ======================= */
$(function () {
$(function () {
   const area = $("#wpTextbox1");
   if (!document.getElementById("wpTextbox1")) return;
   if (!area.length) return;
   if (document.getElementById("pulsanteTraduci")) return;


   if (!$("#pulsanteTraduci").length) {
   $("#wpTextbox1").after('<button id="pulsanteTraduci" class="btn">🧠 Traduci contenuto</button>');
    area.after('<button id="pulsanteTraduci" class="btn">🧠 Traduci contenuto</button>');
  $("#pulsanteTraduci").on("click", traduciTesto);
    $("#pulsanteTraduci").on("click", traduciTesto);
  }
});
});

Versione attuale delle 11:54, 6 dic 2025

/* ======================= CommonTranslate.js (versione con proxy, stesso flusso) ======================= */
console.log("🔄 Caricamento CommonTranslate.js...");

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

    // ✅ Lingua origine (fallback su html lang o en)
    window.linguaOrigine = document.documentElement.lang || "en";

    // ❌ Niente API key nel browser
    // ✅ Definisci solo il modello (verrà usato dal proxy; se vuoto userà il default server)
    window.openaiModel = window.openaiModel || "gpt-4o";

    // ✅ Endpoint proxy sul server (cameriere)
    window.OPENAI_PROXY_URL = "/dashboard/api/openai_project_gpt.php";

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

/* ======================= Funzione principale ======================= */
async function traduciTesto() {
  const area = document.getElementById("wpTextbox1");
  if (!area) { alert("❌ Editor non trovato."); return; }

  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;
  if (!testo.trim()) { alert("⚠️ Niente da tradurre."); return; }

  // ✅ 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 (via proxy):\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;
  }
}

/* ======================= Invio traduzione (usa il CAMERIERE) ======================= */
async function inviaTraduzione(blocchi, lingua, tutto = true) {
  const model = window.openaiModel || "gpt-4o";
  let testoTradotto = "";

  console.log("🧪 Avvio inviaTraduzione() via proxy");
  console.log("📦 Blocchi ricevuti:", blocchi.length, "| 🌍 Lingua:", lingua);

  for (let i = 0; i < blocchi.length; i++) {
    console.log(`🚀 Invio blocco ${i + 1}/${blocchi.length}…`);
    let tradotto = await traduciBloccoProxy(blocchi[i], lingua, model);
    testoTradotto += (tradotto || "[Errore Traduzione]") + "\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 → via proxy ======================= */
async function traduciBloccoProxy(blocco, lingua, model) {
  try {
    const istruzioni = [
      "You are a professional MediaWiki translator.",
      "Translate the text preserving templates, links, headings, lists and any wiki syntax.",
      "Do not add comments or explanations.",
      `Source language: ${window.linguaOrigine}. Target language: ${lingua}.`
    ].join(" ");

    const prompt = `${istruzioni}\n\n--- TEXT START ---\n${blocco}\n--- TEXT END ---`;

    const res = await fetch(window.OPENAI_PROXY_URL, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ prompt, model })
    });

    const data = await res.json().catch(() => ({}));
    if (!res.ok || data.status === "error") {
      const msg = data?.error || `HTTP ${res.status}`;
      console.error("❌ Errore da proxy:", msg);
      return "[Errore Traduzione]";
    }
    return data.result || "";
  } catch (err) {
    console.error("❌ Errore durante traduzione (proxy):", err);
    return "[Errore Traduzione]";
  }
}

/* ======================= Pulsante sotto editor ======================= */
$(function () {
  if (!document.getElementById("wpTextbox1")) return;
  if (document.getElementById("pulsanteTraduci")) return;

  $("#wpTextbox1").after('<button id="pulsanteTraduci" class="btn">🧠 Traduci contenuto</button>');
  $("#pulsanteTraduci").on("click", traduciTesto);
});