useI18n
Panoramica
useI18n è il composable da usare nei componenti Vue per accedere alle traduzioni e cambiare lingua. Lavora su uno stato globale singleton inizializzato da configureI18n: tutti i componenti che invocano useI18n condividono la stessa locale e le stesse translations. Lancia un errore se invocato prima di aver chiamato configureI18n.
Firma
function useI18n<
TLocale extends string = string,
TDict extends TranslationDictionary = TranslationDictionary,
>(): UseI18nReturn<TLocale, TDict>
I generics TLocale e TDict permettono di tipizzare la lingua corrente (es. 'it' | 'en' | 'de') e la struttura del dizionario (per autocompletamento sulle chiavi).
Inizializzazione
import { useI18n } from '@pzeta/vue-i18n'
const { t, locale, setLocale, isLoading, translations } = useI18n()
Tipizzato:
type AppLocale = 'it' | 'en' | 'de'
interface AppDict {
common: { greeting: string }
pages: { home: { title: string } }
}
const { t, locale } = useI18n<AppLocale, AppDict>()
Return
| Proprietà | Tipo | Descrizione |
|---|---|---|
t | (key: string, params?: InterpolationParams) => string | Funzione di traduzione |
locale | ComputedRef<TLocale> | Locale corrente (readonly) |
setLocale | (locale: TLocale) => Promise<void> | Cambio lingua async |
isLoading | ComputedRef<boolean> | Caricamento di una nuova lingua in corso |
translations | ComputedRef<TDict> | Dizionario corrente (accesso diretto) |
t — funzione di traduzione
Naviga il dizionario corrente tramite path dot-notation. Se la chiave non esiste, stampa un warning in console (con warnPrefix configurato) e ritorna la chiave stessa come fallback.
// Traduzione semplice
const title = t('pages.home.title')
// Traduzione con interpolazione
const greeting = t('common.greeting', { name: 'Mario' })
// dizionario: { common: { greeting: 'Ciao {name}!' } } → 'Ciao Mario!'
// Parametri numerici
const counter = t('cart.items', { count: 3, total: 10 })
I segnaposto sono nel formato {nome}. Se un parametro non viene fornito, il segnaposto resta nella stringa così com'è.
Comportamento su chiavi mancanti
const x = t('chiave.inesistente')
// Console: '[i18n] Traduzione mancante: "chiave.inesistente"'
// x === 'chiave.inesistente'
Il fallback alla chiave permette di rendere la UI usabile anche con dizionari incompleti, e di individuare facilmente le traduzioni mancanti in fase di sviluppo.
setLocale — cambio lingua
await setLocale('en')
Comportamento:
- Se la nuova
localeè uguale a quella corrente, non fa nulla. - Fast path: se le traduzioni sono già in cache (preloaded o caricate in precedenza), il cambio è sincrono —
isLoadingnon viene mai settato atrue. - Slow path: se la lingua non è in cache, invoca
loadLocale(lazy import) e settaisLoading=truedurante il caricamento. - Al termine invoca il callback
onLocaleChange(locale)se configurato.
Pattern latest-wins
Se l'utente cambia lingua più volte in rapida successione (es. setLocale('en') → setLocale('de') prima che en finisca di caricarsi), il composable applica solo l'ultima richiesta. Le risposte intermedie vengono scartate per evitare flicker o stati incoerenti.
// Click rapido sui flag della lingua
setLocale('en') // requestId = 1, in caricamento
setLocale('de') // requestId = 2, in caricamento
// → Solo 'de' verrà applicato quando entrambi i load completano
Internamente è implementato con un counter monotono incrementato a ogni setLocale: dopo l'await loader() il composable confronta requestId === latestSetLocaleId prima di scrivere lo stato.
locale — locale corrente
ComputedRef<TLocale> reattivo. Cambia automaticamente al termine di un setLocale riuscito.
<script setup lang="ts">
import { useI18n } from '@pzeta/vue-i18n'
const { locale } = useI18n()
</script>
<template>
<span>Lingua attiva: {{ locale }}</span>
</template>
isLoading — flag di caricamento
ComputedRef<boolean> che indica se è in corso un caricamento async di traduzioni. Utile per mostrare uno spinner durante il cambio lingua:
<template>
<Spinner v-if="isLoading" />
<button :disabled="isLoading" @click="setLocale('en')">EN</button>
</template>
Resta false durante i cambi locali (cache hit).
translations — accesso diretto
Per casi avanzati in cui serve l'intero dizionario (es. iterare opzioni di un select):
const { translations } = useI18n<AppLocale, AppDict>()
const opzioni = computed(() =>
Object.entries(translations.value.menu.voci),
)
Per la maggior parte dei casi è preferibile usare t(key) perché beneficia del logging delle chiavi mancanti.
Note
- Il composable non è scoped al componente:
localeetranslationssono singleton globali. Tutti gliuseI18n()dell'app vedono lo stesso stato. - L'invocazione fuori da un setup Vue è ammessa (es. in service): la reattività funziona comunque grazie ai
refglobali. tè una funzione "stabile" ma non reattiva di per sé — i template Vue che la chiamano sono reattivi perché leggonotranslations.valueindirettamente. Per usaretincomputedowatch, accedere prima alocale.valueotranslations.valueper dichiarare la dipendenza:
const titolo = computed(() => {
// dipendenza esplicita
void locale.value
return t('pages.home.title')
})