bitbucketにsix翻訳をホスト

six翻訳そのものも本題ではあるけれど。

bitbucketにsix翻訳をホスト

前置き

真の狙いは、Sphinxの普及啓蒙と、また、出来るだけ多くの人に、気軽に OSS に参加してもらいたい、ということだったりします。ので、ワタシが six 翻訳をあげるまでの作業内容を記録しときます。(皆がこの手順に従う必要があるということではないです。プロジェクトの大きさによると思う。)

準備

翻訳作業に入る前の準備をしときます。

Sphinxはもちろん必要ですが、翻訳作業を助けてくれる、清水川さんの拡張がありますので、この準備をまず。

Requirements for basicにて、

と説明されてます。

Transifex は今回はパス。six のドキュメントはそう大きなものではないので、皆で共同で、というものでもないですから。ので、清水川さんの拡張本体のみインストール(依存物は pip が解決してくれる):

 1 me@host: ~$ pip install sphinx-intl
 2 Downloading/unpacking sphinx-intl
 3   Downloading sphinx_intl-0.9.5-py2.py3-none-any.whl
 4 Requirement already satisfied (use --upgrade to upgrade): sphinx in c:\python27\lib\site-packages\sphinx-1.2.3-py2.7.egg (from sphinx-intl)
 5 Requirement already satisfied (use --upgrade to upgrade): six in c:\python27\lib\site-packages (from sphinx-intl)
 6 Requirement already satisfied (use --upgrade to upgrade): setuptools in c:\python27\lib\site-packages (from sphinx-intl)
 7 Requirement already satisfied (use --upgrade to upgrade): polib in c:\python27\lib\site-packages (from sphinx-intl)
 8 Requirement already satisfied (use --upgrade to upgrade): Pygments>=1.2 in c:\python27\lib\site-packages\pygments-2.0.2-py2.7.egg (from sphinx->sphinx-intl)
 9 Requirement already satisfied (use --upgrade to upgrade): docutils>=0.7 in c:\python27\lib\site-packages\docutils-0.12-py2.7.egg (from sphinx->sphinx-intl)
10 Requirement already satisfied (use --upgrade to upgrade): Jinja2>=2.3 in c:\python27\lib\site-packages\jinja2-2.7.3-py2.7.egg (from sphinx->sphinx-intl)
11 Requirement already satisfied (use --upgrade to upgrade): markupsafe in c:\python27\lib\site-packages\markupsafe-0.23-py2.7.egg (from Jinja2>=2.3->sphinx->sphinx-intl)
12 Installing collected packages: sphinx-intl
13 Successfully installed sphinx-intl
14 Cleaning up...
15 me@host: ~$ 

基本、「必要なもの」としての準備はこれだけ。

翻訳プロジェクト開始のための準備

本家リソースに追従するために必要な、管理ポリシーを考えておく。

幸い six 本家も bitbucket 管理なので、目標の形としては、https://bitbucket.org/gutworth/sixから Fork して変更していくのがベストと思う。ので、完成形はこの形とする。

ただし、ワタシは恥ずかしがりやさんなので、作業途中の履歴が公開レポジトリに記録されてくのはいやだぁ、と仮定します。ので、イキナリ Fork する前に、先に

  1. 単に自分の PC に clone し
  2. clone した先の .hg をいったん消して
  3. ローカル PC の中だけのレポジトリに(TortoiseHgの「Create Repository Here」で)変更

としときます。このローカルなレポジトリで自分の作業を一時的に管理することで、リビジョン管理の恩恵を受けつつも、公には記録が残らないようにしたい、ってわけね。およそ作業完了後の変更予想箇所はわかってはいますけど、あとで本当に Fork したあと、ローカルに管理してたものを「上書き」すれば、魔法のように一気に完成品 Fork が出来ますわよね。「出来るヒト」に思わせることが出来ます :-P

翻訳プロジェクト開始

sphinx-intl流儀に、documentationを変更する必要があります:

Makefileの末尾に
1 gettext: clean
2 	sphinx-build -b gettext -d build/doctrees . locale/pot
conf.pyに(例えば末尾)
1 # For translation
2 # ---------------
3 gettext_compact = False
4 locale_dirs = ["locale"]
5 language = 'ja'

この Makefile と conf.py の変更を加えたら、

 1 me@host: six$ cd documentation/
 2 me@host: documentation$ ls
 3 Makefile  conf.py  index.rst
 4 me@host: documentation$ make gettext
 5 rm -rf _build/*
 6 sphinx-build -b gettext -d build/doctrees . locale/pot
 7 Making output directory...
 8 Running Sphinx v1.2.3
 9 loading pickled environment... not yet created
10 loading intersphinx inventory from https://docs.python.org/2/objects.inv...
11 loading intersphinx inventory from https://docs.python.org/3/objects.inv...
12 building [gettext]: targets for 0 template files
13 building [gettext]: targets for 1 source files that are out of date
14 updating environment: 1 added, 0 changed, 0 removed
15 reading sources... [100%] index
16 
17 looking for now-outdated files... none found
18 pickling environment... done
19 checking consistency... done
20 preparing documents... done
21 writing output... [100%] index
22 
23 writing message catalogs... [100%] index
24 me@host: documentation$ 

とすると、build/doctreeslocale/pot/index.potが出来上がります(*)。

gettext に馴染みがあるヒトには釈迦に説法ですが、pot の中身はだいたいこんな感じです:

locale/pot/index.potの抜粋
 1 # SOME DESCRIPTIVE TITLE.
 2 # Copyright (C) 2010-2015, Benjamin Peterson
 3 # This file is distributed under the same license as the six package.
 4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 5 #
 6 #, fuzzy
 7 msgid ""
 8 msgstr ""
 9 "Project-Id-Version: six 1.9\n"
10 "Report-Msgid-Bugs-To: \n"
11 "POT-Creation-Date: 2015-07-13 16:02+0900\n"
12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14 "Language-Team: LANGUAGE <LL@li.org>\n"
15 "MIME-Version: 1.0\n"
16 "Content-Type: text/plain; charset=UTF-8\n"
17 "Content-Transfer-Encoding: 8bit\n"
18 
19 #: ..\..\index.rst:2
20 # 459bf97ddd914ddeb4baac04c48a4795
21 msgid "Six: Python 2 and 3 Compatibility Library"
22 msgstr ""
23 
24 #: ..\..\index.rst:11
25 # 3691254aec1a43d6bf81793cc0697f8a
26 msgid "Six provides simple utilities for wrapping over differences between Python 2 and Python 3.  It is intended to support codebases that work on both Python 2 and 3 without modification.  six consists of only one Python file, so it is painless to copy into a project."
27 msgstr ""

この locale/pot/ の下の pot は、翻訳作業における編集対象ファイルではありませんが、これを作らないと各言語用 po を作れません。この pot に基づいて生成するので。(ので、この pot は SCM 管理対象にするのが普通。翻訳対象元に変更があった場合に更新するものになります。)

最後に、「翻訳対象」となる po を、以下で作ります(*):

1 me@host: documentation$ sphinx-intl update -l ja
2 Create: locale/ja\LC_MESSAGES\index.po

この po ファイルが、以後翻訳作業をするファイルになります。まだ何も「翻訳してない」ので、こんなだよ、最初は:

locale/ja/LC_MESSAGES/index.poの抜粋
 1 #
 2 msgid ""
 3 msgstr ""
 4 "Project-Id-Version: six 1.9\n"
 5 "Report-Msgid-Bugs-To: \n"
 6 "POT-Creation-Date: 2015-07-13 16:02+0900\n"
 7 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 8 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 9 "Language-Team: LANGUAGE <LL@li.org>\n"
10 "MIME-Version: 1.0\n"
11 "Content-Type: text/plain; charset=UTF-8\n"
12 "Content-Transfer-Encoding: 8bit\n"
13 
14 #: ..\..\index.rst:2
15 msgid "Six: Python 2 and 3 Compatibility Library"
16 msgstr ""
17 
18 #: ..\..\index.rst:11
19 msgid ""
20 "Six provides simple utilities for wrapping over differences between Python 2"
21 " and Python 3.  It is intended to support codebases that work on both Python"
22 " 2 and 3 without modification.  six consists of only one Python file, so it "
23 "is painless to copy into a project."
24 msgstr ""
25 
26 #: ..\..\index.rst:16
27 msgid ""
28 "Six can be downloaded on `PyPi <http://pypi.python.org/pypi/six/>`_.  Its "
29 "bug tracker and code hosting is on `BitBucket "
30 "<http://bitbucket.org/gutworth/six>`_."
31 msgstr ""
32 
33 #: ..\..\index.rst:19
34 msgid ""
35 "The name, \"six\", comes from the fact that 2*3 equals 6.  Why not addition?"
36 " Multiplication is more powerful, and, anyway, \"five\" has already been "
37 "snatched away by the (admittedly now moribund) Zope Five project."
38 msgstr ""

本格的に作業開始する前に、お試し

流れとしては以後は、

  1. po 編集
  2. sphinx-intl build
  3. make -e SPHINXOPTS="-D language='ja'" html

の繰り返し(*)。ので、まず一つ簡単に翻訳して、出力してみます。

locale/ja/LC_MESSAGES/index.po、最初だけ翻訳してみる
 1 #
 2 msgid ""
 3 msgstr ""
 4 "Project-Id-Version: six 1.9\n"
 5 "Report-Msgid-Bugs-To: \n"
 6 "POT-Creation-Date: 2015-07-13 16:02+0900\n"
 7 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 8 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 9 "Language-Team: LANGUAGE <LL@li.org>\n"
10 "MIME-Version: 1.0\n"
11 "Content-Type: text/plain; charset=UTF-8\n"
12 "Content-Transfer-Encoding: 8bit\n"
13 
14 #: ..\..\index.rst:2
15 msgid "Six: Python 2 and 3 Compatibility Library"
16 msgstr "Six: Python 2 と 3 の互換性ライブラリ"
17 
18 #: ..\..\index.rst:11
19 msgid ""
20 "Six provides simple utilities for wrapping over differences between Python 2"
21 " and Python 3.  It is intended to support codebases that work on both Python"
22 " 2 and 3 without modification.  six consists of only one Python file, so it "
23 "is painless to copy into a project."
24 msgstr ""
25 "Sixは、Python 2 と Python 3 の間の違いを吸収するためのシンプルなユーティリティを提供します。"
26 "それらは、Python 2 と Python 3 の両方でコードベースの変更なく動作することをサポートするよう意図されています。"
27 "six はたった一つの Python ファイルだけで構成されていますから、プロジェクトへコピーして利用することに苦痛はありません。"
 1 me@host: documentation$ sphinx-intl build
 2 Build: locale\ja\LC_MESSAGES\index.mo
 3 me@host: documentation$ make html
 4 sphinx-build -b html -d _build/doctrees   . _build/html
 5 Running Sphinx v1.2.3
 6 loading translations [ja]... done
 7 loading pickled environment... done
 8 building [html]: targets for 0 source files that are out of date
 9 updating environment: 0 added, 1 changed, 0 removed
10 reading sources... [100%] index
11 
12 looking for now-outdated files... none found
13 pickling environment... done
14 checking consistency... done
15 preparing documents... done
16 writing output... [100%] index
17 
18 writing additional files... genindex py-modindex search
19 copying static files... WARNING: html_static_path entry u'c:\\Users\\hhsprings\\__ttmp\\six\\documentation\\_static' does not exist
20 done
21 copying extra files... done
22 dumping search index... done
23 dumping object inventory... done
24 build succeeded, 1 warning.
25 
26 Build finished. The HTML pages are in _build/html.
27 me@host: documentation$ 

知ってる人にはどうでもいい説明を一応しときますと、mo は「コンパイル済みメッセージリソース」で、バイナリなので、中身を読んだからといってどうともならないですけど、Sphinx そのものにとっては mo が「入力」となります。SCM 管理的には除外しておくのが普通。(開発チームが何を共有するか次第。)

さて、こんなん出ました:

良さげだね。

ドキュメントに対する「機能拡張」3つ

またしても翻訳そのものを始める前に、3つ、ドキュメントとしての機能拡張をしておきます。

一つ目はcollapsiblesidebar。conf.py にこれを追加しておきます:

conf.pyに
1 # Theme options are theme-specific and customize the look and feel of a theme
2 # further.  For a list of options available for each theme, see the
3 # documentation.
4 #html_theme_options = {}
5 html_theme_options = {'collapsiblesidebar': True}

ま、これは必須ではないですがね。あたしゃこれ、あった方がやっぱ使いやすいと思う。

もう一つはね、docs.python.jpと同じノリで、「原文へのリンク」機能です。あと、copybutton 機能も欲しいよね(*)。

こっちはどうしても「テンプレート」を自作しなければならないです。ですけど、これは python-doc-ja プロジェクトを真似ればいいのです。さすがに大きいので抽出は大変そうにみえますけど、全然そんなことはないです。「ちゃんと」貢献者が参加出来るようなものにするための作業は残るものの、今必要なのは templates/layout.html と、static/_jp.js、static/copybutton.js だけです。

static/copybutton.js はそのまま改変しません。

static/_jp.js は改変する必要がある。python-doc は階層を持った複雑な加工が必要ですけど、six は単純に一個の index.html になるので、「単純化」が必要な改変:

_ja.js
1 $(document).ready(function() {
2     var base = 'https://pythonhosted.org/six/';
3     $('a.headerlink').each(function() {
4             var html = '<a class="headerlink" href="' + base + $(this).attr('href') +
5                        '" title="原文へのリンク">(原文)</a>';
6             $(this).after(html);
7         })
8 });

templates/layout.html は、これも、ひとまず必要最小限としてはこれだけにしときます:

templates/layout.html
 1 {% extends "!layout.html" %}
 2 {% block relbar1 %} {% if builder != 'qthelp' %} {{ relbar() }} {% endif %} {% endblock %}
 3 {% block relbar2 %} {% if builder != 'qthelp' %} {{ relbar() }} {% endif %} {% endblock %}
 4 {% block extrahead %}
 5     {% if not embedded %}<script type="text/javascript" src="{{ pathto('_static/copybutton.js', 1) }}"></script>{% endif %}
 6     {% if not embedded %}<script type="text/javascript" src="{{ pathto('_static/_jp.js', 1) }}"></script>{% endif %}
 7 {{ super() }}
 8 {% endblock %}
 9 {% block footer %}
10     <div class="footer">
11     &copy; {{copyright}}.
12     Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> {{ sphinx_version|e }}.
13     <br />
14     <!--TODO ここに翻訳者と issue tracker へのリンクを -->
15     </div>
16 {% endblock %}

オリジナルのコピーライトをなくしてしまわないように注意。ほかには、翻訳ドキュメントとしての著作権への考慮、issue tracker へのリンクとか色々気を使わなければならないことを盛り込む必要はありますが、まずは始めるに当たってはひとまずこれで。

で、このテンプレートを使うのに conf.py を変更します:

conf.py
 1 # -- Options for HTML output ---------------------------------------------------
 2 
 3 # The theme to use for HTML and HTML Help pages.  See the documentation for
 4 # a list of builtin themes.
 5 html_theme = "default"
 6 
 7 # Theme options are theme-specific and customize the look and feel of a theme
 8 # further.  For a list of options available for each theme, see the
 9 # documentation.
10 #html_theme_options = {}
11 html_theme_options = {'collapsiblesidebar': True}
12 
13 # Add any paths that contain custom themes here, relative to this directory.
14 #html_theme_path = []
15 
16 # The name for this set of Sphinx documents.  If None, it defaults to
17 # "<project> v<release> documentation".
18 #html_title = None
19 
20 # A shorter title for the navigation bar.  Default is the same as html_title.
21 #html_short_title = None
22 
23 # The name of an image file (relative to this directory) to place at the top
24 # of the sidebar.
25 #html_logo = None
26 
27 # The name of an image file (within the static path) to use as favicon of the
28 # docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
29 # pixels large.
30 #html_favicon = None
31 
32 # Add any paths that contain custom static files (such as style sheets) here,
33 # relative to this directory. They are copied after the builtin static files,
34 # so a file named "default.css" will overwrite the builtin "default.css".
35 html_static_path = ["tools/static"]
36 
37 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
38 # using the given strftime format.
39 #html_last_updated_fmt = '%b %d, %Y'
40 
41 # Path to find HTML templates.
42 templates_path = ['tools/templates']

(tools 配下に置く、というところまで猿真似る必要はないんですが、逆に言えばこんなとこで個性発揮する必要もないんで、踏襲してます。)

この上でビルドして、確認出来たら、自分のレポジトリにコミットしときます。あとはひたすら po を訳していくだけ。

全ての po が翻訳できたので、仕上げに入る

これまで誰も傷付けない「俺様」レポジトリ(自分のPC内)で作業してましたが、いよいよ公開レポジトリにしていきます。

最初に方針を立てた通り、本家最新への追従しやすさを考えると、(documentation部分だけ抽出するのも魅力ではあるんですが)https://bitbucket.org/gutworth/sixを Fork してしまうのがやはり良いと思うので、Fork しました。なお、Fork 時には忘れずに issue tracking が有効になるようにしておきます。

さて、issue trackingが準備出来たので、上で仮で作った layout.html に反映しておきます:

six/documentation/tools/templates/layout.html
 1 {% extends "!layout.html" %}
 2 {% block relbar1 %} {% if builder != 'qthelp' %} {{ relbar() }} {% endif %} {% endblock %}
 3 {% block relbar2 %} {% if builder != 'qthelp' %} {{ relbar() }} {% endif %} {% endblock %}
 4 {% block extrahead %}
 5     {% if not embedded %}<script type="text/javascript" src="{{ pathto('_static/copybutton.js', 1) }}"></script>{% endif %}
 6     {% if not embedded %}<script type="text/javascript" src="{{ pathto('_static/_jp.js', 1) }}"></script>{% endif %}
 7 {{ super() }}
 8 {% endblock %}
 9 {% block footer %}
10     <div class="footer">
11     &copy; {{copyright}}.
12     <br />
13     Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> {{ sphinx_version|e }}.
14     <br />
15     &copy; hhsprings &lt;<a href="https://bitbucket.org/hhsprings">https://bitbucket.org/hhsprings</a>&gt;
16     <br />
17     翻訳への提案や誤訳・誤脱の報告は<a href="https://bitbucket.org/hhsprings/six-doc-ja/issues?status=new&status=open" target="_blank">issues</a>にお願いします。
18     </div>
19 {% endblock %}

ここまでを「俺様」レポジトリで作業しきったら、この内容で先の Forkに上書きします。(レポジトリが違うわけなので、「ファイルの追加」も漏らさずね。)

成果物公開

Forkにコミット、プッシュが済めば、これで「ソースコードを管理する」ための環境は整いました。ですが、これはまだ「ソースコードを管理できる場所」が出来上がっただけです。Forkの上に Sphinx 生成物を配置しても、HTML ページとして参照可能にはなりません。

生成物をホストする場所はこことは別です。以下で説明されている:

の通り、「アカウント名.bitbucket.org」というレポジトリを作ると、そこは静的ページのホスティングが出来る場所になります。ワタシの場合は、レポジトリは https://bitbucket.org/hhsprings/hhsprings.bitbucket.org、これを「WEBページ」として参照するのには、https://hhsprings.bitbucket.io/。つまり、読者に訪れてもらうサイトは後者、その管理レポジトリが前者。(文章だとなかなか伝わりにくいと思うので、実際に訪れてみてください。)

https://hhsprings.bitbucket.io/の構成は自由なので、どうとでも出来ます。ただ、無計画に作ると URL 移動が読者に迷惑になるので、https://hhsprings.bitbucket.io/docs/translations/python/six-doc-jaとしました。これが翻訳した成果物です。


2017-07-12 追記

すぐに更新すれば良かったんだけれどサボってしまってました。bitbucket のポリシー変更によって「https://だけのホストのサポート」になったため、元は「http://<userid>.bitbucket.org/」だったんだけれど、「https://<userid>.bitbucket.io/」になりました。アタシの例の場合は https://hhsprings.bitbucket.io/ ね。