Vai al contenuto
1 settembre 202611 min readGuides

Gestire i file di traduzione senza modificare il JSON a mano

La gestione dei file di traduzione (translation file management) è la pratica di mantenere i file da cui un'applicazione carica le sue traduzioni (JSON, YAML, .resx, .po, .strings e formati simili) completi, validi e sincronizzati con il codice che li usa, senza che sviluppatori o traduttori modifichino quei file a mano. Nella maggior parte delle configurazioni i file continuano a esistere. Cambia il loro ruolo: diventano un output del workflow di traduzione invece che la sua interfaccia utente.

Questo articolo racconta come i team finiscono per modificare a mano i file di traduzione, cosa si rompe quando lo fanno, come sono fatte davvero le alternative, e cosa un cambio di workflow non sistema.

Fatti chiave
  • Un file di traduzione è un input di build, non un documento: una virgola finale o una virgoletta non escapata lo rende invalido, e un file invalido di solito fallisce silenziosamente a runtime.
  • La modifica manuale scala male su due assi contemporaneamente: il numero di lingue e il numero di persone che devono cambiare testo. Uno sviluppatore con due lingue va bene; un traduttore in una pull request no.
  • Cosa si rompe: conflitti di merge sui file di lingua, deriva tra file e codice (chiavi mancanti e orfane), chiavi senza proprietario, un deploy per ogni refuso, e terminologia che varia tra i file senza alcuna vista trasversale.
  • Cosa elimina la modifica manuale: chiavi che nascono nel codice (estrazione o segnalazione a runtime), un editor per le persone che scrivono testo, e file generati da un passaggio di sincronizzazione o sostituiti dalla distribuzione via CDN. Gli agenti di codice possono contribuire con bozze; non sostituiscono questo livello.

Perché i team finiscono per modificare a mano i file di traduzione

Nessuno lo sceglie come strategia. Tutto comincia con la decisione ovviamente corretta: i18next, react-intl, vue-i18n e i loro simili caricano un file JSON per lingua, quindi il primo sviluppatore crea en/common.json, aggiunge de/common.json e modifica entrambi nell'editor di codice. Chiavi annidate o piatte, placeholder {{count}}, suffissi di plurale _one e _other: con una persona e due lingue, modificare il file è lo strumento di traduzione, e pure buono.

Poi gli utenti di quello strumento cambiano mentre lo strumento resta. Arriva una terza lingua con una collega che la parla. Un product manager vuole correggere un'etichetta prima della demo. Una traduttrice di agenzia consegna il polacco. Ognuno di loro riceve esattamente ciò che aveva il primo sviluppatore: un file con sintassi rigida, senza contesto, con un workflow git intorno. La configurazione non è peggiorata. Le persone che la usano hanno smesso di essere sviluppatori.

Il formato stesso aggiunge trappole invisibili finché non scattano. JSON non ammette virgole finali, apici singoli né virgolette non escapate dentro le stringhe. Le forme plurali sono codificate come suffissi delle chiavi che differiscono tra le convenzioni JSON v3 e v4 di i18next (il riferimento del formato JSON le descrive entrambe). Un placeholder rinominato in una lingua viene mostrato letteralmente sullo schermo. E poiché il file viene caricato a runtime, un errore di sintassi non fa fallire il build; fa fallire la pagina, per gli utenti di quella lingua, dopo il deploy.

Cosa si rompe

Conflitti di merge sul file più noioso del repository

Due branch di funzionalità aggiungono entrambi chiavi a common.json. JSON non ha alcuna semantica di merge: il conflitto finisce sulla parentesi graffa di chiusura, qualcuno lo risolve a mano, e le chiavi di uno dei due branch spariscono in silenzio. In molti repository front-end i file di lingua sono il tipo di file con il tasso di conflitto più alto, proprio perché ogni funzionalità li tocca e nessuno se ne sente proprietario.

Deriva tra file e codice

Il codice fa riferimento a chiavi che nessun file contiene, quindi l'interfaccia mostra il nome della chiave o il testo inglese di riserva. I file contengono chiavi a cui nessun codice fa più riferimento, quindi i traduttori continuano a tradurre stringhe morte. Il file inglese è stato aggiornato, quello tedesco no, e niente segnala il valore tedesco come obsoleto. Nel giro di un anno i file di lingua divergono strutturalmente, e l'unico modo per accorgersene è confrontarli a mano.

Traduttori in git

Nel momento in cui un traduttore modifica un file, il workflow pretende una pull request. Il revisore non può giudicare il polacco, quindi controlla il diff per la sintassi. Il traduttore non vede dove compare la stringa, cosa conterrà {{name}} o se il pulsante è abbastanza largo. In pratica la correzione viaggia come messaggio in chat che uno sviluppatore incolla nel file, cioè modifica manuale con un passaggio in più.

Chiavi senza proprietario

I nomi delle chiavi si decidono pull request per pull request. btn.save, actions.save e common.save convivono e nessuno sa se debbano essere diversi. Rinominare una chiave significa toccare ogni file di lingua. Cancellarne una significa sperare che nessuna schermata la usi ancora. Il file non ha alcuna nozione di chi ha creato una chiave, quando o perché.

Un deploy per ogni refuso

In una configurazione basata su file, una modifica di traduzione è una modifica di codice: commit, build, deploy. Un'etichetta sbagliata in italiano parte con il prossimo rilascio, a meno che qualcuno non faccia un hotfix in produzione per una stringa. I team imparano a raggruppare le correzioni di traduzione, che è un modo gentile per dire lasciarle rotte per un po'.

La coerenza tra i file è invisibile

Lo stesso termine di partenza è tradotto in tre modi diversi tra i namespace, e nessuno strumento a livello di file può mostrarvelo, perché il disaccordo vive tra i file, non dentro uno di essi. È la classe di difetti più diffusa nei dati reali di traduzione, e quella che la revisione manuale coglie peggio; i numeri sono in cosa si rompe davvero nelle traduzioni.

Come i team gestiscono i file di traduzione oggi

La maggior parte dei team si trova in una di cinque configurazioni, e il quadro onesto è che ognuna di esse è giusta per qualcuno.

  • Un editor di codice e delle convenzioni. VS Code con validazione JSON e un'estensione come i18n Ally che mostra lo stato di traduzione per lingua. Funziona per uno sviluppatore da solo o per un piccolo team in cui chiunque modifichi testo sa leggere il formato. Smette di funzionare il giorno in cui un non sviluppatore deve cambiare una stringa. Se siete a questo punto, la FAQ su come aprire e modificare i file JSON è la guida pragmatica.
  • Andata e ritorno con fogli di calcolo. Esportare il file in un foglio, mandarlo ai traduttori, reimportare il risultato con uno script. Familiare per i traduttori, e un problema di istantanea per tutti gli altri: foglio e file divergono mentre la traduzione è in corso, e la fusione al ritorno è di nuovo manuale.
  • Script e sincronizzazione in CI. Uno strumento estrae le chiavi dal codice sorgente (per i18next, i18next-cli extract), uno script o una GitHub Action le invia a un servizio e recupera i file tradotti, eventualmente con traduzione automatica o IA nel mezzo. Questo mantiene i file generati e gli sviluppatori lontani da essi. Serve comunque un editor dall'altra parte per le persone che revisionano e correggono, e non risponde da solo alle domande su proprietà e coerenza.
  • Un sistema di gestione delle traduzioni. Le chiavi arrivano dal codice, i traduttori lavorano in un editor con contesto e terminologia, i file vengono esportati o sincronizzati nei formati che il build si aspetta, oppure distribuiti via CDN così che il build smetta di averne bisogno. È la configurazione in cui le altre quattro crescono non appena più di una persona scrive testo.
  • Agenti di codice che modificano i file. L'opzione più recente: un agente aggiunge la chiave a tutti e dodici i file di lingua, abbozza le traduzioni e apre la pull request. Nella parte meccanica è davvero bravo. Reintroduce però anche il problema originale a velocità maggiore: testo che nessuno ha revisionato, terminologia che varia tra un'esecuzione e l'altra, e nessuna traccia oltre a un commit fatto da un bot. Cosa fallisce nelle pipeline solo IA, e la strada per uscirne, è descritto in quando le traduzioni IA si rompono.

Cosa elimina davvero la modifica manuale

A prescindere dallo strumento, quattro proprietà separano un workflow in cui nessuno modifica i file di traduzione da uno in cui qualcuno lo fa ancora.

  1. Le chiavi nascono nel codice, non nei file. O un passaggio di estrazione statica legge le chiamate di traduzione, o l'applicazione in esecuzione segnala una chiave la prima volta che viene usata. In entrambi i casi uno sviluppatore non apre mai un file di lingua per aggiungere una voce.
  2. Le persone che scrivono testo hanno un editor. Testo di partenza, placeholder, screenshot, glossario, cronologia della chiave, tutte le lingue affiancate. Un traduttore che vede il pulsante non deve indovinarne la larghezza.
  3. I file sono generati o assenti. O un passaggio di sincronizzazione o download scrive i file nel formato che il build si aspetta, preservando struttura e forme plurali nell'andata e ritorno, oppure l'applicazione carica le traduzioni a runtime e il repository non contiene alcun file di lingua. La sincronizzazione basata sulle differenze conta qui: una pull request dovrebbe tradurre solo le chiavi che ha aggiunto, non rispedire l'intero progetto.
  4. Ogni modifica ha un proprietario e una traccia. Chi ha aggiunto la chiave, chi l'ha tradotta, chi l'ha approvata, quando è stata pubblicata. Un file non ha niente di tutto questo; una pull request ne ha una frazione.

Cosa questo non risolve

Eliminare la modifica dei file elimina una seccatura. Non elimina le parti davvero difficili della localizzazione, e un cambio di workflow non andrebbe venduto come se lo facesse.

  • La strategia delle chiavi resta vostra. Chiavi in linguaggio naturale o identificatori stabili, namespace per funzionalità o per pagina: uno strumento sposta le chiavi, non le progetta. I compromessi sono nella guida alla denominazione delle chiavi i18n.
  • L'ambiguità ha ancora bisogno di un umano che la noti. "Open" come verbo e "Open" come stato possono richiedere due traduzioni; nessun passaggio di sincronizzazione se ne accorge. Le funzioni di contesto e gli screenshot aiutano il traduttore una volta che qualcuno ha segnalato il caso.
  • La qualità è un livello a parte. Una terminologia che non deve derivare, un registro che non deve ribaltarsi a metà applicazione, e la domanda su chi ha approvato una traduzione sono gestiti da un glossario, da un workflow di revisione e da controlli QA automatici, non da dove stanno i file.
  • A volte il file è lo strumento giusto. Uno sviluppatore, due lingue che sa leggere, nessun fatturato che dipenda dal testo: un editor di codice è la configurazione corretta più economica. Il segnale per cambiare è la seconda persona che ha bisogno di modificare testo.

Come funziona in Locize

Locize è costruito attorno alle quattro proprietà qui sopra, prima per l'ecosistema i18next e, tramite la CLI, per gli altri formati.

  • Chiavi dal codice. Con i18next-locize-backend e saveMissing: true (limitato allo sviluppo, così la produzione resta in sola lettura), ogni chiave che l'applicazione mostra per la prima volta viene creata nel progetto con il suo valore predefinito; locizify fa lo stesso per i siti statici con un solo tag script. Preferite una pipeline statica? i18next-cli extract seguito da locize-sync, oppure locize sync per JSON, YAML, XLIFF, CSV, PO, RESX, Fluent, Properties e altri formati, come descritto nella documentazione della CLI.
  • Un editor per chiunque scriva testo. La vista CAT mostra tutte le lingue di una chiave affiancate, con filtri per i valori non tradotti e da revisionare, azioni in blocco, import ed export nei formati supportati, e una cronologia per chiave che registra chi ha cambiato cosa e quando.
L'editor di traduzione di Locize: tutte le lingue di una chiave affiancate, con filtri, azioni in blocco e assistente IA
L'editor di traduzione di Locize: tutte le lingue di una chiave affiancate, con filtri, azioni in blocco e assistente IA
  • File generati, o nessun file. locize download e le GitHub Actions scrivono i file che il vostro build si aspetta; locize sync --changed-only limita una pull request alle chiavi che ha davvero modificato (locize-cli 12.7 o successivo, i18next-cli 1.72 o successivo). Oppure fate a meno dei file: le traduzioni vengono pubblicate sul CDN per impostazione predefinita, e l'applicazione le carica a runtime, così una correzione va online senza commit né redeploy.
  • Prime bozze, anch'esse senza file. Le nuove chiavi nella lingua di riferimento vengono tradotte in ogni lingua di destinazione dalla traduzione automatica, con il glossario e la guida di stile del progetto inseriti nella richiesta, e contrassegnate da revisionare perché una persona le confermi nell'editor invece che in un diff.

Il file JSON non sparisce dalla vostra vita; smette di essere il posto in cui avviene la traduzione. Se volete vedere la differenza sul vostro progetto, create un progetto, importate i file che avete oggi, e guardate la prossima chiave arrivare dal vostro codice invece che dalla vostra tastiera.

Domande frequenti

Come gestisco i file di traduzione senza modificare il JSON a mano? Rendete i file un output del workflow invece che la sua interfaccia utente. Le chiavi nascono dal codice, per estrazione in CI o per segnalazione a runtime come l'opzione saveMissing di i18next; i traduttori lavorano in un editor con testo di partenza, placeholder e terminologia davanti agli occhi; i file JSON, YAML o resx vengono generati da un passaggio di sincronizzazione o download, oppure sostituiti dalla distribuzione via CDN.

I traduttori dovrebbero modificare direttamente i file JSON? No. Un file di traduzione è un input di build con sintassi rigida, e un file invalido di solito fallisce silenziosamente a runtime. I traduttori inoltre non vedono dove compare una stringa, cosa rappresenta un placeholder o come il termine è stato tradotto altrove. Date loro un editor e lasciate che il file venga generato da lì.

Qual è la differenza tra estrazione delle chiavi e saveMissing? L'estrazione analizza il codice sorgente alla ricerca delle chiamate di traduzione e scrive le chiavi nei file, in modo deterministico e senza avviare l'applicazione. saveMissing segnala una chiave mancante dall'applicazione in esecuzione la prima volta che viene usata, insieme al suo valore predefinito. Molti team usano saveMissing in sviluppo e l'estrazione come controllo in CI.

Ho ancora bisogno dei file di traduzione nel repository? Solo se il vostro build ne ha bisogno. Con la distribuzione via CDN il repository non contiene alcun file di lingua e una correzione pubblicata nell'editor è online senza deploy. I team che hanno bisogno dei file per il rendering lato server o per build statici li scaricano in CI come artefatti generati, mai modificati a mano.

Gli agenti di codice basati su IA possono gestire i miei file di traduzione? Possono scrivere e modificare i file, il che elimina la digitazione ma non la deriva: testo non revisionato, terminologia che varia tra le esecuzioni, nessuna traccia di chi ha approvato cosa. Gli agenti funzionano meglio come collaboratori di un workflow gestito, segnalando nuove chiavi e abbozzando traduzioni, mentre coerenza, revisione e cronologia vivono nel sistema di gestione delle traduzioni.

Stanco di gestire le traduzioni a mano?

Locize è il backend di gestione delle traduzioni creato dal team di i18next: distribuzione via CDN, traduzione con AI, editing in-context, senza nuovi deploy.

Inizia la prova gratuita di 14 giorni