3

i am currently working on a simple like implementation in nuxt. when i change the language with 1i8n, i want to change the facebook sdk language accordingly, so the button renders in the given language code when i change the overall app language. my code looks like this:

import config from '@/config'

export default {
    data() {
        return {
            FB_APP_ID: config.appname.FB_APP_ID
        }
    },
    mounted() {
        var langua;

        if (this.$i18n.locale == 'en') {
            langua = "en_US";
        }

        if (this.$i18n.locale == 'de') {
            langua = "de_DE";
        }

        window.fbAsyncInit = () => {
            FB.init({
                appId: this.FB_APP_ID,
                cookie: true,
                xfbml: true,
                version: 'v2.8'
            })
        }

        (function(d, s, id){
            var js, fjs = d.getElementsByTagName(s)[0];
            if (d.getElementById(id)) {return;}
            js = d.createElement(s); js.id = id;
            js.src = "//connect.facebook.net/" + langua + "/sdk.js";
            fjs.parentNode.insertBefore(js, fjs);
        }(document, 'script', 'facebook-jssdk'));
    }
}

it works but the dynamic change is not happening, do i miss something like async on the button sdk here ??? no idea, i am new to vue, help is appreciated thanks a lot.

  • 1
    What dynamic change are you talking about? You mean you initialize the SDK in language X, and then switch to Y in your app? That won’t work, the SDK can only be embedded and initialized once. – misorude Aug 09 '19 at 06:27
  • yeah yes exactly.. how can i change the language code (en_US) by changing the overall language dynamically, do i need to use an async function to access the asnyc sdk ? no idea... –  Aug 09 '19 at 17:42

2 Answers2

2

That won’t work, the SDK can only be embedded and initialized once.

This is not entirely true: there is a workaround.

If you add a new script to the head, it will be executed once loaded. This is true for any script. If it doesn't, it means the script has a guard that prevents running the same code again most likely by checking if one of its variables is already defined.

In the case of Facebook SDK, it will check if FB is already defined globally so you simply need to delete it before adding your new sdk script with a different locale.

My code looks a bit different, but I'm also using Nuxt:

<template>
  <div
    :key="`fb-chat-${$i18n.locale}`"
    class="fb-customerchat"
    :page_id="pageId"
    theme_color="#4586ff"
    greeting_dialog_display="hide"
    :logged_in_greeting="$t('greeting')"
    :logged_out_greeting="$t('greeting')"
  ></div>
</template>

<script>
export default {
  name: 'FacebookChat',

  data() {
    return {
      pageId: process.env.FACEBOOK_PAGE_ID,
    }
  },

  watch: {
    '$i18n.locale': 'resetFacebookSdk',
  },

  mounted() {
    this.initFacebookSdk()
  },

  methods: {
    initFacebookSdk() {
      if (!process.browser) return

      const locale = this.$i18n.locale === 'de' ? 'de_DE' : 'en_US'
      delete window.FB // needs to be undefined when inserting a second script with different locale

      window.fbAsyncInit = function () {
        window.FB.init({
          appId: process.env.FACEBOOK_APP_ID,
          autoLogAppEvents: true,
          xfbml: true,
          version: 'v10.0',
        })
      }
      ;(function (d, s, id) {
        let js = d.getElementById(id),
          fjs = d.getElementsByTagName(s)[0]
        if (js) js.parentNode.removeChild(js) // remove script tag if exists
        js = d.createElement(s)
        js.id = id
        js.src = `https://connect.facebook.net/${locale}/sdk/xfbml.customerchat.js`
        fjs.parentNode.insertBefore(js, fjs)
      })(document, 'script', `facebook-jssdk-${this.$i18n.locale}`)
    },

    resetFacebookSdk() {
      const fbRoot = this.$el.closest('#fb-root')
      if (!fbRoot) return

      // Move fb-customerchat element outside of fb-root (created by Facebook SDK)
      fbRoot.parentNode.insertBefore(this.$el, fbRoot)
      // Delete fb-root to let Facebook SDK create it again
      fbRoot.parentNode.removeChild(fbRoot)

      this.initFacebookSdk()
    },
  },
}
</script>

What you should pay attention to:


  • The locale is part of the key attribute of my element to make it re-render on locale change in order to remove what the sdk has added (attributes, child elements)
  • There is a watcher to call resetFacebookSdk on locale change
  • I modified the sdk code snippet to remove the script tag if it was already present instead of doing nothing. This way, we can create it again.
  • The element .fb-customerchat is cleaned up with the key attribute, but the sdk has wrapped it with a new element #fb-root. The method resetFacebookSdk is taking care of moving .fb-customerchat outside of that wrapper and deleting it.

You can see it in action on our website (you can switch language in the footer).

Hope it helps. Let me know if something is not clear.

pmrotule
  • 9,065
  • 4
  • 50
  • 58
0

I solved it by using this.$router.go(0); on the button click of the language switch, i had hoped to use another way, but still could'nt find one, anyway, now the language changes when the page reloads and the sdk's lang code as well, if else uses the appropriate language. Maybe i ll find a more elegant solution someday