翻譯小工具 | 翻譯任何語言

任何語言翻譯及快捷一鍵翻譯想要語言 | 頁面翻譯 | 選中文字( 按Ctrl )| 提供快捷方式,只需按一個鍵即可快速翻譯想要語言 |英文學習 | 翻譯文可設置,支持全球多數通用語言 | 有什麼問題都可以反饋

  1. // ==UserScript==
  2. // @name Smart Translator Tool
  3. // @name:ar أداة الترجمة |
  4. // @name:bg Превод на джаджа |
  5. // @name:cs Překlad Widget |
  6. // @name:da Oversættelseswidget |
  7. // @name:de Übersetzungs -Widget |
  8. // @name:el Μεταφραστικό widget | Μεταφράστε οποιαδήποτε γλώσσα
  9. // @name:en Translation widget | Translate any language
  10. // @name:eo Traduko -fenestraĵo |
  11. // @name:es Widget de traducción |
  12. // @name:fi Käännöswidget | Käännä kaikki kielet
  13. // @name:fr Widget de traduction | Traduire n’importe quelle langue
  14. // @name:fr-CA Widget de traduction | Traduire n’importe quelle langue
  15. // @name:he יישומון תרגום |
  16. // @name:hr Prijevod Widget |
  17. // @name:hu A Widget fordítása |
  18. // @name:id Widget Terjemahan | Menerjemahkan bahasa apa pun
  19. // @name:it Widget di traduzione |
  20. // @name:ja 翻訳ウィジェット|
  21. // @name:ka თარგმანის ვიჯეტი | თარგმნეთ ნებისმიერი ენა
  22. // @name:ko 번역 위젯 |. 모든 언어 번역
  23. // @name:nb Oversettelseswidget |
  24. // @name:nl Vertaalwidget |
  25. // @name:pl Widżet tłumaczenia |
  26. // @name:pt-BR Widget de tradução |
  27. // @name:ro Widget de traducere |
  28. // @name:ru Перевод виджет |
  29. // @name:sk Preklad miniaplikácie
  30. // @name:sr Превод Видгет | Преведи било који језик
  31. // @name:sv Översätt widget | Översätt något språk
  32. // @name:th วิดเจ็ตแปล
  33. // @name:tr Çeviri widget’ı |
  34. // @name:ug تەرجىمە كىچىك قورالى | ھەر قانداق تىلنى تەرجىمە قىلىڭ
  35. // @name:uk Віджет перекладу | Перекладіть будь -яку мову
  36. // @name:vi Tiện ích dịch |
  37. // @name:zh 翻译小工具 | 翻译任何语言
  38. // @name:zh-CN 翻译小工具 | 翻译任何语言
  39. // @name:zh-HK 翻譯小工具 | 翻譯任何語言
  40. // @name:zh-SG 翻译小工具 | 翻译任何语言
  41. // @name:zh-TW 翻譯小工具 | 翻譯任何語言
  42. // @description Translate any language and quickly translate the desired language with one key | Page translation | Select text (Press Ctrl) | Provides shortcuts, allowing quick translation of the desired language with just one key | English learning | Translation settings available, supporting most common languages worldwide | Feel free to provide feedback for any issues
  43. // @description:ar ترجمة أي لغة واختصار للترجمة |
  44. // @description:bg Превод на всеки език и пряк път с едно щракване превод на езика, който искате | Превод на страница | Изберете текст (натиснете Ctrl) | Осигурете преки пътища, просто натиснете един клавиш, за да преведете бързо желания език | Английско обучение | Преводът може да бъде зададен и поддържа най -често срещаните езици по света | Обратна връзка, ако имате въпроси
  45. // @description:cs Překlad jazyka a překladu jazyka, který chcete, překlad |
  46. // @description:da Oversættelse af ethvert sprog og genvej med et-klik på det sprog, du ønsker |
  47. // @description:de Übersetzung von Sprach- und Verknüpfungsverknüpfungen Ein-Klick-Übersetzung der gewünschten Sprache | Seitenübersetzung | Text auswählen (drücken Sie Strg) | Stellen Sie Verknüpfungen an, drücken Sie einfach eine Taste, um schnell die gewünschte Sprache zu übersetzen | Englisches Lernen | Die Übersetzung kann festgelegt werden und unterstützt die häufigsten Sprachen auf der ganzen Welt | Feedback, wenn Sie Fragen haben
  48. // @description:el Μετάφραση οποιασδήποτε γλώσσας και συντόμευσης με ένα κλικ της γλώσσας που θέλετε |
  49. // @description:en Translation of any language and shortcut one-click translation of the language you want | Page Translation | Select text (press Ctrl) | Provide shortcuts, just press one key to quickly translate the language you want | English learning | Translation can be set and supports most common languages around the world | Feedback if you have any questions
  50. // @description:eo Traduko de iu ajn lingvo kaj ŝparvojo unu-klaka traduko de la lingvo, kiun vi volas
  51. // @description:es Traducción de cualquier idioma y atajo Traducción del idioma que desee |
  52. // @description:fi Minkä tahansa kielen käännös ja pikakuvake yhden napsautuksen käännös haluamastasi kielestä | Sivun käännös | Valitse teksti (paina Ctrl) | Tarjoa pikakuvakkeita, painamalla vain yhtä näppäintä kääntääksesi haluamasi kielen nopeasti | Englannin oppiminen | Käännös voidaan asettaa ja tukee yleisimpiä kieliä ympäri maailmaa | Palautetta, jos sinulla on kysyttävää
  53. // @description:fr Traduction de toute langue et de la traduction en un seul clic de la langue que vous voulez |
  54. // @description:fr-CA Traduction de toute langue et de la traduction en un seul clic de la langue que vous voulez |
  55. // @description:he תרגום של כל שפה וקיצור של לחיצה אחת על השפה שאתה רוצה |
  56. // @description:hr Prijevod i prečac prijevoda jezika koji želite prijevod |
  57. // @description:hu Bármely nyelv és a parancsikon a kívánt nyelv fordítása |
  58. // @description:id Terjemahan dari bahasa apa pun yang Anda inginkan |
  59. // @description:it Traduzione di qualsiasi linguaggio e premi per la traduzione della lingua |
  60. // @description:ja 任意のショートカットのページ翻訳|
  61. // @description:ka ნებისმიერი ენის თარგმანი და მალსახმობი ერთ-
  62. // @description:ko 모든 언어의 번역은 원하는 텍스트를 선택하십시오
  63. // @description:nb Oversettelse av noe språk og snarvei enklikk på oversettelsen av språket du vil ha | Sideoversettelse |.
  64. // @description:nl Vertaling van elke taal- en snelkoppelingsklikvertaling van de taal die u wilt | Pagina-vertaling | Selecteer tekst (druk op CTRL) |
  65. // @description:pl Tłumaczenie dowolnego języka i skrót tłumaczenie jednego kliknięcia języka, który chcesz | Tłumaczenie strony | Wybierz tekst (naciśnij Ctrl) | Podaj skróty, wystarczy nacisnąć jeden klawisz, aby szybko przetłumaczyć żądany język | Uczenie się angielskiego | Tłumaczenie może być ustawione i obsługuje najczęstsze języki na całym świecie | Informacje zwrotne, jeśli masz jakieś pytania
  66. // @description:pt-BR Tradução de qualquer idioma e atalho com um clique de tradução do idioma que você deseja | Tradução da página | Selecione Texto (pressione Ctrl) | Forneça atalhos, basta pressionar uma tecla para traduzir rapidamente o idioma que deseja | Aprendizagem de inglês | A tradução pode ser definida e suporta idiomas mais comuns em todo o mundo | Feedback se você tiver alguma dúvida
  67. // @description:ro Traducere a oricărei limbi și scurte de traducere cu un singur clic pe un singur clip
  68. // @description:ru Перевод любого языка и ярлык.
  69. // @description:sk Preklad akéhokoľvek jazyka a skratkou prekladu, ktorý chcete, preklad s jedným kliknutím |
  70. // @description:sr Превод било којег језика и пречице Превод једног клика Један превод језика | Изаберите текст (Притисните ЦТРЛ) | Обезбедите пречице, само притисните један тастер да бисте брзо превели језик у којем се можете подесити и подржати најчешћи језици широм света | ако имате било каква питања.
  71. // @description:sv Översättning av alla språk och genvägar en klick översättning av det språk du vill ha |
  72. // @description:th การแปลภาษาใด ๆ และการแปลภาษาหนึ่งคลิกของภาษาที่คุณต้องการ
  73. // @description:tr Herhangi bir dil ve kısayol, metin seçin |
  74. // @description:ug سىز تاللىغان تىل ۋە «قىسقا ئۇچۇرنى تاللاش تەرجىمىسى | قىسقا ئۇچۇر بىلەن تەمىنلەڭ | پەقەت بىر ئاچقۇچنى باسسىڭىز بىر ئاچقۇچنى باسسىڭىز بولىدۇ | ئىنگلىزچە ئۆگىنىشنى | سوئاللىرىڭىز بولسا تەكلىپ-پىكىرلەرنى تىزىڭ ۋە قوللايدۇ
  75. // @description:uk Переклад будь-якої мови та ярлика клацання перекладу мови, яку ви хочете | Переклад сторінки | Виберіть текст (натисніть Ctrl) | Надайте ярлики, просто натисніть одну клавішу, щоб швидко перекласти потрібну мову | Англійське навчання | Переклад може бути встановлений та підтримує найпоширеніші мови у всьому світі | Відгук Якщо у вас є якісь питання
  76. // @description:vi Bản dịch của bất kỳ ngôn ngữ nào của Ngôn ngữ bạn muốn |
  77. // @description:zh 任何语言翻译及快捷一键翻译想要语言 | 页面翻译 | 选中文字( 按Ctrl )| 提供快捷方式,只需按一个键即可快速翻译想要语言 |英文学习 | 翻译文可设置,支持全球多数通用语言 | 有什么问题都可以反馈
  78. // @description:zh-CN 任何语言翻译及快捷一键翻译想要语言 | 页面翻译 | 选中文字( 按Ctrl )| 提供快捷方式,只需按一个键即可快速翻译想要语言 |英文学习 | 翻译文可设置,支持全球多数通用语言 | 有什么问题都可以反馈
  79. // @description:zh-HK 任何語言翻譯及快捷一鍵翻譯想要語言 | 頁面翻譯 | 選中文字( 按Ctrl )| 提供快捷方式,只需按一個鍵即可快速翻譯想要語言 |英文學習 | 翻譯文可設置,支持全球多數通用語言 | 有什麼問題都可以反饋
  80. // @description:zh-SG 任何语言翻译及快捷一键翻译想要语言 | 页面翻译 | 选中文字( 按Ctrl )| 提供快捷方式,只需按一个键即可快速翻译想要语言 |英文学习 | 翻译文可设置,支持全球多数通用语言 | 有什么问题都可以反馈
  81. // @description:zh-TW 任何語言翻譯及快捷一鍵翻譯想要語言 | 頁面翻譯 | 選中文字( 按Ctrl )| 提供快捷方式,只需按一個鍵即可快速翻譯想要語言 |英文學習 | 翻譯文可設置,支持全球多數通用語言 | 有什麼問題都可以反饋
  82. // @author shing0727@foxmail.com,人民的勤务员 <china.qinwuyuan@gmail.com>
  83. // @namespace https://github.com/ChinaGodMan/UserScripts
  84. // @supportURL https://github.com/ChinaGodMan/UserScripts/issues
  85. // @homepageURL https://github.com/ChinaGodMan/UserScripts
  86. // @license MIT
  87. // @match *://*/*
  88. // @icon https://s21.ax1x.com/2024/05/17/pkuVzUH.png
  89. // @require https://code.jquery.com/jquery-3.6.0.min.js
  90. // @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js
  91. // @compatible chrome
  92. // @compatible firefox
  93. // @compatible edge
  94. // @compatible opera
  95. // @compatible safari
  96. // @compatible kiwi
  97. // @compatible qq
  98. // @compatible via
  99. // @compatible brave
  100. // @version 2025.03.21.1227
  101. // @grant GM_xmlhttpRequest
  102. // @created 2025-03-21 12:27:54
  103. // @modified 2025-03-21 12:27:54
  104. // ==/UserScript==
  105.  
  106. // 百度logo
  107. var baiduImgData = `data:image/png;base64,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`
  108.  
  109. // 谷歌logo
  110. var googleImgData = `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAACO5JREFUeF7dWw1wk+Ud//2f5A20DexYaRHLBofgGBPxaFoPxK20gVMs3oEtUMYYoOPjmBs32U4pTJyCB/POc4ofm+vGkO8v107qSpJygkBJOZRzyE45dDihCcjRpqlN8r7/kUC5tE2a90lSEvfe5XLJ+/t//H55nvf5+ofQy9fnE8cMMGdkFqisFYJRSMAgZvQHoR9uvDPDLQguBtwAuxnkBrNbIcPeb9sbTvVmitQbzl2TC+4BoxSMqQAKARgSiHOWCPtY5fqcr5V6Onq0LQFf3UyTJsDFKRNyEfDNMYBKmVCSzCTDfDURoVpAVGXbGo4lI0ZSBHBZCx8H83IAw5ORlB4fBGwhpqqBjuMOPfhomIQEcJVYysC0HIT7EkkiQdt9BKrKsR//Rzx+4hLgy6L8gYpRrGPGz+IJ2hs2RHghx+b8taxvaQFckyxTIWgdgLGywXobz8AxI8Sj2faG03pjSQngLrY8zURr9DpPHY4ey7Uf/7Oe+LoFaCopeIKAF/Q4TTWGmZ8Z5GjU9UPpEsBdYlnEoDdSTUxPfBnyQX8xBXCVWFYCtFZP8FRjZMnHFMBdbFnORC+mmpie+PGQ71GAppKCuQRs1hM81Zh4yUcVoKmkcDyB3wXQP8nk2ghwasz1IHIRk1sVmlswDSHCEGZ8B4QhxLAAuF1P7ETIRxXAVVJQC+ABPQnExBAuMFO1pmnVBva+l3vwtCemDYCLk/LvJaIHhRAPMPO9kWwSJR9RgCZr4Txi3qQnyRiY82De0CJ48x22E1cT8eeyWhYS07Mc1iqSQb6bAP8aPdqUMzirEcCYRBIG0SsGwRuy65znE/ITZhxaYqtYDcKMZJHvJoDLWvAkGM8nlDRjYa7D+ZeEfEQx5vJyg+vyudV6Jzl6cug0D/C8eNuZttq8VlbFOD3GXTEq8aTBtsaD8dimyuamAAGboZQhalRXBrfsHXaYr/S5XyYpZlo6yHH8dRmbdMCGCaC8xcCPO5Ly/n3oEd/pARYGTLESTWafjBUr2fdDAjBDBGyKHwQRHqC9ceAZryNPgUp39BB4e67dWZHsxG6Vv5AAvjrlJyTwt0hBtWbF17x55EfcbIr0XPCCeGKurfHkrUo42XFCAvhtplqAe5z4ePYNPeI/M2BCeALf5KbfwYOabcjOgHJJj7K+jwd84Kn+bh5plAOwR1WNYwYfPPaZHtt0xVDA3mcas1atN0EKCM/VN0edVr9SGnIdjb/Qa5euOFJtymINkB6+2mqGTev/0idx7cSGi1H0bEuREFSfCoE05tnkt5l+B/BqyQTaFau/r6RNRHgqBWDgNxSwKW8y8KgcGd6jWANlcjaR0akVgDZSwG7az8wPypHhSsUaCG6NJ3ylUgCAashvUz4EcLcME2YsMk32/0nGJho2tQLgVLALuBkYKENGA03vY/W9LWOTngLwVfIfUNpBsef74QSItVLjZPWd/wMBWoIt4BwDw6TIED+plATWS9lEAae4C5wJPgOOABgvQ4aBLSarf66MTVp2AYKD/DbjboAekSTzoWL13yNpk3bzAABvke+A8jIRfi5JRlWsfqOkTToKsD7YAp4CQsfdUteK5sIpL814/4CUUQRwKp8BzPxL8tUp80lA9yZmOxuwornw0mequfbdmfvnJUUAoEi3HyEYmtb9TFNQsBhLakJHxOXktxungOmfehJo8OViVUt+q4eVLACeAKtjPqh4O+XL4aLnvx4htMAnejiEY4SKu29siCjB0rMeFzeve78f2OQd2bnfMz/TWLFX1zm8bHIy+OK13scB7Q8yNgycq680Dw8JELArrzFjSSQHLrUv1rTmXznpyx7Q7T7BCw0TGyv2pHRLrHitZ79s82fwq/WV/ZZdbwF1xvsg6HBXgnXteXjZ84Mrl7hvd/I3wby9cfbelG2KlqxrLWXmGplf/zqWpjoqs2pvPkz8duVjMEZ1OPqj93vaprY7NY0p9nCXwq5QvLa1GuBpUgIwLjpWmQeHZOgwVO3Gymtkn/s00B9veEddPuy7LVvGKTOWnqjYI72zJBOjK7Z4nWcFGL+X9UFEm+wrs+Z3EoBtfYfb2nPObvTedeELNTOkjvTFNKmxYvctORorXts8HxC6h+9wLsEDoPpK89ZOAgQ/LN3zwy1Of84caeJhBgRa6Jy9O67E9MYtfq51CYhf04vvjOP3HZX9JnZ812lCMXpnuSlT0xI/HgdeIVY2OCu2J+14PJhw0RqX2aBkbWRw3BOw4EbowVX9dkQUIPilZXvZPCAZBRJ8HqANLMTmEzN3JVQgMW5b2f2CtAWkZS7I+s/6BqF+K2LFiI4WUeOoND8cjotYJmfZUVYL7vmkSEewG6MNLoC5GipVexXx3umZu3SVyEzYOz3X7xMVzKgAoRPhjKZldYqncIruHG4ASWCy/SmzLaYAhVunj9eE6JUiKQBOXC+SugTQJWjqZQhDNoOHEWEoQMPAHNygCb6izk6NLeOPZbqWjASgd7T6q6PSvKCraFELJQu2PjKXRXqXyRn8g65kfvHbU6SZf9Rza6BPNWjTD1b2+0i3ADeeB8sBTvtCycwLv3rH6B37UGQRuJmIS+0r+x+KdD9mqaxlR9lKMKd9qazpykOHMr6aOYKBznMYpocdq7KiTpVjCnC9JcxYhG9AsbSh7c7Psy4u/y+0rNAx/rUV30+vrfgi1j1EHQaj9aX8HTOeIKa0L5cnLQOZX65wGHwjah0rzTHz1dUCOkSxbJuxBkRPyw4/txpPoGXO2btf1RNXSoBQd9hWVgTioAj6t7H0ZJIczFkwPSazHpEWIF1bAxPt04gWn5y5yy2jZdwCBIOM21meLzRtEYDgK0UXnwejKt6tuYQE6GCcIiH+DeIqVv1VJ+bU6KpximseIPOzWrZPv4vYMEsDzyJCcJraG1dw/7GKr/qqTiyu8SYaICktoGsSoWW1qs6CELMAHgvGkAQS9TDRAQIfEqp27PicfUcT8NXNtFcE6Bpl7M7yPJPKo1jwKHDo/8V5YM4D0e0g5BGTl8EuQugv9NffOfhZ1DkrdgcPb3vt+h/a74oTH5DaPgAAAABJRU5ErkJggg==`
  111. var cssContent = `
  112. .fy_btn_box{
  113. position: fixed;
  114. top: 50px;
  115. right: 50px;
  116. z-index: 9999;
  117. background-color: rgba(255, 255, 255, 0.5);
  118. border-radius: 10px;
  119. padding: 10px;
  120. box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
  121. color: #333;
  122. }
  123. #fy_transContainer{
  124. display: none;
  125. position: fixed;
  126. top: 50px;
  127. left: 50px;
  128. max-width: 500px;
  129. min-width: 300px;
  130. padding: 10px;
  131. padding-top: 24px;
  132. border-radius: 4px;
  133. flex-direction: column;
  134. justify-content: center;
  135. align-items: flex-start;
  136. box-shadow: 0 3px 10px 1px rgba(0, 0, 0, 0.1);
  137. background-color: rgba(255,255,255,0.7);
  138. backdrop-filter: saturate(420%) blur(50px);
  139. -webkit-backdrop-filter: saturate(420%) blur(50px);
  140. z-index: 9999;
  141. font-size: 14px;
  142. border-bottom-right-radius: 0;
  143. overflow: hidden;
  144. }
  145. #fy_dragBar{
  146. position: absolute;
  147. top: 0;
  148. left: 0;
  149. width: 100%;
  150. height: 20px;
  151. cursor: grab;
  152. // background-color: #F9E79F;
  153. background-color: rgba(0,0,0,0.1);
  154. backdrop-filter: saturate(420%) blur(50px);
  155. -webkit-backdrop-filter: saturate(420%) blur(50px);
  156. }
  157. #fy_Scale_rb, #fy_Scale_lb{
  158. position:absolute;
  159. bottom:0;
  160. width:9px;
  161. height:9px;
  162. // background: #ddd;
  163. // clip-path: polygon(100% 0%, 100% 100%, 0% 100%);
  164. }
  165. #fy_Scale_rb{
  166. right:0;
  167. cursor: nw-resize;
  168. }
  169. #fy_Scale_lb{
  170. left:0;
  171. cursor: ne-resize;
  172. }
  173.  
  174. #fy_contentBox{
  175. width: 100%;
  176. overflow: auto;
  177. line-height: 1.3em;
  178. letter-spacing: 0.5px;
  179. }
  180. #fy_contentBox .textRight{
  181. text-align: right;
  182. }
  183. .transText_node{
  184. width: 100%;
  185. padding: 7px;
  186. box-sizing: border-box;
  187. }
  188. .transText_node:hover{
  189. background-color: rgba(0,0,0,0.04);
  190. border-radius: 6px;
  191. }
  192. .transText_node_to{
  193. position: relative;
  194. transition: all 0.2s;
  195. }
  196. .transText_node_from{
  197. position: relative;
  198. height: 0;
  199. overflow: hidden;
  200. transition: all 0.2s;
  201. }
  202.  
  203. #fy_contentBox .fy_node_expand{
  204. background-color: rgba(0,0,0,0.04);
  205. border-radius: 6px;
  206. margin: 5px 0;
  207. }
  208.  
  209. .fy_node_expand .transText_node_from, .fy_node_expand .transText_node_to{
  210. padding: 6px 8px;
  211. }
  212. .fy_node_expand .transText_node_to{
  213. background-color: rgb(209, 255, 240);
  214. border-top-left-radius: 4px;
  215. border-top-right-radius: 4px;
  216. }
  217. .fy_node_expand .transText_node_from{
  218. background-color: rgb(254, 234, 242);
  219. height: auto;
  220. border-bottom-left-radius: 4px;
  221. border-bottom-right-radius: 4px;
  222. }
  223.  
  224. .icon_style{
  225. position: absolute;
  226. right: 0;
  227. bottom: 0;
  228. cursor: pointer;
  229. opacity: 0;
  230. transition: all 0.3s ease;
  231. width: 20px;
  232. z-index: 9999;
  233. opacity: 0.5;
  234. }
  235. .transText_node_from:hover .copy_icon{
  236. opacity: 1;
  237. }
  238. .transText_node_to:hover .copy_icon{
  239. opacity: 1;
  240. }
  241. .fy_node_expand .copy_icon{
  242. right: 5px;
  243. bottom: 5px;
  244. }
  245.  
  246. #fy_ctrl_ber{
  247. position: absolute;
  248. top: 2px;
  249. right: 0;
  250. }
  251. #fy_select, #fy_api_select{
  252. position: relative;
  253. background-color: transparent;
  254. border: none; /* 去除默认边框 */
  255. box-shadow: none; /* 去除默认的阴影 */
  256. outline: none; /* 去除可能的轮廓线 */
  257. font: inherit;
  258. line-height: 1.2em;
  259. height: auto;
  260. text-align: center;
  261. width: auto;
  262. min-width: auto;
  263. min-height: auto;
  264. }
  265. #fy_api_select{
  266. }
  267.  
  268. #fy_loading{
  269. display: none;
  270. width: 100%;
  271. padding-top: 10px;
  272. display: flex;
  273. align-items: center;
  274. justify-content: center;
  275. }
  276. #fy_loading svg {
  277. width: 2.25em;
  278. transform-origin: center;
  279. animation: rotate4 2s linear infinite;
  280. }
  281.  
  282. #fy_loading circle {
  283. fill: none;
  284. stroke: hsl(214, 97%, 59%);
  285. stroke-width: 2;
  286. stroke-dasharray: 1, 200;
  287. stroke-dashoffset: 0;
  288. stroke-linecap: round;
  289. animation: dash4 1.5s ease-in-out infinite;
  290. }
  291.  
  292. @keyframes rotate4 {
  293. 100% {
  294. transform: rotate(360deg);
  295. }
  296. }
  297.  
  298. @keyframes dash4 {
  299. 0% {
  300. stroke-dasharray: 1, 200;
  301. stroke-dashoffset: 0;
  302. }
  303.  
  304. 50% {
  305. stroke-dasharray: 90, 200;
  306. stroke-dashoffset: -35px;
  307. }
  308.  
  309. 100% {
  310. stroke-dashoffset: -125px;
  311. }
  312. }
  313.  
  314. #fy_entry_container {
  315. position: fixed;
  316. background-color: aqua;
  317. top: 500px;
  318. right: 0;
  319. border-top-left-radius: 16px;
  320. border-bottom-left-radius: 16px;
  321. width: 35px;
  322. height: 34px;
  323. display: flex;
  324. align-items: center;
  325. padding-left: 12px;
  326. box-sizing: border-box;
  327. transition: width 0.2s;
  328. background-color: #1890ff;
  329. opacity: 0.5;
  330. cursor: pointer;
  331.  
  332. -webkit-user-select: none;
  333. -moz-user-select: none;
  334. -ms-user-select: none;
  335. user-select: none;
  336.  
  337. display:none;
  338. }
  339.  
  340. #fy_entry_container:hover {
  341. width: 55px;
  342. opacity: 1;
  343. }
  344.  
  345. #fy_entry_container img {
  346. width: 20px;
  347. height: 20px;
  348. pointer-events: none;
  349. }
  350.  
  351. #fy_translate_tools_container {
  352. position: fixed;
  353. top: 45vh;
  354. left: 100%;
  355. display: flex;
  356. flex-wrap: wrap;
  357. z-index: 9980;
  358. width: 300px;
  359. box-shadow: 0 0 5px 1px rgba(0, 0, 0, 0.1);
  360. background-color: #f2f4fb;
  361. padding: 6px 8px 10px;
  362. border-radius: 4px;
  363. color: #333;
  364. cursor: grab;
  365. transition: left 0.5s;
  366. }
  367.  
  368. .fy_tools_top,
  369. .fy_tools_main,
  370. .fy_tools_footer {
  371. position: relative;
  372. width: 100%;
  373. }
  374.  
  375. .fy_tools_top {
  376. display: flex;
  377. justify-content: space-between;
  378. align-items: center;
  379. padding-bottom: 6px;
  380. }
  381.  
  382. .fy_tools_top .fy_title {
  383. font-size: 13px;
  384. font-weight: 600;
  385. letter-spacing: 1px;
  386. }
  387.  
  388. .fy_tools_ctrl_box {
  389. display: flex;
  390. align-items: center;
  391. }
  392.  
  393. #fy_tools_close {
  394. font-size: 10px;
  395. padding: 4px;
  396. -webkit-user-select: none;
  397. -moz-user-select: none;
  398. -ms-user-select: none;
  399. user-select: none;
  400. filter: grayscale(100%);
  401. }
  402.  
  403. #fy_tools_close:hover {
  404. filter: grayscale(0%);
  405. cursor: pointer;
  406. }
  407.  
  408. .fy_tools_select_container {
  409. display: flex;
  410. align-items: center;
  411. font-size: 13px;
  412. margin-right: 5px;
  413. border-radius: 4px;
  414. }
  415.  
  416. .fy_tools_select_container img {
  417. display: inline-block;
  418. margin: auto 2px;
  419. width: 16px;
  420.  
  421. -webkit-user-drag: none;
  422. -khtml-user-drag: none;
  423. -moz-user-drag: none;
  424. -o-user-drag: none;
  425. user-drag: none;
  426. }
  427.  
  428. .fy_tools_select_from {
  429. position: relative;
  430. letter-spacing: 0;
  431. background-color: rgba(169, 173, 204, .1);
  432. height: 20px;
  433. line-height: 20px;
  434. padding: 0 6px;
  435. border-radius: 4px;
  436. }
  437.  
  438. .fy_tools_select_to {
  439. position: relative;
  440. }
  441.  
  442. #fy_tools_selected_active {
  443. background-color: #ffffff;
  444. font-size: 12px;
  445. width: 30px;
  446. height: 20px;
  447. line-height: 20px;
  448. border-radius: 4px;
  449. text-align: center;
  450. cursor: pointer;
  451. }
  452.  
  453. .fy_tools_ul {
  454. list-style-type: none;
  455. margin: 0;
  456. padding: 4px 0;
  457. position: absolute;
  458. top: 0;
  459. left: 50%;
  460. transform: translate(-50%, -110%);
  461. color: #333333;
  462. z-index: 9990;
  463. text-align: center;
  464. background-color: #fff;
  465. box-shadow: 0 0 5px 1px rgba(0, 0, 0, 0.1);
  466. font-size: 12px;
  467. border-radius: 4px;
  468. width: 300px;
  469. justify-content: center;
  470. flex-wrap: wrap;
  471. display: none;
  472. overflow: hidden;
  473. }
  474.  
  475. .fy_tools_ul li {
  476. -webkit-user-select: none;
  477. -moz-user-select: none;
  478. -ms-user-select: none;
  479. user-select: none;
  480. line-height: 20px;
  481. cursor: pointer;
  482. width: 40px;
  483. }
  484. .fy_tools_ul li:hover {
  485. background-color: rgba(169, 173, 204, .3);
  486. }
  487.  
  488. .fy_translate_to{
  489. position: relative;
  490. overflow: auto;
  491. }
  492.  
  493. .fy_tools_text_content {
  494. box-sizing: border-box;
  495. max-width: 100%;
  496. width: 100%;
  497. min-height: 100px;
  498. padding: 6px 8px;
  499. font-size: 14px;
  500. border: none;
  501. outline: none;
  502. overflow: auto;
  503. border-radius: 8px;
  504. margin: 0;
  505. }
  506.  
  507. #fy_translate_result {
  508. margin-top: 5px;
  509. width: 100%;
  510. background-color: rgba(169, 173, 204, .1);
  511. display: none;
  512. cursor: auto;
  513. }
  514. .tools_ctrl_box{
  515. position: absolute;
  516. bottom: 0;
  517. right: 0;
  518. padding: 5px;
  519. display: flex;
  520. z-index: 9999;
  521. }
  522. .tools_ctrl_box img{
  523. width: 20px;
  524. transition: all 0.3s ease;
  525. margin-left: 5px;
  526. cursor: pointer;
  527. opacity: 0.7;
  528. }
  529. .tools_ctrl_box img:hover{
  530. opacity: 1;
  531. }
  532.  
  533. #fy_tools_api_selected{
  534. border-radius: 4px;
  535. text-align: center;
  536. cursor: pointer;
  537. display: flex;
  538. justify-content: center;
  539. items-align: center;
  540. margin-right: 5px;
  541. }
  542. #fy_tools_api_selected img{
  543. display: block;
  544. }
  545. #fy_tools_api_ul img{
  546. width: 17px;
  547. margin: 0;
  548. }
  549. #fy_tools_api_active img{
  550. width: 17px;
  551. }
  552. #fy_tools_api_selected .fy_tools_ul{
  553. width: auto;
  554. padding: 0;
  555. }
  556. #fy_tools_api_ul{
  557. left: auto;
  558. transform: translate(0%, -100%);
  559. }
  560. #fy_tools_api_ul li{
  561. width: auto;
  562. padding: 5px 7px;
  563. }
  564.  
  565. /* 滚动条整体样式 */
  566. ::-webkit-scrollbar {
  567. width: 6px; /* 宽度 */
  568. height: 6px; /* 高度(对于垂直滚动条) */
  569. }
  570.  
  571. /* 滚动条滑块 */
  572. ::-webkit-scrollbar-thumb {
  573. background: #aaa;
  574. border-radius: 6px;
  575. }
  576.  
  577. /* 滚动条滑块:hover状态样式 */
  578. ::-webkit-scrollbar-thumb:hover {
  579. background: #888;
  580. }
  581.  
  582. /* 滚动条轨道 */
  583. ::-webkit-scrollbar-track {
  584. background: #f1f1f1;
  585. border-radius: 6px;
  586. }
  587.  
  588. /* 滚动条轨道:hover状态样式 */
  589. ::-webkit-scrollbar-track:hover {
  590. background: #ddd;
  591. }
  592.  
  593. /* 滚动条轨道:active状态样式 */
  594. ::-webkit-scrollbar-track-piece:active {
  595. background: #eee;
  596. }
  597.  
  598. /* 滚动条:角落样式(即两个滚动条交汇处) */
  599. ::-webkit-scrollbar-corner {
  600. background: #535353;
  601. }
  602.  
  603. `
  604.  
  605. // ------------全局----------------
  606. // 显示总容器
  607. var transContainerDOM = null
  608. // 翻译内容容器
  609. var fyContentDOM = null
  610. // 拖动条
  611. var fyDragBarDOM = null
  612. // 待翻译文本
  613. var fromTransTextArray = []
  614. // 翻译结果对象
  615. var transRes = {}
  616. // 时间戳
  617. var salt = Date.now()
  618. // 当前翻译对象数组
  619. var currTransToObjs = []
  620. // --------------------------
  621. // 语言选择类型
  622. var selectTypes = [
  623. { type: 'zh', valueName: '中', name: '中文' },
  624. { type: 'en', valueName: '英', name: '英文' },
  625. { type: 'jp', valueName: '日', name: '日文' },
  626. { type: 'kor', valueName: '韩', name: '韩文' },
  627. { type: 'fra', valueName: '法', name: '法文' },
  628. { type: 'spa', valueName: '西', name: '西班牙文' },
  629. { type: 'ru', valueName: '俄', name: '俄文' },
  630. { type: 'de', valueName: '德', name: '德文' },
  631. { type: 'it', valueName: '意', name: '意大利文' },
  632. { type: 'th', valueName: '泰', name: '泰文' },
  633. { type: 'vie', valueName: '越', name: '越南文' },
  634. { type: 'pt', valueName: '葡', name: '葡萄牙文' },
  635. { type: 'ara', valueName: '阿', name: '阿拉伯文' },
  636. { type: 'cht', valueName: '中(繁)', name: '中文繁体' },
  637. { type: 'yue', valueName: '中(粤)', name: '粤语' }
  638. ]
  639. // 翻译api列表
  640. var apiMap = [
  641. { name: 'Baidu', logo: baiduImgData, descript: '百度翻译' },
  642. { name: 'Google', logo: googleImgData, descript: '谷歌翻译(需要外网)' }
  643. ]
  644. // 默认百度翻译
  645. var currFromApi = 'Baidu'
  646. // 默认翻译语言
  647. var fyToType = '中'
  648.  
  649. // 初始加载样式
  650. const loadStyle = () => {
  651. var style = document.createElement('style')
  652. if (style.styleSheet) {
  653. // 对于老版本的IE浏览器
  654. style.styleSheet.cssText = cssContent
  655. } else {
  656. style.appendChild(document.createTextNode(cssContent))
  657. }
  658. var head = document.head || document.getElementsByTagName('head')[0]
  659. head.appendChild(style)
  660. }
  661. /**
  662. * 传入配置信息创建元素并返回DOM对象
  663. */
  664. const myCreateEle = (option, mountE) => {
  665. let e = document.createElement(option.el || 'div')
  666. option.className && e.classList.add(option.className)
  667. for (let p in (option.props || {})) {
  668. e.setAttribute(p, option.props[p])
  669. }
  670. e.textContent = option.text || ''
  671. e.style.cssText = option.style || ''
  672. mountE && mountE.appendChild(e)
  673. return e
  674. }
  675.  
  676. // 初始生成元素
  677. const initLoadElement = () => {
  678. transContainerDOM = myCreateEle({
  679. props: { id: 'fy_transContainer' }
  680. }, document.body)
  681. // 内容容器
  682. fyContentDOM = myCreateEle({ props: { id: 'fy_contentBox' } }, transContainerDOM)
  683.  
  684. // loading
  685. $(transContainerDOM).append(`
  686. <div id="fy_loading">
  687. <svg viewBox="25 25 50 50">
  688. <circle r="20" cy="50" cx="50"></circle>
  689. </svg>
  690. </div>
  691. `)
  692.  
  693. // 拖动条
  694. fyDragBarDOM = myCreateEle({
  695. props: { id: 'fy_dragBar' }
  696. }, transContainerDOM)
  697.  
  698. // 缩放点
  699. myCreateEle({
  700. props: { id: 'fy_Scale_rb' }
  701. }, transContainerDOM)
  702. myCreateEle({
  703. props: { id: 'fy_Scale_lb' }
  704. }, transContainerDOM)
  705.  
  706. // 控制条
  707. let fyCtrlBarDom = myCreateEle({
  708. props: { id: 'fy_ctrl_ber' }
  709. }, transContainerDOM)
  710. // 选择翻译api源
  711. let fyApiSelectDom = myCreateEle({
  712. el: 'select',
  713. props: { id: 'fy_api_select' }
  714. }, fyCtrlBarDom)
  715. apiMap.forEach(item => {
  716. $(fyApiSelectDom).append(`
  717. <option value="${item.name}" title="${item.descript}">
  718. <span>${item.name}</span>
  719. </option>
  720. `)
  721. })
  722. // 语言选择
  723. let fyLangSelectDom = myCreateEle({
  724. el: 'select',
  725. props: { id: 'fy_select' }
  726. }, fyCtrlBarDom)
  727. selectTypes.forEach(item => {
  728. $(fyLangSelectDom).append(`
  729. <option value="${item.valueName}" title="${item.name}">
  730. <span>${item.valueName}</span>
  731. </option>
  732. `)
  733. })
  734.  
  735. $(document.body).append(`
  736. <div id="fy_entry_container">
  737. <img src="${transImgData}" alt="翻译" />
  738.  
  739. </div>
  740. `)
  741.  
  742. let currlogo = (apiMap.find(item => item.name == currFromApi) || {})?.logo
  743. $(document.body).append(`
  744. <div id="fy_translate_tools_container">
  745. <div class="fy_tools_top">
  746. <div class="fy_title">翻译工具</div>
  747. <div class="fy_tools_ctrl_box">
  748. <div class="fy_tools_select_container">
  749. <div id="fy_tools_api_selected">
  750. <div id="fy_tools_api_active">
  751. <img src="${currlogo}" alt="">
  752. </div>
  753. <ul class="fy_tools_ul" id="fy_tools_api_ul">
  754. </ul>
  755. </div>
  756. <div class="fy_tools_select_from">auto</div>
  757. <img src="${zhuanhuangImgData}" alt="">
  758. <div class="fy_tools_select_to">
  759. <div id="fy_tools_selected_active">中</div>
  760. <ul class="fy_tools_ul" id="fy_tools_transTo_ul">
  761. </ul>
  762. </div>
  763. </div>
  764. <div id="fy_tools_close">❌</div>
  765. </div>
  766. </div>
  767. <div class="fy_tools_main">
  768. <div class="fy_translate_from">
  769. <textarea id="fy_translate_input" class="fy_tools_text_content" placeholder="输入翻译文字"></textarea>
  770. </div>
  771. <div class="fy_translate_to">
  772. <div id='fy_translate_result' class="fy_tools_text_content"></div>
  773. <div class="tools_ctrl_box">
  774. <img title="复制" class="tools_result_copy" alt="复制" src="${copyImgData}">
  775. <img title="发音" class="tools_result_audio" alt="发音" src="${audioImgData}">
  776. </div>
  777. </div>
  778. </div>
  779. <div class="fy_tools_footer">
  780. </div>
  781. </div>
  782. `)
  783.  
  784. selectTypes.forEach(item => {
  785. $('#fy_tools_transTo_ul').append(`
  786. <li value="${item.valueName}">${item.valueName}</li>
  787. `)
  788. })
  789.  
  790. apiMap.forEach(item => {
  791. $('#fy_tools_api_ul').append(`
  792. <li value="${item.name}"><img value="${item.name}" src="${item.logo}" alt="" /></li>
  793. `)
  794. })
  795.  
  796. // ❌➖📌💡🎯📝✔️❓❗️📅🚫🔄✅📖📘
  797. // filter: grayscale(100%); 置灰
  798. }
  799.  
  800. // 生成MD5值
  801. const calculateMD5 = (input) => {
  802. return CryptoJS.MD5(input).toString()
  803. }
  804.  
  805. // 百度翻译
  806. const baiduTranslate = async (fromTransText, isTools = false) => {
  807. let targetLang = (baiduOptions.find(item => item.valueName == fyToType) || {})?.type
  808. let appid = '20240513002050392'
  809. let sign = calculateMD5(appid + fromTransText + salt + 'evAKKTnaxMEpHrnCxwDC')
  810. let param = `?q=${fromTransText}&from=auto&to=${targetLang}&appid=${appid}&salt=${salt}&sign=${sign}`
  811. console.log('baiduRequesy ', param)
  812. await GM_xmlhttpRequest({
  813. url: 'https://fanyi-api.baidu.com/api/trans/vip/translate' + param,
  814. method: 'GET',
  815. onload: function (response) {
  816. if (response.status === 200) {
  817. let res = JSON.parse((response.responseText || ''))
  818. if (!(res.trans_result && res.trans_result.length > 0)) return
  819. transRes = {
  820. apiType: 'baidu',
  821. formText: res.trans_result[0].src,
  822. toText: res.trans_result[0].dst
  823. }
  824. currTransToObjs.push({ ...transRes })
  825. renderRes(res.trans_result[0].src, res.trans_result[0].dst)
  826. $('#fy_loading').hide()
  827. // !reUpdate && computedContainer()
  828. // 复制翻译后文字
  829.  
  830. copyText(res.trans_result[0].dst)
  831.  
  832. isTools && toolsResult(res.trans_result[0].dst)
  833.  
  834. } else {
  835. console.error('百度翻译请求失败,状态码: ' + response.status)
  836. }
  837. },
  838. onerror: function (e) {
  839. handleError(e)
  840. }
  841. })
  842. }
  843.  
  844. /* -------------- 修复google翻译 @ChinaGodMan 2025-03-21 @ 12:25:06 Friday +0800 -------------- */
  845. const googleTranslate = async (texts, isTools = false) => {
  846. const buildQueryString = (params) => {
  847. return '?' + Object.keys(params).map(key => `${key}=${encodeURIComponent(params[key])}`).join('&')
  848. }
  849. isTools && (texts = [texts])
  850. let targetLang = (googleOptions.find(item => item.valueName == fyToType)).type
  851. const translateText = async (text) => {
  852. return new Promise((resolve, reject) => {
  853. const api = 'https://translate.googleapis.com/translate_a/single'
  854. const params = { client: 'gtx', dt: 't', sl: 'auto', tl: targetLang, q: text }
  855. GM_xmlhttpRequest({
  856. method: 'GET',
  857. url: api + buildQueryString(params),
  858. onload: function (response) {
  859. try {
  860. const data = JSON.parse(response.responseText.replace('\'', '\u2019'))
  861. const translatedText = data[0].reduce((acc, item) => acc + item[0], '')
  862. resolve(translatedText)
  863. } catch (error) {
  864. console.error('翻译失败:', error)
  865. reject('翻译失败')
  866. }
  867. },
  868. onerror: function (response) {
  869. console.error('请求翻译失败:', response.statusText)
  870. reject('请求翻译失败')
  871. }
  872. })
  873. })
  874. }
  875.  
  876. try {
  877. const translatedResults = await Promise.all(texts.map(text => translateText(text)))
  878. transRes = {
  879. apiType: 'google',
  880. formTextArray: texts,
  881. toTextsArray: translatedResults
  882. }
  883. translatedResults.forEach((translatedText, i) => {
  884. renderRes(texts[i], translatedText)
  885. })
  886. $('#fy_loading').hide()
  887. //! 禁止复制翻译后的文本到剪辑版.2025-03-21 @ 12:33:38 Friday +0800
  888. //copyText(transRes.toTextsArray[0])
  889. isTools && toolsResult(transRes.toTextsArray[0])
  890. } catch (error) {
  891. console.error('翻译失败:', error)
  892. }
  893. }
  894.  
  895. /* ------------------------------ 谷歌翻译构建URL请求参数 ----------------------------- */
  896. function buildQueryString(params) {
  897. return '?' + Object.keys(params).map(function (key) {
  898. return encodeURIComponent(key) + '=' + encodeURIComponent(params[key])
  899. }).join('&')
  900. }
  901. const renderRes = (formText, toText) => {
  902. $(fyContentDOM).append(`
  903. <div class="transText_node">
  904. <div class="transText_node_to" title="${formText}">${toText}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <img title="复制" class="icon_style copy_icon" value="${toText}" alt="复制" src="${copyImgData}"></div>
  905. <div class="transText_node_from">${formText}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <img class="icon_style copy_icon" title="复制" value="${formText}" alt="复制" src="${copyImgData}" ></div>
  906. </div>
  907. `)
  908. }
  909. const handleError = (e) => {
  910. // <div>或是否在用VPN代理❗️(百度的api😅)</div>
  911. $(fyContentDOM).append(`
  912. <div class="transText_node" style="text-align: center;">
  913. <div>请求失败❗️☹️</div>
  914. <div>请检查网络连接❗️</div>
  915. </div>
  916. `)
  917. $('#fy_loading').hide()
  918. }
  919.  
  920. var currX = 0 // 当前鼠标位置
  921. var currY = 0 // 当前鼠标位置
  922. var isContainer = false // 容器是否出现
  923. var isCtrl = false // 是否处于可翻译状态
  924. // 绑定事件
  925. const bingEvents = () => {
  926. // // transContainerDOM 翻译容器
  927.  
  928. // 绑定Ctrl+右键点击翻译
  929. // bindCtrlRightClick()
  930. // 绑定翻译键
  931. bingTransKeys()
  932.  
  933. // 点击页面
  934. document.body.onclick = function (event) {
  935. if (isContainer) {
  936. clearTransContainer()
  937. }
  938. }
  939. // 清除翻译容器
  940. const clearTransContainer = () => {
  941. isContainer = false
  942. transContainerDOM.style.display = 'none'
  943. transContainerDOM.style.maxWidth = '500px'
  944. transContainerDOM.style.minWidth = '300px'
  945. transContainerDOM.style.width = 'auto'
  946. transContainerDOM.style.height = 'auto'
  947. fyContentDOM.textContent = ''
  948. fromTransTextArray = []
  949. }
  950.  
  951. transContainerDOM.onclick = function (e) {
  952. e.stopPropagation() // 阻止事件冒泡
  953. }
  954. // 上下文菜单
  955. document.addEventListener('contextmenu', function (event) {
  956. if (isCtrl) {
  957. // 取消默认行为(阻止上下文菜单出现)
  958. event.preventDefault()
  959. }
  960. })
  961. bindHandleDrag() // 绑定拖动模块事件
  962. bindHandleScale() // 绑定缩放模块事件
  963. bindHandleSelectLang() // 绑定切换翻译事件
  964. bindHandleSelectApi() // 绑定切换翻译请求的api事件
  965. bindTextClick() // 点击翻译文本事件
  966.  
  967. // 鼠标按键抬起事件
  968. document.addEventListener('mouseup', function (event) {
  969. if (isContainer) {
  970. const rect = transContainerDOM.getBoundingClientRect()
  971. currX = rect.left
  972. currY = rect.top
  973. } else {
  974. currX = event.clientX
  975. currY = event.clientY
  976. }
  977. })
  978.  
  979. }
  980.  
  981. // Ctrl + 鼠标右键点击事件
  982. // const bindCtrlRightClick = () => {
  983. // document.addEventListener('keydown', (e) => {
  984. // if (e.key === 'Control') {
  985. // isCtrl = true;
  986. // }
  987. // });
  988. // document.addEventListener('keyup', (e) => {
  989. // if (e.key === 'Control') {
  990. // isCtrl = false;
  991. // }
  992. // });
  993. // // 鼠标按下事件
  994. // document.addEventListener("mousedown", function (event) {
  995. // currX = event.clientX;
  996. // currY = event.clientY;
  997. // if (isCtrl && event.button === 2) {
  998. // // 获取Selection对象,选中的文本
  999. // let textAll = window.getSelection().toString();
  1000. // if (!textAll) return
  1001. // startTrans()
  1002. // }
  1003. // })
  1004. // }
  1005.  
  1006. // 绑定翻译事件按键
  1007. const bingTransKeys = () => {
  1008. var inOnlyKeyVal = ''
  1009. document.addEventListener('keydown', function (event) {
  1010. inOnlyKeyVal = event.key
  1011. })
  1012. document.addEventListener('keyup', function (event) {
  1013. let textAll = window.getSelection().toString()
  1014. if (!inOnlyKeyVal) return
  1015. if (textAll) {
  1016. // if ([event.key, inOnlyKeyVal].every(key => key === 'Control')) {
  1017. // startTrans()
  1018. // }
  1019. if ([event.key, inOnlyKeyVal].every(key => key === '`')) {
  1020. startTrans()
  1021. }
  1022. }
  1023. if (textAll || fromTransTextArray.length) {
  1024. // 按键必须为数字键,且都为正整数
  1025. if ([event.key, inOnlyKeyVal].every(key => !isNaN(parseInt(key)))) {
  1026. let selectedValue = selectTypes[parseInt(event.key) - 1].valueName || ''
  1027. if (!selectedValue) return
  1028. $('#fy_select').val(selectedValue)
  1029. setFyToType(selectedValue)
  1030. startTrans()
  1031. }
  1032. }
  1033. inOnlyKeyVal = ''
  1034. })
  1035. }
  1036.  
  1037. // 防止重复请求锁
  1038. var isLockTrans = false
  1039. // 开始执行翻译请求
  1040. const startTrans = () => {
  1041. if (isLockTrans) {
  1042. showMessage({ message: '操作频繁,请稍后~', type: 'warning', time: 1000 })
  1043. return
  1044. }
  1045. isLockTrans = true
  1046. let textAll = window.getSelection().toString()
  1047. let arrFroms = formatTrans(textAll)
  1048. if (arrFroms && arrFroms.length) {
  1049. fromTransTextArray = arrFroms
  1050. }
  1051. // 判断是否有选中翻译的文本
  1052. isContainer = true // 更改容器状态
  1053. transContainerDOM.style.display = 'flex'
  1054. $('#fy_loading').show()
  1055. fyContentDOM.textContent = ''
  1056. computedContainer() // 计算容器位置
  1057.  
  1058. const methodMap = {
  1059. Baidu: (texts) => {
  1060. texts.filter(text => text).forEach(text => {
  1061. baiduTranslate(text)
  1062. })
  1063. },
  1064. Google: googleTranslate
  1065. }
  1066. methodMap[currFromApi](fromTransTextArray)
  1067. setTimeout(() => {
  1068. isLockTrans = false
  1069. }, 500)
  1070. }
  1071.  
  1072. // 切换翻译语言
  1073. const bindHandleSelectLang = () => {
  1074. document.getElementById('fy_select').onchange = function (e) {
  1075. setFyToType(this.value)
  1076. fyContentDOM.textContent = ''
  1077. $('#fy_loading').show()
  1078. startTrans()
  1079. // googleTranslate(fromTransTextArray, true)
  1080. }
  1081.  
  1082. document.addEventListener('keyup', (e) => {
  1083. if (isContainer && e.code === 'KeyB') {
  1084. setCurrFromApi('Baidu')
  1085. setTimeout(() => {
  1086. startTrans()
  1087. }, 10)
  1088. }
  1089. if (isContainer && e.code === 'KeyG') {
  1090. setCurrFromApi('Google')
  1091. setTimeout(() => {
  1092. startTrans()
  1093. }, 10)
  1094. }
  1095. })
  1096.  
  1097. }
  1098. // 切换api
  1099. const bindHandleSelectApi = () => {
  1100. document.getElementById('fy_api_select').onchange = function (e) {
  1101. setCurrFromApi(this.value)
  1102. fyContentDOM.textContent = ''
  1103. $('#fy_loading').show()
  1104. startTrans()
  1105. // googleTranslate(fromTransTextArray, true)
  1106. }
  1107. }
  1108.  
  1109. // 窗口拖动事件
  1110. const bindHandleDrag = () => {
  1111. let isMove = false
  1112. let mouseToEleX
  1113. let mouseToEleY
  1114. // 拖动处理
  1115. fyDragBarDOM.addEventListener('mousedown', function (e) {
  1116. if (!isCtrl) {
  1117. isMove = true
  1118. fyDragBarDOM.style.cursor = 'grabbing'
  1119. // 获取鼠标相对于元素的位置
  1120. mouseToEleX = e.clientX - transContainerDOM.getBoundingClientRect().left
  1121. mouseToEleY = e.clientY - transContainerDOM.getBoundingClientRect().top
  1122. }
  1123. })
  1124. // 当鼠标移动时
  1125. window.addEventListener('mousemove', (e) => {
  1126. if (!isMove) return
  1127. // 防止默认的拖动选择文本行为
  1128. e.preventDefault()
  1129. let t = (e.clientY - mouseToEleY) < 0 ? 0 : e.clientY - mouseToEleY
  1130. // 更新元素的位置
  1131. transContainerDOM.style.left = (e.clientX - mouseToEleX) + 'px'
  1132. transContainerDOM.style.top = t + 'px'
  1133. })
  1134. // 当鼠标松开时
  1135. window.addEventListener('mouseup', () => {
  1136. isMove = false
  1137. fyDragBarDOM.style.cursor = 'grab'
  1138. })
  1139. }
  1140. // 改变窗口大小事件
  1141. const bindHandleScale = () => {
  1142. let mainCurrWidth
  1143. let mainCurrHeight
  1144. let cX, cY
  1145. let isScale = false
  1146. let scaleType = ''
  1147.  
  1148. const scaleFun = (e, type) => {
  1149. isScale = true
  1150. mainCurrWidth = transContainerDOM.offsetWidth
  1151. mainCurrHeight = transContainerDOM.offsetHeight
  1152. cX = e.clientX
  1153. cY = e.clientY
  1154. scaleType = type
  1155. let rect = transContainerDOM.getBoundingClientRect()
  1156. if (scaleType == 'rb') {
  1157. transContainerDOM.style.left = rect.left + 'px'
  1158. transContainerDOM.style.right = 'auto'
  1159. }
  1160. if (scaleType == 'lb') {
  1161. let scrollBarWidth = window.innerWidth - document.documentElement.clientWidth
  1162. transContainerDOM.style.right = (window.innerWidth - rect.right - scrollBarWidth) + 'px'
  1163. transContainerDOM.style.left = 'auto'
  1164. }
  1165. }
  1166. fy_Scale_rb.addEventListener('mousedown', (e) => {
  1167. scaleFun(e, 'rb')
  1168. })
  1169. fy_Scale_lb.addEventListener('mousedown', (e) => {
  1170. scaleFun(e, 'lb')
  1171. })
  1172. // 当鼠标移动时
  1173. window.addEventListener('mousemove', (e) => {
  1174. if (!isScale) return
  1175. // 防止默认的拖动选择文本行为
  1176. e.preventDefault()
  1177. transContainerDOM.style.maxWidth = 'none'
  1178. let newHeight = mainCurrHeight + (e.clientY - cY)
  1179. let newWidth = mainCurrWidth
  1180.  
  1181. if (scaleType == 'rb') {
  1182. newWidth = mainCurrWidth + (e.clientX - cX)
  1183. }
  1184. if (scaleType == 'lb') {
  1185. newWidth = mainCurrWidth + (cX - e.clientX)
  1186. }
  1187. // 更新元素的位置
  1188. transContainerDOM.style.width = Math.max(10, newWidth) + 'px'
  1189. transContainerDOM.style.height = Math.max(10, newHeight) + 'px'
  1190. })
  1191. // 当鼠标松开时
  1192. window.addEventListener('mouseup', () => {
  1193. isScale = false
  1194. })
  1195. }
  1196.  
  1197. // 点击译文事件
  1198. var isClickLock = true
  1199. const bindTextClick = () => {
  1200. // fyContentDOM.addEventListener('click', function (event) {
  1201. // if (!isClickLock) return;
  1202. // isClickLock = false
  1203. // setTimeout(() => {
  1204. // isClickLock = true;
  1205. // }, 300); // 双击事件的间隔时间通常是300毫秒左右
  1206. // let textAll = window.getSelection().toString();
  1207. // if (textAll) return;
  1208. // let targetEle = event.target
  1209. // if (!targetEle.classList.contains('transText_node')) {
  1210. // targetEle = targetEle.parentNode
  1211. // }
  1212. // if (!targetEle.classList.contains('transText_node')) return;
  1213.  
  1214. // if (targetEle.classList.contains('fy_node_expand')) {
  1215. // targetEle.classList.remove('fy_node_expand');
  1216. // } else {
  1217. // targetEle.classList.add('fy_node_expand')
  1218. // }
  1219.  
  1220. // var rect = transContainerDOM.getBoundingClientRect();
  1221. // // 获取视口的高度
  1222. // var viewportHeight = window.innerHeight || document.documentElement.clientHeight;
  1223. // // 计算元素底部到视口底部的距离
  1224. // if ((viewportHeight - rect.bottom) < 30) {
  1225. // transContainerDOM.style.height = (viewportHeight - rect.top - 50) + 'px'
  1226. // }
  1227. // });
  1228.  
  1229. $(fyContentDOM).on('click', '.transText_node_to', function (e) {
  1230. if (!isClickLock) return
  1231. isClickLock = false
  1232. setTimeout(() => {
  1233. isClickLock = true
  1234. }, 300) // 双击事件的间隔时间通常是300毫秒左右
  1235. let textAll = window.getSelection().toString()
  1236. if (textAll) return
  1237. var parent = $(e.target).parent()[0]
  1238. if ($(parent).hasClass('fy_node_expand')) {
  1239. $(parent).removeClass('fy_node_expand')
  1240. } else {
  1241. $(parent).addClass('fy_node_expand')
  1242. }
  1243. var rect = transContainerDOM.getBoundingClientRect()
  1244. // 获取视口的高度
  1245. var viewportHeight = window.innerHeight || document.documentElement.clientHeight
  1246. // 计算元素底部到视口底部的距离
  1247. if ((viewportHeight - rect.bottom) < 30) {
  1248. transContainerDOM.style.height = (viewportHeight - rect.top - 50) + 'px'
  1249. }
  1250.  
  1251. })
  1252.  
  1253. $(fyContentDOM).on('click', '.copy_icon', function (e) {
  1254. e.stopPropagation() // 阻止事件冒泡
  1255. copyText(this.getAttribute('value'))
  1256. showMessage({
  1257. message: '复制成功',
  1258. time: 800
  1259. })
  1260. })
  1261.  
  1262. // 翻译工具-结果复制
  1263. $('body').on('click', '.tools_result_copy', function (e) {
  1264. e.stopPropagation() // 阻止事件冒泡
  1265. copyText($('#fy_translate_result').text())
  1266. showMessage({
  1267. message: '复制成功',
  1268. time: 800,
  1269. mainDOM: document.getElementById('fy_translate_tools_container')
  1270. })
  1271. })
  1272. // 翻译工具-结果发音
  1273. $('body').on('click', '.tools_result_audio', function (e) {
  1274. e.stopPropagation() // 阻止事件冒泡
  1275. playAudioText($('#fy_translate_result').text())
  1276. })
  1277.  
  1278. }
  1279.  
  1280. // 计算渲染容器高度位置
  1281. const computedContainer = () => {
  1282. let scrollBarWidth = window.innerWidth - document.documentElement.clientWidth
  1283. let distance_right = (window.innerWidth - transContainerDOM.getBoundingClientRect().right - scrollBarWidth)
  1284. if (distance_right < 5) {
  1285. transContainerDOM.style.left = 'auto'
  1286. transContainerDOM.style.right = '5px'
  1287. } else {
  1288. transContainerDOM.style.right = 'auto'
  1289. transContainerDOM.style.left = currX + 'px'
  1290. }
  1291. transContainerDOM.style.top = currY + 'px'
  1292.  
  1293. let topToBotton = window.innerHeight - currY
  1294. if (transContainerDOM.offsetHeight > topToBotton) {
  1295. transContainerDOM.style.height = topToBotton + 'px'
  1296. }
  1297. }
  1298.  
  1299. // 语音播放文本
  1300. const playAudioText = (text) => {
  1301. // 创建一个新的 SpeechSynthesisUtterance 对象
  1302. console.log('阅读~')
  1303. const utterance = new SpeechSynthesisUtterance(text)
  1304. // 设置一些可选的属性(例如音量、语速和音调)
  1305. utterance.volume = 1 // 0到1之间的值
  1306. utterance.rate = 1 // 0.1到10之间的值
  1307. utterance.pitch = 1 // 0到2之间的值
  1308. // 朗读文本
  1309. window.speechSynthesis.speak(utterance)
  1310.  
  1311. // // 检查浏览器是否支持语音合成
  1312. // if ('speechSynthesis' in window) {
  1313. // // 创建语音合成实例
  1314. // var synthesis = window.speechSynthesis;
  1315. // var textToSpeak = text;
  1316. // // 创建语音合成的配置
  1317. // var utterance = new SpeechSynthesisUtterance(textToSpeak);
  1318. // // 使用默认语音
  1319. // utterance.voice = speechSynthesis.getVoices()[0];
  1320. // // 播放文本
  1321. // synthesis.speak(utterance);
  1322. // } else {
  1323. // console.log("抱歉,您的浏览器不支持语音合成功能。");
  1324. // }
  1325. }
  1326.  
  1327. const init = (e) => {
  1328. initLoadElement()
  1329. bingEvents()
  1330. bindToolsEvent()
  1331. }
  1332.  
  1333. // 入口程序------------------------------------------------
  1334. (function () {
  1335. if (window.self !== window.top) return
  1336. console.log('S translate ~')
  1337. loadStyle()
  1338. this.setTimeout(() => {
  1339. init()
  1340. if (localStorage.getItem('FY_TRANSLATE_TO')) {
  1341. fyToType = localStorage.getItem('FY_TRANSLATE_TO')
  1342. $('#fy_select').val(fyToType)
  1343. fy_tools_selected_active.setAttribute('value', fyToType)
  1344. fy_tools_selected_active.textContent = fyToType
  1345. }
  1346. if (localStorage.getItem('FY_TRANSLATE_API_TYPE')) {
  1347. currFromApi = localStorage.getItem('FY_TRANSLATE_API_TYPE')
  1348. $('#fy_api_select').val(currFromApi)
  1349. }
  1350. }, 200)
  1351. })()
  1352.  
  1353. const setFyToType = (type) => {
  1354. localStorage.setItem('FY_TRANSLATE_TO', type)
  1355. fyToType = type
  1356. fy_tools_selected_active.setAttribute('value', type)
  1357. fy_tools_selected_active.textContent = type
  1358. }
  1359. const setCurrFromApi = (type) => {
  1360. localStorage.setItem('FY_TRANSLATE_API_TYPE', type)
  1361. currFromApi = type
  1362. $('#fy_api_select').val(type)
  1363. }
  1364.  
  1365. // 百度语言标识符列表
  1366. var baiduOptions = [
  1367. { type: 'zh', valueName: '中' },
  1368. { type: 'en', valueName: '英' },
  1369. { type: 'jp', valueName: '日' },
  1370. { type: 'kor', valueName: '韩' },
  1371. { type: 'fra', valueName: '法' },
  1372. { type: 'spa', valueName: '西' },
  1373. { type: 'ru', valueName: '俄' },
  1374. { type: 'de', valueName: '德' },
  1375. { type: 'it', valueName: '意' },
  1376. { type: 'th', valueName: '泰' },
  1377. { type: 'vie', valueName: '越' },
  1378. { type: 'pt', valueName: '葡' },
  1379. { type: 'ara', valueName: '阿' },
  1380. { type: 'cht', valueName: '中(繁)' },
  1381. { type: 'yue', valueName: '中(粤)' }
  1382. ]
  1383. // google语言标识符列表
  1384. var googleOptions = [
  1385. { type: 'zh-CN', valueName: '中' },
  1386. { type: 'en', valueName: '英' },
  1387. { type: 'ja', valueName: '日' },
  1388. { type: 'ko', valueName: '韩' },
  1389. { type: 'fr', valueName: '法' },
  1390. { type: 'es', valueName: '西' },
  1391. { type: 'ru', valueName: '俄' },
  1392. { type: 'de', valueName: '德' },
  1393. { type: 'it', valueName: '意' },
  1394. { type: 'th', valueName: '泰' },
  1395. { type: 'vi', valueName: '越' },
  1396. { type: 'pt', valueName: '葡' },
  1397. { type: 'ar', valueName: '阿' },
  1398. { type: 'zh-TW', valueName: '中(繁)' },
  1399. { type: 'zh-TW', valueName: '中(粤)' }
  1400. ]
  1401.  
  1402. // 唤起提示
  1403. const showMessage = (options) => {
  1404. let { type = 'success', message, time, mainDOM = transContainerDOM } = options
  1405. let tipsDOM = myCreateEle({ text: message, type: type ?? 'success', style: 'position: absolute; top: 30px; left: 50%; transform: translate(-50%, 0%); padding: 2px 6px; border-radius: 2px; color:#fff; background-color: #67c23a; font-size: 10px;' }, mainDOM)
  1406. const colorMap = {
  1407. success: '#67c23a',
  1408. warning: '#e6a23c',
  1409. error: '#f56c6c',
  1410. info: '#909399'
  1411. }
  1412. tipsDOM.style.backgroundColor = colorMap[type]
  1413. setTimeout(() => {
  1414. tipsDOM.remove()
  1415. }, time ?? 2000)
  1416. }
  1417.  
  1418. // 格式化页面划选的文本,拆分成数组
  1419. const formatTrans = (texts = '') => {
  1420. return (texts.split(/[\n\t]+/) || []).filter(text => text)
  1421. }
  1422.  
  1423. // copy 文本
  1424. const copyText = (text) => {
  1425. navigator.clipboard.writeText(text)
  1426. .then(() => {
  1427. })
  1428. .catch(err => {
  1429. // 某些浏览器可能不支持或需要用户交互
  1430. // console.error('无法复制文本: ', err);
  1431. })
  1432. }
  1433.  
  1434. // -------------------------------------
  1435.  
  1436. var isTools = false
  1437. // 翻译小球-拖动事件
  1438. function bindEntryMove() {
  1439. let isMoveEntry = false
  1440. let topMoveY
  1441. fy_entry_container.addEventListener('mousedown', (e) => {
  1442. isMoveEntry = true
  1443. topMoveY = e.clientY - fy_entry_container.getBoundingClientRect().top
  1444. })
  1445. window.addEventListener('mousemove', (e) => {
  1446. if (isMoveEntry) {
  1447. e.preventDefault()
  1448. fy_entry_container.style.top = (e.clientY - topMoveY) + 'px'
  1449. }
  1450. })
  1451. // 当鼠标松开时
  1452. window.addEventListener('mouseup', () => {
  1453. isMoveEntry = false
  1454. })
  1455.  
  1456. // 翻译tools出现及隐藏
  1457. fy_entry_container.addEventListener('mouseup', (e) => {
  1458. if (!isTools) {
  1459. showTools()
  1460. }
  1461. })
  1462. fy_tools_close.onclick = function (e) {
  1463. closeTools()
  1464. }
  1465.  
  1466. let rect = fy_translate_tools_container.getBoundingClientRect()
  1467. var cacheLetf = rect.left - rect.width
  1468. const showTools = () => {
  1469. fy_translate_tools_container.style.left = (cacheLetf) + 'px'
  1470. isTools = true
  1471. setTimeout(() => {
  1472. fy_translate_tools_container.style.transition = 'none'
  1473. }, 600)
  1474. }
  1475. const closeTools = () => {
  1476. isTools = false
  1477. fy_translate_tools_container.style.transition = 'left 0.5s'
  1478. cacheLetf = fy_translate_tools_container.getBoundingClientRect().left
  1479. fy_translate_tools_container.style.left = '100%'
  1480. }
  1481.  
  1482. // 连续点击 两下``
  1483. let isBackquote = false
  1484. window.addEventListener('keydown', (e) => {
  1485. if (e.code === 'Backquote' && isBackquote) {
  1486. isTools ? closeTools() : showTools()
  1487. isBackquote = false
  1488. return
  1489. }
  1490. e.code === 'Backquote' && (isBackquote = true)
  1491. setTimeout(() => {
  1492. isBackquote = false
  1493. }, 250)
  1494. })
  1495.  
  1496. }
  1497.  
  1498. // 输入翻译小工具框-拖动事件
  1499. function bingTranslateTools() {
  1500. let isMoveTools = false
  1501. let mouseToEleX
  1502. let mouseToEleY
  1503. fy_translate_tools_container.addEventListener('mousedown', (e) => {
  1504. if (e.target.classList.contains('fy_tools_text_content') || e.target.id === 'fy_tools_close') return
  1505. isMoveTools = true
  1506. let rect = fy_translate_tools_container.getBoundingClientRect()
  1507. mouseToEleX = e.clientX - rect.left
  1508. mouseToEleY = e.clientY - rect.top
  1509. fy_translate_tools_container.style.cursor = 'grabbing'
  1510. })
  1511. window.addEventListener('mousemove', (e) => {
  1512. if (isMoveTools) {
  1513. e.preventDefault()
  1514. let t = (e.clientY - mouseToEleY) < 0 ? 0 : e.clientY - mouseToEleY
  1515. fy_translate_tools_container.style.top = t + 'px'
  1516. fy_translate_tools_container.style.left = (e.clientX - mouseToEleX) + 'px'
  1517. }
  1518. })
  1519. // 当鼠标松开时
  1520. window.addEventListener('mouseup', () => {
  1521. isMoveTools = false
  1522. fy_translate_tools_container.style.cursor = 'grab'
  1523. })
  1524. }
  1525.  
  1526. // 翻译输入触发事件
  1527. function bindInputChange() {
  1528. let timer = null
  1529. fy_translate_input.addEventListener('input', function (e) {
  1530. if (timer) {
  1531. clearTimeout(timer)
  1532. }
  1533. timer = setTimeout(() => {
  1534. toolsTranslateRequest(this.value)
  1535. }, 500)
  1536. })
  1537. }
  1538.  
  1539. // tools切换翻译语言
  1540. function bindChangeTranslateTo() {
  1541. fy_tools_transTo_ul.onclick = function (e) {
  1542. e.stopPropagation() // 阻止事件冒泡
  1543. let value = e.target.getAttribute('value')
  1544. if (!value) return
  1545. setFyToType(value)
  1546. fy_tools_selected_active.setAttribute('value', value)
  1547. fy_tools_selected_active.textContent = e.target.textContent
  1548. fy_tools_transTo_ul.style.display = 'none'
  1549. toolsTranslateRequest($('#fy_translate_input').val())
  1550. }
  1551. fy_tools_selected_active.onclick = function (e) {
  1552. e.stopPropagation() // 阻止事件冒泡
  1553. if (window.getComputedStyle(fy_tools_transTo_ul).display === 'none') {
  1554. fy_tools_transTo_ul.style.display = 'flex'
  1555. } else {
  1556. fy_tools_transTo_ul.style.display = 'none'
  1557. }
  1558. }
  1559.  
  1560. fy_tools_api_active.onclick = function (e) {
  1561. e.stopPropagation() // 阻止事件冒泡
  1562. if (window.getComputedStyle(fy_tools_api_ul).display === 'none') {
  1563. fy_tools_api_ul.style.display = 'flex'
  1564. } else {
  1565. fy_tools_api_ul.style.display = 'none'
  1566. }
  1567. }
  1568. fy_tools_api_ul.onclick = function (e) {
  1569. e.stopPropagation() // 阻止事件冒泡
  1570. let value = e.target.getAttribute('value')
  1571. if (!value) return
  1572. setCurrFromApi(value)
  1573. fy_tools_api_active.setAttribute('value', value)
  1574. let currlogo = (apiMap.find(item => item.name == value) || {})?.logo
  1575. $('#fy_tools_api_active img').attr('src', currlogo)
  1576. fy_tools_api_ul.style.display = 'none'
  1577. toolsTranslateRequest($('#fy_translate_input').val())
  1578. }
  1579.  
  1580. $('body').click(function (e) {
  1581. fy_tools_transTo_ul.style.display = 'none'
  1582. fy_tools_api_ul.style.display = 'none'
  1583. })
  1584. }
  1585.  
  1586. const toolsTranslateRequest = (fromText) => {
  1587. const methodMap = {
  1588. Baidu: baiduTranslate,
  1589. Google: googleTranslate
  1590. }
  1591. $('#fy_translate_result').text('')
  1592. methodMap[currFromApi](fromText, true)
  1593. }
  1594. var toolsTranslateResultText = ''
  1595. const toolsResult = (text) => {
  1596. $('#fy_translate_result').text(text)
  1597. toolsTranslateResultText = text
  1598. if (text) {
  1599. $('#fy_translate_result').show()
  1600. } else {
  1601. // $('#fy_translate_result').hide()
  1602. }
  1603. }
  1604.  
  1605. const bindToolsEvent = () => {
  1606. // 入口小球事件
  1607. bindEntryMove()
  1608. // 翻译工具事件
  1609. bingTranslateTools()
  1610. // 输入改变事件
  1611. bindInputChange()
  1612. // 切换翻译语言事件
  1613. bindChangeTranslateTo()
  1614. }
  1615.  
  1616. // 转换
  1617. var zhuanhuangImgData = `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAxNJREFUeF7tmjFoFEEUht/bVNpYaGOvFsZGbEyl9mcZEMFAdPftCYIGsTCkSBMFSaM2mTdnOEUMiq0gNkaEVIKVxkoEMWCjQlC8Q+6ZlYuomOzb7F12NjvT7j9v3vvmnzlm5hAq3rDi9YMH4B1QcQJ+CVTcAH4T9EvAL4GKE+jbEqjX67VOpzOCiM9brZZtNpvfXWTdFwBERABgVgsWkXlEPMvMb1yD0HMAURRdRsQr/yn0AyKGxpjHLkHoKQAimgaAi+sU+IqZD2xFAEhEtwBgNKW4T8y8c0sBIKJdADALAMcVhU0w85RCt2mSXEsgiqJ9QRDcFpHDiozrzPx7Y1ToN0WyYQBxHA+JyB0A2JOWKSIOG2MepumK+L4hAN3f+LsAsCMl6W8AUGPmp0UUpxkzM4A4jkdFJFnzaW0pCILazMzMyzRhkd8zASCiSwBwTZHwooh8VOh6KkFEy8z3sgRVAyCi3QCwlCV4EVpEnDbGJBOlamoAYRgeDYLA2bX8Z7WdTudYo9GY1xDwADSUEo13QNWXABFtB4CvWscUqHvXbrcPNpvNL5oc1HtAEoyIhgFgUBO4QM0CMz/Rjp8JgDZomXQeQJlmqx+5egf0g2qZYnoHZJmtldvuSRE5kqXPZmsR8RkzT2rHVTsgDMNDK+f7F9rARer8YcifBv1xuNr3AYg4aIx5rdmH1Jtg9zC0AABDmsBFaURkzlp7Ujt+JgDaoL3URVF0AhHnlDEbzBwptb9kTgOIoug0IiZvjqlNRK5bay+kCv8ROAuAiM4BwE1lQVPMPKHU/iVzEgARJU/syVN7ahORcWvt1VThGgLnABDROABoX5DPM/ONjRbv3B7QvXJ7oClIRM5YazVPdOuGc8oByk2vjYgjxpj7GlBpGqcAxHG8X0QSB6x18foZAE4x86O0wrTfnQKQJL0OhPfJ3+60T16lBbAGhMWu7Xt+HHfOAaszNzY2tm15eXnvwMDAj1ar9bZff7R0FoDWwnl1HkBegmXv7x1Q9hnMm793QF6CZe/vHVD2Gcybv3dAXoJl7/8T5pwVUK1j/PAAAAAASUVORK5CYII=`
  1618.  
  1619. // 复制
  1620. var copyImgData = `data:image/png;base64,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`
  1621.  
  1622. var audioImgData = `data:image/png;base64,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`
  1623.  
  1624. // 翻译-icon
  1625. var transImgData = `data:image/png;base64,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`

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址