Home » vue » How to set reactive locale in all Vue3 Components?

How to set reactive locale in all Vue3 Components?

Posted by: admin November 26, 2021 Leave a comment

Questions:

I have following project structure (index.vue):

<template>
  <div class="container">
    <navbar></navbar>
    <social-media-bar></social-media-bar>
    <main>
      <home></home>
      <news></news>
      <vision></vision>
      <event-section></event-section>
      <artwork></artwork>
      <about></about>
      <donate></donate>
      <contact></contact>
      <partners></partners>
    </main>
    <footer-component></footer-component>
  </div>
</template>

I want to change the app-language from inside navbar.vue:

<template>
  <div class="nav-bar">
    <fa class="icon-locale" @click="toggleLocale" :icon="[ 'fa', 'language' ]" size="2x"></fa>
    <div class="locale-menu" :class="{ locale__open: isActiveLocale }">
      <p @click="toggleLocale(); setLocale('en');">en</p>
      <p @click="toggleLocale(); setLocale('de');">de</p>
      <p @click="toggleLocale(); setLocale('ar');">ar</p>
    </div>
  </div>
</template>

<script setup>
import {ref} from "vue";
import {createI18n} from 'vue-i18n';

const isActiveLocale = ref(false);
const toggleLocale = () => {
    isActiveLocale.value = !isActiveLocale.value;
}
const i18n = createI18n({});
const setLocale = (locale) => {
    i18n.global.locale = locale
};
</script>

Basically this opens a locale menu with en, de, ar locales which start an @click event that changes i18n.global.locale accordingly.

I need to set the newly set i18n.global.locale in the home component.

home.vue:

<template>
  <section id="home" class="home">
    <h2>{{ state.heading[state.locale] }}</h2>
  </section>
</template>


<script setup>
import {reactive} from 'vue';
import {useI18n} from 'vue-i18n';

const {locale} = useI18n()
const loc = locale.value.substring(0, 2)

const state = reactive({
    locale: loc
})
</script>

What I want is to get the newly set i18n.global.locale from navbar.vue into state.locale in home.vue reactively. Since navbar and home are no parent/child, do I have to build an EventBus for this or is there a more elegant solution, maybe with the i18n library?

Edit:

This is the function, that is supposed to change locale globally but it only sets it inside i18n and it looks like the only reactivity possible with that is with i18n‘s messages, which I am not using.

const setLocale = () => {
    i18n.global.locale = 'de'
    console.log(i18n.global.locale);
};

I need to change the locale string globally, so that I can use it in all components reactively.

Answers:

i18n.js

import { createI18n } from "vue-i18n";

export const i18n = createI18n({
  locale: "en",
  messages: {
    en: {
      message: {
        language: "Language",
        hello: "hello world!"
      }
    },
    ja: {
      message: {
        language: "言語",
        hello: "こんにちは、世界!"
      }
    }
  }
});

main.js

import { createApp } from "vue";
import App from "./App.vue";
import { i18n } from "./i18n";

createApp(App).use(i18n).mount("#app");

App.vue

<template>
  <button @click="switch">switch to ja</button>
  <p>{{ $t("message.hello") }}</p>
</template>

<script>
export default {
  name: "App",
  methods: {
    switch() {
      // $i18n is reactively
      this.$i18n.locale = "ja";
    },
  },
};
</script>

###

I found a super easy way to pass around variables between components in vue with sessionStorage. Just define:

sessionStorage.whatever = 'whateverYouWant'

and you can use sessionStorage.whatever in all your components. Other than localStorage, sessionStorage will reset, when the browser/tab is closed.
I am using it to pass around the selected locale.