FreeCAD / DevelopersHandbook

A handbook about FreeCAD development
45 stars 30 forks source link

Alternative translation method in Python #81

Open ostr00000 opened 11 months ago

ostr00000 commented 11 months ago
  1. In this markdown: https://github.com/FreeCAD/DevelopersHandbook/blob/245f3d339187d67716fb6d77c2d4002775ae0549/technical/translation.md?plain=1#L109-L115 I only see Qt translation by function, but it is possible to translate using tr method from QObject. In my opinion, this is a much better option (especially when object-oriented style is used).
    Actually lupdate do not care about parent class, so it should be even possible to implement a custom method:

    class MyGreatClassAlsoExpandingAnotherClassSoItHasALongName:
        def tr(self, text: str) -> str:
            return translate('MyGreatClassAlsoExpandingAnotherClassSoItHasALongName', text)
        def runTr(self):
            print(self.tr("My transalted text"))

    Should this translation pattern be encouraged? Or there are reasons why this is not mentioned here? (There are problems with subclassing, but I know a workaround for this.)

  2. This is a very frustrating error: https://github.com/FreeCAD/DevelopersHandbook/blob/245f3d339187d67716fb6d77c2d4002775ae0549/technical/translation.md?plain=1#L127 It is so frustrating that I created a flake8 plugin to detect these errors. Can I advertise this flake8 plugin/pre-commit check here?

hasecilu commented 10 hours ago

I have added translation support to some external WB, previously using the tools from Qt5 there were problems: using tr() would not be picked by lupdate.

I have just made a test with tr() and even though is picked by the new lupdate from Qt6 there is no translation.

I think continuing to use the functions from FreeCAD.Qt is ok.

 translate = FreeCAD.Qt.translate 
 QT_TRANSLATE_NOOP = FreeCAD.Qt.QT_TRANSLATE_NOOP
ostr00000 commented 7 hours ago

tools from Qt5 there were problems

Strange :thinking: - I have never had problems with generating translation in Qt5.

As I remember, the context is extracted only when tr method is accessed from an object named self. Lupdate source code I agree that there is inconsistent behavior in Qt in python: QObject defines tras a static, but in python it does not work outside instance (in my opinion using classmethod should be allowed)

Also, I found another limitation of this approach - a class inheritance. When you define string on Base, you cannot use it on Inherited class:

class Base(QObject):
    def m1(self):
        return self.tr("tr text")

class Inherited(Base):
    pass

inh = Inherited()
inh.m1()  # returns untranslated text
# this is because, the context for `tr` method is now `Inherited` and we created transaltion with context named `Base`

Both limitations may be fixed using some python inspections (I have code that was tested with all possible combinations). So maybe indeed, it is better to use current, a more verbose approach without need to know all edge cases of tr method.

hasecilu commented 7 hours ago

I made this change but not translations was done, the string is properly attached to its class as context though, do you a a simple working example? What is the main advantage of using tr(), the smaller function name? I just let the formatter do its thing and most of times I got multi-line commands.

In terms of translation functions I would like to have QT_TRANSLATE_NOOP_3() available to be able to add comment for translators.

image

ostr00000 commented 2 hours ago

Your code @hasecilu, probably does not work, because lupdate see a string something with context CreateSketch (you can verify it in .ts file). But in runtime, Qt is asked to give translation for something using context MyGreat....

I created repository with Qt translation example: https://github.com/ostr00000/tr-example - you can analyze there some tricks I discovered over the years.

In your example, you are using inheritance, so you will have probably problems in CreateSketch. Either you declare translation with transalte (the old way) or you may want to look at my smart mixin class - just add TR before QObject in base classes. If you do not use QObject, then just add instead object (starting from python 3 object is always present in base classes, so there is no need to add it explicit).