MediaWiki:CommonTranslate.js: differenze tra le versioni
Nessun oggetto della modifica Etichetta: Annullato |
Nessun oggetto della modifica Etichetta: Annullato |
||
| Riga 1: | Riga 1: | ||
/* ======================= CommonTranslate.js ( | /* ======================= CommonTranslate.js (solo via proxy) ======================= */ | ||
console.log("🔄 Caricamento CommonTranslate.js…"); | console.log("🔄 Caricamento CommonTranslate.js…"); | ||
/ | // Evita ricarichi multipli | ||
if (window. | if (window.__CommonTranslateLoaded) { | ||
console.warn("⚠️ CommonTranslate.js è già stato caricato."); | console.warn("⚠️ CommonTranslate.js è già stato caricato."); | ||
} else { | } else { | ||
window. | window.__CommonTranslateLoaded = true; | ||
/ | // URL del proxy lato server (non mettere la chiave nel browser!) | ||
const PROXY_URL = "/w/proxy.php"; | |||
const | |||
const | // Modello di default (puoi cambiarlo qui o da window.openaiModel) | ||
const DEFAULT_MODEL = (window.openaiModel || "gpt-4o"); | |||
/ | // Lingua di origine (fallback) | ||
const LINGUA_ORIGINE = document.documentElement.lang || "en"; | |||
const | |||
console.log("✅ CommonTranslate.js pronto (via proxy). Modello:", DEFAULT_MODEL); | |||
/ | /* ======================= UTILITIES ======================= */ | ||
function getEditor() { | |||
return document.getElementById("wpTextbox1"); | |||
} | } | ||
function getSelectedTextInfo() { | |||
const area = getEditor(); | |||
if (!area) return { text: "", start: 0, end: 0 }; | |||
const start = area.selectionStart; | |||
const end = area.selectionEnd; | |||
const text = area.value.slice(start, end); | |||
return { text, start, end }; | |||
} | |||
function segmentaTesto(testo, maxChars = 3000) { | |||
// Segmenti “morbidi” a limite caratteri su spazio | |||
const re = new RegExp(`.{1,${maxChars}}(?=\\s|$)`, "gs"); | |||
return testo.match(re) || []; | |||
} | } | ||
// | // Chiamata singolo blocco al proxy | ||
async function traduciBloccoProxy(blocco, lingua, model = DEFAULT_MODEL) { | |||
try { | |||
const res = await fetch(PROXY_URL, { | |||
method: "POST", | |||
headers: { "Content-Type": "application/json" }, | |||
body: JSON.stringify({ | |||
model, | |||
messages: [ | |||
{ | |||
role: "system", | |||
content: | |||
"You are a professional MediaWiki translator. Translate preserving templates, links, headings, lists and any wiki syntax. Do not add explanations." | |||
}, | |||
{ | |||
role: "user", | |||
content: `Translate the following text from ${LINGUA_ORIGINE} to ${lingua}:\n\n${blocco}` | |||
} | |||
], | |||
temperature: 0 | |||
}) | |||
}); | |||
const data = await res.json(); | |||
if (!res.ok) { | |||
const msg = data?.error || `HTTP ${res.status}`; | |||
throw new Error(msg); | |||
} | |||
const content = data?.choices?.[0]?.message?.content ?? ""; | |||
return content || "[Traduzione vuota]"; | |||
} catch (err) { | |||
console.error("❌ Errore da proxy:", err); | |||
return "[Errore Traduzione via proxy]"; | |||
} | |||
} | } | ||
async function inviaTraduzione(blocchi, lingua, sostituisciTutto) { | |||
const area = getEditor(); | |||
if (!area) { | |||
alert("❌ Campo editor non trovato (wpTextbox1)."); | |||
return; | |||
} | |||
let risultato = ""; | |||
} | for (let i = 0; i < blocchi.length; i++) { | ||
console.log(`🚀 Invio blocco ${i + 1}/${blocchi.length}…`); | |||
const tradotto = await traduciBloccoProxy(blocchi[i], lingua); | |||
risultato += tradotto.trim() + "\n\n"; | |||
} | |||
risultato = risultato.trim(); | |||
if (sostituisciTutto) { | |||
area.value = risultato; | |||
} else { | |||
const { start, end } = getSelectedTextInfo(); | |||
const prima = area.value.slice(0, start); | |||
} | const dopo = area.value.slice(end); | ||
area.value = prima + risultato + dopo; | |||
area.selectionStart = start; | |||
area.selectionEnd = start + risultato.length; | |||
} | |||
// Notifica a MediaWiki | |||
area.dispatchEvent(new Event("input", { bubbles: true })); | |||
area.dispatchEvent(new Event("change", { bubbles: true })); | |||
console.log("✅ Traduzione completata e inserita."); | |||
} | |||
} | |||
function | /* ======================= FLOW PRINCIPALE ======================= */ | ||
async function traduciTesto() { | |||
const area = getEditor(); | |||
if (!area) { | |||
alert("❌ Editor non trovato."); | |||
return; | |||
} | |||
// Solo selezione o tutto? | |||
const { text: selezione } = getSelectedTextInfo(); | |||
const conferma = confirm( | |||
"📝 Vuoi tradurre SOLO il testo selezionato?\n\n✅ OK = solo selezione\n❌ Annulla = tutto il testo" | |||
); | |||
if (conferma && !selezione) { | |||
alert("⚠️ Nessuna selezione. Premi Annulla per tradurre tutto il testo."); | |||
return; | |||
} | |||
const testo = conferma ? selezione : area.value; | |||
if (!testo.trim()) { | |||
alert("⚠️ Niente da tradurre."); | |||
return; | |||
} | } | ||
/ | // Lingua destinazione | ||
const lingua = prompt( | |||
"🌍 Scegli la lingua di traduzione (es: it, en, fr, es, de):", | |||
"it" | |||
); | |||
if (!lingua) return; | |||
// Segmentazione e invio | |||
const blocchi = segmentaTesto(testo); | |||
console.log("🧩 Segmentazione:", blocchi.length, "blocchi"); | |||
await inviaTraduzione(blocchi, lingua, !conferma); | |||
} | } | ||
/* ======================= UI: PULSANTE ======================= */ | |||
// Aggiunge un bottone sotto l’editor | |||
function addTranslateButton() { | |||
const area = getEditor(); | |||
const | if (!area) return; | ||
if (document.getElementById("btnCommonTranslate")) return; | |||
const btn = document.createElement("button"); | |||
btn.id = "btnCommonTranslate"; | |||
btn.className = "mw-ui-button"; | |||
btn.textContent = "🧠 Traduci contenuto (via proxy)"; | |||
btn.style.margin = "8px 0"; | |||
btn.addEventListener("click", traduciTesto); | |||
area.parentNode.insertBefore(btn, area.nextSibling); | |||
} | |||
} | |||
// jQuery ready + fallback | |||
// | if (typeof $ !== "undefined") { | ||
$(addTranslateButton); | |||
} else { | |||
document.addEventListener("DOMContentLoaded", addTranslateButton); | |||
} | |||
} | } | ||
} | } | ||
Versione delle 14:12, 18 ago 2025
/* ======================= CommonTranslate.js (solo via proxy) ======================= */
console.log("🔄 Caricamento CommonTranslate.js…");
// Evita ricarichi multipli
if (window.__CommonTranslateLoaded) {
console.warn("⚠️ CommonTranslate.js è già stato caricato.");
} else {
window.__CommonTranslateLoaded = true;
// URL del proxy lato server (non mettere la chiave nel browser!)
const PROXY_URL = "/w/proxy.php";
// Modello di default (puoi cambiarlo qui o da window.openaiModel)
const DEFAULT_MODEL = (window.openaiModel || "gpt-4o");
// Lingua di origine (fallback)
const LINGUA_ORIGINE = document.documentElement.lang || "en";
console.log("✅ CommonTranslate.js pronto (via proxy). Modello:", DEFAULT_MODEL);
/* ======================= UTILITIES ======================= */
function getEditor() {
return document.getElementById("wpTextbox1");
}
function getSelectedTextInfo() {
const area = getEditor();
if (!area) return { text: "", start: 0, end: 0 };
const start = area.selectionStart;
const end = area.selectionEnd;
const text = area.value.slice(start, end);
return { text, start, end };
}
function segmentaTesto(testo, maxChars = 3000) {
// Segmenti “morbidi” a limite caratteri su spazio
const re = new RegExp(`.{1,${maxChars}}(?=\\s|$)`, "gs");
return testo.match(re) || [];
}
// Chiamata singolo blocco al proxy
async function traduciBloccoProxy(blocco, lingua, model = DEFAULT_MODEL) {
try {
const res = await fetch(PROXY_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model,
messages: [
{
role: "system",
content:
"You are a professional MediaWiki translator. Translate preserving templates, links, headings, lists and any wiki syntax. Do not add explanations."
},
{
role: "user",
content: `Translate the following text from ${LINGUA_ORIGINE} to ${lingua}:\n\n${blocco}`
}
],
temperature: 0
})
});
const data = await res.json();
if (!res.ok) {
const msg = data?.error || `HTTP ${res.status}`;
throw new Error(msg);
}
const content = data?.choices?.[0]?.message?.content ?? "";
return content || "[Traduzione vuota]";
} catch (err) {
console.error("❌ Errore da proxy:", err);
return "[Errore Traduzione via proxy]";
}
}
async function inviaTraduzione(blocchi, lingua, sostituisciTutto) {
const area = getEditor();
if (!area) {
alert("❌ Campo editor non trovato (wpTextbox1).");
return;
}
let risultato = "";
for (let i = 0; i < blocchi.length; i++) {
console.log(`🚀 Invio blocco ${i + 1}/${blocchi.length}…`);
const tradotto = await traduciBloccoProxy(blocchi[i], lingua);
risultato += tradotto.trim() + "\n\n";
}
risultato = risultato.trim();
if (sostituisciTutto) {
area.value = risultato;
} else {
const { start, end } = getSelectedTextInfo();
const prima = area.value.slice(0, start);
const dopo = area.value.slice(end);
area.value = prima + risultato + dopo;
area.selectionStart = start;
area.selectionEnd = start + risultato.length;
}
// Notifica a MediaWiki
area.dispatchEvent(new Event("input", { bubbles: true }));
area.dispatchEvent(new Event("change", { bubbles: true }));
console.log("✅ Traduzione completata e inserita.");
}
/* ======================= FLOW PRINCIPALE ======================= */
async function traduciTesto() {
const area = getEditor();
if (!area) {
alert("❌ Editor non trovato.");
return;
}
// Solo selezione o tutto?
const { text: selezione } = getSelectedTextInfo();
const conferma = confirm(
"📝 Vuoi tradurre SOLO il testo selezionato?\n\n✅ OK = solo selezione\n❌ Annulla = tutto il testo"
);
if (conferma && !selezione) {
alert("⚠️ Nessuna selezione. Premi Annulla per tradurre tutto il testo.");
return;
}
const testo = conferma ? selezione : area.value;
if (!testo.trim()) {
alert("⚠️ Niente da tradurre.");
return;
}
// Lingua destinazione
const lingua = prompt(
"🌍 Scegli la lingua di traduzione (es: it, en, fr, es, de):",
"it"
);
if (!lingua) return;
// Segmentazione e invio
const blocchi = segmentaTesto(testo);
console.log("🧩 Segmentazione:", blocchi.length, "blocchi");
await inviaTraduzione(blocchi, lingua, !conferma);
}
/* ======================= UI: PULSANTE ======================= */
// Aggiunge un bottone sotto l’editor
function addTranslateButton() {
const area = getEditor();
if (!area) return;
if (document.getElementById("btnCommonTranslate")) return;
const btn = document.createElement("button");
btn.id = "btnCommonTranslate";
btn.className = "mw-ui-button";
btn.textContent = "🧠 Traduci contenuto (via proxy)";
btn.style.margin = "8px 0";
btn.addEventListener("click", traduciTesto);
area.parentNode.insertBefore(btn, area.nextSibling);
}
// jQuery ready + fallback
if (typeof $ !== "undefined") {
$(addTranslateButton);
} else {
document.addEventListener("DOMContentLoaded", addTranslateButton);
}
}