diff --git a/addons/test_event_full/tests/test_performance.py b/addons/test_event_full/tests/test_performance.py
index 76e2e808847..81061e81a9a 100644
--- a/addons/test_event_full/tests/test_performance.py
+++ b/addons/test_event_full/tests/test_performance.py
@@ -52,7 +52,7 @@ class TestEventPerformance(EventPerformanceCase):
batch_size = 20
# simple without type involved + website
- with freeze_time(self.reference_now), self.assertQueryCount(event_user=3377): # tef 3275 / com 3274
+ with freeze_time(self.reference_now), self.assertQueryCount(event_user=3418): # tef 3316 / com 3315
self.env.cr._now = self.reference_now # force create_date to check schedulers
event_values = [
dict(self.event_base_vals,
@@ -89,7 +89,7 @@ class TestEventPerformance(EventPerformanceCase):
event_type = self.env['event.type'].browse(self.test_event_type.ids)
# complex with type + website
- with freeze_time(self.reference_now), self.assertQueryCount(event_user=3481): # tef 3379 / com 3378
+ with freeze_time(self.reference_now), self.assertQueryCount(event_user=3522): # tef 3420 / com 3419
self.env.cr._now = self.reference_now # force create_date to check schedulers
event_values = [
dict(self.event_base_vals,
@@ -128,7 +128,7 @@ class TestEventPerformance(EventPerformanceCase):
has_social = 'social_menu' in self.env['event.event'] # otherwise view may crash in enterprise
# no type, website
- with freeze_time(self.reference_now), self.assertQueryCount(event_user=447): # tef 379 / com 427
+ with freeze_time(self.reference_now), self.assertQueryCount(event_user=449): # tef 398 / com 399
self.env.cr._now = self.reference_now # force create_date to check schedulers
# Require for `website_menu` to be visible
#
@@ -150,7 +150,7 @@ class TestEventPerformance(EventPerformanceCase):
has_social = 'social_menu' in self.env['event.event'] # otherwise view may crash in enterprise
# type and website
- with freeze_time(self.reference_now), self.assertQueryCount(event_user=470): # tef 402 / com 450
+ with freeze_time(self.reference_now), self.assertQueryCount(event_user=472): # tef 426 / com 428
self.env.cr._now = self.reference_now # force create_date to check schedulers
# Require for `website_menu` to be visible
#
@@ -212,7 +212,7 @@ class TestEventPerformance(EventPerformanceCase):
event_type = self.env['event.type'].browse(self.test_event_type.ids)
# complex with type + website
- with freeze_time(self.reference_now), self.assertQueryCount(event_user=271): # tef 256 / com 262
+ with freeze_time(self.reference_now), self.assertQueryCount(event_user=274): # tef 266 / com 265
self.env.cr._now = self.reference_now # force create_date to check schedulers
event_values = dict(
self.event_base_vals,
diff --git a/addons/website/models/ir_module_module.py b/addons/website/models/ir_module_module.py
index b94aa3fff1e..ee83aefcfd2 100644
--- a/addons/website/models/ir_module_module.py
+++ b/addons/website/models/ir_module_module.py
@@ -189,6 +189,7 @@ class IrModuleModule(models.Model):
self.ensure_one()
translated_fields = self._theme_translated_fields.get(old_rec._name, [])
cur_lang = self.env.lang or 'en_US'
+ valid_langs = set(code for code, _ in self.env['res.lang'].get_installed()) | {'en_US'}
old_rec.flush_recordset()
for (src_field, dst_field) in translated_fields:
__, src_fname = src_field.split(',')
@@ -196,7 +197,11 @@ class IrModuleModule(models.Model):
if dst_mname != new_rec._name:
continue
old_field = old_rec._fields[src_fname]
- old_translations = old_field._get_stored_translations(old_rec)
+ old_translations = {
+ lang: value
+ for lang, value in old_field._get_stored_translations(old_rec).items()
+ if lang in valid_langs
+ }
if not old_translations:
continue
if not callable(old_field.translate):
diff --git a/odoo/addons/base/tests/test_translate.py b/odoo/addons/base/tests/test_translate.py
index 23872e94920..449723a4150 100644
--- a/odoo/addons/base/tests/test_translate.py
+++ b/odoo/addons/base/tests/test_translate.py
@@ -402,6 +402,40 @@ class TestTranslation(TransactionCase):
self.assertEqual(categories.ids, [padawans.id, self.customers.id],
"Search ordered by translated name should return Padawans (Apprentis) before Customers (Clients)")
+ def test_105_duplicate_record_multi_no_en(self):
+ self.env['res.partner'].with_context(active_test=False).search([]).write({'lang': 'fr_FR'})
+ self.env['res.lang']._activate_lang('nl_NL')
+ self.customers.with_context(lang='nl_NL').name = 'Klanten'
+ self.env['res.lang']._activate_lang('zh_CN')
+ self.customers.with_context(lang='zh_CN').name = '客户'
+ self.env.ref('base.lang_en').active = False
+ self.env.ref('base.lang_zh_CN').active = False
+
+ category = self.customers
+ translations = category._fields['name']._get_stored_translations(category)
+ self.assertDictEqual(
+ translations,
+ {
+ 'en_US': 'Customers',
+ 'fr_FR': 'Clients',
+ 'nl_NL': 'Klanten',
+ 'zh_CN': '客户',
+ }
+ )
+
+ category_copy = self.customers.with_context(lang='fr_FR').copy()
+ translations = category_copy._fields['name']._get_stored_translations(category_copy)
+
+ self.assertDictEqual(
+ translations,
+ {
+ 'en_US': 'Customers',
+ 'fr_FR': 'Clients',
+ 'nl_NL': 'Klanten',
+ },
+ 'English, French and Dutch translation should be copied, Chinese translation should be dropped'
+ )
+
def test_107_duplicate_record_en(self):
category = self.customers.with_context({'lang': 'en_US'}).copy()
diff --git a/odoo/models.py b/odoo/models.py
index 009beb6c1bd..f962d7c6668 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -3041,12 +3041,12 @@ class BaseModel(metaclass=MetaModel):
"""
self.ensure_one()
- installed_lang = set(code for code, _ in self.env['res.lang'].get_installed())
- missing_languages = set(translations) - installed_lang
- if missing_languages:
+ valid_langs = set(code for code, _ in self.env['res.lang'].get_installed()) | {'en_US'}
+ missing_langs = set(translations) - valid_langs
+ if missing_langs:
raise UserError(
- _("The following language is not activated: %(missing_names)s",
- missing_names=', '.join(missing_languages))
+ _("The following languages are not activated: %(missing_names)s",
+ missing_names=', '.join(missing_langs))
)
field = self._fields[field_name]
@@ -4840,6 +4840,7 @@ class BaseModel(metaclass=MetaModel):
if old.id in seen_map[old._name]:
return
seen_map[old._name].add(old.id)
+ valid_langs = set(code for code, _ in self.env['res.lang'].get_installed()) | {'en_US'}
for name, field in old._fields.items():
if not field.copy:
@@ -4868,6 +4869,11 @@ class BaseModel(metaclass=MetaModel):
continue
lang = self.env.lang or 'en_US'
old_value_lang = old_translations.pop(lang, old_translations['en_US'])
+ old_translations = {
+ lang: value
+ for lang, value in old_translations.items()
+ if lang in valid_langs
+ }
if not old_translations:
continue
if not callable(field.translate):