aboutsummaryrefslogtreecommitdiff
path: root/node_modules/translatte
diff options
context:
space:
mode:
authorMinteck <contact@minteck.org>2022-04-09 16:39:03 +0200
committerMinteck <contact@minteck.org>2022-04-09 16:40:02 +0200
commit0f8967b9113d698cdeb2d05ca85d2d9a80461c24 (patch)
tree00664ddd9c55a2c33631fd1bd33e556cea9c67e5 /node_modules/translatte
parentdac03ac82bc0f8044a4b339c27b5390e4dcecf2f (diff)
downloadvoicer-trunk.tar.gz
voicer-trunk.tar.bz2
voicer-trunk.zip
CommitHEADtrunk
Diffstat (limited to 'node_modules/translatte')
-rwxr-xr-xnode_modules/translatte/LICENSE.txt21
-rwxr-xr-xnode_modules/translatte/README.md200
-rwxr-xr-xnode_modules/translatte/index.js406
-rwxr-xr-xnode_modules/translatte/languages.js187
-rwxr-xr-xnode_modules/translatte/logo.pngbin0 -> 23775 bytes
-rwxr-xr-xnode_modules/translatte/package.json47
-rwxr-xr-xnode_modules/translatte/token.js120
-rwxr-xr-xnode_modules/translatte/translatte_lg.pngbin0 -> 449434 bytes
-rwxr-xr-xnode_modules/translatte/translatte_md.pngbin0 -> 141215 bytes
9 files changed, 981 insertions, 0 deletions
diff --git a/node_modules/translatte/LICENSE.txt b/node_modules/translatte/LICENSE.txt
new file mode 100755
index 0000000..1f6d321
--- /dev/null
+++ b/node_modules/translatte/LICENSE.txt
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2019, ExtensionsApp <extensionsapp@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE. \ No newline at end of file
diff --git a/node_modules/translatte/README.md b/node_modules/translatte/README.md
new file mode 100755
index 0000000..03e4290
--- /dev/null
+++ b/node_modules/translatte/README.md
@@ -0,0 +1,200 @@
+# A free and unlimited translate for NodeJS.
+
+<p align="center"><img src="https://raw.githubusercontent.com/extensionsapp/translatte/master/translatte_md.png" alt="TRANSLATTE, npm package translate for NodeJS" title="TRANSLATTE, npm package translate for NodeJS"></p>
+
+### Installation
+```
+npm i translatte
+```
+
+### Usage
+
+Translate string to German:
+
+```javascript
+const translatte = require('translatte');
+
+translatte('Do you speak Russian?', {to: 'de'}).then(res => {
+ console.log(res.text);
+}).catch(err => {
+ console.error(err);
+});
+// Ihr sprecht auf Russisch?
+```
+
+Translate string to English using proxy:
+
+```javascript
+const translatte = require('translatte');
+
+translatte('Вы говорите по-русски?', {
+ from: 'ru',
+ to: 'en',
+ agents: [
+ 'Mozilla/5.0 (Windows NT 10.0; ...',
+ 'Mozilla/4.0 (Windows NT 10.0; ...',
+ 'Mozilla/5.0 (Windows NT 10.0; ...'
+ ],
+ proxies: [
+ 'LOGIN:PASSWORD@192.0.2.100:12345',
+ 'LOGIN:PASSWORD@192.0.2.200:54321'
+ ]
+}).then(res => {
+ console.log(res);
+}).catch(err => {
+ console.error(err);
+});
+// { text: 'Do you speak Russian?',
+// from: {
+// language: {
+// didYouMean: false,
+// iso: 'ru'
+// },
+// text: {
+// autoCorrected: false,
+// value: '',
+// didYouMean: false
+// }
+// },
+// raw: '' }
+```
+
+## API
+
+### translatte(text, options)
+
+#### text
+
+Type: `string`
+
+The text to be translated.
+
+#### options
+
+Type: `object`
+
+##### from
+
+Type: `string` Default: `auto`
+
+The `text` language. Must be `auto` or one of the codes/names (not case sensitive) contained in [languages.js](https://github.com/extensionsapp/translatte/blob/master/languages.js).
+
+##### to
+
+Type: `string` Default: `en`
+
+The language in which the text should be translated. Must be one of the codes/names (not case sensitive) contained in [languages.js](https://github.com/extensionsapp/translatte/blob/master/languages.js).
+
+##### raw
+
+Type: `boolean` Default: `false`
+
+If `true`, the returned object will have a `raw` property with the raw response (`string`) from Google Translate.
+
+##### agents
+
+Type: `array` Default: `[]`
+
+An `array` of strings specifying the user-agent `['Mozilla/5.0 ...', 'Mozilla/4.0 ...']`. One random result will be selected.
+
+##### proxies
+
+Type: `array` Default: `[]`
+
+An `array` of strings `LOGIN:PASSWORD@IP:PORT` specifying the proxies `['LOGIN:PASSWORD@192.0.2.100:12345', 'LOGIN:PASSWORD@192.0.2.200:54321']`. One random result will be selected.
+
+##### tld
+
+Type: `string` Default: `com`
+
+TLD for Google translate host to be used in API calls: `https://translate.google.[tld]`
+
+##### client
+
+Type: `string` Default: `t`
+
+Query parameter client used in API calls. Can be `t|gtx`.
+
+#### priority
+
+Type: `array` Default: `['google_free']`
+
+Array of priority services.
+
+#### services
+
+Type: `object` Default: `{"google_free": true}`
+
+Objects in order of priority, if one of the services does not perform the translation, it proceeds to the next.
+
+**Supported services:**
+- `{"google_free": true}`
+ - <a href="https://translate.google.com/" target="_blank">Google Translate</a>, this service works by default. It is completely free and has no limits.
+- `{"google_v3": {"project-id": "XXX", "token": "YYY"}}`
+ - <a href="https://cloud.google.com/translate/docs/quickstart-client-libraries-v3" target="_blank">Google Cloud</a>, requires registration and credit card details. 500,000 characters per month are issued free of charge, then $20 for every million characters.
+- `{"microsoft_v3": {"key": "XXX", "location": "global"}}`
+ - <a href="https://azure.microsoft.com/en-us/pricing/details/cognitive-services/translator-text-api/" target="_blank">Microsoft Azure</a>, requires registration and credit card details. Free of charge 2,000,000 characters per month, then $10 for every million characters.
+- `{"yandex_v1": {"key": "XXX"}}`
+ - <a href="https://translate.yandex.ru/developers/keys" target="_blank">Yandex Translate</a>, requires registration. Free of charge 10,000,000 characters per month.
+- `{"yandex_v2": {"key": "XXX"}}`
+ - <a href="https://cloud.yandex.ru/docs/translate/" target="_blank">Yandex Cloud</a>, requires registration and credit card details. $15 for every million characters.
+
+### Returns an `object`:
+
+- `text` *(string)* – The translated text.
+- `from` *(object)*
+ - `language` *(object)*
+ - `didYouMean` *(boolean)* - `true` if the API suggest a correction in the source language
+ - `iso` *(string)* - The [code of the language](https://github.com/extensionsapp/translatte/blob/master/languages.js) that the API has recognized in the `text`
+ - `text` *(object)*
+ - `autoCorrected` *(boolean)* – `true` if the API has auto corrected the `text`
+ - `value` *(string)* – The auto corrected `text` or the `text` with suggested corrections
+ - `didYouMean` *(boolean)* – `true` if the API has suggested corrections to the `text`
+- `raw` *(string)* - If `options.raw` is true, the raw response from Google Translate servers. Otherwise, `''`.
+- `proxy` *(string)* – The proxy that were used in the request.
+- `agent` *(string)* – The agent that were used in the request.
+- `service` *(object)* – The service that were used in the request.
+
+Note that `res.from.text` will only be returned if `from.text.autoCorrected` or `from.text.didYouMean` equals to `true`. In this case, it will have the corrections delimited with brackets (`[ ]`):
+
+``` js
+translate('I spea Dutch').then(res => {
+ console.log(res.from.text.value);
+ //=> I [speak] Dutch
+}).catch(err => {
+ console.error(err);
+});
+```
+Otherwise, it will be an empty `string` (`''`).
+
+### Errors an `object`:
+
+Errors in the name of each `services`.
+
+```json
+{
+ "google_free": "Could not get token from google",
+ "google_v3": "Response code 403 (Forbidden)",
+ "microsoft_v3": "Response code 403 (Forbidden)",
+ "yandex_v1": "Response code 403 (Forbidden)",
+ "yandex_v2": "Response code 403 (Forbidden)"
+}
+```
+
+If the proxy server `LOGIN:PASSWORD@192.0.2.100:12345` is inactive.
+
+```json
+{
+ "google_free": "LOGIN:PASSWORD@192.0.2.100:12345"
+}
+```
+
+If the error is not related to `services`.
+
+```json
+{
+ "message": "The language «foo» is not supported"
+}
+```
+
+**2020 ExtensionsApp** \ No newline at end of file
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(/<b><i>/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
diff --git a/node_modules/translatte/languages.js b/node_modules/translatte/languages.js
new file mode 100755
index 0000000..083714e
--- /dev/null
+++ b/node_modules/translatte/languages.js
@@ -0,0 +1,187 @@
+/**
+ *
+ * Generated from https://translate.google.com
+ *
+ * The languages that Google Translate supports (as of 5/15/16) alongside with their ISO 639-1 codes
+ * See https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
+ */
+
+var langs = {
+ 'auto': 'Automatic',
+ 'af': 'Afrikaans',
+ 'sq': 'Albanian',
+ 'am': 'Amharic',
+ 'ar': 'Arabic',
+ 'hy': 'Armenian',
+ 'az': 'Azerbaijani',
+ 'eu': 'Basque',
+ 'be': 'Belarusian',
+ 'bn': 'Bengali',
+ 'bs': 'Bosnian',
+ 'bg': 'Bulgarian',
+ 'ca': 'Catalan',
+ 'ceb': 'Cebuano',
+ 'ny': 'Chichewa',
+ 'zh': 'Chinese (Simplified)',
+ 'zh-cn': 'Chinese (Simplified)',
+ 'zh-tw': 'Chinese (Traditional)',
+ 'co': 'Corsican',
+ 'hr': 'Croatian',
+ 'cs': 'Czech',
+ 'da': 'Danish',
+ 'nl': 'Dutch',
+ 'en': 'English',
+ 'eo': 'Esperanto',
+ 'et': 'Estonian',
+ 'tl': 'Filipino',
+ 'fi': 'Finnish',
+ 'fr': 'French',
+ 'fy': 'Frisian',
+ 'gl': 'Galician',
+ 'ka': 'Georgian',
+ 'de': 'German',
+ 'el': 'Greek',
+ 'gu': 'Gujarati',
+ 'ht': 'Haitian Creole',
+ 'ha': 'Hausa',
+ 'haw': 'Hawaiian',
+ 'he': 'Hebrew',
+ 'iw': 'Hebrew',
+ 'hi': 'Hindi',
+ 'hmn': 'Hmong',
+ 'hu': 'Hungarian',
+ 'is': 'Icelandic',
+ 'ig': 'Igbo',
+ 'id': 'Indonesian',
+ 'ga': 'Irish',
+ 'it': 'Italian',
+ 'ja': 'Japanese',
+ 'jw': 'Javanese',
+ 'kn': 'Kannada',
+ 'kk': 'Kazakh',
+ 'km': 'Khmer',
+ 'ko': 'Korean',
+ 'ku': 'Kurdish (Kurmanji)',
+ 'ky': 'Kyrgyz',
+ 'lo': 'Lao',
+ 'la': 'Latin',
+ 'lv': 'Latvian',
+ 'lt': 'Lithuanian',
+ 'lb': 'Luxembourgish',
+ 'mk': 'Macedonian',
+ 'mg': 'Malagasy',
+ 'ms': 'Malay',
+ 'ml': 'Malayalam',
+ 'mt': 'Maltese',
+ 'mi': 'Maori',
+ 'mr': 'Marathi',
+ 'mn': 'Mongolian',
+ 'my': 'Myanmar (Burmese)',
+ 'ne': 'Nepali',
+ 'no': 'Norwegian',
+ 'ps': 'Pashto',
+ 'fa': 'Persian',
+ 'pl': 'Polish',
+ 'pt': 'Portuguese',
+ 'pa': 'Punjabi',
+ 'ro': 'Romanian',
+ 'ru': 'Russian',
+ 'sm': 'Samoan',
+ 'gd': 'Scots Gaelic',
+ 'sr': 'Serbian',
+ 'st': 'Sesotho',
+ 'sn': 'Shona',
+ 'sd': 'Sindhi',
+ 'si': 'Sinhala',
+ 'sk': 'Slovak',
+ 'sl': 'Slovenian',
+ 'so': 'Somali',
+ 'es': 'Spanish',
+ 'su': 'Sundanese',
+ 'sw': 'Swahili',
+ 'sv': 'Swedish',
+ 'tg': 'Tajik',
+ 'ta': 'Tamil',
+ 'te': 'Telugu',
+ 'th': 'Thai',
+ 'tr': 'Turkish',
+ 'uk': 'Ukrainian',
+ 'ur': 'Urdu',
+ 'uz': 'Uzbek',
+ 'vi': 'Vietnamese',
+ 'cy': 'Welsh',
+ 'xh': 'Xhosa',
+ 'yi': 'Yiddish',
+ 'yo': 'Yoruba',
+ 'zu': 'Zulu'
+};
+/**
+ * Returns the ISO 639-1 code of the desiredLang – if it is supported by Google Translate
+ * @param {string} desiredLang – the name or the code of the desired language
+ * @returns {string|boolean} The ISO 639-1 code of the language or false if the language is not supported
+ */
+function getCode(desiredLang) {
+ if (!desiredLang) {
+ return false;
+ }
+ desiredLang = desiredLang.toLowerCase();
+
+ if (langs[desiredLang]) {
+ return desiredLang;
+ }
+
+ var keys = Object.keys(langs).filter(function (key) {
+ if (typeof langs[key] !== 'string') {
+ return false;
+ }
+
+ return langs[key].toLowerCase() === desiredLang;
+ });
+
+ return keys[0] || false;
+}
+
+/**
+ * Returns true if the desiredLang is supported by Google Translate and false otherwise
+ * @param desiredLang – the ISO 639-1 code or the name of the desired language
+ * @returns {boolean}
+ */
+function isSupported(desiredLang) {
+ return Boolean(getCode(desiredLang));
+}
+
+/**
+ * Returns utf8 length
+ * @param str – string
+ * @returns {number}
+ */
+function utf8Length(str) {
+ var utf8 = [];
+ for (var i = 0; i < str.length; i++) {
+ var charcode = str.charCodeAt(i);
+ if (charcode < 0x80) utf8.push(charcode);
+ else if (charcode < 0x800) {
+ utf8.push(0xc0 | (charcode >> 6),
+ 0x80 | (charcode & 0x3f));
+ } else if (charcode < 0xd800 || charcode >= 0xe000) {
+ utf8.push(0xe0 | (charcode >> 12),
+ 0x80 | ((charcode >> 6) & 0x3f),
+ 0x80 | (charcode & 0x3f));
+ }
+ else {
+ i++;
+ charcode = 0x10000 + (((charcode & 0x3ff) << 10)
+ | (str.charCodeAt(i) & 0x3ff));
+ utf8.push(0xf0 | (charcode >> 18),
+ 0x80 | ((charcode >> 12) & 0x3f),
+ 0x80 | ((charcode >> 6) & 0x3f),
+ 0x80 | (charcode & 0x3f));
+ }
+ }
+ return utf8.length;
+}
+
+module.exports = langs;
+module.exports.isSupported = isSupported;
+module.exports.getCode = getCode;
+module.exports.utf8Length = utf8Length; \ No newline at end of file
diff --git a/node_modules/translatte/logo.png b/node_modules/translatte/logo.png
new file mode 100755
index 0000000..9a13d88
--- /dev/null
+++ b/node_modules/translatte/logo.png
Binary files differ
diff --git a/node_modules/translatte/package.json b/node_modules/translatte/package.json
new file mode 100755
index 0000000..96ea209
--- /dev/null
+++ b/node_modules/translatte/package.json
@@ -0,0 +1,47 @@
+{
+ "name": "translatte",
+ "version": "3.0.1",
+ "description": "A free and unlimited translate for NodeJS",
+ "main": "index.js",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/extensionsapp/translatte.git"
+ },
+ "keywords": [
+ "translate",
+ "translator",
+ "google",
+ "google translate",
+ "api",
+ "free",
+ "language",
+ "proxy",
+ "translatte",
+ "microsoft",
+ "azure",
+ "microsoft azure",
+ "microsoft translate",
+ "azure translate",
+ "google cloud",
+ "google cloud translate",
+ "yandex",
+ "yandex cloud",
+ "yandex translate",
+ "yandex cloud translate"
+ ],
+ "author": {
+ "name": "ExtensionsApp",
+ "email": "extensionsapp@gmail.com"
+ },
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/extensionsapp/translatte/issues"
+ },
+ "homepage": "https://github.com/extensionsapp/translatte#readme",
+ "dependencies": {
+ "tunnel": "0.0.6",
+ "configstore": "4.0.0",
+ "proxy-check": "1.0.8",
+ "got": "9.6.0"
+ }
+}
diff --git a/node_modules/translatte/token.js b/node_modules/translatte/token.js
new file mode 100755
index 0000000..71f360b
--- /dev/null
+++ b/node_modules/translatte/token.js
@@ -0,0 +1,120 @@
+/**
+ * Last update: 2018/11/24
+ * https://translate.google.com/translate/releases/twsfe_w_20160620_RC00/r/js/desktop_module_main.js
+ *
+ * Everything between 'BEGIN' and 'END' was copied from the url above.
+ */
+
+var got = require('got');
+var Configstore = require('configstore');
+
+/* eslint-disable */
+// BEGIN
+
+function sM(a) {
+ var b;
+ if (null !== yr)
+ b = yr;
+ else {
+ b = wr(String.fromCharCode(84));
+ var c = wr(String.fromCharCode(75));
+ b = [b(), b()];
+ b[1] = c();
+ b = (yr = window[b.join(c())] || "") || ""
+ }
+ var d = wr(String.fromCharCode(116))
+ , c = wr(String.fromCharCode(107))
+ , d = [d(), d()];
+ d[1] = c();
+ c = "&" + d.join("") + "=";
+ d = b.split(".");
+ b = Number(d[0]) || 0;
+ for (var e = [], f = 0, g = 0; g < a.length; g++) {
+ var l = a.charCodeAt(g);
+ 128 > l ? e[f++] = l : (2048 > l ? e[f++] = l >> 6 | 192 : (55296 === (l & 64512) && g + 1 < a.length && 56320 === (a.charCodeAt(g + 1) & 64512) ? (l = 65536 + ((l & 1023) << 10) + (a.charCodeAt(++g) & 1023),
+ e[f++] = l >> 18 | 240,
+ e[f++] = l >> 12 & 63 | 128) : e[f++] = l >> 12 | 224,
+ e[f++] = l >> 6 & 63 | 128),
+ e[f++] = l & 63 | 128)
+ }
+ a = b;
+ for (f = 0; f < e.length; f++)
+ a += e[f],
+ a = xr(a, "+-a^+6");
+ a = xr(a, "+-3^+b+-f");
+ a ^= Number(d[1]) || 0;
+ 0 > a && (a = (a & 2147483647) + 2147483648);
+ a %= 1E6;
+ return c + (a.toString() + "." + (a ^ b))
+}
+
+var yr = null;
+var wr = function (a) {
+ return function () {
+ return a
+ }
+}
+ , xr = function (a, b) {
+ for (var c = 0; c < b.length - 2; c += 3) {
+ var d = b.charAt(c + 2)
+ , d = "a" <= d ? d.charCodeAt(0) - 87 : Number(d)
+ , d = "+" === b.charAt(c + 1) ? a >>> d : a << d;
+ a = "+" === b.charAt(c) ? a + d & 4294967295 : a ^ d
+ }
+ return a
+};
+
+// END
+/* eslint-enable */
+
+var config = new Configstore('google-translate-api');
+
+var window = {
+ TKK: config.get('TKK') || '422854.923862967'
+};
+
+function updateTKK(opts) {
+ opts = opts || {tld: 'com', proxy: {}, headers: {}};
+ return new Promise(function (resolve, reject) {
+ var now = Math.floor(Date.now() / 3600000);
+
+ if (Number(window.TKK.split('.')[0]) === now) {
+ resolve();
+ } else {
+ got('https://translate.google.' + opts.tld, {...opts.proxy, headers: opts.headers, timeout: 2000, retry: 0}).then(function (res) {
+ var code = res.body.match(/TKK='.*?';/g);
+
+ if (code) {
+ eval(code[0]);
+ /* eslint-disable no-undef */
+ if (typeof TKK !== 'undefined') {
+ window.TKK = TKK;
+ config.set('TKK', TKK);
+ }
+ /* eslint-enable no-undef */
+ }
+
+ /**
+ * Note: If the regex or the eval fail, there is no need to worry. The server will accept
+ * relatively old seeds.
+ */
+
+ resolve();
+ }).catch(function () {
+ reject();
+ });
+ }
+ });
+}
+
+function get(text, opts) {
+ return updateTKK(opts).then(function () {
+ var tk = sM(text);
+ tk = tk.replace('&tk=', '');
+ return {name: 'tk', value: tk};
+ }).catch(function () {
+ return null;
+ });
+}
+
+module.exports.get = get; \ No newline at end of file
diff --git a/node_modules/translatte/translatte_lg.png b/node_modules/translatte/translatte_lg.png
new file mode 100755
index 0000000..a544465
--- /dev/null
+++ b/node_modules/translatte/translatte_lg.png
Binary files differ
diff --git a/node_modules/translatte/translatte_md.png b/node_modules/translatte/translatte_md.png
new file mode 100755
index 0000000..c166c39
--- /dev/null
+++ b/node_modules/translatte/translatte_md.png
Binary files differ