Flusso i18n Vue 3 per 500+ chiavi senza sorprese in produzione
Un flusso pratico i18n per Vue 3 in app di grandi dimensioni: naming delle chiavi, plurali, controlli QA e passi di rilascio per evitare traduzioni mancanti in produzione.

Cosa va storto dopo 500+ chiavi i18n
Quando la tua app supera qualche centinaio di stringhe, la prima cosa che si rompe normalmente non è Vue I18n. È la coerenza. Le persone aggiungono chiavi in stili diversi, duplicano la stessa idea con nomi differenti e nessuno è sicuro di quali messaggi si possano eliminare.
Le traduzioni mancanti smettono di essere rare. Appaiono nei percorsi utente normali, soprattutto in schermate meno usate come impostazioni, stati di errore, empty state e notifiche.
Quando manca una traduzione, gli utenti vedono solitamente uno di tre problemi: un'interfaccia vuota (un pulsante senza etichetta), le chiavi raw (come checkout.pay_now), o un fallback strano in cui parte della pagina cambia lingua. Nessuno di questi sembra un bug minore: fanno sembrare l'app rotta.
Per questo motivo un flusso di lavoro i18n per Vue 3 conta più della singola libreria. La libreria farà ciò che le chiedi. Su scala, i team spesso non concordano su cosa significhi "fatto".
Un esempio comune: uno sviluppatore pubblica un nuovo flusso "Invita un collega" con 40 stringhe nuove. Il file inglese viene aggiornato, ma quello francese no. In staging tutto sembra a posto perché il tester usa l'inglese. In produzione gli utenti francesi vedono un misto di UI tradotta e non tradotta, e il supporto riceve screenshot con chiavi raw.
La soluzione è definire cosa significa veramente "fatto" per l'interfaccia tradotta. Non può essere solo "stringhe aggiunte". Una definizione pratica di fatto include di solito: le chiavi seguono regole di naming, i locali si compilano senza avvisi di chiavi mancanti, plurali e variabili rendono correttamente con dati reali, è stata controllata almeno una lingua non predefinita e le modifiche al testo sono tracciate così che le chiavi vecchie non restino in giro.
A 500+ chiavi vinci trattando la localizzazione come un processo di rilascio, non come un'ultima modifica ai file.
Stabilisci poche regole prima di aggiungere altre stringhe
Dopo qualche centinaio di stringhe, il lavoro di traduzione non è la parte disordinata. È la coerenza. Un piccolo insieme di regole rende il tuo flusso i18n Vue 3 prevedibile, anche quando più persone toccano il copy ogni settimana.
Inizia decidendo cos'è un “concetto” e mantenendo una sola fonte di verità per esso. Se la stessa idea UI appare in cinque posti (ad esempio, "Salva modifiche"), vuoi una sola chiave, non cinque varianti come save, saveChanges, save_update e saveBtn. Le chiavi duplicate cambiano significato col tempo e gli utenti percepiscono quella incoerenza.
Poi decidi dove vive la formattazione. I team spesso lo dividono per caso: alcuni messaggi includono punteggiatura e maiuscole, altri si affidano al codice per aggiungerle. Scegli un approccio e mantienilo.
Un default pratico:
- Metti grammatica, punteggiatura e formattazione rivolta all'utente (come “(opzionale)”) nel messaggio.
- Tieni la formattazione dei dati pura nel codice (date, valuta, unità), poi passa il risultato a i18n.
- Usa placeholder per nomi e conteggi, non concatenazioni di stringhe.
- Considera l'HTML nei messaggi un caso speciale con una regola chiara (permesso o non permesso).
Poi definisci proprietà e responsabili. Decidi chi può aggiungere nuove chiavi, chi revisiona il testo nella lingua base e chi approva le altre localizzazioni. Senza questo, le stringhe vengono aggiunte in fretta e non vengono mai revisionate.
Infine, scegli e documenta una strategia di fallback. Se manca una chiave, cosa vedono gli utenti: il nome della chiave, il testo nella lingua predefinita o un messaggio generico sicuro? In produzione molte squadre preferiscono il fallback sulla lingua predefinita più logging, così gli utenti non restano bloccati mentre tu ricevi un segnale che qualcosa non va.
Se costruisci app Vue 3 con un generatore come AppMaster (Vue3 web UI più backend reale), queste regole valgono comunque. Tratta le traduzioni come contenuto di prodotto, non come "semplice testo dev", e eviterai la maggior parte delle sorprese tardive.
Convenzioni di naming delle chiavi che restano leggibili
Oltre qualche centinaio di stringhe, la coerenza è il fattore moltiplicativo più grande. Scegli uno stile di chiave (la maggior parte dei team usa percorsi con punti come billing.invoice.title) e rendilo regola. Mescolare punti, slash, snake_case e casse casuali rende la ricerca e le revisioni lente.
Usa chiavi stabili che sopravvivono ai cambi di copy. Una chiave come "Please enter your email" si rompe appena il marketing la modifica. Preferisci nomi basati sull'intento come auth.email.required o auth.email.invalid.
Raggruppa le chiavi per area prodotto o superficie UI prima, poi per scopo. Pensa alle stesse categorie che la tua app già ha: auth, billing, settings, support, dashboard. Questo rende i file di locale più facili da scorrere e riduce duplicati quando due schermate hanno la stessa idea.
All'interno di ogni area, mantieni un piccolo insieme di pattern per pezzi UI comuni:
- Pulsanti:
*.actions.save,*.actions.cancel - Etichette:
*.fields.email.label,*.fields.password.label - Suggerimenti/aiuto:
*.fields.email.hint - Errori/validazioni:
*.errors.required,*.errors.invalidFormat - Notifiche/toast:
*.notices.saved,*.notices.failed
I messaggi dinamici dovrebbero dire cosa cambia, non come. Nomina il messaggio per intento e usa parametri per le parti variabili. Per esempio, billing.invoice.dueInDays con {days} è più chiaro di billing.invoice.dueIn3Days.
Esempio (funziona bene in un flusso i18n Vue 3): orders.summary.itemsCount con {count} per il numero, e orders.summary.total con {amount} per l'importo. Chi legge la chiave nel codice dovrebbe capire dove appartiene e perché esiste, anche se il copy finale cambia.
Regole per i plurali e formattazione dei messaggi senza sorprese
Il testo plurale si rompe silenziosamente quando tratti ogni lingua come l'inglese. Decidi presto quando userai la sintassi ICU e quando un semplice placeholder basta.
Usa semplici replacement per etichette e testi brevi che non cambiano in base al numero (per esempio, "Welcome, {name}"). Passa a ICU per qualsiasi testo dipendente dal conteggio, perché mantiene tutte le forme in un unico posto e rende le regole esplicite.
{
"notifications.count": "{count, plural, =0 {No notifications} one {# notification} other {# notifications}}"
}
Scrivi i messaggi con conteggio in modo che siano facili da tradurre. Preferisci una frase completa e tieni il placeholder del numero (#) vicino al sostantivo. Evita scorciatoie come riutilizzare la stessa chiave per "1 item" e "2 items" nel codice. I traduttori devono vedere il messaggio intero, non indovinare come verrà assemblato.
Pianifica almeno =0, one e other, e documenta cosa ti aspetti per 0. Alcuni prodotti vogliono "0 items", altri preferiscono "No items". Scegli uno stile e mantienilo per coerenza nell'interfaccia.
Fai attenzione anche alle lingue con più categorie plurali di quelle che ti aspetti. Molte lingue non seguono "uno vs molti". Se aggiungi una nuova localizzazione dopo, un messaggio che ha solo one e other potrebbe risultare grammaticalmente scorretto anche se viene renderizzato.
Prima di spedire, testa i plurali con conteggi reali nell'UI, non limitarti a guardare il JSON. Un controllo rapido che prende la maggior parte dei problemi è: 0, 1, 2, 5 e 21.
Se costruisci una web app Vue3 (per esempio, dentro AppMaster), fai questo test sulla schermata reale dove il testo appare. Problemi di layout, testo troncato e frasi goffe si vedono lì prima.
Organizzare i file di locale per la crescita
Dopo qualche centinaio di stringhe, un unico grande en.json diventa un collo di bottiglia. Le persone toccano lo stesso file, i conflitti di merge aumentano e perdi traccia di dove vive il copy. Una buona struttura mantiene il flusso i18n Vue 3 stabile anche quando il prodotto cambia.
Strutture suggerite
Per 2-5 locali, suddividere per feature è di solito sufficiente. Mantieni la stessa struttura di file in ogni locale così aggiungere una chiave è un'operazione prevedibile.
locales/en/common.json,locales/en/auth.json,locales/en/billing.jsonlocales/es/common.json,locales/es/auth.json,locales/es/billing.jsonlocales/index.ts(carica e unisce i messaggi)
Per 20+ locali, scala la stessa idea ma rendi più difficile il drift. Tratta l'inglese come sorgente di verità ed esigi che ogni locale rispecchi la stessa cartella e i nomi dei file. Se appare un nuovo dominio (per esempio, notifications), dovrebbe esistere in ogni locale anche se il testo è provvisorio.
Dividere per dominio riduce i conflitti di merge perché due persone possono aggiungere stringhe in file diversi senza pestarsi i piedi. I domini dovrebbero corrispondere a come è costruita la tua app: common, navigation, errors, settings, reports, più cartelle feature per aree più grandi.
Mantenere le chiavi consistenti
All'interno di ogni file, mantieni la stessa forma delle chiavi fra i locali: stessa nidificazione, stessi nomi di chiave, testo diverso. Evita chiavi “creative” per lingua, anche se una frase è difficile da tradurre. Se l'inglese ha bisogno di billing.invoice.status.paid, ogni locale deve avere esattamente quella chiave.
Centralizza solo ciò che realmente si ripete ovunque: etichette di pulsanti, errori di validazione generici e navigazione globale. Tieni il copy specifico di una feature vicino al dominio della feature, anche se sembra riutilizzabile. “Save” appartiene a common. “Save payment method” appartiene a billing.
Contenuti di lunga durata
Testi di aiuto lunghi, passaggi di onboarding e template email diventano rapidamente complicati. Alcune regole utili:
- Metti le stringhe lunghe in un dominio a sé (per esempio,
helpoonboarding) ed evita nidificazioni eccessive. - Preferisci paragrafi brevi invece di una stringa enorme, così i traduttori lavorano più sicuri.
- Se marketing o support modificano spesso il testo, tieni quei messaggi in un file dedicato per ridurre il churn altrove.
- Per le email, conserva soggetto e corpo separati e mantieni i placeholder coerenti (nomi, date, importi).
Questa impostazione rende più facile revisionare le modifiche, tradurre con continuità ed evitare falle all'ultimo minuto.
Un workflow passo-passo per aggiungere e rilasciare stringhe
Un flusso i18n Vue 3 stabile dipende meno dagli strumenti e più dal ripetere gli stessi piccoli passi ogni volta. Nuovi testi UI non dovrebbero raggiungere la produzione senza una chiave, un messaggio predefinito e uno stato di traduzione chiaro.
Inizia aggiungendo la chiave alla lingua base (spesso en). Scrivi il testo di default come copy reale, non come placeholder. Questo dà a prodotto e QA qualcosa di leggibile da revisionare e previene "stringhe misteriose" più avanti.
Quando usi la chiave in un componente, includi parametri e la logica dei plurali fin da subito in modo che i traduttori vedano la forma completa del messaggio.
// simple param
$t('billing.invoiceDue', { date: formattedDate })
// plural
$t('files.selected', count, { count })
Se le traduzioni non sono pronte, non lasciare chiavi mancanti. Aggiungi traduzioni placeholder nelle altre lingue o segnale come pending in modo coerente (per esempio, prefissa il valore con TODO:). L'importante è che l'app venga renderizzata in modo prevedibile e che i revisori individuino il copy incompleto.
Prima del merge, esegui controlli automatici rapidi. Falli noiosi e severi: chiavi mancanti tra i locali, chiavi non usate, mismatch di placeholder (manca {count}, {date} o parentesi graffe sbagliate), forme plurali invalide per le lingue supportate e sovrascritture accidentali.
Infine, fai un breve controllo UI in almeno una lingua non base. Scegli una lingua con stringhe più lunghe (spesso tedesco o francese) per catturare overflow, pulsanti troncati e interruzioni di linea sfortunate. Se la tua UI Vue 3 è generata o mantenuta insieme ad altre parti del prodotto (per esempio, una web app Vue3 prodotta da AppMaster), questo passaggio conta ancora perché i layout cambiano con le nuove feature.
Tratta questi passi come la tua definizione di fatto per qualunque feature che aggiunge testo.
Errori comuni che i team continuano a ripetere
Il modo più rapido per rendere la localizzazione dolorosa è trattare le chiavi i18n come "semplici stringhe." Dopo qualche centinaio di chiavi, piccole abitudini si trasformano in bug di produzione.
Chiavi che si spostano, collidono o mentono
Errori di battitura e differenze di maiuscole sono cause classiche di testo mancante: checkout.title in un punto, Checkout.title in un altro. Sembra a posto in code review, poi la lingua di fallback viene inviata in produzione.
Un altro problema comune è riutilizzare una chiave per significati diversi. “Open” potrebbe significare “Apri ticket” in una schermata di supporto e “Apri ora” in una pagina di store. Se riusi una singola chiave, una di queste schermate sarà sbagliata in altre lingue e i traduttori dovranno indovinare.
Una regola semplice aiuta: una chiave = un significato. Se il significato cambia, crea una nuova chiave anche se l'inglese è identico.
Bug di layout causati da assunzioni sulla forma delle stringhe
I team spesso hardcodano punteggiatura, spazi o parti di HTML nelle traduzioni. Funziona finché una lingua non richiede punteggiatura diversa o la UI non esegue escaping o renderizza il markup in modo differente. Tieni le decisioni sul markup nei template e concentra i messaggi sul testo.
Il mobile è dove i problemi si nascondono. Un'etichetta che entra in inglese può andare a capo in tre righe in tedesco o traboccare in thai. Se testi solo una dimensione schermo, lo perdi.
Fai attenzione ai recidivi: presupporre l'ordine inglese delle parole quando inserisci variabili (nomi, conteggi, date), costruire messaggi concatenando pezzi invece di usare un messaggio unico, dimenticare di testare valori lunghi (nomi prodotto, indirizzi, dettagli errore), spedire con fallback silenzioso abilitato così le chiavi mancanti sembrano "a posto" in inglese, e copiare/incollare chiavi modificando solo il valore inglese.
Se vuoi un flusso i18n Vue 3 che resti tranquillo a 500+ chiavi, tratta le chiavi come parte della tua API: stabili, specifiche e testate come tutto il resto.
Passi QA che catturano le traduzioni mancanti presto
Le traduzioni mancanti sono facili da perdere perché l'app continua a “funzionare”. Semplicemente ricade sulla chiave, sulla lingua sbagliata o su una stringa vuota. Tratta la copertura delle traduzioni come test: vuoi feedback rapido prima che qualcosa raggiunga la produzione.
Controlli automatici (eseguiti su ogni PR)
Inizia con controlli che falliscono la build, non solo avvisi che nessuno legge.
- Scansiona il codice per
$t('...')et('...')e verifica che ogni chiave usata esista nella lingua base. - Confronta gli insiemi di chiavi tra i locali e fai fallire se manca una chiave in un locale (a meno che la chiave sia in una short exception list visionata, tipo "en-only legal notes").
- Segnala chiavi orfane che esistono nei file di locale ma non sono mai usate.
- Valida la sintassi dei messaggi (placeholder, blocchi ICU/plural). Un singolo messaggio rotto può mandare in crash una pagina a runtime.
- Considera errori duplicati di chiavi o maiuscole incoerenti come errori.
Mantieni la lista delle eccezioni corta e gestita dal team, non dal "qualsiasi cosa passi la CI".
Controlli runtime e visivi (staging)
Anche con CI, vuoi comunque una rete di sicurezza in staging perché i percorsi utente reali attivano stringhe che hai dimenticato dinamiche.
Abilita il logging delle traduzioni mancanti in staging e includi abbastanza contesto per risolvere in fretta: locale, route, nome del componente (se disponibile) e la chiave mancante. Rendilo rumoroso. Se è facile ignorarlo, verrà ignorato.
Aggiungi una pseudo-locale e usala per un rapido controllo UI. Un approccio semplice è trasformare ogni stringa (renderla più lunga e aggiungere marcatori) così i problemi di layout saltano all'occhio, per esempio: [!!! 𝗧𝗲𝘀𝘁 𝗲𝘀𝗽𝗮𝗻𝘀𝗼 !!!]. Questo cattura pulsanti troncati, header di tabelle spezzati e spaziature mancanti prima della pubblicazione.
Infine, fai un breve controllo pre-release dei flussi a più alto valore in 2-3 locali: accesso, checkout/pagamento, impostazioni core e la nuova feature che stai rilasciando. Qui trovi i bug tipo “è stato tradotto ma il placeholder è sbagliato”.
Gestire nuove lingue e aggiornamenti continui del copy
Aggiungere una nuova lingua diventa caotico se lo tratti come "lavoro copy" invece che come un piccolo rilascio di prodotto. Il modo più semplice per mantenere stabile il flusso i18n Vue 3 è fare in modo che l'app si compili anche quando un locale è incompleto, rendendo però le lacune evidenti prima che gli utenti le vedano.
Quando aggiungi un nuovo locale, comincia generando la stessa struttura di file della lingua sorgente (spesso en). Traduci dopo, struttura prima.
- Crea la nuova cartella/il nuovo file locale con l'intero set di chiavi copiato dalla sorgente.
- Segna i valori come placeholder TODO così le stringhe mancanti sono visibili in QA.
- Aggiungi la lingua allo switcher solo dopo che i fondamentali sono coperti.
- Esegui un controllo schermo per schermo per catturare problemi di layout (parole più lunghe, andata a capo).
Le traduzioni spesso arrivano in ritardo, quindi decidi in anticipo cosa significa "parziale" per il tuo prodotto. Se una feature è rivolta ai clienti, considera un feature flag così la feature e le sue stringhe vengano rilasciate insieme. Se devi rilasciare senza traduzioni complete, preferisci un fallback chiaro (come l'inglese) rispetto a etichette vuote, ma rendilo evidente in staging.
Gli aggiornamenti del copy sono dove i team rompono le chiavi. Se cambi il testo, mantieni stabile la chiave. Le chiavi dovrebbero descrivere l'intento, non la frase esatta. Salva il rename della chiave per quando cambia il significato e falla con una migrazione controllata.
Per evitare "stringhe zombie", depreca le chiavi intenzionalmente: segnala la deprecazione con una data e la chiave sostitutiva, mantienile per un ciclo di rilascio, poi rimuovile solo dopo aver confermato che non ci sono riferimenti.
Tieni le note di traduzione vicine alla chiave. Se il tuo formato JSON non supporta commenti, conserva note in un documento companion o in un file metadata adiacente (per esempio, "usato nella schermata di successo checkout"). Questo è particolarmente utile quando la tua app Vue 3 è generata da uno strumento come AppMaster e più persone toccano copy e UI.
Esempio: rilasciare una feature con 60 nuove stringhe
In uno sprint, il team rilascia tre cose insieme: una nuova pagina Impostazioni, una schermata Billing e tre template email (ricevuta, pagamento fallito, fine trial). Sono circa 60 nuove stringhe, ed è qui che di solito nascono i problemi i18n.
Il team concorda di raggruppare le chiavi per feature, poi per superficie. Viene creato un nuovo file per ogni feature e le chiavi seguono lo stesso pattern ovunque: feature.area.element.
// settings
"settings.profile.title": "Profile",
"settings.security.mfa.enable": "Enable two-factor authentication",
// billing
"billing.plan.current": "Current plan",
"billing.invoice.count": "{count} invoice | {count} invoices",
// email
"email.receipt.subject": "Your receipt",
"email.payment_failed.cta": "Update payment method"
Prima che inizi il lavoro di traduzione, le stringhe plurali vengono testate con valori reali, non con supposizioni. Per billing.invoice.count, QA controlla 0, 1, 2 e 5 usando dati preimpostati (o un semplice toggle dev). Questo cattura casi strani come "0 invoice".
QA poi esegue un flusso mirato che tende a far emergere chiavi mancanti: aprire Settings e Billing e cliccare ogni tab una volta, innescare ogni template email in staging con account di test, eseguire l'app con una lingua non predefinita attiva e far fallire la build se nei log compaiono avvisi di traduzioni mancanti.
In questo sprint QA trova due chiavi mancanti: un'etichetta nella schermata Billing e un oggetto email. Il team le sistema prima del rilascio.
Quando decidono se bloccare il rilascio o permettere il fallback, usano una regola semplice: schermate rivolte agli utenti e email transazionali bloccano il rilascio; testi a basso rischio visibili solo ad admin possono temporaneamente ricadere sulla lingua predefinita, ma solo con un ticket e una deadline chiara.
Prossimi passi e una semplice checklist di rilascio
Un flusso i18n Vue 3 resta stabile quando tratti le traduzioni come codice: aggiungile sempre nello stesso modo, testale e tieni il punteggio.
Checklist di rilascio (5 minuti prima del merge)
- Chiavi: seguono il pattern di naming e mantengono lo scope chiaro (pagina, feature, componente).
- Plurali: conferma che le forme plurali rendono correttamente in almeno una lingua con regole plurali multiple.
- Placeholders: verifica che le variabili siano presenti, abbiano gli stessi nomi ovunque e risultino corrette con dati reali.
- Fallback: conferma che il comportamento per le chiavi mancanti corrisponda alla policy attuale.
- Schermate: controlla rapidamente le poche schermate più a rischio (tabelle, toast, modali, empty states).
Decidi cosa misurare (così i problemi emergono presto)
Scegli alcuni numeri semplici e rivedili regolarmente: tasso di chiavi mancanti nei test, conteggio di stringhe non tradotte in lingue non predefinite e numero di chiavi non usate (stringhe che non appaiono più da nessuna parte). Tracciali per rilascio se puoi, così vedi le tendenze invece che problemi singoli.
Scrivi i passaggi esatti per aggiungere una stringa, aggiornare le traduzioni e verificare il risultato. Mantienilo breve e includi esempi di nomi chiave e uso dei plurali. I nuovi contributori dovrebbero poterlo seguire senza chiedere.
Se costruisci strumenti interni, AppMaster (appmaster.io) può essere un modo pratico per mantenere coerenti copy dell'interfaccia e chiavi di traduzione attraverso una web app Vue3 e app mobili companion, dato che tutto è gestito in un unico posto.
Programma un piccolo compito di salute i18n ogni sprint: elimina chiavi morte, sistema placeholder incoerenti e rivedi i recenti missing. Piccole pulizie battono le cacce emergenziali alle traduzioni in produzione.


