How to build a multi-language dashboard with Streamlit

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.

▶️ Live demo: http://keywordicebreaker.herokuapp.com/

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.

🕹️ 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:

After providing the API key:

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 a base.pot file with strings taken from the dashboard.py file in the locales folder.

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.

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 with Localazy

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 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 favorite features are the possibility of cooperative translation and automagic management of changes in translated files.

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

Select POT files from available file formats.

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

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

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

localazy upload

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

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

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.

Read: Automatic data reports in multiple languages with Python, Gettext and Localazy

✔️ 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.

Thank you for reading. I hope you enjoyed reading as much as I enjoyed writing this for you.

This article was originally published at Dev Genius Blog.

If you would like to share feedback or simply say hello, you can connect with me on LinkedIn.

💖 You might also like

If you enjoyed reading this, you’ll probably enjoy my other articles too:


This is a companion discussion topic for the original entry at https://localazy.com/blog/how-to-build-a-multi-language-dashboard-with-streamlit