Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get translations inside the components method #52

Closed
kskrlin opened this issue Dec 12, 2017 · 11 comments
Closed

Get translations inside the components method #52

kskrlin opened this issue Dec 12, 2017 · 11 comments
Labels

Comments

@kskrlin
Copy link

kskrlin commented Dec 12, 2017

I am trying to use translations object inside the methods. I lost more than 1 hour with this and finally came with this solution, but it is really intuitive to me. Is there any shorter way, because I can't find it in documentation.

export default {
    data () {
        return {
            trans: this.$store.state.i18n.translations[this.$store.state.i18n.locale],
            ...
        }
    },
    methods: {
        ...
        setTitle (index, item) {
            console.log('--- TITLE ---');
            console.log(this.trans['services.' + index + '.items.' + item + '.title']);
            return this.trans['services.' + index + '.items.' + item + '.title'];
        }
        ...
    }
}
@tikiatua
Copy link
Member

Hi @kikky7,

You should be able to simply use this.$t('key') to access the translations in methods. However please be aware, that the method result will not update if the locale or translation is changed. For this to work, you must use computed properties.

@daveo1001
Copy link

@tikiatua
I'm using another package to set the page header. I'm trying to use your i18n package for the translation.

I get this.$t is not a function, which makes sense, I guess, but I'm not sure how to correct it.

export default {
  metaInfo: {
    title: this.$t('login')
  }
}

I also tried sticking it in created () but in that instance this is dealing with data, not the component.

@tikiatua
Copy link
Member

Hi @daveo1001,

It is a little tricky to follow your code logic, given only the snippets above. However, this is usually related to the current component and is only available if the component is already initialized.

As a first step: try to use mounted() instead of created(). https://vuejs.org/v2/guide/instance.html#Lifecycle-Diagram

If this does not work, I would recommend to use the functions provided on the vue instance i.e. Vue.i18n.translate(..). see #50 for an example on how to use it with vue router.

@daveo1001
Copy link

nope and nope :/

But I figured it out. The package i'm using for setting title in header had an example.

Thanks for the quick response!

@tikiatua
Copy link
Member

So basically you need to use a computed property?

@daveo1001
Copy link

I don't really get the wizardy portion of vue but turning the metaInfo from an object into a function got things cooking. Oh, and I had to move this.$t() into a lifestyle function instead of being inside data, which makes sense but I wasn't thinking. Here's the final working code.

export default {
  data: () => ({
    title: '' // can't put this.$t() here
  }),
  metaInfo () {
    return {
      title: this.title
    }
  },
  created () {
    this.title = this.$t('login')
  }
}

Thanks again for hanging out with me as I got through this!

@daplan128
Copy link

daplan128 commented Sep 3, 2020

hi i need help with my code

<template>
    <div class="help-container">
        <div class="help-title">{{ $t("helpage.help") }}</div>
        <div class="content-container-mobile">https://guides.github.com/features/mastering-markdown/
            <div class="content-title">{{ $t("helpage.table") }}</div>
                <div class="redirect-container" v-for="(help, index) in $t('general.helpTitles')" :key="index">
                    <div class="redirect-link"><a :href="'#'+ index">{{help}}</a></div>
                </div>
        </div>
        <title>My Example App</title>
            <div v-for="(help, index) in this.helpInfo" :key="index">
                <div :id="help.id" class="help-subtitle">{{ help.title }}:</div>
                <HelpItem :question="help.question" :answear="help.answear" :num="help.id"/>
            </div>
        <div class="floater-container">
            <div class="floater-title">{{ $t("helpage.ask") }}</div>
            <div class="floater-info">{{$t('general.helpInfo.floaterInfo1')}}</div>
            <br>
            <div class="floater-email">{{$t('general.helpInfo.email')}}</div>
            <br>
            <div class="floater-info-second">{{$t('general.helpInfo.floaterInfo2')}}</div>
            <div class="floater-title">{{ $t("helpage.feedback") }}</div>
            <div class="floater-feedback">{{$t('general.helpInfo.feedbackInfo')}}</div>
            <br>
            <div class="floater-title floater-desktop">{{ $t("helpage.table") }}</div>
            <div class="content-container" v-for="(help, index) in $t('general.helpTitles')" :key="index">
                <div class="content-subtitle"><a :href="'#'+ index">{{help}}</a></div>
            </div>
        </div>
    </div>
</template>

import HelpItem from './HelpItem'

export default {
    name: 'ModelHelp',
    data() {
        return {
            Question1: 'general.help.helpStarted',
            Info1: 'general.help.helpStartedInfo',
            Question2: 'general.help.helpMembers',
            Info2: 'general.help.helpMembersInfo',
            Question3: 'general.help.helpAccount',
            Info3: 'general.help.helpAccountInfo',
            Question4: 'general.help.helpPayment',
            Info4: 'general.help.helpPaymentInfo',
            Question5: 'general.help.helpSocial',
            Info5: 'general.help.helpSocialInfo',
            Question6: 'general.help.helpFraud',
            Info6: 'general.help.helpFraudInfo',
            Question7: 'general.help.helpSupport',
            Info7: 'general.help.helpSupportInfo',
            Question8: 'general.help.helpStudio',
            Info8: 'general.help.helpStudioInfo',
            helpTitles: 'general.helpTitles',
            helpInfo: [],
            info: [],
            question: []
        }
    },
    metaInfo() {
        return {
            Question1: this.Question1,
            Info1: this.Info1,
            Question2: this.Question1,
            Info2: this.Info1,
            Question3: this.Question1,
            Info3: this.Info1,
            Question4: this.Question1,
            Info4: this.Info1,
            Question5: this.Question1,
            Info5: this.Info1,
            Question6: this.Question1,
            Info6: this.Info1,
            Question7: this.Question1,
            Info7: this.Info1,
            Question8: this.Question1,
            Info8: this.Info1,
            helpTitles: this.Question1,
            helpInfo: [],
            info: [],
            question: [],
            htmlAttrs: {
                lang: this.$i18n.locale,
                amp: true // "amp" has no value
            }
        }
    },
    components: {
        HelpItem
    },
    methods: {
        createHelp() {
            this.info = [this.Info1, this.Info2, this.Info3, this.Info4, this.Info5, this.Info6, this.Info7, this.Info8]
            this.question = [this.Question1, this.Question2, this.Question3, this.Question4, this.Question5, this.Question6, this.Question7, this.Question8]
            for (let i = 0; i < this.helpTitles.length; i++) {
                this.helpInfo.push({
                    'id': i,
                    'title': this.$t(helpTitles[i]),
                    'answear': this.$t(info[i]),
                    'question': this.$t(question[i])
                })
            }
        }
    },
    mounted() {
        this.createHelp()
    }
}

try with @daveo1001 solution but don't work.

i tried with key.map and v-for inside v-for and it doesn't work i can't work with keys

@tikiatua
Copy link
Member

tikiatua commented Sep 3, 2020

Hi @daplan128

Thank you for your request. From what I understand, you try to iterature over this.helpTitles to construct a translated object to push onto the this.helpInfo array. However this.helpTitles is set as a string further above. Maybe there is something I do not understand correctly.

    methods: {
        createHelp() {
            this.info = [this.Info1, this.Info2, this.Info3, this.Info4, this.Info5, this.Info6, this.Info7, this.Info8]
            this.question = [this.Question1, this.Question2, this.Question3, this.Question4, this.Question5, this.Question6, this.Question7, this.Question8]
            // this.helpTitles is specified as string value in the data section
            for (let i = 0; i < this.helpTitles.length; i++) {
                this.helpInfo.push({
                    'id': i,
                    // where dou you get the helpTitles, info and question arrays from. 
                    // this should probably be this.helpTitles, this.info and this.question
                    'title': this.$t(helpTitles[i]),
                    'answear': this.$t(info[i]),
                    'question': this.$t(question[i])
                })
            }
        }
    },
    mounted() {
        this.createHelp()
    }

@daplan128
Copy link

daplan128 commented Sep 3, 2020

@tikiatua This is my original code, it shows the support information of my website, each title has a series of questions and answers saved within a .json file with all the information to be translated, the app opens correctly with it with the browser language but when I change the language with a switch, data is not rendered, add metaInfo as explained in the comments and try to add $ t in metainfo and in the method but I get an error, I don't understand where I should add $ t so that the title is translated with your questions and answers (these are organized through the helpItem component)

If you can help me I would appreciate it

<template>
    <div class="help-container">
        <div class="help-title">{{ $t("helpage.help") }}</div>
        <div class="content-container-mobile">
            <div class="content-title">{{ $t("helpage.table") }}</div>
                <div class="redirect-container" v-for="(help, index) in $t('general.helpTitles')" :key="index">
                    <div class="redirect-link"><a :href="'#'+ index">{{help}}</a></div>
                </div>
        </div>
        
              //this part does not render
            <div v-for="(help, index) in this.helpInfo" :key="index">
                <div :id="help.id" class="help-subtitle">{{ help.title }}:</div>
                <HelpItem :question="help.question" :answear="help.answear" :num="help.id"/>
            </div>

        <div class="floater-container">
            <div class="floater-title">{{ $t("helpage.ask") }}</div>
            <div class="floater-info">{{$t('general.helpInfo.floaterInfo1')}}</div>
            <br>
            <div class="floater-email">{{$t('general.helpInfo.email')}}</div>
            <br>
            <div class="floater-info-second">{{$t('general.helpInfo.floaterInfo2')}}</div>
            <div class="floater-title">{{ $t("helpage.feedback") }}</div>
            <div class="floater-feedback">{{$t('general.helpInfo.feedbackInfo')}}</div>
            <br>
            <div class="floater-title floater-desktop">{{ $t("helpage.table") }}</div>
            <div class="content-container" v-for="(help, index) in $t('general.helpTitles')" :key="index">
                <div class="content-subtitle"><a :href="'#'+ index">{{help}}</a></div>
            </div>
        </div>
    </div>
</template>

<script>
import HelpItem from './HelpItem'

export default {

    name: 'ModelHelp',
    data() {
        return {
            Question1: this.$t('general.help.helpStarted'),
            Info1: this.$t('general.help.helpStartedInfo'),
            Question2: this.$t('general.help.helpMembers'),
            Info2: this.$t('general.help.helpMembersInfo'),
            Question3: this.$t('general.help.helpAccount'),
            Info3: this.$t('general.help.helpAccountInfo'),
            Question4: this.$t('general.help.helpPayment'),
            Info4: this.$t('general.help.helpPaymentInfo'),
            Question5: this.$t('general.help.helpSocial'),
            Info5: this.$t('general.help.helpSocialInfo'),
            Question6: this.$t('general.help.helpFraud'),
            Info6: this.$t('general.help.helpFraudInfo'),
            Question7: this.$t('general.help.helpSupport'),
            Info7: this.$t('general.help.helpSupportInfo'),
            Question8: this.$t('general.help.helpStudio'),
            Info8: this.$t('general.help.helpStudioInfo'),
            helpTitles: this.$t('general.helpTitles'),
            helpInfo: [],
            info: [],
            question: []
        }
    },
    components: {
        HelpItem
    },
    methods: {
        createHelp() {
            this.info = [this.Info1, this.Info2, this.Info3, this.Info4, this.Info5, this.Info6, this.Info7, this.Info8]
            this.question = [this.Question1, this.Question2, this.Question3, this.Question4, this.Question5, this.Question6, this.Question7, this.Question8]
            for (let i = 0; i < this.helpTitles.length; i++) {
                this.helpInfo.push({
                    'id': i,
                    'title': this.helpTitles[i],
                    'answear': this.info[i],
                    'question': this.question[i]
                })
            }
        }
    },
    mounted() {
        this.createHelp()
    }
}
</script>

my json files are shown like this:

general: {
        helpTitles: [
            'title1',
            'title2',
            'title3',
            'title4',
            'title5',
            'title6',
            'title7',
            'title8'
        ],
        help: {
            helpStarted: [
                'question1',
                'question2',
                'question3',
                'question4',
                'question5',
                'question6',
                'question7',
                'question8',
                'question9',
                'question10'
            ],
            helpStartedInfo: [
                'answer1',
                'answer2',
                'answer3',
                'answer4',
                'answer5',
                'answer6',
                'answer7',
                'answer8',
                'answer9',
                'answer10'

		],
            helpMembers: [
                'question1',
                'question2',
                'question3',
                'question4',
                'question5',
                'question6'
            ],
            helpMembersInfo: [
                'answer1',
                'answer2',
                'answer3',
                'answer4',
                'answer5',
                'answer6',
            ],
            helpAccount: [
                'question1',
                'question2',
            ],
            helpAccountInfo: [
                'answer1',
                'answer2',
            ],
            helpPayment: [
                'question1',
                'question2',
                'question3',
                'question4',
                'question5',
                'question6',
                'question7',
                'question8',
            ],
            helpPaymentInfo: [
                'answer1',
                'answer2',
                'answer3',
                'answer4',
                'answer5',
                'answer6',
                'answer7',
                'answer8',
            ],
            helpSocial: [
		more question
            ],
            helpSocialInfo: [
                more answer
            ],
            helpFraud: [
		more question
            ],
            helpFraudInfo: [
                more answer
            ],
            helpSupport: [
		more question
            ],
            helpSupportInfo: [
                more answer
            ],
            helpStudio: [
		more question
            ],
            helpStudioInfo: [
                more answer
            ]
        },

titulo1 tiene helpStarted (quiestion) and helpStartedInfo (answer)
titulo2 tiene helpMembers (quiestion) and helpMembersInfo (answer)
titulo 3....
titulo 4....
etc

helpItem.vue

<template>
    <div class="help-info-container">
        <div v-for="(info, index) in this.question" :key="index" class="help-text-primary">
            <div class="help-text-show" @click="showInfo(index)"><div id="info-text">{{info}}</div>
                <span class="d-flex justify-content-center align-items-center">
                    <i :id="'chevron-down-' + num + index" class="fas fa-chevron-down"></i>
                    <i :id="'chevron-up-' + num + index" class="fas fa-chevron-up"></i>
                </span>
            </div>
            <pre v-html="answear[index]" :id="num + '-hide-' + index" class="help-text-hide" ></pre>
        </div>
    </div>
</template>

@tikiatua
Copy link
Member

tikiatua commented Sep 3, 2020

Hmm.. Ok. I think, I know the reason for the problem. The $t function returns an object that is not reactive.

This means, that changing the locale on the store will not change values already returned by this.$t(...). So the information that is returned in your data() function will not be automatically updated, if the locale on the store changes. Likewise, the information stored in the this.helpInfo will also not be updated, when you change the locale.

I presume, that it should work, if you return the translations as computed properties instead of putting them on the data object – could you try this out.

If this works, the next step would be to get the integration with the metaInfo() method working.

<script>
import HelpItem from './HelpItem'

export default {
    name: 'ModelHelp',
    components: {
        HelpItem
    },
    computed: {
        // generate translations as computed property to update information
        translations() {
           return {
              question: this.$t('general.help.helpStarted'),
              info1: this.$t('general.help.helpStartedInfo'),
              ...
           }
        },

        // generate help information as computed property
        createHelp() {
            let info = [this.translations.info1, this.translations.info2, ...]
            let questions = [this.translations.question1, this.translations.question2, ...]
           
           let helpInfo = [];
            for (let i = 0; i < this.helpTitles.length; i++) {
                helpInfo.push({
                    'id': i,
                    'title': this.helpTitles[i],
                    'answear': this.info[i],
                    'question': this.question[i]
                })
            }
            return helpInfo;
        }
    }
}
</script>

@tikiatua
Copy link
Member

tikiatua commented Sep 3, 2020

@daplan128: I created a small example that works as intended. You can save it as html file and open it directly in the browser. The example is not yet done with the metaInfo plugin.

P.S. What exactly is your intention with putting the information in metaInfo?

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>vuex-i18n</title>

  <script src='https://cdn.polyfill.io/v2/polyfill.min.js?flags=gated&unknown=polyfill'></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
  <script src="https://unpkg.com/[email protected]"></script>

  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuex-i18n.umd.js"></script>

  </head>
  <body>

    <div id="app">
      <div>Current locale: {{ $i18n.locale()}}</div>
      <div @click="$i18n.set('en')" style="cursor:pointer">Set English</div>
      <div @click="$i18n.set('de')" style="cursor:pointer">Set German</div>
      <my-test-component />
    </div>

    <!-- application code -->
    <script type="text/javascript">

      // enable the vue devtools
      Vue.config.devtools = true;

      // initialize a new vuex store including our i18nVuexModule
      const store = new Vuex.Store({});

      // initialize the vuexi18nPlugin
      Vue.use(vuexI18n.plugin, store);

      // define default translations for english text
      const localeEn = {
        'message.title': 'My translated title',
        'help.titles': [ 'title1 (English)', 'title2 (English)', 'title3 (English)']
      };

      // define default translations for english text
      const localeDe = {
        'message.title': 'Mein übersetzter Titel',
        'help.titles': [ 'titel1 (German)', 'titel2 (German)', 'titel3 (German)']
      };

      // add the english locale to the i18n store
      Vue.i18n.add('en', localeEn);
      Vue.i18n.add('de', localeDe);

      // set the current language to english
      Vue.i18n.set('en');

      Vue.component('my-test-component', {
        template: `<div class="example-text">
         <h1>message.title: {{ $t("message.title") }}</h1>
         <div v-for="(help, index) in helpInfo" :key="index">
            <div :id="help.id" class="help-subtitle">- {{ help.title }}</div>
          </div>
        </div>`,
        computed: {
          helpInfo() {
            let info = [];
            let helpTitles = this.$t('help.titles');
            for (i = 0; i < helpTitles.length; i++) {
              info.push({
                index: i,
                title: helpTitles[i]
              })
            }
            return info;
          }
        }
      });

      var app = new Vue({
        store: store,
        el: '#app'
      });

    </script>

</body>
</html>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants