vue-i18n: Access to vue-i18n assets is not available within a Vue component method when called via a Promise

vue & vue-i18n version

vue v2.3.4 vue-i18n v7.0.3 Using with Laravel 5.4, and bundling assets with Webpack via Laravel Mix.

Reproduction Link

(Pending, will update post upon completion.)

Steps to reproduce

  • Prepare a Vue component, with Vue-i18n included as an asset on the top-level Vue instance
  • Prepare a Vue component, which includes a Vue method that accesses this.$t or this.$tc within the method. The method should not be defined using ES6 arrow notation so that the ‘this’ context is the Vue instance.
  • Call the method as the response or error method from a JS Promise

What is Expected?

Access to this.$t is provided via the ‘this’ binding solution provided by Vue

What is actually happening?

vue-i18n is not available (VueComponent property ‘_i18n’ is null). Other Vue instance properties are available in this context, such as this.$store when using vuex, as well as all component data, props and computed properties via ‘this’. An attempt to access this.$t generates an error: TypeError: Cannot read property '_t' of null Error is generated here, though the source cause is external of this: https://github.com/kazupon/vue-i18n/blob/9ef7b798e3c1d58dfae4f25e5e6b8c488b86d819/dist/vue-i18n.js#L111

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 3
  • Comments: 41 (4 by maintainers)

Commits related to this issue

Most upvoted comments

I having the same issue, use this.$root.$t() in promise works for me

Can we reopen this ? I experienced the same error when using $t('xxx') inside a watcher callback. version: vue-i18n@7.4.2

As a workaround I stored the value outside the callback…

I agree. It is strange 😃 I used idea https://github.com/kazupon/vue-i18n/issues/184#issuecomment-446591824 and implemented wrapper

const I18nPlugin = {
  install (Vue, options) {
    const _$t = Vue.prototype.$t
    Vue.prototype._$t = _$t

    Vue.prototype.$t = function () {
      if (this.$i18n) {
        return _$t.apply(this, arguments)
      } else {
        return _$t.apply(this.$root, arguments)
      }
    }
  }
}

// ....
Vue.use(VueI18n)
Vue.use(I18nPlugin)

I agree. I don’t understand why not setting self._i18n = null might introduce a memory leak. If there are no references to it any more, won’t it be removed by the garbage collector automatically?

If that’s the case, the solution doesn’t require any new function, only dropping the self._i18n = null line as the pull request did.

I agree. I don’t understand why not setting self._i18n = null might introduce a memory leak. If there are no references to it any more, won’t it be removed by the garbage collector automatically?

If that’s the case, the solution doesn’t require any new function, only dropping the self._i18n = null line as the pull request did.

@redevening, could you please provide your view on this? You rejected https://github.com/kazupon/vue-i18n/pull/690, so you probably had reasons we have missed here.

I had the same problem, this problem occurs only when I destroy the component, then looking at the source file I found beforeDestroy function:

image

This error happens because before the component is destroyed this function sets _i18n to null. To solve this, you can use the solution @hunterliu1003 or store the values in some variable out of the promise

I having the same issue, use this.$root.$t() in promise works for me

works, thanks. But it’s just a workaround no real solution for this issue, right?

the funny think is on my webserver the app does not respond anymore when the error occurs. locally built for prod the error occurs but the app still works/react.

btw: i use vue-cli

Thank you volks

@SirLamer but why did you close this issue? It’s still reproducible. It’s really great to use this.$t for notifications (vue-notification) inside .then() or .catch().

In master, beforeDestroy now looks as follows:

beforeDestroy (): void {
    if (!this._i18n) { return }

    const self = this
    this.$nextTick(() => {
      if (self._subscribing) {
        self._i18n.unsubscribeDataChanging(self)
        delete self._subscribing
      }

      if (self._i18nWatcher) {
        self._i18nWatcher()
        self._i18n.destroyVM()
        delete self._i18nWatcher
      }

      if (self._localeWatcher) {
        self._localeWatcher()
        delete self._localeWatcher
      }

      self._i18n = null
    })
  }

The this.$nextTick construct was added in version 8.8 to address #499.

Wouldn’t both #499 and this ticket be solved if we just drop the self._i18n = null line? The component is destroyed anyway moment later. I’d even say that the this.$nextTick construct isn’t needed anymore then, but I might miss something there.

Happy to make the (very simple) pull.

In Vue I18n 8.x, you can avoid this comment. https://github.com/kazupon/vue-i18n/issues/184#issuecomment-446591824

Close the issue once, so we need to organize.

Can this please be reopened – this is still an issue in the latest release (8.3.1). You cannot access this.$t(...) inside of a Promise callback even though the rest of the Vue component works as expected on the this object.