Discovering access to this.$i18n.locales from store getter in Nuxt, i18n, and Vuex

Currently, I am constructing a web application utilizing Nuxt v2.15 and @nuxtjs/i18n v7.2 while employing Vuex for state management. Within my global state, I aim to develop a getter that retrieves a value reliant on this.$i18n.locale.

How can I effectively access the existing app context, which incorporates $i18n, in my Vuex getter method?

nuxt.config.js

export default {
  modules: [
    "@nuxtjs/i18n", // https://i18n.nuxtjs.org/
  ],
  i18n: {
    locales: { /* configuration */ },
    defaultLocale: "en",
    detectBrowserLanguage: {
      fallbackLocale: "en",
      redirectOn: "root",
    },
    langDir: "~/locales/",
    vueI18n: {
      fallbackLocale: "en",
      messages: { /* translation data */ },
    },
  },
};

store/index.js

export const state = () => ({
  // Root module for Vuex store: https://nuxtjs.org/docs/directory-structure/store/
});

export const getters = {
  loginOpts() {
    const locale = this.$i18n.locale;
    const uiLocales = [locale];
    if (locale === "zh") {
      uiLocales.push("zh-CN");
    }
    return { params: { ui_locales: uiLocales } };
  },
};

components/login.vue

<template>
  <div>
    <v-btn v-if="$auth.loggedIn" @click="$auth.logout()">Sign Out</v-btn>
    <v-btn v-else @click="$auth.loginWith('auth0', $store.getters.loginOpts)">Sign In</v-btn>
  </div>
</template>

<script>
import { mapGetters } from "vuex";

export default {
  name: "Login",
  data() {
    return {};
  },
  computed: {
    ...mapGetters(["loginOpts"]),
  },
};
</script>

My Expectations

My expectation is to be able to retrieve this.$i18n from a Vuex getter, or some alternative method to accomplish this.

The Current Scenario

Presently, within the getter method, this appears to be undefined.

TypeError: Cannot read properties of undefined (reading '$i18n')

Attempts Made

I have reviewed documentation for Vuex including State, Getters, as well as information regarding Nuxt i18n.

In addition, I have attempted:

  • Accessing state.$i18n
  • Incorporating $i18n: this.$i18n into the root state

Answer №1

Last week, I encountered a similar issue where I had to utilize i18n within a Vuex getter.

While not the most efficient solution, it proved to be effective for me and resolved a major challenge during the development of a government application.

components/login.vue

<template>
  <div>
    <v-btn v-if="$auth.loggedIn" @click="$auth.logout()">Sign Out</v-btn>
    <v-btn v-else @click="$auth.loginWith('auth0', theLoginOpts)">Sign In</v-btn>
  </div>
</template>

<script>
import { mapGetters } from "vuex";

export default {
  name: "Login",
  data() {
    return {
        theLoginOpts: $store.getters.loginOpts(this) // Implementing the necessary change
    };
  },
  computed: {
    ...mapGetters(["loginOpts"]),
  },
};
</script>

store/index.js

export const state = () => ({
  // Root module for Vuex store: https://nuxtjs.org/docs/directory-structure/store/
});

export const getters = {
  loginOpts: (state) => (app) => { // Utilizing app as an essential component 
    const locale = app.$i18n.locale;
    const uiLocales = [locale];
    if (locale === "zh") {
      uiLocales.push("zh-CN");
    }
    return { params: { ui_locales: uiLocales } };
  },
};

Answer №2

After hours of research, trial and error, and valuable discussions with the generous individuals who provided solutions here, it has become evident that accessing i18n directly in a Vuex getter method is not feasible, despite the fact that @nuxt/i18n registers a Vuex module named i18n, and all my readings on Vuex modules indicate otherwise.

However, I stumbled upon the documentation for @nuxt/i18n callbacks, which led me to develop a small custom plugin that updates the values of locale and uiLocales in the global state using a mutation.

The final implementation is structured as follows:

nuxt.config.js

export default {
  modules: [
    "@nuxtjs/i18n", // https://i18n.nuxtjs.org/
  ],
  plugins: [
    "~/plugins/i18n.js",
  ],
  i18n: {
    locales: { /* configuration */ },
    defaultLocale: "en",
    detectBrowserLanguage: {
      fallbackLocale: "en",
      redirectOn: "root",
    },
    langDir: "~/locales/",
    vueI18n: {
      fallbackLocale: "en",
      messages: { /* translation data */ },
    },
  },
};

plugins/i18n.js

export function findLocaleConfig (i18n, locale) {
  return (
    i18n.locales.find(({ iso, code }) => [iso, code].includes(locale)) || {}
  );
}

export default function ({ app }) {
  app.store.commit("localeChange", findLocaleConfig(app.i18n, app.i18n.locale));

  app.i18n.onLanguageSwitched = (oldLocale, newLocale) => {
    app.store.commit("localeChange", findLocaleConfig(app.i18n, newLocale));
  };
}

store/index.js

export const state = () => ({
  locale: null,
  uiLocales: [],
});

export const mutations = {
  localeChange(state, locale) {
    state.locale = locale.code;
    state.uiLocales = [locale.code, locale.iso];
  },
};

components/login.vue

<template>
  <div>
    <v-btn v-if="$auth.loggedIn" @click="$auth.logout()">Sign Out</v-btn>
    <v-btn v-else @click="$auth.loginWith('auth0', loginOpts)">Sign In</v-btn>
  </div>
</template>

<script>
export default {
  name: "Login",
  data() {
    return {};
  },
  computed: {
    loginOpts() {
      const uiLocales = this.$store.state.uiLocales;
      return { params: { ui_locales: uiLocales } };
    },
  },
};
</script>

Answer №3

To retrieve the locale within a Vuex action, you can use: this.app.i18n.locale.
Keep in mind that this cannot be accessed within a state or getter (and using a getter for it isn't recommended anyway).

Just a heads up, this means you can access this value anywhere that you have access to the Nuxt context.

Answer №4

Our project implemented a simple method as shown below: In the computed property of the component

teamsForSelector() {
  return this.$store.getters['company/teamsForSelector'](this.$i18n);
}

and in the state getters

teamsForSelector: (state) => ($i18n) => {
const teamsForSelector = state.teams.map((team) => {
  return {
    id: team.teamUid,
    label: team.teamName,
  };
});
teamsForSelector.unshift({
  id: 'all-teams',
  label: $i18n.t('key'),
});

return teamsForSelector; }

Answer №5

If your page successfully renders on the frontend in Nuxt 2, you have the option to access $i18n by using either window.$nuxt or simply $nuxt:

export const getters = {
  loginOptions() {
    const language = window.$nuxt.$i18n.language;
    ...
  },
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Vue.js variable routes present an issue where the Favicon fails to appear

I've successfully set my favicon in the index.html file for my Vue webpack SPA. It displays properly when I visit the main site or any standard route, but it fails to show up when I navigate to a dynamic route (path: "/traduzione/:translation"). I&ap ...

Optimal approach for vertically aligning elements in CSS

I'm looking to arrange my header ('Sail away today with Starboard Rentals.') and link buttons on top of each other. I want the navigation buttons to be positioned below the h1 on the lower half of the 'home-jumbo' div. What's ...

Preloading error alert message displayed during AJAX request

When I send an ajax request with a dropdown change, the loader div is shown using "before send". However, the issue is that the loader only displays for the first time, even though the ajax functionality works all the time. If you want to check this issue ...

Deliver a communication from the dialogue box on the MEAN stack website to the task pane

Currently experimenting with the Dialog API within Office addins. Able to successfully trigger a Dialog box from my task pane using: $scope.openDialog = function () { Office.context.ui.displayDialogAsync('https://localhost:3000/home', ...

Implementing onClick functionality in RecyclerView post JSON data extraction

I recently implemented a RecyclerView in a fragment and successfully parsed JSON data from a website to display it in the RecyclerView following a helpful tutorial found at: Now, my next challenge is adding an onClick listener to the items in the Recycler ...

How to extract words from a dynamic router.pathname in NextJS when only the filename is displayed instead of the full path?

I'm keeping this example as straightforward as possible, but I can add more details if needed to solve the issue Currently, I am working with dynamic routes in nextJS. My application fetches data from Twitter based on the keywords entered into the dy ...

implementing a collapsible sidebar menu with CSS tables

I am working on a layout with three columns created using css tables to perfectly fit the browser window. The first column serves as a menu and I want it to hide or move to the left when clicked, allowing the middle column to expand into its space. However ...

Use the regex tag in a React component to find a specific tag by name within two different possible

Looking for a regex that can identify <Field ...name="document"> or <FieldArray ...name="document"> within a multiline text string so they can be replaced with an empty string. The text string is not formatted as HTML or XHTML, it simply conta ...

Using Javascript, load a URL by making a JQuery ajax GET request and specifying custom headers

I currently have a small single-page application (SPA) using JQuery/Ajax for the frontend and Node/Express for the backend. The user authentication and authorization are handled with JSON-Webtoken, but I encountered an issue. If someone tries to access the ...

What is the best way to create a cube in Three.js with the 4 corner points of the base and a specified height?

Given a JSON with base coordinates, I am looking to generate a cube in Three.js. The height of the cube will be a constant value, such as 1. { "points": [ { "x": 0, ...

Issue with Ext JS: The property 'substring' is being attempted to be read from an undefined value

Hey there! I'm trying to incorporate a grid panel into my view using Extjs 4.1.1, but I keep encountering an error in the browser console that says "Cannot read property 'substring' of undefined". Below is the JavaScript code snippet I am us ...

Updating content on a webpage via AJAX request without altering the original source code

Within the body of our document, referred to as "form.php," we have the following components: At the head section, there is a JavaScript code block: <script> function showUser(str) { if (str == "") { document.getElementById("txtHint").i ...

Simultaneous malfunction of two ajax forms

I have a dilemma with two boxes: one is called "min amount" and the other is called "max amount." Currently, if I input 100 in the max amount box, it will display products that are priced at less than $100. However, when I input an amount like $50 in the m ...

Changing the depth buffer in a Three.js Shader Material

While working with Three js, I have implemented a vertex shader to animate a large geometry. Additionally, I have incorporated a Depth of Field effect into the output. However, I am encountering an issue where the Depth of Field effect does not seem to re ...

Accordion Functionality in Vue with Animation Effects

I'm struggling to implement a smooth transition for the Accordion component, but unfortunately it's not working as expected. Everything else is functioning correctly except for the animation. template: <div class="accordion"> <di ...

In React Native, the onPress handler will continue to be triggered indefinitely after 2-3 presses

import firebase from './Firebase'; import { useState, useEffect } from 'react'; import { StyleSheet, Text, View, Button, FlatList } from 'react-native'; import { TextInput } from 'react-native-web'; import { setStatu ...

The absence of the 'profileStore' property is noticed in the '{}' type, which is necessary in the 'Readonly<AppProps>' type according to TypeScript error code ts(2741)

I'm currently using MobX React with TypeScript Why am I getting an error with <MainNote/>? Do I just need to set default props? https://i.stack.imgur.com/5L5bq.png The error message states: Property 'profileStore' is missing in typ ...

I attempted to verify the login through postman, but encountered an error in the process

I created the login route on the backend and tested it in Postman, but encountered this error message: https://i.stack.imgur.com/PdyCo.png Below is the code for the login route: router.post("/login", async (req, res) => { try { const user = await ...

adding content to div is becoming less speedy

Currently, I'm developing a drawing board using only html/css/jquery and the drawing functionality is working smoothly. The approach I've taken involves capturing the mousemove events and placing a dot (div) at each point where the event occurs, ...

Display a button in a single row table

Here is my table markup: <table class="table table-condensed"> <thead> <tr> <th>id</th> <th>task</th> <th>date</th> </tr> </thead> ...