'Select2 with Google Website Translator Plugin - Maximum call stack size exceeded

I have included the google website translator on my site using the following steps shown in the site below:

https://translate.google.com/manager/website/

If you're not familiar with the above link, it helps you create your html and javascript placement for a dropdown to appear. I'm trying to add customizations to the html and javascript (described below).

To keep with the theme of the site I'm building, I'm trying to change the dropdown to use the select2 plugin.

$(window).load(function () {
    setTimeout(function () {

        $('.goog-te-combo').select2()
            .on('change', function (e) {
                //console.log($('.goog-te-combo').val());
                var event;

                event = document.createEvent('HTMLEvents');
                event.initEvent('change', true, true);
                document.getElementsByClassName('goog-te-combo')[0].dispatchEvent(event);
            });
    }, 1000);
});

<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>

The code above works, I was able to get the site to use select2, including autocomplete.

The problem is, I get maximum call size exceeded, and it's because I'm creating a recursive dispatch change event over and over again. In other words, in my select2 on change method, I'm dispatching another change event to the same element that trigger, making the loop occur. I'm curious to know if there's anyway to get around this, or if there's any other work around to getting this to work without any errors.



Solution 1:[1]

After a few hours, I decided to hide the google website translator, and create a new dropdown select2 option, and when I change the value of this dropdown I change the value of the hidden google drop down.

so I hid this:

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

and created a new select option:

<select id="newGoogleTrans">
    <option disabled value="0">Select one</option>
    <option value="ar">Arabic</option>
    <option value="en">English</option>
    <option value="fr">French</option>
</select>

And this is how I controlled the dropdown:

$('#newGoogleTrans')
    .select2()
    .on('change', function () {
        value =  $('#newGoogleTrans').val();
        $('.goog-te-combo').val(value );
        document.getElementsByClassName('goog-te-combo')[0].dispatchEvent(event);
     })

EDIT:

I also realized that the dropdown needs to be updated to reflect if you selected the dropdown before, because the browser saves the state of the previously selected google translate dropdown in the form of a cookie, so in order to update the select2 dropdown face:

var nameEQ = "googtrans=";
var cookieVal = "";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
    var c = ca[i];
    while (c.charAt(0) == ' ')
        c = c.substring(1, c.length);
    if (c.indexOf(nameEQ) == 0)
        cookieVal = c.substring(nameEQ.length, c.length).split("/")[2];
}
cookieVal = cookieVal == "" ? 'en' : cookieVal;
$('#newGoogleTrans').val(cookieVal );

Solution 2:[2]

I had the same problem with the mobile version of my site when adding the gtranslte select dropdown to the mobile menu.

For me the only way for solving the problem was use the manual method for inserting the translation menu instead of the automated way.

Insert into your footer.php the Javascripts:

<script>
function GTranslateGetCurrentLang() {var keyValue = document['cookie'].match('(^|;) ?googtrans=([^;]*)(;|$)');return keyValue ? keyValue[2].split('/')[2] : null;}
function GTranslateFireEvent(element,event){try{if(document.createEventObject){var evt=document.createEventObject();element.fireEvent('on'+event,evt)}else{var evt=document.createEvent('HTMLEvents');evt.initEvent(event,true,true);element.dispatchEvent(evt)}}catch(e){}}
function doGTranslate(lang_pair){if(lang_pair.value)lang_pair=lang_pair.value;if(lang_pair=='')return;var lang=lang_pair.split('|')[1];if(GTranslateGetCurrentLang() == null && lang == lang_pair.split('|')[0])return;var teCombo;var sel=document.getElementsByTagName('select');for(var i=0;i<sel.length;i++)if(sel[i].className.indexOf('goog-te-combo')!=-1){teCombo=sel[i];break;}if(document.getElementById('google_translate_element2')==null||document.getElementById('google_translate_element2').innerHTML.length==0||teCombo.length==0||teCombo.innerHTML.length==0){setTimeout(function(){doGTranslate(lang_pair)},500)}else{teCombo.value=lang;GTranslateFireEvent(teCombo,'change');GTranslateFireEvent(teCombo,'change')}}
</script>

And create a new function into your functions.php file for adding the new element to your menu:

// Filter wp_nav_menu() to add additional links and other output
function new_nav_menu_items($items) {
    $homelink = '<!-- GTranslate: https://gtranslate.io/ -->
 <select onchange="doGTranslate(this);" class="notranslate" id="gtranslate_selector" aria-label="Website Language Selector"><option value="">Select Language</option><option value="es|da">Dansk</option><option value="es|nl">Nederlands</option><option value="es|en">English</option><option value="es|fr">Français</option><option value="es|de">Deutsch</option><option value="es|it">Italiano</option><option value="es|es">Español</option><option value="es|sv">Svenska</option></select><style>
#goog-gt-tt {display:none !important;}
.goog-te-banner-frame {display:none !important;}
.goog-te-menu-value:hover {text-decoration:none !important;}
.goog-text-highlight {background-color:transparent !important;box-shadow:none !important;}
body {top:0 !important;}
#google_translate_element2 {display:none!important;}
</style>

<div id="google_translate_element2"></div>';
    // add the home link to the end of the menu
    $items = $items . $homelink;
    return $items;
}
add_filter( 'wp_nav_menu_items', 'new_nav_menu_items' );

Best.

Solution 3:[3]

I removed this code on my html>head and it went fine, I guess this init function is recursive to itself when it creates the object.

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Nat