Vue-i18n: $t and SFC locales not working in functional components

Created on 19 Apr 2018  路  5Comments  路  Source: kazupon/vue-i18n

vue & vue-i18n version

Vue: 2.5.13
Vue-i18n : 7.4.2

Steps to reproduce

  • Create a project with Vue and Vue-i18n
  • Add a locale and some messages
// for example
<i18n>
{
  "fr": {
      "my_message": "Bonjour"
  }
}
  • Create a functional component and user $t function or v-t directive
<template functional>
  <p>{{ $t('my_message') }} <span v-t="'my_message'"></span></p>
</template>

What is Expected?

I'm excpecting to see "Bonjour Bonjour" in a p and a span tag

What is actually happening?

warnings / errors / only keys are rendered


image

Most helpful comment

I'm with @darkylmnx for this issue
parent.$t isn't optimal because it's working only if it's the parent component who have the <i18n> translation defined in it.

This mean if i need to make a simple translation component, i can't do it functional:

<i18n>
{
  "fr": {
    "greet": "Bonjour, {name}"
  },
  "en": {
    "greet": "Hello {name}"
  },
  "de": {
    "greet": "Hallo {name}"
  },
  "es": {
    "greet": "Hola {name}"
  },
  "it": {
    "greet": "Ciao {name}"
  },
  "nl": {
    "greet": "Hallo {name}"
  },
  "pt": {
    "greet": "Ola {name}"
  }
}
</i18n>

<script>
export default {
  name: 'Greeter',
  functional: true,
  props: {
    name: {
      type: String,
      required: true,
    },
  },
  render(h, { parent, props }) {
    const { name } = props;
    return (<span>{parent.$t('greet', { nam })}</span>);
  },
};
</script>

It will not work in two case:

  • If there's no traduction in the file (no <i18n> tags)
  • If the parent is functional
<template>
  <div><greeter :name="username" /></div>
</template>

<script>
import Greeter from './Greeter.vue';

export default {
  name: 'ParentGreeter',
  components: {
    Greeter,
  },
  data() {
    return {
      username: 'Warudo',
  },
}
</script>

OR

<template functional>
  <div><greeter :name="username" /></div>
</template>

<script>
import Greeter from './Greeter.vue';

export default {
  name: 'ParentGreeter',
  components: {
    Greeter,
  },
  props: {
    username: {
      type: String,
      default: 'Warudo',
    },
  },
}
</script>

All 5 comments

@poldixd did you try this: https://github.com/vuejs/vue/issues/8074 ?
Basically you should use parent.$t, I believe it's because of:

In cases like this, we can mark components as functional, which means that they鈥檙e stateless (no reactive data) and instanceless (no this context). 

VueJS Docs

@kimuraz as I said it's not working for $t and SFC, what you said works for "$t" yes but SFC i18n tag still doesn't work from what I saw

I'm with @darkylmnx for this issue
parent.$t isn't optimal because it's working only if it's the parent component who have the <i18n> translation defined in it.

This mean if i need to make a simple translation component, i can't do it functional:

<i18n>
{
  "fr": {
    "greet": "Bonjour, {name}"
  },
  "en": {
    "greet": "Hello {name}"
  },
  "de": {
    "greet": "Hallo {name}"
  },
  "es": {
    "greet": "Hola {name}"
  },
  "it": {
    "greet": "Ciao {name}"
  },
  "nl": {
    "greet": "Hallo {name}"
  },
  "pt": {
    "greet": "Ola {name}"
  }
}
</i18n>

<script>
export default {
  name: 'Greeter',
  functional: true,
  props: {
    name: {
      type: String,
      required: true,
    },
  },
  render(h, { parent, props }) {
    const { name } = props;
    return (<span>{parent.$t('greet', { nam })}</span>);
  },
};
</script>

It will not work in two case:

  • If there's no traduction in the file (no <i18n> tags)
  • If the parent is functional
<template>
  <div><greeter :name="username" /></div>
</template>

<script>
import Greeter from './Greeter.vue';

export default {
  name: 'ParentGreeter',
  components: {
    Greeter,
  },
  data() {
    return {
      username: 'Warudo',
  },
}
</script>

OR

<template functional>
  <div><greeter :name="username" /></div>
</template>

<script>
import Greeter from './Greeter.vue';

export default {
  name: 'ParentGreeter',
  components: {
    Greeter,
  },
  props: {
    username: {
      type: String,
      default: 'Warudo',
    },
  },
}
</script>

Is it OK to do like this?

in /src/i18n.js

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

Vue.use(VueI18n);
export const i18n = new VueI18n({
  locale: '',
  fallbackLocale: 'en',
  messages: {},
});
/// ...

in /src/functional-component.js

import { i18n } from './i18n.js;

const t = i18n.t.bind(i18n);

export default {
  name: 'FunctionalComponent',
  functional: true,
  props: {
    someKey: { type: String, default: 'hello' },
  },
  render(h, context) {
    return h('span', {}, [t(context.props.someKey)]);
  }
} 
Was this page helpful?
0 / 5 - 0 ratings

Related issues

forddyce picture forddyce  路  5Comments

lucianobosco picture lucianobosco  路  4Comments

zhaohaodang picture zhaohaodang  路  4Comments

koslo picture koslo  路  5Comments

karol-f picture karol-f  路  3Comments