aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2021-06-26 14:37:17 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-07-16 09:54:52 +0000
commit5c9d4986cdc6ebf63efa0e94430798c81c2dff3e (patch)
tree98d8242b81e55b5f4d69d6281c5d705c62a4376d
parent234b33aafe12c6f880600598ed1d7ee9bc83c53a (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.cpp46
-rw-r--r--sources/pyside6/tests/QtCore/translation_test.py13
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()