diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e8e7dd1474..f3dfb25fc5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,34 +11,77 @@ jobs: name: Test runs-on: ubuntu-22.04 steps: + # Obtención del código - uses: actions/checkout@v4 + with: + submodules: 'true' + # Necesario para que tj-actions/changed-files se ejecute + # dentro de un tiempo adecuado + fetch-depth: 2 + + # Instalación de dependencias - name: Preparar Python v3.11 uses: actions/setup-python@v4 with: python-version: "3.11" cache: "pip" - - name: Sincronizar con CPython + - name: Configura dpkg/apt para ejecutarse de manera eficiente + uses: abbbi/github-actions-tune@v1 + - name: Deshabilita triggers de postgresql-common + run: sudo sed -i '/postgresql-common/d' /var/lib/dpkg/triggers/File + - name: Instalar dependencias de sistema run: | - git submodule update --init --depth=1 cpython - - name: Instalar dependencias + sudo apt-get install -y hunspell hunspell-es gettext language-pack-es locales-all + - name: Instalar dependencias de Python run: | - sudo apt-get update - sudo apt-get install -y hunspell hunspell-es gettext language-pack-es python -m pip install -r requirements.txt + - name: Listar paquetes y versiones + run: | pip list pospell --version powrap --version + + # Cálculo de los archivos .po a verificar. + # En el caso de un PR, sólo se chequean los .po que se están editando, + # mientras que en caseo de un push a las ramas 3.* queremos revisar + # todos los archivos + - name: Obtiene la lista de archivos .po con cambios (sólo en PRs) + if: github.event_name == 'pull_request' + id: changed-po-files + uses: tj-actions/changed-files@v40 + with: + files: | + **/*.po + - name: Calcula lista de archivos .po a revisar + id: po-files-to-check + env: + PO_FILES_TO_CHECK: ${{ steps.changed-po-files.conclusion == 'skipped' && '**/*.po' || steps.changed-po-files.outputs.all_changed_files }} + run: | + echo "po_files_to_check=$PO_FILES_TO_CHECK" >> $GITHUB_OUTPUT + echo "any_po_files_to_check=`test -n \"$PO_FILES_TO_CHECK\" && echo true || echo false`" >> $GITHUB_OUTPUT + - name: Muestra outputs de steps anteriores para debugueo + env: + CHANGED_PO_FILES: ${{ toJson(steps.changed-po-files) }} + PO_FILES_TO_CHECK: ${{ toJson(steps.po-files-to-check) }} + run: | + echo "steps.changed-po-files=$PO_FILES_TO_CHECK" + echo "steps.po-files-to-change.$CHANGED_PO_FILES" + + # Chequeos a realizar - name: TRANSLATORS run: | diff -Naur TRANSLATORS <(LANG=es python scripts/sort.py < TRANSLATORS) - name: Powrap - run: powrap --check --quiet **/*.po + if: steps.po-files-to-check.outputs.any_po_files_to_check == 'true' + run: powrap --check --quiet ${{ steps.po-files-to-check.outputs.po_files_to_check }} - name: Sphinx lint - run: | - sphinx-lint */*.po + if: steps.po-files-to-check.outputs.any_po_files_to_check == 'true' + run: sphinx-lint ${{ steps.po-files-to-check.outputs.po_files_to_check }} - name: Pospell - run: | - python scripts/check_spell.py + if: steps.po-files-to-check.outputs.any_po_files_to_check == 'true' + run: python scripts/check_spell.py ${{ steps.po-files-to-check.outputs.po_files_to_check }} + + # Construcción de la documentación - name: Construir documentación run: | # FIXME: Relative paths for includes in 'cpython' diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml new file mode 100644 index 0000000000..7be6faccd1 --- /dev/null +++ b/.github/workflows/pr-comment.yml @@ -0,0 +1,45 @@ +name: Agrega comentario a PR + +on: + pull_request_target: + +jobs: + pr-comment: + name: Entradas sin traducción + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.merge_commit_sha }} + persist-credentials: false + - name: Preparar Python v3.11 + uses: actions/setup-python@v4 + with: + python-version: "3.11" + cache: "pip" + - name: Instalar dependencias + run: | + python -m pip install -r requirements.txt + - name: Obtiene lista de archivos con cambios + id: changed-files + uses: tj-actions/changed-files@v39 + with: + files: | + **/*.po + - name: Calcular entradas faltantes + if: steps.changed-files.outputs.any_changed == 'true' + id: create-pr-comment + env: + CHANGED_PO_FILES: ${{ steps.changed-files.outputs.all_changed_files }} + run: | + { + echo 'comment<> "$GITHUB_OUTPUT" + - name: Agregar comentario con entradas faltantes + if: steps.changed-files.outputs.any_changed == 'true' + uses: thollander/actions-comment-pull-request@v2 + with: + message: ${{ steps.create-pr-comment.outputs.comment }} + comment_tag: missing-entries diff --git a/library/weakref.po b/library/weakref.po index 31e003654f..85279986a1 100644 --- a/library/weakref.po +++ b/library/weakref.po @@ -11,15 +11,16 @@ msgstr "" "Project-Id-Version: Python 3.8\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-10-12 19:43+0200\n" -"PO-Revision-Date: 2021-08-04 21:07+0200\n" -"Last-Translator: Cristián Maureira-Fredes \n" -"Language: es_PE\n" +"PO-Revision-Date: 2023-11-05 22:46+0100\n" +"Last-Translator: Andrea Alegre \n" "Language-Team: python-doc-es\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Generated-By: Babel 2.13.0\n" +"X-Generator: Poedit 3.4\n" #: ../Doc/library/weakref.rst:4 msgid ":mod:`weakref` --- Weak references" @@ -144,7 +145,6 @@ msgstr "" "`weakref` para el beneficio de usuarios avanzados." #: ../Doc/library/weakref.rst:68 -#, fuzzy msgid "" "Not all objects can be weakly referenced. Objects which support weak " "references include class instances, functions written in Python (but not in " @@ -152,12 +152,12 @@ msgid "" "object>`, :term:`generators `, type objects, sockets, arrays, " "deques, regular expression pattern objects, and code objects." msgstr "" -"No todos los objetos pueden ser débilmente referenciados; esos objetos que " -"pueden incluir instancias de clases, funciones escritas en Python (pero no " -"en C), métodos de instancia, conjuntos, frozensets, algunos :term:`objetos " -"de archivo `, :term:`generadores `, objetos de " -"tipos, sockets, arreglos, deques, objetos de patrones de expresiones " -"regulares, y objetos código." +"No todos los objetos pueden ser débilmente referenciados. Objetos que " +"soportan referencias débiles pueden incluir instancias de clases, funciones " +"escritas en Python (pero no en C), métodos de instancia, conjuntos, " +"frozensets, algunos :term:`objetos archivo `, :term:" +"`generadores `, objetos de tipo, sockets, arreglos, deques, " +"objetos de patrones de expresiones regulares, y objetos código." #: ../Doc/library/weakref.rst:74 msgid "Added support for thread.lock, threading.Lock, and code objects." @@ -234,15 +234,15 @@ msgstr "" "retrollamada registrada más antigua." #: ../Doc/library/weakref.rst:112 -#, fuzzy msgid "" "Exceptions raised by the callback will be noted on the standard error " "output, but cannot be propagated; they are handled in exactly the same way " "as exceptions raised from an object's :meth:`~object.__del__` method." msgstr "" -"Las excepciones lanzadas por la retrollamada serán anotadas en la salida de " -"error estándar, pero no pueden ser propagadas; son manejadas igual que las " -"excepciones lanzadas por el método :meth:`__del__` de un objeto." +"Las excepciones lanzadas por la retrollamada serán visibles en la salida de " +"error estándar pero no pueden ser propagadas; son manejadas de la misma " +"forma que las excepciones lanzadas por el método :meth:`~object.__del__` de " +"un objeto." #: ../Doc/library/weakref.rst:116 msgid "" @@ -291,7 +291,6 @@ msgid "Added the :attr:`__callback__` attribute." msgstr "Se añadió el atributo :attr:`__callback__`." #: ../Doc/library/weakref.rst:140 -#, fuzzy msgid "" "Return a proxy to *object* which uses a weak reference. This supports use " "of the proxy in most contexts instead of requiring the explicit " @@ -309,15 +308,18 @@ msgstr "" "retornado tendrá un tipo ``ProxyType`` o ``CallableProxyType``, dependiendo " "si *object* es invocable. Objetos Proxy no son :term:`hashable` " "independiente de la referencia; esto evita un número de problemas " -"relacionados a su naturaleza mutable fundamental, y previene su uso como " -"claves de diccionario. *callback* es el mismo como el parámetro del mismo " -"nombre de la función :func:`ref`." +"relacionados a su naturaleza mutable fundamental, y evita su uso como clave " +"de diccionario. *callback* corresponde al parámetro del mismo nombre de la " +"función :func:`ref`." #: ../Doc/library/weakref.rst:149 msgid "" "Accessing an attribute of the proxy object after the referent is garbage " "collected raises :exc:`ReferenceError`." msgstr "" +"Acceder al atributo de un objeto proxy después de que el objeto referenciado " +"haya sido recolectado por el recolector de basura lanza :exc:" +"`ReferenceError`." #: ../Doc/library/weakref.rst:152 msgid "" @@ -363,10 +365,16 @@ msgid "" "not replace the existing key. Due to this, when the reference to the " "original key is deleted, it also deletes the entry in the dictionary::" msgstr "" +"Nótese que cuando una clave cuyo valor es igual a una clave ya existente " +"(pero no tienen igual identidad) es insertado en el diccionario, el valor es " +"reemplazado pero no se reemplaza la clave existente. Debido a esto, cuando " +"la referencia a la clave original es eliminada, se elimina la entrada en el " +"diccionario::" #: ../Doc/library/weakref.rst:188 msgid "A workaround would be to remove the key prior to reassignment::" msgstr "" +"Una solución alternativa sería remover la clave antes de la reasignación::" #: ../Doc/library/weakref.rst:199 msgid "Added support for ``|`` and ``|=`` operators, specified in :pep:`584`." @@ -412,14 +420,12 @@ msgstr "" "pep:`584`." #: ../Doc/library/weakref.rst:223 -#, fuzzy msgid "" ":class:`WeakValueDictionary` objects have an additional method that has the " "same issues as the :meth:`WeakKeyDictionary.keyrefs` method." msgstr "" "Los objetos :class:`WeakValueDictionary` tienen un método adicional que " -"tiene los mismos problemas que el método :meth:`keyrefs` de los objetos :" -"class:`WeakyKeyDictionary`." +"posee los mismos problemas que el método :meth:`WeakKeyDictionary.keyrefs`." #: ../Doc/library/weakref.rst:229 msgid "Return an iterable of the weak references to the values." @@ -452,6 +458,8 @@ msgid "" "*callback* is the same as the parameter of the same name to the :func:`ref` " "function." msgstr "" +"*callback* corresponde al parámetro del mismo nombre de la función :func:" +"`ref`." #: ../Doc/library/weakref.rst:270 msgid "" @@ -480,7 +488,6 @@ msgstr "" "`None`." #: ../Doc/library/weakref.rst:280 -#, fuzzy msgid "" "Exceptions raised by finalizer callbacks during garbage collection will be " "shown on the standard error output, but cannot be propagated. They are " @@ -490,7 +497,7 @@ msgstr "" "Las excepciones lanzadas por retrollamadas de finalizadores durante la " "recolección de basura serán mostradas en la salida de error estándar, pero " "no pueden ser propagadas. Son gestionados de la misma forma que las " -"excepciones lanzadas del método :meth:`__del__` de un objeto o la " +"excepciones lanzadas por el método :meth:`~object.__del__` de un objeto o la " "retrollamada de una referencia débil." #: ../Doc/library/weakref.rst:286 @@ -510,8 +517,9 @@ msgid "" "replaced by :const:`None`." msgstr "" "Un finalizador nunca invocará su retrollamada durante la última parte del :" -"term:`interpreter shutdown ` cuando los módulos " -"globales están sujetos a ser reemplazados por :const:`None`." +"term:`apagado del intérprete ` cuando las variables " +"globales del módulo (globals) están sujetos a ser reemplazados por :const:" +"`None`." #: ../Doc/library/weakref.rst:296 msgid "" @@ -734,9 +742,8 @@ msgstr "" "Por ejemplo" #: ../Doc/library/weakref.rst:526 -#, fuzzy msgid "Comparing finalizers with :meth:`~object.__del__` methods" -msgstr "Comparando finalizadores con los métodos :meth:`__del__`" +msgstr "Comparando finalizadores con los métodos :meth:`~object.__del__`" #: ../Doc/library/weakref.rst:528 msgid "" @@ -753,45 +760,42 @@ msgid "the object is garbage collected," msgstr "el objeto es recolectado por el recolector de basura," #: ../Doc/library/weakref.rst:533 -#, fuzzy msgid "the object's :meth:`!remove` method is called, or" -msgstr "el método :meth:`remove` del objeto es llamado, o" +msgstr "el método :meth:`!remove` del objeto es llamado, o" #: ../Doc/library/weakref.rst:534 msgid "the program exits." msgstr "el programa sale." #: ../Doc/library/weakref.rst:536 -#, fuzzy msgid "" "We might try to implement the class using a :meth:`~object.__del__` method " "as follows::" msgstr "" -"Nosotros podemos intentar implementar la clase usando el método :meth:" -"`__del__` como sigue::" +"Podemos intentar implementar la clase usando un método :meth:`~object." +"__del__` como se muestra a continuación::" #: ../Doc/library/weakref.rst:555 -#, fuzzy msgid "" "Starting with Python 3.4, :meth:`~object.__del__` methods no longer prevent " "reference cycles from being garbage collected, and module globals are no " "longer forced to :const:`None` during :term:`interpreter shutdown`. So this " "code should work without any issues on CPython." msgstr "" -"Empezando con Python 3.4, Los métodos :meth:`__del__` ya no previenen ciclos " -"de referencia de ser recolectado como basura, y los módulos globales ya no " -"fuerzan :const:`None` durante :term:`interpreter shutdown`. Por lo que este " -"código debe trabajar sin ningún problema en CPython." +"A partir de Python 3.4, los métodos :meth:`~object.__del__` ya no impiden " +"que los ciclos de referencia sean recolectados como basura y las variables " +"globales del módulo (globals) ya no son forzados a :const:`None` durante el :" +"term:`apagado del intérprete `. Por lo tanto, este " +"código debería funcionar sin ningún problema en CPython." #: ../Doc/library/weakref.rst:560 -#, fuzzy msgid "" "However, handling of :meth:`~object.__del__` methods is notoriously " "implementation specific, since it depends on internal details of the " "interpreter's garbage collector implementation." msgstr "" -"Sin embargo, la gestión de métodos :meth:`__del__` es notoriamente " -"específico por la implementación, ya que depende de detalles internos de la " +"Sin embargo, la gestión de métodos :meth:`~object.__del__` es notoriamente " +"específica a la implementación, ya que depende de detalles internos de la " "implementación del recolector de basura del intérprete." #: ../Doc/library/weakref.rst:564 diff --git a/scripts/list_missing_entries.py b/scripts/list_missing_entries.py new file mode 100644 index 0000000000..4c51b37a63 --- /dev/null +++ b/scripts/list_missing_entries.py @@ -0,0 +1,55 @@ +import argparse +import dataclasses +import enum +import glob +import itertools +import os + +import polib +import tabulate + + +class MissingReason(enum.StrEnum): + FUZZY = "fuzzy" + UNTRANSLATED = "untranslated" + + @staticmethod + def from_poentry(poentry: polib.POEntry): + if poentry.fuzzy: + return MissingReason.FUZZY + assert not poentry.translated() + return MissingReason.UNTRANSLATED + +@dataclasses.dataclass +class MissingEntry: + reason: MissingReason + file: str + line: int + + @staticmethod + def from_poentry(pofilename: str, poentry: polib.POEntry) -> "MissingEntry": + return MissingEntry(MissingReason.from_poentry(poentry), pofilename, poentry.linenum) + + +def find_missing_entries(filename: str) -> list[MissingEntry]: + po = polib.pofile(filename) + fuzzy = po.fuzzy_entries() + untranslated = po.untranslated_entries() + return [MissingEntry.from_poentry(filename, entry) for entry in fuzzy + untranslated] + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("files", nargs="+") + parser.add_argument("-g", "--github-mode", help="Produce output as a GitHub comment", action='store_true') + opts = parser.parse_args() + missing_entries = list(itertools.chain.from_iterable(map(find_missing_entries, opts.files))) + if not missing_entries: + print(f"All entries translated, horray!{' :tada:' if opts.github_mode else ''}") + else: + missing_entries.sort(key = lambda entry: (entry.file, entry.line)) + print("Entries missing translation, details follow:\n") + print(tabulate.tabulate(missing_entries,headers=["Reason", "File", "Line"], tablefmt="github")) + + +if __name__ == "__main__": + main()