Skip to content

Commit

Permalink
Add :notranslate: metadata feature
Browse files Browse the repository at this point in the history
  • Loading branch information
jeanas committed Dec 19, 2023
1 parent 3596590 commit 3918e8f
Show file tree
Hide file tree
Showing 13 changed files with 95 additions and 1 deletion.
4 changes: 4 additions & 0 deletions doc/usage/advanced/intl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ because code blocks do not contain references anyway.)
.. versionadded:: 4.5
The ``#noqa`` mechanism.

If certain parts of the documentation should not be translated, e.g., you want
to translate tutorials but not technical reference material, you can use the
``:notranslate:`` metadata field. See :ref:`special-metadata-fields`.


Translating with sphinx-intl
----------------------------
Expand Down
11 changes: 11 additions & 0 deletions doc/usage/restructuredtext/field-lists.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ document metadata, and is not displayed in the output.
*docinfo* as normal and will be displayed in the output.


.. _special-metadata-fields:

Special metadata fields
-----------------------

Expand Down Expand Up @@ -76,3 +78,12 @@ At the moment, these metadata fields are recognized:
.. note:: object search is still available even if `nosearch` option is set.

.. versionadded:: 3.0

``notranslate``
If set, no paragraphs from this document will be added to Gettext message
catalogs. This may be useful to save work to the translators, e.g., if you
want to internationalize tutorials but not technical reference material. When
found in a document ``.../index``, this recursively applies to all
documents in the directory ``.../``.

.. versionadded:: 7.3.0
9 changes: 8 additions & 1 deletion sphinx/builders/gettext.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
from sphinx.util.display import status_iterator
from sphinx.util.i18n import CatalogInfo, docname_to_domain
from sphinx.util.index_entries import split_index_msg
from sphinx.util.nodes import extract_messages, traverse_translatable_index
from sphinx.util.nodes import (
extract_messages,
is_translatable_document,
traverse_translatable_index,
)
from sphinx.util.osutil import canon_path, ensuredir, relpath
from sphinx.util.tags import Tags
from sphinx.util.template import SphinxRenderer
Expand Down Expand Up @@ -150,6 +154,9 @@ def compile_catalogs(self, catalogs: set[CatalogInfo], message: str) -> None:
return

def write_doc(self, docname: str, doctree: nodes.document) -> None:
if not is_translatable_document(docname, self.env):
return

catalog = self.catalogs[docname_to_domain(docname, self.config.gettext_compact)]

for toctree in self.env.tocs[docname].findall(addnodes.toctree):
Expand Down
8 changes: 8 additions & 0 deletions sphinx/transforms/i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,14 @@ class Locale(SphinxTransform):
default_priority = 20

def apply(self, **kwargs: Any) -> None:
# TODO/FIXME: If this document is marked :notranslate:, it might
# be better to skip translation here. Some paragraphs might
# still get translated in rare cases, e.g., if gettext_compact=True
# and there is an identical paragraph in a document that is not
# marked :notranslate:. This might be tricky, since self.env.metadata
# is only populated in the doctree-read event, which runs after
# this transform.

settings, source = self.document.settings, self.document['source']
msgstr = ''

Expand Down
13 changes: 13 additions & 0 deletions sphinx/util/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,19 @@ def is_translatable(node: Node) -> bool:
return False


def is_translatable_document(docname: str, env: BuildEnvironment) -> bool:
docname_parts = docname.split('/')
for i in range(len(docname_parts) + 1):
bare_prefix = '/'.join(docname_parts[:i])
for prefix_docname in (bare_prefix, bare_prefix + '/index'):
if (
prefix_docname in env.metadata
and 'notranslate' in env.metadata[prefix_docname]
):
return False
return True


LITERAL_TYPE_NODES = (
nodes.literal_block,
nodes.doctest_block,
Expand Down
1 change: 1 addition & 0 deletions tests/roots/test-notranslate/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
gettext_compact = False
14 changes: 14 additions & 0 deletions tests/roots/test-notranslate/dir/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
:notranslate:

A directory
===========

``dir/index.rst`` is not translated.

The ``:notranslate:`` metadata on this document will apply
to the whole directory.

.. toctree::

non-translated
subdir/index
4 changes: 4 additions & 0 deletions tests/roots/test-notranslate/dir/non-translated.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Non-translated document
=======================

``dir/non-translated.rst`` is not translated.
4 changes: 4 additions & 0 deletions tests/roots/test-notranslate/dir/subdir/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Non-translated document
=======================

``dir/subdir/non-translated.rst`` is not translated.
7 changes: 7 additions & 0 deletions tests/roots/test-notranslate/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
``index.rst`` is translated.

.. toctree::

non-translated
translated
dir/index
6 changes: 6 additions & 0 deletions tests/roots/test-notranslate/non-translated.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
:notranslate:

Non-translated document
=======================

``non-translated.rst`` is not translated.
4 changes: 4 additions & 0 deletions tests/roots/test-notranslate/translated.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Translated document
===================

``translated.rst`` is translated.
11 changes: 11 additions & 0 deletions tests/test_notranslate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pathlib import Path

import pytest


@pytest.mark.sphinx("gettext", testroot="notranslate")
def test_notranslate_extraction(app):
app.build()
out = Path(app.outdir)
pot_files = {path.relative_to(out) for path in out.glob("*.pot")}
assert pot_files == {Path("index.pot"), Path("translated.pot")}

0 comments on commit 3918e8f

Please sign in to comment.