Google Translate API Library

Google Translate API Library for UserScripts

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.gf.qytechs.cn/scripts/521561/1508824/Google%20Translate%20API%20Library.js

  1. // ==UserScript==
  2. // @name Google Translate API Library
  3. // @namespace http://tampermonkey.net/
  4. // @version 2024.12.24.2
  5. // @description Google Translate API Library for UserScripts
  6. // @author Yuusei
  7. // @grant GM_xmlhttpRequest
  8. // @icon https://cdn-icons-png.flaticon.com/512/9502/9502737.png
  9. // ==/UserScript==
  10.  
  11. const GoogleTranslateAPI = (function () {
  12. 'use strict';
  13.  
  14. const translationCache = new Map();
  15. const CACHE_EXPIRY = 24 * 60 * 60 * 1000;
  16. const MAX_BATCH_SIZE = 128;
  17. const MAX_RETRIES = 3;
  18. const RETRY_DELAY = 1000;
  19.  
  20. const languages = {
  21. auto: 'Automatic',
  22. af: 'Afrikaans',
  23. sq: 'Albanian',
  24. am: 'Amharic',
  25. ar: 'Arabic',
  26. hy: 'Armenian',
  27. az: 'Azerbaijani',
  28. eu: 'Basque',
  29. be: 'Belarusian',
  30. bn: 'Bengali',
  31. bs: 'Bosnian',
  32. bg: 'Bulgarian',
  33. ca: 'Catalan',
  34. ceb: 'Cebuano',
  35. ny: 'Chichewa',
  36. 'zh-cn': 'Chinese Simplified',
  37. 'zh-tw': 'Chinese Traditional',
  38. co: 'Corsican',
  39. hr: 'Croatian',
  40. cs: 'Czech',
  41. da: 'Danish',
  42. nl: 'Dutch',
  43. en: 'English',
  44. eo: 'Esperanto',
  45. et: 'Estonian',
  46. tl: 'Filipino',
  47. fi: 'Finnish',
  48. fr: 'French',
  49. fy: 'Frisian',
  50. gl: 'Galician',
  51. ka: 'Georgian',
  52. de: 'German',
  53. el: 'Greek',
  54. gu: 'Gujarati',
  55. ht: 'Haitian Creole',
  56. ha: 'Hausa',
  57. haw: 'Hawaiian',
  58. iw: 'Hebrew',
  59. hi: 'Hindi',
  60. hmn: 'Hmong',
  61. hu: 'Hungarian',
  62. is: 'Icelandic',
  63. ig: 'Igbo',
  64. id: 'Indonesian',
  65. ga: 'Irish',
  66. it: 'Italian',
  67. ja: 'Japanese',
  68. jw: 'Javanese',
  69. kn: 'Kannada',
  70. kk: 'Kazakh',
  71. km: 'Khmer',
  72. ko: 'Korean',
  73. ku: 'Kurdish (Kurmanji)',
  74. ky: 'Kyrgyz',
  75. lo: 'Lao',
  76. la: 'Latin',
  77. lv: 'Latvian',
  78. lt: 'Lithuanian',
  79. lb: 'Luxembourgish',
  80. mk: 'Macedonian',
  81. mg: 'Malagasy',
  82. ms: 'Malay',
  83. ml: 'Malayalam',
  84. mt: 'Maltese',
  85. mi: 'Maori',
  86. mr: 'Marathi',
  87. mn: 'Mongolian',
  88. my: 'Myanmar (Burmese)',
  89. ne: 'Nepali',
  90. no: 'Norwegian',
  91. ps: 'Pashto',
  92. fa: 'Persian',
  93. pl: 'Polish',
  94. pt: 'Portuguese',
  95. pa: 'Punjabi',
  96. ro: 'Romanian',
  97. ru: 'Russian',
  98. sm: 'Samoan',
  99. gd: 'Scots Gaelic',
  100. sr: 'Serbian',
  101. st: 'Sesotho',
  102. sn: 'Shona',
  103. sd: 'Sindhi',
  104. si: 'Sinhala',
  105. sk: 'Slovak',
  106. sl: 'Slovenian',
  107. so: 'Somali',
  108. es: 'Spanish',
  109. su: 'Sundanese',
  110. sw: 'Swahili',
  111. sv: 'Swedish',
  112. tg: 'Tajik',
  113. ta: 'Tamil',
  114. te: 'Telugu',
  115. th: 'Thai',
  116. tr: 'Turkish',
  117. uk: 'Ukrainian',
  118. ur: 'Urdu',
  119. uz: 'Uzbek',
  120. vi: 'Vietnamese',
  121. cy: 'Welsh',
  122. xh: 'Xhosa',
  123. yi: 'Yiddish',
  124. yo: 'Yoruba',
  125. zu: 'Zulu',
  126. };
  127.  
  128. function validateLanguage(language) {
  129. if (!language) {
  130. throw new Error('Language cannot be empty');
  131. }
  132. const isoCode = getISOCode(language);
  133. if (!isoCode) {
  134. throw new Error(`Language not supported: ${language}`);
  135. }
  136. return isoCode;
  137. }
  138.  
  139. function getISOCode(language) {
  140. if (!language) return false;
  141. language = language.toLowerCase();
  142. if (language in languages) return language;
  143.  
  144. let keys = Object.keys(languages).filter(key => {
  145. if (typeof languages[key] !== 'string') return false;
  146. return languages[key].toLowerCase() === language;
  147. });
  148.  
  149. return keys[0] || false;
  150. }
  151.  
  152. function isSupported(language) {
  153. return Boolean(getISOCode(language));
  154. }
  155.  
  156. function getCacheKey(text, options) {
  157. return `${text}|${options.from}|${options.to}`;
  158. }
  159.  
  160. function getFromCache(text, options) {
  161. const key = getCacheKey(text, options);
  162. const cached = translationCache.get(key);
  163. if (cached && Date.now() - cached.timestamp < CACHE_EXPIRY) {
  164. return cached.result;
  165. }
  166. return null;
  167. }
  168.  
  169. function saveToCache(text, options, result) {
  170. const key = getCacheKey(text, options);
  171. translationCache.set(key, {
  172. result,
  173. timestamp: Date.now(),
  174. });
  175. }
  176.  
  177. async function translate(text, options = {}) {
  178. if (!text) throw new Error('Text cannot be empty');
  179.  
  180. options.from = options.from || 'auto';
  181. options.to = options.to || 'en';
  182.  
  183. options.from = validateLanguage(options.from);
  184. options.to = validateLanguage(options.to);
  185.  
  186. const cached = getFromCache(text, options);
  187. if (cached) return cached;
  188.  
  189. let baseUrl = 'https://translate.googleapis.com/translate_a/single';
  190. let data = {
  191. client: 'gtx',
  192. sl: options.from,
  193. tl: options.to,
  194. dt: 't',
  195. q: text,
  196. };
  197.  
  198. let url = `${baseUrl}?` + new URLSearchParams(data).toString();
  199.  
  200. return new Promise((resolve, reject) => {
  201. GM_xmlhttpRequest({
  202. method: 'GET',
  203. url: url,
  204. headers: {
  205. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
  206. Accept: '*/*',
  207. },
  208. timeout: 10000,
  209. onload: function (response) {
  210. try {
  211. if (response.status !== 200) {
  212. throw new Error(`HTTP Error: ${response.status}`);
  213. }
  214.  
  215. const body = JSON.parse(response.responseText);
  216.  
  217. if (!body || !Array.isArray(body) || !body[0]) {
  218. throw new Error('Invalid response structure');
  219. }
  220.  
  221. let result = {
  222. text: '',
  223. from: {
  224. language: {
  225. didYouMean: false,
  226. iso: body[2] || options.from,
  227. },
  228. text: {
  229. autoCorrected: false,
  230. value: '',
  231. didYouMean: false,
  232. },
  233. },
  234. raw: body,
  235. };
  236.  
  237. result.text = body[0]
  238. .filter(chunk => chunk && chunk[0])
  239. .map(chunk => decodeURIComponent(chunk[0].trim()))
  240. .join(' ')
  241. .trim();
  242.  
  243. saveToCache(text, options, result);
  244.  
  245. resolve(result);
  246. } catch (error) {
  247. reject(new Error('Error processing response: ' + error.message));
  248. }
  249. },
  250. onerror: function (error) {
  251. reject(new Error('Connection error: ' + error));
  252. },
  253. ontimeout: function () {
  254. reject(new Error('Timeout: Request took too long'));
  255. },
  256. });
  257. });
  258. }
  259.  
  260. async function translateWithRetry(text, options = {}, maxRetries = MAX_RETRIES, delay = RETRY_DELAY) {
  261. let lastError;
  262. for (let i = 0; i < maxRetries; i++) {
  263. try {
  264. return await translate(text, options);
  265. } catch (error) {
  266. lastError = error;
  267. console.log(`Try ${i + 1}/${maxRetries} failed:`, error);
  268. if (i < maxRetries - 1) {
  269. await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, i)));
  270. }
  271. }
  272. }
  273. throw new Error(`Translation failed after ${maxRetries} attempts: ${lastError.message}`);
  274. }
  275.  
  276. async function translateBatch(texts, options = {}) {
  277. if (!Array.isArray(texts)) {
  278. throw new Error('Texts must be an array');
  279. }
  280.  
  281. const results = [];
  282. const chunks = [];
  283.  
  284. // Chia nhỏ mảng texts thành các chunks có kích thước MAX_BATCH_SIZE
  285. for (let i = 0; i < texts.length; i += MAX_BATCH_SIZE) {
  286. chunks.push(texts.slice(i, i + MAX_BATCH_SIZE));
  287. }
  288.  
  289. // Dịch từng chunk
  290. for (const chunk of chunks) {
  291. const chunkResults = await Promise.all(
  292. chunk.map(text => translateWithRetry(text, options).catch(error => ({ error })))
  293. );
  294. results.push(...chunkResults);
  295. }
  296.  
  297. return results;
  298. }
  299.  
  300. function clearExpiredCache() {
  301. const now = Date.now();
  302. for (const [key, value] of translationCache.entries()) {
  303. if (now - value.timestamp > CACHE_EXPIRY) {
  304. translationCache.delete(key);
  305. }
  306. }
  307. }
  308.  
  309. setInterval(clearExpiredCache, 60 * 60 * 1000);
  310.  
  311. return {
  312. translate,
  313. translateWithRetry,
  314. translateBatch,
  315. languages,
  316. getISOCode,
  317. isSupported,
  318. clearExpiredCache,
  319. };
  320. })();
  321.  
  322. if (typeof module !== 'undefined' && module.exports) {
  323. module.exports = GoogleTranslateAPI;
  324. }

QingJ © 2025

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