Add i18n capabilities for custom templates.

For example: The Sphinx reference documentation in doc directory provides
sphinx.pot file from ``doc/_templates/*.html`` by ``make gettext``.
This commit is contained in:
Takayuki Shimizukawa 2013-03-10 22:07:31 +09:00
parent 7b443298a3
commit 2c409959ac
9 changed files with 167 additions and 62 deletions

View File

@ -1,6 +1,10 @@
Release 1.2 (in development) Release 1.2 (in development)
============================ ============================
* Add i18n capabilities for custom templates.
For example: The Sphinx reference documentation in doc directory provides
sphinx.pot file from ``doc/_templates/*.html`` by ``make gettext``.
* PR#123, #1106: Add epub_use_index configuration value. * PR#123, #1106: Add epub_use_index configuration value.
If provided, it will be used instead of html_use_index for epub builder. If provided, it will be used instead of html_use_index for epub builder.

View File

@ -1,87 +1,87 @@
{% extends "layout.html" %} {% extends "layout.html" %}
{% set title = 'Overview' %} {% set title = _('Overview') %}
{% block body %} {% block body %}
<h1>Welcome</h1> <h1>{{ _('Welcome') }}</h1>
<div class="quotebar"> <div class="quotebar">
<p><em>What users say:</em></p> <p><em>{%trans%}What users say:{%endtrans%}</em></p>
<p>&ldquo;Cheers for a great tool that actually makes programmers <b>want</b> <p>{%trans%}&ldquo;Cheers for a great tool that actually makes programmers <b>want</b>
to write documentation!&rdquo;</p> to write documentation!&rdquo;{%endtrans%}</p>
</div> </div>
<p> <p>{%trans%}
Sphinx is a tool that makes it easy to create intelligent and beautiful Sphinx is a tool that makes it easy to create intelligent and beautiful
documentation, written by Georg Brandl and licensed under the BSD license.</p> documentation, written by Georg Brandl and licensed under the BSD license.{%endtrans%}</p>
<p>It was originally created for <a href="http://docs.python.org/">the <p>{%trans%}It was originally created for <a href="http://docs.python.org/">the
new Python documentation</a>, and it has excellent facilities for the new Python documentation</a>, and it has excellent facilities for the
documentation of Python projects, but C/C++ is already supported as well, documentation of Python projects, but C/C++ is already supported as well,
and it is planned to add special support for other languages as well. Of and it is planned to add special support for other languages as well. Of
course, this site is also created from reStructuredText sources using course, this site is also created from reStructuredText sources using
Sphinx! The following features should be highlighted: Sphinx! The following features should be highlighted:{%endtrans%}
</p> </p>
<ul> <ul>
<li><b>Output formats:</b> HTML (including Windows HTML Help), LaTeX (for <li>{%trans%}<b>Output formats:</b> HTML (including Windows HTML Help), LaTeX (for
printable PDF versions), Texinfo, manual pages, plain text</li> printable PDF versions), Texinfo, manual pages, plain text{%endtrans%}</li>
<li><b>Extensive cross-references:</b> semantic markup and automatic links <li>{%trans%}<b>Extensive cross-references:</b> semantic markup and automatic links
for functions, classes, citations, glossary terms and similar pieces of for functions, classes, citations, glossary terms and similar pieces of
information</li> information{%endtrans%}</li>
<li><b>Hierarchical structure:</b> easy definition of a document tree, with <li>{%trans%}<b>Hierarchical structure:</b> easy definition of a document tree, with
automatic links to siblings, parents and children</li> automatic links to siblings, parents and children{%endtrans%}</li>
<li><b>Automatic indices:</b> general index as well as a language-specific <li>{%trans%}<b>Automatic indices:</b> general index as well as a language-specific
module indices</li> module indices{%endtrans%}</li>
<li><b>Code handling:</b> automatic highlighting using the <a <li>{%trans%}<b>Code handling:</b> automatic highlighting using the <a
href="http://pygments.org">Pygments</a> highlighter</li> href="http://pygments.org">Pygments</a> highlighter{%endtrans%}</li>
<li><b>Extensions:</b> automatic testing of code snippets, inclusion of <li>{%trans path=pathto('extensions')%}<b>Extensions:</b> automatic testing of code snippets, inclusion of
docstrings from Python modules (API docs), and docstrings from Python modules (API docs), and
<a href="{{ pathto('extensions') }}#builtin-sphinx-extensions">more</a></li> <a href="{{ path }}#builtin-sphinx-extensions">more</a>{%endtrans%}</li>
</ul> </ul>
<p> <p>{%trans%}
Sphinx uses <a href="http://docutils.sf.net/rst.html">reStructuredText</a> Sphinx uses <a href="http://docutils.sf.net/rst.html">reStructuredText</a>
as its markup language, and many of its strengths come from the power and as its markup language, and many of its strengths come from the power and
straightforwardness of reStructuredText and its parsing and translating straightforwardness of reStructuredText and its parsing and translating
suite, the <a href="http://docutils.sf.net/">Docutils</a>. suite, the <a href="http://docutils.sf.net/">Docutils</a>.{%endtrans%}
</p> </p>
<h2 style="margin-bottom: 0">Documentation</h2> <h2 style="margin-bottom: 0">{%trans%}Documentation{%endtrans%}</h2>
<table class="contentstable" align="center" style="margin-left: 30px"><tr> <table class="contentstable" align="center" style="margin-left: 30px"><tr>
<td width="50%"> <td width="50%">
<p class="biglink"><a class="biglink" href="{{ pathto("tutorial") }}">First steps with Sphinx</a><br/> <p class="biglink"><a class="biglink" href="{{ pathto("tutorial") }}">{%trans%}First steps with Sphinx{%endtrans%}</a><br/>
<span class="linkdescr">overview of basic tasks</span></p> <span class="linkdescr">{%trans%}overview of basic tasks{%endtrans%}</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">Contents</a><br/> <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">{%trans%}Contents{%endtrans%}</a><br/>
<span class="linkdescr">for a complete overview</span></p> <span class="linkdescr">{%trans%}for a complete overview{%endtrans%}</span></p>
</td><td width="50%"> </td><td width="50%">
<p class="biglink"><a class="biglink" href="{{ pathto("search") }}">Search page</a><br/> <p class="biglink"><a class="biglink" href="{{ pathto("search") }}">{%trans%}Search page{%endtrans%}</a><br/>
<span class="linkdescr">search the documentation</span></p> <span class="linkdescr">{%trans%}search the documentation{%endtrans%}</span></p>
<p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">General Index</a><br/> <p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">{%trans%}General Index{%endtrans%}</a><br/>
<span class="linkdescr">all functions, classes, terms</span></p> <span class="linkdescr">{%trans%}all functions, classes, terms{%endtrans%}</span></p>
</td></tr> </td></tr>
</table> </table>
<p> <p>{%trans%}
You can also download PDF versions of the Sphinx documentation: You can also download PDF versions of the Sphinx documentation:
a <a href="http://sphinx-doc.org/sphinx.pdf">version</a> generated from a <a href="http://sphinx-doc.org/sphinx.pdf">version</a> generated from
the LaTeX Sphinx produces, and the LaTeX Sphinx produces, and
a <a href="http://sphinx-doc.org/sphinx-rst2pdf.pdf">version</a> generated a <a href="http://sphinx-doc.org/sphinx-rst2pdf.pdf">version</a> generated
by rst2pdf. by rst2pdf.{%endtrans%}
</p> </p>
<h2>Examples</h2> <h2>{%trans%}Examples{%endtrans%}</h2>
<p>Links to documentation generated with Sphinx can be found on the <p>{%trans path=pathto("examples")%}Links to documentation generated with Sphinx can be found on the
<a href="{{ pathto("examples") }}">Projects using Sphinx</a> page. <a href="{{ path }}">Projects using Sphinx</a> page.{%endtrans%}
</p> </p>
<p> <p>{%trans%}
For examples of how Sphinx source files look, use the &#8220;Show For examples of how Sphinx source files look, use the &#8220;Show
source&#8221; links on all pages of the documentation apart from this source&#8221; links on all pages of the documentation apart from this
welcome page. welcome page.{%endtrans%}
</p> </p>
<p>You may also be interested in the very nice <p>{%trans%}You may also be interested in the very nice
<a href="http://matplotlib.sourceforge.net/sampledoc/">tutorial</a> on how to <a href="http://matplotlib.sourceforge.net/sampledoc/">tutorial</a> on how to
create a customized documentation using Sphinx written by the matplotlib create a customized documentation using Sphinx written by the matplotlib
developers.</p> developers.{%endtrans%}</p>
<p>There is a <a href="http://sphinx-users.jp/doc10/">Japanese translation</a> <p>{%trans%}There is a <a href="http://sphinx-users.jp/doc10/">Japanese translation</a>
of this documentation, thanks to Yoshiki Shibukawa.</p> of this documentation, thanks to Yoshiki Shibukawa.{%endtrans%}</p>
{% endblock %} {% endblock %}

View File

@ -1,32 +1,32 @@
<p class="logo">A <a href="http://pocoo.org/"> <p class="logo">A <a href="http://pocoo.org/">
<img src="{{ pathto("_static/pocoo.png", 1) }}" /></a> project</a></p> <img src="{{ pathto("_static/pocoo.png", 1) }}" /></a> {%trans%}project{%endtrans%}</a></p>
<h3>Download</h3> <h3>Download</h3>
{% if version.endswith('(hg)') %} {% if version.endswith('(hg)') %}
<p>This documentation is for version <b>{{ version }}</b>, which is <p>{%trans%}This documentation is for version <b>{{ version }}</b>, which is
not released yet.</p> not released yet.{%endtrans%}</p>
<p>You can use it from the <p>{%trans%}You can use it from the
<a href="http://bitbucket.org/birkenfeld/sphinx/">Mercurial repo</a> or look for <a href="http://bitbucket.org/birkenfeld/sphinx/">Mercurial repo</a> or look for
released versions in the <a href="http://pypi.python.org/pypi/Sphinx">Python released versions in the <a href="http://pypi.python.org/pypi/Sphinx">Python
Package Index</a>.</p> Package Index</a>.{%endtrans%}</p>
{% else %} {% else %}
<p>Current version: <b>{{ version }}</b></p> <p>{%trans%}Current version: <b>{{ version }}</b>{%endtrans%}</p>
<p>Get Sphinx from the <a href="http://pypi.python.org/pypi/Sphinx">Python Package <p>{%trans%}Get Sphinx from the <a href="http://pypi.python.org/pypi/Sphinx">Python Package
Index</a>, or install it with:</p> Index</a>, or install it with:{%endtrans%}</p>
<pre>easy_install -U Sphinx</pre> <pre>easy_install -U Sphinx</pre>
<p>Latest <a href="http://sphinx-doc.org/latest/">development version docs</a> <p>{%trans%}Latest <a href="http://sphinx-doc.org/latest/">development version docs</a>
are also available.</p> are also available.{%endtrans%}</p>
{% endif %} {% endif %}
<h3>Questions? Suggestions?</h3> <h3>{%trans%}Questions? Suggestions?{%endtrans%}</h3>
<p>Join the <a href="http://groups.google.com/group/sphinx-users">Google group</a>:</p> <p>{%trans%}Join the <a href="http://groups.google.com/group/sphinx-users">Google group</a>:{%endtrans%}</p>
<form action="http://groups.google.com/group/sphinx-users/boxsubscribe" <form action="http://groups.google.com/group/sphinx-users/boxsubscribe"
style="padding-left: 0.5em"> style="padding-left: 0.5em">
<input type="text" name="email" value="your@email" style="font-size: 90%; width: 120px" <input type="text" name="email" value="your@email" style="font-size: 90%; width: 120px"
onfocus="$(this).val('');"/> onfocus="$(this).val('');"/>
<input type="submit" name="sub" value="Subscribe" style="font-size: 90%; width: 70px"/> <input type="submit" name="sub" value="Subscribe" style="font-size: 90%; width: 70px"/>
</form> </form>
<p>or come to the <tt>#pocoo</tt> channel on FreeNode.</p> <p>{%trans%}or come to the <tt>#pocoo</tt> channel on FreeNode.{%endtrans%}</p>
<p>You can also open an issue at the <p>{%trans%}You can also open an issue at the
<a href="http://www.bitbucket.org/birkenfeld/sphinx/issues/">tracker</a>.</p> <a href="http://www.bitbucket.org/birkenfeld/sphinx/issues/">tracker</a>.{%endtrans%}</p>

View File

@ -9,16 +9,17 @@
:license: BSD, see LICENSE for details. :license: BSD, see LICENSE for details.
""" """
from os import path from os import path, walk
from codecs import open from codecs import open
from datetime import datetime from datetime import datetime
from collections import defaultdict from collections import defaultdict
from uuid import uuid4
from sphinx.builders import Builder from sphinx.builders import Builder
from sphinx.util import split_index_msg from sphinx.util import split_index_msg
from sphinx.util.nodes import extract_messages, traverse_translatable_index from sphinx.util.nodes import extract_messages, traverse_translatable_index
from sphinx.util.osutil import safe_relpath, ensuredir, find_catalog from sphinx.util.osutil import safe_relpath, ensuredir, find_catalog, SEP
from sphinx.util.console import darkgreen from sphinx.util.console import darkgreen, purple, bold
from sphinx.locale import pairindextypes from sphinx.locale import pairindextypes
POHEADER = ur""" POHEADER = ur"""
@ -57,6 +58,17 @@ class Catalog(object):
self.metadata[msg].append((origin.source, origin.line, origin.uid)) self.metadata[msg].append((origin.source, origin.line, origin.uid))
class MsgOrigin(object):
"""
Origin holder for Catalog message origin.
"""
def __init__(self, source, line):
self.source = source
self.line = line
self.uid = uuid4().hex
class I18nBuilder(Builder): class I18nBuilder(Builder):
""" """
General i18n builder. General i18n builder.
@ -101,6 +113,43 @@ class MessageCatalogBuilder(I18nBuilder):
""" """
name = 'gettext' name = 'gettext'
def init(self):
I18nBuilder.init(self)
self.create_template_bridge()
self.templates.init(self)
def _collect_templates(self):
template_files = set()
for template_path in self.config.templates_path:
tmpl_abs_path = path.join(self.app.srcdir, template_path)
for dirpath, dirs, files in walk(tmpl_abs_path):
for fn in files:
if fn.endswith('.html'):
filename = path.join(dirpath, fn)
filename = filename.replace(path.sep, SEP)
template_files.add(filename)
return template_files
def _extract_from_template(self):
files = self._collect_templates()
self.info(bold('building [%s]: ' % self.name), nonl=1)
self.info('targets for %d template files' % len(files))
extract_translations = self.templates.environment.extract_translations
for template in self.status_iterator(files,
'reading templates... ', purple, len(files)):
#catalog = self.catalogs[template]
catalog = self.catalogs['sphinx']
context = open(template, 'rt').read() #TODO: encoding
for line, meth, msg in extract_translations(context):
origin = MsgOrigin(template, line)
catalog.add(msg, origin)
def build(self, docnames, summary=None, method='update'):
self._extract_from_template()
I18nBuilder.build(self, docnames, summary, method)
def finish(self): def finish(self):
I18nBuilder.finish(self) I18nBuilder.finish(self)
data = dict( data = dict(
@ -136,7 +185,8 @@ class MessageCatalogBuilder(I18nBuilder):
# message contains *one* line of text ready for translation # message contains *one* line of text ready for translation
message = message.replace(u'\\', ur'\\'). \ message = message.replace(u'\\', ur'\\'). \
replace(u'"', ur'\"') replace(u'"', ur'\"'). \
replace(u'\n', u'\\n"\n"')
pofile.write(u'msgid "%s"\nmsgstr ""\n\n' % message) pofile.write(u'msgid "%s"\nmsgstr ""\n\n' % message)
finally: finally:

View File

@ -0,0 +1,5 @@
{% extends "layout.html" %}
{% block body %}
<h1>{{ _('Welcome') }}</h1>
<p>{%trans%}Sphinx {{ version }}{%endtrans%}</p>
{% endblock %}

View File

@ -5,3 +5,6 @@ import sys, os
project = 'Sphinx intl <Tests>' project = 'Sphinx intl <Tests>'
source_suffix = '.txt' source_suffix = '.txt'
keep_warnings = True keep_warnings = True
templates_path = ['_templates']
html_additional_pages = {'index': 'index.html'}
release = version = '2013.120'

View File

@ -0,0 +1,23 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2012, foof
# This file is distributed under the same license as the foo package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: sphinx 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-11-22 08:28\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "Welcome"
msgstr "WELCOME"
msgid "Sphinx %(version)s"
msgstr "SPHINX %(version)s"

View File

@ -137,3 +137,15 @@ def test_gettext_index_entries(app):
# unexpected msgid existent # unexpected msgid existent
assert msgids == [] assert msgids == []
@with_app(buildername='gettext',
srcdir=(test_roots / 'test-intl'),
doctreedir=(test_roots / 'test-intl' / '_build' / 'doctree'))
def test_gettext_template(app):
app.builder.build_all()
assert (app.outdir / 'sphinx.pot').isfile()
result = (app.outdir / 'sphinx.pot').text(encoding='utf-8')
assert "Welcome" in result
assert "Sphinx %(version)s" in result

View File

@ -420,3 +420,11 @@ def test_i18n_docfields_html(app):
app.builder.build(['docfields']) app.builder.build(['docfields'])
result = (app.outdir / 'docfields.html').text(encoding='utf-8') result = (app.outdir / 'docfields.html').text(encoding='utf-8')
# expect no error by build # expect no error by build
@with_intl_app(buildername='html')
def test_gettext_template(app):
app.builder.build_all()
result = (app.outdir / 'index.html').text(encoding='utf-8')
assert "WELCOME" in result
assert "SPHINX 2013.120" in result