[PyKDE] Feedback Needed on Possible tr() Changes
Phil Thompson
phil at riverbankcomputing.co.uk
Sat May 24 12:38:01 BST 2003
I think people have hinted to me before about this, but I've only just
properly understood the problem. I suspect that it is impossible for PyQt to
implement QObject.tr() properly - although I may get lucky with SIP v4's use
of metaclasses. I've made a couple of attempts in the past, but it seems that
the current implementation may not the best design decision I've ever made.
Translation in Qt is based on the string to translate and a context. The
context is usually the name of the class from which tr() is called. Each C++
class that contains the Q_OBJECT macro has it's tr() method created
automatically by moc. Each generated tr() has the proper context hardcoded.
It is very difficult/impossible to emulate this behaviour in PyQt for Python
classes that extend C++ classes.
Note that there is a workaround for all this. Just use...
qApp.translate("Context","String")
...instead of calls to tr().
At the moment I see 3 options...
1. Current Unpredictable Option
The current implementation uses the name of the class of the instance as the
context. The problem is then that, if the class is further sub-classed, the
context changes. An example (ignoring calls to __init__)...
class A(QObject):
def hello(self):
return self.tr("Hello")
class B(A):
pass
class C(A):
pass
a = A().hello() # Context is "A"
b = B().hello() # Context is "B"
c = C().hello() # Context is "C"
...which requires 3 translations of the string. The problem is at its worse if
A is a class generated by pyuic.
2. Old Predictable Option
The original implementation had an automatically generated tr() for each
wrapped QObject sub-class. This meant that the context was correct for those,
but incorrect for any Python sub-class where it was the most recent C++ in
the hierarchy. For example...
class A(QObject):
def hello(self):
return self.tr("Hello")
class B(QObject):
def welcome(self):
return self.tr("Hello")
a = A().hello() # Context is "QObject"
b = B().welcome() # Context is "QObject"
...which (I think) has the consequence of creating one string for translation
when, perhaps, there should be two. Also, I'm not sure if pylupdate will
determine the correct context.
3. New Clumsy Option
Another option is to dump the problem onto the application developer. A
Q_OBJECT() method could be added to QObject that does the same job as the
Q_OBJECT macro and creates the tr() method with the correct context
hardcoded. For example...
class A(QObject):
def __init__(self):
QObject.__init__(self)
self.Q_OBJECT(A)
def hello(self):
return A.tr("Hello")
class B(A):
def __init__(self):
A.__init__(self)
self.Q_OBJECT(B)
def goodbye(self):
return B.tr("Goodbye")
b = B()
b.hello() # Context is "A"
b.goodbye() # Context is "B"
...but note that you must explicitly call the class specific tr() and not
self.tr() - which I feel means you might as well call qApp.translate() and
forget the added complexity of Q_OBJECT().
Note that whatever option is used, I will fix pyuic so that generated forms
get the context right.
Each option has its advantages and disadvantages - developers are currently
dealing with Option 1, Option 2 is probably the least confusing.
Comments and other suggestions welcome.
Phil
More information about the PyQt
mailing list