Vue I18n

vue-i18n

Composable leggero per internazionalizzazione Vue 3 con lazy loading e cache.

Panoramica

@pzeta/vue-i18n è un sistema i18n leggero per Vue 3 senza dipendenze da vue-i18n. Supporta:

  • Lazy loading delle traduzioni per lingua
  • Dizionario pre-caricato per la lingua di default (bundle iniziale)
  • Cache automatica delle lingue già caricate
  • Interpolazione con parametri {name}
  • Fallback locale configurabile
  • Pattern latest-wins per cambio lingua concorrente

Installazione

npm install @pzeta/vue-i18n

Configurazione

Chiamare configureI18n() una sola volta prima di montare l'app:

// main.ts
import { configureI18n } from '@pzeta/vue-i18n'
import itLocale from './locales/it'

configureI18n({
  defaultLocale: 'it',
  fallbackLocale: 'it',
  locales: {
    it: {
      // Preloaded: incluso nel bundle, nessun fetch aggiuntivo
      loader: () => Promise.resolve({ default: itLocale }),
      preloaded: itLocale,
    },
    en: {
      // Lazy: caricato solo quando richiesto
      loader: () => import('./locales/en'),
    },
    de: {
      loader: () => import('./locales/de'),
    },
  },
  onLocaleChange: (locale) => {
    document.documentElement.lang = locale
    localStorage.setItem('locale', locale)
  },
  warnPrefix: '[my-app]',
})

I18nConfig

CampoTipoDefaultDescrizione
defaultLocalestringLingua iniziale
fallbackLocalestringFallback se traduzione mancante
localesRecord<locale, LocaleConfig>Configurazione per ogni lingua
onLocaleChange(locale) => voidCallback al cambio lingua
warnPrefixstring'[i18n]'Prefisso warning console

useI18n

import { useI18n } from '@pzeta/vue-i18n'

const { t, locale, isLoading, setLocale, translations } = useI18n()

Traduzione semplice

t('pages.home.title')
// → "Home"

Traduzione con parametri

I parametri usano la sintassi {nomeparametro}:

t('common.greeting', { name: 'Mario' })
// locale: { common: { greeting: 'Ciao {name}!' } }
// → "Ciao Mario!"

t('common.counter', { count: 3, total: 10 })
// locale: { common: { counter: '{count} di {total} elementi' } }
// → "3 di 10 elementi"

Cambio lingua

// Lazy load + cache automatica
await setLocale('en')

// isLoading.value = true durante il fetch
// Al secondo cambio alla stessa lingua: cache hit, sincrono

Traduzione mancante

Se la chiave non esiste, t() restituisce la chiave stessa e lancia un console.warn:

[my-app] Traduzione mancante: "pages.missing.key"

Struttura file traduzioni

// locales/it.ts
export default {
  common: {
    save: 'Salva',
    cancel: 'Annulla',
    greeting: 'Ciao {name}!',
  },
  pages: {
    home: { title: 'Home' },
    users: { title: 'Utenti', count: '{count} utenti' },
  },
}

TypeScript — dizionario tipato

import type { TranslationDictionary } from '@pzeta/vue-i18n'
import itLocale from './locales/it'

type AppDict = typeof itLocale

// useI18n con tipo — t() autocompleta le chiavi
const { t } = useI18n<'it' | 'en', AppDict>()

Utility loader

import { loadLocale, isLocaleLoaded, getLocaleFromCache } from '@pzeta/vue-i18n'

// Precarica una lingua senza cambiarla
await loadLocale('en')

// Controlla se già in cache
if (isLocaleLoaded('en')) { ... }

// Accesso diretto alla cache
const dict = getLocaleFromCache('en')

Testing

import { initI18n, resetI18n } from '@pzeta/vue-i18n'

beforeEach(() => initI18n({ it: { greeting: 'Ciao {name}!' } }))
afterEach(() => resetI18n())

initI18n e resetI18n sono utility specifiche per test — non usarle in produzione.