国際化対応済みのSphinxドキュメントに言語切り替えボタンを実装する

こんにちは。サービスグループの武田です。国際化対応した後のSphinxドキュメントに、手軽に言語切り替えするためのボタン(プルダウン)を実装してみました。
2020.07.28

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

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

先日、Sphinxで国際化対応をする手順を確認しました。

各言語ごとにドキュメントが生成されるため、これらをWebサーバーやS3などにデプロイすることで公開できます。さてそうなると次は、各言語の切り替えがしたくなります。URLを直接変更してもらうのは、あまり現実的ではありませんね。というわけで、手軽に言語切り替えするためのボタン(プルダウン)を実装してみました。

なお、前回作成したもの(上記のリンク先参照)を拡張する形で実装します。実際に試してみたい方はそちらを参考にプロジェクトの作成などを行ってください。

今回のゴール

ゴールはもちろん切り替えボタンの実装ですが、それに伴いいくつかの前提を設けます。

まず、ドキュメント公開後のURLですが、ベースURLの後にパスとして次のような言語コードを含めるものとします。言い換えれば、ja/en/がドキュメントのルートになります。

  • https://docs.example.com/ja/index.html
  • https://docs.example.com/en/index.html
  • https://docs.example.com/ko/index.html

ローカルでも同じ構成にしたいので、buildディレクトリの構成を次のようにします。

$ tree -L 2 build/
build/
└── html
    ├── en
    ├── ja
    └── ko

切り替えボタンを実装してみる

実現したい要件を書き出してみます。

  1. サポートしている言語がプルダウン表示される
  2. 言語を選択するとその言語のページに切り替わる(ページ遷移する)
  3. 現在選択中の言語がプルダウンで選択済みとなっている

さてページのどこに切り替えボタンを配置するかですが、今回はフッタ部分に置きます(細かい調整はしません)。Sphinxではテンプレートの上書きがサポートされているため、使用しているテーマごとに編集するファイルは異なります。今回はデフォルトのAlabasterです。Alabasterではフッタは独立ファイルではなくlayout.htmlの一部で定義されています。まずはこれをコピーします。

$ cp .venv/lib/python3.7/site-packages/alabaster/layout.html source/_templates/

さっそく修正していきたいところですが、その前にconf.pyで、ドキュメントがサポートしている言語一覧を辞書として定義しておきます。キーを言語コード、値を言語名とします。定義した値はテンプレートに渡されるため、それを利用してプルダウンを定義します。

source/conf.py

@@ -61,3 +61,11 @@ html_theme = 'alabaster'
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
 html_static_path = ['_static']
+
+html_context = {
+    'support_languages': {
+        'ja': '日本語',
+        'en': 'English',
+        'ko': '한국어'
+    }
+}

次にlayout.htmlを次のように修正します。

source/_templates/layout.html

@@ -86,6 +86,18 @@

 {%- block footer %}
     <div class="footer">
+      <div>
+        <select name="lang" onchange="location.href=value;">
+          {%- for code, display in support_languages.items() %}
+            <option value="{{ pathto('../' + code + '/', 1) }}{{ pathto(pagename, 0, '.') }}"
+              {%- if code == language %}
+                selected
+              {%- endif %}
+            >{{ display }}</option>
+          {%- endfor %}
+        </select>
+      </div>
+
       {% if show_copyright %}&copy;{{ copyright }}.{% endif %}
       {% if theme_show_powered_by|lower == 'true' %}
       {% if show_copyright %}|{% endif %}

selectタグのonchange="location.href=value;"は、プルダウンで選択した際のイベントハンドラを定義しています。選択された項目のvalueをURLに指定することで自動的なページ遷移を実現します。

次のforループは、先ほどconf.pyで定義したhtml_contextの値がテンプレートに渡されているためここでoptionタグに展開します。codeにはjaなどの言語コードが、displayには日本語などの言語名が代入されます。

{{ pathto('../' + code + '/', 1) }}{{ pathto(pagename, 0, '.') }}が何をしているのかわかりにくいのですが……。ざっくりいうと言語コードだけ変えた現在ページへの相対パスを生成しています(/ja/index.htmlに対する../en/index.htmlなど)。

{%- if code == language %} selectedは、languageが生成するドキュメントの言語設定が入っているので、同じであれば選択済みとします。

これで言語切り替えボタンの実装は完了です。

Makefileを修正して出力先を変更する

ビルド→本番サーバーにコピー(デプロイ)を各言語ごとに行うのであれば、ここの作業は特に必要ありません。というのも、初期設定のままだと、build/htmlにビルドしたドキュメントが生成されるので、言語の指定だけ変更して再ビルドすると上書きされます。そのため、次の言語でビルドする前にコピーを済ませておく必要があります。これはビルドおよびデプロイプロセスの話なのでまぁいいんですが、ローカルで確認するときに不便ですね。というわけで、Makefileを修正して、各言語のドキュメント生成を一括でかつ独立して生成されるようにしましょう。

次のようにMakefileを修正します。html_%はワイルドカードを使用したターゲットで、言語設定および出力先をターゲットで指定できます。htmlはデフォルトのターゲットを上書きするもので、対応する言語を依存先として指定しています。こうしておけばhtmlを指定するだけで各言語のドキュメントが生成されます。

Makefile

@@ -14,6 +14,13 @@ help:

 .PHONY: help Makefile

+html_%:
+       @$(SPHINXBUILD) -D language="$*" -b html "$(SOURCEDIR)" "$(BUILDDIR)/html/$*" $(0)
+
+# orverride default html target
+html: html_ja html_en html_ko
+       @
+
 # Catch-all target: route all unknown targets to Sphinx using the new
 # "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
 %: Makefile

切り替えを試してみる

これで準備できました!さっそくビルドして試してみましょう。

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

日本語ページ。

英語ページ。

韓国語ページ。

プルダウンの選択で切り替わりますし、選択済みの言語も変わっていますね!

まとめ

Sphinxドキュメントに言語切り替えボタンを実装してみました。今回はデフォルトのAlabasterのままシンプルに実装しましたが、CSSで見栄えをきれいにもできます。配置する場所も融通がききますので、好きなところに配置してみてください。