aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2021-06-26 14:37:17 +0200
committerChristian Tismer <tismer@stackless.com>2021-06-29 16:09:15 +0200
commit5054038dd43fbb243e2c44b0a9aad35181b043b1 (patch)
tree5d9434d3517ce78a5679e7ef6f6744521cd8af10 /sources
parent4ca5aefe4f6e05eba4d73a93620134e37ac5f1d6 (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.cpp46
-rw-r--r--sources/pyside2/tests/QtCore/translation_test.py13
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):