Samouczek¶
Ta strona prowadzi od pustego katalogu do programu, który wita po japońsku. Pięć kroków, żadnego zakładanego doświadczenia z gettext, a każde polecenie jest pokazane z wynikiem, który naprawdę wypisuje — więc na każdym kroku wiesz, czy jesteś na dobrej drodze.
Potrzebujesz Pythona 3.14 lub nowszego, bo t-stringi to nowa składnia w 3.14.
Japoński jest przykładowym językiem docelowym tej strony, ale nic nie zależy
od tego wyboru. Aby użyć innego języka, zamień ja w kroku 4 — ten kod locale
jest jedynym miejscem, które go wskazuje.
1. Zainstaluj¶
Rozszerzenie [babel] dostarcza Babel, narzędzie, które w kroku 3 zbiera
Twoje komunikaty do plików katalogu. To narzędzie czasu deweloperskiego: kod
produkcyjny renderuje wyłącznie z pomocą biblioteki standardowej.
2. Oznacz komunikat w kodzie¶
Utwórz app.py:
t"Hello {name}" wygląda jak f-string, ale przedrostek t trzyma tekst i
wartość osobno, zamiast scalać je na miejscu. To rozdzielenie pozwala funkcji
tr() wyszukać tłumaczenie całego zdania Hello {name} i wstawić wartość
dopiero potem.
Uruchom to teraz:
Żadne tłumaczenia nie są jeszcze zainstalowane, więc tekst źródłowy renderuje się bez zmian. Program używający tej biblioteki nigdy nie wymaga katalogu, żeby działać — angielski (lub jakikolwiek jest Twój język źródłowy) jest wbudowanym zabezpieczeniem.
3. Wyodrębnij komunikaty¶
Tłumacze zwykle pracują na katalogach, a nie na kodzie źródłowym, więc między Wami krąży mały plik zwany katalogiem. Pierwszym krokiem w jego stronę jest zebranie z kodu każdego oznaczonego komunikatu.
Powiedz Babel, jak znaleźć Twoje komunikaty, tworząc babel.cfg:
Następnie wyodrębnij je do pliku szablonu (.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 zawiera teraz jeden wpis na komunikat:
msgid to klucz, po którym Twój kod będzie szukał. Pusty msgstr to miejsce
na tłumaczenie — ale nie w tym pliku: .pot to szablon, a następny krok
kopiuje go raz na każdy język.
4. Przetłumacz i skompiluj¶
Utwórz japoński katalog z szablonu:
$ pybabel init -i locales/messages.pot -d locales -l ja
creating catalog locales/ja/LC_MESSAGES/messages.po based on locales/messages.pot
Otwórz locales/ja/LC_MESSAGES/messages.po i wypełnij msgstr:
Zachowaj {name} dokładnie tak, jak jest — symbol zastępczy jest tym, dzięki
czemu wartość znajduje swoje miejsce w przetłumaczonym zdaniu, a tłumaczenie
może przesunąć go tam, gdzie potrzebuje tego język docelowy. W prawdziwym
projekcie ten plik .po to właśnie to, co przekazujesz tłumaczowi lub
wysyłasz na platformę tłumaczeniową; format jest w obu przypadkach ten sam.
Katalogi edytuje się jako tekst, ale wczytuje w postaci binarnej (.mo),
więc skompiluj:
$ pybabel compile -d locales
compiling catalog locales/ja/LC_MESSAGES/messages.po to locales/ja/LC_MESSAGES/messages.mo
To polecenie jest też siatką bezpieczeństwa. Gdyby tłumaczenie uszkodziło
symbol zastępczy — powiedzmy {nome} zamiast {name} — odmówiłoby przejścia:
$ 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.
Jedno zastrzeżenie, o którym warto wiedzieć od razu: polecenie zgłasza błąd i
kończy się niezerowym kodem wyjścia, ale mimo to zapisuje .mo. W prawdziwym
projekcie to CI musi zatrzymać się na tym kodzie wyjścia — W
produkcji pokazuje, jak to ustawić.
5. Uruchom¶
Kroki 2–4 korzystały z tr(), które szuka katalogu i żadnego nie znajduje.
Teraz, gdy katalog istnieje, wczytaj go i zwiąż raz: Translator przechowuje
katalog, żeby miejsca wywołań nie musiały go nazywać, a _ to konwencjonalna
gettextowa nazwa dla wyniku.
Skieruj app.py na skompilowany katalog. Kliknij znaczniki, żeby zobaczyć,
co robi każda linia:
import gettext
from gettext_tstrings import Translator
_ = Translator(gettext.translation("messages", localedir="locales", languages=["ja"])) # (1)!
name = "Ada"
print(_(t"Hello {name}")) # (2)!
- Biblioteka standardowa wczytuje skompilowany
.mo, aTranslatorwiąże go z obiektem wywoływalnym._to konwencjonalna gettextowa nazwa dla „przetłumacz to" — krótka, bo pojawia się przy każdym łańcuchu widocznym dla użytkownika. Wykonuje to samo tłumaczenie cotr, związane z jednym katalogiem. - W miejscu wywołania: tekst t-stringa staje się kluczem wyszukiwania
Hello {name}, katalog odpowiadaこんにちは {name}, odpowiedź jest sprawdzana względem źródłowych symboli zastępczych i dopiero wtedy wstawiana jest wartość.
To cała pętla i warto zobaczyć ją jako jeden obraz:
flowchart LR
mark["1–2 oznacz<br>t-stringi w kodzie"] --> extract["3 wyodrębnij<br>messages.pot"]
extract --> translate["4 przetłumacz<br>ja/…/messages.po"]
translate --> compile["4 skompiluj<br>ja/…/messages.mo"]
compile --> run["5 uruchom<br>こんにちは Ada"]
Oznacz → wyodrębnij → przetłumacz → skompiluj → uruchom. Wszystko inne na tej stronie jest doprecyzowaniem jednego z tych pięciu kroków.
Co dalej¶
- Dlaczego t-stringi — przed czym ten projekt Cię chroni, w
porównaniu z
%(name)s,.format()i$-stringami. - Przewodnik — liczba mnoga, języki na żądanie, odroczone łańcuchy i to, co dzieje się w czasie działania, gdy katalog mimo wszystko jest błędny.
- W produkcji — ta sama pętla tak, jak prowadzi ją zespół, tydzień po tygodniu: aktualizowanie katalogów, bramki CI i platformy tłumaczeniowe.
- Ekstrakcja — pełna dokumentacja
pybabel: własne nazwy funkcji, ścisły tryb CI i kontrole, które strzegą Twoich katalogów. - Migracja — jeśli projekt, w którym naprawdę chcesz tego użyć, ma już katalogi gettext.
- Dla tłumaczy — jedna strona do przekazania osobie, która
wypełnia linie
msgstr.