Last active
May 7, 2026 09:36
-
-
Save vaakx-dev/f410709a79de60a9449bc14310e76552 to your computer and use it in GitHub Desktop.
istrolid client translator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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