details:   https://code.tryton.org/tryton/commit/dba330085af9
branch:    default
user:      Cédric Krier <[email protected]>
date:      Fri Oct 02 14:58:38 2026 +0200
description:
        Support reading translated fields in any suffixed language

        Closes #15132
diffstat:

 trytond/CHANGELOG                      |   1 +
 trytond/doc/ref/models.rst             |   4 ++
 trytond/trytond/model/modelsql.py      |  14 +++++++++
 trytond/trytond/tests/test_modelsql.py |  49 ++++++++++++++++++++++++++++++++++
 4 files changed, 68 insertions(+), 0 deletions(-)

diffs (119 lines):

diff -r beb60346fb5d -r dba330085af9 trytond/CHANGELOG
--- a/trytond/CHANGELOG Fri Oct 16 10:52:57 2026 +0200
+++ b/trytond/CHANGELOG Fri Oct 02 14:58:38 2026 +0200
@@ -1,3 +1,4 @@
+* Support reading translated fields in any suffixed language
 * Rename delete_many to deletemany in the FileStore
 * Restrict the wizard session to the user who created it (issue15206)
 * Only permit administrators to execute wizards without models or groups 
(issue15205)
diff -r beb60346fb5d -r dba330085af9 trytond/doc/ref/models.rst
--- a/trytond/doc/ref/models.rst        Fri Oct 16 10:52:57 2026 +0200
+++ b/trytond/doc/ref/models.rst        Fri Oct 02 14:58:38 2026 +0200
@@ -403,6 +403,10 @@
    :class:`~fields.Selection` or :class:`~fields.MultiSelection` fields.
    Their human-readable value are returned.
 
+   ``fields_names`` can also contain ``<field>:<language>`` for translatable
+   fields.
+   Their translated values are returned.
+
    The virtual fields ``_write`` and ``_delete`` can be used the read the
    writeable and deleteable state of the records.
    Regarding the ``_timestamp`` virtual fields it contains a timestamp that is
diff -r beb60346fb5d -r dba330085af9 trytond/trytond/model/modelsql.py
--- a/trytond/trytond/model/modelsql.py Fri Oct 16 10:52:57 2026 +0200
+++ b/trytond/trytond/model/modelsql.py Fri Oct 02 14:58:38 2026 +0200
@@ -1202,6 +1202,7 @@
         extra_fields = set()
         if 'write_date' not in fields_names:
             extra_fields.add('write_date')
+        fields_translated = []
         for field_name in fields_names:
             if field_name in {'_timestamp', '_write', '_delete', '__name__'}:
                 continue
@@ -1211,6 +1212,10 @@
             if field_name.endswith(':string'):
                 field_name = field_name[:-len(':string')]
                 fields_related[field_name]
+            elif ':' in field_name:
+                field_name, language = field_name.split(':', 1)
+                fields_translated.append((field_name, language))
+                extra_fields.add(field_name)
             field = cls._fields[field_name]
             if hasattr(field, 'datetime_field') and field.datetime_field:
                 extra_fields.add(field.datetime_field)
@@ -1312,6 +1317,15 @@
         max_write_date = max(
             (r['write_date'] for r in result if r.get('write_date')),
             default=None)
+
+        for fname, language in fields_translated:
+            translations = Translation.get_ids(
+                f'{cls.__name__},{fname}', 'model', language, ids,
+                cached_after=max_write_date)
+            for row in result:
+                row[f'{fname}:{language}'] = (
+                    translations.get(row['id']) or row[fname])
+
         for fname, column in columns.items():
             if fname.startswith('_'):
                 continue
diff -r beb60346fb5d -r dba330085af9 trytond/trytond/tests/test_modelsql.py
--- a/trytond/trytond/tests/test_modelsql.py    Fri Oct 16 10:52:57 2026 +0200
+++ b/trytond/trytond/tests/test_modelsql.py    Fri Oct 02 14:58:38 2026 +0200
@@ -1755,6 +1755,55 @@
         self.assertEqual(other.name, "Bar")
 
     @with_transaction()
+    def test_read_multiple_languages(self):
+        "Test read multiple languages"
+        pool = Pool()
+        Model = pool.get('test.modelsql.translation')
+        transaction = Transaction()
+
+        with transaction.set_context(language=self.default_language):
+            record, = Model.create([{'name': "Foo"}])
+        with transaction.set_context(language=self.other_language):
+            Model.write([record], {'name': "Bar"})
+
+        values = Model.read([record.id], [
+                'name',
+                f'name:{self.default_language}',
+                f'name:{self.other_language}',
+                ])
+
+        self.assertEqual(values, [{
+                    'id': record.id,
+                    'name': "Foo",
+                    f'name:{self.default_language}': "Foo",
+                    f'name:{self.other_language}': "Bar",
+                    }])
+
+    @with_transaction()
+    def test_read_multiple_languages_fallback(self):
+        "Test read multiple languages with fallback"
+        pool = Pool()
+        Model = pool.get('test.modelsql.translation')
+        transaction = Transaction()
+
+        with transaction.set_context(language=self.default_language):
+            record, = Model.create([{'name': "Foo"}])
+        with transaction.set_context(language=self.other_language):
+            Model.write([record], {'name': "Bar"})
+
+        with transaction.set_context(language=self.other_language):
+            values = Model.read([record.id], [
+                    f'name:{self.other_language}',
+                    'name:unknown',
+                    ])
+
+        self.assertEqual(values, [{
+                    'id': record.id,
+                    f'name:{self.other_language}': "Bar",
+                    'name:unknown': "Foo",
+                    }])
+
+    @with_transaction()
     def test_read_last_translation(self):
         "Test read last translation record"
         pool = Pool()

Reply via email to