pybabelコマンドで pot, po, mo, ファイルを作ってみた。
成果物
Python.i18n.Babel.201709151320
前回
pybabel
Babelをインストールすると、pybabel
コマンドが使えるようになる。
$ pybabel -h Usage: pybabel command [options] [args] Options: --version show program's version number and exit -h, --help show this help message and exit --list-locales print all known locales and exit -v, --verbose print as much as possible -q, --quiet print as little as possible commands: compile compile message catalogs to MO files extract extract messages from source files and generate a POT file init create new message catalogs from a POT file update update existing message catalogs from a POT file
ヘルプにあるように、POT
, MO
ファイルを作成できる。PO
ファイルはpybabel init -l ja
等のコマンドで作成できる。
サブコマンド | 生成 |
---|---|
extract | py →pot |
init | pot →po |
compile | po →mo |
extract
py
→pot
。コマンドを確認してみる。
$ pybabel extract -h Usage: pybabel extract [options] <input-paths> extract messages from source files and generate a POT file Options: -h, --help show this help message and exit --charset=CHARSET charset to use in the output file (default "utf-8") -k KEYWORDS, --keywords=KEYWORDS, --keyword=KEYWORDS space-separated list of keywords to look for in addition to the defaults (may be repeated multiple times) --no-default-keywords do not include the default keywords -F MAPPING_FILE, --mapping-file=MAPPING_FILE, --mapping=MAPPING_FILE path to the mapping configuration file --no-location do not include location comments with filename and line number --add-location=ADD_LOCATION location lines format. If it is not given or "full", it generates the lines with both file name and line number. If it is "file", the line number part is omitted. If it is "never", it completely suppresses the lines (same as --no-location). --omit-header do not include msgid "" entry in header -o OUTPUT_FILE, --output-file=OUTPUT_FILE, --output=OUTPUT_FILE name of the output file -w WIDTH, --width=WIDTH set output line width (default 76) --no-wrap do not break long message lines, longer than the output line width, into several lines --sort-output generate sorted output (default False) --sort-by-file sort output by file location (default False) --msgid-bugs-address=MSGID_BUGS_ADDRESS set report address for msgid --copyright-holder=COPYRIGHT_HOLDER set copyright holder in output --project=PROJECT set project name in output --version=VERSION set project version in output -c ADD_COMMENTS, --add-comments=ADD_COMMENTS place comment block with TAG (or those preceding keyword lines) in output file. Separate multiple TAGs with commas(,) -s, --strip-comments, --strip-comment-tags strip the comment TAGs from the comments. --input-dirs=INPUT_DIRS alias for input-paths (does allow files as well as directories).
以下のように打ってみる。指定ディレクトリ以下を再帰的に検索し、存在する全.py
ファイルから_(...)
部分を抽出する。
$ pybabel extract --input-dirs=/tmp/Python.i18n.Babel.201709151320/src -o hello.pot extracting messages from /tmp/Python.i18n.Babel.201709151320/src/main.py extracting messages from /tmp/Python.i18n.Babel.201709151320/src/sub.py extracting messages from /tmp/Python.i18n.Babel.201709151320/src/mypackage/mymodule.py writing PO template file to hello.pot
以下のようなファイルがカレントディレクトリに出力された。
hello.pot
# Translations template for PROJECT. # Copyright (C) 2017 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # FIRST AUTHOR <EMAIL@ADDRESS>, 2017. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2017-09-15 14:45+0900\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.5.1\n" #: /tmp/Python.i18n.Babel.201709151320/src/main.py:7 msgid "Hello World !!" msgstr "" #: /tmp/Python.i18n.Babel.201709151320/src/main.py:17 msgid "Welcome i18n !!" msgstr "" #: /tmp/Python.i18n.Babel.201709151320/src/sub.py:1 msgid "Good bye." msgstr "" #: /tmp/Python.i18n.Babel.201709151320/src/mypackage/mymodule.py:1 msgid "Good Luck !" msgstr ""
複数.py
ファイルの_()
部分が抽出され、このファイルに記載されているのがわかる。
init
pot
→po
。
まずは先ほど作ったhello.pot
をコピペしてhello_ja.pot
にする。適当にmsgstr
を埋めていく。
次に、pybabel init
サブコマンドを確認してみる。
$ pybabel init -h Usage: pybabel init [options] create new message catalogs from a POT file Options: -h, --help show this help message and exit -D DOMAIN, --domain=DOMAIN domain of PO file (default 'messages') -i INPUT_FILE, --input-file=INPUT_FILE name of the input file -d OUTPUT_DIR, --output-dir=OUTPUT_DIR path to output directory -o OUTPUT_FILE, --output-file=OUTPUT_FILE name of the output file (default '<output_dir>/<locale>/LC_MESSAGES/<domain>.po') -l LOCALE, --locale=LOCALE locale for the new localized catalog -w WIDTH, --width=WIDTH set output line width (default 76) --no-wrap do not break long message lines, longer than the output line width, into several lines
$ pybabel init -D hello -l ja -i hello_ja.pot -d ./languages/ creating catalog ./languages/ja/LC_MESSAGES/hello.po based on hello_ja.pot
ドメイン名、ロケール名(言語名)、入力ファイルパス、出力ディレクトリ、の4つを指定する必要がある。
compile
po
→mo
。
$ pybabel compile -h Usage: pybabel compile [options] compile message catalogs to MO files Options: -h, --help show this help message and exit -D DOMAIN, --domain=DOMAIN domains of PO files (space separated list, default 'messages') -d DIRECTORY, --directory=DIRECTORY path to base directory containing the catalogs -i INPUT_FILE, --input-file=INPUT_FILE name of the input file -o OUTPUT_FILE, --output-file=OUTPUT_FILE name of the output file (default '<output_dir>/<locale>/LC_MESSAGES/<domain>.mo') -l LOCALE, --locale=LOCALE locale of the catalog to compile -f, --use-fuzzy also include fuzzy translations --statistics print statistics about translations
$ pybabel compile -D hello -d ./languages/ compiling catalog ./languages/ja/LC_MESSAGES/hello.po to ./languages/ja/LC_MESSAGES/hello.mo
update
pot
からpo
を更新する。
pot
はソースコードから_(...)
を抽出したもの。ソースコードに新しいメッセージができたり、既存メッセージの実装行数が変わったりしたら新規にpot
を作りなおすことになる。その後、既存のpo
を更新してくれるのがこのコマンド。本コマンドで更新後、新しいメッセージは.po
ファイル内でmsgstr ""
として追加されている。
$ pybabel init ...
だと.po
ファイルを上書きしてしまい、これまで入力した翻訳テキストがすべてmsgstr ""
になってしまう。それを避けるのが本コマンドの意義。
$ pybabel update -h Usage: pybabel update [options] update existing message catalogs from a POT file Options: -h, --help show this help message and exit -D DOMAIN, --domain=DOMAIN domain of PO file (default 'messages') -i INPUT_FILE, --input-file=INPUT_FILE name of the input file -d OUTPUT_DIR, --output-dir=OUTPUT_DIR path to base directory containing the catalogs -o OUTPUT_FILE, --output-file=OUTPUT_FILE name of the output file (default '<output_dir>/<locale>/LC_MESSAGES/<domain>.po') -l LOCALE, --locale=LOCALE locale of the catalog to compile -w WIDTH, --width=WIDTH set output line width (default 76) --no-wrap do not break long message lines, longer than the output line width, into several lines --ignore-obsolete whether to omit obsolete messages from the output -N, --no-fuzzy-matching do not use fuzzy matching --update-header-comment update target header comment --previous keep previous msgids of translated messages
$ pybabel update -D hello -l en -i hello.pot -d ./languages/ updating catalog ./languages/en/LC_MESSAGES/hello.po based on hello.pot
便利な点
pygettext.py、msgfmt.pyの2ツールを使ったときと比べて便利な点は以下。
- 指定ディレクトリ配下の全
py
ファイルからpot
ファイルを作成できる - 新規
pot
から既存po
ファイルを更新(マージ)できる <lang_code>/LC_MESSAGES/<domain>.po
などのディレクトリを自動生成してくれる
だいぶ楽になる。
理想
- ソースコードファイルの更新と同時に
py
→pot
→翻訳→po
→mo
を自動実行してほしい
不足
- ドメイン名やパスなどは自動管理してくれない
- 翻訳とそのテキスト入力が自動化できない
メッセージID
運用的な話として、ソースコードに埋め込むMessageIdをどんなものにするか考えたほうがいい。
今は英語っぽいテキストにしているが、「微妙に表現がおかしくて変えたくなった」などの場合が起こりうる。文章でなく識別番号のようなもののほうがいいかもしれない。
たとえばMSG0000
。でも、DEBUG
, ERROR
, INFO
などプレフィックスを変えたほうがいいとか、逆に番号だけのほうがいいとか、細かいことを考えると面倒。IDも自動で割り振ってくれたら楽なのだが、自分で区別が付けられなくなるかも知れない。
そもそも、po
ファイルを作成する前の本文となるため、識別番号だと意味不明。何かしらの資料と照らし合わせる必要がある。やはり文章のほうが楽かもしれない。少なくとも翻訳やコードリーディングするときは。
所感
pygettext.py、msgfmt.pyの2ツールを使い分けるだけではできないことも可能なので便利。
しかし、ドメイン名やパスなどは自動管理してくれない。コマンドの引数が多くて面倒。