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

Vue.extend does not accept a VueI18n class instance as i18n option #200

Closed
esclapes opened this issue Jul 26, 2017 · 10 comments · Fixed by #420
Closed

Vue.extend does not accept a VueI18n class instance as i18n option #200

esclapes opened this issue Jul 26, 2017 · 10 comments · Fixed by #420

Comments

@esclapes
Copy link

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.

@esclapes esclapes changed the title Vue.exted does not accept a VueI18n class instance as i18n option Vue.extend does not accept a VueI18n class instance as i18n option Jul 26, 2017
@kazupon
Copy link
Owner

kazupon commented Jul 28, 2017

Thank you for your feedback!

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

@kimuraz
Copy link
Contributor

kimuraz commented Sep 15, 2017

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?

@rikbrowning
Copy link

@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()

@kimuraz
Copy link
Contributor

kimuraz commented Feb 13, 2018

@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) :)

@simmons-kyle
Copy link

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

@kazupon
Copy link
Owner

kazupon commented Mar 16, 2018

close (avoid with #200 (comment))

@kazupon kazupon closed this as completed Mar 16, 2018
@vfragosop
Copy link

vfragosop commented Mar 29, 2018

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',
});

@vfragosop
Copy link

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

@andrewharvey
Copy link

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

@jaredzhu1993
Copy link
Contributor

@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.

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

Successfully merging a pull request may close this issue.

8 participants