Problems with gettext and py.crust

Robin Dunn wrote:

David Brown wrote:

I'm working on an application that supports multiple languages. At the start of my main module, I use:

__builtin__.dict__["_"] = wx.GetTranslation

Once the locale is set, the appropriate translation is used whenever the _() function is called. That's all working nicely - wxGlade uses _() automatically which is very convenient.

I also have a py.crust frame shown as an aid to debugging and testing (I find it very useful). The code I use, between instantiating the instance of my wx.App class and running MainLoop(), is:

from wx import py
frame = py.crust.CrustFrame()
frame.SetSize((750, 525))
frame.Show(True)
frame.shell.interp.locals["app"] = app

(copied from PyWrap.py)

The PyCrust frame shows up, and I can use it as an interactive shell accessing the code and data in my program. The trouble comes when I try to do something from the main program again, such as clicking a button to open a new frame - I'm getting an exception every time the "_()" function is called. It seems that PyCrust is setting the global __builtin__._ to the last value returned by the PyCrust interpreter. So if I ask PyCrust "1 + 2", it gives me the result "3", and I when my main code (or a command entered in PyCrust) tries to open a frame, I get an exception along the lines of:

    self.SetTitle(_("Frame title"))
TypeError: 'int' object is not callable

If in PyCrust I write "wx.GetTranslation" (resulting in PyCrust printing the function name), I can continue running my code, as __builtin__._ is back to wx.GetTranslation.

I had a little look at the PyCrust, but I saw no immediate reason for this problem.

It's not a problem, it's the intended behavior. The same thing happens with the stock interactive interpreter, it's been setting _ to the value of the previous expression since before gnu gettext popularized _().

One way to workaround the feature is to not use __builtin__ but instead assign _ in each module. That way the local module's "_" attribute will be found before the builtin one.

The other way to workaround this is to override Python's default behavior of setting "_" in builtins in the interactive modes. This is normally done in the function referred to with sys.displayhook, so replacing that function with something else will take care of it. For example:

    def my_displayhook(value):
        if value is not None:
            print repr(value)

    sys.displayhook = my_displayhook

That does essentially the same thing as the default displayhook function (although it is C code, located in sysmodule.c) except for making the assignment to "_". The only downside of this is if a user is expecting _ to be set in the shell and tries to use it, but it's a lesser known feature so it probably won't be a problem.

I didn't see this problem with gettext, so I looked at gettext.py in the hope of finding some inspiration for a solution.

Instead of:
__builtin__.dict__["_"] = wx.GetTranslation

they are doing something along these lines:
import __builtin__
__builtin__.__dict__['_'] = wx.GetTranslation

It seems to work for me, i.e. I can inspect and do e.g. x = 1+1 and then keep going in the application without an exception. Can someone please explain why this is behaving differently.

I guess an other alternative would be to use "_t" or something similar instead of just "_".

Werner