Search code examples
javascriptvue.jsinternationalizationvue-i18n

Vue.js + i18n load external JSON's from server and make it globally accessible in every component


I'm currently trying to figure out a way to load translation files from a server and make them accessible in every component of the project.

For example i can call https://server.com/lang=de and get that JSON

{
    "DASHBOARD_SETTINGS": "Einstellungen",
    "DASHBOARD_CUSTOMERS": "Kunden",
    "DASHBOARD_CAMPAIGNS": "Kampagnen",
    "DASHBOARD_LOCATIONS": "Standorte",
    "DASHBOARD_DISPLAYS": "Displays"
}

This is my file structure

  • router.js
  • i18n_setup.js
  • app.js
  • components
    • Dashboard.vue

i18n_setup.js

import Vue from 'vue'
import VueI18n from 'vue-i18n'

Vue.use(VueI18n)

export const i18n = new VueI18n({
    locale: 'de',
    fallbackLocale: 'en'
})

const loadedLanguages = ['de']

function setI18nLanguage (lang) {
    i18n.locale = lang
    axios.defaults.headers.common['Accept-Language'] = lang
    document.querySelector('html').setAttribute('lang', lang)
    return lang
}

export function loadLanguageAsync (lang) {
    if (typeof lang === 'undefined') {
        lang = window.navigator.userLanguage || window.navigator.language;
        lang = lang.slice(0,2);
    }
    if (loadedLanguages.includes(lang)) {
        if (i18n.locale !== lang) setI18nLanguage(lang)
        return Promise.resolve()
    }
    return fetch(`https://EXAMPLE.de/locales?lang=${lang}`)
        .then(response => {
            let msgs = response.data
            loadedLanguages.push(lang)
            i18n.setLocaleMessage(lang, msgs)
            return setI18nLanguage(lang)
        });
}

router.js

...
router.beforeEach((to, from, next) => {
    const lang = to.params.lang
    loadLanguageAsync(lang).then(() => next())
})

app.js

...
// i18n
import { i18n } from './i18n_setup'
...
const app = new Vue({
    store,
    i18n,
    el: '#app',
    components: {
        App
    },
    router
});

Dashboard.vue

import { loadLanguageAsync } from '../i18n_setup'

I can see that the translations are loaded via the network tab of the browser, but when i try to access a translation with for example {{ $t('DASHBOARD_SETTINGS') }} i get the warning / error

[vue-i18n] Cannot translate the value of keypath 'DASHBOARD_SETTINGS'. Use the value of keypath as default.

Any ideas what i'm missing?


Solution

  • fetch returns an object of type Response. You are accessing response.data which does not exist on that object (let msgs = response.data)

    To extract the data from the response, use response.json()

    return fetch(`https://EXAMPLE.de/locales?lang=${lang}`)
      .then(response => response.json())
      .then(msgs => {
         loadedLanguages.push(lang)
         i18n.setLocaleMessage(lang, msgs)
         return setI18nLanguage(lang)
       });