diff options
author | Christian Tismer <tismer@stackless.com> | 2021-06-26 14:37:17 +0200 |
---|---|---|
committer | Christian Tismer <tismer@stackless.com> | 2021-06-29 16:09:15 +0200 |
commit | 5054038dd43fbb243e2c44b0a9aad35181b043b1 (patch) | |
tree | 5d9434d3517ce78a5679e7ef6f6744521cd8af10 /sources | |
parent | 4ca5aefe4f6e05eba4d73a93620134e37ac5f1d6 (diff) |
translate: Fix translation for derived types
[ChangeLog][PySide6] The `tr` function now works also for
PySide derived Python class instances with the right context.
Qt has a translation feature that works fine on strings that
are directly parsed from a Python class.
For derived classes, the correct context could not be found.
This problem could have been solved by obtaining the calling
function name from the frame stack, walking the mro and
examining in which class dict the calling function can be
found, but this works for Python functions, only.
For any function, simply probing the translation result is
even easier and always works.
We walk the mro, too, but simply use each class name in turn
as context and probe by comparison if a translation was done.
Change-Id: Ibca9dc0098a3aa26a674b3d5e24ea14e651fe6de
Fixes: PYSIDE-131
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
(cherry picked from commit c61141d43fd6e56a52449cbfe6cc13d07f9156bb)
Diffstat (limited to 'sources')
-rw-r--r-- | sources/pyside2/PySide2/glue/qtcore.cpp | 46 | ||||
-rw-r--r-- | sources/pyside2/tests/QtCore/translation_test.py | 13 |
2 files changed, 47 insertions, 12 deletions
diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp index f76189d21..0c5d75695 100644 --- a/sources/pyside2/PySide2/glue/qtcore.cpp +++ b/sources/pyside2/PySide2/glue/qtcore.cpp @@ -830,19 +830,41 @@ QObject *child = _findChildHelper(%CPPSELF, %2, reinterpret_cast<PyTypeObject *> _findChildrenHelper(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>(%PYARG_1), %PYARG_0); // @snippet qobject-findchildren +////////////////////////////////////////////////////////////////////////////// +// PYSIDE-131: Use the class name as context where the calling function is +// living. Derived Python classes have the wrong context. +// +// The original patch uses Python introspection to look up the current +// function (from the frame stack) in the class __dict__ along the mro. +// +// The problem is that looking into the frame stack works for Python +// functions, only. For including builtin function callers, the following +// approach turned out to be much simpler: +// +// Walk the __mro__ +// - translate the string +// - if the translated string is changed: +// - return the translation. + // @snippet qobject-tr -QString result; -if (QCoreApplication::instance()) { - PyObject *klass = PyObject_GetAttr(%PYSELF, Shiboken::PyMagicName::class_()); - PyObject *cname = PyObject_GetAttr(klass, Shiboken::PyMagicName::name()); - result = QString(QCoreApplication::instance()->translate(Shiboken::String::toCString(cname), - /* %1, %2, QCoreApplication::CodecForTr, %3)); */ - %1, %2, %3)); - - Py_DECREF(klass); - Py_DECREF(cname); -} else { - result = QString(QString::fromLatin1(%1)); +PyTypeObject *type = Py_TYPE(%PYSELF); +PyObject *mro = type->tp_mro; +auto len = PyTuple_GET_SIZE(mro); +QString result = QString::fromUtf8(%1); +QString oldResult = result; +static auto *sbkObjectType = reinterpret_cast<PyTypeObject *>(SbkObject_TypeF()); +for (Py_ssize_t idx = 0; idx < len - 1; ++idx) { + // Skip the last class which is `object`. + auto *type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx)); + if (type == sbkObjectType) + continue; + const char *context = type->tp_name; + const char *dotpos = strrchr(context, '.'); + if (dotpos != nullptr) + context = dotpos + 1; + result = QCoreApplication::translate(context, %1, %2, %3); + if (result != oldResult) + break; } %PYARG_0 = %CONVERTTOPYTHON[QString](result); // @snippet qobject-tr diff --git a/sources/pyside2/tests/QtCore/translation_test.py b/sources/pyside2/tests/QtCore/translation_test.py index 0f36067bd..b2e674aac 100644 --- a/sources/pyside2/tests/QtCore/translation_test.py +++ b/sources/pyside2/tests/QtCore/translation_test.py @@ -59,6 +59,19 @@ class TranslationTest(UsesQCoreApplication): obj = QObject() obj.setObjectName(obj.tr('Hello World!')) + self.assertEqual(obj.objectName(), 'Orbis, te saluto!') + + def testLatinDerived(self): + # PYSIDE-131: Test that derived classes work, too. + translator = QTranslator() + translator.load(os.path.join(self.trdir, 'trans_latin.qm')) + self.app.installTranslator(translator) + + class Derived(QObject): + pass + + obj = Derived() + obj.setObjectName(obj.tr('Hello World!')) self.assertEqual(obj.objectName(), py3k.unicode_('Orbis, te saluto!')) def testRussian(self): |