GhostOfBitcoin (OP)
Newbie

Activity: 28
Merit: 10
|
 |
May 25, 2026, 02:30:20 PM Last edit: Today at 08:56:12 PM by GhostOfBitcoin |
|
Hello I am a skilled and passionate full-stack developer, skilled in building scalable, secure, and user-friendly applications using modern web technologies. I am comfortable working with React, Next.js, Node.js, Express, MongoDB, MySQL, and REST APIs. I have recently been working on creating a modern and very lightweight Translator Userscript for the Bitcointalk forum, the main goal of which is to remove the language barrier of various local boards and make the forum easier to use for international users. Currently, reading posts in different languages on Bitcointalk often requires using an external translator, which slows down the browsing experience and disrupts the discussion flow. To solve this problem, I am creating [UserScript] Bitcointalk Translator with modern UI and multi-language support. Main purpose:This userscript can be used to instantly translate any post, PM, quote, reply, or thread. It is designed to provide a modern translation experience without breaking the classic UI of Bitcointalk. Main Features:- One Click Translation: There will be a Translate button at the bottom of each post.
- Instant Translation: Real-time translation without page reload
- Multi-Language Support Currently added: العربية (Arabic), Indonesian, Spanish, Chinese, Croatian, German, Greek, Hebrew, Français, Hindi, Italian, Japanese, Nederlands, Korean, Pilipinas, Portuguese, Russian, Romanian, Turkish, Urdu, and বাংলা.
- Text to Speech: You can also listen to translated text.
- Side-by-Side Mode: Enables viewing of original and translated text simultaneously.
- Optimized interface for both desktop and mobile.
https://i.bitlist.co/GndD53rg.png https://i.bitlist.co/NSHFMW0b.png https://i.bitlist.co/YocSJvbs.pngInstallation// ==UserScript== // @name Bitcointalk Userscript Translator // @namespace https://bitcointalk.org/ // @version 3.0.0 // @description Bitcointalk Translator with modern UI and multi-language support // @author Crypto Community // @match https://bitcointalk.org/* // @icon https://bitcointalk.org/favicon.ico // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @connect translate.googleapis.com // @run-at document-end // ==/UserScript==
(function () {
'use strict';
/* ========================================================= CONFIG ========================================================= */
const CONFIG = {
targetLanguage: GM_getValue('btc_target_lang', 'en'),
sideBySide: GM_getValue('btc_side_by_side', false),
autoTranslate: GM_getValue('btc_auto_translate', false),
accent: GM_getValue('btc_accent', '#f7931a')
};
/* ========================================================= STYLES ========================================================= */
GM_addStyle(`
.btc-translate-btn{
display:inline-flex; align-items:center; gap:5px;
padding:4px 10px; margin-top:6px;
border-radius:8px;
background:rgba(247,147,26,.12);
border:1px solid rgba(247,147,26,.25);
color:${CONFIG.accent};
cursor:pointer;
font-size:12px; font-weight:600;
transition:.2s ease; }
.btc-translate-btn:hover{
transform:translateY(-1px);
background:rgba(247,147,26,.2); }
.btc-translation-box{
margin-top:12px;
padding:14px;
border-radius:12px;
background:rgba(0,0,0,.18);
border-left:3px solid ${CONFIG.accent};
line-height:1.8;
animation:btcFade .2s ease;
word-break:break-word;
overflow-wrap:break-word; }
.btc-head{
display:flex;
justify-content:space-between;
align-items:center;
margin-bottom:10px; }
.btc-tools{
display:flex; gap:8px; }
.btc-tool{
border:none;
padding:4px 8px;
border-radius:6px;
cursor:pointer;
background:rgba(255,255,255,.08);
color:#fff;
font-size:12px; }
.btc-panel{
position:fixed;
right:20px; bottom:20px;
width:260px;
z-index:999999;
background:#111;
color:#fff;
padding:16px;
border-radius:16px;
box-shadow:0 10px 30px rgba(0,0,0,.45);
font-family:Arial,sans-serif; }
.btc-panel-title{
font-size:15px;
font-weight:bold;
color:${CONFIG.accent};
margin-bottom:14px; }
.btc-panel select{
width:100%;
margin-bottom:12px;
padding:8px;
border-radius:8px;
border:none;
background:#222;
color:#fff;
font-size:14px; }
.btc-thread-btn{
width:100%;
border:none;
padding:10px;
border-radius:10px;
background:${CONFIG.accent};
color:#fff;
cursor:pointer;
font-weight:bold; }
.btc-arabic{
direction:rtl;
text-align:right;
font-family: "Tahoma", "Arial", sans-serif;
line-height:2; }
@keyframes btcFade{
from{
opacity:0;
transform:translateY(8px); }
to{
opacity:1;
transform:translateY(0); } }
@media(max-width:768px){
.btc-panel{
width:calc(100vw - 30px);
left:15px;
right:15px;
bottom:15px; } }
`);
/* ========================================================= CACHE ========================================================= */
class TranslationCache {
constructor(){
this.prefix = 'btc_translation_'; }
get(key){
return localStorage.getItem( this.prefix + key ); }
set(key, value){
localStorage.setItem( this.prefix + key, value ); }
hash(str){
let hash = 0;
for(let i = 0; i < str.length; i++){
hash = ((hash << 5) - hash) + str.charCodeAt(i);
hash |= 0; }
return hash; } }
const cache = new TranslationCache();
/* ========================================================= ESCAPE HTML ========================================================= */
function escapeHTML(str){
return str .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>'); }
/* ========================================================= TRANSLATION ENGINE ========================================================= */
async function translateText(text, target = 'en') {
if(!text || text.length < 2){
return text; }
const cacheKey = cache.hash(text + target);
const cached = cache.get(cacheKey);
if(cached){
return cached; }
try{
const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=${target}&dt=t&q=${encodeURIComponent(text)}`;
const response = await fetch(url);
const data = await response.json();
let translated = '';
data[0].forEach(item => {
translated += item[0]; });
if(!translated){
translated = text; }
cache.set(cacheKey, translated);
return translated;
}catch(error){
console.error( 'Translation Error:', error );
return text; } }
/* ========================================================= TRANSLATION BOX ========================================================= */
function createTranslationBox(original, translated){
const isArabic = CONFIG.targetLanguage === 'ar';
const box = document.createElement('div');
box.className = 'btc-translation-box';
if(isArabic){
box.classList.add('btc-arabic'); }
box.innerHTML = `
<div class="btc-head">
<strong> 🌐 Translation </strong>
<div class="btc-tools">
<button class="btc-tool btc-copy"> Copy </button>
<button class="btc-tool btc-speak"> 🔊 </button>
<button class="btc-tool btc-close"> ✖ </button>
</div>
</div>
<div class="btc-content">
${ CONFIG.sideBySide
?
`
<div style="margin-bottom:14px;">
<b>Original:</b>
<div style="margin-top:6px;"> ${escapeHTML(original)} </div>
</div>
<div>
<b>Translated:</b>
<div style="margin-top:6px;"> ${escapeHTML(translated)} </div>
</div>
`
:
escapeHTML(translated) }
</div>
`;
/* COPY */
box.querySelector('.btc-copy') .addEventListener('click', () => {
navigator.clipboard.writeText( translated ); });
/* SPEECH */
box.querySelector('.btc-speak') .addEventListener('click', () => {
const speech = new SpeechSynthesisUtterance( translated );
speech.lang = CONFIG.targetLanguage;
speechSynthesis.speak(speech); });
/* CLOSE */
box.querySelector('.btc-close') .addEventListener('click', () => {
box.remove(); });
return box; }
/* ========================================================= PROCESS POSTS ========================================================= */
async function processPost(post){
if(post.dataset.btcReady){
return; }
post.dataset.btcReady = 'true';
const footer = post.querySelector('.smalltext');
const content = post.querySelector('.post');
if(!footer || !content){
return; }
const button = document.createElement('div');
button.className = 'btc-translate-btn';
button.innerHTML = '🌐 Translate';
footer.appendChild(button);
button.addEventListener( 'click', async () => {
const old = post.querySelector( '.btc-translation-box' );
if(old){
old.remove();
return; }
const text = content.innerText.trim();
if(!text){
return; }
button.innerHTML = '⏳ Translating...';
const translated = await translateText( text, CONFIG.targetLanguage );
const box = createTranslationBox( text, translated );
content.appendChild(box);
button.innerHTML = '✅ Done';
setTimeout(() => {
button.innerHTML = '🌐 Translate';
}, 1500);
} );
if(CONFIG.autoTranslate){
button.click(); } }
/* ========================================================= OBSERVER ========================================================= */
function observeForum(){
const observer = new MutationObserver(() => {
const posts = document.querySelectorAll( 'td.windowbg, td.windowbg2' );
posts.forEach( processPost );
});
observer.observe( document.body, { childList:true, subtree:true } );
const initialPosts = document.querySelectorAll( 'td.windowbg, td.windowbg2' );
initialPosts.forEach( processPost ); }
/* ========================================================= SETTINGS PANEL ========================================================= */
function createPanel(){
const panel = document.createElement('div');
panel.className = 'btc-panel';
panel.innerHTML = `
<div class="btc-panel-title">
Bitcointalk Translator
</div>
<label> Translation Language </label>
<select id="btc-lang">
<option value="ar">العربية (Arabic)</option>
<option value="id">Indonesian</option>
<option value="es">Spanish</option>
<option value="zh-CN">Chinese</option>
<option value="hr">Croatian</option>
<option value="de">German</option>
<option value="el">Greek</option>
<option value="he">Hebrew</option>
<option value="fr">Français</option>
<option value="hi">India</option>
<option value="it">Italian</option>
<option value="ja">Japanese</option>
<option value="nl">Nederlands</option>
<option value="yo">Nigeria</option>
<option value="ko">Korean</option>
<option value="tl">Pilipinas</option>
<option value="pt">Portuguese</option>
<option value="ru">Russian</option>
<option value="ro">Romanian</option>
<option value="sv">Skandinavisk</option>
<option value="tr">Turkish</option>
<option value="ur">Pakistan</option>
<option value="bn">বাংলা</option>
</select>
<label style="display:block;margin-bottom:10px;">
<input type="checkbox" id="btc-side" ${CONFIG.sideBySide ? 'checked' : ''} >
Side-by-Side Mode
</label>
<label style="display:block;margin-bottom:14px;">
<input type="checkbox" id="btc-auto" ${CONFIG.autoTranslate ? 'checked' : ''} >
Auto Translate
</label>
<button class="btc-thread-btn">
Translate Entire Thread
</button>
`;
document.body.appendChild(panel);
const lang = panel.querySelector('#btc-lang');
lang.value = CONFIG.targetLanguage;
lang.addEventListener( 'change', e => {
CONFIG.targetLanguage = e.target.value;
GM_setValue( 'btc_target_lang', e.target.value ); } );
panel.querySelector('#btc-side') .addEventListener( 'change', e => {
CONFIG.sideBySide = e.target.checked;
GM_setValue( 'btc_side_by_side', e.target.checked ); } );
panel.querySelector('#btc-auto') .addEventListener( 'change', e => {
CONFIG.autoTranslate = e.target.checked;
GM_setValue( 'btc_auto_translate', e.target.checked ); } );
panel.querySelector('.btc-thread-btn') .addEventListener( 'click', async () => {
const buttons = document.querySelectorAll( '.btc-translate-btn' );
for(const btn of buttons){
btn.click();
await sleep(400); } } ); }
/* ========================================================= UTILITIES ========================================================= */
function sleep(ms){
return new Promise(resolve => {
setTimeout(resolve, ms);
}); }
/* ========================================================= SHORTCUTS ========================================================= */
function shortcuts(){
document.addEventListener( 'keydown', e => {
if( e.altKey && e.key === 't' ){
const first = document.querySelector( '.btc-translate-btn' );
if(first){
first.click(); } } } ); }
/* ========================================================= INIT ========================================================= */
function init(){
console.log( 'Bitcointalk Translator Ultimate Loaded' );
observeForum();
createPanel();
shortcuts(); }
init();
})();
New Update:Greasyfork link for one click install : https://greasyfork.org/en/scripts/579899-bitcointalk-translator- Translation engine fix
- Arabic language rendering fix
- Floating translator button redesign
- Draggable floating button
- Faster drag movement optimization
- Toggle panel system
- New modern UI design
- Cache system optimize
- Mobile responsive UI improve
- Performance optimization
Any feedback, suggestions, or problem reports from you will help me to work better and more effectively. I always try to learn new things and improve my skills, so I give great importance to constructive feedback. If you find any problems or want to share any new ideas, then feel free to let me know. I'm trying to create another userscript tool for the Bitcointalk community.
|
|
|
|
|
|
SquirrelJulietGarden
|
 |
May 25, 2026, 02:41:31 PM |
|
Main purpose:
This userscript can be used to instantly translate any post, PM, quote, reply, or thread. It is designed to provide a modern translation experience without breaking the classic UI of Bitcointalk.
There is another userscript for translation and that one was announced before yours. One Click Bitcointalk Post Translator (No Copy-Paste Needed).Just informing your about that for reference, perhaps it can be helpful or useless for you but because I am not interested in translator user script, I don't mind to check differences between two user scripts.
|
.Winna.com.. | │ | ░░░░░░░▄▀▀▀ ░░█ █ █▒█ ▐▌▒▐▌ ▄▄▄█▒▒▒█▄▄▄ █████████████ █████████████ ▀███▀▒▀███▀
▄▄▄▄▄▄▄▄
| | ██████████████ █████████████▄ █████▄████████ ███▄███▄█████▌ ███▀▀█▀▀██████ ████▀▀▀█████▌█ ██████████████ ███████████▌██ █████▀▀▀██████
▄▄▄▄▄▄▄▄
| | | THE ULTIMATE CRYPTO ...CASINO & SPORTSBOOK... ───── ♠ ♥ ♣ ♦ ───── | | | ▄▄██▄▄ ▄▄████████▄▄ ▄██████████████▄ ████████████████ ████████████████ ████████████████ ▀██████████████▀ ▀██████████▀ ▀████▀
▄▄▄▄▄▄▄▄
| | ▄▄▀███▀▄▄ ▄███████████▄ ███████████████ ███▄▄█▄███▄█▄▄███ █████▀█████▀█████ █████████████████ ███████████████ ▀███████████▀ ▀▀█████▀▀
▄▄▄▄▄▄▄▄
| │ | ►
► | .....INSTANT..... WITHDRAWALS ...UP TO 30%... LOSSBACK | │ |
| │ |
PLAY NOW |
|
|
|
Pmalek
Legendary

Activity: 3500
Merit: 9268
|
Web browsers have translation tools that can translate from A to B if you don't understand the original language. The automated translations are good on both Firefox and Chrome. Sometimes they don't detect a page as not being in English, but the translation feature can still be accessed with a few clicks.
If you were to compare the in-built browser translations with the script you built, what would you say should be reasons for me to use the translator that you have built?
|
| EARNBET | ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ | ███████▄▄███████████ ████▄██████████████████ ██▄▀▀███████████████▀▀███ █▄████████████████████████ ▄▄████████▀▀▀▀▀████████▄▄██ ███████████████████████████ █████████▌████▀████████████ ███████████████████████████ ▀▀███████▄▄▄▄▄█████████▀▀██ █▀█████████████████████▀██ ██▀▄▄███████████████▄▄███ ████▀██████████████████ ███████▀▀███████████ | | ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ |
▄▄▄ ▄▄▄███████▐███▌███████▄▄▄ █████████████████████████ ▀████▄▄▄███████▄▄▄████▀ █████████████████████ ▐███████████████████▌ ███████████████████ ███████████████████ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
| King of The Castle $200,000 in prizes | ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ | 62.5% | RAKEBACK BONUS |
|
|
|
GhostOfBitcoin (OP)
Newbie

Activity: 28
Merit: 10
|
 |
May 25, 2026, 05:21:23 PM |
|
Web browsers have translation tools that can translate from A to B if you don't understand the original language. The automated translations are good on both Firefox and Chrome. Sometimes they don't detect a page as not being in English, but the translation feature can still be accessed with a few clicks.
If you were to compare the in-built browser translations with the script you built, what would you say should be reasons for me to use the translator that you have built?
Good question. If we look closely, we will see that the purpose of the browser's built-in translator and my userscript translator are the same. However, there are some advantages or reasons to use this userscript for forums. For example: 1. If you notice, the browser's built-in translator translates the entire page at once. You can't translate any of your specific posts separately even if you want to. But if you use this userscript, you can translate the specific post of your choice while keeping the layout or design of the forum intact. 2. When you use the browser's built-in translator to translate, you have to reload the page repeatedly. However, using this userscript, you can get the translation directly within the post with just one click, without any reloading. 3. You yourself said that sometimes the browser cannot detect English or other languages correctly. But since this userscript has the option to manually select the source language, that problem will not occur at all. 4. It is completely open source. So you can modify its code to your own convenience if you want. Also, you can use it completely safely without any fear of data tracking or information theft. 5. With a cache system, there will be no need to translate the same post repeatedly. 6. It has the ability to view the original content and translations side by side. In addition, you will also get a special feature to auto-translate all posts. Browser translator is definitely best for general browsing, but for those who spend regular time on forums and want to get things done quickly, this script can be a great shortcut. I hope you give it a try!
|
|
|
|
|
dkbit98
Legendary

Activity: 2968
Merit: 8685
AntiSwap.io - NO AML/KYC EXCHANGER MONITORING
|
 |
May 25, 2026, 05:28:36 PM |
|
OP can you tell us something, did you use AI tools in creating this userscript? If the answer is YES, than you need to give credits what exactly you used. Web browsers have translation tools that can translate from A to B if you don't understand the original language. The automated translations are good on both Firefox and Chrome. Sometimes they don't detect a page as not being in English, but the translation feature can still be accessed with a few clicks.
Correct, and I honestly don't understand why anyone would create translation tool that works only for bitcointalk forum. It's not like this userscript is using something special, it's just same g00gle translate crap.
|
|
|
|
|
|
[center][table][tr][td][font=Arial Black][size=24pt][glow=#222,1][nbsp][url=https://en.antiswap.io/?utm_source=bitcointalk_s3][size=5pt][sup][size=21pt][b][color=#03adfd]🛡[/b][/sup][/size][size=13pt][nbsp][/size][size=5pt][sup][size=18pt][color=#fff]Anti[color=#3b82f6]Swap[/sup][/size][nbsp][nbsp][size=14pt][sup][size=8pt][i][color=#fff]NO[nbsp]AML/KYC—EXCHANGER[nbsp]MONITORING[/sup][/size][nbsp][nbsp][size=6pt][sup][size=16pt][glow=#03adfd,1][nbsp][font=Impact][color=#fff]900+[/font][nbsp][/glow][/size][/sup][/size][size=6pt][sup][size=16pt][glow=#3b82f6,1][nbsp][size=8pt][sup][size=8pt][color=#fff]EXCHANGERS[/size][/sup][/size][nbsp][/glow][/size][/sup][/size][/url][nbsp][nbsp][font=Arial][b][size=14pt][sup][size=8pt][url=https://bitcointalk.org/index.php?topic=5568680.msg66184227#msg66184227][color=#fff]BITCOINTALK[/url][/size][/sup][/size][/font][nbsp][size=9pt][sup][size=18pt][color=#3b82f6]│[/size][/sup][/size][nbsp][font=Arial][b][size=14pt][sup][size=8pt][url=https://t.me/+qGCCD6ncnctiZTli][color=#fff]TELEGRAM[/url][/size][/sup][/size][/font][nbsp][nbsp][/td][/tr][/table][/center]
|
|
|
GhostOfBitcoin (OP)
Newbie

Activity: 28
Merit: 10
|
 |
May 25, 2026, 06:14:26 PM |
|
OP can you tell us something, did you use AI tools in creating this userscript? If the answer is YES, than you need to give credits what exactly you used.
I am a skilled and passionate full-stack developer, skilled in building scalable, secure, and user-friendly applications using modern web technologies.
My friend... Can userscripts be created using AI tools? I don't know for sure. If so, please tell me which tools to use. (Off-topic: Because this might help me in my important work in the future. It's worth mentioning that I am currently employed as a junior full-stack developer.)
|
|
|
|
|
Welsh
Staff
Legendary

Activity: 3780
Merit: 4469
Reporting saves lives. Probably.
|
 |
May 25, 2026, 06:29:07 PM Last edit: May 25, 2026, 07:10:02 PM by Welsh |
|
1. If you notice, the browser's built-in translator translates the entire page at once. You can't translate any of your specific posts separately even if you want to. But if you use this userscript, you can translate the specific post of your choice while keeping the layout or design of the forum intact.
You can usually highlight and right click on Firefox which will allow to translate. This might be limited to what language your Firefox is on though at the time. I haven't tested extensively. My friend... Can userscripts be created using AI tools? I don't know for sure. If so, please tell me which tools to use. (Off-topic: Because this might help me in my important work in the future. It's worth mentioning that I am currently employed as a junior full-stack developer.)
Yeah, almost every single one. Gemini, AI studio, Claude, Cursor + any api, locally run LLMs.
|
|
|
|
DYING_S0UL
Legendary

Activity: 1036
Merit: 1029
The Alliance Of Bitcointalk Translators - ENG>BAN
|
 |
May 25, 2026, 07:26:48 PM |
|
OP, is there anything unique to this tool apart from being able to translate posts? To be honest, I haven't tested your userscript yet, but judging by the content from you, I don't see anything new. It's seems nearly identical to the one from Royal Cap. Afaik, every feature you mentioned is available in his tool too. What I have been meaning to say is that, I don't see any originality here. The concept is good, but it already exists, and someone already created something based on that. I'm not trying to discourage you or anything, I appreciate you trying to make things convenient for others, and since you say you have a good knowledge in coding, maybe you can add features that are completely unique to others (just a small suggestion). I hope you understood point I was trying to make...  Edit: 1. Ok it looks good, I just tried using it. I liked that you added the "Translate" button beside the profile info for each user. 2. A little suggestion. Can you make the right side menu bar moveable? Also an option to make it minimize? It's kinda looks big and distractive at this point.
|
|
|
|
Upgrade00
Legendary

Activity: 2772
Merit: 2898
Community Manager - Brand Promotions ✅
|
 |
May 25, 2026, 08:07:15 PM |
|
<snip> the main goal of which is to remove the language barrier of various local boards and make the forum easier to use for international users.
This is not the best goal, local boards are meant to have that language and cultural barrier, it is meant to be for those local to that region or country. A better use case will be making it easier for non native English speakers to read the bulk of content posted in general boards here and allow them communicate in their familiar language while the content is easily translated to English for the test of us to read, similar to what Musk is doing on X. I know there are easy tools that makes it easy to read content in other languages, but I don't know any that automatically allows you post and it is converted to the language you want it posted in.
|
|
|
|
Pmalek
Legendary

Activity: 3500
Merit: 9268
|
 |
Today at 06:55:32 AM |
|
1. If you notice, the browser's built-in translator translates the entire page at once. You can't translate any of your specific posts separately even if you want to. But if you use this userscript, you can translate the specific post of your choice while keeping the layout or design of the forum intact.
I don't think it's a disadvantage to translate the entire page to be honest. If I don't understand the first post in French, I am also not going to understand the second, the third, etc. 2. When you use the browser's built-in translator to translate, you have to reload the page repeatedly. However, using this userscript, you can get the translation directly within the post with just one click, without any reloading.
It depends on the browser. In Firefox, a "Translate" button does the translation without reloading. The "The "Show Original" button cancels the changes with reloading. But in Chrome there is no reloading in both instances. 3. You yourself said that sometimes the browser cannot detect English or other languages correctly. But since this userscript has the option to manually select the source language, that problem will not occur at all.
Fair enough. 5. With a cache system, there will be no need to translate the same post repeatedly.
What if I don't want the post translated the next time I open that particular topic for some reason? Will the script still translate it automatically by default?
|
| EARNBET | ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ | ███████▄▄███████████ ████▄██████████████████ ██▄▀▀███████████████▀▀███ █▄████████████████████████ ▄▄████████▀▀▀▀▀████████▄▄██ ███████████████████████████ █████████▌████▀████████████ ███████████████████████████ ▀▀███████▄▄▄▄▄█████████▀▀██ █▀█████████████████████▀██ ██▀▄▄███████████████▄▄███ ████▀██████████████████ ███████▀▀███████████ | | ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ |
▄▄▄ ▄▄▄███████▐███▌███████▄▄▄ █████████████████████████ ▀████▄▄▄███████▄▄▄████▀ █████████████████████ ▐███████████████████▌ ███████████████████ ███████████████████ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
| King of The Castle $200,000 in prizes | ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ | 62.5% | RAKEBACK BONUS |
|
|
|
GhostOfBitcoin (OP)
Newbie

Activity: 28
Merit: 10
|
 |
Today at 08:21:23 PM Last edit: Today at 10:00:37 PM by Mr. Big |
|
Updated UserScript: // ==UserScript== // @name Bitcointalk Translator // @namespace https://bitcointalk.org/ // @version 4.0.0 // @description Bitcointalk translator with draggable modern panel // @author GhostOfBitcoin // @match https://bitcointalk.org/* // @icon https://bitcointalk.org/favicon.ico // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @connect translate.googleapis.com // @run-at document-end // ==/UserScript==
(function () {
'use strict';
/* ========================================================= CONFIG ========================================================= */
const CONFIG = {
lang: GM_getValue('btc_lang', 'bn'),
side: GM_getValue('btc_side', false),
auto: GM_getValue('btc_auto', false),
panelOpen: false };
/* ========================================================= STYLES ========================================================= */
GM_addStyle(`
:root{
--btc-main:#5b8cff; --btc-second:#7f5cff; --btc-dark:#10131a; --btc-dark2:#171b24; --btc-text:#ffffff; }
/* ===================================================== FLOAT BUTTON ===================================================== */
.btc-floating-btn{
position:fixed;
width:52px; height:52px;
border-radius:50%;
bottom:20px; right:20px;
z-index:999999;
background: linear-gradient( 135deg, var(--btc-main), var(--btc-second) );
display:flex; align-items:center; justify-content:center;
cursor:grab;
box-shadow: 0 10px 30px rgba(0,0,0,.35);
user-select:none;
transition: transform .15s ease, box-shadow .2s ease; }
.btc-floating-btn:hover{
transform:scale(1.06); }
.btc-floating-btn svg{
width:24px; height:24px;
fill:white; }
/* ===================================================== PANEL ===================================================== */
.btc-panel{
position:fixed;
width:290px;
background: linear-gradient( 180deg, rgba(20,24,35,.98), rgba(15,18,28,.98) );
backdrop-filter:blur(12px);
color:white;
border-radius:18px;
padding:18px;
z-index:999998;
box-shadow: 0 20px 50px rgba(0,0,0,.45);
border: 1px solid rgba(255,255,255,.06);
display:none;
animation:btcPanel .18s ease; }
.btc-panel.active{
display:block; }
@keyframes btcPanel{
from{
opacity:0; transform:translateY(8px); }
to{
opacity:1; transform:translateY(0); } }
.btc-title{
font-size:16px; font-weight:700;
margin-bottom:16px;
background: linear-gradient( 90deg, #8ab4ff, #b388ff );
-webkit-background-clip:text; -webkit-text-fill-color:transparent; }
.btc-panel select{
width:100%;
padding:10px 12px;
border:none;
border-radius:12px;
background:#1d2330;
color:white;
outline:none;
margin-bottom:14px;
font-size:14px; }
.btc-switch{
display:flex;
align-items:center;
gap:8px;
margin-bottom:14px;
font-size:14px; }
.btc-thread-btn{
width:100%;
padding:11px;
border:none;
border-radius:12px;
background: linear-gradient( 135deg, var(--btc-main), var(--btc-second) );
color:white;
font-weight:700;
cursor:pointer;
transition:.2s ease; }
.btc-thread-btn:hover{
transform:translateY(-1px); }
/* ===================================================== TRANSLATE BUTTON ===================================================== */
.btc-translate-btn{
display:inline-flex;
align-items:center;
gap:5px;
padding:5px 10px;
margin-top:7px;
border-radius:8px;
background: rgba(91,140,255,.12);
border: 1px solid rgba(91,140,255,.22);
color:#8ab4ff;
font-size:12px;
font-weight:700;
cursor:pointer;
transition:.15s ease; }
.btc-translate-btn:hover{
background: rgba(91,140,255,.2); }
/* ===================================================== TRANSLATION BOX ===================================================== */
.btc-translation{
margin-top:14px;
padding:16px;
border-radius:16px;
background: rgba(255,255,255,.04);
border: 1px solid rgba(255,255,255,.06);
line-height:1.8;
font-size:14px;
animation:btcPanel .18s ease;
overflow-wrap:anywhere; }
.btc-tools{
display:flex;
justify-content:space-between;
align-items:center;
margin-bottom:12px; }
.btc-tool-buttons{
display:flex; gap:7px; }
.btc-tool{
border:none;
padding:5px 10px;
border-radius:8px;
background:#222a38;
color:white;
cursor:pointer;
font-size:12px; }
.btc-ar{
direction:rtl;
text-align:right;
font-family: Tahoma, Arial, sans-serif;
line-height:2.1; }
@media(max-width:768px){
.btc-panel{
width:calc(100vw - 30px); } }
`);
/* ========================================================= CACHE ========================================================= */
class Cache{
constructor(){
this.prefix = 'btc_cache_'; }
hash(str){
let hash = 0;
for(let i=0;i<str.length;i++){
hash = ((hash << 5) - hash) + str.charCodeAt(i);
hash |= 0; }
return hash; }
get(key){
return localStorage.getItem( this.prefix + key ); }
set(key,val){
localStorage.setItem( this.prefix + key, val ); } }
const cache = new Cache();
/* ========================================================= ESCAPE ========================================================= */
function escapeHTML(str){
return str .replace(/&/g,'&') .replace(/</g,'<') .replace(/>/g,'>'); }
/* ========================================================= TRANSLATOR ========================================================= */
async function translateText(text,target){
if(!text) return text;
const key = cache.hash(text + target);
const cached = cache.get(key);
if(cached){
return cached; }
try{
const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=${target}&dt=t&dt=bd&dj=1&q=${encodeURIComponent(text)}`;
const res = await fetch(url);
const data = await res.json();
let translated = '';
if(data.sentences){
data.sentences.forEach(s=>{
translated += s.trans || ''; }); }
translated = translated.trim();
if(!translated){
translated = text; }
cache.set(key, translated);
return translated;
}catch(e){
console.error(e);
return text; } }
/* ========================================================= TRANSLATION UI ========================================================= */
function createTranslationBox(original,translated){
const box = document.createElement('div');
box.className = 'btc-translation';
if(CONFIG.lang === 'ar'){
box.classList.add('btc-ar'); }
box.innerHTML = `
<div class="btc-tools">
<strong> 🌐 Translation </strong>
<div class="btc-tool-buttons">
<button class="btc-tool btc-copy"> Copy </button>
<button class="btc-tool btc-speak"> 🔊 </button>
<button class="btc-tool btc-close"> ✖ </button>
</div>
</div>
<div>
${ CONFIG.side
?
`
<div style="margin-bottom:15px;">
<b>Original:</b>
<div style="margin-top:6px;"> ${escapeHTML(original)} </div>
</div>
<div>
<b>Translated:</b>
<div style="margin-top:6px;"> ${escapeHTML(translated)} </div>
</div>
`
:
escapeHTML(translated) }
</div> `;
box.querySelector('.btc-copy') .onclick = () => {
navigator.clipboard .writeText(translated); };
box.querySelector('.btc-speak') .onclick = () => {
const speech = new SpeechSynthesisUtterance( translated );
speech.lang = CONFIG.lang;
speechSynthesis.speak( speech ); };
box.querySelector('.btc-close') .onclick = () => {
box.remove(); };
return box; }
/* ========================================================= PROCESS POSTS ========================================================= */
async function processPost(post){
if(post.dataset.btcDone){
return; }
post.dataset.btcDone = '1';
const footer = post.querySelector('.smalltext');
const content = post.querySelector('.post');
if(!footer || !content){
return; }
const btn = document.createElement('div');
btn.className = 'btc-translate-btn';
btn.innerHTML = '🌐 Translate';
footer.appendChild(btn);
btn.onclick = async () => {
const old = post.querySelector( '.btc-translation' );
if(old){
old.remove();
return; }
let text = content.innerText.trim();
if(!text){
return; }
btn.innerHTML = '⏳ Translating';
const translated = await translateText( text, CONFIG.lang );
const box = createTranslationBox( text, translated );
content.appendChild(box);
btn.innerHTML = '✅ Done';
setTimeout(()=>{
btn.innerHTML = '🌐 Translate';
},1200); };
if(CONFIG.auto){
btn.click(); } }
/* ========================================================= OBSERVER ========================================================= */
function observe(){
const observer = new MutationObserver(()=>{
const posts = document.querySelectorAll( 'td.windowbg,td.windowbg2' );
posts.forEach( processPost ); });
observer.observe( document.body, { childList:true, subtree:true } );
const posts = document.querySelectorAll( 'td.windowbg,td.windowbg2' );
posts.forEach( processPost ); }
/* ========================================================= FLOAT BUTTON ========================================================= */
function createFloatingUI(){
const btn = document.createElement('div');
btn.className = 'btc-floating-btn';
btn.innerHTML = `
<svg viewBox="0 0 24 24">
<path d="M12 2a10 10 0 100 20 10 10 0 000-20zm6.93 9h-3.02a15.7 15.7 0 00-1.32-5.01A8.02 8.02 0 0118.93 11zm-6.93 9c-.83-1.2-1.53-3.02-1.86-5h3.72c-.33 1.98-1.03 3.8-1.86 5zm-2.14-7a13.7 13.7 0 010-2h4.28a13.7 13.7 0 010 2H9.86zm.28 2h3.72c-.33 1.98-1.03 3.8-1.86 5-.83-1.2-1.53-3.02-1.86-5zm-4.07-4a8.02 8.02 0 014.34-5.01A15.7 15.7 0 009.09 11H6.07zm0 2h3.02c.12 1.78.56 3.5 1.32 5.01A8.02 8.02 0 016.07 13zm8.84 5.01c.76-1.51 1.2-3.23 1.32-5.01h3.02a8.02 8.02 0 01-4.34 5.01z"/>
</svg> `;
document.body.appendChild(btn);
const panel = document.createElement('div');
panel.className = 'btc-panel';
panel.innerHTML = `
<div class="btc-title"> Bitcointalk Translator </div>
<select id="btc-lang">
<option value="ar">العربية (Arabic)</option> <option value="id">Indonesian</option> <option value="es">Spanish</option> <option value="zh-CN">Chinese</option> <option value="hr">Croatian</option> <option value="de">German</option> <option value="el">Greek</option> <option value="he">Hebrew</option> <option value="fr">Français</option> <option value="hi">India</option> <option value="it">Italian</option> <option value="ja">Japanese</option> <option value="nl">Nederlands</option> <option value="yo">Nigeria</option> <option value="ko">Korean</option> <option value="tl">Pilipinas</option> <option value="pt">Portuguese</option> <option value="ru">Russian</option> <option value="ro">Romanian</option> <option value="sv">Skandinavisk</option> <option value="tr">Turkish</option> <option value="ur">Pakistan</option> <option value="bn">বাংলা</option>
</select>
<label class="btc-switch">
<input type="checkbox" id="btc-side" ${CONFIG.side ? 'checked':''} >
Side by Side
</label>
<label class="btc-switch">
<input type="checkbox" id="btc-auto" ${CONFIG.auto ? 'checked':''} >
Auto Translate
</label>
<button class="btc-thread-btn"> Translate Entire Thread </button>
`;
document.body.appendChild(panel);
/* ===================================================== POSITION ===================================================== */
function updatePanelPosition(){
const rect = btn.getBoundingClientRect();
panel.style.left = (rect.left - 230) + 'px';
panel.style.top = (rect.top - 10) + 'px'; }
updatePanelPosition();
/* ===================================================== TOGGLE PANEL ===================================================== */
btn.addEventListener('click', e => {
if(btn.dragging){
return; }
CONFIG.panelOpen = !CONFIG.panelOpen;
if(CONFIG.panelOpen){
updatePanelPosition();
panel.classList.add( 'active' );
}else{
panel.classList.remove( 'active' ); } });
/* ===================================================== DRAG BUTTON ===================================================== */
let dragging = false;
let offsetX = 0; let offsetY = 0;
btn.addEventListener('mousedown', e => {
dragging = true;
btn.dragging = false;
offsetX = e.clientX - btn.offsetLeft;
offsetY = e.clientY - btn.offsetTop;
panel.classList.remove( 'active' );
document.body.style.userSelect = 'none'; });
document.addEventListener( 'mousemove', e => {
if(!dragging){
return; }
btn.dragging = true;
btn.style.left = (e.clientX - offsetX) + 'px';
btn.style.top = (e.clientY - offsetY) + 'px';
btn.style.right = 'auto';
btn.style.bottom = 'auto'; } );
document.addEventListener( 'mouseup', () => {
dragging = false;
document.body.style.userSelect = ''; } );
/* ===================================================== SETTINGS ===================================================== */
const lang = panel.querySelector('#btc-lang');
lang.value = CONFIG.lang;
lang.onchange = e => {
CONFIG.lang = e.target.value;
GM_setValue( 'btc_lang', e.target.value ); };
panel.querySelector('#btc-side') .onchange = e => {
CONFIG.side = e.target.checked;
GM_setValue( 'btc_side', e.target.checked ); };
panel.querySelector('#btc-auto') .onchange = e => {
CONFIG.auto = e.target.checked;
GM_setValue( 'btc_auto', e.target.checked ); };
panel.querySelector('.btc-thread-btn') .onclick = async () => {
const buttons = document.querySelectorAll( '.btc-translate-btn' );
for(const b of buttons){
b.click();
await new Promise(r=>{
setTimeout(r,300);
}); } }; }
/* ========================================================= SHORTCUT ========================================================= */
document.addEventListener( 'keydown', e => {
if( e.altKey && e.key === 't' ){
const btn = document.querySelector( '.btc-translate-btn' );
if(btn){
btn.click(); } } } );
/* ========================================================= INIT ========================================================= */
function init(){
observe();
createFloatingUI();
console.log( 'Bitcointalk Translator V4 Loaded' ); }
init();
})(); Or use this greasyfork link for one click install : https://greasyfork.org/en/scripts/579899-bitcointalk-translatorNew Update: - Translation engine fix
- Arabic language rendering fix
- Floating translator button redesign
- Draggable floating button
- Faster drag movement optimization
- Toggle panel system
- New modern UI design
- Cache system optimize
- Mobile responsive UI improve
- Performance optimization
1. Ok it looks good, I just tried using it. I liked that you added the "Translate" button beside the profile info for each user.
Hello friend! @DYING_SOUL I'm glad to hear that you've already used my userscript. Thank you very much. 2. A little suggestion. Can you make the right side menu bar moveable? Also an option to make it minimize? It's kinda looks big and distractive at this point.
Any suggestions from you will help me work better and more effectively. I always try to learn new things and improve my skills, However, many more things have been updated as per your suggestions. Hope you will have a more cool experience using the updated userscript. Here is a Greasy Fork link for one click install : https://greasyfork.org/en/scripts/579899-bitcointalk-translator
What if I don't want the post translated the next time I open that particular topic for some reason? Will the script still translate it automatically by default?
No, by default the script will not auto translate. The Auto Translate feature is kept optional and the user can turn it ON/OFF from the settings panel if they want. The cache system is only used to load previously translated posts quickly, so that the same post does not take repeated API requests. That is, if you turn off auto-translate, then even if there is a cached translation, the script will not show the translation itself it will only show the translation if you click it manually.
|
|
|
|
|
|