🏠 Home 

Yandex一键翻译

右下角出现一个一键翻译的按钮,点击即可一键翻译当前页面


Install this script?
  1. // ==UserScript==
  2. // @name Yandex一键翻译
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.0.3
  5. // @description 右下角出现一个一键翻译的按钮,点击即可一键翻译当前页面
  6. // @author thunder-sword
  7. // @match *://*/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=yandex.com
  9. // @license MIT
  10. // @grant GM_xmlhttpRequest
  11. // @grant GM_setValue
  12. // @grant GM_getValue
  13. // @connect translate.yandex.com
  14. // ==/UserScript==
  15. //系统变量
  16. var g###ode='';
  17. class NetworkError extends Error {
  18. constructor(message) {
  19. super(message);
  20. this.name = "NetworkError";
  21. }
  22. }
  23. // 封装GM_xmlhttpRequest为Promise
  24. function httpRequest(options) {
  25. return new Promise((resolve, reject) => {
  26. GM_xmlhttpRequest({
  27. ...options,
  28. onload: response => resolve(response),
  29. onerror: error => reject(error)
  30. });
  31. });
  32. }
  33. //作用:生成toast,让其在toast_container中,显示在页面中上部,会永久性向页面添加一个id为ths_toast_container的div标签
  34. function showStackToast(message, backcolor='rgb(76, 175, 80)', timeout=3000){
  35. //没有容器则生成容器
  36. let box=document.querySelector("body > div#ths_toast_container");
  37. if(!box){
  38. box=document.createElement('div');
  39. box.id="ths_toast_container";
  40. box.style.cssText = `
  41. position: fixed;
  42. top: 10px;
  43. left: 50%;
  44. transform: translateX(-50%);
  45. right: 10px;
  46. width: 300px;
  47. height: auto;
  48. display: flex;
  49. z-index: 9999;
  50. flex-direction: column-reverse;`;
  51. document.body.appendChild(box);
  52. }
  53. //创建toast
  54. const toast = document.createElement('div');
  55. toast.innerText = message;
  56. toast.style.cssText = `
  57. padding: 10px;
  58. background-color: ${backcolor};
  59. color: rgb(255, 255, 255);
  60. border-radius: 10px;
  61. font-size: 24px;
  62. font-weight: bold;
  63. text-align: center;
  64. box-shadow: rgb(0 0 0 / 30%) 0px 5px 10px;
  65. opacity: 1;
  66. transition: opacity 0.3s ease-in-out 0s;
  67. z-index: 9999;
  68. margin: 5px;
  69. `;
  70. box.appendChild(toast);
  71. toast.style.opacity = 1;
  72. if(timeout > 0){
  73. setTimeout(() => {
  74. toast.style.opacity = 0;
  75. setTimeout(() => {
  76. box.removeChild(toast);
  77. }, 300);
  78. }, timeout);
  79. }
  80. return toast;
  81. }
  82. //作用:获取gpc
  83. async function getGCP(){
  84. console.log("尝试获取token……");
  85. showStackToast("尝试获取token……");
  86. const data = await httpRequest({
  87. url: 'https://translate.yandex.com/',
  88. }).then(function(response) {
  89. return response.responseText;
  90. }).catch(error => {
  91. if (error instanceof NetworkError) {
  92. console.error("Network error: ", error.message);
  93. } else {
  94. console.error("Other error: ", error);
  95. alert("获取数据失败,请联系开发者");
  96. }
  97. });
  98. let fIndex=data.indexOf('GC_STRING');
  99. if(-1===fIndex){
  100. console.log(data);
  101. console.log("没有找到GC_STRING");
  102. showStackToast("获取token失败,请联系开发者", "red");
  103. }
  104. let gStart=fIndex+13;
  105. g###ode=data.substr(gStart, data.indexOf("'", gStart)-gStart);
  106. showStackToast("获取token成功");
  107. //设置到全局变量中
  108. GM_setValue("g###ode", g###ode);
  109. }
  110. //作用:翻译一个页面
  111. async function translatePage(url){
  112. if(!g###ode){
  113. if(!GM_getValue("g###ode")){
  114. await getGCP();
  115. } else{
  116. g###ode=GM_getValue("g###ode");
  117. }
  118. }
  119. //尝试使用g###ode打开翻译页面
  120. window.open(`https://translate.yandex.com/translate?view=compact&lang=en-zh&gcp=${g###ode}&url=${url}`);
  121. }
  122. //版本号:v0.0.2
  123. //作用:创建一个在右下角出现的悬浮窗按钮,多个按钮会自动排序,点击即可执行对应函数
  124. function createFloatButton(name, func){
  125. //没有容器则生成容器
  126. let box=document.querySelector("body > div#ths_button_container");
  127. if(!box){
  128. box=document.createElement('div');
  129. box.id="ths_button_container";
  130. box.style.cssText = `
  131. position: fixed;
  132. bottom: 10px;
  133. right: 10px;
  134. min-height: 30px; /* 设置一个最小高度,确保容器有一定高度 */
  135. display: flex;
  136. z-index: 9999;
  137. flex-direction: column;
  138. `;
  139. document.body.appendChild(box);
  140. }
  141. // 创建一个 div 元素
  142. var floatWindow = document.createElement('div');
  143. // 设置 div 的内容
  144. //floatWindow.innerHTML = '点我执行代码';
  145. floatWindow.innerHTML = name;
  146. // 设置 div 的样式
  147. floatWindow.style.cssText = `
  148. padding: 5px;
  149. background-color: #333;
  150. color: #fff;
  151. border-radius: 5px;
  152. font-size: 16px;
  153. text-align: center;
  154. opacity: 1;
  155. z-index: 9999;
  156. margin: 5px;
  157. cursor: pointer; /* 鼠标可以选中 */
  158. `;
  159. // 将悬浮窗的优先级提高
  160. floatWindow.style.zIndex = "99999";
  161. var isDragging = false;
  162. var currentX;
  163. var currentY;
  164. var initialX;
  165. var initialY;
  166. var xOffset = 0;
  167. var yOffset = 0;
  168. var cursorX;
  169. var cursorY;
  170. floatWindow.addEventListener("mousedown", function(e) {
  171. if (!isDragging) {
  172. cursorX = e.clientX;
  173. cursorY = e.clientY;
  174. initialX = cursorX - xOffset;
  175. initialY = cursorY - yOffset;
  176. isDragging = true;
  177. }
  178. });
  179. floatWindow.addEventListener("mousemove", function(e) {
  180. if (isDragging) {
  181. e.preventDefault();
  182. currentX = e.clientX - initialX;
  183. currentY = e.clientY - initialY;
  184. xOffset = currentX;
  185. yOffset = currentY;
  186. setTranslate(currentX, currentY, floatWindow);
  187. }
  188. });
  189. floatWindow.addEventListener("mouseup", async function(e) {
  190. initialX = currentX;
  191. initialY = currentY;
  192. isDragging = false;
  193. // 如果点击时鼠标的位置没有改变,就认为是真正的点击
  194. if (cursorX === e.clientX && cursorY === e.clientY) {
  195. await func();
  196. }
  197. });
  198. // 为悬浮窗添加事件处理程序,用来监听触摸开始和触摸移动事件
  199. // 这些事件处理程序的实现方式与上面的鼠标事件处理程序类似
  200. floatWindow.addEventListener('touchstart', (event) => {
  201. if (!isDragging) {
  202. cursorX = event.touches[0].clientX;
  203. cursorY = event.touches[0].clientY;
  204. initialX = cursorX - xOffset;
  205. initialY = cursorY - yOffset;
  206. isDragging = true;
  207. }
  208. });
  209. floatWindow.addEventListener('touchmove', (event) => {
  210. if (isDragging) {
  211. currentX = event.touches[0].clientX - initialX;
  212. currentY = event.touches[0].clientY - initialY;
  213. xOffset = currentX;
  214. yOffset = currentY;
  215. setTranslate(currentX, currentY, floatWindow);
  216. }
  217. });
  218. // 为悬浮窗添加事件处理程序,用来监听触摸结束事件
  219. // 这个事件处理程序的实现方式与上面的鼠标事件处理程序类似
  220. floatWindow.addEventListener('touchend', async () => {
  221. initialX = currentX;
  222. initialY = currentY;
  223. isDragging = false;
  224. // 如果点击时鼠标的位置没有改变,就认为是真正的点击
  225. if (cursorX === event.touches[0].clientX && cursorY === event.touches[0].clientY) {
  226. await func();
  227. }
  228. });
  229. function setTranslate(xPos, yPos, el) {
  230. el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0)";
  231. }
  232. //将悬浮窗添加到box元素中
  233. box.appendChild(floatWindow);
  234. }
  235. //作用:主函数,添加翻译当前页面的按钮
  236. function mainFunction(){
  237. createFloatButton("一键翻译", ()=>{
  238. translatePage(window.location.href);
  239. });
  240. }
  241. (function() {
  242. 'use strict';
  243. mainFunction();
  244. })();