py-googletrans: Found a Google Translate endpoint that doesn't require an API key.

This isn’t a bug report, just a sharing of some findings while looking through minified source code.

While digging through the source code of Google’s Google Dictionary Chrome extension, which has support for translating via Google Translate, I found the endpoint they use in order to do just that. Since googletrans frequently runs into 5xx errors, it might be useful to switch off to another endpoint, although this one is also annoyingly touchy with 403s.

Breakdown

Endpoint: https://clients5.google.com/translate_a/t

Query Parameters

Query Parameter Default Notes
client dict-chrome-ex Needs to be dict-chrome-ex or else you’ll get a 403 error.
sl auto Designates the source language of the text to translate.
tl (none) Designates the destination language of the text to translate.
q (none) Text to translate

Example Response

URL: https://clients5.google.com/translate_a/t?client=dict-chrome-ex&sl=auto&tl=en&q=bonjour

{
  "sentences": [
    {
      "trans": "Hello",
      "orig": "bonjour",
      "backend": 1
    }
  ],
  "dict": [
    {
      "pos": "interjection",
      "terms": [
        "Hello!",
        "Hi!",
        "Good morning!",
        "Good afternoon!",
        "How do you do?",
        "Hallo!",
        "Hullo!",
        "Welcome!"
      ],
      "entry": [
        {
          "word": "Hello!",
          "reverse_translation": [
            "Bonjour!",
            "Salut!",
            "Tiens!",
            "Allô!"
          ],
          "score": 0.7316156
        },
        {
          "word": "Hi!",
          "reverse_translation": [
            "Salut!",
            "Bonjour!",
            "Hé!"
          ],
          "score": 0.084690653
        },
        {
          "word": "Good morning!",
          "reverse_translation": [
            "Bonjour!"
          ],
          "score": 0.065957151
        },
        {
          "word": "Good afternoon!",
          "reverse_translation": [
            "Bonjour!"
          ],
          "score": 0.02749503
        },
        {
          "word": "How do you do?",
          "reverse_translation": [
            "Bonjour!",
            "Salut!",
            "Ça marche?"
          ]
        },
        {
          "word": "Hallo!",
          "reverse_translation": [
            "Bonjour!",
            "Tiens!",
            "Salut!",
            "Allô!"
          ]
        },
        {
          "word": "Hullo!",
          "reverse_translation": [
            "Tiens!",
            "Allô!",
            "Salut!",
            "Bonjour!"
          ]
        },
        {
          "word": "Welcome!",
          "reverse_translation": [
            "Salut!",
            "Bonjour!",
            "Soyez le bienvenu!"
          ]
        }
      ],
      "base_form": "Bonjour!",
      "pos_enum": 9
    }
  ],
  "src": "fr",
  "alternative_translations": [
    {
      "src_phrase": "bonjour",
      "alternative": [
        {
          "word_postproc": "Hello",
          "score": 1000,
          "has_preceding_space": true,
          "attach_to_next_token": false
        }
      ],
      "srcunicodeoffsets": [
        {
          "begin": 0,
          "end": 7
        }
      ],
      "raw_src_segment": "bonjour",
      "start_pos": 0,
      "end_pos": 0
    }
  ],
  "confidence": 0.96875,
  "ld_result": {
    "srclangs": [
      "fr"
    ],
    "srclangs_confidences": [
      0.96875
    ],
    "extended_srclangs": [
      "fr"
    ]
  },
  "query_inflections": [
    {
      "written_form": "bonjour",
      "features": {
        "gender": 1,
        "number": 2
      }
    },
    {
      "written_form": "bonjours",
      "features": {
        "gender": 1,
        "number": 1
      }
    },
    {
      "written_form": "bonjour",
      "features": {
        "number": 2
      }
    },
    {
      "written_form": "bonjours",
      "features": {
        "number": 1
      }
    }
  ]
}

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 62
  • Comments: 61 (1 by maintainers)

Commits related to this issue

Most upvoted comments

After some testing with the request headers, I found the solution for the garbled text. Simply set the User-Agent header to the one that Google Chrome uses.

Example:

import requests
word = 'لماذا تفعل هذا'
url = "https://clients5.google.com/translate_a/t?client=dict-chrome-ex&sl=auto&tl=en&q=" + word
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
}

try:
    request_result = requests.get(url, headers=headers).json()
    
    print(request_result)
    print('[In English]: ' + request_result['alternative_translations'][0]['alternative'][0]['word_postproc'])
    print('[Language Dectected]: ' + request_result['src'])
except:
     pass

Response:

{'sentences': [{'trans': 'Why are you doing this', 'orig': 'لماذا تفعل هذا', 'backend': 1}, {'src_translit': 'limadha tafeal hdha'}], 'src': 'ar', 'alternative_translations': [{'src_phrase': 'لماذا تفعل هذا', 'alternative': [{'word_postproc': 'Why are you doing this', 'score': 1000, 'has_preceding_space': True, 'attach_to_next_token': False}], 'srcunicodeoffsets': [{'begin': 0, 'end': 14}], 'raw_src_segment': 'لماذا تفعل هذا', 'start_pos': 0, 'end_pos': 0}], 'confidence': 1, 'ld_result': {'srclangs': ['ar'], 'srclangs_confidences': [1], 'extended_srclangs': ['ar']}}
[In English]: Why are you doing this
[Language Dectected]: ar

I found another endpoint within the source code of one of the google translate extensions on VSCode too.

"https://translate.googleapis.com/translate_a/single?client=gtx&dt=t + params"
// where the params are:
{
  "sl": source language,
  "tl": destination language,
  "q": the text to translate
}

The results looks something like this:

[[["こんにちは、今日はお元気ですか?","Hello, how are you today?",null,null,3,null,null,[[]
]
,[[["9588ca5d94759e1e85ee26c1b641b1e3","kgmt_en_ja_2020q3.md"]
]
]
]
]
,null,"en",null,null,null,null,[]
]

for the query: https://translate.googleapis.com/translate_a/single?client=gtx&dt=t&sl=en&tl=ja&q=Hello, how are you today?

And something like this:

[[["Bonjour","Hello",null,null,1]
]
,null,"en",null,null,null,null,[]
]

for the query: https://translate.googleapis.com/translate_a/single?client=gtx&dt=t&sl=en&tl=fr&q=Hello

When using it only to translate things, I would use it like so:

from json import loads
from requests import get
request_result = get("https://translate.googleapis.com/translate_a/single?client=gtx&dt=t&sl=en&tl=fr&q=Hello")
translated_text = loads(request_result.text)[0][0][0]
print(translated_text)

@NawtJ0sh

I just made a repository which groups all of the APIs if you want (called translate)

https://github.com/Animenosekai/translate

I made a comparison of all (known) Google Translate API endpoints based on my findings while making my translation library, this may be useful if you don’t know which API endpoint to use.

  • https://clients5.google.com/translate_a no longer seems to return faithful translations; only returns the translated text.
  • https://translate.googleapis.com/translate_a/single still returns faithful translations and some info about the translation (source language, translation confidence and transliteration if available).
  • https://translate.google.com/_/TranslateWebserverUi/data/batchexecute only returns a faithful translation with the X-Goog-BatchExecute-Bgr, the algorithm that creates this header doesn’t seem to be deciphered yet. This is the endpoint that returns the most info (source language, translation confidence, transliteration, alternative translations, definitions, examples, etc.).
  • https://translate.google.com/m returns a faithful translation, but no extra info. Returns HTML instead of JSON so parsing is required.

In conclusion, the second endpoint is currently the best free Google Translate API endpoint, unless someone manages to decipher the X-Goog-BatchExecute-Bgr header.

@Animenosekai Awesome, another endpoint to add. We should probably create a way to house all of these endpoints through one API, perhaps an interface that all of the endpoints implement?

Seems like a few hours ago @SuperSonicHub1’s Google Translate endpoint has started to return the more detailed response structure.

I’ve found this alternative endpoint for google: Free endpoint: https://translate.google.com/m?hl=en&sl=en&tl=pt&ie=UTF-8&prev=_m&q=Text The caveat? the response is an HTML page. It is easily parseable though and the translation is much better than the ones they are spitting through the simple json endpoints above

import requests

 """
l = language
s = sentence
"""

def trans1(l, s):
	return requests.get(f"https://translate.googleapis.com/translate_a/single?client=gtx&dt=t&sl=auto&tl={l}&q={s}").json()[0][0][0]

def trans2(l, s):
	return requests.get(f"https://clients5.google.com/translate_a/t?client=dict-chrome-ex&sl=auto&tl={l}&q={s}").json()["sentences"][0]["trans"]

The endpoint now returns a simpler response (translation and detected language).

Url: https://clients5.google.com/translate_a/t?client=dict-chrome-ex&sl=auto&tl=es&q=Hello World

Response:

[[[[["Hola Mundo"]],null,"en"]]]

Formatted response:

[
    [
        [
            [
                [
                    "Hola Mundo"
                ]
            ],
            null,
            "en"
        ]
    ]
]

Here is the yandex translate, I worked on last night its just like the bing.com one i posted.

import requests

url = 'https://translate.yandex.net/api/v1/tr.json/translate?id=1308a84a.6016deed.0c4881a2.74722d74657874-3-0&srv=tr-text&lang=en&reason=auto&format=text'

post_header = {}
post_header['Accept'] = '*/*'
post_header['Accept-Encoding'] = 'gzip, deflate'
post_header['Accept-Language'] = 'en-US,en;q=0.9'
post_header['Cache-Control'] = 'no-cache'
post_header['Connection'] = 'keep-alive'
post_header['Content-Type'] = 'application/x-www-form-urlencoded'
post_header['Host'] = 'translate.yandex.com'
post_header['Referer'] = 'https://translate.yandex.com/'
post_header['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'


data_payload = {'text': search_str, 'options': '4'}

resp = requests.get(url, headers=post_header, data=data_payload).json()

print(str(resp) + '\n')

I know this is an older thread but just wanted to warn people that https://translate.googleapis.com/translate_a/single has issues with punctuation and will just halt translations (like if it encounters an ‘!’).

https://clients5.google.com/translate_a/t works great though! Thank you @SuperSonicHub1 !

@lokinmodar The only caveat is that it’s the mobile version of Google Translate which tends to yield worse translations (based on previous observations, this might have changed and this page is slightly different than the normal Google Translate mobile page)

i noticed this is much more faithful to the translations I used to get with the https://clients5.google.com/translate_a/t?client=dict-chrome-ex&sl=en&tl=it&q=body endpoint before they screwed it up

Wow, seems like its changed back to how it was before…

Could do this…

try:
    return data[0][0][2], "".join(sentence for sentence in data[0][0][0][0])
except:
    return data['ld_result']["srclangs"][0], "".join(sentence["trans"] for sentence in data["sentences"])

Lmao that’s exactly what I did on Animenosekai/translate d5f0357 (flipped their position though)

Edit: the new version is up on PyPI, update the module with pip install --upgrade translatepy (might want to run it twice to force pip checking for the new version)

@d4n3436 It seems our little operation has been busted by Google. This heavily reminds me of their other obfuscated JSON responses, where arrays are used instead of objects, which makes it hell for us stragglers to trivially parse. Try making more translations in a variety of languages and then share the results with us, as the lengths of the inner arrays may vary.

Nice you fixed it!! Thank you.