Commits

Takayuki Shimizukawa committed b5fb711

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``.

Comments (0)

Files changed (9)

 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.
   If provided, it will be used instead of html_use_index for epub builder.
 

doc/_templates/index.html

 {% extends "layout.html" %}
-{% set title = 'Overview' %}
+{% set title = _('Overview') %}
 {% block body %}
-  <h1>Welcome</h1>
+  <h1>{{ _('Welcome') }}</h1>
 
   <div class="quotebar">
-    <p><em>What users say:</em></p>
-    <p>&ldquo;Cheers for a great tool that actually makes programmers <b>want</b>
-      to write documentation!&rdquo;</p>
+    <p><em>{%trans%}What users say:{%endtrans%}</em></p>
+    <p>{%trans%}&ldquo;Cheers for a great tool that actually makes programmers <b>want</b>
+      to write documentation!&rdquo;{%endtrans%}</p>
   </div>
 
-  <p>
+  <p>{%trans%}
     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>
-  <p>It was originally created for <a href="http://docs.python.org/">the
+    documentation, written by Georg Brandl and licensed under the BSD license.{%endtrans%}</p>
+  <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
     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
     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>
   <ul>
-    <li><b>Output formats:</b> HTML (including Windows HTML Help), LaTeX (for
-      printable PDF versions), Texinfo, manual pages, plain text</li>
-    <li><b>Extensive cross-references:</b> semantic markup and automatic links
+    <li>{%trans%}<b>Output formats:</b> HTML (including Windows HTML Help), LaTeX (for
+      printable PDF versions), Texinfo, manual pages, plain text{%endtrans%}</li>
+    <li>{%trans%}<b>Extensive cross-references:</b> semantic markup and automatic links
       for functions, classes, citations, glossary terms and similar pieces of
-      information</li>
-    <li><b>Hierarchical structure:</b> easy definition of a document tree, with
-      automatic links to siblings, parents and children</li>
-    <li><b>Automatic indices:</b> general index as well as a language-specific
-      module indices</li>
-    <li><b>Code handling:</b> automatic highlighting using the <a
-      href="http://pygments.org">Pygments</a> highlighter</li>
-    <li><b>Extensions:</b> automatic testing of code snippets, inclusion of
+      information{%endtrans%}</li>
+    <li>{%trans%}<b>Hierarchical structure:</b> easy definition of a document tree, with
+      automatic links to siblings, parents and children{%endtrans%}</li>
+    <li>{%trans%}<b>Automatic indices:</b> general index as well as a language-specific
+      module indices{%endtrans%}</li>
+    <li>{%trans%}<b>Code handling:</b> automatic highlighting using the <a
+      href="http://pygments.org">Pygments</a> highlighter{%endtrans%}</li>
+    <li>{%trans path=pathto('extensions')%}<b>Extensions:</b> automatic testing of code snippets, inclusion of
       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>
-  <p>
+  <p>{%trans%}
     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
     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>
 
-  <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>
     <td width="50%">
-      <p class="biglink"><a class="biglink" href="{{ pathto("tutorial") }}">First steps with Sphinx</a><br/>
-         <span class="linkdescr">overview of basic tasks</span></p>
-      <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">Contents</a><br/>
-         <span class="linkdescr">for a complete overview</span></p>
+      <p class="biglink"><a class="biglink" href="{{ pathto("tutorial") }}">{%trans%}First steps with Sphinx{%endtrans%}</a><br/>
+         <span class="linkdescr">{%trans%}overview of basic tasks{%endtrans%}</span></p>
+      <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">{%trans%}Contents{%endtrans%}</a><br/>
+         <span class="linkdescr">{%trans%}for a complete overview{%endtrans%}</span></p>
     </td><td width="50%">
-      <p class="biglink"><a class="biglink" href="{{ pathto("search") }}">Search page</a><br/>
-         <span class="linkdescr">search the documentation</span></p>
-      <p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">General Index</a><br/>
-         <span class="linkdescr">all functions, classes, terms</span></p>
+      <p class="biglink"><a class="biglink" href="{{ pathto("search") }}">{%trans%}Search page{%endtrans%}</a><br/>
+         <span class="linkdescr">{%trans%}search the documentation{%endtrans%}</span></p>
+      <p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">{%trans%}General Index{%endtrans%}</a><br/>
+         <span class="linkdescr">{%trans%}all functions, classes, terms{%endtrans%}</span></p>
     </td></tr>
   </table>
 
-  <p>
+  <p>{%trans%}
     You can also download PDF versions of the Sphinx documentation:
     a <a href="http://sphinx-doc.org/sphinx.pdf">version</a> generated from
     the LaTeX Sphinx produces, and
     a <a href="http://sphinx-doc.org/sphinx-rst2pdf.pdf">version</a> generated
-    by rst2pdf.
+    by rst2pdf.{%endtrans%}
   </p>
 
-  <h2>Examples</h2>
-  <p>Links to documentation generated with Sphinx can be found on the
-    <a href="{{ pathto("examples") }}">Projects using Sphinx</a> page.
+  <h2>{%trans%}Examples{%endtrans%}</h2>
+  <p>{%trans path=pathto("examples")%}Links to documentation generated with Sphinx can be found on the
+    <a href="{{ path }}">Projects using Sphinx</a> page.{%endtrans%}
   </p>
-  <p>
+  <p>{%trans%}
     For examples of how Sphinx source files look, use the &#8220;Show
     source&#8221; links on all pages of the documentation apart from this
-    welcome page.
+    welcome page.{%endtrans%}
   </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
     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>
-    of this documentation, thanks to Yoshiki Shibukawa.</p>
+  <p>{%trans%}There is a <a href="http://sphinx-users.jp/doc10/">Japanese translation</a>
+    of this documentation, thanks to Yoshiki Shibukawa.{%endtrans%}</p>
 
 {% endblock %}

doc/_templates/indexsidebar.html

 <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>
 {% if version.endswith('(hg)') %}
-<p>This documentation is for version <b>{{ version }}</b>, which is
-  not released yet.</p>
-<p>You can use it from the
+<p>{%trans%}This documentation is for version <b>{{ version }}</b>, which is
+  not released yet.{%endtrans%}</p>
+<p>{%trans%}You can use it from the
   <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
-    Package Index</a>.</p>
+    Package Index</a>.{%endtrans%}</p>
 {% else %}
-<p>Current version: <b>{{ version }}</b></p>
-<p>Get Sphinx from the <a href="http://pypi.python.org/pypi/Sphinx">Python Package
-Index</a>, or install it with:</p>
+<p>{%trans%}Current version: <b>{{ version }}</b>{%endtrans%}</p>
+<p>{%trans%}Get Sphinx from the <a href="http://pypi.python.org/pypi/Sphinx">Python Package
+Index</a>, or install it with:{%endtrans%}</p>
 <pre>easy_install -U Sphinx</pre>
-<p>Latest <a href="http://sphinx-doc.org/latest/">development version docs</a>
-are also available.</p>
+<p>{%trans%}Latest <a href="http://sphinx-doc.org/latest/">development version docs</a>
+are also available.{%endtrans%}</p>
 {% 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"
       style="padding-left: 0.5em">
   <input type="text" name="email" value="your@email" style="font-size: 90%; width: 120px"
          onfocus="$(this).val('');"/>
   <input type="submit" name="sub" value="Subscribe" style="font-size: 90%; width: 70px"/>
 </form>
-<p>or come to the <tt>#pocoo</tt> channel on FreeNode.</p>
-<p>You can also open an issue at the
-  <a href="http://www.bitbucket.org/birkenfeld/sphinx/issues/">tracker</a>.</p>
+<p>{%trans%}or come to the <tt>#pocoo</tt> channel on FreeNode.{%endtrans%}</p>
+<p>{%trans%}You can also open an issue at the
+  <a href="http://www.bitbucket.org/birkenfeld/sphinx/issues/">tracker</a>.{%endtrans%}</p>

sphinx/builders/gettext.py

     :license: BSD, see LICENSE for details.
 """
 
-from os import path
+from os import path, walk
 from codecs import open
 from datetime import datetime
 from collections import defaultdict
+from uuid import uuid4
 
 from sphinx.builders import Builder
 from sphinx.util import split_index_msg
 from sphinx.util.nodes import extract_messages, traverse_translatable_index
-from sphinx.util.osutil import safe_relpath, ensuredir, find_catalog
-from sphinx.util.console import darkgreen
+from sphinx.util.osutil import safe_relpath, ensuredir, find_catalog, SEP
+from sphinx.util.console import darkgreen, purple, bold
 from sphinx.locale import pairindextypes
 
 POHEADER = ur"""
         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):
     """
     General i18n builder.
     """
     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):
         I18nBuilder.finish(self)
         data = dict(
 
                     # message contains *one* line of text ready for translation
                     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)
 
             finally:

tests/roots/test-intl/_templates/index.html

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

tests/roots/test-intl/conf.py

 project = 'Sphinx intl <Tests>'
 source_suffix = '.txt'
 keep_warnings = True
+templates_path = ['_templates']
+html_additional_pages = {'index': 'index.html'}
+release = version = '2013.120'

tests/roots/test-intl/sphinx.po

+# 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"

tests/test_build_gettext.py

 
     # unexpected msgid existent
     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

tests/test_intl.py

     app.builder.build(['docfields'])
     result = (app.outdir / 'docfields.html').text(encoding='utf-8')
     # 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
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.