Gå till innehållet

Handledning

Den här sidan går från en tom katalog till ett program som hälsar på japanska. Fem steg, ingen gettext-erfarenhet förutsätts, och varje kommando visas med den utdata det faktiskt producerar — så att du i varje steg vet om du är på rätt spår.

Du behöver Python 3.14 eller nyare, eftersom t-strings är ny syntax i 3.14. Japanska är sidans exempelmål, men ingenting hänger på det valet. För att använda ett annat språk byter du ut ja i steg 4 — den språkkoden är det enda som namnger det.

1. Installera

python -m pip install "gettext-tstrings[babel]"

Extrat [babel] drar in Babel, verktyget som samlar dina meddelanden i katalogfiler i steg 3. Det är ett utvecklingsverktyg: produktionskod renderar med enbart standardbiblioteket.

2. Markera ett meddelande i din kod

Skapa app.py:

from gettext_tstrings import tr

name = "Ada"
print(tr(t"Hello {name}"))

t"Hello {name}" ser ut som en f-string, men prefixet t håller texten och värdet åtskilda i stället för att slå ihop dem på plats. Den åtskillnaden är vad som låter tr() slå upp en översättning för hela meningen Hello {name} och sätta in värdet efteråt.

Kör det nu:

$ python app.py
Hello Ada

Inga översättningar är installerade ännu, så källtexten renderas som den är. Ett program som använder det här biblioteket kräver aldrig en katalog för att köra — engelska (eller vad ditt källspråk nu är) är den inbyggda reservlösningen.

3. Extrahera meddelandena

Översättare arbetar oftast utifrån kataloger snarare än utifrån källkod, så en liten fil som kallas katalog reser mellan dig och dem. Första steget mot en sådan är att samla ihop varje markerat meddelande ur koden.

Berätta för Babel hur den hittar dina meddelanden genom att skapa babel.cfg:

[gettext_tstrings: **.py]
encoding = utf-8

Extrahera sedan till en mallfil (.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 innehåller nu en post per meddelande:

#. gettext-tstrings
#: app.py:4
#, python-brace-format
msgid "Hello {name}"
msgstr ""

msgid är nyckeln din kod slår upp. Den tomma msgstr är där en översättning hamnar — men inte i den här filen: en .pot är en mall, och nästa steg kopierar den en gång per språk.

4. Översätt och kompilera

Skapa den japanska katalogen från mallen:

$ pybabel init -i locales/messages.pot -d locales -l ja
creating catalog locales/ja/LC_MESSAGES/messages.po based on locales/messages.pot

Öppna locales/ja/LC_MESSAGES/messages.po och fyll i msgstr:

msgid "Hello {name}"
msgstr "こんにちは {name}"

Behåll {name} exakt som det är — platshållaren är hur värdet hittar sin plats i den översatta meningen, och översättningen får fritt flytta den dit målspråket behöver den. I ett riktigt projekt är den här .po-filen vad du lämnar över till en översättare eller laddar upp till en översättningsplattform; formatet är detsamma i båda fallen.

Kataloger redigeras som text men läses in i binär form (.mo), så kompilera:

$ pybabel compile -d locales
compiling catalog locales/ja/LC_MESSAGES/messages.po to locales/ja/LC_MESSAGES/messages.mo

Det här kommandot är också ett skyddsnät. Hade översättningen skadat platshållaren — säg {nome} i stället för {name} — skulle det vägra släppa igenom:

$ 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.

En sak värd att känna till redan nu: det rapporterar felet och avslutar med nollskild status, men skriver .mo-filen ändå. I ett riktigt projekt är det CI som måste stanna på den statusen — I produktion sätter upp det.

5. Kör det

Steg 2–4 använde tr(), som letar efter en katalog och inte hittar någon. Nu när det finns en: läs in den och bind den en gång. Translator håller en katalog så att anropsställena slipper namnge den, och _ är det konventionella gettext-namnet för resultatet.

Peka app.py mot den kompilerade katalogen. Klicka på markörerna för att se vad varje rad gör:

import gettext

from gettext_tstrings import Translator

_ = Translator(gettext.translation("messages", localedir="locales", languages=["ja"]))  # (1)!

name = "Ada"
print(_(t"Hello {name}"))  # (2)!
  1. Standardbiblioteket läser in den kompilerade .mo-filen, och Translator binder den till en anropbar funktion. _ är det konventionella gettext-namnet för "översätt det här" — kort eftersom det förekommer vid varje sträng som möter användaren. Den utför samma översättning som tr, bunden till en katalog.
  2. Vid anropet: t-strängens text blir uppslagsnyckeln Hello {name}, katalogen svarar こんにちは {name}, svaret kontrolleras mot källans platshållare, och först därefter sätts värdet in.
$ python app.py
こんにちは Ada

Det är hela kretsloppet, och det är värt att se som en enda bild:

flowchart LR
  mark["1–2 markera<br>t-strings i koden"] --> extract["3 extrahera<br>messages.pot"]
  extract --> translate["4 översätt<br>ja/…/messages.po"]
  translate --> compile["4 kompilera<br>ja/…/messages.mo"]
  compile --> run["5 kör<br>こんにちは Ada"]

Markera → extrahera → översätt → kompilera → kör. Allt annat på den här webbplatsen är en förfining av något av dessa fem steg.

Vart härnäst

  • Varför t-strings — vad den här designen skyddar dig mot, jämfört med %(name)s, .format() och $-strängar.
  • Guide — pluralformer, språk per förfrågan, uppskjutna strängar, och vad som händer vid körning när en katalog ändå är fel.
  • I produktion — samma kretslopp så som ett team kör det, vecka efter vecka: kataloguppdateringar, CI-grindar och översättningsplattformar.
  • Extrahering — den fullständiga pybabel-referensen: egna funktionsnamn, strikt CI-läge och kontrollerna som vaktar dina kataloger.
  • Migrering — om projektet du egentligen vill göra det här i redan har gettext-kataloger.
  • För översättare — den enda sidan att räcka över till den som fyller i de där msgstr-raderna.