We are using kivy for the GUI of the knit editor. It can be used to create Android, Windows, Linux, Mac and IOS apps. You can divide UI-design and code by using the kv language. In this blog post, I want to share some revelations I had when using kivy. This includes showing you how you can update translations automatically when the configuration changes and subtracting values. This awaits you:
Automatic Update of Translated Text in the Kivy UI
In projects like Django, there is the “_” function that allows translations of text. The implementation usually look calls a “gettext” function of some sort, which takes a string and returns its translation as a string. What we have in the kniteditor, is an observable translation, with the same interface:
"""Translate a string using the current language.
:param str string: the string to translate
:return: the translated string
_ = ObservableTranslation(_)
The difference is that the observable translation can be used like the “_” function but has additional methods that allow the UI to register and be notified when the language changes. When the language is changed, the global “gettext” is replaced by the “gettext” in the new language and, inthe last line, the observers are notified about the change.
"""Change the language to a language from the translations folder.
:param str new_language: the language code of the new language
global _locales, _current_language
_locales = gettext.translation(DOMAIN, _locale_dir,
_current_language = new_language
To see what this does, we can look at the whole implementation. I would like to give the whole picture, first, as it clarifies the context and discuss them below.
"""Observable Translations for kivy that change when the language changes.
The functionality of this module is highly inspired by
from kivy.lang import Observable
"""This class allows kivy translations to be updated with the language."""
def __init__(self, translate):
"""Create a new translation object with a translation function.
:param translate: a callable that translates the text.
Even when the language is changed,
it returns the text for the current language.
self._translate = translate
self._observers = 
def __call__(self, text):
"""Call this object to translate text.
:param str text: the text to translate
:return: the text translated to the current language
def fbind(self, name, func, args, **kwargs):
"""Add an observer. This is used by kivy."""
self._observers.append((name, func, args, kwargs))
def funbind(self, name, func, args, **kwargs):
"""Remove an observer. This is used by kivy."""
key = (name, func, args, kwargs)
if key in self._observers:
"""Update all the kv rules attached to this text."""
for name, func, args, kwargs in self._observers:
func(args, None, None)
__all__ = ["ObservableTranslation"]
The constructor takes the “_” function. When the object is called like a function, the “__call__” method is invoked, translating like “_”. If we only have these two methods, the observable translation works just like the “_” function.
“fbind” and “funbind” are the methods that are called when a translation is used in the kv language. They add and remove the observes from the list of observes.
“language_changed” walks through the observers and tells everyone of then to update. With this, you already have a updated translations when “change_language_to” is called.
Here is how you create a button in the kv language that uses the translation function:
#:import _ kniteditor.localization._
Updating the Translations From the Configuration
Ultimately, you want the translations to be changed, when the built-in kivy configuration changed. In the video, seconds, you have seen what it can look like.
LANGUAGE_SECTION = "language"
LANGUAGE_CODE = "current"
LANGUAGES = ["English", "Deutsch"]
"""The editor window."""
def build_config(self, config):
"""Build the configuration.
:param kivy.config.ConfigParser config: the configuration parser
.. seealso:: `Application Configuration
"""Build the application."""
"""Set the current language from the configuration.
config_language = self.config.get(LANGUAGE_SECTION, LANGUAGE_CODE)
def build_settings(self, settings):
"""Create the applications settings dialog.
:param kivy.uix.settings.Settings settings: the settings
for this app
.. seealso:: `Create a settings panel
"""The settings specification as JSON string.
:return: a JSON string
settings = [
"desc": _("Choose your language"),
def on_config_change(self, config, section, key, value):
"""The configuration was changed.
:param kivy.config.ConfigParser config: the configuration that was
:param str section: the section that was changed
:param str key: the key in the section that was changed
:param value: the value this key was changed to
if section == LANGUAGE_SECTION and key == LANGUAGE_CODE:
“build_config” is calls when the application starts to fill the empty configuration with useful values.
“build” is called when the application creates its window, at this point in time, the translation is updated.
“build_settings” is called when the F1 key is pressed or the Android settings menu is activated. “settings_sepcification” is a JSON string used by kivy to build the settings.
“on_config_change” is called, when the configuration is updated. Through e.g. the settings dialog.
With these components together, you can have a updated language every time the language is changed. The video shows an application which uses this code.
Bonus Material: Kivy’s Update is Mighty
In the kv language, variables are accessed via identifiers and not via global variables. As such, the kv language can register every time a Property (like “StringProperty” and “ObjectProperty”) is used. It an register when they change. Thus you can automatically update formulas whenever a value changes.
in this example you can see how a value is subtracted but still, an automatic update is possible:
value: 100 - other_slider.value
Thanks to Mathieu Virbel for the kivy-gettext-example. It was the basis of this work and an inspiration.