From 78399ef60b7bac3052628b7110a194c7b1167588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=C3=A1n=20Maureira-Fredes?= Date: Thu, 9 Dec 2021 12:09:37 +0100 Subject: [PATCH 1/3] =?UTF-8?q?Agregar=20script=20de=20traducci=C3=B3n=20a?= =?UTF-8?q?utom=C3=A1tica?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Se utiliza deep_translator en vez de googletrans para evitar los problemas de timeout, y restricciones del módulo. No se agregó el módulo en el archivo `requirements.txt` pues no es necesario para la construcción de la documentación. El script utiliza `polib` para iterar sobre las entradas de un archivo po determinado y luego reemplaza mediante expresiones regulares todas las sentencias de sphinx, por ejemplo: This :mod:`polib` module allows you to handle :ref:`translations`. quedaría como: This XASDF00 module allows you to handle XASDF02. texto que luego peude ser traducido sin problemas de alterar los espacios, acentos invertidos, dos puntos, etc, que es un problem usual al utilizar otros servicios de traducción automática. La traducción quedaría: Este módulo XASDF00 te permite manejar XASDF02. a lo que luego se vuelven a reemplazar los textos temporales por su contenido original: Este módulo :mod:`polib` te permite manejar :ref:`translations`. --- scripts/translate.py | 118 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 scripts/translate.py diff --git a/scripts/translate.py b/scripts/translate.py new file mode 100644 index 0000000000..7f31812a68 --- /dev/null +++ b/scripts/translate.py @@ -0,0 +1,118 @@ +import os +import re +import sys +from typing import Dict, Tuple + +import polib + +VERBOSE = False +DEBUG = False +SKIP_TRANSLATED_ENTRIES = True + +try: + from deep_translator import GoogleTranslator +except ImportError: + print("Error: This util script needs `deep_translator` to be installed") + sys.exit(1) + + +def protect_sphinx_directives(s: str) -> Tuple[dict, str]: + """ + Parameters: + string containing the text to translate + + Returns: + dictionary containing all the placeholder text as keys + and the correct value. + """ + exps = [ + ":c:func:`[^`]+`", + ":c:type:`[^`]+`", + ":c:macro:`[^`]+`", + ":c:member:`[^`]+`", + ":c:data:`[^`]+`", + ":py:data:`[^`]+`", + ":py:mod:`[^`]+`", + ":func:`[^`]+`", + ":mod:`[^`]+`", + ":ref:`[^`]+`", + ":class:`[^`]+`", + ":pep:`[^`]+`", + ":data:`[^`]+`", + ":exc:`[^`]+`", + ":term:`[^`]+`", + ":meth:`[^`]+`", + ":envvar:`[^`]+`", + ":file:`[^`]+`", + ":attr:`[^`]+`", + ":const:`[^`]+`", + ":issue:`[^`]+`", + ":opcode:`[^`]+`", + ":option:`[^`]+`", + ":keyword:`[^`]+`", + ":RFC:`[^`]+`", + ":doc:`[^`]+`", + "``[^`]+``", + "`[^`]+`__", + "`[^`]+`_", + "\*\*.+\*\*", # bold text between ** + "\*.+\*", # italic text between * + ] + + i = 0 + d: Dict[str, str] = {} + for exp in exps: + matches = re.findall(exp, s) + if DEBUG: + print(exp, matches) + for match in matches: + ph = f"XASDF{str(i).zfill(2)}" + s = s.replace(match, ph) + if ph in d and VERBOSE: + print(f"Error: {ph} is already in the dictionary") + print("new", match) + print("old", d[ph]) + d[ph] = match + i += 1 + return d, s + + +def undo_sphinx_directives_protection(placeholders: dict, translated_text: str) -> str: + for ph, value in placeholders.items(): + translated_text = translated_text.replace(ph, value) + if DEBUG: + print(ph, value) + print(translated_text) + return translated_text + + +if __name__ == "__main__": + filename = sys.argv[1] + if not os.path.isfile(filename): + print(f"File not found: '{filename}'") + sys.exit(-1) + + po = polib.pofile(filename) + translator = GoogleTranslator(source="en", target="es") + + for i, entry in enumerate(po): + # If the entry has already a translation, skip. + if SKIP_TRANSLATED_ENTRIES and entry.msgstr: + continue + + print("\nEN|", entry.msgid) + placeholders, temp_text = protect_sphinx_directives(entry.msgid) + if VERBOSE: + print(temp_text) + print(placeholders) + + # Translate the temporary text without sphinx statements + translated_text = translator.translate(temp_text) + + # Recover sphinx statements + real_text = undo_sphinx_directives_protection(placeholders, translated_text) + print("ES|", real_text) + + # Replace the po file translated entry, and save + entry.msgstr = real_text + po.save() From 61fbe63c790916b202f774b010227bceab468656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=C3=A1n=20Maureira-Fredes?= Date: Thu, 9 Dec 2021 16:23:11 +0100 Subject: [PATCH 2/3] =?UTF-8?q?agregar=20comentarios=20de=20la=20revisi?= =?UTF-8?q?=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/translate.py | 80 +++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/scripts/translate.py b/scripts/translate.py index 7f31812a68..d752959e51 100644 --- a/scripts/translate.py +++ b/scripts/translate.py @@ -15,6 +15,41 @@ print("Error: This util script needs `deep_translator` to be installed") sys.exit(1) +_patterns = [ + ":c:func:`[^`]+`", + ":c:type:`[^`]+`", + ":c:macro:`[^`]+`", + ":c:member:`[^`]+`", + ":c:data:`[^`]+`", + ":py:data:`[^`]+`", + ":py:mod:`[^`]+`", + ":func:`[^`]+`", + ":mod:`[^`]+`", + ":ref:`[^`]+`", + ":class:`[^`]+`", + ":pep:`[^`]+`", + ":data:`[^`]+`", + ":exc:`[^`]+`", + ":term:`[^`]+`", + ":meth:`[^`]+`", + ":envvar:`[^`]+`", + ":file:`[^`]+`", + ":attr:`[^`]+`", + ":const:`[^`]+`", + ":issue:`[^`]+`", + ":opcode:`[^`]+`", + ":option:`[^`]+`", + ":keyword:`[^`]+`", + ":RFC:`[^`]+`", + ":doc:`[^`]+`", + "``[^`]+``", + "`[^`]+`__", + "`[^`]+`_", + "\*\*.+\*\*", # bold text between ** + "\*.+\*", # italic text between * +] + +_exps = [re.compile(e) for e in _patterns] def protect_sphinx_directives(s: str) -> Tuple[dict, str]: """ @@ -25,44 +60,11 @@ def protect_sphinx_directives(s: str) -> Tuple[dict, str]: dictionary containing all the placeholder text as keys and the correct value. """ - exps = [ - ":c:func:`[^`]+`", - ":c:type:`[^`]+`", - ":c:macro:`[^`]+`", - ":c:member:`[^`]+`", - ":c:data:`[^`]+`", - ":py:data:`[^`]+`", - ":py:mod:`[^`]+`", - ":func:`[^`]+`", - ":mod:`[^`]+`", - ":ref:`[^`]+`", - ":class:`[^`]+`", - ":pep:`[^`]+`", - ":data:`[^`]+`", - ":exc:`[^`]+`", - ":term:`[^`]+`", - ":meth:`[^`]+`", - ":envvar:`[^`]+`", - ":file:`[^`]+`", - ":attr:`[^`]+`", - ":const:`[^`]+`", - ":issue:`[^`]+`", - ":opcode:`[^`]+`", - ":option:`[^`]+`", - ":keyword:`[^`]+`", - ":RFC:`[^`]+`", - ":doc:`[^`]+`", - "``[^`]+``", - "`[^`]+`__", - "`[^`]+`_", - "\*\*.+\*\*", # bold text between ** - "\*.+\*", # italic text between * - ] i = 0 d: Dict[str, str] = {} - for exp in exps: - matches = re.findall(exp, s) + for exp in _exps: + matches = exp.findall(s) if DEBUG: print(exp, matches) for match in matches: @@ -95,7 +97,7 @@ def undo_sphinx_directives_protection(placeholders: dict, translated_text: str) po = polib.pofile(filename) translator = GoogleTranslator(source="en", target="es") - for i, entry in enumerate(po): + for entry in po: # If the entry has already a translation, skip. if SKIP_TRANSLATED_ENTRIES and entry.msgstr: continue @@ -113,6 +115,8 @@ def undo_sphinx_directives_protection(placeholders: dict, translated_text: str) real_text = undo_sphinx_directives_protection(placeholders, translated_text) print("ES|", real_text) - # Replace the po file translated entry, and save + # Replace the po file translated entry entry.msgstr = real_text - po.save() + + # Save the file after all the entries are translated + po.save() From 927704264a801ac5bcaa7ebaad590b4f445dc7c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristi=C3=A1n=20Maureira-Fredes?= Date: Fri, 10 Dec 2021 08:51:42 +0100 Subject: [PATCH 3/3] Update scripts/translate.py --- scripts/translate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/translate.py b/scripts/translate.py index d752959e51..7b9b131374 100644 --- a/scripts/translate.py +++ b/scripts/translate.py @@ -39,6 +39,7 @@ ":issue:`[^`]+`", ":opcode:`[^`]+`", ":option:`[^`]+`", + ":program:`[^`]+`", ":keyword:`[^`]+`", ":RFC:`[^`]+`", ":doc:`[^`]+`",