# General Translation Knowledge Base: Come si traducono i file PO e POT?
URL: https://generaltranslation.com/it/kb/translate-po-files.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Compila ogni msgstr, incluse tutte le forme plurali richieste dall'intestazione Plural-Forms, e lascia invariati msgid, msgctxt e i segnaposto. Esegui msgfmt --check per verificare intestazioni, numero di forme plurali e segnaposto nelle voci con un flag di formato, e controlla a parte che nessun msgstr sia vuoto. La CLI di General Translation genera un file PO tradotto per ogni lingua a partire dal tuo template POT.
Category: Traduzione
Last updated: 2026-10-28
Authors: General Translation Team
Published: 2026-10-28

Un file POT (Portable Object Template) contiene le stringhe di origine estratte dal codice, mentre ogni file PO (Portable Object) associa quelle stringhe alle traduzioni in una specifica lingua. Tradurre significa compilare ogni `msgstr`, uno per ciascuna forma plurale prevista dalla lingua, lasciando `msgid`, `msgctxt` e i segnaposto esattamente come sono stati estratti. Poi si compila ogni file PO nel catalogo binario `.mo` caricato dal programma. Il formato è semplice, ma gli errori sono silenziosi: per tutto ciò che non riesce a usare, gettext mostra semplicemente il testo di origine.

## Da dove provengono i file POT e PO

Ogni stack basato su gettext esegue gli stessi quattro passaggi, cambiano solo i nomi dei comandi:

| Passaggio                                                            | GNU gettext | Babel (Flask, FastAPI) |
| -------------------------------------------------------------------- | ----------- | ---------------------- |
| Estrarre le stringhe di origine in un template                       | `xgettext`  | `pybabel extract`      |
| Creare un file PO per una nuova lingua                               | `msginit`   | `pybabel init`         |
| Eseguire il merge delle modifiche del template nei file PO esistenti | `msgmerge`  | `pybabel update`       |
| Compilare un file PO in `.mo`                                        | `msgfmt`    | `pybabel compile`      |

Django accorpa i primi tre passaggi in `makemessages`, che scrive direttamente i file PO, e compila con `compilemessages`. La traduzione avviene tra il merge e la compilazione: il template non è associato ad alcuna lingua, quindi le traduzioni si trovano solo nei file PO. (Consulta [General Translation vs. GNU gettext](/kb/general-translation-vs-gettext) per il ciclo completo di gettext, compreso il comportamento di `msgmerge` quando una stringa di origine cambia.)

## Cosa contiene una voce PO

Ecco il file PO in polacco che la CLI di General Translation ha generato a partire da un template estratto con `xgettext` da un breve script Python (intestazione abbreviata):

```text title="po/pl.po"
msgid ""
msgstr ""
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;\n"

#: inbox.py:8
#. TRANSLATORS: Heading of the inbox page.
msgid "Inbox"
msgstr "Skrzynka odbiorcza"

#: inbox.py:9
#, python-format
msgid "You have %(num)d unread message."
msgid_plural "You have %(num)d unread messages."
msgstr[0] "Masz %(num)d nieprzeczytaną wiadomość."
msgstr[1] "Masz %(num)d nieprzeczytane wiadomości."
msgstr[2] "Masz %(num)d nieprzeczytanych wiadomości."

#: inbox.py:10
msgctxt "email action"
msgid "Archive"
msgstr "Archiwizuj"
```

Il [manuale di GNU gettext](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html) definisce ciascuna parte:

* **`msgid` e `msgid_plural`** sono il testo di origine, e `msgid` funge anche da chiave di ricerca. Non modificarli mai in un file PO: un `msgid` modificato non trova più alcuna corrispondenza nel codice, e gli utenti vedono il testo di origine.
* **`msgstr`** è la traduzione, ed è l&#39;unica riga che devi scrivere. Una voce plurale va da `msgstr[0]` fino al numero di forme plurali della lingua meno uno.
* **`msgctxt`** distingue stringhe di origine identiche ma con significati diversi, come &quot;Archive&quot; inteso come azione sulle email e come cartella di archivio. Deriva da `pgettext`, ogni contesto riceve una traduzione propria e va lasciato così come è stato estratto.
* **I commenti estratti `#.`** sono note degli sviluppatori (`xgettext --add-comments` li estrae dal codice), **i riferimenti `#:`** rimandano alle righe del codice sorgente e **i commenti del traduttore `# `** sono riservati a chi traduce.
* **I flag `#,`** sono di due tipi. `fuzzy` è un flag di flusso di lavoro che segnala che la traduzione potrebbe essere errata e va verificata da una persona. I flag di formato come `c-format` e `python-format` vengono impostati da `xgettext` e indicano a `msgfmt` di confrontare i segnaposto tra sorgente e traduzione.
* **L&#39;intestazione** è la voce con un `msgid` vuoto. I suoi campi `Language`, charset di `Content-Type` e `Plural-Forms` valgono per l&#39;intero file.

## Come Plural-Forms determina il numero di traduzioni

`Plural-Forms` indica il numero di forme (`nplurals`) e un&#39;espressione in stile C che associa un conteggio `n` a un indice di forma ([manuale di GNU gettext: forme plurali](https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html)). Con GNU gettext 1.0, `msginit` generava `nplurals=1; plural=0;` per il giapponese, `nplurals=2; plural=(n != 1);` per il tedesco, `nplurals=2; plural=(n > 1);` per il francese (dove lo zero è singolare) e tre forme per il polacco e il russo. L&#39;arabo ne richiede sei, ma per questa lingua lo stesso `msginit` lasciava nell&#39;intestazione il segnaposto `nplurals=INTEGER; plural=EXPRESSION;`: verifica quindi l&#39;intestazione prima che inizi la traduzione.

Una volta compilato il file polacco, `ngettext` di Python seleziona uno slot diverso a seconda del conteggio:

```text title="Output"
count  slot        output
1      msgstr[0]   Masz 1 nieprzeczytaną wiadomość.
3      msgstr[1]   Masz 3 nieprzeczytane wiadomości.
5      msgstr[2]   Masz 5 nieprzeczytanych wiadomości.
22     msgstr[1]   Masz 22 nieprzeczytane wiadomości.
```

Un testo sorgente inglese ha due forme, quindi tradurlo voce per voce in due stringhe polacche lascia `msgstr[2]` senza alcuna forma corretta da mostrare per 5 o 12.

## Cosa si rompe quando traduci un file PO

Tutti questi problemi superano la compilazione o l&#39;esecuzione senza crash, ed è per questo che arrivano in produzione:

* **Le voci fuzzy non arrivano mai agli utenti.** `msgfmt` le esclude dal file `.mo` a meno che non passi `--use-fuzzy`, opzione che il manuale definisce &quot;di solito sbagliata&quot;. Dopo aver contrassegnato come fuzzy la voce plurale, la build polacca ha stampato &quot;You have 5 unread messages.&quot; in inglese. Rivedi ogni voce fuzzy, poi rimuovi il flag.
* **Una voce del plurale vuota può non stampare nulla.** `msgfmt` ha compilato una voce con un `msgstr[2]` vuoto e l&#39;ha conteggiata come tradotta, e Python ha stampato una riga vuota per un conteggio pari a 5. `--check` la rifiuta solo quando la voce ha un flag di formato, perché in quel caso alla voce del plurale vuota manca il segnaposto; senza flag, la voce supera il controllo.
* **I segnaposto vengono eliminati o rinominati.** Una traduzione senza `%(num)d` perde il conteggio. `msgfmt --check` se ne accorge solo nelle voci con un flag di formato.
* **Virgolette ed escape seguono le convenzioni del C.** Un `"` all&#39;interno di `msgstr` va scritto `\"`; una virgoletta senza escape è un errore di sintassi, e un a capo all&#39;interno di una stringa si scrive `\n`.
* **Nei modelli il charset è un segnaposto.** `xgettext` scrive `charset=CHARSET` nell&#39;intestazione del POT, e `msgfmt --check` rifiuta un file PO che riporta ancora quel valore. `msginit` e `pybabel` scrivono UTF-8; se uno strumento traduce direttamente una copia del template, esegui prima `msgconv --to-code=UTF-8` sul template.

`msgfmt --check` segnala i problemi che è in grado di rilevare, mentre `--statistics` conta ciò che è effettivamente finito nella build:

```text title="msgfmt --check"
$ msgfmt --check -o /dev/null missing-placeholder.po
missing-placeholder.po:30: a format specification for argument 'num' doesn't exist in 'msgstr[2]'
msgfmt: found 1 fatal error

$ msgfmt --check -o /dev/null two-forms.po
two-forms.po:7: nplurals = 3...
two-forms.po:30: ...but some messages have only 2 plural forms
msgfmt: found 1 fatal error

$ msgfmt --check --statistics -o inbox.mo fuzzy.po
2 translated messages, 1 fuzzy translation.
```

Eseguilo in CI su ogni file PO e considera qualsiasi conteggio fuzzy maggiore di zero come lavoro ancora da completare.

Nessuno strumento gettext segnala una voce plurale con una voce del plurale vuota: `msgfmt --check` la lascia passare se la voce non ha un flag di formato, e `msgattrib --untranslated` la salta. Un breve script con [Babel](https://babel.pocoo.org/) (`pip install babel`) fa fallire la build se trova anche una sola traduzione vuota:

```python title="check_po.py"
import sys

from babel.messages.pofile import read_po

failed = False
for path in sys.argv[1:]:
    with open(path, "rb") as f:
        catalog = read_po(f)
    for message in catalog:
        if not message.id or message.fuzzy:
            continue  # l'intestazione e le voci fuzzy, che msgfmt ignora già
        forms = message.string if isinstance(message.string, tuple) else (message.string,)
        if not all(forms):
            print(f"{path}:{message.lineno}: empty translation for {message.id!r}")
            failed = True
sys.exit(1 if failed else 0)
```

```text title="Output"
$ python check_po.py po/pl.po
po/pl.po:17: empty translation for ('You have %(num)d unread message.', 'You have %(num)d unread messages.')
```

## Modi per tradurre i file PO

| Approccio                                                                                                                | Chi traduce                                         | Voci del plurale                                                                  | Contesto fornito al traduttore                                                                 | Quando il template cambia                                                                                                             |
| ------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------- | --------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| Modifica manuale o in [Poedit](https://poedit.com/features/)                                                             | Tu o un traduttore                                  | Poedit segnala forme plurali errate e token mancanti                              | Commenti e riferimenti nel file                                                                | Esegui `msgmerge`, poi rivedi le voci fuzzy                                                                                           |
| [Weblate](https://docs.weblate.org/en/latest/formats/gettext.html) o un altro sistema di gestione delle traduzioni (TMS) | Traduttori, con suggerimenti automatici facoltativi | Supportate; fuzzy corrisponde a &quot;Needs editing&quot;                         | Commenti, riferimenti, screenshot o glossario del TMS                                          | L&#39;add-on msgmerge o la sincronizzazione del repository aggiorna i file PO                                                         |
| `msgpre` di GNU gettext                                                                                                  | Un LLM locale tramite ollama, come bozza            | Generate in bozza, da far revisionare a un traduttore                             | Ciò che è presente nel file PO                                                                 | Riesegui sulle nuove voci ([pretraduzione di gettext 1.0](https://www.gnu.org/software/gettext/manual/html_node/Pretranslating.html)) |
| Uno script che si appoggia a un&#39;API di traduzione automatica o a un LLM                                              | Il modello                                          | Lo script deve generare tutte le voci richieste dall&#39;intestazione             | Tutto ciò che lo script invia                                                                  | Riesegui e valida l&#39;output in autonomia                                                                                           |
| [La CLI di General Translation](/docs/cli/reference/formats/po-pot-files)                                                | Il servizio di traduzione di General Translation    | Tutte le voci previste per la lingua di destinazione, con verifica dei segnaposto | `msgctxt`, commenti, riferimenti, flag, oltre al tuo Glossario e ai tuoi Prompt Personalizzati | Riutilizza le traduzioni invariate e traduce le voci nuove o modificate                                                               |

La pretraduzione automatica di Poedit è una funzionalità Pro; modifica, memoria di traduzione e controlli sono inclusi nella versione gratuita. (Consulta [General Translation vs. Weblate](/kb/general-translation-vs-weblate) per un confronto con il ciclo di andata e ritorno di un TMS.)

Usa Poedit se traduci personalmente una o due lingue. Usa Weblate o un altro [TMS](/kb/what-is-a-translation-management-system) se i cataloghi sono gestiti da traduttori professionisti che hanno bisogno di assegnazioni e code di revisione. Usa uno script o `msgpre` solo se sei disposto a occuparti tu della validazione. Usa General Translation se i file PO devono essere tradotti in tutte le lingue a ogni build, con una terminologia condivisa con gli altri tuoi prodotti.

## Tradurre i file PO con General Translation

La CLI di General Translation, `gt`, legge un file POT (o un file PO nella lingua sorgente) e genera un file PO tradotto per ogni impostazione regionale. Aggiungi una voce `pot` a `gt.config.json`. Questa config è stata verificata con `gt` 2.26.11 e la risoluzione dei percorsi propria della CLI associa `po/messages.pot` a `po/de.po`, `po/pl.po` e `po/pt_BR.po`:

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": ["de", "pl", "pt_BR"],
  "customMapping": { "pt_BR": { "code": "pt-BR" } },
  "files": {
    "pot": {
      "include": ["po/messages.pot"],
      "transform": { "match": "^po/messages\\.pot$", "replace": "po/{locale}.po" },
      "transformationFormat": "PO"
    }
  }
}
```

* **`pot`** legge sia i file PO sia i file POT (funziona anche `POT`). Il supporto per PO e POT è disponibile a partire da `gt` 2.14.22.
* **`"transformationFormat": "PO"`** è obbligatorio. Senza questa opzione, l&#39;output resta un template non tradotto.
* **[`transform`](/docs/cli/reference/config#locale-placeholders)** definisce il nome di ciascun file di output; `{locale}` è l&#39;impostazione regionale così come è scritta in `locales`, mentre [`customMapping`](/docs/cli/reference/config#custom-mapping) associa il `pt_BR` di gettext al codice standard `pt-BR`.
* **I layout di Babel e Django** non usano `transform`: fai puntare `include` al catalogo inglese inserendo un segnaposto `[locale]` nel percorso della cartella, ad esempio `[locale]/LC_MESSAGES/*.po` in `translations/`, e la CLI scriverà il catalogo di ciascuna lingua accanto a esso, ad esempio `pl/LC_MESSAGES/messages.po`.

Poi esegui la CLI tra l&#39;estrazione e la compilazione:

```bash
xgettext --language=Python --keyword=pgettext:1c,2 --add-comments=TRANSLATORS -o po/messages.pot app.py
msgconv --to-code=UTF-8 -o po/messages.pot po/messages.pot
npx gt translate
msgfmt --check -o locale/pl/LC_MESSAGES/messages.mo po/pl.po
```

Per prima cosa configura le credenziali con [`npx gt login`](/docs/cli/reference/commands/login) e un ID progetto, oppure con una chiave API di progetto in CI ([credenziali della CLI](/docs/cli/guides/configuring#credentials)). Se i tuoi file PO contengono già traduzioni revisionate, importale con [`npx gt upload`](/docs/cli/reference/commands/upload) prima di eseguire per la prima volta [`npx gt translate`](/docs/cli/reference/commands/translate).

Per ogni voce, General Translation traduce il testo di `msgid`, inviando come contesto anche `msgctxt`, i commenti `#.`, i riferimenti `#:` e i flag. Imposta l&#39;intestazione `Language` dell&#39;output e, se il file contiene voci plurali, scrive la regola `Plural-Forms` della lingua di destinazione e compila tutti i `msgstr[n]` previsti da tale regola: tre per il polacco, sei per l&#39;arabo. Per ogni traduzione plurale viene verificato che non ci siano slot vuoti e che nessuna forma manchi di segnaposto come `%(num)d`, `%s` o `{name}`. Commenti, riferimenti, flag e `msgctxt` vengono ripresi dal template, e alla successiva esecuzione le voci invariate riutilizzano le traduzioni precedenti.

Poiché la sorgente è il `msgid`, questo approccio funziona al meglio quando il codice usa il testo di origine come chiave, che è il comportamento predefinito di gettext. I revisori possono [modificare le voci nella Dashboard](/docs/platform/dashboard/guides/reviewing-translations), mentre un Glossario e dei Prompt Personalizzati in un [gruppo di contesto](/docs/platform/dashboard/guides/defining-context-for-translations) garantiscono che un termine come &quot;Archive&quot; resti coerente con la tua web app e la documentazione. Se qualcuno modifica un file PO in locale, sincronizzalo con [`npx gt save-local`](/docs/cli/reference/commands/save-local) prima dell&#39;esecuzione successiva. Per configurazioni specifiche dei framework, consulta [General Translation e il framework di traduzione di Django a confronto](/kb/general-translation-vs-django-i18n), [General Translation, Babel e Flask-Babel a confronto](/kb/general-translation-vs-flask-babel) e [Come si traduce un&#39;app Flask o FastAPI?](/kb/translate-python-app).

## Domande frequenti

### Qual è la differenza tra un file PO e un file POT?

Un file POT è il template: ogni `msgstr` è vuoto e l&#39;intestazione non specifica alcuna lingua. Un file PO è una copia destinata a una singola lingua e contiene un&#39;intestazione `Language`, la regola `Plural-Forms` di quella lingua e le traduzioni.

### Serve ancora msgmerge se General Translation scrive i file PO?

Non per le lingue di destinazione, se la sorgente è il template POT. Ogni esecuzione rigenera il file PO di ciascuna lingua a partire dal template corrente: le voci rimosse dal codice scompaiono e quelle nuove arrivano già tradotte, senza voci fuzzy da ripulire. Con i layout di Babel e Django, il catalogo inglese va comunque aggiornato con `pybabel update` o `makemessages`.

### Perché la mia app mostra ancora l&#39;inglese anche dopo che ho tradotto il file PO?

Di solito le cause possibili sono tre: la voce è ancora contrassegnata come `fuzzy`, il file `.mo` non è stato ricompilato o ridistribuito, oppure il `msgid` nel file PO non corrisponde più alla stringa nel codice. `msgfmt --statistics` mostra quante voci sono tradotte e quante sono fuzzy.

## Punti chiave

* Traduci solo `msgstr`: `msgid`, `msgid_plural` e `msgctxt` sono chiavi di ricerca e vanno lasciate così come sono state estratte.
* Scrivi tanti slot `msgstr[n]` quanti ne indica `nplurals` nell&#39;intestazione: uno per il giapponese, due per il tedesco, tre per il polacco, sei per l&#39;arabo.
* `msgfmt` scarta le voci fuzzy e compila senza errori una voce del plurale vuota, che poi non mostra nulla; `--check` la rileva solo nelle voci con un flag di formato, quindi esegui `msgfmt --check --statistics` e un controllo separato delle traduzioni vuote su ogni file PO.
* La CLI di General Translation traduce un template POT in un file PO per ciascuna impostazione regionale tramite `"pot"`, `"transformationFormat": "PO"` e un `transform`, compilando tutte le voci del plurale previste dalla lingua di destinazione.

## Related questions

- [General Translation vs. GNU gettext: servono entrambi?](https://generaltranslation.com/it/kb/general-translation-vs-gettext.mdx): Mantieni GNU gettext per l'estrazione e il rendering e aggiungi General Translation per generare e mantenere aggiornati i file PO. General Translation tiene conto delle note per i traduttori e del contesto dei messaggi in fase di generazione, applica una terminologia condivisa e mette a disposizione dei revisori un editor nella Dashboard. Le chiamate gettext esistenti e i cataloghi compilati restano al loro posto.
- [General Translation e il framework di traduzione di Django: servono entrambi?](https://generaltranslation.com/it/kb/general-translation-vs-django-i18n.mdx): Usa insieme il framework di traduzione di Django e General Translation. Django si occupa dell'estrazione dei messaggi, della selezione della lingua e del rendering. General Translation compila i suoi file PO, forme plurali comprese, con la terminologia del tuo prodotto e la revisione nella Dashboard. I tuoi template e i modelli di URL restano invariati, mentre le traduzioni si aggiornano di pari passo con il codice.
- [General Translation, Babel e Flask-Babel a confronto: quale scegliere?](https://generaltranslation.com/it/kb/general-translation-vs-flask-babel.mdx): Babel formatta date, numeri e valute per qualsiasi impostazione regionale e gestisce i cataloghi gettext, mentre Flask-Babel lo integra con Flask, ma nessuno dei due traduce le tue stringhe. La CLI di General Translation popola i file PO di Babel per ogni lingua, forme plurali incluse, così puoi continuare a usare Flask-Babel e smettere di tradurre i cataloghi a mano.
- [Come si traduce un'app Flask o FastAPI?](https://generaltranslation.com/it/kb/translate-python-app.mdx): Contrassegna le stringhe visibili agli utenti, determina l'impostazione regionale di ogni richiesta (di solito da Accept-Language) e carica le traduzioni corrispondenti. Le app Flask in genere usano Flask-Babel con cataloghi gettext, mentre le app FastAPI integrano Babel tramite un middleware. La CLI di General Translation popola questi cataloghi, mentre i suoi SDK sperimentali gt-flask e gt-fastapi traducono le stringhe inline di t() senza bisogno di cataloghi.
- [General Translation vs. Weblate: quale scegliere?](https://generaltranslation.com/it/kb/general-translation-vs-weblate.mdx): Weblate è una piattaforma di localizzazione self-hostable basata su Git, pensata per tradurre i file di un repository insieme a una community o a un team. General Translation integra la generazione delle traduzioni nello sviluppo e nei rilasci, sfruttando JSX contrassegnato e un contesto di prodotto condiviso. Puoi mantenere i tuoi file gettext oppure adottare la scrittura inline per eliminare anche la manutenzione del catalogo di origine.

## Previous and next questions

- Previous question: [Come si traducono i file di impostazioni regionali YAML?](https://generaltranslation.com/it/kb/translate-yaml-files.mdx)
- Next question: [Come si traducono i titoli SEO e le meta description?](https://generaltranslation.com/it/kb/translate-seo-metadata.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/it/kb/sitemap.md) for every article.
