返回首頁 

Greasy Fork is available in English.

Pixiv 辅助翻译

现已支持标签TAG、作品详情页对标题和说明,以及评论区翻译!

// ==UserScript==// @name         Pixiv 辅助翻译// @namespace    https://greasyfork.org/users/159546// @version      1.1.7// @description  现已支持标签TAG、作品详情页对标题和说明,以及评论区翻译!// @author       LEORChn// @include      *://www.pixiv.net/*// @run-at       document-start// @grant        GM_xmlhttpRequest// @connect      translate.google.cn// ==/UserScript==var tag_trans=[// 图型类'漫画','漫画','うごイラ','动图','厚塗り','多层上色','オリジナル','原创',// 角色类型类'UTAU獣人','兽人虚拟歌手','ケモノ','野兽','wolf','狼','オオカミ','狼','ハスキー','哈士奇','kemono','毛怪','furry','兽人','獣人','兽人', // 这个是日文的'獸人','兽人', // 这个是繁体的'オスケモ','雄兽','デブケモ','胖兽','ケモホモ','兽人同性向','ケモ交尾','兽性',// 作品名称类'東#放課後サモナーズ','东#放课后召唤师', // 我在2018年9月初玩过,几号来着忘了'放サモ','东放','housamo','东放','あらしのよるに','翡翠森林狼与羊(暴风雨之夜)', // 我在2019年3月初左右观看完了这个动画'ひみつのともだち','秘密的朋友','ゼロから始める魔法の書','从零开始的魔法书', // 我在2019年5月8日14时观看完了这个动画,17时35分开始观看第12话,17时58分观看完毕撒花// 人物名称类'狼音アロ','狼音阿罗','モリタカ','犬塚戍孝','犬塚モリタカ','犬塚戍孝','ホロケウカムイ','狼神神#', //ID为 20880639 的作者似乎打错了这个标签所以替换不到'テムジン','铁木真','ガルム','加姆','ノーマッド(放サモ)','诺曼德(东放)', // 东#放课后里的虎兽人所用的化名'主5','5号主人公(东放)','獣の傭兵','佣兵(零书)',// 着装类'ふんどし','兜裆布','褌','兜裆布','ラバースーツ','橡胶紧身衣','靴下','袜子',// 器官类'腹筋','腹肌','ㄋㄟㄋㄟ','胸部',// 行为类'金的','捣蛋','猿轡','封口','目隠し','蒙眼','拘束','捆绑Play'];(function(){recheck();})();function recheck(){init();if(load())return;setTimeout(recheck,100);}function init(){ // call once when start loading pageif(ft('body').length==0) return;main_daemon();//inited=true; //}function load(){ // call once when loaded pageif(document.readyState.toLowerCase()=='complete'){main_daemon();// write code herereturn true;}}var daemonLauncher;function main_daemon(){if(daemonLauncher) return;daemonLauncher = setInterval(main_do, 3000);main_do();}function main_do(){tagTranslate_illust();             // 个人空间 > 作品列表页面 - 标签tagTranslate_illust_single();      // 作品页面 - 标签tagTranslate_bookmark();           // 个人空间 > 我的收藏页面 - 标签tagTranslate_addBookmark();        // 作品页面 > 编辑心页面 - 添加收藏时的可选择标签tagTranslate_member_tag_all();     // 个人空间 - 所有绘制的作品包含的标签(包含频率降序)detailTranslate_illust();          // 作品页面 - 自动翻译作品标题和简介button_trans_comment();            // 作品页面 - 添加评论翻译的按钮unblock_popular_illust_overlay();  // 搜索页面 - 有作品在“查看更多「xxx」的热门作品”面板的下方,点击该面板提示开通会员,用这个隐藏会员面板popup_popular_order();             // 【预想】搜索页面 - 突破会员限制delete_illust_expanded_ad();       // 作品页面 - 在展开多页作品后最底部会出现广告,删除它以节省滚动操作}// ========== 功能性function unblock_popular_illust_overlay(){ // 搜索页面 热门作品提示var v = $$('.popular-introduction-overlay');for(var i=0; i<v.length; i++) v[i].style.display = 'none';}function delete_illust_expanded_ad(){ // 作品页面 广告var v = $('main section div iframe');if(v) v.remove();}function popup_popular_order(){ // 【预想测试】【失败】突破会员限制实现某些功能var v = $('.require-premium-popular_d'),v2 = $('._popular-search-select-popup-container');if(v && v2){v.onmousemove = v2.onmousemove = function(){v2.style.setProperty('display', 'block', 'important');v2.style.marginTop = '-5px';}v.onmouseleave = v2.onmouseleave = function(){v2.style.display = '';}}}// ========== 作品页面标签(单图预览和评论区) 以下function tagTranslate_illust_single(){if(!location.pathname.startsWith('/artworks/')) return;var tags=$$('figcaption footer>ul>li');if(tags.length==0)return;for(var li=0;li<tags.length;li++){var c=tags[li].childNodes,tt=tagDict(c[0].innerText);tags[li].style.display='inline-block';if(tt){c[0].childNodes[0].innerText=tt;if(c.length>1) c[1].remove();}}}// ----- 作品页标题和说明 以下var ID_TRANSLATION_SOURCE='leorchn_icon_google_translate', ICON_TRANSLATION_SOURCE='https://translate.google.cn/favicon.ico',ID_TRANSLATED_TITLE = 'leorchn_translated_title',ID_TRANSLATED_DESC = 'leorchn_translated_desc',block_detail_root;function detailTranslate_illust(){if(!location.pathname.startsWith('/artworks/')) return;// if(!location.href.includes('mode=medium')) return;var detail_block_post_time = $('figcaption div[title]');if(!detail_block_post_time) return;block_detail_root = detail_block_post_time.parentElement;if(!fv(ID_TRANSLATION_SOURCE)){var img=ct('img'); img.id=ID_TRANSLATION_SOURCE; img.src=ICON_TRANSLATION_SOURCE; img.style.cssText='width:24px; float:right';block_detail_root.insertBefore(img, block_detail_root.children[0]);}trans_title();trans_desc();}function trans_title(){ // 作品标题var p=$('figcaption div>h1'), d=fv(ID_TRANSLATED_TITLE);if(!p) return;if(d){if(d.title == d.innerText){ // 标题块中缓存的原文与自身内容一致,表示翻译完成但与原文一致或无法翻译p.style.backgroundColor='#c0e0ff'; // 译文等于原文自身,给原文块加蓝底表示无需翻译d.style.display='none';}if(d.title == p.innerText) return; // 标题块中缓存的与原文一致,表示页面没有变化,取消翻译p.style.backgroundColor=''; // 页面有变化,如果修改过蓝底的就重置它d.parentElement.remove();d = undefined;}/* 要解释为什么不能在这两个if之间用else连起来,先看看进入下一个if的两种情况:1.新建页面,没有找到翻译块2.页面更改,并进入了上一个if。并且没有触碰到return,导致d被设为undefined很明显,2号情况决定了这俩if不能用else连起来*/if(!d){ // 因为标题块没有双层嵌套,二次读取会导致缓存文字块被误翻译var q = ct('h1'); d = trans_create_block('');q.className = p.className;d.id=ID_TRANSLATED_TITLE;d.title=p.innerText; // 标题块中缓存原文q.appendChild(d);p.parentElement.insertBefore(q, p.nextElementSibling);}googleTranslateProxy(p.innerText, fv(ID_TRANSLATED_TITLE), trans_title);}function trans_desc(){ // 作品描述var p=$('figcaption div>h1+div>div'), d=fv(ID_TRANSLATED_DESC);if(!p) return;if(d){if(p.innerText.replace(/\s/g,'') == d.innerText.replace(/\s/g,'')){ // 标题块中缓存的原文与自身内容一致,表示翻译完成但与原文一致或无法翻译p.style.backgroundColor='#c0e0ff'; // 译文等于原文自身,给原文块加蓝底表示无需翻译d.style.display='none';}if(d.title == p.innerText) return; // 标题块中缓存的与原文一致,表示页面没有变化,取消翻译p.style.backgroundColor=''; // 页面有变化,如果修改过蓝底的就重置它d.remove();d = undefined;}// 这里还用复制一遍解释么,标题块那个方法里有过了if(!d){d = trans_create_block('')d.id=ID_TRANSLATED_DESC;d.title=p.innerText; // 标题块中缓存原文p.parentElement.appendChild(d);}googleTranslateProxy(p.innerText.replace(/\n/g, CRLF), fv(ID_TRANSLATED_DESC), trans_desc);}// ----- 评论区翻译按钮 以下var ID_COMMENT_TRANSLATE_TRIGGER = 'leorchn_comment_translate_trigger',ID_COMMENT_TRANSLATION_BLOCK = 'leorchn_comment_translation_block';function button_trans_comment(){var p=$$('main section li div>span+span+span');for(var i=0;i<p.length;i++){var parent = p[i].parentElement;if(parent.getElementsByClassName(ID_COMMENT_TRANSLATE_TRIGGER).length == 0){var d=ct('span', '翻译');d.className=p[i].className + ' ' + ID_COMMENT_TRANSLATE_TRIGGER;d.style.marginLeft='16px';d.onclick=function(){var _this=this,commentRoot=this.parentElement.previousElementSibling;if(commentRoot.getElementsByClassName(ID_COMMENT_TRANSLATION_BLOCK).length == 0){var tb = trans_create_block('')tb.className = ID_COMMENT_TRANSLATION_BLOCK;commentRoot.appendChild(tb);}googleTranslateProxy(commentRoot.children[0].innerText, commentRoot.getElementsByClassName(ID_COMMENT_TRANSLATION_BLOCK)[0]);}parent.appendChild(d);}}}// ========== 作品页面(单图预览和评论区) 以上// ========== 自己和其他画师空间 以下// ----- 主页(显示全部作品、筛选其中一个标签)function tagTranslate_illust(){if(location.pathname != '/member_illust.php')return;var tags=$$('div>nav+div>div>div>ul>li');if(tags.length==0)return;for(var li=0;li<tags.length;li++){var c=tags[li].children,tt=tagDict(c[0].innerText);if(tt){c[0].innerText=tt;}}}// ----- 所有已加心的作品 页面function tagTranslate_bookmark(){if(location.pathname != '/bookmark.php')return;tagTranslate_mode_tagCloud();}// ----- 所有绘制的作品包含的标签(包含频率降序)function tagTranslate_member_tag_all(){if(location.pathname != '/member_tag_all.php')return;tagTranslate_mode_tagCloud();var tags=fc('tag-list');if(tags.length==0)return;tags=tags[0].getElementsByTagName('dd');for(var dd=0;dd<tags.length;dd++){var c=tags[dd].childNodes[0].childNodes;for(var li=0;li<c.length;li++){var tt=tagDict(c[li].innerText);if(tt){var atag= c[li].getElementsByTagName('a')[0];atag.innerText=tt;atag.style.backgroundColor='#ffd040';}}}}// ----- 加心/编辑心 页面function tagTranslate_addBookmark(){if(location.pathname != '/bookmark_add.php')return;var tags=fc('tag-cloud');if(tags.length==0)return;for(var g=0,gt=tags;g<gt.length;g++){tags=gt[g].childNodes;for(var li=0;li<tags.length;li++){try{ // 作品自带标签的列表中,“原创”后面竟然跟一个空白的元素不知道为啥var c=tags[li].childNodes[0].childNodes,cl=c.length-1,tt=tagDict(c[cl].nodeValue);if(tt) c[cl].nodeValue=tt;}catch(e){}}}}// ========== 自己和其他画师空间 以上// ----- 模板:标签云function tagTranslate_mode_tagCloud(){var tags=fc('tagCloud');if(tags.length==0)return;tags=tags[0].childNodes;for(var li=0;li<tags.length;li++){try{if(tags[li].className.includes('level0')) continue;}catch(e){ continue; }tags[li].style.display='inline-block';var c=tags[li].childNodes[0].childNodes,tt=tagDict(c[0].nodeValue);if(tt) c[0].nodeValue=tt;}}// ----- 标签 字典翻译function tagDict(origin){for(var i=0;i<tag_trans.length;i+=2)if(origin==tag_trans[i])return tag_trans[i+1];}var CRLF = '<br>', CRLF_REGEX_ESCAPE = '&lt;br&gt;';// ----- 创建和编辑外部翻译块function trans_create_block(oriText, existsBlock){var n=existsBlock? existsBlock: ct('p');n.innerHTML=oriText? googleTranslate_get(oriText).replace(new RegExp(CRLF_REGEX_ESCAPE, 'g'), CRLF): '翻译中';n.style.backgroundColor='#d0ffd0';return n;}//----- my ezjs libfunction fv(id){return document.getElementById(id);}function ft(tag){return document.getElementsByTagName(tag);}function fc(cname){return document.getElementsByClassName(cname);}function ct(tag, t){var d=document.createElement(tag); if(t)d.innerText=t; return d;}function $(s){return document.querySelector(s);}function $$(s){return document.querySelectorAll(s);}function msgbox(msg){alert(msg);}function inputbox(title,defalt){return prompt(title,defalt);}function pl(s){console.log(s);}function googleTranslateProxy(origText, postTo, invokeWhenFinish){/* 如果此处判定成功则是原文过长,感觉没有翻译成功的希望,暂时隐藏它。此处的 4500字节 = 500亚洲文字 或者 4500英文字母和数字空格和某些需要转义的字符和标点每个占 3字节亚洲文字及标点每个占 9字节。例如“我”这个字转义后是 %E6%88%91 即占用 9字节*/if(encodeURI(origText).length > 4500){postTo.style.display = 'none';}googleTranslate(origText, function(r){if(!r.responseText || r.responseText.length<20) if(googleTranslateProxy(origText, postTo) || true) return;trans_create_block(r.responseText, postTo);if(postTo.style.display == 'none') postTo.style.display = ''; // 已翻译完成,取消隐藏(如果之前觉得这个翻译块没有翻译成功的希望并被隐藏的话)if(invokeWhenFinish) try{ invokeWhenFinish(); }catch(e){}});}function googleTranslate_get(origin){return new RegExp('<div\\s.{0,15}class=\\"t0\\".{0,15}>(.*)<\\/div><f').exec(origin)[1];}function googleTranslate(word,dofun,dofail){http('get','https://translate.google.cn/m?hl=zh-CN&sl=auto&tl=zh-CN&ie=UTF-8&prev=_m&q='+encodeURI(word),'',dofun,dofail);}function http(_method,_url,formdata,dofun,dofail){GM_xmlhttpRequest({method: _method.toUpperCase(),url: _url,data: formdata,headers:{},onload: dofun,onerror: dofail});}