Cómo traducir un cuadro de mando en Streamlit

Traducción de Inglés a Español de un interesantísimo artículo de Rafał Rybnik, programador polaco que nos explica cómo traducir con Gettext y Localazyel el cuadro de mando de su aplicación de gestion de keywords desarrollada en Streamlit. Análisis detallado de la gestion de carpetas de traducción, generación de traducciones, archivos .pot, .mo y .po, etc

cuadro de mandoMULTILINGUEstreamlittraduccion software
26 diciembre, 2021 Cómo traducir una aplicacion Streamlit
26 diciembre, 2021 Cómo traducir una aplicacion Streamlit

Traducción de Chema, experto en traducción de software de Inglés a Español y responsable del dpt. de Traducción de Ibidem Group.

Texto original escrito por Rafał Rybnik

***

Demo: http://keywordicebreaker.herokuapp.com/

En teoría, hacer una traducción de software, no parece difícil. Al fin y al cabo, basta con traducir las etiquetas y descripciones de un idioma a otro y utilizar un diccionario para mapearlas.

En la práctica, este sencillo enfoque lleva mucho tiempo y es propenso a errores. Definitivamente, es mejor no reinventar la rueda y utilizar soluciones establecidas. Una de ellas es Gettext, un conjunto universal de herramientas para generar mensajes traducidos en diversos idiomas.

En este artículo, aprenderás a traducir la aplicación de software Streamlit utilizando Gettext y Localazy.

Interfaz de usuario gráfica, Aplicación, Teams  Descripción generada automáticamente

Inicio del proyecto

https://github.com/fischerbach/streamlit-gettext

Incluimos en este artículo un repositorio de código. Los pasos están separados individualmente. El archivo README.md contiene instrucciones detalladas.

El resultado debería ser el siguiente:

Interfaz de usuario gráfica, Aplicación  Descripción generada automáticamente

Después de proporcionar la clave de la API:

Interfaz de usuario gráfica, Aplicación, Teams  Descripción generada automáticamente

Podríamos traducir los mensajes a otros idiomas y utilizar sentencias if para cambiarlos según el idioma escogido por el usuario, pero este enfoque sería tedioso y propenso a errores. Mejor vamos a extraer todas las cadenas de código para trabajar con ellas por separado, sin tocar toda la lógica del software.

Gettext

GNUgettext es un conjunto universal de herramientas para generar mensajes multilingües (es decir traducciones). Proporciona un marco para soportar cadenas de mensajes traducidas. Soporta muchos lenguajes de programación 😉, incluyendo Python. El módulo gettext viene incluido en la biblioteca estándar de Python. Lo mejor de gettext es que nos ayudará a extraer sin problemas los mensajes de texto en archivos separados.

Vamos a intentar generar 3 versiones del software, la original en Inglés y su traducción a Alemán y Polaco. En primer lugar, tenemos que preparar la estructura de directorios.

.
├── README.md
├── dashboard.py
├── locales
│ ├── base.pot
│ ├── de
│ │ └── LC_MESSAGES
│ │ └── base.po
│ └── pl
│ └── LC_MESSAGES
│ └── base.po
└── requirements.txt
mkdir -p locales/{de,pl}/LC_MESSAGES 

A continuación, debemos extraer los mensajes del código.

/Library/Frameworks/Python.framework/Versions/3.8/share/doc/python3.8/examples/Tools/i18n/pygettext.py -d base -o locales/base.pot dashboard.py

Para encontrar el archivo pygettext.py, puedes utilizar el comando: locate pygettext.py .

Eso generará en la carpeta de locales un archivo base.pot con cadenas extraidas del archivo dashboard.py.

Desafortunadamente, el base.pot generado no contiene ninguna cadena de texto a traducir. Para solucionarlo, tenemos que modificar dashboard.py marcando los mensajes para su traducción.

import gettext
_ = gettext.gettext
Each label string replace surround by _() function:
st.markdown(_('## This app uses Zenserp API'))

Después de generar de nuevo el base.pot, ahora ya sí aparecen las cadenas de texto a traducir.

: dashboard.py:9
msgid "Enter API key"
msgstr ""
: dashboard.py:35
msgid "## This app uses Zenserp API"
msgstr ""
branch: step1 

Primeras traducciones

Ahora vamos a preparar las primeras traducciones. Para ello lo primero es copiar y renombrar el base.pot en cada carpeta de idioma:

cp locales/base.pot locales/de/LC_MESSAGES/base.po
cp locales/base.pot locales/pl/LC_MESSAGES/base.po

Modificamos los archivos de los idiomas:

/locales/de/LC_MESSAGES/base.po
: dashboard.py:9
msgid "Enter API key"
msgstr "API-Schlüssel eingeben"
: dashboard.py:35
msgid "## This app uses Zenserp API"
msgstr "Diese App verwendet die Zenserp API"
/locales/pl/LC_MESSAGES/base.po
: dashboard.py:9
msgid "Enter API key"
msgstr "Podaj klucz API"
: dashboard.py:35
msgid "## This app uses Zenserp API"
msgstr "## Ta aplikacja używa Zenserp API"

Para utilizar la traducción en nuestro software, necesitamos generar los archivos MO. Los archivos MO son archivos de datos binarios que sanalizará el módulo gettext de Python.

msgfmt -o locales/de/LC_MESSAGES/base.mo locales/de/LC_MESSAGES/base
msgfmt -o locales/pl/LC_MESSAGES/base.mo locales/pl/LC_MESSAGES/base

Ahora podemos modificar el archivo dashboard.py para mostrar los informes en diferentes idiomas.

Al principio del archivo debes añadir:

language = st.sidebar.selectbox('', ['en', 'pl', 'de'])
try:
localizator = gettext.translation('base', localedir='locales', languages=[language])
localizator.install()
_ = localizator.gettext
except:
pass

A partir de ahora, el usuario puede seleccionar un idioma en el desplegable. La interfaz se refrescará cada vez que se procese la etiqueta con la función _():

Dos etiquetas de la app están ya traducidas, es el momento del resto. El procedimiento es el mismo. Cada vez que aparezca una cadena con un mensaje en el código fuente, rodéala con la función _(‘This is a string’) . Una vez hecho esto, genera el archivo POT desde el principio, cópialo en las localizaciones de cada idioma, tradúcelo y genera los archivos binarios.

branch: step2 

Gestión de las traducciones

En la siguiente iteración de nuestra solución, añadiremos funciones al tablero que generen archivos POT y MO. Tienes todos los cambios aquí:

from os import system, path
(…)
POT = st.sidebar.button(_('POT generate'))
MO = st.sidebar.button('MO generate')
if POT:
system(f'cd {path.dirname(path.realpath(file))} & /Library/Frameworks/Python.framework/Versions/3.8/share/doc/python3.8/examples/Tools/i18n/pygettext.py -d base -o locales/base.pot dashboard.py')
system(f'cd {path.dirname(path.realpath(file))} && cp locales/base.pot locales/de/LC_MESSAGES/base.po && cp locales/base.pot locales/pl/LC_MESSAGES/base.po')
if MO:
system(f'cd {path.dirname(path.realpath(file))} && msgfmt -o locales/de/LC_MESSAGES/base.mo locales/de/LC_MESSAGES/base & msgfmt -o locales/pl/LC_MESSAGES/base.mo locales/pl/LC_MESSAGES/base')

Localazy

Localazy es un software impresionante que hace que la experiencia de traducción, normalmente horrible, sea soportable e incluso casi agradable. Soporta muchos frameworks y formatos de archivo y proporciona herramientas CLI para la automatización del proceso. Mis funciones favoritas son la posibilidad de traducción cooperativa y la gestión automática de los cambios en los archivos traducidos.

Interfaz de usuario gráfica, Aplicación  Descripción generada automáticamente

Vamos a integrar nuestro informe con Localazy. Primero, crea una cuenta de Localazy e instala Localazy CLI. Luego, crea una nueva aplicación.

A continuación, selecciona «archivos POT» dentro del listado de formatos disponibles.

Interfaz de usuario gráfica, Aplicación  Descripción generada automáticamente

Verás un archivo de configuración de plantilla localazy.json. Cópialo en la carpeta principal del proyecto.

{
"writeKey": "WRITE_KEY",
"readKey": "READ_KEY",

"upload": {
"type": "pot",
"files": "locales/base.pot"
},

"download": {
"files": "locales/${lang}/LC_MESSAGES/base.po"
}

}

Recuerda modificar la ruta de la carpeta de locales. Ve a tu aplicación en Localazy y añade algunos idiomas nuevos.

Ahora puedes volver a generar los archivos PO y cargarlos en Localazy:

localazy upload 

Después de un rato, verás una lista de frases para traducir en cada idioma de tu aplicación.

Interfaz de usuario gráfica, Aplicación  Descripción generada automáticamente

Y la guinda del pastel, para cada frase verás al lado una traducción automática!

Interfaz de usuario gráfica, Aplicación  Descripción generada automáticamente

Una vez aceptadas o modificadas todas las traducciones, puedes descargarlas en tu aplicación y volver a generar archivos binarios MO.

Lamentablemente, para que los cambios se carguen en la aplicación Streamlit, es necesario reiniciar la instancia. Si puedo resolver este inconveniente, actualizaré el artículo.

Resultado final:

 branch: step3  

Problema con las cadenas f

El proyecto utiliza bastante las cadenas f. Desafortunadamente, no podemos usarlas como argumentos de la función _(), gettext devolverá un error. Describo cómo resolver este problema en este artículo :

https://netlabe.com/how-to-create-automatic-data-report-in-multiple-languages-2a53b6417d42

Conclusiones

Como habrás podido comprobar, el dúo de Gettext y Localazy es una solución flexible para la traduccion y localización de una aplicación o software. Cada uno aborda diferentes fuentes de carga de trabajo y se complementan maravillosamente.

Lo mejor de la combinación de Gettext y Localazy es que si generamos nuevos archivos POT (y por tanto perdemos las partes previamente traducidas), Localazy se encargará de volver a traducirlas, para no repetir el trabajo innecesariamente.

Rate this post

Articulos relacionados


Traducción a español de un artículo en Inglés escrito por Supriya M., desarrolladora web de la India, que nos explica cómo crear una App web de traducción usando la API Fetch y la función de JavaScript getTranslatedURL

Traducción de un artículo de Jen Schaefer, donde nos explica lo complicado que puede llegar a ser traducir a otros idiomas un texto que esta escrito en perfecto Inglés y que ha sido pensado y calculado hasta el último milímetro por un experto en UX.

Traducción de un interesante artículo de Kristaps Grinbergs donde nos explica cómo podemos traducir nuestras aplicaciones SwiftUI usando las funcionalidades que vienen por defecto: traducir no sólo texto estático sino también texto dinámico (números, fechas, moneda, medidas...),...