DEV Community

michburkhalter
michburkhalter

Posted on • Edited on

Creating a python app with translations using PySimpleGUI and Babel

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.


Requirements

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

Translated PySimpleGui


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
Enter fullscreen mode Exit fullscreen mode

Translations are used with the built-in function gettext

## Setup translations
    localedir = 'locale'
    translate = gettext.translation('messages', localedir=localedir, languages=['de'])
    _ = translate.gettext
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

pybabel update -i locale/base.pot -d locale/
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

In my demo app 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

Enter fullscreen mode Exit fullscreen mode

Repo

The whole code I've just explained can be found in this repo: TranslatedPySimpleGUI

Top comments (0)