How to switch PrimeVue locale dynamically

Today, while working on a project built with the Nuxt.js, I found myself in the need to implement internationalization (i18n) to support both Portuguese and English languages. To achieve this goal, I integrated the @nuxtjs/i18n module, which facilitates the localization of the application.

Additionally, the project makes use of nuxt-primevue, a comprehensive set of components for Nuxt. In order to provide a fully localized experience, it was necessary to configure not only the translation of the application but also the components provided by PrimeVue.

Fortunately, PrimeVue already offers localization files for various languages in its official repository, simplifying the integration with different language settings.

primefaces / primelocale

The configuration for internationalization in PrimeVue is relatively straightforward. However, an additional challenge arose: the need to dynamically change the language of PrimeVue without reloading the page. While @nuxtjs/i18n enabled this dynamic language switching for the application, achieving the same functionality for PrimeVue components posed some difficulties.

This article aims to share the challenges encountered during this process and provide solutions for these specific problems. The detailed approach outlined here is intended to facilitate the successful implementation of internationalization for both the application and PrimeVue components, enabling a seamlessly localized and dynamic user experience.


One of the initial issues I encountered was actually related to @nuxtjs/i18n. The module configuration was initially set up as follows:

nuxt.config.ts
export default defineNuxtConfig({
	i18n: {
		baseUrl: 'https://example.com/',
		defaultLocale: 'en',
		langDir: 'locales',
		locales: [
			{ code: 'en', iso: 'en-US', name: 'English (US)', file: 'en.ts' },
			{ code: 'pt', iso: 'pt-BR', name: 'Português (BR)', file: 'pt.ts' },
		],
	},
})

As you can see, the i18n was configured to read the 'locales' folder, and one detail about this module that I wasn't aware of is that it reads and modifies all files contained in that folder. Unaware of this detail, I placed the PrimeVue locales within this folder in the following manner:

/locales
----/en.ts
----/pt.ts
----/primeEN.ts
----/primePT.ts
			

In this manner, when applying one of these locales to PrimeVue, the components text appeared as follows:

Primevue Component Text
{ "type": 0, "start": 0, "end": 2, "loc": { "start": { "line": 1, "column": 1, "offset": 0 }, "end": { "line": 1, "column": 3, "offset": 2 }, "source": "Fr" }, "body": { "type": 2, "start": 0, "end": 2, "loc": { "start": { "line": 1, "column": 1, "offset": 0 }, "end": { "line": 1, "column": 3, "offset": 2 } }, "items": [ { "type": 3, "start": 0, "end": 2, "loc": { "start": { "line": 1, "column": 1, "offset": 0 }, "end": { "line": 1, "column": 3, "offset": 2 } } } ], "static": "Fr" } }

As mentioned above, i18n will modify all files in the 'locale' folder, including the PrimeVue locale. So, the first solution is NOT to place the PrimeVue locale in the same folder as the i18n module. In my case, I placed it in the 'utils' folder, allowing it to be automatically imported when I dynamically changed the locale.


The second issue occurred because I was not calling usePrimeVue() at the top of the setup block; instead, I placed it inside a function. In summary, if your code is structured in the following way, you will encounter an error, as usePrimeVue() utilizes Vue's inject(), which is only available at the top of the setup block.

components/Navbar.vue
<script setup lang="ts">
const { locale, setLocale, t } = useI18n()

function changeLang() {
	const primeConfig = usePrimeVue()
	// Warns [Vue warn]: inject() can only be used inside setup() or functional components.
	// Throws Uncaught Error: PrimeVue is not installed!
	if (locale.value === 'en') {
		setLocale('pt')
		primeConfig.config.locale = primept
	}
	else {
		setLocale('en')
		primeConfig.config.locale = primeen
	}
}
</script>

The solution is to follow the code example below, executing usePrimeVue at the top of the setup block and assigning its value to a variable that can be used later within the function responsible for changing the language. Additionally, it is possible to change the language of i18n simultaneously.

components/Navbar.vue
<script setup lang="ts">
const { locale, setLocale, t } = useI18n()

const primeConfig = usePrimeVue()

onMounted(() => {
	if (locale.value === 'en')
		primeConfig.config.locale = primeen
	else
		primeConfig.config.locale = primept
})

function changeLang() {
	if (locale.value === 'en') {
		setLocale('pt')
		primeConfig.config.locale = primept
	}
	else {
		setLocale('en')
		primeConfig.config.locale = primeen
	}
}
</script>

<template>
	<button aria-label="Switch Language" @click="changeLang">
		<Icon
			:name="locale === 'pt' ? 'openmoji:flag-brazil' : 'openmoji:flag-united-states'"
			size="24"
		/>
	</button>
</template>

And voilà, your code is now working perfectly, with the language dynamically changing in both the i18n and PrimeVue modules! 😊

If you have any questions or would like to get in touch, feel free to reach out to me on any of the social media platforms listed below. Thank you very much for reading!