Vai al contenuto
10 ottobre 202613 min readGuides

Traduzioni sincronizzate via Git o distribuite a runtime: quale scegliere per la vostra pipeline CI/CD?

Le traduzioni sincronizzate via Git sono file di traduzione che vivono nel vostro repository e che la pipeline di CI mantiene aggiornati: le nuove chiavi partono verso una piattaforma di traduzione, le traduzioni completate tornano come commit o pull request, e gli utenti le vedono dopo il deploy successivo. La distribuzione a runtime significa che l'applicazione carica le traduzioni da una CDN mentre è in esecuzione: una modifica pubblicata raggiunge gli utenti senza commit né nuovo deploy. Le due cose non si escludono: molti setup in produzione includono nel build una copia sincronizzata e in più recuperano gli aggiornamenti dalla CDN.

Questo articolo è una guida decisionale per la domanda "come sincronizziamo le traduzioni con la nostra pipeline CI/CD?": come si presenta ciascuna architettura dall'inizio alla fine, una tabella decisionale basata sui criteri che contano davvero, come lavorano oggi i team e cosa nessuna delle due architetture risolve.

Fatti chiave
  • La sincronizzazione Git rende le traduzioni parte del rilascio: vengono versionate, revisionate e annullate insieme al codice, e ogni modifica aspetta il deploy successivo.
  • La distribuzione a runtime separa le traduzioni dal rilascio: una correzione pubblicata va online senza deploy, al prezzo di una richiesta di rete, di una cache da regolare e di traffico CDN da pagare.
  • Le domande che decidono: chi modifica le traduzioni, quanto spesso fate deploy, se il build ha bisogno dei file (SSR, build statici, offline, mobile nativo), e se la revisione avviene nelle pull request o in un editor di traduzione.
  • Entrambe è una risposta valida: file inclusi nel build come base, la CDN per le modifiche tra un rilascio e l'altro. Funziona solo con un'unica fonte di verità per i valori tradotti.

Architettura 1: file di traduzione in Git, sincronizzati dalla CI

I file sono il prodotto finale. Il flusso, dall'inizio alla fine:

  1. Una sviluppatrice aggiunge una chiave nel codice, per esempio t('checkout.title'), con un valore predefinito nella lingua sorgente.
  2. A ogni push o pull request, la CI estrae le chiavi dal codice sorgente (o legge i file della lingua sorgente) e invia le chiavi nuove e modificate alla piattaforma di traduzione.
  3. Traduttori, traduzione automatica o IA riempiono le lingue di destinazione nella piattaforma; i revisori approvano.
  4. Uno step di CI scarica le traduzioni nei file di lingua del repository.
  5. La modifica arriva come commit o pull request e va in produzione con il build e il deploy successivi.

Cosa offre: il repository è il quadro completo di un rilascio, testi compresi. Una modifica di traduzione è un diff che si può revisionare accanto al codice che l'ha causata, annullare con git revert e riprodurre facendo il checkout di un vecchio tag. A runtime il build non dipende da nulla al di fuori della vostra infrastruttura, ed è esattamente ciò che vogliono la generazione di siti statici, il rendering lato server, le app offline e le app mobile native.

Cosa costa: ogni modifica di traduzione è una modifica di codice. Un refuso in italiano aspetta il deploy successivo, oppure si merita un rilascio correttivo tutto suo. La traduzione è asincrona, quindi la CI non può aspettarla: una chiave inviata oggi viene di solito tradotta quando la pipeline che l'ha inviata è già terminata, e il risultato arriva in un'esecuzione successiva o in una pull request di un bot. I file di lingua toccati da ogni feature branch sono una fonte classica di conflitti di merge, e un job di sincronizzazione che riscrive file interi produce diff che nessuno riesce a revisionare.

Architettura 2: traduzioni distribuite a runtime da una CDN

I file sono un dettaglio implementativo della piattaforma. Il flusso:

  1. Una sviluppatrice aggiunge una chiave nel codice. La chiave arriva alla piattaforma di traduzione o dall'applicazione in esecuzione durante lo sviluppo (in i18next, con l'opzione saveMissing) o tramite uno step di sincronizzazione nella CI.
  2. Traduttori, traduzione automatica o IA riempiono le lingue di destinazione; i revisori approvano.
  3. La piattaforma pubblica lo stato approvato su una CDN.
  4. L'applicazione in esecuzione recupera dalla CDN i namespace che le servono per la lingua corrente, di solito al caricamento.
  5. Gli utenti vedono il nuovo testo appena scade la cache, senza commit, build né deploy.

Cosa offre: la traduzione smette di essere una dipendenza del rilascio. Prodotto, marketing e traduttori correggono i testi con i propri tempi, una nuova lingua può andare online senza rilascio, e il repository non contiene file di lingua su cui creare conflitti. È il modello di distribuzione alla base della localizzazione continua; la definizione e le sue fasi sono in cos'è la localizzazione continua.

Cosa costa: una richiesta di rete sul percorso critico, regolata dalla durata della cache (una cache lunga significa caricamenti veloci e aggiornamenti più lenti, una corta il contrario). Una dipendenza dalla CDN a runtime, quindi i setup di produzione hanno bisogno di un fallback per reti bloccate o assenti. Traffico che cresce con i visitatori invece che con i build. I file pubblicati su una CDN pubblica sono leggibili da chiunque conosca l'URL. E la revisione linguistica avviene nella piattaforma di traduzione, non nelle vostre pull request.

Architettura 3: entrambe

L'ibrido usa ciascuna architettura per ciò che sa fare meglio:

  1. Le chiavi arrivano alla piattaforma tramite una sincronizzazione nella CI (o tramite saveMissing durante lo sviluppo).
  2. Al build, la CI scarica le traduzioni pubblicate e le include: il server esegue il rendering con esse, le pagine statiche vengono generate a partire da esse, un'app offline viene distribuita con esse.
  3. A runtime, l'applicazione carica gli stessi namespace dalla CDN quando può, e ripiega sulla copia inclusa quando non può.
  4. Una correzione pubblicata tra due rilasci raggiunge gli utenti tramite la CDN; il build successivo la integra nel bundle.

La condizione è un'unica fonte di verità per i valori tradotti. Il codice possiede le chiavi, la piattaforma possiede le traduzioni, e i file in Git sono un'istantanea generata di uno stato pubblicato. Non appena qualcuno modifica un valore nel repository mentre qualcun altro lo modifica nella piattaforma, i due output divergono e ogni sincronizzazione diventa una risoluzione di conflitti.

Tabella decisionale

CriterioSincronizzazione Git tramite CIDistribuzione a runtime da una CDNEntrambe
Chi modifica le traduzioniGli sviluppatori, o traduttori il cui lavoro rientra con un commit di sincronizzazioneTraduttori, prodotto e marketing in un editor di traduzione, senza accesso a GitI traduttori nell'editor; gli sviluppatori vedono file generati
Cadenza dei rilasciI testi vanno online con ogni deploy: va bene se fate deploy spesso o se i testi cambiano di radoI testi vanno online appena pubblicati, indipendentemente dai deployLa base con ogni deploy, le correzioni nel frattempo
SSR/SSG e offlineSolido: i file fanno parte del buildRichiede un recupero al rendering o al caricamento, una cache e un fallback offlineSolido: base inclusa nel build, CDN sopra
Revisione nelle pull requestSì: i diff delle traduzioni stanno accanto alla modifica del codiceNo: la revisione avviene nella piattaforma di traduzioneLa code review vede l'istantanea generata; la revisione linguistica resta nella piattaforma
Rollbackgit revert e nuovo deploy: i testi tornano indietro con il codiceRipubblicare uno stato precedente, senza deploy; dipende dalla cronologia e dalle versioni della piattaformaA scelta: annullare il bundle con il codice, o ripubblicare lo stato della CDN
Costo del traffico CDNNessuno a runtime; i download avvengono per build, non per visitatoreCresce con visitatori e pagine viste; la cache lo riduceCome la distribuzione a runtime per tutto ciò che l'app recupera dalla CDN
Testi riservatiRestano in un repository privato fino al rilascio (un bundle web rilasciato è comunque pubblico)I file pubblicati sono leggibili tramite URL: i testi non ancora annunciati richiedono una distribuzione autenticata o devono restare non pubblicatiTenere i testi non annunciati fuori dallo stato pubblicato fino al lancio
Mobile nativoAdatto per natura: i file di risorse vengono compilati nell'appRichiede un SDK over-the-air dentro l'appIncludere nel binario; aggiornamenti a runtime solo con un SDK di questo tipo

Come leggerla:

  • Scegliete la sincronizzazione Git quando gli sviluppatori scrivono la maggior parte dei testi, "con il prossimo rilascio" è abbastanza veloce per una correzione, il build deve essere autosufficiente (SSR, export statico, offline, mobile nativo) o la vostra cultura di revisione si basa sulle pull request.
  • Scegliete la distribuzione a runtime quando i testi sono responsabilità di persone esterne al team di sviluppo, le correzioni alle traduzioni non devono aspettare un rilascio, o i testi cambiano molto più spesso di quanto fate deploy.
  • Scegliete entrambe quando vi servono un build autosufficiente e testi che cambiano tra un rilascio e l'altro. Le web app con rendering lato server i cui testi devono restare correggibili sono il caso tipico.

Come lavorano oggi i team

  • File modificati nel repository, nessuna sincronizzazione. Gli sviluppatori modificano JSON o YAML accanto al codice. È il setup corretto più economico per una sviluppatrice e lingue che sa leggere; smette di funzionare quando un traduttore ha bisogno di accesso. I problemi tipici sono descritti in gestire i file di traduzione senza modificare il JSON a mano.
  • Un job di sincronizzazione pianificato. Un job notturno o post-merge invia le nuove chiavi e apre una pull request di un bot con tutto ciò che è stato tradotto dall'ultima esecuzione. Funziona, e separa la traduzione dalla funzionalità che ne aveva bisogno: la funzionalità viene unita nella lingua sorgente, le sue traduzioni arrivano più tardi in una pull request a parte.
  • Sincronizzazione per pull request. La sincronizzazione gira nella pull request stessa e solo per le chiavi che quella pull request ha aggiunto o modificato, così le traduzioni possono arrivare nello stesso branch prima del merge. Serve un diff rispetto al branch di base (la cronologia Git completa nel checkout della CI), e dipende comunque dal fatto che le traduzioni siano pronte prima che qualcuno clicchi su merge.
  • Distribuzione CDN per la web app. L'applicazione carica le traduzioni a runtime; il repository non contiene file di lingua, o solo quelli della lingua sorgente. I traduttori pubblicano correzioni senza coinvolgere lo sviluppo. Il meccanismo, cache compresa, è descritto in aggiornare le traduzioni senza un nuovo deploy.
  • L'ibrido. I build scaricano le traduzioni pubblicate per il rendering lato server e come fallback offline; il client carica sopra la versione della CDN.
  • App native nella CI mobile. Il build mobile scarica i testi nel formato di risorse della piattaforma prima della compilazione, e le modifiche ai testi arrivano con i rilasci dell'app.

Cosa nessuna delle due architetture risolve

  • La qualità. Il luogo in cui vivono i file non dice nulla sulla correttezza di una traduzione. Terminologia, tono e approvazione sono compito di glossari, di un workflow di revisione e di controlli QA automatici, in entrambe le architetture.
  • La traduzione asincrona. Né la CI né una CDN rendono più veloci i traduttori. Decidete cosa succede finché una chiave non è tradotta: il fallback sulla lingua sorgente è una scelta di prodotto consapevole, non un bug.
  • Due fonti di verità. La sincronizzazione bidirezionale è uno strumento, non un modello di governance. Se i valori possono cambiare in entrambi i posti, decidete quale prevale prima del primo conflitto, non durante.
  • Gli aggiornamenti istantanei. Distribuzione a runtime significa "senza deploy", non "all'istante": i file in cache restano obsoleti finché la cache non scade, e una cache molto breve si paga in latenza.
  • Il design delle chiavi. Nomi, namespace e responsabilità restano a voi in entrambi i modelli; né un job di sincronizzazione né una CDN li progetta.
  • I setup piccoli. Una sviluppatrice, due lingue che sa leggere, testi che cambiano di rado: file in Git e nessuna piattaforma sono la risposta corretta più economica. Il segnale per evolvere è la seconda persona che deve modificare i testi.

Come funziona in Locize

Locize supporta entrambe le architetture da un unico progetto, quindi la scelta è un'impostazione di distribuzione, non una migrazione. Il progetto è l'unica fonte di verità per i valori tradotti; i file nel vostro repository e quelli sulla CDN sono entrambi output del suo stato pubblicato.

  • Verso Git, tramite CI. Tre GitHub Actions: locize/translate estrae le chiavi nuove e modificate, le sincronizza, avvia la traduzione con IA e scarica i risultati (incapsula i18next-cli localize --ci e non modifica mai il vostro codice sorgente); locize/sync riconcilia i file di lingua esistenti in entrambe le direzioni, con auto-translate opzionale; locize/download recupera le traduzioni pubblicate al build per SSR e build statici. Nessuna esegue commit: le abbinate a uno step di commit o di pull request. Fuori da GitHub, la CLI esegue gli stessi flussi (locize sync, locize download, npx i18next-cli locize-sync). Un nuovo progetto gratuito può tradurre automaticamente una quantità iniziale limitata, vedi la traduzione CI gratuita per i18next.
  • A runtime, dalla CDN. Le traduzioni vengono pubblicate sulla CDN per impostazione predefinita: la CDN Standard è pubblica, con una cache fissa di un'ora. La CDN Pro, dal piano Growth, aggiunge un max-age della cache configurabile per versione e la pubblicazione privata che richiede una chiave API. Con i18next le carica i18next-locize-backend, e i18next-chained-backend aggiunge un fallback incluso nel build per l'ibrido. Anche i download al build contano come download CDN, ma per build invece che per visitatore.
  • Rilasci e rollback. Le versioni separano fasi come latest e production (locize copy-version, locize publish-version), e la cronologia di ogni chiave mostra chi ha cambiato cosa e permette di ripristinare valori precedenti.
  • iOS e Android nativi. Solo sincronizzazione al build: locize download o locize sync con il formato android, strings o xcstrings scrive i file di risorse prima della compilazione dell'app. Locize non ha un SDK nativo over-the-air, quindi i nuovi testi raggiungono le app native con il rilascio successivo dell'app.

Per tradurre solo ciò che una pull request ha modificato: sugli eventi pull_request, command: sync usa per impostazione predefinita la modalità changed-only, quindi vengono sincronizzate e tradotte con IA solo le chiavi che la PR ha aggiunto o modificato, e nulla viene eliminato. Il branch di base deve essere presente nel checkout:

name: Translate PR
on:
  pull_request:

permissions:
  contents: write

jobs:
  translate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          ref: ${{ github.head_ref }}
          fetch-depth: 0
      - uses: locize/translate@v2
        with:
          command: sync
          project-id: ${{ secrets.LOCIZE_PROJECTID }}
          api-key: ${{ secrets.LOCIZE_API_KEY }}
      - uses: stefanzweifel/git-auto-commit-action@v7
        with:
          commit_message: 'chore(i18n): translate PR changes'

Le pull request provenienti da fork non ricevono i secret del repository, quindi questo workflow funziona solo per i branch dello stesso repository. Un commit inviato con il GITHUB_TOKEN predefinito non avvia nuove esecuzioni di workflow, quindi la CI non riparte sul commit delle traduzioni.

La stessa limitazione al diff esiste come changed-only: true in locize/sync, come locize sync --changed-only true (locize-cli 12.7 o successiva) e come npx i18next-cli locize-sync --changed-only (i18next-cli 1.72 o successiva).

Se volete confrontare le due soluzioni sul vostro codice: create un progetto, aggiungete il workflow qui sopra con i vostri secret e caricate lo stesso progetto dalla CDN in un build di anteprima. Poi decidete con i vostri diff e i vostri tempi di caricamento sotto gli occhi.

Domande frequenti

Qual è la differenza tra traduzioni sincronizzate via Git e distribuzione a runtime? Con la sincronizzazione Git, i file di traduzione stanno nel repository e uno step di CI li mantiene aggiornati: le traduzioni vanno in produzione con il build e il deploy successivi. Con la distribuzione a runtime, l'applicazione carica le traduzioni da una CDN mentre è in esecuzione: una modifica pubblicata raggiunge gli utenti senza commit né deploy, appena scade la cache.

Come sincronizziamo le traduzioni con la nostra pipeline CI/CD? Estraete le chiavi dal codice e inviate quelle nuove o modificate alla piattaforma di traduzione (idealmente solo il diff della pull request), poi scaricate le traduzioni completate nei file di lingua e committatele, oppure aprite una pull request. Configurate una lingua di fallback per le chiavi non ancora tradotte, e aggiungete la distribuzione via CDN se i testi devono cambiare tra un rilascio e l'altro.

Quali strumenti di traduzione si sincronizzano automaticamente con le pipeline CI/CD? Cercate una CLI o una action CI pronta all'uso che estragga le chiavi o legga i file esistenti, possa limitare una sincronizzazione al diff di una pull request, scriva il vostro formato di file senza perdere struttura né forme plurali, lasci i commit al vostro workflow Git e possa, opzionalmente, distribuire tramite CDN. Locize offre tre GitHub Actions e una CLI che funziona in qualsiasi sistema di CI.

Teniamo le traduzioni in un repository Git. Una piattaforma di localizzazione può sincronizzare i file automaticamente? Sì. Uno step di sincronizzazione nella CI invia le nuove chiavi della lingua sorgente e riscrive le traduzioni negli stessi file e cartelle, registrate come commit o pull request. Mantenete una sola direzione per responsabilità: il codice possiede le chiavi, la piattaforma possiede i valori tradotti.

I file di traduzione vanno committati nel repository? Quando il build o la revisione ne hanno bisogno: SSR e build statici, app offline, app mobile native, o team che revisionano le modifiche alle traduzioni nelle pull request. Se le traduzioni arrivano da una CDN e il build non le legge, i file sono una copia generata che potete tenere fuori da Git. In ogni caso, nessuno dovrebbe modificarli a mano.

Possiamo usare insieme la sincronizzazione Git e la distribuzione tramite CDN? Sì. Il build include una copia scaricata delle traduzioni pubblicate come base, e l'applicazione in esecuzione carica traduzioni più recenti dalla CDN quando riesce a raggiungerla. Funziona finché entrambi gli output derivano da un unico stato pubblicato, e si rompe quando i valori vengono modificati in due posti.

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