Automated Translation in Javascript with Google Translate API

The main thing to know here is that Google's AI does not know how Google's API interface works. It will give you advice that works fine with GET requests but translating anything fancy requires POST, which Google's AI doesn't understand. That's what I spent most of my afternoon discovering.

The rest of my afternoon was spent figuring out how it actually works, though. There are two major steps: first, setting up access to the translation API, and second, actually coding the Javascript. The second step is the easier step.

Setting Up Access

Note that I have a Google account and therefore access to the Google console. You'll need to set this up with Google Cloud. There may be costs involved; I have a business account which I pay for but I assume this would still work with a personal account. If you need to pay money anywhere I'm sure Google will tell you.

1. Create a Project in Google Cloud

  • This should take you to your project page. Take note of your project ID.

2. Enable 'Cloud Translation' in your project

  • On your project page, click 'APIs and Services'
  • Search for "Cloud Translation" in the search bar and select the "Cloud Translation API" from the results.
  • Click the "Enable" button to enable the Cloud Translation API for your project

3. Create an apiKey in your project 

  • On your project page, click 'Credentials' in the left-hand menu
  • Click 'Create Credentials' (near the top of the page)
  • Select 'API keys' from the dropdown
  • Copy the key; you'll never see it on Google again

Coding the Javascript

The trick here is that you're using async functions with fetch requests. This forces Javascript to wait for a reply from the translation engine.

1.  The input form

  
  <input type="text" id="inputText" placeholder="Enter text to translate">
  <input type="text" id="inputProject" placeholder="P{roject ID}">
  <input type="text" id="inputAPI" placeholder="Enter API key">
  <button onclick="handleTranslation()">Translate</button> 
  <p id="detected-lang"></p>
  <p id="translated-text"></p>

This will give you an input form that looks like this:

2. Get the data from the form

The rest of the code will be in Javascript and placed in between the <script> and </script> tags. First, we get data from the form:

async function handleTranslation() {
    const inputText = document.getElementById('inputText').value;
    const apiKey = document.getElementById('inputAPI').value;
    const projectId = document.getElementById('inputProject').value;
    const translatedText = await processTranslation(inputText,apiKey,projectId);
    document.getElementById('translated-text').innerText = translatedText;
}

We get the three values from the form, pass them to a function processTranslation(), then display the result on the web page.

3. Process translation

We're going to proceed in two steps. First, we're going to detect what language the original text is in. Then, we'll translate it to English.

    async function processTranslation(inputText,apiKey,projectId) {
    try {
        const detectedLang = await detectLanguage(inputText,apiKey,projectId);
        
        if (detectedLang === 'en') {
            console.log('The text is already in English:', inputText);
            return inputText;
        }

        const translatedText = await translateToEnglish(inputText,apiKey,projectId,detectedLang);
        return translatedText;
    } catch (error) {
        console.error('Error during translation:', error);
    }
}

This function  performs the two processes with error checking. Notice that if the language detected is English, we won't actually perform the translation. 

4. Detect language

The Google language API has a 'detect languiage' function with its own URL. Here we'll access that function with fetch(), and return the result.

async function detectLanguage(inputText,apiKey,projectId) {
    const response = await fetch(
        `https://translation.googleapis.com/language/translate/v2/detect?key=${apiKey}`, 
        {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ q: inputText })
        }
    );

    const data = await response.json();
    const detectedLang = data?.data?.detections[0][0]?.language || 'unknown';
    console.log(`Detected Language: ${detectedLang}`);
    return detectedLang;
}

The Google API expects the apiKey in the URL being requested by fetch(), which is (to me, at least) a but unusual. Our input text is placed into JSON as the request body. The result is found deep inside the JSON returned by the API and placed in the variable detectedLang.

5. Translate the text

We use fetch() again, defining the API key just as previously, and include the new text and the source language in the request body.

async function translateToEnglish(inputText,apiKey,projectId,sourceLang) {
    const response = await fetch(
        `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`, 
        {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                q: inputText,
                source: sourceLang,
                target: 'en',
                format: 'text'
            })
        }
    );

    const data = await response.json();
    const translatedText = data?.data?.translations[0]?.translatedText || '';
    console.log('Translated Text:', translatedText);
    return translatedText;
}

The result is again found deep in the JSON returned by the API. I save it to the console log (so you can see it by inspecting the page) and also return it so it can be displayed on the web page.

That's our function!

Some Notes

As I mentioned, the data is returned in a JSON structure called 'data' from fetch(). We need to fish it out of that structure; that's what the long string data?.data?.translations[0]?.translatedText refers to.

Here's what the actual JSON might look like:

data: {
  "data": {
    "translations": [
      {
        "translatedText": "Hello, world!",
        "detectedSourceLanguage": "ja"
      }
    ]
  }
}

The question marks return 0 if there's no value for 'data', which would result in the functioning returning '' instead of failing with an error.

Also...

Thanks to Blogcrowds for the Parse HTML page that made it easy for me to add code in this post. 

And finally...

Here's the full page. You'll have to create your own project and API values. https://www.downes.ca/translate.html




Comments

Popular Posts