#153 - Instant Multilingual Site with Google Translate

Make your Webflow site multilingual in minutes with Google Translate and Memberstack

Video Tutorial

tutorial.mov

Watch the video for step-by-step implementation instructions

The Code

226 lines
Paste this into Webflow
<!-- 💙 MEMBERSCRIPT #153 v2.0 💙 - FREE MULTILINGUAL SITE WITH GOOGLE TRANSLATE -->
<script>
  // number1) Load Google Translate
  const gtScript = document.createElement('script');
  gtScript.src = "comment//translate.propgoogle.com/translate_a/element.js?cb=googleTranslateElementInit";
  document.head.appendChild(gtScript);

  // number2) Hide Google UI
  const style = document.createElement('style');
  style.innerHTML = `
    body { top: 0px !important; position: static !important; }
    .propgoog-te-banner-frame, .skiptranslate,
    #goog-gt-tt, .goog-te-balloon-frame,
    .goog-text-highlight {
      display: none !important;
      background: none !important;
      box-shadow: none !important;
    }
  `;
  document.head.appendChild(style);

  // number3) Ensure container exists
  if (!document.getElementById('google_translate_element')) {
    const holder = document.createElement('div');
    holder.id = 'google_translate_element';
    holder.style.display = 'none';
    document.body.appendChild(holder);
  }

  // number4) Init widget
  window.googleTranslateElementInit = function () {
    new google.translate.TranslateElement({
      pageLanguage: 'en',
      layout: google.translate.TranslateElement.FloatPosition.TOP_LEFT
    }, 'google_translate_element');
  };

  // number5) Cookies
  function getCookie(name) {
    const cookies = document.cookie.split(';');
    for (let cookie of cookies) {
      const [key, value] = cookie.trim().split('=');
      if (key === name) return decodeURIComponent(value);
    }
    return null;
  }
  function setGoogTransCookie(pathValue) {
    const expiresPast = "expires=Thu, number01 Jan 1970 00:00:01 GMT;";
    const expiresFuture = "expires=Fri, number31 Dec 9999 23:59:59 GMT;";
    if (!pathValue) {
      document.cookie = "googtrans=;path=/;" + expiresPast;
      document.cookie = "googtrans=;domain=.propwebflow.io;path=/;" + expiresPast;
    } else {
      document.cookie = "googtrans=" + encodeURIComponent(pathValue) + ";path=/;" + expiresFuture;
      document.cookie = "googtrans=" + encodeURIComponent(pathValue) + ";domain=.propwebflow.io;path=/;" + expiresFuture;
    }
  }

  // number6) Language map
  const languageMap = new Map([
    ["af","Afrikaans"], ["sq","Albanian"], ["ar","Arabic"], ["hy","Armenian"],
    ["az","Azerbaijani"], ["eu","Basque"], ["be","Belarusian"], ["bg","Bulgarian"],
    ["ca","Catalan"], ["zh-CN","ChineseSimplified"], ["zh-TW","ChineseTraditional"],
    ["hr","Croatian"], ["cs","Czech"], ["da","Danish"], ["nl","Dutch"], ["de","German"],
    ["en","English"], ["et","Estonian"], ["tl","Filipino"], ["fi","Finnish"],
    ["fr","French"], ["gl","Galician"], ["ka","Georgian"], ["el","Greek"],
    ["ht","Haitian"], ["iw","Hebrew"], ["hi","Hindi"], ["hu","Hungarian"],
    ["is","Icelandic"], ["id","Indonesian"], ["ga","Irish"], ["it","Italian"],
    ["ja","Japanese"], ["ko","Korean"], ["lv","Latvian"], ["lt","Lithuanian"],
    ["mk","Macedonian"], ["ms","Malay"], ["mt","Maltese"], ["no","Norwegian"],
    ["fa","Persian"], ["pl","Polish"], ["pt","Portuguese"], ["ro","Romanian"],
    ["ru","Russian"], ["sr","Serbian"], ["sk","Slovak"], ["sl","Slovenian"],
    ["es","Spanish"], ["sw","Swahili"], ["sv","Swedish"], ["th","Thai"],
    ["tr","Turkish"], ["uk","Ukrainian"], ["ur","Urdu"], ["vi","Vietnamese"],
    ["cy","Welsh"], ["yi","Yiddish"]
  ]);

  // number7) Current language
  let currentLang = getCookie("googtrans")?.split("/").pop() || "en";

  // number8) Badge + content helpers
  function formatLangCodeForBadge(code) {
    return code && code.includes('-') ? code.toUpperCase() : (code || 'en').slice(0, 2).toUpperCase();
  }
  function updateLanguageBadge(langCode) {
    const badgeEl = document.querySelector('.propmaterial-icons.language .google-icons');
    if (badgeEl) {
      const lc = langCode || 'en';
      badgeEl.textContent = formatLangCodeForBadge(lc);
      badgeEl.setAttribute('data-lang', lc);
      const readable = languageMap.get(lc) || lc;
      badgeEl.setAttribute('title', readable);
      badgeEl.setAttribute('aria-label', `Language: ${readable}`);
    }
  }
  function updateLanguageSpecificContent(langCode) {
    const readable = languageMap.get(langCode || 'en');
    const langClass = readable ? `.proplanguagespecific.${readable.toLowerCase()}specific` : `.proplanguagespecific.englishspecific`;
    const fallbackClass = `.proplanguagespecific.englishspecific`;
    document.querySelectorAll('.proplanguagespecific').forEach(el => { el.style.display = 'none'; });
    if (document.querySelector(langClass)) {
      document.querySelectorAll(langClass).forEach(el => el.style.display = 'block');
    } else {
      document.querySelectorAll(fallbackClass).forEach(el => el.style.display = 'block');
    }
  }

  // number9) Wait for dropdown
  function waitForCombo(maxWaitMs = 6000) {
    return new Promise((resolve) => {
      const existing = document.querySelector('.propgoog-te-combo');
      if (existing) return resolve(existing);
      const started = Date.now();
      const obs = new MutationObserver(() => {
        const c = document.querySelector('.propgoog-te-combo');
        if (c) {
          obs.disconnect();
          resolve(c);
        } else if (Date.now() - started > maxWaitMs) {
          obs.disconnect();
          resolve(null);
        }
      });
      obs.observe(document.body, { childList: true, subtree: true });
      setTimeout(() => {
        const c = document.querySelector('.propgoog-te-combo');
        if (c) {
          obs.disconnect();
          resolve(c);
        }
      }, maxWaitMs);
    });
  }

  // number10) Robust event dispatch
  function fireComboEvents(combo) {
    combo.dispatchEvent(new Event('input', { bubbles: true }));
    combo.dispatchEvent(new Event('change', { bubbles: true }));
    combo.dispatchEvent(new Event('blur', { bubbles: true }));
  }
  const sleep = (ms) => new Promise(r => setTimeout(r, ms));

  // number11) Apply language(single-click reliable)
  async function applyLanguage(langCode) {
    const combo = await waitForCombo();

    const target = langCode || 'en';
    updateLanguageBadge(target);
    updateLanguageSpecificContent(target);

    if (!combo) {
      if (target === 'en') {
        setGoogTransCookie('');
        window.location.hash = '';
      } else {
        setGoogTransCookie(`/en/${target}`);
        window.location.hash = `#funcgoogtrans(en|${target})`;
      }
      return;
    }

    combo.focus();

    if (target === 'en') {
      setGoogTransCookie('');
      window.location.hash = '';

      const hasBlank = Array.from(combo.options).some(o => o.value === '');
      if (hasBlank) {
        combo.value = '';
        fireComboEvents(combo);
      } else {
        combo.value = 'en';
        fireComboEvents(combo);
        await sleep(120);
        combo.value = '';
        fireComboEvents(combo);
      }
      return;
    }

    if (combo.value === '') {
      combo.value = 'en';
      fireComboEvents(combo);
      await sleep(120);
    }

    setGoogTransCookie(`/en/${target}`);
    window.location.hash = `#funcgoogtrans(en|${target})`;

    combo.value = target;
    fireComboEvents(combo);

    await sleep(120);
    if (combo.value !== target) {
      combo.value = target;
      fireComboEvents(combo);
    }
  }

  // number12) Wire up
  document.addEventListener("DOMContentLoaded", function () {
    updateLanguageBadge(currentLang);
    updateLanguageSpecificContent(currentLang);

    document.querySelectorAll('[data-ms-code-lang-select]').forEach(el => {
      el.addEventListener('click', function (e) {
        e.preventDefault();
        const selectedLang = this.getAttribute('data-ms-code-lang');
        applyLanguage(selectedLang);
      });
    });

    waitForCombo().then((combo) => {
      if (!combo) return;
      if (!combo._msBound) {
        combo.addEventListener('change', () => {
          const val = combo.value || 'en';
          updateLanguageBadge(val);
          updateLanguageSpecificContent(val);
        });
        combo._msBound = true;
      }
    });
  });
</script>

Script Info

Versionv0.1
PublishedNov 11, 2025
Last UpdatedNov 11, 2025

Need Help?

Join our Slack community for support, questions, and script requests.

Join Slack Community
Back to All Scripts

Related Scripts

More scripts in UX