Wednesday, November 19, 2014

Translating a programming environment

tl;dr: volunteers always welcome! ;-)

Over the past few years, there has been an explosion in the number of web sites dedicated to teaching programming.  A few, like Codecademy, are making an effort to offer multilingual content.  While there seems to exist a prejudice shared by many programmers that "real programmers code in English and therefore everyone should learn to program using English", there is no doubt that for most non-English speakers, having to learn programming concepts and new English vocabulary at the same time can make the learning experience more challenging. So, for beginners, the best learning environment is one that is available in their native tongue.  However, to do so can require a massive amount of work and a team of people.  Freely available programming environments rely on the help of volunteers to provide translation.

Viewed from the outside, the work required to translate a programming environment like that of codecademy appears to be an all or nothing kind of effort, as everything (UI, lessons and feedback messages) is tightly integrated.  A given tutorial is broken up in a series of lessons, each of which can be translated independently.  For many of these lessons, the range of acceptable input by users is fairly limited, and so are the possible feedback messages.  Still, the amount of work required for providing a complete translation of a given tutorial is enormous.

When I started the work required to create Reeborg's World, I knew that I would be largely on my own.  Still, I wanted to make sure that the final "product" would be available in both English and French, and could be adapted relatively easily for other languages.  The approach I have used for Reeborg's World is different than that of codecademy, and has been greatly influenced by my past experiences with RUR-PLE and Crunchy, as well as during the development of Reeborg's World itself.

1. I have completed separated the tutorials from the programming environment itself.  Thus, one can find a (slightly outdated) tutorial for complete beginners in English as well as  a French version of the same tutorial, separately from the programming environment itself.  This separation of the tutorial and the programming environment makes it easily possible for others to create their own tutorial (in whatever language) like this beautiful tutorial site created by a teacher in California that makes use of Reeborg's World, but calls the robot Karel as a hat tip to the original one created by Richard Pattis.

2. The programming environment is a single web page, with a mimimum amount of visible text. Currently, there are two versions: one in English, and one in French.

3. Programming languages available are standard ones (currently Python, Javascript and CoffeeScript). Whereas I have seen translated "real" programming language (like ChinesePython or Perunis, both of which are Python with keywords and builtins translated in other languages) or translated mini-programming language, like that used by Guido van Robot, I do not believe that the slight additional work required to memorize the meaning of keywords and builtins is a significant hurdle, especially when taking into account the possibilities of using the programming language outside of the somewhat artificial learning environment.

4. Possible feedback given to the user are currently available in both French and English.  The approach I have used is to create a simple Javascript function

RUR.translate = function (s) {
    if (RUR.translation[s] !== undefined) {
        return RUR.translation[s];
    } else {
        return s;
    }
};

Here, RUR is a namespace that contains the vast majority of functions and other objects hidden from the end user.   A given html page (English or French) will load the corresponding javascript file containing some translations, such as

RUR.translation["Python Code"] = "Code Python";

The total number of such strings that need to be translated is currently slightly less than 100.

5. Functions (and a class) specific to Reeborg's World are available in both English and French, as well as in Spanish (for the Python version).  By default, the English functions are loaded on the English page and the French ones are loaded on the French page.  An example of a definition of a Python command in English could be:

move = RUR._move_

class UsedRobot(object):
    def move(self):
        RUR.control.move(self.body)

whereas the French equivalent would be

avance = RUR._move_

class RobotUsage(object):
    def avance(self):
        RUR.control.move(self.body)

with similar definitions done for Javascript.

6. When using Python, one can use commands in any human language by using a simple import statement.  For example, one can use the French version of the commands on the English page as follows:

from reeborg_fr import *
avance()     #   equivalent to move()
move()       #   still works by default

If anyone is interested in contributing, this would likely be the most important part (and relatively easy, as shown above) to translate in other languages.

7. As part of the programming environment, a help button can be clicked so that a window shows the available commands (e.g. move, turn_left, etc.).  When importing a set of commands using Python in a given human language as above, there is also a provision to automatically update the help available on that page based on the content of the command file. (While the basic commands are available in Spanish, the corresponding help content has not been translated yet.)

8. In order to teach the concept of using a library, two editor tabs are available on the page of the programming environment, one of which represents the library.  In the tutorial I wrote, I encourage beginners to put the functions that they define and reuse in many programs, such as turn_right or turn_around, in their library so that they don't have to redefine them every single time.  The idea of having a user library is one that was requested in the past by teachers using RUR-PLE.  The idea of using a second editor on the second page is one that I first saw on this html canvas tutorial by Bill Mill.  When programming in Javascript (or CoffeeScript), for which the concept of a library is not native like it is in Python, if the user calls the function

import_lib();

the content of the library will be evaluated at that point.

For Python, I ensure that the traditional way works.   Brython (which I use as the Python in the browser implementation) can import Python files found on the server.  For the English version, the library is called my_lib.py and contains the following single line:

from reeborg_en import *

(The french version is called biblio.py and contains a similar statement.)

When a user runs their Python program, the following code is executed

def translate_python(src):
    import my_lib
    #setup code to save the current state of my_lib

    exec(library.getValue(), my_lib.__dict__)
    exec("from reeborg_en import *\n" + src)

    # cleanup to start from a clean slate next time

The content of the editor (user program) is passed as the string src.  
library.getValue()returns the content of the user library as a string.  Even if my_lib only imported once by Brython, its content effectively gets updated each time a program is run by a user.

9. One thing which I did not translate, but that we had done for Crunchy (!), are the Python traceback statements.  However, they are typically simplified from the usual full tracebacks provided.

In summary, to provide a complete translation of Reeborg's World itself in a different language, the following are needed:
1. a translated single page html file;
2. a javascript file containing approximately 100 strings used for messages;
3. a Python file containing the defintion of the robot functions as well as a corresponding "help" section;
4. a javascript file containing the definition of the robot functions. If the Python file containing translation is available, it is trivial for me to create this corresponding javascript file.

Saturday, November 08, 2014

Tracking users

A while ago, after reading about how much excessive tracking of users is done on the web, I decided that I was not going to track users of Reeborg's World.  I had initially tracked users with piwik, found that some minor spikes occurred when I posted about it (I even found out that one person had copied the entire site) but the information that I got did not seem to be worth getting.

So, I stopped tracking, and mentioned on the site and elsewhere that I was not tracking users ... and have no idea how much it is used (it's free to use and does not require any login), and if the various changes I made to the site which are intended to be improvements are seen as such by the silent users.

A few people have contacted me with suggestions for improvements and with mentions of how useful the tutorial and the programming environment were in helping to learn Python.  I am very grateful to those that contacted me.  Still, I am curious about how much the site is used.

So, I am going to start tracking users and thought I should mention it in the interest of openness.  After reading about various options, I am thinking of using Clicky instead of Piwik ... but I am curious to find out if anyone has better suggestions.

Thursday, November 06, 2014

Line highlighting working - development version

Reeborg's World is better than RUR-PLE ever was in all aspects ... except for one thing: line of codes being executed were simultaneously highlighted in RUR-PLE something which, up until now, had not been possible to do on the web version as it relied upon some features specific to CPython.

Well... I may have just found an alternative method. :-)




Tuesday, November 04, 2014

Partial fun

My daughter suggested to me that

To sort in descending order in python, you should be able to do
detros() instead of sorted( ... reverse = True)

This is what I suggested to her:

>>> from functools import partial
>>> detros = partial(sorted, reverse=True)
>>> detros([1, 3, 4, 2])
[4, 3, 2, 1]

I love Python. :-)

Sunday, November 02, 2014

Tasks with random initial values

Quick Reeborg update:

Reeborg's World now allows for tasks with randomly selected initial values within a certain range.  For example, this world (and solution) is such that Reeborg can start at any of three initial positions, in any of the four basic orientations.   Furthermore, there is an initially unspecified number of tokens at grid position (5, 4).    This type of random selection opens the possibility to create more interesting programming challenges.

Friday, June 20, 2014

Reeborg in real life

One of the first users of rur-ple is a high school teacher in New Jersey who gave me some great feedback while I was developing the program.  He reall seems to have found a way to make students enjoy learning.  A while ago, he sent me this picture of one of his students who decided to make a Reeborg costume for Hallowe'en.


And, today, for the last day of school, another student gave him this as a token of appreciation:

Knowing that the little robot, whose image I drew pixel by pixel with my limited art skills, seem to have been appreciated by students as they learned programming using Python makes my day! :-)

Wednesday, May 21, 2014

Reeborg programming challenges - Challenge #1

Can you have Reeborg do multiplication without using numerical variables?

Reeborg must show that it can multiply two numbers by taking a number N tokens located at x=1 and  y=Y, and leave a single token at row y=1 and x = N*Y.  For example, here's a starting position (image taken from RUR-PLE, so that it looks a bit different from the web version)
the final position must be
where a single token must be deposited.

So, without using numerical variables, and using only a single instruction per line (so no use of semi-colon, or having a colon followed by a statement), how short can a solution to this problem be?  Here's an example of a solution that is NOT allowed under the above rules:
think(0)
select_challenge("mul5x1")
y = 1      # numerical variables not allowed
tokens = 0;turn_left()  # use of ; is not allowed
def turn_around():
    turn_left()
    turn_left()
while not token_here():  
    move()
    y += 1  # not allowed
while token_here():
    take()
    tokens += 1  # not allowed
turn_around()

while front_is_clear():  move()  # not allowed, statement after colon

turn_left()
repeat(move, y*tokens-1)  # not allowed, multiplication
put()

The solution must work for 5 different challenges (mul5x1, mul1x5, mul5x5, mul4x3, mul3x2) - or any other such challenges for which I could create a world. Excluding the line with think(0), which makes Reeborg move as quickly as possible, and the line select_challenge(...), can you write a solution shorter than 29 lines?  Solutions can be attempted at Reeborg's World. You may want to click on the help button to see a brief summary of all known instructions.