Migrering¶
Om ditt projekt redan använder gettext är frågorna som avgör om det här biblioteket går att införa smala: ogiltigförklarar det katalogerna du har, kan det samexistera med koden du inte är redo att ändra, och hur mycket av flytten måste ske på en gång. Svaren, det kortaste först:
| Fråga | Svar |
|---|---|
Fungerar befintliga .po- och .mo-filer fortfarande? |
Ja. Samma filer, samma verktyg. |
| Kan gamla och nya anrop bo i samma fil? | Ja, och en enda extraktormappning täcker båda. |
| Ändras msgid:n? | Inte från .format(). Ja från %-format. |
| Måste hela projektet flytta på en gång? | Nej. Ett anropsställe är en giltig ändring. |
| Vad händer med Jinja, Django-mallar, JavaScript? | Orörda, samma kataloger. |
Resten av den här sidan är detaljerna bakom var och en av dem.
Från .format(): msgid:n ändras inte¶
Det här är fallet där migreringen nästan inte kostar något. Ett
str.format-meddelande och ett t-string-meddelande härleder samma
katalognyckel, eftersom nyckeln är texten med {name} kvar i sig i båda
fallen:
# Before
_("Hello {name}").format(name=name)
# After — the msgid is still "Hello {name}"
tr(t"Hello {name}")
Så den befintliga översättningen sitter kvar. Utgå från en katalog som innehåller
ändra anropet, extrahera om, och uppdatera:
$ pybabel extract -F babel.cfg -o locales/messages.pot .
extracting messages from app.py (encoding="utf-8")
writing PO template file to locales/messages.pot
$ pybabel update -i locales/messages.pot -d locales
updating catalog locales/ja/LC_MESSAGES/messages.po based on locales/messages.pot
Posten som kommer tillbaka skiljer sig på två metadatarader och ingenting annat — en markörkommentar som identifierar den som ett t-string-meddelande, och ett radnummer i källkoden:
Ingen fuzzy-flagga, ingen omöversättning, på något språk. Meddelandet
renderas omedelbart:
$ pybabel compile -d locales
compiling catalog locales/ja/LC_MESSAGES/messages.po to locales/ja/LC_MESSAGES/messages.mo
$ python app.py
こんにちは Ada
update --check kommer att rapportera katalogerna som inaktuella
Den markörkommentaren och de flyttade radnumren räcker för att
pybabel update --check ska säga att en katalog behöver genereras om,
eftersom den jämför hela posten och inte bara översättningen. Kör den
riktiga pybabel update i samma commit som kodändringen, och committa
katalogerna med den — samma vana som
CI-grinden redan ber om.
Från %-format: msgid:n ändras, så översättningar blir fuzzy¶
Printf-syntax bor inuti meddelandet, så att ersätta den skriver om
katalognyckeln. Det går inte att komma runt, och det är den ärliga kostnaden
för att lämna %(name)s bakom sig:
pybabel update känner igen det nya meddelandet som en nära släkting till det
borttagna och bär över den gamla översättningen, märkt fuzzy:
#. gettext-tstrings
#: app.py:4
#, fuzzy, python-brace-format, python-format
msgid "Hello {name}"
msgstr "こんにちは %(name)s"
Tre saker att veta om det tillståndet:
- Ingenting går sönder vid körning. Fuzzy-poster utesluts ur den
kompilerade
.mo-filen, så applikationen renderar källmeddelandet tills en människa bekräftar paret — samma degradering som varje omformulerat meddelande går igenom. pybabel compilerapporterar var och en, eftersom det överförda%(name)sinte är en giltig klammerplatshållare, och avslutar med nollskild status. Den listan är din arbetskö, inte ett falsklarm; posterna i den behöver verkligen redigeras.- Den gamla
python-format-flaggan följer med och bör raderas tillsammans medfuzzy-flaggan, annars fortsättermsgfmt --check-formatatt tillämpa printf-regler på ett brace-format-meddelande.
För namngivna printf-platshållare är redigeringen mekanisk — %(name)s blir
{name} och ingenting annat rör sig — så en stor katalog är en skriptad
genomgång följd av en översättares granskning, snarare än en omöversättning.
Positionella %s är inte mekaniska: de har inget namn att bära över, och att
välja ett är hela poängen med ändringen.
Därför är den praktiska ordningen att migrera %-format-meddelanden medvetet
— en modul, en release, ett språk i taget — snarare än i ett svep som gör varje
katalog röd på en gång.
Gamla och nya anrop samexisterar¶
Extraktorn som läser t-strings läser också vanliga gettext-anrop, så en enda mappning täcker en fil mitt i migreringen:
from gettext_tstrings import tr
from myapp.i18n import _
name = "Ada"
print(_("Save changes"))
print(tr(t"Hello {name}"))
Båda meddelandena hamnar i samma mall, och bara t-string-meddelandet bär markörkommentaren som slår på det här bibliotekets extra kontroller:
#: app.py:5
msgid "Save changes"
msgstr ""
#. gettext-tstrings
#: app.py:6
#, python-brace-format
msgid "Hello {name}"
msgstr ""
Den känner igen _(), de fyra standardnamnen i gettext, aliasen tr() /
ntr() och de uppskjutna lazy_gettext() / lazy_pgettext(). En egen
hjälpfunktion måste namnges i mappningen.
Vid körning är de två stilarna lika oberoende: gettext.translation()
returnerar ett översättningsobjekt, och både _ och det här bibliotekets
ingångar läser ur det.
Vad som inte flyttar¶
- Mallspråk. Jinja2:s
{% trans %}, Djangos malltaggar och deras Babel-extraktorer fortsätter fungera oförändrade och fortsätter mata samma PO-kataloger. t-strings är Python-syntax; de gäller Python-källkod. - Dina katalogfiler. Ingen formatändring, ingen ny fil, inget konverteringssteg.
- Din översättningsplattform. Utbytet via
.poär identiskt, och flagganpython-brace-formatsom ett t-string-meddelande bär är samma flagga som ett.format()-meddelande bär — så platshållar-QA fortsätter fungera. - Kod som inte är Python. En JavaScript- eller C-katalog i samma projekt påverkas inte.
En migreringschecklista¶
- Lägg till extrat
babeldärpybabelkörs, och bytpython-mappningen ibabel.cfgtill metodengettext_tstrings— en mappning täcker då båda stilarna, och-kfortsätter fungera för de vanliga anropen. - Konvertera
.format()-anropsställena först. Extrahera om, körpybabel update, och committa katalogerna med koden; räkna med noll fuzzy-poster. - Konvertera
%-format-anropsställena i satser du hinner få granskade, skriv om de överförda platshållarna och rensa flaggornafuzzyochpython-format. - Åtgärda det som begränsningen avvisar: en interpolation måste vara ett rent
namn, så
t"Hello {user.name}"blir en lokal variabel först. Det är en ändring på anropsstället, inte i katalogen. - Slå på
strict = truei extraktormappningen när svepet är klart, så att ett meddelande som inte går att extrahera fäller bygget i stället för att försvinna ur mallen. - Lägg till körningskontrollen från I produktion:
rendera ett meddelande per levererat språk genom en strikt
Translator.
Steg 2 och 3 är vanliga commits. Ingenting i den här listan behöver en omställningsdag.