Reputation: 3987
I'm building a web app using Nuxt v2.15 and @nuxtjs/i18n v7.2. I'm using Vuex for state management. In my global state, I want to create a getter that returns a value based on this.$i18n.locale
.
What is the best way to access the current app context, which has $i18n
attached to it, 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>
What I expect
I expect to be able to access this.$i18n
from a Vuex getter, or to have some means of doing so.
What actually happens
In the getter method, this
is undefined.
TypeError: Cannot read properties of undefined (reading '$i18n')
What I've tried
I see here that a getter is passed four arguments: state
, getters
, rootState
, and rootGetters
.
I've tried:
state.$i18n
$i18n: this.$i18n
to the root stateUpvotes: 6
Views: 5490
Reputation: 1
In Nuxt 2 if your page renders on frontend you can try to access $i18n
using window.$nuxt
or simply $nuxt
:
export const getters = {
loginOpts() {
const locale = window.$nuxt.$i18n.locale;
...
},
};
Upvotes: 0
Reputation: 9
The simple way we did in our project is like below: In component computed prop
teamsForSelector() {
return this.$store.getters['company/teamsForSelector'](this.$i18n);
}
and in 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; }
Upvotes: 0
Reputation: 3987
After digging through docs, experimenting, and discussing with the folks who were kind enough to offer answers here, it is clear that i18n
is not directly accessible in a Vuex getter method, despite the fact that @nuxt/i18n registers a Vuex module called i18n
and everything I've read about Vuex modules suggests this should be possible.
I did however come across the docs for @nuxt/i18n callbacks, which led me to create a small plugin that sets the value of locale
and uiLocales
in the global state using a mutation.
The end result looks like this:
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>
Upvotes: 1
Reputation: 1523
I had a similar problem last week where I absolutely needed to use i18n inside a vuex getter.
I wouldn't recommend this as its probably not the most performant thing in the world but it worked for me and solved a huge problem while I was working on 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) // The secret sauce
};
},
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) => { // App is the secret sauce from earlier
const locale = app.$i18n.locale;
const uiLocales = [locale];
if (locale === "zh") {
uiLocales.push("zh-CN");
}
return { params: { ui_locales: uiLocales } };
},
};
Upvotes: 3
Reputation: 46814
You can access a the locale in an Vuex action with: this.app.i18n.locale
.
This cannot be accessed in a state
or getter
(a getter is a not a place for it anyway IMO).
PS: The above means that means that you can access this value anywhere you have access to the Nuxt context.
Upvotes: 0