Hot-Swapping Languages Batman!

One of the requirements for this community greeter (login screen for community center machines) is the ability to switch languages. Normally to switch a language you would unload the greeter and relaunch it with a LANG environment variable and your new language would fall into place from gettext.

But I wanted more. First, what languages are installed on the computer? For this I used python-pybabel and gettext, these two tools working together allow me to both get all the installed languages, limit them to just those I have translations for and show the translated name for the language (see screenshot below).

I decided that what I wanted to do was to hot-swap the text in the widgets. Since I’m using gtkme extensions, I could achieve this by creating a TranslatableWindow class. It’s job is simply to go through the window container at load time and note down all the translatable strings from labels and tooltips:

class TranslatableWindow(gtkme.Window):
“””Provides functions for translating the window on the fly”””
def __init__(self, *args, **kwargs):
Window.__init__(self, *args, **kwargs)
self.labels = []
self.tips = []
self.store_translations(self.window)

def store_translations(self, widget):
“””Go through all widgets and store the translatable elements”””
for child in widget.get_children():
if isinstance(child, Gtk.Container):
self.store_translations(child)
if isinstance(child, Gtk.Label):
self.labels.append( (child, child.get_label()) )
if child.get_has_tooltip():
self.tips.append( (child, child.get_tooltip_text()) )

def translate_to(self, lang):
“””Loop through everything and translate on the fly”””
lang = TEXTS[lang]
for (child, text) in self.labels:
child.set_label(lang.gettext(text))
for (child, text) in self.tips:
child.set_tooltip_markup(lang.gettext(text))
logging.debug(“Performed translation to %s” % lang)

Once I had translatable windows, I could tell my application class to go through each window and translate it if it was translatable:

def translate_to(self, lang):
“””Translate all windows to target language”””
for window in self._loaded.values():
if isinstance(window, TranslatableWindow):
logging.debug(“I18n window %s to %s” % (window.name, lang))
window.translate_to(lang)

Obviously because I’m not modifying the environment, when I log you on I need to update your language settings. I actually only show major language varieties and only ask about minor languages at registration time or when you change your setting:

If you’re even more curious, you can check out the code here: Launchpad Code or look at the translations here.