Tutorial¶
Questa pagina va da una directory vuota a un programma che saluta in giapponese. Cinque passi, nessuna esperienza con gettext richiesta, e ogni comando è mostrato con l'output che produce davvero — così a ogni passo sai se sei sulla strada giusta.
Serve Python 3.14 o più recente, perché le t-string sono sintassi nuova
della 3.14. Il giapponese è la lingua di esempio di questa pagina, ma niente
dipende da quella scelta. Per usare un'altra lingua, sostituisci ja al
passo 4 — quel codice di locale è l'unica cosa che la nomina.
1. Installa¶
L'extra [babel] porta con sé Babel, lo strumento che al passo 3 raccoglie
i tuoi messaggi nei file di catalogo. È uno strumento da tempo di sviluppo: il
codice di produzione fa il rendering con la sola libreria standard.
2. Marca un messaggio nel codice¶
Crea app.py:
t"Hello {name}" sembra una f-string, ma il prefisso t mantiene separati il
testo e il valore invece di fonderli sul posto. È quella separazione a
permettere a tr() di cercare una traduzione per l'intera frase
Hello {name} e inserire il valore dopo.
Eseguilo subito:
Non c'è ancora nessuna traduzione installata, quindi il testo sorgente viene reso così com'è. Un programma che usa questa libreria non richiede mai un catalogo per funzionare — l'inglese (o qualunque sia la tua lingua sorgente) è il ripiego incorporato.
3. Estrai i messaggi¶
I traduttori di solito lavorano sui cataloghi anziché sul codice sorgente, quindi tra te e loro viaggia un piccolo file chiamato catalogo. Il primo passo verso di esso è raccogliere dal codice ogni messaggio marcato.
Di' a Babel come trovare i tuoi messaggi creando babel.cfg:
Poi estrai in un file template (.pot):
$ mkdir -p locales
$ pybabel extract -F babel.cfg -c "Translators:" -o locales/messages.pot .
extracting messages from app.py (encoding="utf-8")
writing PO template file to locales/messages.pot
locales/messages.pot ora contiene una voce per messaggio:
msgid è la chiave che il tuo codice cercherà. Il msgstr vuoto è dove va
una traduzione — ma non in questo file: un .pot è un template, e il
prossimo passo lo copia una volta per lingua.
4. Traduci e compila¶
Crea il catalogo giapponese a partire dal template:
$ pybabel init -i locales/messages.pot -d locales -l ja
creating catalog locales/ja/LC_MESSAGES/messages.po based on locales/messages.pot
Apri locales/ja/LC_MESSAGES/messages.po e riempi il msgstr:
Mantieni {name} esattamente com'è — il segnaposto è il modo in cui il
valore trova il suo posto dentro la frase tradotta, e la traduzione è libera
di spostarlo dovunque la lingua di destinazione lo richieda. In un progetto
reale questo file .po è ciò che consegni a un traduttore o carichi su una
piattaforma di traduzione; il formato è lo stesso in entrambi i casi.
I cataloghi si modificano come testo ma si caricano in forma binaria (.mo),
quindi compila:
$ pybabel compile -d locales
compiling catalog locales/ja/LC_MESSAGES/messages.po to locales/ja/LC_MESSAGES/messages.mo
Questo comando è anche una rete di sicurezza. Se la traduzione avesse
danneggiato il segnaposto — {nome} invece di {name}, poniamo — si
rifiuterebbe di passare:
$ pybabel compile -d locales
error: locales/ja/LC_MESSAGES/messages.po:24: translation does not match the
source placeholders: {name} is missing; {nome} is not in the source message
1 errors encountered.
Un avvertimento che vale la pena conoscere fin d'ora: segnala l'errore ed esce
con stato diverso da zero, ma scrive comunque il .mo. Su un progetto vero è
la CI a doversi fermare su quello stato di uscita —
In produzione lo configura.
5. Eseguilo¶
I passi 2–4 hanno usato tr(), che cerca un catalogo e non ne trova nessuno.
Ora che ne esiste uno, caricalo e legalo una volta sola: Translator tiene un
catalogo perché i punti di chiamata non debbano nominarlo, e _ è il nome
gettext convenzionale per il risultato.
Punta app.py al catalogo compilato. Fai clic sui marcatori per vedere che
cosa fa ogni riga:
import gettext
from gettext_tstrings import Translator
_ = Translator(gettext.translation("messages", localedir="locales", languages=["ja"])) # (1)!
name = "Ada"
print(_(t"Hello {name}")) # (2)!
- La libreria standard carica il
.mocompilato eTranslatorlo lega a un callable._è il nome gettext convenzionale per "traduci questo" — corto perché compare su ogni stringa rivolta all'utente. Esegue la stessa traduzione ditr, legata a un solo catalogo. - Alla chiamata: il testo della t-string diventa la chiave di ricerca
Hello {name}, il catalogo rispondeこんにちは {name}, la risposta viene verificata contro i segnaposto sorgente, e solo allora il valore viene inserito.
Questo è l'intero ciclo, e vale la pena vederlo in un colpo d'occhio:
flowchart LR
mark["1–2 marca<br>le t-string nel codice"] --> extract["3 estrai<br>messages.pot"]
extract --> translate["4 traduci<br>ja/…/messages.po"]
translate --> compile["4 compila<br>ja/…/messages.mo"]
compile --> run["5 esegui<br>こんにちは Ada"]
Marca → estrai → traduci → compila → esegui. Tutto il resto di questo sito è un raffinamento di uno di quei cinque passi.
Dove proseguire¶
- Perché le t-string — da che cosa ti protegge questo
design, rispetto a
%(name)s,.format()e alle$-string. - Guida — plurali, lingue per richiesta, stringhe differite e che cosa succede a runtime quando un catalogo è comunque sbagliato.
- In produzione — questo stesso ciclo come lo conduce un team, settimana dopo settimana: aggiornamento dei cataloghi, controlli in CI e piattaforme di traduzione.
- Estrazione — il riferimento completo per
pybabel: nomi di funzione personalizzati, modalità strict per la CI e i controlli che proteggono i tuoi cataloghi. - Migrazione — se il progetto in cui vuoi davvero fare tutto questo ha già cataloghi gettext.
- Per i traduttori — l'unica pagina da consegnare a chi
riempie quelle righe
msgstr.