diff options
author | Christian Tismer <tismer@stackless.com> | 2021-06-26 14:37:17 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-07-16 09:54:52 +0000 |
commit | 5c9d4986cdc6ebf63efa0e94430798c81c2dff3e (patch) | |
tree | 98d8242b81e55b5f4d69d6281c5d705c62a4376d | |
parent | 234b33aafe12c6f880600598ed1d7ee9bc83c53a (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)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | sources/pyside6/PySide6/glue/qtcore.cpp | 46 | ||||
-rw-r--r-- | sources/pyside6/tests/QtCore/translation_test.py | 13 |
2 files changed, 47 insertions, 12 deletions
diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp index fb9a3db40..9bc516f08 100644 --- a/sources/pyside6/PySide6/glue/qtcore.cpp +++ b/sources/pyside6/PySide6/glue/qtcore.cpp @@ -887,19 +887,41 @@ QObject *child = _findChildHelper(%CPPSELF, %2, reinterpret_cast<PyTypeObject *> _findChildrenHelper(%CPPSELF, %2, reinterpret_cast<PyTypeObject *>(%PYARG_1), %3, %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/pyside6/tests/QtCore/translation_test.py b/sources/pyside6/tests/QtCore/translation_test.py index fbce644e0..6536ca66f 100644 --- a/sources/pyside6/tests/QtCore/translation_test.py +++ b/sources/pyside6/tests/QtCore/translation_test.py @@ -62,6 +62,19 @@ class TranslationTest(UsesQCoreApplication): 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(), 'Orbis, te saluto!') + def testRussian(self): # Set string value to Russian translator = QTranslator() |