lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20231030113052.ykblzg2jdca6pmlt@numero-86.vaga.pv.it>
Date:   Mon, 30 Oct 2023 12:30:52 +0100
From:   Federico Vaga <federico.vaga@...a.pv.it>
To:     Vegard Nossum <vegard.nossum@...cle.com>
Cc:     Jonathan Corbet <corbet@....net>, linux-doc@...r.kernel.org,
        Akira Yokosawa <akiyks@...il.com>,
        Carlos Bilbao <carlos.bilbao@....com>,
        Alex Shi <alexs@...nel.org>,
        Yanteng Si <siyanteng@...ngson.cn>,
        Hu Haowen <src.res.211@...il.com>, linux-kernel@...r.kernel.org
Subject: Re: [PATCH] docs: translations: add translations links when they
 exist

I find it a nice initiative :)

On Sat, Oct 28, 2023 at 06:29:31PM +0200, Vegard Nossum wrote:
>Add a new Sphinx extension that knows about the translations of kernel
>documentation and can insert links to the translations at the top of
>the document.
>
>It basically works like this:
>
>1. Register a new node type, LanguagesNode.
>
>2. Register a new transform, TranslationsTransform, that inserts a new
>   LanguageNode at the top of every document. The LanguageNode contains
>   "pending references" to translations of the document. The key here
>   is that these are pending (i.e. unresolved) references that may or
>   may not actually exist.
>
>3. Register a 'doctree-resolved' event that iterates over all the
>   LanguageNode nodes. Any unresolved references are filtered out; the
>   list of resolved references is passed to the 'translations.html'
>   template and rendered as an HTML node (if HTML output is selected).
>
>Testing: make htmldocs with v7.3.0.
>
>Signed-off-by: Vegard Nossum <vegard.nossum@...cle.com>
>---
> Documentation/conf.py                         |  2 +-
> Documentation/sphinx-static/custom.css        |  8 ++
> .../sphinx/templates/translations.html        | 12 +++
> Documentation/sphinx/translations.py          | 96 +++++++++++++++++++
> 4 files changed, 117 insertions(+), 1 deletion(-)
> create mode 100644 Documentation/sphinx/templates/translations.html
> create mode 100644 Documentation/sphinx/translations.py
>
>diff --git a/Documentation/conf.py b/Documentation/conf.py
>index d4fdf6a3875a..64eab500b2cd 100644
>--- a/Documentation/conf.py
>+++ b/Documentation/conf.py
>@@ -55,7 +55,7 @@ needs_sphinx = '1.7'
> extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include',
>               'kfigure', 'sphinx.ext.ifconfig', 'automarkup',
>               'maintainers_include', 'sphinx.ext.autosectionlabel',
>-              'kernel_abi', 'kernel_feat']
>+              'kernel_abi', 'kernel_feat', 'translations']
>
> if major >= 3:
>     if (major > 3) or (minor > 0 or patch >= 2):
>diff --git a/Documentation/sphinx-static/custom.css b/Documentation/sphinx-static/custom.css
>index 084a884f6fb7..33adee4a35d9 100644
>--- a/Documentation/sphinx-static/custom.css
>+++ b/Documentation/sphinx-static/custom.css
>@@ -73,3 +73,11 @@ input.kernel-toc-toggle { display: none; }
>     h3.kernel-toc-contents { display: inline; }
>     div.kerneltoc a { color: black; }
> }
>+
>+/* Language selection bar */
>+div.language-selection {
>+    background: #eeeeee;
>+    border: 1px solid #cccccc;
>+    margin-bottom: 1em;
>+    padding: .5em;
>+}
>diff --git a/Documentation/sphinx/templates/translations.html b/Documentation/sphinx/templates/translations.html
>new file mode 100644
>index 000000000000..08afb595c203
>--- /dev/null
>+++ b/Documentation/sphinx/templates/translations.html
>@@ -0,0 +1,12 @@
>+<!-- SPDX-License-Identifier: GPL-2.0 -->
>+<!-- Copyright © 2023, Oracle and/or its affiliates. -->
>+
>+{# Create a language bar for translations #}
>+{% if languages|length > 0: %}
>+<div class="language-selection">
>+Languages:

Should also "Languages" subject to translation?
Or perhaps, nothing. Just the list of languages.

>+{% for ref in languages: %}
>+<a href="{{ ref.refuri }}">{{ ref.astext() }}</a>{% if not loop.last %}, {% endif %}
>+{% endfor %}
>+</div>
>+{% endif %}
>diff --git a/Documentation/sphinx/translations.py b/Documentation/sphinx/translations.py
>new file mode 100644
>index 000000000000..e1da811bdaf0
>--- /dev/null
>+++ b/Documentation/sphinx/translations.py
>@@ -0,0 +1,96 @@
>+# SPDX-License-Identifier: GPL-2.0
>+#
>+# Copyright © 2023, Oracle and/or its affiliates.
>+# Author: Vegard Nossum <vegard.nossum@...cle.com>
>+#
>+# Add translation links to the top of the document.
>+#
>+
>+import os
>+
>+from docutils import nodes
>+from docutils.transforms import Transform
>+
>+import sphinx
>+from sphinx import addnodes
>+from sphinx.errors import NoUri
>+
>+all_languages = {
>+    # English is always first
>+    None: 'English',
>+
>+    # Keep the rest sorted alphabetically
>+    'zh_CN': 'Chinese',
>+    'it_IT': 'Italian',
>+    'ja_JP': 'Japanese',
>+    'ko_KR': 'Korean',
>+    'sp_SP': 'Spanish',
>+    'zh_TW': 'Taiwanese',

Minor comment. Should we use the language name in its original language?

Example:

[... snip ...]
'it_IT': Italiano,
[... snip ...]
'sp_SP': Español,
[... snip ...]

>+}
>+
>+class LanguagesNode(nodes.Element):
>+    pass
>+
>+class TranslationsTransform(Transform):
>+    default_priority = 900
>+
>+    def apply(self):
>+        app = self.document.settings.env.app
>+        if app.builder.format not in ['html']:
>+            return
>+
>+        docname = self.document.settings.env.docname
>+
>+        this_lang_code = None
>+        components = docname.split(os.sep)
>+        if components[0] == 'translations' and len(components) > 2:
>+            this_lang_code = components[1]
>+
>+            # normalize docname to be the untranslated one
>+            docname = os.path.join(*components[2:])
>+
>+        new_nodes = LanguagesNode()
>+
>+        for lang_code, lang_name in all_languages.items():
>+            if lang_code == this_lang_code:
>+                continue

We could show all languages (remove the above two lines) to have a consistent
output among pages.

>+            if lang_code is None:
>+                target_name = docname
>+            else:
>+                target_name = os.path.join('translations', lang_code, docname)
>+
>+            pxref = addnodes.pending_xref('', refdomain='std',
>+                reftype='doc', reftarget='/' + target_name, modname=None,
>+                classname=None, refexplicit=True)
>+            pxref += nodes.Text(lang_name)
>+            new_nodes += pxref
>+
>+        self.document.insert(0, new_nodes)
>+
>+def process_languages(app, doctree, docname):
>+    for node in doctree.traverse(LanguagesNode):
>+        languages = []
>+
>+        # Iterate over the child nodes; any resolved links will have
>+        # the type 'nodes.reference', while unresolved links will be
>+        # type 'nodes.Text'.
>+        languages = list(filter(lambda xref:
>+            isinstance(xref, nodes.reference), node.children))
>+
>+        html_content = app.builder.templates.render('translations.html',
>+            context={
>+                'languages': languages,
>+            })
>+
>+        node.replace_self(nodes.raw('', html_content, format='html'))
>+
>+def setup(app):
>+    app.add_node(LanguagesNode)
>+    app.add_transform(TranslationsTransform)
>+    app.connect('doctree-resolved', process_languages)
>+
>+    return {
>+        'parallel_read_safe': True,
>+        'parallel_write_safe': True,
>+    }
>-- 
>2.34.1
>

-- 
Federico Vaga

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ