Vodnik¶
Ta stran je referenca za čas izvajanja: vse, kar vaša aplikacijska koda počne s to knjižnico, ko katalogi že obstajajo. Če celotne zanke — označi, izvleci, prevedi, kompiliraj, zaženi — še niste videli, jo vadnica prehodi enkrat v petih minutah; ustvarjanje in preverjanje katalogov pokriva Ekstrakcija, kako pa ekipa to zanko vrti naprej — cikli posodobitev, CI, prevajalske platforme —, je opisano v V produkciji.
Katero vstopno točko naj uporabim?¶
Paket izvaža več načinov za prevod sporočila, ker aplikacije jezik vežejo na več različnih načinov. Izberite glede na to, kako se vaš program odloči, v katerem jeziku je:
| Vaš položaj | Uporabite |
|---|---|
| En jezik za ves proces — CLI, namizna aplikacija, skript | Translator, klican kot _ |
| En jezik na zahtevo ali na asinhrono opravilo — spletna aplikacija | use_translations() okoli dela, nato tr() |
| Sporočilo, določeno ob uvozu — oznaka obrazca, naštevni tip, konstanta | lazy_gettext() ali lazy_pgettext() |
| O ubeseditvi odloča število | ngettext() / npgettext(), v kateri koli zgornji obliki |
| Izris vzorca, pri katerem ni nobenega kataloga | compile_template() |
Vse spodnje je teh pet, v tem vrstnem redu.
Vezava kataloga¶
Priporočena oblika zrcali gettextovo razredno rabo: standardni prevajalni
objekt vežite enkrat in klicljivi obdelovalec uporabljajte kot _.
import gettext
from gettext_tstrings import Translator
translations = gettext.translation("messages", localedir="locales", languages=["ja"])
_ = Translator(translations)
name = "Ada"
print(_(t"Hello {name}")) # こんにちは Ada
n = 3
print(_.ngettext(t"One file", t"{n} files", n)) # picks the right plural form for n
filename = "report.txt"
print(_.pgettext("button", t"Open {filename}")) # "button" disambiguates homonyms
Funkcije na ravni modula sledijo imenom iz standardne knjižnice in njenemu izključno pozicijskemu klicnemu dogovoru:
from gettext_tstrings import gettext, ngettext, npgettext, pgettext
gettext(t"Hello {name}", translations=translations)
ngettext(t"One file", t"{n} files", n, translations=translations)
pgettext("button", t"Open {filename}", translations=translations)
npgettext("inbox", t"One message", t"{n} messages", n, translations=translations)
tr in ntr sta natančna vzdevka za gettext in ngettext.
Jezik na zahtevo¶
Spletno ogrodje izbere jezik za vsako zahtevo posebej. Prevode zahteve vežite na trenutni kontekst in vsak klic na ravni modula se razreši v ta jezik, varno tudi pri sočasnih zahtevah:
from gettext_tstrings import tr, use_translations
def handle(request):
name = request.user.display_name
translations = load_translations(request.locale)
with use_translations(translations):
return render(tr(t"Hello {name}"))
set_translations(translations) veže brez bloka with, za ogrodja, ki
življenjski cikel zahteve upravljajo sama; get_translations() prebere
trenutno vezavo. Izrecni argument translations= vedno premaga kontekst,
nevezan kontekst pa se zateče h globalno nameščenim funkcijam gettext iz
standardne knjižnice. Razdelana primera za Flask in vmesno programje ASGI sta
na strani V produkciji.
Odloženo prevajanje¶
T-niz svoje vrednosti ujame takoj, kar je napačno za niz, določen ob uvozu — oznako obrazca, vrednost naštevnega tipa, modulsko konstanto —, ki se mora izrisati v tistem jeziku, ki je dejaven ob njegovi rabi.
from gettext_tstrings import lazy_gettext, lazy_pgettext, use_translations
SAVE = lazy_gettext(t"Save changes") # defined once, at import
OPEN = lazy_pgettext("button", t"Open file")
with use_translations(japanese):
assert str(SAVE) == "変更を保存" # rendered here, in this language
LazyString se izriše prek str(), format() in f-nizov ter je enak svojemu
izrisanemu besedilu.
Namenoma nezgoščljiv
Besedilo objekta LazyString je odvisno od dejavnega jezika, zato bi se
zgostitev ob zamenjavi jezika spremenila in tiho pokvarila vsako množico ali
slovar, ki ga hrani. Če potrebujete ključ, najprej pokličite str().
O strict se odloči tam, kjer je sporočilo zapisano, ne tam, kjer se izriše:
Odloženi niz se izriše tam, kjer je nazadnje uporabljen — znotraj predloge,
obrazca, dnevniške vrstice —, in to mesto le redko ve, ali gre za testni tek ali
za produkcijo. Prav strict=True ob določitvi je tisto, kar omogoči, da ista
izbira glasno v CI, prizanesljivo v produkciji
velja tudi za niz, ki se ne izriše na svojem klicnem mestu.
Množinske oblike so odvisne od števila med izvajanjem, zato jih tam, kjer je
število znano, izrišite takoj z ngettext.
Več jezikov hkrati¶
Ena sama zahteva pogosto potrebuje več kot en jezik: stran, izrisana za bralca, ki hkrati uvrsti v vrsto obvestilo za račun, nastavljen na drug jezik, ali povzetek, ki vsakega udeleženca navede v njegovem lastnem. Vezave se gnezdijo, izhod iz notranjega bloka pa obnovi zunanjega.
with use_translations(reader):
page = tr(t"Hello {name}")
with use_translations(recipient):
notice = tr(t"Hello {name}") # the recipient's language
footer = tr(t"Hello {name}") # the reader's again
Pri seznamu prejemnikov delo opravijo odloženi nizi: sporočilo je zapisano enkrat, ob uvozu, izriše pa se enkrat za vsak jezik.
SUBJECT = lazy_gettext(t"Your order shipped")
for user in users:
with use_translations(load_translations(user.locale)):
send(user.email, str(SUBJECT))
Vezava je ContextVar in ne sklad na deljenem objektu, zato prekrivajoče se
zahteve ne morejo pobrati jezika druga drugi — tudi tedaj ne, kadar svoje bloke
zapustijo v istem vrstnem redu, kot so vanje vstopile, kar je prav
prepletanje, ki ga sklad zgreši. Nalaganje kataloga za vsak jezik je poceni:
gettext.translation() vsak .mo razčleni enkrat in razdaja kopije, ki si
razčlenjeni katalog delijo.
Ali delovna nit podeduje vezavo, je odvisno od gradnje
Gola threading.Thread ali ThreadPoolExecutor.submit se začne bodisi s
kopijo klicateljevega konteksta bodisi s praznim; katero od tega, določa
sys.flags.thread_inherit_context — privzeto resničen na prostonitnih
gradnjah in neresničen povsod drugod. Ista koda zato na 3.14t izriše vezani
jezik, na 3.14 pa globalni gettextov katalog procesa. Kontekst podajte,
namesto da bi se zanašali na privzeto vrednost:
asyncio.to_thread to za vas stori že sam.
Vrednosti glede na locale¶
Ta knjižnica odloči, kje se vrednost pojavi v prevedenem sporočilu.
Vrednosti same ne lokalizira. {amount:,.2f} je pythonska formatna
specifikacija z nespremenljivim vedenjem — vejica na vsake tri števke in pika
pred decimalkami — in proizvede iste znake, ne glede na to, v katerem jeziku
je sporočilo:
Nemščina to število zapiše 1.234,50, francoščina 1 234,50, hindijščina pa
1234567 združuje kot 12,34,567 in ne 1,234,567. Števila, valute, datumi,
ure in enote sodijo k Babelu. Vrednost najprej oblikujte,
nato postavite dokončani niz:
from babel.numbers import format_currency
total = format_currency(amount, "EUR", locale=locale)
tr(t"Your order comes to {total}")
Pri sporočilu s številom to število opravlja dve nalogi — izbere množinsko obliko in se pojavi v besedilu — lokalizirana pa je le druga. Za izbiro ohranite surovo število, za prikaz pa podajte oblikovani niz:
from babel.numbers import format_decimal
shown = format_decimal(n, locale=locale)
_.ngettext(t"One file", t"{shown} files", n)
Oblikovanje pred klicem je tudi tisto, kar formatno specifikacijo drži zunaj kataloga: prevajalec vidi dokončan kos besedila, ne števila skupaj z navodili za njegov izris.
Kaj se zgodi, kadar je katalog napačen¶
Če se ograde prevoda ne ujemajo z izvornimi — manjkajoče, neznano ali preoblikovano polje, ki se je izmuznilo preverjanju, iz ročno urejenega MO, iz prevzetega kataloga ali iz cevovoda, ki preskoči preverjevalnik —, je privzeti odziv, da se izriše izvorno sporočilo, ne pa da se sproži izjema. To zrcali gettextov lastni dogovor, da slab katalog nikoli ne pokvari aplikacije.
Kadar je Hello {name} preveden kot こんにちは {nombre}, izris uspe, v
dnevnik gettext_tstrings pa gre eno opozorilo:
WARNING gettext_tstrings: invalid translation for msgid 'Hello {name}'; using
source text: translation does not match the source placeholders: {name} is
missing; {nombre} is not in the source message
Opozorilo se sproži enkrat na sporočilo in vzorec, ne enkrat na izris, tako da pokvarjen katalogni vnos ne preplavi dnevnika.
Za teste in CI se lahko odločite za glasno odpoved:
strict = Translator(translations, strict=True)
tr(t"Hello {name}", translations=translations, strict=True)
Isto iskanje tedaj sproži izjemo z isto povedjo, le brez polovice o »using source text«:
>>> strict(t"Hello {name}")
Traceback (most recent call last):
...
gettext_tstrings.errors.InvalidTranslationError: translation does not match the
source placeholders: {name} is missing; {nombre} is not in the source message
Ta sporočila so napisana za tistega, ki lahko ukrepa, pri težavi s katalogom pa
je to pogosteje prevajalec kot programer — zato tam, kjer je ograda videti
navzoča, pa ni, sporočilo pojasni zakaj, namesto da bi ponavljalo, da manjka.
Široki zaviti oklepaji, podvojeni {{name}}, neviden nedeljivi presledek,
cirilska črka med latinskimi: vsak ima svojo ubeseditev, naštete pa so s
primeri vred na strani
Za prevajalce. Ta stran je napisana
tako, da jo izročite osebi, ki ureja .po.
Izris vzorca brez kataloga¶
compile_template isto strojevje razkrije eno raven nižje: t-niz spremeni v
njegov msgid in vezano množico vrednosti ter izriše kateri koli vzorec, ki mu
ga izročite.
from gettext_tstrings import compile_template
name = "Ada"
compiled = compile_template(t"Hello {name}")
compiled.msgid # "Hello {name}"
compiled.placeholders # ("name",)
compiled.render("こんにちは {name}") # "こんにちは Ada"
render preverja po istih pravilih in ob neujemanju vedno sproži izjemo.
Prizanesljivega načina tu ni: prizanesljivost obstaja zato, da se lahko
iskanje po katalogu poslabša do izvornega besedila, vzorec, ki ste ga izročili
sami, pa nima od česa poslabšati.
Varnost in obseg¶
To je veljavno:
To je zavrnjeno namenoma:
Najprej izračunajte smiselno vrednost:
Omejitev daje stabilne katalogne ključe, prevajalcem uporabna imena in preprečuje, da bi preveden niz postal izrazni jezik.
Jamstvo je omejeno na zgradbo in oblikovanje: prevod se nikoli ne ovrednoti in nikoli ne more dodati dostopa do atributov, klicev, pretvorb ali formatnih specifikacij. Dvoje ostaja odgovornost klicatelja, natanko kot pri gettextu iz standardne knjižnice — ubežno zapisovanje izrisanega izhoda za njegov ponor (HTML, lupina, terminal) in celovitost kataloga, saj lahko sovražen katalog ogrado ponovi in tako napihne velikost izhoda, kar je lastno vsakemu i18n, ki temelji na ogradah.