Hướng dẫn nhập môn¶
Trang này đưa bạn từ một thư mục trống đến một chương trình chào hỏi bằng tiếng Nhật. Năm bước, không đòi hỏi kinh nghiệm gettext nào, và mỗi lệnh đều được trình bày kèm đầu ra mà nó thực sự tạo ra — nhờ vậy ở từng bước bạn biết mình có đang đi đúng hướng hay không.
Bạn cần Python 3.14 trở lên, vì t-string là cú pháp mới trong 3.14. Tiếng
Nhật là ngôn ngữ đích ví dụ của trang này, nhưng không có gì phụ thuộc vào
lựa chọn đó. Muốn dùng ngôn ngữ khác, hãy thay ja ở bước 4 — mã locale ấy
là thứ duy nhất gọi tên nó.
1. Cài đặt¶
Phần mở rộng [babel] kéo theo Babel, công cụ thu thập các thông điệp của
bạn vào các tệp catalog ở bước 3. Đây là công cụ dùng lúc phát triển: mã chạy
production kết xuất chỉ với thư viện chuẩn.
2. Đánh dấu một thông điệp trong mã¶
Tạo app.py:
t"Hello {name}" trông giống một f-string, nhưng tiền tố t giữ phần văn
bản và giá trị tách rời nhau thay vì gộp chúng lại ngay tại chỗ. Chính sự
tách rời đó là điều cho phép tr() tra cứu bản dịch cho trọn vẹn câu
Hello {name} rồi mới chèn giá trị vào sau.
Chạy thử ngay:
Chưa có bản dịch nào được cài đặt, nên văn bản nguồn được kết xuất nguyên trạng. Một chương trình dùng thư viện này không bao giờ bắt buộc phải có catalog mới chạy được — tiếng Anh (hoặc bất kỳ ngôn ngữ nguồn nào của bạn) là phương án dự phòng có sẵn.
3. Trích xuất các thông điệp¶
Người dịch thường làm việc với catalog chứ không phải với mã nguồn, nên một tệp nhỏ gọi là catalog sẽ qua lại giữa bạn và họ. Bước đầu tiên để có được nó là gom mọi thông điệp đã đánh dấu ra khỏi mã.
Cho Babel biết cách tìm các thông điệp của bạn bằng cách tạo babel.cfg:
Rồi trích xuất vào một tệp mẫu (.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 giờ chứa một mục cho mỗi thông điệp:
msgid là khóa mà mã của bạn sẽ tra cứu. msgstr trống là chỗ điền bản
dịch — nhưng không phải trong tệp này: .pot là một tệp mẫu, và bước tiếp
theo sẽ sao chép nó, mỗi ngôn ngữ một bản.
4. Dịch và biên dịch¶
Tạo catalog tiếng Nhật từ tệp mẫu:
$ pybabel init -i locales/messages.pot -d locales -l ja
creating catalog locales/ja/LC_MESSAGES/messages.po based on locales/messages.pot
Mở locales/ja/LC_MESSAGES/messages.po và điền vào msgstr:
Hãy giữ {name} nguyên xi — placeholder là cách giá trị tìm được chỗ đứng
của mình trong câu đã dịch, và bản dịch hoàn toàn tự do di chuyển nó đến bất
cứ đâu ngôn ngữ đích cần. Trên một dự án thực tế, tệp .po này chính là thứ
bạn giao cho người dịch hoặc tải lên một nền tảng dịch thuật; định dạng đều
như nhau trong cả hai trường hợp.
Catalog được chỉnh sửa ở dạng văn bản nhưng được nạp ở dạng nhị phân
(.mo), nên hãy biên dịch:
$ pybabel compile -d locales
compiling catalog locales/ja/LC_MESSAGES/messages.po to locales/ja/LC_MESSAGES/messages.mo
Lệnh này đồng thời là một lưới an toàn. Giả sử bản dịch làm hỏng
placeholder — chẳng hạn {nome} thay vì {name} — nó sẽ từ chối cho qua:
$ 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.
Có một điểm đáng biết ngay từ bây giờ: lệnh này báo lỗi và thoát với mã khác
không, nhưng vẫn ghi tệp .mo ra. Trong một dự án thật, chính CI mới là thứ
phải dừng lại trước mã thoát đó — Vận hành thực
tế dựng sẵn phần ấy.
5. Chạy chương trình¶
Các bước 2–4 dùng tr(), hàm này đi tìm một catalog và không thấy gì. Giờ đã
có một catalog, hãy nạp nó và gắn một lần: Translator giữ một catalog để
những nơi gọi không phải nêu tên nó nữa, còn _ là tên gettext quy ước cho
kết quả.
Trỏ app.py vào catalog đã biên dịch. Nhấp vào các dấu chú thích để xem từng
dòng đang làm gì:
import gettext
from gettext_tstrings import Translator
_ = Translator(gettext.translation("messages", localedir="locales", languages=["ja"])) # (1)!
name = "Ada"
print(_(t"Hello {name}")) # (2)!
- Thư viện chuẩn nạp tệp
.mođã biên dịch, vàTranslatorgắn nó vào một đối tượng gọi được._là tên quy ước của gettext cho "hãy dịch cái này" — ngắn gọn vì nó xuất hiện trên mọi chuỗi hướng tới người dùng. Nó thực hiện đúng phép dịch nhưtr, nhưng gắn với một catalog. - Tại lời gọi: phần văn bản của t-string trở thành khóa tra cứu
Hello {name}, catalog trả lờiこんにちは {name}, câu trả lời được kiểm tra so với các placeholder nguồn, và chỉ sau đó giá trị mới được đưa vào.
Đó là toàn bộ vòng lặp, và nó đáng được nhìn như một bức tranh duy nhất:
flowchart LR
mark["1–2 đánh dấu<br>t-string trong mã"] --> extract["3 trích xuất<br>messages.pot"]
extract --> translate["4 dịch<br>ja/…/messages.po"]
translate --> compile["4 biên dịch<br>ja/…/messages.mo"]
compile --> run["5 chạy<br>こんにちは Ada"]
Đánh dấu → trích xuất → dịch → biên dịch → chạy. Mọi thứ còn lại trên trang web này đều là sự tinh chỉnh của một trong năm bước đó.
Tiếp theo đi đâu¶
- Vì sao chọn t-string — thiết kế này bảo vệ bạn khỏi điều
gì, so với
%(name)s,.format()và chuỗi$. - Cẩm nang — số nhiều, ngôn ngữ theo từng request, chuỗi trì hoãn, và điều gì xảy ra lúc chạy khi catalog dù sao cũng bị sai.
- Vận hành thực tế — chính vòng lặp này khi một đội ngũ vận hành nó, tuần này qua tuần khác: cập nhật catalog, cổng chặn CI và các nền tảng dịch thuật.
- Trích xuất — tài liệu tham khảo
pybabelđầy đủ: tên hàm tùy chỉnh, chế độ CI nghiêm ngặt, và các bước kiểm tra bảo vệ catalog của bạn. - Chuyển đổi — nếu dự án bạn thực sự muốn làm điều này đã có sẵn catalog gettext.
- Dành cho người dịch — một trang duy nhất để đưa cho ai đó
sẽ điền vào những dòng
msgstrấy.