From 0f8967b9113d698cdeb2d05ca85d2d9a80461c24 Mon Sep 17 00:00:00 2001 From: Minteck Date: Sat, 9 Apr 2022 16:39:03 +0200 Subject: Commit --- node_modules/translatte/index.js | 406 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 406 insertions(+) create mode 100755 node_modules/translatte/index.js (limited to 'node_modules/translatte/index.js') diff --git a/node_modules/translatte/index.js b/node_modules/translatte/index.js new file mode 100755 index 0000000..16083db --- /dev/null +++ b/node_modules/translatte/index.js @@ -0,0 +1,406 @@ +const querystring = require('querystring'); +const languages = require('./languages'); +const proxy_check = require('proxy-check'); +const tunnel = require('tunnel'); +const token = require('./token'); +const got = require('got'); + +const translatte = async (text, opts) => { + opts = opts || {}; + opts = JSON.parse(JSON.stringify(opts)); + + let result = { + text: '', + raw: '', + from: { + language: { + didYouMean: false, + iso: '' + }, + text: { + autoCorrected: false, + value: '', + didYouMean: false + } + }, + proxy: '', + agent: '', + service: {google_free: true} + }; + + let errors = [ + 'The language «[lang]» is not supported', + 'Text must not exceed 5000 bytes', + 'The server returned an empty response', + 'Could not get token from google', + 'Text translation request failed' + ]; + + if (opts.from && !languages.isSupported(opts.from)) { + return Promise.reject({message: errors[0].replace('[lang]', opts.from)}); + } + + if (opts.to && !languages.isSupported(opts.to)) { + return Promise.reject({message: errors[0].replace('[lang]', opts.to)}); + } + + let bytes = languages.utf8Length(text); + opts.client = opts.client || 't'; + opts.tld = opts.tld || 'com'; + opts.from = languages.getCode(opts.from || 'auto'); + opts.to = languages.getCode(opts.to || 'en'); + opts.services = opts.services || {google_free: true}; + let services = Object.keys(opts.services); + + opts.priority = opts.priority + ? typeof opts.priority === 'string' + ? [opts.priority] + : opts.priority.filter(p => services.indexOf(p) + 1) + : services; + + if (opts.priority.length > 1) { + let all_index = opts.priority.length - 1; + let err_services = {}; + return opts.priority.reduce((p, priority, index) => { + return p.then(prev => { + return new Promise((resolve, reject) => { + if (prev) return resolve(prev); + translatte(text, {...opts, priority}).then(t => { + if (!t || !t.text) { + err_services[priority] = errors[2]; + return all_index === index + ? reject(err_services) + : resolve(); + } + return resolve(t); + }).catch(e => { + err_services[priority] = typeof e === 'object' && (e[priority] || e.message) + ? e[priority] || e.message + : e; + return all_index === index + ? reject(err_services) + : resolve(); + }); + }); + }); + }, Promise.resolve()); + } + + let priority = opts.priority[0]; + + if (bytes > 5000) { + let chars = Math.ceil(text.length / Math.ceil(bytes / 4700)) + 100; + let plain = ' ' + text + ' '; + let texts = []; + let j = 0; + ['.', ',', ' '].forEach(separator => { + if (!plain) return; + let split = plain.split(separator); + for (let i = 0, l = split.length; i < l; i++) { + if (!texts[j]) texts[j] = []; + if ((texts[j].join(separator) + split[i]).length < chars) { + texts[j].push(split[i]); + plain = split.slice(i+1).join(separator); + } else { + if (!texts[j].length) break; + texts[j].push(''); + texts[++j] = []; + if ((texts[j].join(separator) + split[i]).length < chars) { + texts[j].push(split[i]); + plain = split.slice(i+1).join(separator); + } else { + break; + } + } + } + texts = texts.map(function (t) { + if (!t) return; + if (typeof t === 'object') { + return t.join(separator).trim(); + } else if (typeof t === 'string') { + return t.trim(); + } + }).filter(Boolean); + }); + if (!texts || !texts.length) return Promise.reject({[priority]: errors[1]}); + return texts.reduce((p, item) => { + return p.then(prev => { + return new Promise((resolve, reject) => { + setTimeout(() => { + translatte(item, opts).then(t => { + if (!t || !t.text) return reject(errors[2]); + t.text = prev && prev.text ? prev.text + ' ' + t.text : t.text; + return resolve(t); + }).catch(e => reject(e)); + }, 1000); + }); + }); + }, Promise.resolve()); + } + + if (priority === 'google_v3') { + if (Array.isArray(opts.services['google_v3'])) { + opts.services['google_v3'] = opts + .services['google_v3'][Math.floor(Math.random() * opts + .services['google_v3'].length)]; + } + result.service = {google_v3: opts.services['google_v3']}; + let url = 'https://translation.googleapis.com/v3beta1/projects/' + + opts.services['google_v3']['project-id'] + '/locations/global:translateText'; + try { + const {body} = await got(url, { + method: 'POST', + headers: { + 'Authorization': 'Bearer ' + opts.services['google_v3']['token'], + 'Content-type': 'application/json' + }, + body: { + source_language_code: opts.from, + target_language_code: opts.to, + contents: [text] + }, + json: true, + timeout: 10000, + retry: 0 + }); + for (const translation of body.translations) { + result.text += result.text + ? ' ' + translation.translations.translatedText + : translation.translations.translatedText; + } + } catch (e) { + return Promise.reject({google_v3: e.message || e}); + } + return Promise.resolve(result); + } + + if (priority === 'microsoft_v3') { + if (!opts.services['microsoft_v3']) return Promise.resolve(result); + if (Array.isArray(opts.services['microsoft_v3'])) { + opts.services['microsoft_v3'] = opts + .services['microsoft_v3'][Math.floor(Math.random() * opts + .services['microsoft_v3'].length)]; + } + result.service = {microsoft_v3: opts.services['microsoft_v3']}; + let url = 'https://api.cognitive.microsofttranslator.com/translate?' + + querystring.stringify({ + 'api-version': '3.0', + from: opts.from === 'auto' ? '' : opts.from, + to: opts.to + }); + try { + const {body} = await got(url, { + method: 'POST', + headers: { + 'Ocp-Apim-Subscription-Key': opts.services['microsoft_v3']['key'], + 'Ocp-Apim-Subscription-Region': opts.services['microsoft_v3']['location'] + ? opts.services['microsoft_v3']['location'].replace(/[^a-z]/ig, '').toLowerCase() + : 'global', + 'Content-type': 'application/json' + }, + body: [{text}], + json: true, + timeout: 10000, + retry: 0 + }); + for (const translation of body) { + if (translation.detectedLanguage && translation.detectedLanguage.language) { + result.from.language.iso = translation.detectedLanguage.language; + } + result.text += result.text + ? ' ' + translation.translations[0].text + : translation.translations[0].text; + } + } catch (e) { + return Promise.reject({microsoft_v3: e.message || e}); + } + return Promise.resolve(result); + } + + if (priority === 'yandex_v1') { + if (!opts.services['yandex_v1']) return Promise.resolve(result); + if (Array.isArray(opts.services['yandex_v1'])) { + opts.services['yandex_v1'] = opts + .services['yandex_v1'][Math.floor(Math.random() * opts + .services['yandex_v1'].length)]; + } + result.service = {yandex_v1: opts.services['yandex_v1']}; + let url = 'https://translate.yandex.net/api/v1.5/tr.json/translate?' + + querystring.stringify({ + key: opts.services['yandex_v1']['key'], + lang: opts.from && opts.from !== 'auto' + ? opts.from + '-' + opts.to + : opts.to, + text: text + }); + try { + const {body} = await got(url, {json: true, timeout: 10000, retry: 0}); + for (const translation of body.text) { + result.text += result.text + ? ' ' + translation + : translation; + } + } catch (e) { + return Promise.reject({yandex_v1: e.message || e}); + } + return Promise.resolve(result); + } + + if (priority === 'yandex_v2') { + if (!opts.services['yandex_v2']) return Promise.resolve(result); + if (Array.isArray(opts.services['yandex_v2'])) { + opts.services['yandex_v2'] = opts + .services['yandex_v2'][Math.floor(Math.random() * opts + .services['yandex_v2'].length)]; + } + result.service = {yandex_v2: opts.services['yandex_v2']}; + let url = 'https://translate.api.cloud.yandex.net/translate/v2/translate'; + try { + const {body} = await got(url, { + method: 'POST', + headers: { + 'Authorization': 'Api-Key ' + opts.services['yandex_v2']['key'], + 'Content-type': 'application/json' + }, + body: { + sourceLanguageCode: opts.from, + targetLanguageCode: opts.to, + texts: [text] + }, + json: true, + timeout: 10000, + retry: 0 + }); + for (const translation of body.translations) { + result.text += result.text + ? ' ' + translation.text + : translation.text; + } + } catch (e) { + return Promise.reject({yandex_v2: e.message || e}); + } + return Promise.resolve(result); + } + + let proxy = {}; + let translate = {}; + + opts.agents = opts.agents + ? typeof opts.agents === 'string' + ? opts.agents.split(',').map(p => p.trim()) + : opts.agents + : []; + opts.proxies = opts.proxies + ? typeof opts.proxies === 'string' + ? opts.proxies.split(',').map(p => p.trim()) + : opts.proxies + : []; + + if (opts.agents.length) { + let a = opts.agents[Math.floor(Math.random() * opts.agents.length)]; + result.agent = a; + opts.headers = { + 'User-Agent': a + }; + } + if (opts.proxies.length) { + let p = opts.proxies[Math.floor(Math.random() * opts.proxies.length)]; + result.proxy = p; + if (p.indexOf('@') + 1) { + proxy.proxyAuth = p.split('@')[0]; + proxy.host = (p.split('@')[1]).split(':')[0]; + proxy.port = (p.split('@')[1]).split(':')[1]; + } else { + proxy.host = p.split(':')[0]; + proxy.port = p.split(':')[1]; + } + } + + opts.proxy = proxy.host + ? opts.headers + ? {agent: tunnel.httpsOverHttp({proxy, headers: opts.headers})} + : {agent: tunnel.httpsOverHttp({proxy})} + : {}; + + const translate_string = () => { + return new Promise(async (resolve, reject) => { + let t = await token.get(text, opts); + + if (!t) return reject({google_free: errors[3]}); + + let url = 'https://translate.google.' + opts.tld + '/translate_a/single?' + + querystring.stringify({ + [t.name]: t.value, + client: opts.client, + sl: opts.from, + tl: opts.to, + hl: opts.to, + dt: ['at', 'bd', 'ex', 'ld', 'md', 'qca', 'rw', 'rm', 'ss', 't'], + ie: 'UTF-8', + oe: 'UTF-8', + otf: 1, + ssel: 0, + tsel: 0, + kc: 7, + q: text + }); + + try { + translate = await got(url, {...opts.proxy, json: true, timeout: 10000, headers: opts.headers, retry: 0}); + } catch (e) { + return reject({google_free: errors[4]}); + } + + result.raw = opts.raw + ? JSON.stringify(translate.body) + : ''; + + let body = translate.body; + + body[0].forEach(obj => { + if (obj[0]) { + result.text += obj[0]; + } + }); + + if (body[2] === body[8][0][0]) { + result.from.language.iso = body[2]; + } else { + result.from.language.didYouMean = true; + result.from.language.iso = body[8][0][0]; + } + + if (body[7] && body[7][0]) { + let str = body[7][0]; + + str = str.replace(//g, '['); + str = str.replace(/<\/i><\/b>/g, ']'); + + result.from.text.value = str; + + if (body[7][5] === true) { + result.from.text.autoCorrected = true; + } else { + result.from.text.didYouMean = true; + } + } + + return result.text + ? resolve(result) + : reject({google_free: errors[2]}); + }); + }; + + if (opts && opts.proxy && opts.proxy.agent) { + return proxy_check(result.proxy).then(() => { + return translate_string(); + }).catch(() => { + return Promise.reject({google_free: result.proxy}); + }); + } else { + return translate_string(); + } +}; + +module.exports = translatte; +module.exports.languages = languages; \ No newline at end of file -- cgit