読者です 読者をやめる 読者になる 読者になる

smellman's Broken Diary

クソみたいなもんです

pgRoutingの例で見るsphinx-intlとtransifixの連携

これは Doc-ja Advent Calendar 2013 6日目の記事です。

先日、FOSS4G 2013 Tokyoのハンズオンのため、同僚と一緒にpgRoutingworkshop日本語への翻訳を行いました。
pgRoutingは弊社が中心となって開発しているOSSです。
pgRouting自体の説明はpgRouting workshopの日本語版などを参考にして下さい。

pgRouting workshopのドキュメントはSphinxを使って作成をしています。
国際化の部分をsphinx-intlを使って行い、transifexを使って共同作業で翻訳を行っています。

今回は実際の翻訳作業を通して得た知識を元に説明をします。なお、pgRoutingの例で見るとありますが、そこまでガッツリpgRouting絡んでないので安心してください(何

今回の作業では主に以下の4つの作業を元に説明します。

  1. 作業を行うのに必要なツールのインストールと設定
  2. プロジェクトの翻訳を開始して、翻訳ファイルのベースをtransifexにアップロード
  3. transifexで翻訳をした後にローカルに反映してhtmlなどを作成
  4. プロジェクトの原文が更新されたときの作業方法

作業を行うのに必要なツールのインストールと設定

今回必要となるツールは以下のものです。

いずれもPythonで作成されており、virtualenvを使えば簡単に構築環境を作ることができます。

まず、virtualenv環境の構築です。ここは主題ではないので適当に進めます。

$ virtualenv sphinx
$ echo "sphinx/*" >> .gitignore

.gitignoreに追加したのはプロジェクト管理から外すためです。
プロジェクト管理をしていない、もしくは別の仕組みを使っている場合は無視しても構いません。

次に、各ツールのインストールを行います。なお、(sphinx)はvirtualenv上にいることを指します。

$ source sphinx/bin/activate
(sphinx) $ pip install sphinx==1.2b3
(sphinx) $ pip install sphinx-intl
(sphinx) $ pip install transifex-client

これでインストールは完了です。
次のコマンドが打てるか確認しましょう。

(sphinx) $ sphinx-build
(sphinx) $ tx

sphinx-buildがsphinxのコマンドで、txがtransifex-clientのコマンドとなります。
shellによっては実行できない場合があります。その場合は一旦virtualenvを抜けて再度activateにすれば良いと思います。

(sphinx) $ deactivate
$ source sphinx/bin/activate

なお、次からの記述から(sphinx)を省略します。基本、virtualenv環境で行うことに注意をしてください。

次にsphinxのプロジェクトを作ります。

$ sphinx-quickstart docs

今回はdocsというディレクトリにファイルがあるという前提で進めます。
これはpgRoutingで使われている構成と一致します。

続いて、transifex-clientのセットアップを行います。
まず、先にtransifexでアカウントを作成しておきます。

次にtx initコマンドを使って作業用のディレクトリに設定ファイル(.tx/config)と、個人用の設定ファイル(~/.transifexrc)を作成します。

$ cd docs
$ tx init --user=<username> --pass=<password>

Transifex instanceを聞かれますが、それはこのままEnterを押して下さい。

続いて、Transifex側でプロジェクトの作成を行います。
この作業は僕のケースではすでに作成済だったため、作成方法は割愛をします。

続いてプロジェクトのIDを確認します。
こちらはTransifexのURLを確認すればOKです。
pgRouting workshopの場合では、 https://www.transifex.com/projects/p/pgrouting-workshop/ となるので、プロジェクトIDは pgrouting-workshop となります。
今回は仮にyasumetarouとしておきます。

プロジェクトの翻訳を開始して、翻訳ファイルのベースをtransifexにアップロード

では、実際にプロジェクトの翻訳を始めていきます。

基本的な流れは以下のようになります。

  1. potファイルの作成(sphinx-build -b gettext)
  2. transifexにアップロードできるようリソースを更新する(sphinx-intl update-txconfig-resources)
  3. transifexにpotをアップロードする

なお、今回の解説ではsphinxが提供するmakeコマンドは使わないようにしてる点に注意して下さい。

まず、翻訳の元となるpotファイルを作成します。

作成に使うコマンドはsphinx-buildです。 -b gettext オプションでpotファイルの作成となります。

$ cd docs
$ sphinx-build -b gettext -a -E -c . . ./i18n/pot

-c オプションはconf.pyがあるディレクトリを指定します。
ハイフン無しのオプションは source ディレクトリ、 output ディレクトリの順になります。

続いて、potファイルをtransifexにアップロードできるようにします。

$ sphinx-intl update-txconfig-resources -c "./conf.py" -p "./i18n/pot" -d "./i18n" --transifex-project-name=yasumetarou

-c でsphinxのconf.pyを指定します。
-p でpotファイルのパスを指定します。
-d でpoファイルのlocaleの位置を指定します。
--transifex-project-name で先ほど確認しておいたプロジェクトIDを指定します。

ここで行われれる作業は .tx/config の更新となります。
この作業後は以下の様な状態になります。

[main]
host = https://www.transifex.com
type = PO

[yasumetarou.index]
file_filter = i18n/<lang>/LC_MESSAGES/index.po
source_file = i18n/pot/index.pot
source_lang = en

今回ではi18n以下にpotと各localeが入るような構成にしています。
実際pgRoutingでは以下のような構成になっています。

% tree -L 1 i18n
i18n
├── de
├── es
├── fr
├── ja
└── pot

.tx/configにおけるfile_filterのが各言語のパスに置き換わるような形です。

最後にtransifexにpotをアップロードします。

$ tx push -s

-s はsourceファイル、つまりpotファイルのみをアップロードすることを意味します。

これでpotファイルがアップロードされます。
あとは、transifexから言語を追加して翻訳を行います。

transifexで翻訳をした後にローカルに反映してhtmlなどを作成

ここからが継続的な作業となります。

翻訳を取り込んでhtmlなどを作成します。

  1. transifexで行った翻訳ファイル(poファイル)をダウンロード(tx pull)
  2. 取得したpoファイルを元にmoファイルを作成(sphinx-intl build)
  3. sphinx-buildでhtmlを作成

まず、poファイルをダウンロードします。

$ tx pull -l "ja" -f --minimum-perc=1

-l で言語を指定します。
-f はダウンロードを強制します。
--minimum-percはその言語がどのぐらい翻訳されたらダウンロードするかという基準を与えています。この場合では 1 なので 1% 以上更新されていたらダウンロードするようにしています。

次にpoファイルをmoファイルに変換します。

$ sphinx-intl build -l "ja" -c "./conf.py" -p "./i18n/pot" -d "./i18n"

-l で言語を指定しています。

最後に、sphinx-buildでhtmlを作成します。

$ sphinx-build -b html -a -E -D language="ja" -c .  ./_build/doc/html/ja

これで、翻訳されたドキュメントを得ることができます。

プロジェクトの原文が更新されたときの作業方法

最後に原文に更新が入った時の対処です。

基本的には以下の手順になります。

  1. potファイルを再度作成する(sphinx-build -b gettext)
  2. transifexの最終更新分を取得しておく(tx pull)
  3. potファイルを元にpoファイルに更新を行う(sphinx-intl update)
  4. potファイルをtransifexにアップロードする(sphinx-intl update-txconfig-resources)
  5. ローカルのpoファイルをtransifexにアップロードする(tx push)

ここで使われているコマンドは全ていままで紹介したものなので、具体的なコマンド例は割愛しますが、いくつか重要なポイントがあります。

一つ目はtx pullで最終更新分を取得しておく事と、新しくできたpotファイルを元に手元のpoファイルを更新することです。

というのも、原文にちょっとした修正が入ってしまうとtransifix側ではまるごと文章が変更されたという扱いになります。
そのため、一旦手元に更新されたものを置いておいて、git diffなどで差分をとっておくと変更点がわかりやすくなります。

また、今回はtx pushで-sオプションのみ使うようにしています。
実は手元のpoファイルも-tオプションで更新できるようなのですが、transifexではファイルの扱いが非常に破壊的なため、このオプションでtransifex側で不具合があると危険なので、僕自身は使わないようにしています。

基本手元のpoファイルはread onlyという扱いにして、更新は全てtransifexで行うというふうにしています。
正直これが良いかどうかはわかってないのですが、危機回避という点では徹底するようにしています。

使えるスクリプト

完璧ではないのですが、pgRoutingでは以下の場所にあるスクリプトで基本的に作業をしています。

https://github.com/pgRouting/workshop/tree/master/tools/transifex

potの更新部分については

  1. init_gettext.sh
  2. update_transifex.sh

の順番で動かすようにしています。

プロジェクトごとにこのようなスクリプトを用意しておくと円滑に進めることができると思います。

ぜひ活用してください。

おまけ1: sphinx-buildとpdf出力

本筋とは関係ないのですが、sphinx-buildでlatex経由でpdfを作成できるよう同僚が調整しています。

https://github.com/pgRouting/workshop/blob/master/tools/transifex/build_translations.sh

うまく出力できない!っていう人はこれを試してみるとよいかもしれません。

おまけ2: github pagesの活用

pgRoutingでは本家サイトもpgRouting workshopも公開のためにgithub pagesを使っています。

https://github.com/pgRouting/pgrouting/tree/gh-pages

https://github.com/pgRouting/workshop/tree/gh-pages

これらのおかげでサイトの構築のためのリソースも含めて一括してgithub内で扱うことができます。
新しいプロジェクトを作りたいという人はドキュメントをsphinxで、公開はgithub pagesというのも結構使える手段だと思います。

まとめ

三行でまとめると

  1. sphinxとtransifexは相性がよい
  2. transifex側で翻訳作業を完結させればトラブルは起きない
  3. 簡単なスクリプトを書いて作業を楽にしよう!

ってな感じです。皆さんの翻訳に参考になれば幸いです。

次回は@Arachansanさんです。あれ、さんが二回?