[FIX] core: fix copy translations

after odoo #113888
when copy translations from one record to another, translations for
non-installed languages may raise error.

These translations may be
1. created before the langauge is deactivated
2. en_US which is always available for non falsy translated field value

this commit drops translations for uninstalled languages except 'en_US' when
copy and prevents raising error when users want to translate en_US when en_US is
not activated

closes odoo/odoo#115711

X-original-commit: 7bb1825ddbf2340882bef5ed1d9c877f78a2b815
Signed-off-by: Raphael Collet <rco@odoo.com>
Signed-off-by: Wang Chong (cwg) <cwg@odoo.com>
This commit is contained in:
Chong Wang (cwg)
2023-03-20 15:31:27 +01:00
parent 9539d9a778
commit 0cef635102
4 changed files with 56 additions and 11 deletions
@@ -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
# <div name="event_menu_configuration" groups="base.group_no_one">
@@ -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
# <div name="event_menu_configuration" groups="base.group_no_one">
@@ -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,
+6 -1
View File
@@ -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):
+34
View File
@@ -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()
+11 -5
View File
@@ -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):