7

I want to create a dynamical slider which depends on the page.

    security_signin: {
        slide1: 'Kitten1',
        slide2: 'Kitten2',
    },
    signup: {
        slide1: 'Kitten1',
        slide2: 'Kitten2',
        slide3: 'Kitten3'
    }

The thing is I want to render in my component my slider in function of the number of slide.

So this is something like this:

<slide v-for="(item, index) in $t('message.'+page).length">
    <p v-html="$t('message.'+page+'.slide'+index)"></p>
</slide>

However I do not manage to access properly messages this way. Since $t('message.'+page).length is giving me back the length of the first slide (7 in the Kitten1 case).

Is there a way to access i18n without recreating an instance of it ?

jps
  • 20,041
  • 15
  • 75
  • 79
Baldráni
  • 5,332
  • 7
  • 51
  • 79

4 Answers4

13

It's very simple, access the messages property from $i18n. For instance:

<slide v-for="(item, index) in Object.keys($i18n.messages[$i18n.fallbackLocale].message[page]).length">
    <p v-html="$t('message.'+page+'.slide'+index)"></p>
</slide>

In more detail, $i18n.messages holds all your translations, e.g.

en: {
    security_signin: {
        slide1: 'Kitten1',
        slide2: 'Kitten2',
    },
    signup: {
        slide1: 'Kitten1',
        slide2: 'Kitten2',
        slide3: 'Kitten3'
    }
}

Subset a locale of your choice, $i18n.fallbackLocale for the fallback locale or $i18n.locale for your current locale. You should obtain your javascript object.

Be very careful, when you translate with $t() any missing translations are recovered from the fallback locale. But when you access the javascript object directly, you give up this safety net. Some locales may have missing keys.

In this case fallbackLocale suffices because we don't want to access the translations, only the number of elements.

Javier
  • 476
  • 3
  • 7
3

Okay so it appears that $t() is always returning a string.

So the solution I found out was to import messages in my components and directly use it from there :

import messages from '../messages'

export default {
   props: ['page', 'locale'],
   data(){
       return {
           slides: messages[this.locale].message[this.page]
       }
   }
}

<slide v-for="(slide, i) in slides">
    <p v-html="slide"></p>
    <img :src="'/assets/img/slider-bg-'+ i +'.png'" alt="">
</slide>
Baldráni
  • 5,332
  • 7
  • 51
  • 79
0

You are using objects instead of arrays but JavaScript objects do not have a length property - you can try with arrays:

// English locale
{
  "message":
  {
    security_signing:
    {
      slides:
      [
        'Kitten1',
        'Kitten2'
      ]
    },
    signup:
    {
      slides:
      [
        'Kitten1',
        'Kitten2',
        'Kitten3'
      ]
    }
  }
}

<slide v-for="item in $t('message.'+page+'.slides').length">
    <p v-html="item"></p>
</slide>
IVO GELOV
  • 13,496
  • 1
  • 17
  • 26
  • I sadly don't think this is working. Morevor I don't know how to check inside my component but when I try to display this: `{{ Object.keys($t('message.'+page)).length }}` I have the same result as `{{ $t('message.'+page).length }}` – Baldráni Sep 15 '18 at 14:03
  • Updated my answer to use arrays instead of objects – IVO GELOV Sep 15 '18 at 14:18
0

in Vue 3 version

import { createI18n } from "vue-i18n";
import pluralRules from "./rules/pluralization";
import numberFormats from "./rules/numbers.js";
import datetimeFormats from "./rules/datetime.js";
import en from "./locales/en.json";
import tr from "./locales/tr.json";

export default createI18n({
  locale: import.meta.env.VITE_DEFAULT_LOCALE,
  fallbackLocale: import.meta.env.VITE_FALLBACK_LOCALE,
  legacy: false,
  globalInjection: true,
  messages: { tr, en },
  runtimeOnly: false,
  pluralRules,
  numberFormats,
  datetimeFormats,
});

After the definitions you can get your messages from global object.

let locale = this.i18n.global.locale.value
let messages = this.i18n.global.messages.value[locale]
Ersin Güvenç
  • 93
  • 1
  • 14