MediaWiki:CommonTranslate.js
Nota: dopo aver pubblicato, potrebbe essere necessario pulire la cache del proprio browser per vedere i cambiamenti.
- Firefox / Safari: tieni premuto il tasto delle maiuscole Shift e fai clic su Ricarica, oppure premi Ctrl-F5 o Ctrl-R (β-R su Mac)
- Google Chrome: premi Ctrl-Shift-R (β-Shift-R su un Mac)
- Edge: tieni premuto il tasto Ctrl e fai clic su Aggiorna, oppure premi Ctrl-F5.
/* ======================= 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 = "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"; // <--- 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);
});