├── index.js ├── src ├── util.js ├── translate.js ├── token.js └── language.js ├── package.json ├── yarn.lock ├── .gitignore └── README.md /index.js: -------------------------------------------------------------------------------- 1 | 2 | var translate_1 = require("./src/translate"); 3 | 4 | function translate(value, options) { 5 | var text; 6 | if (typeof value === 'string') { 7 | text = [value]; 8 | } 9 | else { 10 | text = value; 11 | } 12 | return translate_1.default(text, options); 13 | } 14 | 15 | module.exports = translate; -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | const JOIN_WITH = "[]"; 3 | Object.defineProperty(exports, "__esModule", { value: true }); 4 | function arrayStringify(data) { 5 | return data.join(`${JOIN_WITH}\n`); 6 | } 7 | 8 | exports.arrayStringify = arrayStringify; 9 | function parseMultiple(list) { 10 | const size = list.length; 11 | var translateMap = list.map(function (item, index) { 12 | var text = item[0]; 13 | return text.trim(); 14 | }); 15 | var result = translateMap.join(' ').split(JOIN_WITH).map(item => item.trim()); 16 | return result; 17 | } 18 | exports.parseMultiple = parseMultiple; 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "translate-google-api", 3 | "version": "1.0.3", 4 | "description": "A free and unlimited API for Google Translate(contains single and multiple)", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "google", 11 | "translate", 12 | "multiple", 13 | "language", 14 | "react", 15 | "react-native" 16 | ], 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/Binhluan1234/react-google-translate-api" 20 | }, 21 | "author": "LuanNguyen", 22 | "license": "ISC", 23 | "dependencies": { 24 | "axios": "^0.20.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | axios@^0.20.0: 6 | version "0.20.0" 7 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd" 8 | integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA== 9 | dependencies: 10 | follow-redirects "^1.10.0" 11 | 12 | follow-redirects@^1.10.0: 13 | version "1.13.0" 14 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" 15 | integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | .idea -------------------------------------------------------------------------------- /src/translate.js: -------------------------------------------------------------------------------- 1 | var axios = require('axios'); 2 | 3 | var translateToken = require("./token"); 4 | var language_1 = require("./language"); 5 | var util_1 = require("./util"); 6 | 7 | function translate(data, options) { 8 | var e; 9 | options.from = options.from || 'auto'; 10 | options.to = options.to || 'en'; 11 | if (options.from) { 12 | if (!language_1.isSupport(options.from)) { 13 | e = new Error(); 14 | e.language = options.from; 15 | } 16 | } 17 | if (!language_1.isSupport(options.to)) { 18 | e = new Error(); 19 | e.language = options.to; 20 | } 21 | if (e) { 22 | e.code = 400; 23 | e.message = 'The language \'' + e.language + '\' is not supported'; 24 | return new Promise(function (_, reject) { 25 | reject(e); 26 | }); 27 | } 28 | 29 | var tld = options.tld || 'com'; 30 | return translateToken 31 | .get(data.join(''), { 32 | tld: tld, 33 | proxy: options.proxy || false, 34 | }) 35 | .then(function (res) { 36 | const text = util_1.arrayStringify(data); 37 | const url = `/translate_a/single`; 38 | var query = { 39 | client: options.client || 'gtx', 40 | sl: options.from, 41 | tl: options.to, 42 | hl: options.to, 43 | dt: 't', 44 | ie: 'UTF-8', 45 | oe: 'UTF-8', 46 | otf: 1, 47 | ssel: 0, 48 | tsel: 0, 49 | kc: 7, 50 | [res.name]: res.value, 51 | q: text 52 | }; 53 | 54 | var headers = { 55 | "content-type": "application/json", 56 | "Accept": "application/json, text/plain, */*", 57 | 'X-Requested-With': 'XMLHttpRequest' 58 | }; 59 | 60 | var extra = { 61 | method: 'post', 62 | headers, 63 | baseURL: 'https://translate.google.' + tld, 64 | url, 65 | params: query, 66 | proxy: options.proxy || false 67 | }; 68 | 69 | return axios(extra).then(function (response) { 70 | const res = util_1.parseMultiple(response.data[0]); 71 | return Promise.resolve(res); 72 | }).catch(function (error) { 73 | return Promise.reject(error); 74 | }); 75 | }) 76 | } 77 | 78 | module.exports.default = translate; 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # translate-google-api 2 | A free and unlimited API for Google Translate(support single text and Multi-segment text) 💵🚫 3 | # Feature 4 | 5 | - Multi-segment text support 6 | - Auto language detection 7 | - Language correction 8 | - Fast and reliable – it uses the same servers that [translate.google.com](https://translate.google.com/) uses 9 | - Free and unlimited (translate.google.com uses a token to authorize the requests. If you are not Google, you do not have this token and will have to pay [$20 per 1 million characters of text](https://cloud.google.com/translate/v2/pricing)) 10 | - Supports: ReactJs, React-Native, NodeJs ... 11 | 12 | # Install 13 | 14 | ```shell 15 | npm install --save translate-google-api 16 | ``` 17 | 18 | # Why this repo ? 19 | 20 | I have tried some libs for translate on React-Native app. But don't have any package support. 21 | 22 | I don't want to translate all the text first and I'd like to translate segment by segment. Especially in an article, the whole translation may not work well. 23 | 24 | In the existing library, if I want to translate multi-segment text, I have to request multiple times.(like [google-translate-api](https://github.com/matheuss/google-translate-api)) 25 | 26 | So I have to use the new api to implement, so the `translate-google-api` is born. 27 | 28 | # Usage 29 | 30 | Single segment 31 | ```javascript 32 | import translate from 'translate-google-api'; 33 | const result = await translate(`I'm fine.`, { 34 | tld: "cn", 35 | to: "vi", 36 | }); 37 | // ["Tôi ổn."] 38 | 39 | 40 | ``` 41 | 42 | Multi-segment text 43 | ```javascript 44 | import translate from 'translate-google-api'; 45 | 46 | const result = await translate(['Hi', 'How are you?', `I'm fine`], { 47 | tld: "cn", 48 | to: "vi", 49 | }); 50 | //["Chào","Bạn khỏe không?","Tôi ổn."] 51 | 52 | ``` 53 | 54 | Proxy 55 | 56 | proxy-config [https://github.com/axios/axios#request-config](https://github.com/axios/axios#request-config) 57 | ```javascript 58 | const result = await translate([`I'm fine. And you?`,`I'm ok.`], { 59 | tld: "cn", 60 | to: "vi", 61 | proxy: { 62 | host: '127.0.0.1', 63 | port: 9000, 64 | auth: { 65 | username: 'mikeymike', 66 | password: 'rapunz3l' 67 | } 68 | } 69 | }); 70 | ``` 71 | 72 | # API 73 | 74 | ## translate(text, options) 75 | 76 | ### text 77 | 78 | Type: `string`, `array` 79 | 80 | The text to be translated 81 | 82 | ### options 83 | 84 | Type: object 85 | 86 | **from?** 87 | Type: `string` Default: auto 88 | 89 | The text language. Must be auto or one of the codes/names (not case sensitive) contained in src/languages.ts 90 | 91 | **to** 92 | Type: `string` Default: en 93 | 94 | The language in which the text should be translated. Must be one of the codes/names (not case sensitive) contained in src/languages.ts. 95 | 96 | **tld** 97 | Type: `string` 'com' | 'cn' 98 | 99 | `cn` is for China, `com` for others. 100 | 101 | **proxy** 102 | Type: `AxiosProxyConfig` 103 | 104 | proxy for request. 105 | 106 | **config** 107 | Type: `object` 108 | 109 | config for [axios](https://github.com/axios/axios) 110 | 111 | # Related 112 | - [vitalets/google-translate-token](https://github.com/vitalets/google-translate-token) 113 | - [google-translate-api](https://github.com/matheuss/google-translate-api) 114 | - [translate-md-viewer](https://github.com/hua1995116/translate-md-viewer) 115 | 116 | # Inspiration 117 | 118 | # License 119 | 120 | Apache License -------------------------------------------------------------------------------- /src/token.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Last update: 2016/06/26 3 | * https://translate.google.com/translate/releases/twsfe_w_20160620_RC00/r/js/desktop_module_main.js 4 | * 5 | * Everything between 'BEGIN' and 'END' was copied from the url above. 6 | * fork from https://github.com/vitalets/google-translate-token 7 | * for support brower 8 | */ 9 | 10 | var axios = require('axios'); 11 | 12 | /* eslint-disable */ 13 | // BEGIN 14 | 15 | function sM(a) { 16 | var b; 17 | if (null !== yr) 18 | b = yr; 19 | else { 20 | b = wr(String.fromCharCode(84)); 21 | var c = wr(String.fromCharCode(75)); 22 | b = [b(), b()]; 23 | b[1] = c(); 24 | b = (yr = window[b.join(c())] || "") || "" 25 | } 26 | var d = wr(String.fromCharCode(116)) 27 | , c = wr(String.fromCharCode(107)) 28 | , d = [d(), d()]; 29 | d[1] = c(); 30 | c = "&" + d.join("") + "="; 31 | d = b.split("."); 32 | b = Number(d[0]) || 0; 33 | for (var e = [], f = 0, g = 0; g < a.length; g++) { 34 | var l = a.charCodeAt(g); 35 | 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), 36 | e[f++] = l >> 18 | 240, 37 | e[f++] = l >> 12 & 63 | 128) : e[f++] = l >> 12 | 224, 38 | e[f++] = l >> 6 & 63 | 128), 39 | e[f++] = l & 63 | 128) 40 | } 41 | a = b; 42 | for (f = 0; f < e.length; f++) 43 | a += e[f], 44 | a = xr(a, "+-a^+6"); 45 | a = xr(a, "+-3^+b+-f"); 46 | a ^= Number(d[1]) || 0; 47 | 0 > a && (a = (a & 2147483647) + 2147483648); 48 | a %= 1E6; 49 | return c + (a.toString() + "." + (a ^ b)) 50 | } 51 | 52 | var yr = null; 53 | var wr = function(a) { 54 | return function() { 55 | return a 56 | } 57 | } 58 | , xr = function(a, b) { 59 | for (var c = 0; c < b.length - 2; c += 3) { 60 | var d = b.charAt(c + 2) 61 | , d = "a" <= d ? d.charCodeAt(0) - 87 : Number(d) 62 | , d = "+" == b.charAt(c + 1) ? a >>> d : a << d; 63 | a = "+" == b.charAt(c) ? a + d & 4294967295 : a ^ d 64 | } 65 | return a 66 | }; 67 | 68 | // END 69 | /* eslint-enable */ 70 | 71 | var window = { 72 | TKK: '0' 73 | }; 74 | 75 | function updateTKK(opts) { 76 | opts = opts || {tld: 'com'}; 77 | return new Promise(function (resolve, reject) { 78 | var now = Math.floor(Date.now() / 3600000); 79 | 80 | if (Number(window.TKK.split('.')[0]) === now) { 81 | resolve(); 82 | } else { 83 | axios({ 84 | url: 'https://translate.google.' + opts.tld, 85 | proxy: opts.proxy, 86 | }).then(function (res) { 87 | var matches = res.data.match(/tkk:\s?'(.+?)'/i); 88 | 89 | if (matches) { 90 | window.TKK = matches[1]; 91 | } 92 | 93 | /** 94 | * Note: If the regex or the eval fail, there is no need to worry. The server will accept 95 | * relatively old seeds. 96 | */ 97 | 98 | resolve(); 99 | }).catch(function (err) { 100 | var e = new Error(); 101 | e.code = 'BAD_NETWORK'; 102 | e.message = err.message; 103 | reject(e); 104 | }); 105 | } 106 | }); 107 | } 108 | 109 | function get(text, opts) { 110 | return updateTKK(opts).then(function () { 111 | var tk = sM(text); 112 | tk = tk.replace('&tk=', ''); 113 | return {name: 'tk', value: tk}; 114 | }).catch(function (err) { 115 | throw err; 116 | }); 117 | } 118 | 119 | module.exports.get = get; -------------------------------------------------------------------------------- /src/language.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * 4 | * Generated from https://translate.google.com 5 | * 6 | * The languages that Google Translate supports (as of 5/15/16) alongside with their ISO 639-1 codes 7 | * See https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes 8 | */ 9 | Object.defineProperty(exports, "__esModule", { value: true }); 10 | var langs = { 11 | Automatic: "auto", 12 | Afrikaans: "af", 13 | Albanian: "sq", 14 | Amharic: "am", 15 | Arabic: "ar", 16 | Armenian: "hy", 17 | Azerbaijani: "az", 18 | Basque: "eu", 19 | Belarusian: "be", 20 | Bengali: "bn", 21 | Bosnian: "bs", 22 | Bulgarian: "bg", 23 | Catalan: "ca", 24 | Cebuano: "ceb", 25 | Chichewa: "ny", 26 | "Chinese Simplified": "zh-cn", 27 | "Chinese Traditional": "zh-tw", 28 | Corsican: "co", 29 | Croatian: "hr", 30 | Czech: "cs", 31 | Danish: "da", 32 | Dutch: "nl", 33 | English: "en", 34 | Esperanto: "eo", 35 | Estonian: "et", 36 | Filipino: "tl", 37 | Finnish: "fi", 38 | French: "fr", 39 | Frisian: "fy", 40 | Galician: "gl", 41 | Georgian: "ka", 42 | German: "de", 43 | Greek: "el", 44 | Gujarati: "gu", 45 | "Haitian Creole": "ht", 46 | Hausa: "ha", 47 | Hawaiian: "haw", 48 | Hebrew: "iw", 49 | Hindi: "hi", 50 | Hmong: "hmn", 51 | Hungarian: "hu", 52 | Icelandic: "is", 53 | Igbo: "ig", 54 | Indonesian: "id", 55 | Irish: "ga", 56 | Italian: "it", 57 | Japanese: "ja", 58 | Javanese: "jw", 59 | Kannada: "kn", 60 | Kazakh: "kk", 61 | Khmer: "km", 62 | Korean: "ko", 63 | "Kurdish (Kurmanji)": "ku", 64 | Kyrgyz: "ky", 65 | Lao: "lo", 66 | Latin: "la", 67 | Latvian: "lv", 68 | Lithuanian: "lt", 69 | Luxembourgish: "lb", 70 | Macedonian: "mk", 71 | Malagasy: "mg", 72 | Malay: "ms", 73 | Malayalam: "ml", 74 | Maltese: "mt", 75 | Maori: "mi", 76 | Marathi: "mr", 77 | Mongolian: "mn", 78 | "Myanmar (Burmese)": "my", 79 | Nepali: "ne", 80 | Norwegian: "no", 81 | Pashto: "ps", 82 | Persian: "fa", 83 | Polish: "pl", 84 | Portuguese: "pt", 85 | Punjabi: "ma", 86 | Romanian: "ro", 87 | Russian: "ru", 88 | Samoan: "sm", 89 | "Scots Gaelic": "gd", 90 | Serbian: "sr", 91 | Sesotho: "st", 92 | Shona: "sn", 93 | Sindhi: "sd", 94 | Sinhala: "si", 95 | Slovak: "sk", 96 | Slovenian: "sl", 97 | Somali: "so", 98 | Spanish: "es", 99 | Sundanese: "su", 100 | Swahili: "sw", 101 | Swedish: "sv", 102 | Tajik: "tg", 103 | Tamil: "ta", 104 | Telugu: "te", 105 | Thai: "th", 106 | Turkish: "tr", 107 | Ukrainian: "uk", 108 | Urdu: "ur", 109 | Uyghur: "ug", 110 | Uzbek: "uz", 111 | Vietnamese: "vi", 112 | Welsh: "cy", 113 | Xhosa: "xh", 114 | Yiddish: "yi", 115 | Yoruba: "yo", 116 | Zulu: "zu" 117 | }; 118 | function isSupport(language) { 119 | return Boolean(getCode(language)); 120 | } 121 | exports.isSupport = isSupport; 122 | function getCode(language) { 123 | if (!language) { 124 | return false; 125 | } 126 | if (langs[language]) { 127 | return langs[language]; 128 | } 129 | var keys = Object.keys(langs).filter(function (item) { 130 | var lowerLan = language.toLowerCase(); 131 | return langs[item] === lowerLan; 132 | }); 133 | if (keys[0]) { 134 | return langs[keys[0]]; 135 | } 136 | return false; 137 | } 138 | exports.getCode = getCode; 139 | function getAllLanguage() { 140 | return Object.keys(langs); 141 | } 142 | exports.getAllLanguage = getAllLanguage; 143 | function getAllCode() { 144 | return Object.keys(langs).map(function (item) { return (langs[item]); }); 145 | } 146 | exports.getAllCode = getAllCode; 147 | exports.default = langs; 148 | --------------------------------------------------------------------------------