No More Posting New Topics!

If you have a question or an issue, please start a thread in our Github Discussions Forum.
This forum is closed for new threads/ topics.

Navigation

    Quasar Framework

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search

    [SOLVED] Dynamic set of Quasar lang from store value

    Framework
    4
    24
    4456
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ssuess
      ssuess last edited by ssuess

      I have a value that is set in my store that should be read to determine what language quasar will use. Following the instructions, I have created a boot file and included it, but it failes to find my store. I assume this is because the boot process happens earlier than the store load? Not sure how to call my store value in the boot file then, any suggestions? Here is my boot file:

      // for when you don't specify quasar.conf.js > framework: 'all'
      import { Quasar } from 'quasar'
      // OTHERWISE:
      // import Quasar from 'quasar'
      
      export default async () => {
        let langIso = 'en-gb'
        if (this.$store.state.rstruth.lang_prefs !== 'en-gb') {
          langIso = this.$store.state.rstruth.lang_prefs
        }
      
        try {
          await import(`quasar/lang/${langIso}`)
            .then(lang => {
              Quasar.lang.set(lang.default)
            })
        } catch (err) {
          // Requested Quasar Language Pack does not exist,
          // let's not break the app, so catching error
        }
      }
      

      I have also tried Store in the place of this.$store and tried importing the store in this file, to no avail (although perhaps my syntax was wrong). Any suggestions for how to choose the lang from a vuex store value? Thanks.

      1 Reply Last reply Reply Quote 0
      • s.molinari
        s.molinari last edited by

        Following the instructions

        Where does it say to do the language selection in the boot file?

        You should put your language selection in a component for language selection. Since the two language systems (assuming you are also using vue-i18n) are global properties of Vue, that’s all you need to “manipulate” to get the language changed. See here (pro tip at the bottom). If you need to change it with a Vuex mutation or store value, you can build that into your “language selection component” too.

        Scott

        ssuess 1 Reply Last reply Reply Quote 0
        • metalsadman
          metalsadman last edited by metalsadman

          @ssuess https://quasar.dev/quasar-cli/cli-documentation/boot-files#Anatomy-of-a-boot-file
          Pass your store context as param like so export default async ({store}) => { ... store.state.rstruth.lang_prefs ...}.

          1 Reply Last reply Reply Quote 1
          • ssuess
            ssuess @s.molinari last edited by ssuess

            @s-molinari I assumed I needed to put it into a boot file, because whenever I refresh my app, it is back to en-gb, even if I have switched to another language (like es) that was working just fine until a refresh. The page with the instructions I was following are from here: https://quasar.dev/options/quasar-language-packs#Dynamically-Picking-Default-Language

            Once someone navigates to my prefs page with a chooser, they can set the language no problem. But it does not save across a refresh and this is what I am trying to fix. I can store my value in vuex, but need a way to force my app to that language pref across restart/refresh of app.

            1 Reply Last reply Reply Quote 0
            • s.molinari
              s.molinari last edited by

              Ah. An important piece of information missing from your original post. Cross-session persistence. 😁

              Did the post from @metalsadman help you? Also, how is Vuex persisting the value across the sessions?

              Scott

              ssuess 1 Reply Last reply Reply Quote 0
              • ssuess
                ssuess @s.molinari last edited by

                @s-molinari I am using vuex-persist to persist my values. As for the post from @metalsadman I need to examine it more closely, but it seems that the logic is backwards. I need to access the vuex store BEFORE (or at boot), not after, and it seems that solution is for passing it later (but as I said, perhaps I am missing something about that and I need to investigate).

                1 Reply Last reply Reply Quote 0
                • s.molinari
                  s.molinari last edited by s.molinari

                  It’s not backwards. The store is initialized before the boot files are ran and “offered” to the boot file as an argument. It’s dependency injection in action.

                  I have this in a freshly created Quasar app.

                  export default function ({ store }) {
                    const Router = new VueRouter({
                      scrollBehavior: () => ({ x: 0, y: 0 }),
                      routes,
                  
                      // Leave these as is and change from quasar.conf.js instead!
                      // quasar.conf.js -> build -> vueRouterMode
                      // quasar.conf.js -> build -> publicPath
                      mode: process.env.VUE_ROUTER_MODE,
                      base: process.env.VUE_ROUTER_BASE
                    })
                    console.log('store:', store)
                    return Router
                  }
                  

                  And I see the store when the app initially loads:

                  676c97d5-690c-4674-98d6-ec46d14b6952-image.png

                  Try it! 😃

                  Scott

                  1 Reply Last reply Reply Quote 1
                  • ssuess
                    ssuess last edited by

                    That is great news, I will try it. Thanks!

                    1 Reply Last reply Reply Quote 0
                    • ssuess
                      ssuess last edited by ssuess

                      Alas, this does not work for me, here is my boot file:

                      import { Quasar } from 'quasar'
                      import store from 'src/router'
                      
                      console.log(store)
                      export default async () => {
                        let langIso = 'en-gb'
                        if (store.state.rstruth.lang_prefs !== 'en-gb') {
                          langIso = store.state.rstruth.lang_prefs
                        }
                      
                        try {
                          await import(`quasar/lang/${langIso}`)
                            .then(lang => {
                              Quasar.lang.set(lang.default)
                            })
                        } catch (err) {
                          // Requested Quasar Language Pack does not exist,
                          // let's not break the app, so catching error
                        }
                      }
                      

                      Which results in this from the console:

                      [HMR] Waiting for update signal from WDS...
                      quasar-lang-pack.js?f5b9:6 ƒ (_ref) {
                        var store = _ref.store;
                        var Router = new vue_router__WEBPACK_IMPORTED_MODULE_4__["default"]({
                          scrollBehavior: function scrollBehavior() {
                            return {
                              y: 0
                            };
                          },
                      …
                      client-entry.js?2f39:62 [Quasar] Running PWA.
                      client-entry.js?2f39:63 [Quasar] Forcing PWA into the network-first approach to not break Hot Module Replacement while developing.
                      client-entry.js?2f39:100 [Quasar] boot error: TypeError: Cannot read property 'rstruth' of undefined
                          at _callee$ (quasar-lang-pack.js?f5b9:9)
                          at tryCatch (runtime.js?4bc9:45)
                          at Generator.invoke [as _invoke] (runtime.js?4bc9:271)
                          at Generator.prototype.<computed> [as next] (runtime.js?4bc9:97)
                          at asyncGeneratorStep (asyncToGenerator.js?fa84:5)
                          at _next (asyncToGenerator.js?fa84:27)
                          at eval (asyncToGenerator.js?fa84:34)
                          at new Promise (<anonymous>)
                          at new F (_export.js?63b6:36)
                          at Array.eval (asyncToGenerator.js?fa84:23)
                      _callee$ @ client-entry.js?2f39:100
                      tryCatch @ runtime.js?4bc9:45
                      invoke @ runtime.js?4bc9:271
                      prototype.<computed> @ runtime.js?4bc9:97
                      asyncGeneratorStep @ asyncToGenerator.js?fa84:5
                      _throw @ asyncToGenerator.js?fa84:31
                      Promise.then (async)
                      asyncGeneratorStep @ asyncToGenerator.js?fa84:15
                      _next @ asyncToGenerator.js?fa84:27
                      Promise.then (async)
                      asyncGeneratorStep @ asyncToGenerator.js?fa84:15
                      _next @ asyncToGenerator.js?fa84:27
                      (anonymous) @ asyncToGenerator.js?fa84:34
                      F @ _export.js?63b6:36
                      (anonymous) @ asyncToGenerator.js?fa84:23
                      _start @ client-entry.js?2f39:77
                      start @ client-entry.js?2f39:77
                      (anonymous) @ client-entry.js?2f39:120
                      ./.quasar/client-entry.js @ app.js:933
                      __webpack_require__ @ app.js:770
                      fn @ app.js:130
                      0 @ app.js:7166
                      __webpack_require__ @ app.js:770
                      (anonymous) @ app.js:908
                      (anonymous) @ app.js:911
                      client?f1f8:48 [WDS] Hot Module Replacement enabled.
                      client?f1f8:52 [WDS] Live Reloading enabled.
                      register-service-worker.js?407e:12 App is being served from cache by a service worker.
                      register-service-worker.js?407e:15 Service worker has been registered.
                      

                      and I have tried several ways of importing the store to that file (or not importing at all and just trying to call store or this.$store as in other places in my app, and they all fail…

                      I should note that when I call this.$store in any of my components, it works fine. Which leads me to think that it is not yet available to boot files like I mentioned above…

                      1 Reply Last reply Reply Quote 0
                      • metalsadman
                        metalsadman last edited by metalsadman

                        @ssuess have you looked and tried the sample code me and @s-molinari shown above?.. anyway you can check that it works here https://codesandbox.io/s/0ybb3 if you have doubts :x.

                        1 Reply Last reply Reply Quote 0
                        • ssuess
                          ssuess last edited by ssuess

                          @metalsadman yes I have, and in fact, I already had the same store export from my router. As I mentioned above, I am able to access it in any of my components without any issue. The problem is trying to access the store from within the BOOT file above. Unless I am not understanding you?

                          Here is my src/router/index.js file btw in case it helps:

                          export default function ({ store }) {
                            const Router = new VueRouter({
                              scrollBehavior: () => ({ y: 0 }),
                              routes,
                          
                              // Leave these as is and change from quasar.conf.js instead!
                              // quasar.conf.js -> build -> vueRouterMode
                              // quasar.conf.js -> build -> publicPath
                              mode: process.env.VUE_ROUTER_MODE,
                              base: process.env.VUE_ROUTER_BASE
                            })
                            // console.log(store._vm.$root._data)
                            let previouslyRestored = false
                            const waitForStorageToBeReady = async (to, from, next) => {
                              await store.restored
                              if (!previouslyRestored) {
                                // do the things you want to do only once after the store is restored
                                previouslyRestored = true
                              }
                              next()
                            }
                            Router.beforeEach(waitForStorageToBeReady)
                          
                            return Router
                          }
                          

                          So perhaps I am missing something fundamental, but I don’t currently see it. Thanks again for any suggestions you have, I really appreciate it.

                          1 Reply Last reply Reply Quote 0
                          • metalsadman
                            metalsadman last edited by

                            well i don’t know why it’s not working for you, nowhere i need to import the store in a bootfile, since the store is already available for me if i add it is as a param. unless you’re not providing anymore info :/.

                            1 Reply Last reply Reply Quote 0
                            • ssuess
                              ssuess last edited by

                              Interestingly, when I look at the sandbox you set up, I don’t see a single case of any file inside /boot that is actually accessing store data

                              metalsadman 1 Reply Last reply Reply Quote 0
                              • metalsadman
                                metalsadman @ssuess last edited by metalsadman

                                @ssuess you’re not looking enough, see lines 95 and 102 of src/boot/axios.js :). line 14 of src/router/index.js and see further how i’m tapping into the store to change the title of the current page.

                                1 Reply Last reply Reply Quote 0
                                • ssuess
                                  ssuess last edited by

                                  Thanks! Sorry I missed that, it gives me an idea of something new to try…I will do that and get back to you…

                                  1 Reply Last reply Reply Quote 0
                                  • ssuess
                                    ssuess last edited by ssuess

                                    Finally! Now I see what the problem was! I was neglecting to use {store} INSIDE the EXPORT of the boot logic, thinking it was provided by other components. Now it seems so obvious (and I feel pretty dumb). Thanks @metalsadman and @s-molinari for helping me troubleshoot this!

                                    FYI, the code change was from this:

                                    export default async () => {
                                      let langIso = 'en-gb'
                                      console.log(store.state.rstruth.lang_prefs)
                                      if (store.state.rstruth.lang_prefs !== 'en-gb') {
                                        langIso = store.state.rstruth.lang_prefs
                                      }
                                    

                                    to THIS:

                                    export default async ({ store }) => {
                                      let langIso = 'en-gb'
                                      console.log(store.state.rstruth.lang_prefs)
                                      if (store.state.rstruth.lang_prefs !== 'en-gb') {
                                        langIso = store.state.rstruth.lang_prefs
                                      }
                                    
                                    1 Reply Last reply Reply Quote 0
                                    • s.molinari
                                      s.molinari last edited by s.molinari

                                      Hehehe…sorry. But, this deserves a 🤦♂.

                                      😁

                                      Scott

                                      1 Reply Last reply Reply Quote 0
                                      • ssuess
                                        ssuess last edited by

                                        @s-molinari Since we are still on the same subject, I am now trying to also set the language for i18n at the same time, but it does not seem there is a param to pass through in the same way is there? So I assume I need to do something like this?

                                        import i18n from 'boot/i18n.js'
                                        
                                        export default async ({ store }) => {
                                            i18n.locale = myStoredLocale
                                        }
                                        

                                        or do you recommend another way to set the i18n locale at boot?

                                        1 Reply Last reply Reply Quote 0
                                        • s.molinari
                                          s.molinari last edited by

                                          Try it out. I’ve never dealt with presetting the language and in fact, this is a use case that we should know about. I’m going to be updating my article with what we find out here. So, try what you can. If it works or maybe @metalsadman has a better idea, then that is what we’ll go with for now.

                                          Scott

                                          1 Reply Last reply Reply Quote 0
                                          • ssuess
                                            ssuess last edited by ssuess

                                            FYI, it totally works with the code shown above. Now we have a way to set lang (for both Quasar and i18n) across restarts/reloads. This assumes that the i18n boot file is configured to export it like so (from @s-molinari medium article):

                                            import VueI18n from 'vue-i18n'
                                            import messages from 'src/i18n'
                                            
                                            let i18n
                                            
                                            export default async ({ app, Vue }) => {
                                              Vue.use(VueI18n)
                                            
                                              // Set i18n instance on app
                                              app.i18n = new VueI18n({
                                                locale: 'en-gb',
                                                fallbackLocale: 'en-gb',
                                                // enableInSFC: true,
                                                messages
                                              })
                                              i18n = app.i18n
                                            }
                                            
                                            export { i18n }
                                            
                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post