Creating a python app with translations using PySimpleGUI and Babel
Tags: python, pysimplegui, babel, i18n
Published: 2022-07-08 13:47:35

I've recently come across the need to create a Python3 app with a GUI and translated texts into several languages. I quickly found out that Babel and PySimpleGui are the tools of my choice but it took me some time to find out how to integrate the two. So here's how I did it. 

If you want to jump right to the complete Repo you can do that [TranslatedPySimpleGUI](https://github.com/michburkhalter/TranslatedPySimpleGUI).

---

## Requirements
I want to have an application where I could change the language dynamically in the menu without any further user action.

![Translated PySimpleGui](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6i2bbhaay9yjwm6hvu3g.gif)

---

## Python app with PySimpleGui
The key takeaway here is to replace the existing window with a new one if the language changes. By this the texts are updated to the new language as well:

```
def main_window(my_window=None):
    menu_def = [_('&About'), [_('Close::close')]], [_('&Language'), ['&de', 'en']],
    layout_mainwindow = [
        [
            [sg.Menu(menu_def, pad=(10, 10))],
            [sg.Text(_('Select direction: '), key='txt_direction')], [sg.Combo([_('Left'), _('Right')], key='cmb_direction', size=20)],
            [sg.Button(_('Close'), key='btn_close')],
        ]
    ]

    new_window = sg.Window("Demo TranslatedPySimpleGui", layout_mainwindow, finalize=True)

    if my_window is not None:
        my_window.close()
    return new_window
```
Translations are used with the built-in function `gettext`

```
## Setup translations
    localedir = 'locale'
    translate = gettext.translation('messages', localedir=localedir, languages=['de'])
    _ = translate.gettext
```
In order to change the translations dynamically we need to update the _ function whenever needed and then recreate the window:

```
        elif event == 'de':
            translate = gettext.translation('messages', localedir=localedir, languages=['de'])
            _ = translate.gettext
            print(_("Language changed to DE"))
            window = main_window(window)

        elif event == 'en':
            translate = gettext.translation('messages', localedir=localedir, languages=['en'])
            _ = translate.gettext
            print(_("Language changed to EN"))
            window = main_window(window)
```
---

## Translation
With Babel we can comfortably extract all text we would like to translate and process them into language specific files we can translate. These files are then compiled into binaries that are used by the application:

First we need to extract the text that shall be translated:
```
pybabel extract . -o locale/base.pot
```

As a second step we need, if the locale does not yet exist, create the desired locales. 'de' and 'en' in my case:

```
pybabel init -l de -i locale/base.pot -d locale
```

Third we need to update the locales with the texts generated in step 1:

```
pybabel update -i locale/base.pot -d locale/
```

Fourth we need to add the translated texts to files messages.po in the locales (here de and en) manually.

Fifth we need to compile the po files into mo binaries that are then used in the application:

```
pybabel compile -d locale

```
In my [demo app](https://github.com/michburkhalter/TranslatedPySimpleGUI/blob/develop/create_translations.bat) I've automated this in a bat file:

```
@ECHO OFF

ECHO Creating and Updating Translations
ECHO Initiating directory locale if necessary
if not exist locale\ (
    mkdir locale\
)

ECHO Initiating base translation file
venv\Scripts\pybabel extract . -o locale/base.pot

if not exist locale\de\ (
  echo Init Language DE
  venv\Scripts\pybabel init -l de -i locale/base.pot -d locale
)
if not exist locale\en\ (
  echo Init Language EN
  venv\Scripts\pybabel init -l en -i locale/base.pot -d locale
)

ECHO Create and compile translations
venv\Scripts\pybabel update -i locale/base.pot -d locale/
:: Between these 2 steps you have to add the translations manually to e.g. locale/de/messages.po
venv\Scripts\pybabel compile -d locale

```
---

## Repo
The whole code I've just explained can be found in this repo: [TranslatedPySimpleGUI](https://github.com/michburkhalter/TranslatedPySimpleGUI)