Migratie¶
Gebruikt je project al gettext, dan zijn de vragen die bepalen of deze bibliotheek bruikbaar is smalle vragen: maakt ze de catalogi die je hebt ongeldig, kan ze samenleven met de code die je nog niet wilt veranderen, en hoeveel van de verhuizing moet in één keer gebeuren. De antwoorden, het kortste eerst:
| Vraag | Antwoord |
|---|---|
Werken bestaande .po- en .mo-bestanden nog? |
Ja. Dezelfde bestanden, dezelfde tools. |
| Kunnen oude en nieuwe aanroepen in één bestand samenleven? | Ja, en één extractor-mapping dekt beide. |
| Verandert de msgid? | Niet vanuit .format(). Wel vanuit %-format. |
| Moet het hele project in één keer over? | Nee. Eén aanroepplek is een geldige wijziging. |
| En Jinja, Django-templates, JavaScript? | Onaangeroerd, dezelfde catalogi. |
De rest van deze pagina is het detail achter elk van die antwoorden.
Vanuit .format(): de msgid verandert niet¶
Dit is het geval waarin migreren vrijwel niets kost. Een str.format-bericht en
een t-string-bericht leiden dezelfde catalogussleutel af, omdat de sleutel in
beide gevallen de tekst is met {name} er nog in:
# Before
_("Hello {name}").format(name=name)
# After — the msgid is still "Hello {name}"
tr(t"Hello {name}")
De bestaande vertaling blijft er dus aan hangen. Uitgaande van een catalogus met
verander je de aanroep, extraheer je opnieuw, en werk je bij:
$ 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
De entry die terugkomt verschilt in twee regels metadata en verder in niets — een markeringscommentaar dat hem als t-string-bericht aanwijst, en een bronregelnummer:
Geen fuzzy-vlag, geen hervertaling, in geen enkele taal. Het bericht rendert
meteen:
$ 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 meldt de catalogi als verouderd
Dat markeringscommentaar en de verschoven regelnummers zijn genoeg voor
pybabel update --check om te zeggen dat een catalogus opnieuw gegenereerd
moet worden, want het vergelijkt de hele entry en niet alleen de vertaling.
Draai de echte pybabel update in dezelfde commit als de codewijziging, en
commit de catalogi ermee — dezelfde gewoonte die de
CI-poort al vraagt.
Vanuit %-format: de msgid verandert, dus vertalingen worden fuzzy¶
Printf-syntaxis leeft binnen het bericht, dus haar vervangen herschrijft de
catalogussleutel. Daar is geen ontkomen aan, en het is de eerlijke prijs van het
achterlaten van %(name)s:
pybabel update herkent het nieuwe bericht als een naaste verwant van het
verwijderde en neemt de oude vertaling mee, gemarkeerd als fuzzy:
#. gettext-tstrings
#: app.py:4
#, fuzzy, python-brace-format, python-format
msgid "Hello {name}"
msgstr "こんにちは %(name)s"
Drie dingen om over die toestand te weten:
- Er breekt tijdens runtime niets. Fuzzy-entries worden uit de
gecompileerde
.moweggelaten, dus de applicatie rendert het bronbericht totdat een mens het paar bevestigt — dezelfde degradatie die elk geherformuleerd bericht doormaakt. pybabel compilemeldt er elk van, omdat de meegenomen%(name)sgeen geldige accolade-placeholder is, en eindigt met een niet-nul exitcode. Die lijst is je werkvoorraad, geen vals alarm; de entries erin moeten echt bewerkt worden.- De oude
python-format-vlag lift mee en hoort samen met defuzzy-vlag verwijderd te worden, anders blijftmsgfmt --check-formatprintf-regels toepassen op een brace-format-bericht.
Voor benoemde printf-placeholders is de bewerking mechanisch — %(name)s wordt
{name} en verder verschuift er niets — dus een grote catalogus is een
geautomatiseerde doorloop gevolgd door de review van een vertaler, en geen
hervertaling. Positionele %s is niet mechanisch: er is geen naam om mee te
nemen, en er een kiezen is juist de kern van de wijziging.
Daarom is de praktische volgorde om %-format-berichten weloverwogen te
migreren — een module, een release, een taal tegelijk — in plaats van in één
veeg die elke catalogus tegelijk rood kleurt.
Oude en nieuwe aanroepen leven samen¶
De extractor die t-strings leest, leest ook gewone gettext-aanroepen, dus één mapping dekt een bestand middenin de migratie:
from gettext_tstrings import tr
from myapp.i18n import _
name = "Ada"
print(_("Save changes"))
print(tr(t"Hello {name}"))
Beide berichten belanden in hetzelfde sjabloon, en alleen dat van de t-string draagt het markeringscommentaar dat de extra controle van deze bibliotheek inschakelt:
#: app.py:5
msgid "Save changes"
msgstr ""
#. gettext-tstrings
#: app.py:6
#, python-brace-format
msgid "Hello {name}"
msgstr ""
Ze herkent _(), de vier standaard gettext-namen, de aliassen tr() / ntr(),
en de uitgestelde lazy_gettext() / lazy_pgettext(). Een eigen hulpfunctie
moet in de mapping benoemd worden.
Tijdens runtime zijn de twee stijlen even onafhankelijk:
gettext.translation() geeft één vertaalobject terug, en zowel _ als de
instappunten van deze bibliotheek lezen daaruit.
Wat niet verhuist¶
- Sjabloontalen. Jinja2's
{% trans %}, de templatetags van Django en hun Babel-extractors blijven ongewijzigd werken en blijven dezelfde PO-catalogi voeden. T-strings zijn Python-syntaxis; ze gelden voor Python-broncode. - Je catalogusbestanden. Geen formaatwijziging, geen nieuw bestand, geen conversiestap.
- Je vertaalplatform. De
.po-uitwisseling is identiek, en de vlagpython-brace-formatdie een t-string-bericht draagt is dezelfde vlag die een.format()-bericht draagt — dus placeholder-QA blijft werken. - Code die geen Python is. Een JavaScript- of C-catalogus in hetzelfde project blijft onaangeroerd.
Een migratiechecklist¶
- Voeg de
babel-extra toe waarpybabeldraait, en verander depython-mapping inbabel.cfgnaar de methodegettext_tstrings— één mapping dekt dan beide stijlen, en-kblijft werken voor de gewone aanroepen. - Zet eerst de
.format()-aanroepplekken om. Extraheer opnieuw, draaipybabel update, en commit de catalogi met de code; verwacht geen fuzzy-entries. - Zet de
%-format-aanroepplekken om in porties die je gereviewd krijgt, herschrijf de meegenomen placeholders en wis de vlaggenfuzzyenpython-format. - Repareer wat de beperking afwijst: een interpolatie moet een gewone naam
zijn, dus
t"Hello {user.name}"wordt eerst een lokale variabele. Dat is een bewerking op de aanroepplek, niet in de catalogus. - Zet
strict = trueaan in de extractor-mapping zodra de doorloop klaar is, zodat een bericht dat niet geëxtraheerd kan worden de build laat falen in plaats van uit het sjabloon te verdwijnen. - Voeg de runtime-controle uit In productie toe:
render één bericht per uitgeleverde taal via een strikte
Translator.
Stap 2 en 3 zijn gewone commits. Niets in deze lijst vereist een grote omschakeldag.