Vue-i18n: Vue.extend does not accept a VueI18n class instance as i18n option

Created on 26 Jul 2017  路  10Comments  路  Source: kazupon/vue-i18n

vue & vue-i18n version

2.4.2 & 7.0.5 (using dist from master in fiddle)

Reproduction Link

Minimal example http://jsfiddle.net/Ly55ew8m/2/

Our use case is not represented in that fiddle, see below.

Steps to reproduce

Passing a VueI18n instance to Vue.extend is ignored, only a plain old i18n options object works.

In fiddle just comment and un-comment the relevant lines

What is Expected?

If a class instance would work, we could keep (and export) a reference to the instance and import it in other parts of the application (like vuex actions) to control vue-i18n, i.e. locale switch.

What is actually happening?

We can not use a class instance so we have to add the locale switch logic inside the Vue.extend options: i.e. watch a vuex getter for current language and switch language through this.$i18n.locale.

Most helpful comment

@kimuraz to get around this issue you must pass the i18n object into the constructor not the extend call.

const Constructor = Vue.extend(SmallComponent);
const vm = new Constructor({i18n}).$mount()

All 10 comments

Thank you for your feedback!

This issue is occurred due to Vue.extend.
I seem that Vue.extend can not pass the Class instance. 馃

It does have an impact on Unit Testing for this kind of implementation:

https://vuejs.org/v2/guide/unit-testing.html#Writing-Testable-Components

We are developing a project that now uses vue-i18n. When we implemented it, some warnings appeared on existing tests:

WARN: '[vue-i18n] Cannot translate the value of keypath 'input.required'. Use the value of keypath as default.'

It correctly does any assertion, since the keypath will be compared with it own value and we are not testing the vue-i18n messages itself, but the values that the component uses for internal processing.
Is there any workaround to not triggering these warnings?

@kimuraz to get around this issue you must pass the i18n object into the constructor not the extend call.

const Constructor = Vue.extend(SmallComponent);
const vm = new Constructor({i18n}).$mount()

@rikbrowning Thank you, I'll give it a try to test it, although I've already solve it mocking vue-i18n instance using vue-test-utils + jest (changed my test tools) :)

@kimuraz do you have an example repo of your mocked vue-i18n instance via jest?

close (avoid with https://github.com/kazupon/vue-i18n/issues/200#issuecomment-359516610)

Hmmm, actually there are some use cases other than tests that would be covered by this.
For instance:

const CommonApplication = Vue.extend({
  router: new VueRouter({
    routes: [
      { path: '/shared', component: shared },
    ],
  }),
  i18n: new VueI18n({
    locale: 'en',
    messages: {
      en: {
        shared: 'Shared Message'
      },
    },
  }),
});

const fooApplication = new CommonApplication({ el: '#foo' });
// Works as expected and $router contains /shared and /foo routes
fooApplication.$router.addRoutes([ { path: '/foo', component: foo } ]);
// Doesn't work and $i18n doesn't contain 'shared' message, but only 'foo'
fooApplication.$i18n.locale = 'en';
fooApplication.$i18n.mergeLocaleMessage('en', {
  foo: 'Foo Message',
});

const barApplication = new CommonApplication({ el: '#bar' });
// Works as expected and $router contains /shared and /bar routes
barApplication.$router.addRoutes([ { path: '/bar', component: bar } ]);
// Doesn't work and $i18n doesn't contain 'shared' message, but only 'bar'
barApplication.$i18n.locale = 'en';
barApplication.$i18n.mergeLocaleMessage('en', {
  bar: 'Bar Message',
});

@kazupon I've created this fiddle to illustrated the concept:
https://jsfiddle.net/vFragosop/rstygetw/9/

const Constructor = Vue.extend(SmallComponent);
const vm = new Constructor({i18n}).$mount()

In case it helps anyone else I had to also do

const i18n = this.$i18n

@kazupon I've found the reason why Vue.extend cannot work, It's because Vue.config.optionMergeStrategies.i18n use Vue.config.optionMergeStrategies.methods, which makes i18n instance loses his __proto__, so the options.i18n instanceof VueI18n becomes false. Will vue-i18n support Vue.extend({i18n})? If yes, I can fix this problem.

Was this page helpful?
0 / 5 - 0 ratings