Search code examples
vue.jsvue-i18nvue-ssr

Vue-i18n - Issue with dynamic localizations from http request


I m trying to load the localization from HTTP call as i want the languages to be dynamic and manageable, rather than shipping it with the application.

I did a work around using the SSR sample and some of my own implementation. But on the initial render the language does not loading. When changing the route client-side things are getting updated.

i18n.js

import Vue from 'vue'
import VueI18n from 'vue-i18n'
import en from './en.json'
import ar from './ar.json'
import axios from 'axios'

Vue.use(VueI18n)

const fallbackLocale = 'en'
let defaultLocale = 'ar'

export const i18n = new VueI18n({
  locale: defaultLocale, // set locale
  fallbackLocale: fallbackLocale,
  messages: {
    'en': en
  }
})

export function createI18n () {
  return i18n
}

Router - router.beforeEach

router.beforeEach((to, from, next) => {
    if (router.app.$store) {
        router.app.$store
          .dispatch('getI18nData')
          .then(function(){
            router.app.$i18n.setLocaleMessage('ar',router.app.$store.getters.getLocale)
            return next()
          })
          .catch(() => console.log('getI18nData-error'))
      } else {
        next()
      }
  })

Store Action - to fetch locale

getI18nData ({ commit }) {
   try {
     axios.get('http://localhost:8080/lang?lang=ar')
    .then(function (response) {
      let locale = response.data
      commit('setLocale', { locale })
    })
    .catch(function (error) {
      console.log('Error:getI18nData')
    })
   } catch (error) {
     console.error(error);
   }
 }

Findings: i18n is initializing before router.beforeEach where it should initialize after router.beforeEach.

Github Issue Link


Solution

  • Alright, to be a little bit more detailed: You don't want to mix try/catch with your promise-chain, but you need to return a promise from getI18nData or dispatch won't wait. So you either:

    getI18nData ({ commit }) {
        // axios.get() returns a promise already, so we can just return the whole thing:
        return axios
          .get('http://localhost:8080/lang?lang=ar')
          .then(function (response) {
            let locale = response.data
            commit('setLocale', { locale })
          })
          .catch(function (error) {
            console.log('Error:getI18nData')
          });
    }
    

    Or your use async/await (which does allow try/catch):

    async getI18nData ({ commit }) {
      try {
        let response = await axios.get('http://localhost:8080/lang?lang=ar');
        let locale = response.data
        commit('setLocale', { locale })
      } catch (error) {
        console.error(error);
      }
    }
    

    I'd like to add that I do like the async/await option better, but in vuex-land it usually leads to you having to make everything async/await (if you use nested dispatch calls). So depending on the rest of your code-base, it might be easier to just return the promise.