Search code examples
javascriptgatsbygoogle-translate

How to add a Google Translate Element to a GatsbyJS website


I am trying to add a google translate element to my Gatsby website. In essence, I am trying to get the following code to work in Gatsby:

<div id="google_translate_element"></div>

<script type="text/javascript">
function googleTranslateElementInit() {
  new google.translate.TranslateElement({pageLanguage: 'en'}, 'google_translate_element');
}
</script>

<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>

I am relatively new to Gatsby and would like to know the proper (or at least a working) way of achieving this.

What I have tried

  1. Calling the Javascript code on mount
const Footer = () => {

    useEffect(() => {
        const script = document.createElement("script")
        script.src = "//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"
        script.async = true
        document.body.appendChild(script)

        googleTranslateElementInit(() => {
            new google.translate.TranslateElement({pageLanguage: 'en'}, 'google_translate_element')
        })

        return () => {
            document.body.removeChild(script)
        }
    }, [])

    return <div id="google_translate_element"></div>
}

This did not work, due to googleTranslateElementInit and google being undefined.

  1. Moving the <script to the <Helmet> component
<Helmet>
    <script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
    <script type="text/javascript">
        {googleTranslateElementInit(() => {
             new google.translate.TranslateElement({pageLanguage: 'en'}, 'google_translate_element')
        })}
    </script>
</Helmet>

Which produced the same error as (1)

  1. Adding the Javascript to the beginning of the <body> tag of html.js
 <body {...props.bodyAttributes}>
     <script 
          dangerouslySetInnerHTML={{
            __html: `
            function googleTranslateElementInit() {
                new google.translate.TranslateElement({pageLanguage: 'en'}, 'google_translate_element');
            }
            `
          }}
    />
    <script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>

This worked the first time I loaded the website. After refreshing it, the button was gone. It only appeared the first time I loaded the page after starting the development server. I also tried to make a production build with same results.

I have been stuck with this for a long time and I would greatly appreciate any advice.


Solution

  • It looks like you are not using a React-based approach, so your translate script will always lack scope (it will load asynchronously or it will never load-on-demand). My suggestion is to use a react dependency, such as react-google-translate, in addition the clean will be much cleaner.

    Once you set your environment (environment variables and so on), you just need to:

    import React, { useState, useEffect } from 'react'
     
    import { useLazyTranslate } from 'react-google-translate'
     
    const Example = () => {
     
      const [text] = useState('test');
      const [language] = useState('zh-CN');
     
      const [translate, { data, loading }] = useLazyTranslate({
        language 
      })
     
      useEffect(() => {
        if (text) {
          translate(text, language);
        }
      }, [translate, text])
     
      render() {
        return (
          <div>{loading ? 'Loading...' : data}</div>
        )
      }
    }
    

    As you can see, there are some custom hooks exposed (useLazyTranslate) that allow you to use the translation on-demand, ensuring that the library is properly loaded.