コンテンツにスキップ

完全なメッセージを訳す、
Pythonのt-stringで。

gettext-tstringsは、Python 3.14以降のt-stringを標準のgettextカタログとBabel のツール群へつなぎます。値と書式指定はアプリケーションのコードに残り、翻訳者は 完全なメッセージと{name}という単純なプレースホルダーを扱います。

import gettext

from gettext_tstrings import Translator

_ = Translator(gettext.translation("messages", localedir="locales"))
name = "Ada"
print(_(t"Hello {name}"))  # with a Japanese catalog: こんにちは Ada

カタログに入るのはHello {name}です。翻訳では{name}を移動させたり繰り返したり できます。プレースホルダーを削除したり、名前を変えたり、書式を付け替えたりすると、 カタログの検証がそのエラーを報告します。不正なエントリがそれでも本番へ届いた 場合、ライブラリは警告をログへ記録し、クラッシュせずにソースメッセージを レンダリングします。

5分のチュートリアルを始める 他の選択肢と比べる

alpha版 · Python 3.14以降 · 標準のPO/MOカタログ · サードパーティの実行時依存なし

このサイト自身が、ここに書かれていることを実践しています。ナビゲーション、 ラベル、複数形に対応したビルドレポートを含むどの言語版も、POカタログから gettext-tstrings自身で描画しています。

あなたに向いているか

いま向いているのは、アプリケーションがPython 3.14以降で動いていて、すでに gettextとBabelを使っている(あるいはそのPO/MOワークフローを採り入れたい)、 そしてレンダリング前に検査される名前付きプレースホルダーをt-stringの構文で 書きたい場合です。

まだ向いていないのは、Python 3.13以前が必要な場合、安定したPython APIが 必要な場合 — これはalpha版で、固まっているのは仕様の部分です — あるいは翻訳対象のテキストのほとんどが、Pythonソースではなくテンプレート言語の 中にある場合です。

すでにカタログがありますか。そのまま動き続けます。 _("Hello {name}").format(name=name)tr(t"Hello {name}")は同じmsgidを 生成するので、既存の翻訳は乗り換えても失われません — 移行の全体像は 移行で説明します。

カタログが言えること

翻訳は、自分が翻訳するメッセージの構造を変えられない。約束はこれがすべてで、 このサイトの残りはすべてそこから導かれます。翻訳では{name}の順序を変えたり 繰り返したりでき、その周りの語はすべて書き換えられます。ただし、プレースホルダーを 省略すること、新しいものをでっち上げること、そこからあなたのオブジェクトへ手を 伸ばすこと、独自の書式指定を付けることはできません。

ライブラリはそれを入口で — カタログのコンパイル時に — 検査し、レンダリング時に もう一度検査します。これが、レビューで見つかる誤りと、ユーザーに見つかる誤りとの 違いです。

gettextが初めての方へ — ワークフロー全体を4文で

gettextは、Pythonに限らず広く使われている、ソフトウェアを翻訳するための 標準的な仕組みです。コードが翻訳対象のメッセージをマークし、抽出器がそれらを templateファイル(.pot)へ集めます。翻訳者 — 多くの場合programmerでは ありません — が言語ごとに1つのカタログファイル(.po)を埋め、それが バイナリの.moへコンパイルされ、アプリケーションが実行時に読み込みます。 翻訳関数の慣習的な名前は_なので、_(t"Hello {name}")は「このメッセージを 翻訳する」と読めます。チュートリアルでは、マーク、抽出、 翻訳、コンパイル、実行という一連の流れを5分ほどで一巡します。

解決する課題

f-stringはライブラリが受け取る時点ですでに補間済みです。f"Hello {name}""Hello Ada"になっており、値の前後の断片を翻訳することは、ほとんどの言語で 文法を壊します。t-string(PEP 750)は、静的なテキスト、評価済みの値、元の式、 変換指定、フォーマット指定を分離したまま保持します。これはメッセージカタログが 必要とする分離そのものです。%(name)s.format()$文字列と比べて 何が変わるのかを確認できます。

ただし、gettextにもBabelにも、t-stringをどのようにメッセージへ変換するかの 規定はありません。このライブラリはその規約を定め、 バージョン付きの仕様として文書化し、実装を検証する 適合性テストスイートも提供します。

設計上の規則

  • 文の断片ではなく、常に完全なメッセージを翻訳します。
  • {name} のような単純な変数名だけを受け付けます。
  • !r:.2f はアプリケーション側で管理し、カタログには渡しません。
  • 翻訳が既知のプレースホルダーを並べ替えたり繰り返したりすることは認めつつ、 属性へ手を伸ばしたり書式を追加したりすることは防ぎます。
  • 一般的なPOT、PO、MOファイルと、それらに対応する既存ツールを再利用します。

そして、意図的に手を出さないことの一覧も対になっています。数値、通貨、日付の ローカライズはしません — 先に整形してください、 Babelで。HTML、shell、terminalといった出力先に応じたレンダリング結果のescape もしません。そして翻訳が正しいかどうかは判定できません。判定できるのは プレースホルダーが無傷かどうかだけです。

インストール

python -m pip install gettext-tstrings

Python 3.14以降が必要です。レンダリングには依存パッケージがありません。 標準ライブラリの gettext だけを使用します。

抽出とカタログ検証はBabel経由で行います。pybabel を実行する環境にextraを インストールしてください。通常は本番イメージではなく、開発環境やCIです。

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

次に読むページ

まずはここから — gettextの経験は前提としません:

  • チュートリアル — 空のディレクトリから動く日本語翻訳まで 5ステップ、すべてのコマンドを出力付きで示します。
  • t-stringを選ぶ理由 — 同じメッセージを4通りで記述し、 %(name)s.format()$文字列がそれぞれカタログに何を渡すかを比較します。

使う — 実務のリファレンス:

  • ガイド — ランタイムAPI。どの入り口を使うか、複数形、 リクエストごとの言語、遅延文字列、不正なカタログへの対応を説明します。
  • 抽出pybabel のリファレンス。設定、独自の関数名、 既存ツールが追加コストなしにカタログを検証する仕組みを説明します。
  • 実運用 — チームが回すループ。更新サイクル、fuzzy エントリ、CIゲート、翻訳プラットフォーム、そして出荷を説明します。
  • 移行 — すでにカタログのあるプロジェクトへ、呼び出し箇所を 1つずつ導入していく方法です。
  • 翻訳者向け.poファイルを編集する人へそのまま渡せる 1ページです。

理解する — 歴史から実装まで:

  • 背景 — このライブラリが存在する理由。30年にわたる gettext、2つのPEP、そして答えのないまま閉じられた標準ライブラリの議論を 辿ります。
  • 落とし穴 — このサイトを35言語へ翻訳して実際に壊れたもの、 そしてそのうち道具が捕まえられる半分を説明します。
  • 動作原理 — PEP 750のtemplateオブジェクトから レンダリング済み文字列まで、そして検査を安価にするキャッシュを説明します。

リファレンス — 契約:

  • API — パッケージが公開するすべての要素を1ページにまとめています。
  • 仕様 — t-stringとmsgidの対応を、機械可読な適合性テストを備えた 安定したバージョン付き契約として定義します。

開発状況

パッケージ版数 0.1.0a8
APIの安定性 alpha — Python APIは今後変更される可能性があります
仕様 v1、適合性テスト付き
Python 3.14以降。3.14、3.14t(free-threaded)、3.15でテスト済み
Babel 2.18以降。pybabelを動かす場所でのみ必要
実行時依存 なし — 標準ライブラリのgettextのみ
カタログ形式 通常のPOT、PO、MO
変更履歴 CHANGELOG

現在はalpha版です。契約は意図的に小さく保たれ、 仕様が安定部分です。Python APIは今後変更される可能性があります。 安定版までには、より多くの言語のfixture、継続的な性能計測、gettextとBabelの 実利用者によるAPIレビュー、対応するすべてのPython/Babelリリースでの互換性検証が 必要です。

IssueとPull Requestを歓迎します。 alpha版の今こそ、インターフェースを議論する価値があります。

コミュニティに参加する