Sphinxでi18nなドキュメントを作成するときのナレッジ:解決編

Sphinx X i18n

こんにちは、 ryosuke です。

今回は、 以前に取り上げた、ドキュメント作成ツールである Sphinx を使って、多言語の文章を作成する際に、困った点とその解決手段についての続編です。
この記事では、「解決方法」の話をします。

前回の記事は「Sphinxでi18nなドキュメントを作成するときのナレッジ:課題編」です

おさらい: 翻訳作業時の課題

前回の記事では翻訳作業における3つの課題を説明しました。

  • reference による大量の差分
  • 文の自動改行による大量の差分
  • 翻訳漏れの検知機構不足

これらを解消するために用いた技術的方法を紹介します。

方針: gettext utilities の助けを借りる

このような課題に悩まされる背景に、 sphinx-intl コマンドでは細かいオプションが指定できない点があると思います。
sphinx-intl コマンドは Sphinx で i18n 対応をする際に、一連の作業をスムーズに進めるために有用なツールですが、出力する PO ファイルの細かい制御まではサポートしていないようです。

ところで、 Sphinx のドキュメントにも書いてあるとおり[1]、Sphinx の i18n 機構は、 gettext を採用しています。
POT ファイルや PO ファイルを使った i18n の仕組みは、古くからある GNU gettext システムによるものです。
gettext には多数の utility コマンドが用意されており、多数の機能や細かいオプション指定ができます。
gettext のコマンドを活用することで、 sphinx-intl コマンドだけでは手が届かない痒いところを解消します。

解消方法

reference による大量の差分

この課題の解消には、 gettextとバージョン管理システムの相性の悪さを解消する案 - 2013-11-14 - ククログ で紹介されている案を採用しました。

reference の情報はファイルのバージョンや差分管理の観点では、無視したい(注目したくない)内容のため、 git などの VCS との相性はよくありません。
従って、 git commit する段階では、削除しておきたい情報です。

上記記事のとおり、 reference を PO ファイルから簡単に削除する手段は用意されています。
(自前で sed とか grep で処理する必要はありません!)

reference が含まれる PO ファイルから reference を消すために msgcat コマンドを使用します。

msgcat --no-location --output-file="PO file" "PO file"

本来は、複数 PO ファイルを結合して、単一の PO ファイルを出力するためのコマンドですが、入力と出力に同一の PO ファイルを指定することで、 msgcat コマンドをあたかも formmater として使う事ができます。

肝は --no-location オプションを指定してる点です。
このオプションによって、 reference の記述が削除されます。

reference が消えることで、以下の reST ファイルがある場合、

1行目の文章です。

3行目の文章です。

5行目の文章です。

生成される PO ファイルは下記のようになります。

msgid "1行目の文章です。"
msgstr "This is a paragraph on first line."

msgid "3行目の文章です。"
msgstr "This is a paragraph on third line."

msgid "5行目の文章です。"
msgstr "This is a paragraph on fifth line."

従って reST ファイルを下記のように変更しても、

1行目の文章です。

後から追記した文章です。

3行目の文章です。

5行目の文章です。

再生成した PO ファイルは下記のようになります。

msgid "1行目の文章です。"
msgstr "This is a paragraph on first line."

msgid "後から追記した文章です。"
msgstr "This is a paragraph that was added later."

msgid "3行目の文章です。"
msgstr "This is a paragraph on third line."

msgid "5行目の文章です。"
msgstr "This is a paragraph on fifth line."

従って reST ファイルの加筆に伴う PO ファイルの変更が発生しても、差分は下記のように表示されます。
file

reference が記述されているときと比べて、明らかに注目すべき変更点に集中できる状態になったと思います。

文の自動改行による大量の差分

この課題は、自動改行を無効にすることによって解消します。
実際の手段は、下記の2つのいずれかを好みに応じて選択できます。

  • sphinx-intl コマンドでオプション指定する
    sphinx-intl update -p builddir -l en -w 0
  • msgcat コマンドでオプション指定する
    msgcat --no-wrap --output-file="PO file" "PO file"

sphinx-intl コマンドを使う手段は、原文修正時の PO ファイル再生成をする時に実行する sphinx-intl update コマンド に -w 0 オプションを指定する使い方です。
-w は、1行あたりの文字数を指定できるオプションですが、 0 を指定することで自動改行を無効にできます。

msgcat コマンドを使う手段は、 reference 問題の解消方法と同様に、 PO ファイルから自動改行を削除する formatter として使う手段です。
--no-wrap オプションを指定することで、自動改行を無効にできます。

この手段を使った場合の効果を、前回記事の例を使って視覚化してみましょう。

reST ファイルで以下のような修正を行った場合、

-今日は晴れです。明日は曇りです。明後日は雨の可能性がありますが、現時点では降水確率は低めの予報です。
+今日は晴れです。明日は曇りです。明後日は雨の可能性があります。

修正前の PO ファイルは下記のようになり、

msgid "今日は晴れです。明日は曇りです。明後日は雨の可能性がありますが、現時点では降水確率は低めの予報です。"
msgstr "Today is sunny. Tomorrow will be cloudy. The day after tomorrow there is a chance of rain, but at this time the chance of precipitation is forecast to be low."

修正後の PO ファイルは下記のようになります。

msgid "今日は晴れです。明日は曇りです。明後日は雨の可能性があります。"
msgstr "Today is sunny. Tomorrow will be cloudy. The day after tomorrow there is a chance of rain."

従って PO ファイルの変更差分は下記のように表示されます。
file
こちらの問題も、注目すべき変更点が読み取りやすくなったと思います。

翻訳漏れの検知機構不足

この課題は、 msgcmp コマンドを活用することで解消します。
このコマンドを使った翻訳漏れの検知は、主に CI で実施することを前提に紹介します。

原文の reST ファイルに任意の文章を加筆し、併せて PO ファイルも再生成し、適切な訳を記述済みの commit に対して、 msgcmp コマンドを使った CI を行うことを想定します。

CI の中では、まず reST ファイルから POT ファイルを再生成します。

sphinx-build -b gettext sourcedir builddir

そして、生成した POT ファイルと commit 済みの PO ファイルについて、 msgcmp コマンドを使用します。

msgcmp "PO file" "POT file"

msgcmp コマンドを実行しても、何の出力もなく、コマンド実行のステータスコードも 0 であれば、問題なしです。
一方で、何らかのエラーメッセージが出力され、ステータスコードも 0 以外であれば、異常があります。

msgcmp コマンドは、指定した PO ファイルと POT ファイルの全ての msgid の存在が両ファイル間で完全一致しているかどうかを判定します。

例えば、 原文の reST ファイルに加筆したのに PO ファイルの再生成を怠った場合を考えましょう。
このとき、 POT ファイルには含まれるが PO ファイルにはない msgid が存在します。
その状態で msgcmp コマンドを実行すると、以下のようなエラーメッセージが表示されます。

sample.pot:XXX: this message is used but not defined in sample.po
msgcmp: found 1 fatal error

一方で、原文の reST ファイルから文章を削除したのに PO ファイルの更新を怠った場合を考えましょう。
このとき、 POT ファイルにはないが PO ファイルには含まれる msgid が存在します。
この場合は、翻訳漏れは起きませんが、不要な訳の記述が PO ファイルに残ったままとなり、健全な状態から逸脱します。
このような状態で msgcmp コマンドを実行すると、以下のようなエラーメッセージが表示されます。

sample.po:XXX: warning: this message is not used
msgcmp: found 1 fatal error

この仕組みによって、翻訳の過不足を検知できます。

解消手段導入による効果

上記の課題解消手段を導入したことにより、翻訳に関わる下記のトラブルを回避できました。

  • 訳の更新漏れ
  • 訳文のレビュー時のレビュアーに対する無用な負荷

まとめ

今回紹介した手段を導入することによって、国際化ドキュメンテーションの活動での無用な品質低下の要因を減らせます。
その分、ドキュメンテーションの関係者は、本来注力すべき、ドキュメントそのものの構成や、適切な訳の記述などに集中でき、本質的な内容の品質向上につながります。

似たような課題に悩んでいるようでしたら、是非参考にして下さい。