Skip to content

Instantly share code, notes, and snippets.

@neoOpus
Last active November 1, 2021 18:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save neoOpus/24316c9c5cde5189e3b936ae11ca07c9 to your computer and use it in GitHub Desktop.
Save neoOpus/24316c9c5cde5189e3b936ae11ca07c9 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Translator for Whatsapp
// @namespace http://tampermonkey.net/
// @homepage https://greasyfork.org/scripts/28218-translator-for-whatsapp
// @version 2.4.3
// @description Translator for Whatsapp web
// @author JedLiu modded as suggested by neoOpus
// @match https://web.whatsapp.com/*
// @run-at document-start
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_xmlhttpRequest
// @connect translate.googleapis.com
// @connect www.googleapis.com
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js
// ==/UserScript==
var API_KEY = 'INSERT YOUR GOOGlE TRANSLATE API KEY HERE';
(function() {
'use strict';
/*************************************************************
ATTENTION:
All supported languages
Remove // if you want to include this for translation
*************************************************************/
var all_languages = [
{id:'zh-CN', name:'Chinese Simplified'},
//{id:'zh-TW', name:'Chinese Traditional'},
//{id:'af', name:'Afrikaans'},
//{id:'sq', name:'Albanian'},
{id:'ar', name:'Arabic'},
//{id:'hy', name:'Armenian'},
//{id:'az', name:'Azerbaijani'},
//{id:'eu', name:'Basque'},
//{id:'be', name:'Belarusian'},
//{id:'bn', name:'Bengali'},
//{id:'bs', name:'Bosnian'},
//{id:'bg', name:'Bulgarian'},
//{id:'ca', name:'Catalan'},
//{id:'ceb', name:'Cebuano'},
//{id:'ny', name:'Chichewa'},
//{id:'co', name:'Corsican'},
//{id:'hr', name:'Croatian'},
//{id:'cs', name:'Czech'},
//{id:'da', name:'Danish'},
{id:'nl', name:'Dutch'},
{id:'en', name:'English'},
//{id:'eo', name:'Esperanto'},
//{id:'et', name:'Estonian'},
//{id:'tl', name:'Filipino'},
//{id:'fi', name:'Finnish'},
{id:'fr', name:'French'},
//{id:'fy', name:'Frisian'},
//{id:'gl', name:'Galician'},
//{id:'ka', name:'Georgian'},
{id:'de', name:'German'},
//{id:'el', name:'Greek'},
//{id:'gu', name:'Gujarati'},
//{id:'ht', name:'Haitian Creole'},
//{id:'ha', name:'Hausa'},
//{id:'haw', name:'Hawaiian'},
//{id:'iw', name:'Hebrew'},
//{id:'hi', name:'Hindi'},
//{id:'hmn', name:'Hmong'},
//{id:'hu', name:'Hungarian'},
//{id:'is', name:'Icelandic'},
//{id:'ig', name:'Igbo'},
//{id:'id', name:'Indonesian'},
//{id:'ga', name:'Irish'},
{id:'it', name:'Italian'},
//{id:'ja', name:'Japanese'},
//{id:'jw', name:'Javanese'},
//{id:'kn', name:'Kannada'},
//{id:'kk', name:'Kazakh'},
//{id:'km', name:'Khmer'},
//{id:'ko', name:'Korean'},
//{id:'ku', name:'Kurdish (Kurmanji)'},
//{id:'ky', name:'Kyrgyz'},
//{id:'lo', name:'Lao'},
//{id:'la', name:'Latin'},
//{id:'lv', name:'Latvian'},
//{id:'lt', name:'Lithuanian'},
//{id:'lb', name:'Luxembourgish'},
//{id:'mk', name:'Macedonian'},
//{id:'mg', name:'Malagasy'},
//{id:'ms', name:'Malay'},
//{id:'ml', name:'Malayalam'},
//{id:'mt', name:'Maltese'},
//{id:'mi', name:'Maori'},
//{id:'mr', name:'Marathi'},
//{id:'mn', name:'Mongolian'},
//{id:'my', name:'Myanmar (Burmese)'},
//{id:'ne', name:'Nepali'},
//{id:'no', name:'Norwegian'},
//{id:'ps', name:'Pashto'},
//{id:'fa', name:'Persian'},
//{id:'pl', name:'Polish'},
//{id:'pt', name:'Portuguese'},
//{id:'ma', name:'Punjabi'},
//{id:'ro', name:'Romanian'},
//{id:'ru', name:'Russian'},
//{id:'sm', name:'Samoan'},
//{id:'gd', name:'Scots Gaelic'},
//{id:'sr', name:'Serbian'},
//{id:'st', name:'Sesotho'},
//{id:'sn', name:'Shona'},
//{id:'sd', name:'Sindhi'},
//{id:'si', name:'Sinhala'},
//{id:'sk', name:'Slovak'},
//{id:'sl', name:'Slovenian'},
//{id:'so', name:'Somali'},
{id:'es', name:'Spanish'},
//{id:'su', name:'Sudanese'},
//{id:'sw', name:'Swahili'},
//{id:'sv', name:'Swedish'},
//{id:'tg', name:'Tajik'},
//{id:'ta', name:'Tamil'},
//{id:'te', name:'Telugu'},
//{id:'th', name:'Thai'},
//{id:'tr', name:'Turkish'},
//{id:'uk', name:'Ukrainian'},
//{id:'ur', name:'Urdu'},
//{id:'uz', name:'Uzbek'},
//{id:'vi', name:'Vietnamese'},
//{id:'cy', name:'Welsh'},
//{id:'xh', name:'Xhosa'},
//{id:'yi', name:'Yiddish'},
//{id:'yo', name:'Yoruba'},
//{id:'zu', name:'Zulu'}
];
var SOURCE_LANGUAGE = 'en',
TRANSLATED_LANGUAGE = 'es';
var $ = $ || window.$,
addListenerInterval = null,
translateInterval = null,
translateTimeout = null,
translate_enabled = true,
translate_ready = false,
translate_string = '',
custom_style = '.language_selected{background-color: #00bfa5;}',
image_uri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAFZklEQVR42sWXe0xTVxzHv5drWXkIKBQfE61Y2DIyR3Sy+FrqRgRF1IFD54IawU03dUE2I3ukxTgqPuYjK6KOZRndnFPYJoEpcUunokNxYnFT4wOQp9A/BshD4N6zc1sKvaWV0C7xhEt/59Hf93N+5/c7uWXwlBtjMV6JeBnz5r0KhmGG/BIhxKYPtLW1Qaf7Aa30c9gA4eFTof+9KJ5l2WzaDRhakIhs+sdT6/T5C5cSFi9JaB82wHsb1iFz5/ZmJ8UFy2Jv9JdN1DoLQGwnrcXWvbsJsYsWmB574n1jan/ZpHSXAU4VFA0CKCj4FaGhCjwXGiJI9s8LY6Ehij4gog4IlLsOkPzORptQiDvEajwmJhqLYqL6AWRjJrsGIDjiOF6kah2Jzs4upKRuwxtLYxE1/3WLcD9A4Nhg5wFsE+7q1Wuoq2tAZKQSUqnUdOaGihvQao8gdcsmKBTBgwDGjJviHMBOTbo40NRhebkBWYe+wpLFMViwYD4d47F7zwF0d3cjbVtq/zprgLHjFcMH2LAhGZmagRywympos47i5s1b2PpRCm78/Q9OnSrCh6mbIZdPtBUHzxP1+AkhrgHY1nl7ewcyd+9Da2sbOjs6sGLFMsydM8ueuCkCzwaFOg9g75Lp6elBru4YSkuvwF3ijqTk1XAPDEdF3TOgmn3AZoDG1hH6kkov/QCY7RGZPBtbKs9/c/v4inbucWsfwPpkUQ5YFldVV+Pb3GMwNhuR8GYcymhSGh7wePTCDirJ2LsJRZ+Dx/vtouritJjGUu1gAGFRVfUDFBf/RqugHMHBcqxKfAsyWQDdJY/ss904V69wRVx4+No/NGz9+Z1iAMuiO3fuQvfdcURHRSIiYroo20+W+yLvuo8r4ia77pyGsQJIgiYjnVg7fdwL3Gtm8fyYHtE5mgF8HYrHvsRhpBQouQPcb4ZDEAGg4UKmGWC9APB5Oken3Czi2wtHoqJ+BD6JbsX0oMf9DgRx4bEnPmEUQXZiL4RXCv0tQFPIOIwC3f0AwPLl8cjO2l9IJxZaxP+qkZhCL2EJPp7fgmlBXaZMF8TzDb52w540h8PicIILdPezFMDKwwxaOuxXBBUfAJBIJMjSfuH12jzlmtzLHgG/XJcq3T39lJaqkDId6u3R9Qj07oXOMFlZUumttBVn3QhykzhanoDuIoNDqwgO64GTVwaLC02IQGPJLth9/5oYd1w1clyY2lsmN/Vr9RlMnT7DZM/57KGKlfqqbRNubghBWgyPT/MZXL4PHHybwENCo5IDel+IxS0ReCIA6+6t9vSfBAHCGmBhRqPqEe+nts32jDgOE0YDiUcYcPSoFk4lSIli8IGOh6FGLG4G2MU8vOgAYErCCRXv5qkWbAHiRb8qhmm6aJpbtHKLqvi2p9o6w8f6EOSs5XGvCbh011xJnu7AshkMzlQQaAo4kbjw0N1TgN32AdIOnJHPnDmbniAm2Zvvpf5+vsbQMjU7XTObR0IEUFHTV8Z96wJ9gNFeQPxBDo+6xFeyANB0yQGAj18AdmQVyuWKsCdCHCsFGlpo8q2jZfUvkPK9OOGm0W/uXcli32kOP5Vxomqg4acAe+DwR8BQEMIR5JURzJhMoF4KaM8S5F8Vh9mNes/bzMLYRrD2aI8Ijoafaf7zCQAWCNX+fPm4oODVljEvb19lpZFRCuI9nKOrVpxw9ubp7ocGsNdSc2pVl2t91a6IC30q7hzAjK0177NSvy9dEafNSBNQZizdO3wARdzXXv5hy36kzqKFY3ZGnPDc+qoTS/I6G8qGD8C4SeAfFg/WY5TpzZ2Y/1l+qgzYZKAcbd+2O+pK0dVkMPsbLsD/3f4DRTYAbJ65vloAAAAASUVORK5CYII=',
custom_html = '<div class="block-compose tranlate-bottom"><div tabindex="-1" class="input-container" style="padding-top:0px;padding-bottom:0px;padding-left:0px;"><button title="Click for translation help!" class="trans_help_btn" style="float:left"><img alt="Translator" draggable="false" src="' + image_uri + '" style="width:30px;height:30px;padding-left:15px;padding-right:30px;padding-bottom:8px;"></button><div class="input" dir="auto" style="padding-top:6px;"></div></div></div>',
html_language1 = '<div class="menu-item" style="display:table"><button title="Click for translation help!" class="trans_help_btn"><img alt="Translator" draggable="false" src="data:'+ image_uri +'" style="width:32px;height:32px;"/></button></div>',
username = '',
is_debug = true,
lan_select = '',
help_url = 'https://greasyfork.org/zh-CN/scripts/28218-translator-for-whatsapp';
//For menu html
for(var i=0;i<all_languages.length;i++){
lan_select = lan_select + '<option value="'+ all_languages[i].id +'">' + all_languages[i].name +'</option>';
}
var lan_select_1 = '<span style="padding-left:5px;padding-right:5px;color:green;font-size:10pt;">From:</span><select class="languageSelect1" style="padding-right:5px;width: 126px; text-align-last:center;">' + lan_select + '</select>';
var lan_select_2 = '<span style="padding-left:20px;padding-right:5px;color:green;font-size:10pt;">To:</span><select class="languageSelect" style="padding-right:5px;width: 126px; text-align-last:center;border-bottom-width: 0px !important;"><option value="off">OFF</option>' + lan_select + '</select>';
html_language1 = html_language1 + '<div style="display:table;"><div style="display:table-row">'+ lan_select_1 +'</div><div style="display:table-row">'+ lan_select_2 +'</div></div>';
//Add style
var customStyleNode = document.createElement('style');
customStyleNode.textContent = custom_style;
document.querySelector('head').appendChild(customStyleNode);
//Replace all function
function replaceAll(str, find, replace) {
return str.replace(new RegExp(find, 'g'), replace);
}
//Show debug
var debugMessage = function(mes){
if(is_debug){
console.info(mes);
}
};
//Show error message
var showError = function(err){
alert(err);
console.error(err);
};
//Translate
//sl - source language
//dl - target language
//txt - content to be translated
//cb - callback after translation
var translate = function(sl,dl,txt,cb){
//debugMessage('Source='+ txt+",sl="+sl+",dl="+dl+",txt="+txt);
GM_xmlhttpRequest({
method: "GET",
url: "https://www.googleapis.com/language/translate/v2?key=" + API_KEY + "&client=gtx&source="+ sl +"&target=" + dl +"&format=text&q=" + encodeURI(txt),
//url: "https://www.googleapis.com/language/translate/v2?key=AIzaSyBMk2j1E4aRDn9Rx9DhNYnDyOHnkMR62tY&client=gtx&target=" + dl +"&format=text&q=" + encodeURI(txt),
onload: function(response) {
//replace the \n
var _r_text = replaceAll(response.responseText, '\n"', '"');
var _r = JSON.parse(_r_text);
translate_string = _r.data.translations[0].translatedText;
debugMessage('Translation:'+translate_string);
cb.apply({text: translate_string});
}
});
};
//Bind to get user input
var onInput = function(){
var $_translate_input_1 = $('.tranlate-bottom').find('.input');
$_translate_input_1.html('Typing...');
translate_ready = false;
var _this = $(this);
delay(function(){
var _input = $.trim(_this.text());
if(_input){
translate(SOURCE_LANGUAGE, TRANSLATED_LANGUAGE, _input, function(){
$_translate_input_1.html(this.text);
translate_ready = true;
});
}else{
$_translate_input_1.html('');
}
}, 1000);
};
//Bind to send the translated content
//Updated: 2018-07-30
var onEnterKeyPressed = function( event ) {
if (event.which == 13 && translate_enabled) {
debugMessage('Waiting translation');
event.preventDefault();
var _this = $(this);
translateInterval = setInterval(function(){
if(translate_ready){
debugMessage('Now sending message:'+translate_string);
sendTranslatedMessage(_this, translate_string);
debugMessage('Message sent');
clearInterval(translateInterval);
}
}, 100);
}
};
//Send translated message
//Updated: 2018-07-31
var sendTranslatedMessage = function(inputTarget, message){
translate_string = '';
inputTarget.focus();
document.execCommand("selectAll");
document.execCommand("insertText", false, message);
if($('footer button:has(span):last span').data('icon') == 'send'){
$('footer button:has(span):last').click();
}else{
showError('Not able to send the translated message');
}
translate_ready = false;
}
//Add translation bindings
var addTranslateFunc = function(selectChange){
if(!username){
showError('Can not get the username');
return;
}
if(selectChange){
GM_setValue(username, $('.languageSelect').val());
GM_setValue(username+'_o', $('.languageSelect1').val());
}
TRANSLATED_LANGUAGE = GM_getValue(username) ? GM_getValue(username) : TRANSLATED_LANGUAGE;
SOURCE_LANGUAGE = GM_getValue(username+'_o') ? GM_getValue(username+'_o') : SOURCE_LANGUAGE;
//Menu
debugMessage('Set original language to: ' + SOURCE_LANGUAGE + ', translate to: '+ TRANSLATED_LANGUAGE);
$('.languageSelect').val(TRANSLATED_LANGUAGE);
$('.languageSelect1').val(SOURCE_LANGUAGE);
//Add translation input
var $_input_body = $('footer div.copyable-text.selectable-text');
if(TRANSLATED_LANGUAGE !== 'off' && $('.tranlate-bottom').length === 0){
$('footer').append($(custom_html));
if($_input_body === null || $_input_body.length !== 1){
showError('Error binding for Whatsapp translator plugin!');
}else{
$_input_body.on('input', onInput)
.on('keydown', onEnterKeyPressed);
}
//translate sent or received messages
$('.copyable-area').on('click', '.selectable-text', function(){
if(TRANSLATED_LANGUAGE!='off'){
var $_t_this = $(this);
translate(TRANSLATED_LANGUAGE, SOURCE_LANGUAGE, $(this).text(), function(){
$_t_this.html(this.text);
});
}
});
//visit the help page
$('.trans_help_btn').on('click', function(){
window.open(help_url,'_blank');
});
}else if(TRANSLATED_LANGUAGE === 'off' && $('.tranlate-bottom').length !== 0){
//remove bindings
$('.tranlate-bottom').remove();
$_input_body.off('input', onInput)
.off('keydown', onEnterKeyPressed);
}
};
//Add listener when user activates a new chat
addListenerInterval = setInterval(function(){
var $_div_chat = $('#pane-side');
//console.log('div_chat_length', $_div_chat.length);
if($_div_chat.length){
//console.log('found #pane-side');
var contacts = document.querySelector('div[role="grid"]').children;
if(!contacts || contacts.length === 0){
showError('Not able to get the contacts sidebar');
return;
}
var c_name = contacts[0].className;
console.log('One of the chat selector', contacts[0]);
//更新会经常导致这个地方需要修改
$('#pane-side').on('click','div.'+c_name, function(){
//Get the username
//username = escape($(this).find('.chat-title').text());
console.info($(this));
var _tusername = '';
$(this).find('span').each(function(i,x){
if(x.hasAttribute('title')) {
//console.info(x.title);
_tusername = x.title;
return false;
}
});
if(_tusername !== ''){username = escape(_tusername);}
else{showError('Not able to get the user name');}
debugMessage('Chat menu clicked');
//Return if the translation input is added
if($('.languageSelect').length>0){return;}
var $header = $('#main header div:first').next();
if($header.length != 1){showError('Not able to insert translate menu');}
$header.after($(html_language1));
//Bind lanaguage select change event
$('.languageSelect').on('change', function(){
addTranslateFunc(true);
});
$('.languageSelect1').on('change', function(){
addTranslateFunc(true);
});
//Apply the translate function
addTranslateFunc();
});
clearInterval(addListenerInterval);
}
}, 1000);
//Delay function
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment