details: https://code.tryton.org/tryton/commit/03757ba2dd9d
branch: default
user: Cédric Krier <[email protected]>
date: Fri Sep 26 08:45:49 2025 +0200
description:
Return the closest language instance for the code
When the language code is provided by an external source, a best effort
strategy must be used to always return a language.
Closes #14258
diffstat:
trytond/doc/modules/ir/reference.rst | 2 +-
trytond/trytond/ir/lang.py | 32 +++++++++++++++++++++++++++-----
trytond/trytond/tests/test_ir.py | 17 +++++++++++++++++
3 files changed, 45 insertions(+), 6 deletions(-)
diffs (90 lines):
diff -r 8a062bb4f22e -r 03757ba2dd9d trytond/doc/modules/ir/reference.rst
--- a/trytond/doc/modules/ir/reference.rst Wed Oct 01 10:17:22 2025 +0200
+++ b/trytond/doc/modules/ir/reference.rst Fri Sep 26 08:45:49 2025 +0200
@@ -54,7 +54,7 @@
.. method:: Language.get([code])
- Returns the language instance for the ``code`` or the
+ Returns the closest language instance for the ``code`` or the
:attr:`~trytond.transaction.Transaction.language`.
.. method:: Language.format(percent, value[, grouping[, monetary[,
\*\*additional]]])
diff -r 8a062bb4f22e -r 03757ba2dd9d trytond/trytond/ir/lang.py
--- a/trytond/trytond/ir/lang.py Wed Oct 01 10:17:22 2025 +0200
+++ b/trytond/trytond/ir/lang.py Fri Sep 26 08:45:49 2025 +0200
@@ -423,20 +423,42 @@
cls._lang_cache.clear()
Translation._get_language_cache.clear()
_parents.clear()
- if mode in {'write', 'delete'}:
+ if mode in {'create', 'write', 'delete'}:
cls._code_cache.clear()
@classmethod
@inactive_records
def get(cls, code=None):
"Return language instance for the code or the transaction language"
+ pool = Pool()
+ Configuration = pool.get('ir.configuration')
+
+ def languages(code):
+ for sep in ['@', '_']:
+ if sep in code:
+ code, _ = code.rsplit(sep, 1)
+ if code:
+ yield code
+ yield from languages(code)
if code is None:
code = Transaction().language
+ code = code.replace('-', '_')
lang_id = cls._code_cache.get(code)
- if not lang_id:
- lang, = cls.search([
- ('code', '=', code),
- ])
+ if lang_id is None:
+ try:
+ lang, = cls.search([
+ ('code', '=', code),
+ ])
+ except ValueError:
+ for parent_code in languages(code):
+ if lang := cls.get(parent_code):
+ break
+ else:
+ default_code = Configuration.get_language()
+ if default_code != code:
+ lang = cls.get(default_code)
+ else:
+ raise
cls._code_cache.set(code, lang.id)
else:
lang = cls(lang_id)
diff -r 8a062bb4f22e -r 03757ba2dd9d trytond/trytond/tests/test_ir.py
--- a/trytond/trytond/tests/test_ir.py Wed Oct 01 10:17:22 2025 +0200
+++ b/trytond/trytond/tests/test_ir.py Fri Sep 26 08:45:49 2025 +0200
@@ -347,6 +347,23 @@
Model.global_search('User', 10)
@with_transaction()
+ def test_lang_get_subtags(self):
+ "Test Lang.get with subtags"
+ pool = Pool()
+ Lang = pool.get('ir.lang')
+
+ self.assertEqual(Lang.get('fr_CA').code, 'fr')
+ self.assertEqual(Lang.get('fr-BE').code, 'fr')
+
+ @with_transaction()
+ def test_lang_get_unknown(self):
+ "Test Lang.get with unknown language"
+ pool = Pool()
+ Lang = pool.get('ir.lang')
+
+ self.assertEqual(Lang.get('foo').code, 'en')
+
+ @with_transaction()
def test_lang_currency(self):
"Test Lang.currency"
pool = Pool()