Search code examples
javascriptlaravelvue.jsvuejs2translation

Vue i18n translation for single file components


I'm using laravel and currently trying to do multilanguage pages, So i've found this pretty neat plugin called VueI18N for translations and got it working (somehow) by installing it via npm and then putting the following code in my app.js

//app.js
window.Vue = require('vue');

import VueI18n from 'vue-i18n'
Vue.use(VueI18n)

//tons of more components here
Vue.component('vue-test', require('./components/VueTestFileForLocalization.vue').default);

const messages = {
    en: {
        message: {
            hello: 'Hello, {name}!'
        }
    },
    de: {
        message: {
            hello: 'Guten Tag, {name}!'
        }
    }
};

const i18n = new VueI18n({
    locale: 'de',
    messages
});


  
const app = new Vue({
    el: '#vue-app',
    i18n
});

Then in my vue-test i tried outputting this successfully:

 <template>
   <div>{{ $t('message.hello', { name: 'John' }) }}</div>
 </template>
 <script>
 export default {
   data() {
     return {};
   },
   created() {
     this.$i18n.locale = 'en';
   }
 };
 </script>

and by changing the locale i can also display the other language. Great. Now I think with so many components, I might have a problem defining all the localization inside app.js , and its not beautiful either. So I tried looking up This link here to the docs for single file components but unsuccessfully, unfortunately. I copy-pasted the code, (vue-i18n-loader should also be installed by laravel by default) and modified the webpack file. The error I get seems pretty common after research but I cannot seem to fix it.

Value of key 'hello' is not a string!
Cannot translate the value of keypath 'hello'. Use the value of keypath as default

It does simply output whatever the key is i specify in message.

Does any of you out there have an idea, what I might have done wrong or forgot to setup? Any hints would be appreciated very very much. Thank you for your time Best regards, Desory


Solution

  • While not a direct answer to your question I recently found another approach to the same problem that is less effort when it comes to maintaining translations.

    I put all my translations in JSON files so I can share the same translations between Laravel backend and Vue front end.

    I did this based on this: https://www.codeandweb.com/babeledit/tutorials/how-to-translate-your-vue-app-with-vue-i18n

    So as per: https://laravel.com/docs/7.x/localization#using-translation-strings-as-keys

    Create resources/lang/en.json etc. with contents:

    {
    "my_message": "This is my message in english",
    ...
    }
    

    I'd create resources/js/i18n.js containing:

    import Vue from "vue";
    import VueI18n from "vue-i18n";
    Vue.use(VueI18n);
    
    function loadLocaleMessages() {
        const locales = require.context(
            "../lang",
            true,
            /[A-Za-z0-9-_,\s]+\.json$/i
        );
        const messages = {};
        locales.keys().forEach(key => {
            const matched = key.match(/([A-Za-z0-9-_]+)\./i);
            if (matched && matched.length > 1) {
                const locale = matched[1];
                messages[locale] = locales(key);
            }
        });
        return messages;
    }
    
    export default new VueI18n({
        locale: process.env.VUE_APP_I18N_LOCALE || "en",
        fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || "en",
        messages: loadLocaleMessages()
    });
    

    and in app.js import that as follows:

    //Localise
    import i18n from "./i18n";
    Vue.use(i18n);
    
    /**
     * Next, we will create a fresh Vue application instance and attach it to
     * the page. Then, you may begin adding components to this application
     * or customize the JavaScript scaffolding to fit your unique needs.
     */
    const app = new Vue({
        i18n,
        el: "#app"
    });
    

    You can then use the same translations in your blade templates with the __ helper and in Vue with $t(...)