[0.15] Access plugin component outside of Vue instance (e.g. from router navigation guards)?



  • Hello,

    I’m a bit new to Vue and Quasar, so please help me understand how to accomplish the following:

    I wish to use the vue-i18n plugin to translate something in a Dialog that is created in a vue-router beforeEach navigation guard, i.e.:

    import Vue from 'vue';
    import VueRouter from 'vue-router';
    import { Dialog } from 'quasar';
    import routes from './routes';
    
    
    const Router = new VueRouter({
      /*
       * NOTE! Change Vue Router mode from quasar.conf.js -> build -> vueRouterMode
       *
       * If you decide to go with "history" mode, please also set "build.publicPath"
       * to something other than an empty string.
       * Example: '/' instead of ''
       */
    
      // Leave as is and change from quasar.conf.js instead!
      mode: process.env.VUE_ROUTER_MODE,
      base: process.env.VUE_ROUTER_BASE,
      scrollBehavior: () => ({y: 0}),
      routes
    });
    
    Router.beforeEach((to, from, next) => {
      if (to.matched.some(record => record.meta.someProp) &&
        !from.matched.some(record => record.meta.someProp)) {
        Dialog.create({
          // The following does not work :(
          title: Vue.t('some.translation.key'),
          form: {
                 ...
            }
          },
          buttons: [
                ...
          ]
        });
      }
      else {
        next();
      }
    });
    
    export default Router;
    

    Before, I could just import the i18n instance, but since the thing is now initialized as a plugin to the Vue system, how can I access it from router, which has no this to use? Stuff like Vue.t or Vue.$i18n.t doesn’t work.

    I’m sure I’m missing some core concept here, please help me out.



  • Hello sarndt,

    I was a little stuck also with this problem. My solution was:

    MUST KNOW BEFORE SOLUTION:
    If you use this.$q.i18n.<quasar-label> is the label of QUASAR, this is only for components as DataTable.
    If you want to use your own translations you must to do: this.$i18n.<your-custom-label>

    SOLUTION:
    1- To do your own translations after install Vue WITH i18n you must change src/i18n and add your own languages and then change index.js inside this folder. In my case, I have 4 languages:

    import en from './en’
    import de from './de’
    import ca from './ca’
    import es from ‘./es’

    export default {
    en,de,ca,es
    }

    2- Inside your layout (default.vue) yo can declare this:

    in your HTML:

    <q-btn @click=“changeLanguage(‘en’)”>EN</q-btn>
    <q-btn @click=“changeLanguage(‘de’)” >DE</q-btn>
    <q-btn @click=“changeLanguage(‘ca’)” >CA</q-btn>
    <q-btn @click=“changeLanguage(‘es’)”>ES</q-btn>

    in your script:

    methods: {
    openURL,
    changeLanguage (lng) {
    //DANGER!!!
    //this.$q.i18n -> International QUASAR
    //this.$i18n -> International local files
    console.log(‘Change lang:’,lng);
    this.$i18n.locale=lng;
    }
    }

    I hope you help with this solution.



  • You can pass vm: this to the store when dispatching an action. Then you can do everything there

    Edit:

    You can access the vue from the store instance using this._vm



  • @benoitranque said in [0.15] Access plugin component outside of Vue instance (e.g. from router navigation guards)?:

    You can pass vm: this to the store when dispatching an action. Then you can do everything there

    Edit:

    You can access the vue from the store instance using this._vm

    My problem is that I’m not having a store instance to work with, I’m in a Router.beforeEach() guard, so that I don’t have any vue instance at this point either. I would really just like to know how to access the i18n plugin from the general Vue object that I can import with import Vue from 'vue';



  • I would suggest you create a plugin for your router.beforeEach() guard, and add it after i18n plugin has been initiated



  • That doesn’t sound too bad, I’ll see if that works. Haven’t written plugins for vue yet, but maybe that’s the right way to go about it



  • You can(should) init a quasar plugin using quasar new plugin <name>



  • @benoitranque
    Yep, that actually did the trick, just wanted to write this down here in case someone else comes around with the same problem.
    NB: The plugin order doesn’t matter actually, as the guard is only used once all plugins are initialized.

    In my case, using a plugin, I could reference my i18n instance via app.i18n and thus just add a navigation guard like this:

    import {Dialog, Notify} from 'quasar';
    
    export default ({app, router, store}) => {
      router.beforeEach((to, from, next) => {
        if (to.matched.some(record => record.meta.someProperty) {
          // Do something here like creating a dialogue
          Dialog.create({
            title: app.i18n.t('some.i18n.key'),
            ok: true,
            cancel: true,
            preventClose: true,
            prompt: {
              model: ''
            }
          }).then(data => {
            // Handle okay
          }).catch(() => {
            // Handle cancel
            Notify.create(app.i18n.t('some.other.i18n.key'));
          });
        }
        else {
          next();
        }
      });
    };
    


  • I would agree with @benoitranque on your use case.
    However if you run in the problem that you really need i18n access from external files (e.g. pure JS files that are imported in your component) I have come up with the following solution.

    1. Set up your i18n instance in a seperate file (for example src/i18n/i18n.js) with the following conent:
    import Vue from 'vue'
    import VueI18n from 'vue-i18n'
    import locales from 'src/i18n'
    
    Vue.use(VueI18n)
    
    const i18n = new VueI18n({
      locale: 'en',
      messages: locales
    })
    
    export default i18n
    
    
    1. Create a Quasar plugin for i18n (or use the default one) with the following content:
    import i18n from 'src/i18n/i18n'
    
    export default ({ app, Vue }) => {
      app.i18n = i18n
    }
    
    

    This way you can use this.$t in your Vue components, but you are also able to use it like this in pure JS:

    import i18n from `src/i18n/i18n.js`
    
    // whatever code
    
    i18n.t('my-string')