Sphinxドキュメントの国際化対応をやってみた

こんにちは。サービスグループの武田です。Sphinxに用意されている国際化対応のための機能を試してみました。
2020.07.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。サービスグループの武田です。

Sphinxは多様なフォーマットでドキュメントを生成できるツールです。ドキュメントを管理・運用していて、あとから「国際化・多言語化」が必要になるケースがあります。

さてSphinxの場合はというと、きちんと国際化対応のための機能が提供されています。公式のドキュメントを参考にしながら実際に試してみました。

環境

次のような環境で検証しています。

$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.15.5
BuildVersion:	19F101

$ pipenv --version
pipenv, version 2018.11.26

またsphinx-buildは3.1.2です。Sphinxはグローバルにインストールもできますが、今回はPipenvを使用しています。

国際化対応の流れ

Sphinxが提供している国際化機能を利用する場合、次のような流れになります(フロー図も参考)。

  1. ベースとなるドキュメント(rst)を作成
  2. POT(Potable Object Template)ファイルを生成
    • make gettextで生成できる
  3. 各言語用のPO(Potable Object)ファイルを作成
    • sphinx-intl updateで各言語用にコピー後、翻訳作業
  4. ビルドして各言語の成果物(HTMLなど)を生成
    • 内部的にMO(Machine Object)ファイルが生成されている

1のベースドキュメントは任意の言語で問題ありません。ただし英語で用意できるなら、英語がベターです。違いは何かというと、見出しに対して自動生成されるパーマリンクに差が出ます。パーマリンクの一部となるハッシュ(#foo-bar形式の文字列)は見出しをもとに自動的に付与されます。このとき、アルファベットや数字であればそのまま使われるのですが、日本語でアルファベットが含まれていない見出しだと#id1のようになります。他の言語では試していませんが、おそらくマルチバイト文字列はこういう挙動なのかなと想像しています。ベースドキュメントを英語で用意できるのであれば、国際化対応後の成果物でもきれいなハッシュが付与されます。

ベースドキュメントを作成する

それでは前述した流れに沿って国際化対応を実際に試してみましょう。まずはベースとなるドキュメントを作成します。先ほど英語がベターと書きましたが、気にせず日本語で用意します。

$ cd /path/to/working
$ mkdir sphinx-test-doc && $_
$ pipenv --python 3.7
$ pipenv install sphinx
$ pipenv run sphinx-quickstart --sep -p 'Sphinx Test Doc' -a 'Classmethod' -r '' -l ja

プロジェクトが作成できたら適当にページを追加してみます。

source/developers-io-2020-connect.rst

==========================
Developers.IO 2020 CONNECT
==========================

- `就職せずに自己資本でクラスメソッドを起業して16年掛けて年商200億円になった話 <https://www.youtube.com/watch?v=4wWeazCpjpU>`_

トップページも修正します。

source/index.rst

==========
ようこそ!
==========

.. toctree::
   :maxdepth: 2
   :caption: Contents:

   developers-io-2020-connect

これで準備できましたのでビルドして結果を確認してみましょう。

$ pipenv run make html
$ open build/html/index.html

問題なさそうです!

POTファイルを生成する

Sphinxの国際化機能はGNU gettextを利用しています。前述したように、まずドキュメントから翻訳対象となる文章を集めてカタログテンプレート化(POTファイル)します。この操作はすでに用意されているため、コマンドをたたくだけで簡単に生成できますが、事前に公式の推奨設定を追記しておきます。

source/conf.py

@@ -40,6 +40,8 @@ templates_path = ['_templates']
 # Usually you set "language" from the command line for these cases.
 language = 'ja'

+gettext_compact = False
+
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
 # This pattern also affects html_static_path and html_extra_path.

実際にコマンドをたたいてみます。

$ pipenv run make gettext

$ ls build/gettext/
developers-io-2020-connect.pot	index.pot

無事に生成されました。ちなみに、中身は次のようなフォーマットになっています。msgidにベースドキュメントの文章。msgstrは空ですが、翻訳文を記載する箇所です。

$ tail build/gettext/developers-io-2020-connect.pot
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: ../../source/developers-io-2020-connect.rst:3
msgid "Developers.IO 2020 CONNECT"
msgstr ""

#: ../../source/developers-io-2020-connect.rst:5
msgid "`就職せずに自己資本でクラスメソッドを起業して16年掛けて年商200億円になった話 <https://www.youtube.com/watch?v=4wWeazCpjpU>`_"
msgstr ""

各言語用のPOファイルを生成する

先ほど生成されたPOTファイルは、そのままは使いません。各言語用にコピーして使うことになります。ただ手作業でコピーとか面倒ですし、ドキュメント更新の際に翻訳も追加するといった場合に、単に上書きするというわけにもいきません。というわけでsphinx-intlというツールが提供されています。これを使うことで難しいことを考えずにPOファイルが準備できます。

$ pipenv install sphinx-intl

また公式の推奨設定を追記します。

source/conf.py

@@ -42,6 +42,8 @@ language = 'ja'

 gettext_compact = False

+locale_dirs = ['locale/']
+
 # List of patterns, relative to source directory, that match files and
 # directories to ignore when looking for source files.
 # This pattern also affects html_static_path and html_extra_path.

それではsphinx-intlを使ってPOファイルを準備していきます。コマンド実行時に、国際化が必要な言語をコードで指定します。今回は英語(en)と韓国語(ko)を指定してみました。ちなみに、すでにPOファイルが存在しても差分を取り込んでくれるため安心してupdateしてください。

$ pipenv run sphinx-intl update -p build/gettext -l en -l ko

$ ls source/locale/*/*
source/locale/en/LC_MESSAGES:
developers-io-2020-connect.po	index.po

source/locale/ko/LC_MESSAGES:
developers-io-2020-connect.po	index.po

POファイルが生成されました。あとはこのPOファイルに、翻訳文を記入していきます(機械翻訳なので、翻訳文についてはあまり気にしないでください)。なお、翻訳が必要ない箇所は空欄のままでOKです。

--- a/source/locale/en/LC_MESSAGES/developers-io-2020-connect.po
+++ b/source/locale/en/LC_MESSAGES/developers-io-2020-connect.po
@@ -27,4 +27,5 @@ msgid ""
 "`就職せずに自己資本でクラスメソッドを起業して16年掛けて年商200億円になった話 "
 "<https://www.youtube.com/watch?v=4wWeazCpjpU>`_"
 msgstr ""
-
+"`Talking about 20 billion yen in annual sales over 16 years since starting a class method with equity without employment "
+"<https://www.youtube.com/watch?v=4wWeazCpjpU>`_"

--- a/source/locale/en/LC_MESSAGES/index.po
+++ b/source/locale/en/LC_MESSAGES/index.po
@@ -24,5 +24,5 @@ msgstr ""

 #: ../../source/index.rst:3
 msgid "ようこそ!"
-msgstr ""
+msgstr "Welcome!"

--- a/source/locale/ko/LC_MESSAGES/developers-io-2020-connect.po
+++ b/source/locale/ko/LC_MESSAGES/developers-io-2020-connect.po
@@ -27,4 +27,5 @@ msgid ""
 "`就職せずに自己資本でクラスメソッドを起業して16年掛けて年商200億円になった話 "
 "<https://www.youtube.com/watch?v=4wWeazCpjpU>`_"
 msgstr ""
-
+"`취업하지 않고 자기 자본에서 클래스 메소드를 창업 해 16 년 걸어 연매출 200 억엔 된 이야기 "
+"<https://www.youtube.com/watch?v=4wWeazCpjpU>`_"

@@ -24,5 +24,5 @@ msgstr ""

 #: ../../source/index.rst:3
 msgid "ようこそ!"
-msgstr ""
+msgstr "오신 것을 환영합니다!"

各言語でビルドする

各言語用のPOファイルが用意できたら、あとはビルドすれば完成です。さっそくビルドして確認してみましょう。

まずは英語でビルドしてみます。

$ pipenv run make html -e SPHINXOPTS='-D language="en"'
$ open build/html/index.html

英語になっていますね。

同様に韓国語でもビルドしてみます。

$ pipenv run make html -e SPHINXOPTS='-D language="ko"'
$ open build/html/index.html

韓国語になっています(が、私は読めません)。

まとめ

Sphinxドキュメントの国際化対応について手順をさらってみました。Sphinxの公式ドキュメントも使用していますし、しくみとして実績のあるものですので安定して使えるのではないでしょうか。