I've created a Streamlit app for my recent article about keyword monitoring. It is used to search keywords in Google and is quite useful. As search results and SEO topics, in general, are location-dependent, I thought it would be useful to translate the app interface into several languages.

In theory, making another language version does not seem difficult. After all, it is enough to translate individual labels and descriptions into another language and by using a dictionary to map these.

In practice, this simple approach is time-consuming and error-prone. It is definitely better not to reinvent the wheel and to use established solutions. One of them is Gettext — a universal set of tools for producing multi-lingual messages.

From this article, you'll learn how to translate Streamlit application by using Gettext and Localazy.

🔔 Want more articles like this? Sign up here.

None

Project start

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

A code repository is attached to this article. The individual steps are separated into successive branches. The README.md file contains instructions for getting the dashboard up and running.

The result should be as follows:

None

After providing the API key:

None

Perhaps, we could translate messages into other languages and use if statements to change them according to the user's will, but this approach would be tedious and error-prone. Therefore we will first extract all strings from the code to work on them separately from the business logic.

Gettext

GNU gettext is a universal set of tools for producing multi-lingual messages. It provides a framework to support translated message strings. It supports many programming languages 😉, including Python. The gettext module comes shipped with Python standard library. The best thing about gettext is that it will help us seamlessly extract text messages into separate files.

We will prepare English, Polish and German language versions. First, we need to prepare the directory structure.

mkdir -p locales/{de,pl}/LC_MESSAGES

Then, we should extract the messages from the code.

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

To find the pygettext.py file, you can use the command: locate pygettext.py .

That will generate in the locales folder a base.pot file with strings taken from the dashboard.py file.

Unfortunately, generated base.pot does not contain any strings. To fix this, we need to modify dashboard.py by marking the messages for translation.

After generating the base.pot again, strings appear in it.

branch: step1

First translations

Now let's prepare the first translations. Copy and rename the base.pot into each language folder:

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

Let's modify the individual language files:

To use translation in our program, we need to generate the MO files. MO files are binary data files that are parsed by the Python gettext module and used in the program.

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

Now we can modify the dashboard.py file to display reports in different languages.

None

At the beginning of the file add:

From now on, the user can select a language from a dropdown. The interface will refresh every label that is processed by _() function:

Two labels in the app are. translated, it's time for the rest. The procedure is the same. Every time a string with a message appears in the source code, surround it with the function _('This is a string'). Once this is done, generate the POT file from the beginning, copy it to the locales of each language, translate it and generate the binary files.

branch: step2

Translation management

So in the next iteration of our solution, we will add functions to the dashboard that generate POT and MO files. You have all the changes here:

Localazy

Localazy is an awesome piece of software that makes the usually awful translation experience bearable and even almost enjoyable. It supports many frameworks and file formats and provides CLI tools for build automation. My favourite features are the possibility of cooperative translation and automagic management of changes in translated files.

None

So let's integrate our report with Localazy. First, create a Localazy account and install Localazy CLI. Then, create a new application.

Then, select POT files from available file formats.

None

You will see a template configuration file localazy.json. Copy it to the project main folder.

None

Remember to modify the locales folder path. Go to your app on Localazy and add some new languages.

None

Now you can generate the PO files again and load them into Localazy:

None
localazy upload

After a while, you will see a list of phrases to translate in each language of your application.

None

And the cherry on the top, a machine translation comes with each phrase.

None

Once all the translations have been accepted or created, you can download them into your application and re-generate binary MO files.

Unfortunately, for the changes to be loaded into the Streamlit app, the instance must be reset. If I can resolve this inconvenience, I will update the article.

Final effect:

branch: step3

f-strings problem

The project uses f-strings quite extensively. Unfortunately, we cannot use them as arguments of _() function, gettext will return an error. I describe how to solve this issue in the previous article:

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

Takeaways

As you can see, the duo of Gettext and Localazy is a flexible solution to localization problems. Each addresses different sources of workload and they complement each other wonderfully.

The best thing about the combination of Gettext and Localazy is that if we generate new POT files (and thus lose the previously translated parts), Localazy will take care of re-translating them, so as not to repeat the work unnecessarily.

None

If you enjoyed my article, please support the charitable foundation in which I am actively involved:

https://4fund.com/w7ctjx

None
None

References

GNU Gettext: https://www.gnu.org/software/gettext/

Localazy: https://localazy.com/

Streamlit: https://streamlit.io/