6

The following code:

import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class SomeComponent extends Vue {
  public someText = this.$t('some.key')
}

Throws an error:

[Vue warn]: Error in data(): "TypeError: i18n is undefined"

I made sure to initialize Vue with Vue.use(VueI18n) and new Vue({ /* ... */, i18n }). The i18n object is initialized this way:

new VueI18n({
  locale: DEFAULT_LOCALE, // imported
  fallbackLocale: 'en',
  messages // imported
})

Translations work perfectly fine as long as they are not immediately called, for example in templates or in component methods.

This vue-i18n issue seems to imply that there is an initialization problem.
I could work around this by using methods and only translating in templates, but there is a specific instance out of my control in which such immediate calls happen: Vuetify input rules.

someRule = [(v) => !!v || this.$t('field.must_not_be_empty')]

These rules are executed immediately, even with lazy-validation on Vuetify forms.

I have identified two possible solutions:

  1. Circumventing the Vuetify rules system and allowing to simply return a string to be translated within the template itself;
  2. Solving the $t immediate availability issue.

Sadly I have not been able to accomplish any of these.

Is there any way to solve this problem?

Kyll
  • 7,036
  • 7
  • 41
  • 64

2 Answers2

5

The issue lied in the use of this.
Basically, Vue needs a very specific execution context that is not the same as what is normally accessible in the root context of a fresh class.

The solution ends up being very simple: Use a getter.

import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class SomeComponent extends Vue {
  public get someText () { return this.$t('some.key') }
}
Kyll
  • 7,036
  • 7
  • 41
  • 64
  • is there any progress about this? How do you think did vue-class-component do smth about it? – Sasha Kos Oct 29 '19 at 23:22
  • 1
    @SashaKos The answer solves the problem. I'm thinking that the trouble with Vue class components is that while `$t` exists when the class is instantiated but it has not yet been populated with `i18n` (to which `$t` refers). – Kyll Oct 30 '19 at 09:33
  • I'm having a similar issue when defining rules for a v-text-field: `Error in beforeMount hook: "TypeError: Cannot read property '_t' of undefined"`. Your solution with a getter doesn't seem to work for me: nameRules = [ (v: any) => !!v || this.errorName1]. Do you have any new input for this? Thanks. – Paul Apr 11 '20 at 18:47
  • Did you create it as a plugin? Mixin, component or what? – Herii Jul 08 '21 at 03:32
0

Your solution with placing the error message in a getter didn't work for me in the context of Vuetify input rules, I get this: Error in beforeMount hook: "TypeError: Cannot read property '_t' of undefined"

I managed to get it working in 2 possible ways:

  1. Use a getter, but for the whole rules array:
get someRules() {
    return [
        (v) => !!v || this.$t('field.must_not_be_empty')
    ];
}
  1. Place the rules in the @Component decorator:
@Component({
    data() {
        return {
            someRules: [
                (v) => !!v || this.$t('field.must_not_be_empty')
            ]
        };
    }
})
export default class SomeComponent extends Vue {
...
}
Paul
  • 1,224
  • 2
  • 14
  • 31