Guía completa de i18n en Python.

Traducción de Inglés a Español de un interesantísimo artículo de Matt Layman, ingeniero de software experto en open source y Python, que nos muestra en esta guía cómo hacer la internacionalización (i18n) para una aplicación de Python.

I18internacionalizarPythontraduccion software
14 diciembre, 2021 Internacionalización de aplicaciones Python
14 diciembre, 2021 Internacionalización de aplicaciones Python

Traducción de Inglés a Español realizada por Jose, traductor profesional de Inglés con más de 20 años de experiencia traduciendo textos de todo tipo para la agencia de traducción Ibidem Group.

Texto original escrito por Matt Layman y publicado en su web mattlayman.com

***

Índice de contenidos:

  • Marcar las cadenas de texto a traducir
  • Generar la lista maestra
  • Obtener traducciones
  • Empaquetarlo todo
  • Probar las traducciones
  • Dudas y preguntas

Resumen

Para internacionalizar código, primero hay que preparar las cadenas de texto a traducir. Todas las cadenas de texto deben ir acompañadas de una llamada a una función especial. Esta función especial marca las cadenas como algo que necesita ser traducido. Una vez que todas las cadenas están marcadas, las herramientas de i18n pueden escanear el código para hacer una lista maestra de todo lo que debe traducirse. A partir de esta lista maestra, los traductores pueden generar un listado de cadenas traducidas para cada idioma. Las cadenas traducidas se añaden de nuevo al código Python y todo queda agrupado en un bonito producto final que incluye todas las traducciones. ¿Quieres probarlo?

Son muchas cosas, pero explicaré cada parte del proceso en detalle y paso a paso. A efectos de esta guía, todo mi código de ejemplo se hará referencia al paquete handroll. Si usas este código Python, sustituye handroll por el nombre de tu paquete Python de nivel superior.

Marcar las cadenas de texto a traducir

La función especial que mencioné en el resumen se parece a _(‘Hello World’) . Esta función proviene del módulo gettext. Python utiliza GNU gettext para hacer la traducción, así que veamos el código de handroll que crea la función _ en handroll/i18n.py.

import gettext
import os

localedir = os.path.join(os.path.abspath(os.path.dirname(file)), 'locale')
translate = gettext.translation('handroll', localedir, fallback=True)
_ = translate.gettext

Este pequeño trozo de código crea un objeto de traducción utilizando un directorio de configuración regional como fuente de las cadenas traducidas. Tu directorio locale no existe todavía, pero es donde tu aplicación buscará las traducciones en tiempo de ejecución. Desde el objeto de traducción, hice un alias _ para translate.gettext. Este guión bajo no es particularmente especial, sin embargo, es el nombre convencional de esta función que es utilizado por la comunidad de Python.

Espero que haya suficiente aquí para entender lo que sucederá en tiempo de ejecución. La idea importante es que ‘Hello World’ actúa como una clave. Cuando el código se ejecuta, esa «clave» se utilizará para buscar en los datos de la configuración regional una traducción que coincida. El valor de retorno de _ será la cadena traducida o el original si falta la traducción.

… y cadenas de formato

Una peculiaridad que detectarás rápidamente si utilizas formato para tus cadenas, es dónde cerrar los paréntesis _. Aquí hay un ejemplo para que quede claro.

_('Close the underscore function first. A {number}').format(number=42)

Generar la lista maestra

Con todas las cadenas marcadas con _(), es el momento de extraerlas en una lista maestra. Gettext se refiere a esta lista maestra como el archivo Portable Object Template (POT). Para generar el archivo POT, recurrí a una herramienta llamada Babel. Babel está diseñada para ayudar a los desarrolladores a manejar problemas de i18n. Es genial y tiene un montón de características interesantes, pero para esta guía, me centraré en su soporte de gettext.

Babel extiende un archivo setup.py con nuevos comandos. (El empaquetado de Python va más allá del alcance de esta guía, así que si setup.py te es completamente ajeno, consulta Distribuir módulos de Python para obtener más información) .

Para generar un archivo POT, ejecuta python setup.py extract_messages. Necesitarás escribir algo así como:

[extract_messages]
input_dirs = handroll
output_file = handroll/locale/handroll.pot

Obtener las traducciones

Ahora que has generado un archivo POT, estás listo para obtener versiones traducidas de tus cadenas. Recuerda que la T de POT es de template (plantilla). Los archivos traducidos se llaman archivos PO, y los traductores utilizan el archivo POT como punto de partida para generar su archivo PO. Hacer la traducción creando manualmente el archivo PO es posible, pero es tedioso. En este punto, recurrí a un servicio llamado Transifex.

Transifex se centra en facilitar la traducción. Es gratuito para proyectos de código abierto y realmente fácil de usar. Configuré un proyecto para handroll, configuré Transifex para «vigilar» el archivo POT en busca de cambios, y los traductores pueden traducir fácilmente todas las cadenas del proyecto. Transifex tiene una API que me permitió recuperar los archivos POT en el repositorio cuando lo necesité. El script es demasiado largo para ponerlo en este post, pero puedes verlo en GitHub.

Una cosa importante que hace el script es almacenar los ficheros PO en una estructura específica en el directorio locale. Gettext espera un orden como <language>/LC_MESSAGES/handroll.po.

Empaquetarlo todo

Una vez que los archivos de PO traducidos están en su lugar, es el momento de empaquetar las traducciones. El proceso de configuración incluye datos extra en MANIFEST.in. Añade una línea similar a la siguiente para asegurarse de que todos los datos de localización se ponen en el archivo del paquete.

recursive-include handroll/locale *

Hasta ahora he mentido un poco para aclarar la explicación. Gettext no utiliza archivos PO directamente para buscar traducciones. La verdad es que el fichero PO debe ser compilado en un fichero binario (MO) para mayor velocidad. De nuevo, podemos recurrir a Babel en busca de ayuda. Babel tiene un comando compile_catalog que puede compilar PO en MO. Puedes ejecutarlo con python setup.py compile_catalog.

Necesitarás escribir algo así como:

[compile_catalog]
domain = handroll
directory = handroll/locale

Debido a que las traducciones no funcionarán sin archivos MO, extendí setup.py para que el comando sdist siempre ejecute compile_catalog.

from setuptools.command.sdist import sdist

class Sdist(sdist):
"""Custom sdist command to ensure that mo files are always created."""
def run(self):
self.run_command('compile_catalog')
# sdist is an old style class so super cannot be used. sdist.run(self)

Si lo haces, no olvides añadir cmdclass={‘sdist’: Sdist} y setup_requires=[‘Babel’] en la llamada de configuración.

En este punto, ejecutando python setup.py sdist deberías crear un tarball con las traducciones para tu proyecto. ¡Ya casi has terminado!

Probar las traducciones

Probar las traducciones no es fácil. Si te esfuerzas al máximo, podrás comprobar que personas de todas las culturas puedan disfrutar de tu software. Pero las pruebas de traducción no son fáciles porque necesitas pruebas que ejecuten cada cadena de tu código. En el caso de Handroll, eso significaba que tenía que llegar a una cobertura de pruebas del 100% para conseguir esos casos realmente extraños.

La razón para probar es que las cadenas mal traducidas pueden destruir tu código. Si tienes una cadena de formato como_(‘Hello{name}!’).format(name=’Johnny’) y un traductor comete un error como ‘¡Hola {nombre}!’, ese código se rompería para los usuarios españoles.

 >>> '¡Hola {nombre}!'.format(name='Johnny')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'nombre'

Para probar estas cadenas, necesitas dos cosas: Los archivos MO y la variable de entorno LANGUAGE. Asumamos que usas el ejecutor de pruebas nose. Para probar su soporte en español, puedes ejecutar

$ LANGUAGE=es nosetests
…………………………….

----------------------------------------------------------------------
Ran 34 tests in 1.440s
OK

Cualquiera que sea el sistema de integración que utilices, ejecuta tus pruebas primero sobre los idiomas que conozcas, para cerciorarte de que que las traducciones no han roto nada del software. Handrolltox.ini proporciona un ejemplo para comparar. Tox es impresionante para este tipo de cosas.

¿Preguntas?

En esta guía, hice todo lo posible para documentar paso a paso el proceso de internacionalización de un proyecto de software. Espero que todos estos detalles te ayuden a traducir tu propio proyecto. Si falta algo o está roto, házmelo saber y estaré encantado de actualizar el post.

Rate this post

Articulos relacionados


Traducción de un interesantísimo artículo de Jordan Kalebu explicando cómo utilizar Python para realizar traducción automática de idiomas, usando 3 bibliotecas alternativas: Goslate, Googletrans y TextBlob. Una forma super sencilla y gratuita de traducir de forma automática todos...

Traducción de un texto original de Behic Guven, publicado el 8/6/2020 en su blog https://sonsuzdesign.blog, donde explica cómo crear un traductor de voz en Python, un proyecto sencillo para traducir de forma automática lo que dices sin necesidad de escribir nada.

Traducción de un artículo publicado originalmente en auth0.com y firmado por Bruno Krebs, un programador full stack apasionado por la arquitectura de contenidos y la escalabilidad, que nos explica aquí como desarrollar una API RESTful en Python, usando el framework Flask. Aprenderemos...