Rubyではライブラリのリファレンスマニュアル作成のドキュメントツールとしてRDocが標準となっています。これは、古くからあるという理由とRuby本体に標準添付されているという理由からです。しかし、RDocはそれほど活発に開発されていないため、最近のドキュメントツールとして機能不足と言わざるをえません*1。どのような機能が足りないのかについては別の機会にします。
数年前からYARD(Yey! A Ruby Documentation Tool)というドキュメントツールが開発されています。YARDはRDocとの互換性を残したまま機能を拡張しているため、RDocからの移行も容易です。実は、YARDは第2回フクオカRuby大賞(SSLの証明書の期限が切れているので警告がでます)に「Improving Documentation in the Ruby Community」というタイトルで応募していたので知っている人もいるのではないでしょうか*2。
そこで、ドキュメントツールとしてRDocではなくYARDを使う方法を紹介します。と、いきたいところですが、その前にプログラミング言語に依存しないレベルでライブラリのリファレンスマニュアルの記述方法について振り返っておきます。
ライブラリのリファレンスマニュアルを記述する方法には大きく分けて以下の2つの方法があります。
ソースコードに埋め込む方式でも、インターフェイスを記述しているファイル(CやC++ならヘッダーファイル)に埋め込む方式や実装を記述しているファイルに埋め込む方式などいくつか違いがあります。また、コメントとしてドキュメントを記述する方式の他にも、言語が提供するdocstringという仕組みを利用する場合もあります*3。これらは採用しているドキュメントツールや言語などに依存することなので、ここでは深く考えないことにします。
ソースコードに埋め込む方式を採用しているドキュメントツールはDoxygenやJavadoc、GTK-Docなどです。RDocやYARDもこの方式です。この方式の方がソースコードと分離する方式よりもメジャーです。分離方式ではなくこの方式を採用しているドキュメントツール・プロジェクトの方が多いです。
ソースコードとは別に記述する方式を採用しているドキュメントツールはSphinxやBitClust、Texinfo、RDtool*4などです。Sphinxを利用しているプロジェクトはPythonなどです。BitClustを利用しているプロジェクトはRubyの日本語リファレンスマニュアルを整備しているるりまプロジェクトです。Texinfoを利用しているプロジェクトはGaucheなどです。RDtoolを利用しているプロジェクトはRuby-GNOME2プロジェクトなどです。
分離方式は、ドキュメント量が大きいプロジェクトや、より厳密に公開したいAPIだけを選別したいプロジェクトのリファレンスマニュアルを作成する場合に使われることが多いのかもしれません。例えば、プログラミング言語を開発しているプロジェクトにはそういうニーズが多いのかもしれません。また、動的に生成するコードのドキュメントはソースコード中に対応するドキュメントを埋め込めません*5。この場合は埋め込み方式は使えないため、埋め込み方式でなんとかやりくりするかこの方式を利用します*6。これについては後述します。
ソースコードに埋め込む方式と分離する方式ではそれぞれにメリットとデメリットがあります。これらについて検討して自分のプロジェクトにあった方式を選びましょう。「どちらでもいいな」と思ったらよりメジャーな埋め込み方式を選ぶとよいでしょう。
ソースコードに埋め込む方式のメリット・デメリットは以下の通りです。
埋め込み方式では網羅的にAPIのリファレンスマニュアルを整備しやすくなります。よって、すでにソースコード中にドキュメントを記述するスタイルの場合や特にこだわりのない場合はこの方式を採用するとよいでしょう。
ただし、同じ方法で英語と日本語など複数の言語向けのリファレンスマニュアルを作成することはやめた方がよいです。この方式で複数の言語をサポートする場合はドキュメント中に「言語タグ」のようなものを仕込んで、対応する言語のドキュメントをすべてソースコード中に記述することになります。例えば以下のようになります。
1 2 3 4 5 |
# @en logs message on debug mode. # @ja デバッグモードのときだけmessageを出力する。 def debug(message) puts message if $DEBUG end |
しかし、このやり方にはいくつも問題があります。まず、このやり方に対応したドキュメントツールがありません。また、あったとしても、メリットの1つである「ソースコードとドキュメントの不整合を防ぎやすくなる」を実現できなくなります。これは、ソースコードを変更する人がすべての言語のドキュメントを書けるわけではないからです。例えば、GNOMEは174の言語で利用できます*10が、GNOMEの関係者全員がすべての言語を読み書きできるわけではありません。GNOMEは特に多言語サポートが進んでいるプロジェクトですが、これほどでなくても、対応する言語が3言語以上になったらソースコードを書きながらドキュメントも整備することは無理でしょう。
なお、より現実的に複数の言語に対応する方法については別の機会に紹介します。
ソースコードとドキュメントを分ける方式のメリット・デメリットは以下の通りです。
埋め込み方式のドキュメントツールにはAPI収集機能が確実についています。それと同じようなAPI収集機能を用意できるのならば、小さなプロジェクトでも分離方式を採用できます。Ruby-GNOME2プロジェクトはAPIを収集するツールを作ってこの方式を採用しています。
プロジェクトに関わる人数が多くなってきたり、複数の言語に対応したい場合はこの方式のメリットが大きくなるかもしれません。そうでない場合は埋め込み方式で十分でしょう。
ドキュメントツールとしてRDocではなくYARDを使う方法と、複数の言語に対応したリファレンスマニュアルの作成方法を書くつもりだったのですが、その予備知識としてリファレンスマニュアルの記述方法に書いたら長くなってしまったのでそれだけで一区切りとしました。
読みやすく利用しやすいリファレンスマニュアルを作成するためにも、使いやすく書きやすいドキュメントツールを採用したいですね。
*1 Ruby 1.8に標準添付されていた頃のTest::Unitみたいですね。
*2 受賞はしていません。RubyやRuby周辺をよくするツールが評価される機会がもっと増えるといいですね。
*3 Lisp系の言語やPythonなど
*4 =beginと=endを使うことにより埋め込み方式でも利用可能です。Yuguiさん、ありがとうございます!ただ、メソッドを抽出する機能がないので他の埋め込み方式よりは不便です。
*5 最新のYARDではこのケースにも対応できる仕組みを提供しています。
*6 RubyやLispでevalしたりCやLispでマクロを使う場合など。
*7 確実に防げるわけではないことに注意。ソースコードとドキュメントが違うことを言っていて苦労した覚えはありませんか?
*8 ドキュメントの中にコードがある状態。
*9 少なくとも現実的ではない
*10 2011/05/05現在。
*11 ただし、言語毎にファイルなどを分けている場合に限る。Gaucheは1ファイル中に英語と日本語を書いているためそれ以上の言語のサポートは難しい。
リファレンスマニュアルの記述方法を検討し、埋め込み方式のドキュメントツールを採用したとします。Rubyで埋め込み方式のドキュメントツールを使うとしたらRDocかYARDになります*1。
RDocからYARDへの移行方法につなげたいのでYARDを使う方向で話を進めたいわけですが、その前にRDocとYARDの背景や機能の違いを確認しておきましょう。
RDocはRuby 1.8.1からRuby本体に標準添付されています。Ruby1.8.1は2003年のクリスマスにリリースされているので、もう7年くらい前になります。Ruby本体や標準添付されているライブラリもRDoc用にドキュメントが書かれていますし、Rubyで標準的なドキュメントツールといえばRDocという存在です。
RDocは2004年くらいまではRuby本体のリポジトリ上で活発に開発されていましたが、それから数年は開発が停滞していました。その後、2008年頃より開発リポジトリをRuby本体のリポジトリからRubyForgeのリポジトリに移動して*2、再び開発が活発になりはじめます*3。RDoc 2.Xがはじまったのもこの頃です。2年後の2010年の12月にRDoc 3.Xがはじまるなど、今でも開発のペースは衰えていません。
と、こう書くとRDocでいいんじゃないかと思うところです。しかし、Ruby 1.9を使っていて日本語も含むドキュメントを扱っていた人はそんなことはないということに気づいているはずです。Ruby 1.9の大きな変更の1つがEncodingの導入ですが、RDoc 2はEncodingの対応が不十分です。RDoc 2でHTMLを生成しようとして、Encoding関連の例外が発生した人もいるのではないでしょうか。
そして、ハマリポイントなのが、Ruby 1.9.2に標準添付されているRDocは RDoc 3ではなくRDoc 2だということです。Encoding関連で問題が発生している人はgemでRDoc 3をインストールして、そっちを試してみてください。
RDocではドキュメントのマークアップ言語として独自のマークアップ言語を作成しています。MarkdownやTextileなどといったマークアップ言語よりもシンプルで、機能が足りないと感じることが多いかもしれません。特に、Ruby用のドキュメントシステムとして開発されたのにも関わらず、コード用の専用マークアップがないことには驚くかもしれません*4。
クラスやメソッド用のメタ情報記述方法ではRuby用ドキュメントツールらしい記述がサポートされています。Rubyは動的な言語なので「メソッドを定義するメソッド」*5も定義できます。そのようなメソッドのドキュメントも記述できるようになっています。
例えば、以下のようにprotected_attr_reader
という独自の「メソッドを定義するメソッド」を定義したとします。このとき、protected_attr_reader
で定義したメソッドもattr_reader
と同じように読み込み専用属性としてドキュメント化して欲しいですよね。RDocでは以下のように記述することによって、独自の「メソッドを定義するメソッド」で定義したメソッドにも適切にドキュメントを記述することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class CoveredBook class << self def protected_attr_reader(name) attr_reader name protected name end end ## # :attr_reader: # タイトルを返す。ただし、内部からのみから利用可能。 protected_attr_reader :title def initialize(title) @title = title end end |
と、こう書くとRDocでいいんじゃないかと思うところです。しかし、DoxygenやGTK-Docなど他のドキュメントツールにはあるような専用マークアップがありません。例えば、メソッドの引数*6や戻り値*7のドキュメントを記述するための専用マークアップがありません。これらはメソッドのドキュメントを読みやすく整形するときに便利です。また、「バージョンいくつから追加された機能」*8や「非推奨のAPI」*9を記述する専用マークアップもありません。
現在も開発が継続しており、RDoc 3もリリースされ、継続的に改良されている*10のですが、まだ細かいところのサポートが不足しているという印象です。
YARDは2007年から開発が始まっています。RDocの開発が再び活発になりはじめたのが2008年頃なので、あまり改良されていなかった当時のRDocに不満を持っていたのかもしれません。
YARDが重視していることは拡張のしやすさです。YARDのトップページにはアピールポイントとして「Preview As You Document」、「Easily Customize Templates」、「Support Your Own DSL」、「Extend, Extend, Extend!」の4つが挙げられています。このうち3つは拡張性に関することです。Rubyは動的な言語なので使われ方も様々です。様々な使われ方をしているときでもドキュメントを記述できるように拡張性を高くしているものと考えられます。
また、RDocとの互換性も重視しています。RDoc用に書かれたドキュメントを変更なしで処理できるため、RDocからの移行も容易です。
YARDは複数のマークアップ言語をサポートしています。組み込みではRDoc由来のマークアップ言語だけのサポートですが、gemをインストールすることでMarkdownやTextileも利用することができます。チュートリアルや設計に関する文書など、ある程度長めの文書を書くときはRDocのマークアップではなく、より汎用的なマークアップ言語の方を使うのがよいでしょう。
YARDはメソッドなどのメタ情報の記述方法はRDocとは異なる書式を採用しています。YARDはDoxygenやGTK-Docなどと同様に@タグ名
という記述方法を採用しています*11。YARDではこれをタグと呼んでいます。組み込みで利用できるタグにはRDocにはなかった、引数記述用タグ、戻り値記述用タグ、初出バージョン記述用タグ、非推奨API記述用タグなどライブラリのドキュメントを記述するために必要そうなタグが一通り揃っています。また、タグを追加することもできます*12。
また、ドキュメントとして抽出したテキスト情報やメタ情報を再利用しやすい形で提供しています。これを利用することでるりまサーチのようなドキュメント検索システムを作りやすくなりそうですが、これについてはまた別の機会にします。
今後はRDocも記述力が高まったりメタ情報の扱いが改良されていくのかもしれませんが、現時点ではYARDの方がより実践的な機能を持っているといえるでしょう。ただし、ドキュメント生成速度はRDoc 3の方が圧倒的に速いです*13。
Ruby用のドキュメントツールであるRDocとYARDについて比較しました*14。YARDの方がよさそうに思えるように書いているので、YARDを使いたくなったかもしれません。次こそはYARDの使い方を紹介できるかもしれません。
*2 今はGitHubのリポジトリに移動しています。
*3 つまり、RDocがRuby本体のリポジトリと独自リポジトリの複数のリポジトリに存在するようになったのもこの頃です。RDocは今でも標準添付ライブラリなので、RDocのリポジトリを更新するだけではなく、Ruby本体のリポジトリのRDocも更新する必要があります。これは、新しいバージョンをリリースしたタイミングなどでごっそりRuby本体のリポジトリのRDocを上書きするという方法で行われています。これに関してはいろいろ意見がある人もいるので、このあたりに興味がある人は、Rubyの開発を見ていたり参加したりしているまわりの人に聞いてみましょう。
*4 整形済みテキスト用のマークアップはあります。
*5 RDocではメタメソッドと呼んでいるようです。
*6 Doxygenなら\param
、GTK-Docなら@引数名
。
*7 Doxygenなら\return
、GTK-DocならReturns:
。
*8 Doxygenなら\since
、GTK-Docなら@since
。
*9 Doxygenなら\deprecated
、GTK-Docなら#ifdef ... #endif
から自動抽出。
*10 ドキュメントの生成速度はだいぶ速くなっているという印象です。
*11 Doxygenは\since
でも@since
でもどちらでも書けます。
*12 RDocでもできるようです。
*13 ここで「YARDに速度改善パッチを送れるなぁ」と考えられる人はいいセンスを持っていますよ。:-)
*14 偏った視点が含まれているので、自分が必要な機能に関する部分は念のため自分で本家の情報を確認することをオススメします。
WindowsにRubyをインストールする場合、どうやってインストールしますか?現在のところ、以下のようにいくつも選択肢があります。
それぞれ特徴があるので自分の使い方にあったものを選ぶ必要がありますが、今回の話の趣旨は「これがオススメです!」というものを伝えることではないので、簡単に紹介するだけにしておきます。ピンときたものがあったら、それについてもう少し詳しく調べてみることをおすすめします。
今回の話ではRubyInstaller for Windowsを使います。では、どうしてRubyInstaller for Windowsを使うのでしょうか。
今回挙げたビルド済みRubyのパッケージの中で、RubyInstaller for WindowsのみがMinGWでRubyをビルドしています。これが、今回RubyInstaller for Windowsを選んだ理由です。RubyがMinGWでビルドされているとDebian GNU/Linux上で拡張ライブラリをクロスコンパイルすることができます*1。
GNU/Linuxなどでは64bit版Rubyが普通に使われていますが、Windowsではまだそうでもないようです。しかし、今後はWindowsでも64bit版Rubyの利用が進んでいくでしょう。そうなった場合、拡張ライブラリは64bit版Ruby用のバイナリ入りで配布することが求められます*2。
普段からWindowsで開発している拡張ライブラリであれば簡単に64bit版Ruby用バイナリを作成できるでしょうが、メインの開発環境がGNU/Linux*3という場合は難しいです。GNU/Linuxで開発している場合は、GNU/Linux上でクロスコンパイルして64bit版Ruby用バイナリを作成できるととても便利です。そして、MinGW-w64を利用すれば64bit版Windows用のDLLをクロスコンパイルできるのです。
しかし、RubyInstallerはまだ64bit版Rubyには対応していません。つまり、64bit版Ruby用の拡張ライブラリをクロスコンパイルしてバイナリを作っても、それを使うための64bit版Rubyの入手が困難な状況ということです。
RubyInstallerが64bit版Rubyに対応していないため、クロスコンパイルした拡張ライブラリを使える64bit版Rubyを簡単にインストールできない問題をどのように解決すればよいでしょうか?簡単ですね。RubyInstallerを64bit版Rubyに対応させればいいのです。
ということで、対応させたものがGitHub上のkou/rubyinstallerのmingw-w64ブランチにあります。これを使って作成した64bit版Ruby*4用のRubyInstallerと、Debian GNU/Linux上でクロスコンパイルしたrroongaのgemを以下に置いておきます*5。
rroongaのチュートリアルで、実際にきちんと動くことを確認できます。
というように、なんとなく動くようになっていますが、まだいくつかやらなければいけないことがあります。
ということで、Ruby 1.9.3がリリースされるまでにみなさんがこれらの修正できるように64bit版Ruby用RubyInstallerの作り方を紹介します。タイトルからは想像できなかった展開ですね。
まず、初期設定の方法を紹介し、それからRubyをビルド・テストする方法とRubyInstallerを作成する方法を紹介します。
必要なものは以下の通りです。
Ruby 1.8.7はすでにあるRubyInstaller for Windowsを使ってインストールします。Ruby 1.9.2では動作しないので注意してください。
Inno SetupはWindowsインストーラを作成するフリーソフトウェアです。ダウンロードページからisetup-5.4.2.exeをダウンロードしてインストールします。
本当はCygwinはなくてもよいのですが、初期設定が楽なのでCygwinを使います。まず、setup.exeをダウンロードしてCygwinをインストールします。追加でインストールするソフトウェアは以下の通りです。
必須ではありませんが、mingw64-x86_64-binutilsもあると便利でしょう。
CygwinをインストールしたらRubyをチェックアウトします。trunkのRubyを修正しないと取り込んでもらえないからです。また、作業は~/work/ruby/*6以下で行うことにします。
% mkdir -p ~/work/ruby % cd ~/work/ruby % svn co http://svn.ruby-lang.org/repos/ruby/trunk ruby % cd ruby % autoconf
RubyInstaller for Windowsのソースコードもチェックアウトします。mingw-w64ブランチの成果はオフィシャルリポジトリに取り込まれそうな雰囲気はあるのですが、まだ取り込まれていないのでmingw-w64ブランチを使います。
% cd ~/work/ruby % git clone https://github.com/kou/rubyinstaller.git % cd rubyinstaller % git checkout mingw-w64
以上が初期設定です。ここまでの作業は最初に1回行うだけです。今後は~/work/ruby/rubyinstaller/で作業を行います。
ここからはcmd.exe上で実行します。ただし、cmd.exe上で長いコマンドを打つのは大変なので、バッチファイルを作成します。
build.bat:
c:\Ruby187\bin\ruby.exe c:\Ruby187\bin\rake ruby19 LOCAL='C:\Cygwin\home\kou\work\ruby\ruby' ProgramFiles='c:\Program Files (x86)' dkver=mingw64-64-4.5.4 --trace > build.log 2>&1
これをC:\cygwin\home\kou\work\ruby\rubyinstaller\で実行します。
C:\cygwin\home\kou\work\ruby\rubyinstaller>build.bat
小一時間ほど待つとsandbox\ruby19_mingw\以下に64bit用Rubyが作成されているはずです。
C:\cygwin\home\kou\work\ruby\rubyinstaller>sandbox\ruby19_mingw\bin\ruby.exe --version ruby 1.9.3dev (2011-05-14) [x64-mingw32]
ビルド時のログはbuild.logに保存されているので、問題が発生した場合はログを見て問題を解決し、RubyやRubyInstallerの開発チームに報告して解決内容を取り込んでもらいましょう。開発チームにコンタクトをとる方法など、関連リソースについては一番最後に書いてあるので参考にしてください。
パッケージの作成もコマンドが長いのでバッチファイルを作成します。
package.bat:
c:\Ruby187\bin\ruby.exe c:\Ruby187\bin\rake ruby19:package LOCAL='C:\cygwin\home\kou\work\ruby\ruby' ProgramFiles='c:\Program Files (x86)' dkver=mingw64-64-4.5.4 --trace > package.log 2>&1
これをC:\cygwin\home\kou\work\ruby\rubyinstaller\で実行します。
C:\cygwin\home\kou\work\ruby\rubyinstaller>package.bat
10分ほど待つとpkg\以下にRubyInstallerが作成されているはずです。このRubyInstallerにはsandbox\ruby19_mingw\以下にビルドされたRuby用が含まれています。RubyInstallerのファイル名はpkg\rubyinstaller-1.9.2-p180.exeになっていて、直さなければいけないものの1つです。ただ、このファイル名は後で直すことにして、まずは、試しにインストールしてみましょう。インストーラをダブルクリックするとインストールできます*7。
ここまでくればパッケージの修正作業はできますね。現在のところ、以下のような問題があります。
テストの実行もコマンドが長いのでバッチファイルとシェルスクリプトを作成します。テストはMSYS上で実行するため、まずはcmd.exeからMSYSのbashに入るためのバッチファイルが必要です。
shell.bat:
c:\Ruby187\bin\ruby.exe c:\Ruby187\bin\rake devkit:sh LOCAL='C:\Cygwin\home\kou\work\ruby\ruby' ProgramFiles='c:\Program Files (x86)' dkver=mingw64-64-4.5.4
次に、bash上でテストを実行するためのシェルスクリプトです。
run-test.sh:
1 2 3 4 5 6 |
#!/bin/sh export PATH=$PWD/sandbox/ruby19_mingw/bin:$PATH ruby --version cd sandbox/ruby19_build make test-all |
以下のように使います。
C:\cygwin\home\kou\work\ruby\rubyinstaller>shell.bat ... sh-3.1#$ ./run-test.sh > test.log 2>&1
テスト結果はtest.logに出力されます。この結果ですべてのテストがパスするようにしましょう。なお、r31560では「9486 tests,1877705 assertions, 29 failures, 8 errors, 82 skips」となりました。結果の詳細は以下にあります。
やりがいがありそうですね。
MinGW-w64で64bit版Rubyをビルド・テストする方法と、ビルドした64bit版RubyのRubyInstallerを作成する方法を紹介しました。まだ、いくつか問題があるのでピンときた人はRuby 1.9.3がでるまでに修正してみてはいかがでしょうか?
関連リソース:
*1 補足すると、Ruby-mswin32とActiveScruptRubyで配布されている32bit版Ruby用の拡張ライブラリもクロスコンパイルできます。しかし、64bit版Ruby用の拡張ライブラリをクロスコンパイルできません。理由はVisual Studioでビルドした64bit版Rubyではmsvcrt.dllではなくmsvcr80.dllやmsvcr100.dllが使われているためです。MinGWでクロスコンパイルするとmsvcrt.dllを使うようになるため、異なるCランタイムライブラリを使うことになってしまい、うまく動かないのです。参考: C ランタイム ライブラリの「アプリケーションで msvcrt.dll と msvcr100.dll の両方を使用した場合に発生する問題」のところなど。
*2 Windows上でも需要がある拡張ライブラリであれば。
*3 rroongaやrcairoのケース。
*4 ruby --version
は"ruby 1.9.3dev (2011-05-14) [x64-mingw32]"。
*5 一時的に作ったものを置いているだけなので、ある日突然削除されているかもしれません。
*6 WindowsのパスではC:\cygwin\home\kou\work\ruby\。
*7 右クリックで「管理者として実行」を選ばないといけないかもしれません。
昨年に引き続き、クリアコードは今年も日本Ruby会議2011のGoldスポンサーになりました。
まだでていませんが、発表などでも参加する予定なので、会場で見かけたら声でもかけてください。
開催は2ヶ月後で、まだ少し時間がありますが、RubyKaigi2011の講演以外の企画についてやRubyKaigi Advent Calendar 2011など関連情報がいくつかでています。Online.kaigi.rbなど日本Ruby会議2011以前に行われるイベントもあるようなので、興味のある方はそちらにも参加してみてはいかがでしょうか。
YARDのことの続きを書きたいと思いつつもなかなか辿りつきません。今回はPython製のドキュメントツールSphinxの話です。groongaのケースを例にしてSphinxで複数言語用のドキュメントを生成する方法の概要を紹介します。書いていたら長くなったので、具体的にどうするかというのは次の機会にします。
5/29にgroonga 1.2.2がリリースされました。今後は日本だけではなく世界でも使ってもらえるように、英語でも情報を発信していく方向になりました。そこで、今回のリリースに合わせてサイトデザインをリニューアルし、英語のページも用意しました。ただし、すでにあった日本語のコンテンツを今回のリリースで全部英語にした、というものではありません。今回のリリースでやったのは「日本語と英語という複数の言語で情報を発信する仕組み」を作るところまでです。せっかくなので、今回のリリースで導入した、Sphinxを使って実現している複数言語用のドキュメントを用意する仕組み(の概要)を紹介します。
なお、実際のページは以下のようになります。英語のページでも日本語の文章がまだまだ多く残っていますが、これはおいおい改善していく予定です*1。
それぞれのページのヘッダーには他の言語へのリンクを用意してあり、すぐに対応する他の言語のページに行けるようになっています。
まず、複数言語用のドキュメントを用意する仕組みの概要を説明します。
しばらくしたらリリースされるだろうSphinx 1.1には国際化機能がついています。(Sphinx本家の国際化についてのドキュメント(英語)。)今回紹介する仕組みはこの機能をベースにした仕組みになります*2。
国際化機能を使うと、ベースとなるドキュメント1つから、そのドキュメントを他の言語に翻訳したドキュメントを複数生成することができます。ふつうはベースとなるドキュメントは英語で記述するので、以下のようなイメージになります。
ポイントは、本文のテキストだけ他の言語に翻訳すればよいというところです。章分けや説明する順序などの文章の構造などはベースとなる英語のドキュメントと同じものを共有します。
以下のようにドキュメント全体を翻訳する方法もありますが、この場合は文章の構造は共有していません。それぞれの翻訳されたドキュメントは翻訳した時点の英語のドキュメントの文書の構造をコピーしています。そのため、英語のドキュメントの文書の構造が変わったら、それにあわせて翻訳したドキュメントの方も変える必要があります*3。
ドキュメント全体を翻訳する場合は元のドキュメントをコピーして翻訳するだけなので、通常のドキュメント作成作業と作業の流れはそれほど違いはないでしょう。
しかし、Sphinxが採用しているのは本文のみ翻訳する方法なので、通常の作業の流れとはだいぶ異なる流れになります。
Sphinxでは「元の本文」を「翻訳した本文」に置き換えるためにgettextを使っています。gettextは昔からある国際化用ライブラリで、Sphinxが使っているのはgettextのPython実装です。
昔からあるだけあって、周辺ツールがそろっていることが利点です。例えば、元の本文と翻訳した本文とを比較して、変更された本文を自動検出するツールがあったりします。「一度翻訳して終わり」という場合は必要のないツールですが、「元の本文に追従して翻訳も更新する」という場合には有用なツールです。
groongaは継続して開発しているソフトウェアなのでドキュメントも更新されます。この場合は翻訳作業は以下のような流れになります。
「(1)本文を抽出」*4と「(4)本文の差分抽出」*5の部分がツールを使って自動化できる部分です。この部分は手動でやるには大変な部分なのでとても助かります。
「(3)更新」の部分は翻訳とは関係なく通常のドキュメント更新作業と同じです。
残りの(2)と(5)の「日本語へ翻訳」がメインの翻訳作業になりますが、ここの作業が通常の翻訳作業とやり方が違う部分になります。これは、gettextの作法に従う必要があるためです。
gettextはPO (Portable Object)というファイルで「元のテキスト」と「翻訳したテキスト」を関連付けます。POは以下のようなフォーマットのテキストです*6。
#: ${元のテキストがあるファイルのパス1}:${行1} msgid "${元のテキスト1}" msgstr "${翻訳したテキスト1}" #: ${元のテキストがあるファイルのパス2}:${行2} msgid "${元のテキスト2}" msgstr "${翻訳したテキスト2}"
元の文書から本文を抽出した段階では${翻訳したテキスト}の部分が空になっているので、淡々とそこを埋めていく作業が翻訳作業になります。POファイルはテキストなので好きなエディタで編集できますが、専用の編集ツールもあります。Emacsのpo-modeやGNOMEのGtranslator、KDEのLokalizeなどです。
翻訳ができたら、それと元のドキュメントを使ってHTML形式でドキュメントを生成できます。
Sphinxを使った複数言語用のドキュメントを用意する仕組みの概要を紹介しました。具体的な設定などは次の機会に紹介する予定ですが、待ちきれない人はgroongaのリポジトリをのぞいてみてください。
図はblockdiagで作りましたが、便利ですね。
*1 このあたりの改善に興味のある方はgroongaのドキュメントの国際化の方法を参考にチャレンジしてみてください!
*2 未リリースの機能を使っているだけあって、いろいろ大変なところもありました。いくつかは修正してSphinx本体に取り込んでもらいましたが、まだまだ細かくいろいろ問題が残っています。Sphinx推しのみなさんは今のうちに国際化機能を使って、1.1がリリースされる前にもっと改良してみてはいかがでしょうか。
*3 それでもこの方法で複数の言語のドキュメントを用意したい場合はドキュメントの翻訳にSphinxを使うなどを参考にしてみてはいかがでしょうか。
*4 Sphinxが生成したMakefileを使うとmake gettext
で抽出できます。
*5 make gettext
とmsgmerge
を組み合わせます。
*6 詳細は本家のThe Format of PO Filesを参照。