Showing the languages menuPart three of the Convert-O-Matic tutorial focusses on the user interface text and the translations. While there is a common method for localising applications called L10N, writing a simple language changer introduces a few different features of the Python language.

Part 1 builds the first iteration of the program and part 2 discusses improvements to the main program.

Once again, the complete code for this project will be at the end of the tutorial.

On with the tutorial code

As has been mentioned in the previous instalments, this is a Python 3 project. The shebang isn’t needed to use this module in the project but it is still useful as you’ll see later in the tutorial.

Importing the os module gives us access to operating system functionality such as file systems, files and processes. You should note that this tutorial is written using openSUSE Linux and has not been tested under Windows.

Considering that we are looking at handling the user interface text, there is a logical choice for a class name.

#!/usr/bin/env python3
import os

class InterfaceText(object):

The first method is a simple public accessor for the text value of user interface element. You could argue that this method is unnecessary given that it only returns a string with leading / trailing white space removed but it is always good to sure about what your code expects.

Another advantage of using an accessor is the ability to change where the data comes from without affecting the calling code, as long as the function definition isn’t changed. There is a case against having accessors for all of your member variables and if all you are doing is returning the value, it’s a good one.

def get(self, key):
    try:
        return self._text[key].strip()
    except:
        return False

If you’ve been paying attention, you may notice a potentially devastating issue with the available_languages method. Even when ignoring the hard-coded path, we can see that the function returns the names of all the files in the directory. The problem could occur when an improperly named file is placed in the directory. Given that the happy path work, we can ignore that for now and re-factor it later1. You will recall that the method can be changed without affecting the calling program as long as its signature remains unchanged.

def available_languages(self):
    try:
        return os.listdir("languages")
    except:
        return False

The load_for_language method simply reads and parses the language file passed as a parameter. In this iteration, you’ll notice the same flaws as in the available_languages method. Namely, a hard-coded directory and no validation of the input data.

These flaws will be addressed in a later iteration.

def load_for_language(self, language):
    try:
        with open("languages/" + language.lower(), "r") as lang_text:
            for line in lang_text:
                if len(line) > 1:
                    tmp = line.split("=")
                    self._text[tmp[0]] = tmp[1]
        return True
    except:
        return False

As constructors go, they don’t come much simpler than this. All it does is create the dictionary to hold the user interface text and labels.

def __init__(self):
    self._text = {}

The rest of the code in this module is just some simple tests. These are useful as we know they currently pass. When we fix the issues with the code, they should still pass, along with any new tests that are required.

if __name__ == '__main__':
    test = InterfaceText()

<pre><code>print("Test: Successfully load language")
if test.load_for_language('english'):
    print("Passed!")
else:
    print("Failed")

print("Test: Fail to load language")
if not test.load_for_language('klingon'):
    print("Passed!")
else:
    print("Failed")

print("Test load available languages")
if not test.available_languages():
    print("Failed")
else:
    print("Passed")

print("Test get method with real key")
if test.get('menu_file'):
    print("Passed")
else:
    print("Failed")

print("Test get method with bad key")
if not test.get('oh_no_it_dont_exist'):
    print("Passed")
else:
    print("Failed")

Finally, for this episode, I will show the contents of a language file. They are simply correctly formatted text files.

window_title=Onvert-O-Maticcay
calculate=Alculatecay
equivalent=isway equivalentway otay
convert=Onvertcay</p>

menu_file=Ilefay
menu_file_quit=Itquay
menu_languages=Anguageslay

feet=eetfay
metres=etresmay
inches=inchesway
feettometres=Eetfay otay etresmay
metrestofeet=Etresmay otay eetfay
metrestoinches=Etresmay otay inchesway

The next instalment will look at the conversions.

Convert-O-Matic source code

1 Hence the saying that if builders built buildings the way programmers build programs, the first woodpecker would mean the end of civilisation.

Leave a Reply

Your email address will not be published. Required fields are marked *