Search code examples
javascriptvue.jsvue-i18n

How to use VueI18n for component instance based internationalization?


I'm building Vue app without using npm. As there are too many guides referring to npm, I can not follow them correctly. So, I just included scripts like this:

    <script src="/js/bluebird.min.js"></script>
    <script src="/js/vue.js"></script>
    <script src="/js/vue-i18n.js"></script>
    <script src="/js/axios.min.js"></script>
    <script src="/js/components.js"></script>
    <script src="/js/app.js"></script>

For now I'm trying to show buttons list, by loading them from json file. That file contains array of object with info about button, including it's text on different languages. So, for now I cannot understand how to make vue-i18n load messages from that file. Basic code:

            <buttons-list inline-template>
                <div class="buttons-list">
                    <big-button inline-template
                        :class="[button.position, button.number]"
                        v-for="button in buttons"
                        :key="button.id"
                        :button="button">
                        <div class="big-button">{{ $t(button.text) }}</div>
                    </big-button>
                </div>
            </buttons-list>

buttonsList component code:

Vue.component('buttons-list', {
    data: function() {
        return {
            buttons: []
        }
    },
    created: function() {
        this.loadButtons()
    },
    methods: {
        loadButtons: function() {
            const list = this;
            axios.get('/json/buttons.json')
            .then(function(response) {
                list.buttons = response.data
            })
        }
    }
})

Here I read json file when component created, so when bigButton created, button property will have all required info. bigButton component code:

Vue.component('big-button', {
    data: function() {
        return {
            text: ''
        }
    },
    props: ['button'],
    created: function() {            
        this.$i18n.setLocaleMessage('en', this.button.messages.en)
        this.$i18n.setLocaleMessage('ru', this.button.messages.ru)
    },
    i18n: {
        messages: {}
    }
})

Here, in created function I tried to set instance's i18n.messages to data from json file. Basically, this works, except it resets messages for all buttons to current data, ending up in all buttons having same, last button's text. Is it possible to work with component instances in vue-i18n? Or is there other ways I'm missing?


SOLUTION

I've changed my bigButton component code to:

Vue.component('big-button', {
    data: function() {
        return {
            text: ''
        }
    },
    props: {
        button: {
            type: Object,
            default: function() {return {}}
        },
    },
    created: function() {
        this.$i18n.setLocaleMessage('en', this.button.messages.en)
        this.$i18n.setLocaleMessage('ru', this.button.messages.ru)
    },
    i18n: {
        //i18n stops working when this block removed
    }
})

and it worked!


Solution

  • VueI18n supports per-component localization - it is explained in the official documentation Just define i18nobject with messages inside your component - documentation shows exactly how to do it:

    // setup locale info for root Vue instance
    const i18n = new VueI18n({
      locale: 'ja',
      messages: {
        en: {
          message: {
            hello: 'hello world',
            greeting: 'good morning'
          }
        },
        ja: {
          message: {
            hello: 'こんにちは、世界',
            greeting: 'おはようございます'
          }
        }
      }
    })
    
    // Define component
    const Component1 = {
      template: `
        <div class="container">
         <p>Component1 locale messages: {{ $t("message.hello") }}</p>
         <p>Fallback global locale messages: {{ $t("message.greeting") }}</p>
       </div>`,
      i18n: { // `i18n` option, setup locale info for component
        messages: {
          en: { message: { hello: 'hello component1' } },
          ja: { message: { hello: 'こんにちは、component1' } }
        }
      }
    }
    
    // template
    <div id="app">
      <p>{{ $t("message.hello") }}</p>
      <component1></component1>
    </div>
    

    UPDATE

    How to initialize a component with unique localization strings:

    const Component1 = {
      template: `
        <div class="container">
         <p>Component1 locale messages: {{ $t("message.hello") }}</p>
         <p>Fallback global locale messages: {{ $t("message.greeting") }}</p>
       </div>`,
      i18n: { // `i18n` option, setup locale info for component
        messages: uniqueLocalization
      },
      props:
      {
        uniqueLocalization:
        {
          type: Object,
          default: () => ({})
        }
      }
    }
    
    <template>
      <div>
        <comp :unique-localization="locale_1"/>
        <comp :unique-localization="locale_2"/>
        <comp :unique-localization="locale_3"/>    
      </div>
    </template>
    
    <script>
    import component1 from '@/components/component1.vue'
    
    export default
    {
      components:
      {
        comp: component1
      },
      data()
      {
        return {
          locale_1:
          {
            en:
            {
              message:
              {
                hello: 'Greetings',
                bye: 'Farewell'
              }
            },
            ru:
            {
              message:
              {
                hello: 'Привет',
                bye: 'До свидания'
              }
            }
          },
          locale_3:
          {
            en:
            {
              message:
              {
                hello: 'Greetings, buddy',
                bye: 'Farewell, dude'
              }
            },
            ru:
            {
              message:
              {
                hello: 'Привет, ребята',
                bye: 'До свидания, мужики'
              }
            }
          },
          locale_3:
          {
            en:
            {
              message:
              {
                hello: 'Godd day, team',
                bye: 'Bye-bye, darling'
              }
            },
            ru:
            {
              message:
              {
                hello: 'Здравствуйте, братушки',
                bye: 'Пока'
              }
            }
          }
        };
      }
    }
    </script>