Como Alternar Dinamicamente o locale do PrimeVue

Hoje, enquanto trabalhava em um projeto desenvolvido com o Nuxt.js, deparei-me com a necessidade de implementar a internacionalização (i18n) para suportar os idiomas português e inglês. Para alcançar esse objetivo, integrei o módulo @nuxtjs/i18n, que facilita a localização do aplicativo.

Além disso, o projeto faz uso do nuxt-primevue, um conjunto abrangente de componentes para Nuxt. A fim de proporcionar uma experiência totalmente localizada, foi necessário configurar não apenas a tradução do aplicativo, mas também dos componentes fornecidos pelo PrimeVue.

Felizmente, o PrimeVue já oferece arquivos de localização para vários idiomas em seu repositório oficial, facilitando a integração com diferentes línguas.

primefaces / primelocale

A configuração da internacionalização para o PrimeVue é relativamente simples. No entanto, surgiu um desafio adicional: a necessidade de alterar dinamicamente o idioma do PrimeVue, sem a necessidade de recarregar a página. Enquanto o @nuxtjs/i18n possibilitava essa troca dinâmica de idiomas para o aplicativo, a mesma funcionalidade para o PrimeVue apresentou algumas dificuldades.

Este artigo visa compartilhar os desafios encontrados durante esse processo e fornecer soluções para esses problemas específicos. A abordagem detalhada aqui visa facilitar a implementação bem-sucedida da internacionalização tanto para o aplicativo quanto para os componentes do PrimeVue, permitindo uma experiência de usuário perfeitamente localizada e dinâmica.


Um dos primeiros problemas que encontrei estava, na verdade, relacionado ao @nuxtjs/i18n. A configuração do módulo estava inicialmente assim:

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' },
		],
	},
})

Como você pode perceber, o i18n estava configurado para ler a pasta 'locales', e um dos detalhes desse módulo que eu não sabia é que ele lê e modifica todos os arquivos contidos nessa pasta. Por não estar ciente desse detalhe, coloquei os locales do PrimeVue dentro dessa pasta da seguinte forma:

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

Desta forma, ao aplicar um desses locales no PrimeVue, o texto dos componentes ficavam da seguinte forma:

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" } }

Como mencionado anteriormente, o i18n irá modificar todos os arquivos na pasta "locale", inclusive o locale do PrimeVue. Portanto, a primeira solução é NÃO colocar o locale do PrimeVue na mesma pasta do módulo i18n. No meu caso, optei por colocá-lo na pasta 'utils', para que fosse automaticamente importado quando eu alterasse dinamicamente o locale.


O segundo problema ocorreu porque eu não estava chamando o usePrimeVue() no topo do bloco setup, mas sim, dentro de uma função. Resumindo o problema, se o seu código estiver da seguinte forma, você encontrará um erro, pois o usePrimeVue() utiliza o inject() do Vue, que está disponível apenas no topo do bloco setup.

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>

A solução é realizar conforme exemplificado no código abaixo, executando o usePrimeVue no início do bloco setup e atribuindo o seu valor a uma variável que pode ser utilizada posteriormente dentro da função responsável por alterar o idioma. Além disso, é possível aproveitar para modificar o idioma do i18n.

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>

E voilà, seu código agora estará funcionando perfeitamente, com o idioma sendo alterado dinamicamente, tanto no módulo do i18n quanto no do PrimeVue! 😊

Se você tiver alguma dúvida ou quiser entrar em contato, sinta-se à vontade para me encontrar em qualquer uma das redes sociais listadas abaixo. Muito obrigado por ler!