Skip to content

Instantly share code, notes, and snippets.

@vaakx-dev
Last active May 7, 2026 09:36
Show Gist options
  • Select an option

  • Save vaakx-dev/f410709a79de60a9449bc14310e76552 to your computer and use it in GitHub Desktop.

Select an option

Save vaakx-dev/f410709a79de60a9449bc14310e76552 to your computer and use it in GitHub Desktop.
istrolid client translator
// arcon-manifest:
// name: istrolid-translator
// permissions: [chat, hud, ui.chat]
//
// istrolid client translator - by vaakx
// robust mixed-language handling via script-aware pre-filtering
(function () {
if (!window.arcon) {
console.error("istrolid_translator: arcon not found, load arcon.js first");
return;
}
if (!arcon.require({ major: 1, minor: 0 })) return;
var config = {
enabled: true,
default_language: "en",
dont_translate: ["en"]
};
// ------------------------------------------------------------------
// Pre-filter: ignore digits, spaces, and ASCII punctuation.
// If any character remains outside basic A-Z/a-z, forward to Google.
// ------------------------------------------------------------------
function should_translate(text) {
if (!text || typeof text !== "string") return false;
for (var i = 0; i < text.length; i++) {
var cp = text.charCodeAt(i);
// skip whitespace, digits, common ascii symbols
if (cp <= 0x20 || (cp >= 0x30 && cp <= 0x39) ||
(cp >= 0x21 && cp <= 0x2F) || (cp >= 0x3A && cp <= 0x40) ||
(cp >= 0x5B && cp <= 0x60) || (cp >= 0x7B && cp <= 0x7F)) {
continue;
}
// basic unaccented A-Z / a-z is normal English
if ((cp >= 0x41 && cp <= 0x5A) || (cp >= 0x61 && cp <= 0x7A)) {
continue;
}
// anything else (CJK, Hangul, Cyrillic, accented Latin, etc.)
return true;
}
return false;
}
// ------------------------------------------------------------------
// Google returns an array of sentence segments in data[0].
// We concatenate them all so multi-sentence messages are preserved.
// ------------------------------------------------------------------
function extract_translation(data) {
if (!data || !data[0] || !data[0].length) return null;
var out = "";
for (var i = 0; i < data[0].length; i++) {
if (data[0][i] && data[0][i][0]) out += data[0][i][0];
}
return out || null;
}
async function translate(msg) {
var url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=" +
encodeURIComponent(config.default_language) +
"&dt=t&q=" + encodeURIComponent(msg.text);
try {
var data = await fetch(url).then(function (r) { return r.json(); });
var detected = data[2];
if (config.dont_translate.indexOf(detected) !== -1 ||
detected === config.default_language) {
return;
}
var translated = extract_translation(data);
if (translated && translated !== msg.text) {
msg._original_text = msg.text;
msg._translated_text = translated;
msg.text = translated;
}
} catch (e) {
console.warn("istrolid_translator: fetch failed", e);
}
}
arcon.chat.on_message(function (msg) {
if (!config.enabled) return;
if (!msg || !msg.text) return;
if (typeof commander !== "undefined" && commander && msg.name === commander.name) return;
if (msg.name === "Server") return;
if (!should_translate(msg.text)) return;
translate(msg).then(function () {
if (typeof onecup !== "undefined") onecup.refresh();
});
});
// ------------------------------------------------------------------
// Per-message right-click menu items (requires arcon-ui)
// ------------------------------------------------------------------
if (arcon.ui_module && arcon.ui_module.chat && arcon.ui_module.chat.add_message_menu_item) {
arcon.ui_module.chat.add_message_menu_item({
label_fn: function () { return "Show original"; },
is_visible: function (msg) {
return !!msg._translated_text && msg.text === msg._translated_text;
},
on_click: function (msg) {
msg.text = msg._original_text;
if (typeof onecup !== "undefined") onecup.refresh();
arcon.ui.menu.close();
}
});
arcon.ui_module.chat.add_message_menu_item({
label_fn: function () { return "Show translated"; },
is_visible: function (msg) {
return !!msg._translated_text && msg.text === msg._original_text;
},
on_click: function (msg) {
msg.text = msg._translated_text;
if (typeof onecup !== "undefined") onecup.refresh();
arcon.ui.menu.close();
}
});
arcon.ui_module.chat.add_message_menu_item({
label_fn: function () { return "Force translate"; },
is_visible: function (msg) {
if (msg._translated_text) return false;
if (typeof commander !== "undefined" && commander && msg.name === commander.name) return false;
if (msg.name === "Server") return false;
return true;
},
on_click: function (msg) {
translate(msg).then(function () {
if (typeof onecup !== "undefined") onecup.refresh();
});
arcon.ui.menu.close();
}
});
}
arcon.hud.register("istrolid_translator", function () {}, {
mode: "any",
config: config
});
}.call(this));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment