From f7fca3faf96e08411eb149689054bedf346630c5 Mon Sep 17 00:00:00 2001 From: Alvaro Fuentes Date: Mon, 15 May 2023 06:55:17 +0000 Subject: [PATCH] [FIX] core: do not udpate translation terms from text to xml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Steps to reproduce the issue: * In a clean v16 db install base_setup * Log in into DB, switch language to French (install and activate it) * Upgrade to saas-16.1 Issue: The main settings page under Companies settings (Sociétés in Frech) shows ``` Mise en page du document ``` instead of just ``` Mise en page du document ``` The issue comes from this difference, 16.0: https://github.com/odoo/odoo/blob/fb02720aed0b0be00df8f5d0e1932b948c300b92/addons/base_setup/views/res_config_settings_views.xml#L78-L79 vs saas-16.1: https://github.com/odoo/odoo/blob/80bc702ecfe6f704af05f9830d272b162018f2ad/addons/base_setup/views/res_config_settings_views.xml#L79 Note that `Document Layout` is used in two different contexts. In 16.0 it comes within an xml/html block containing a `` tag, and more importantly it is the **text** part of the xml tag. In saas-16.1 the same `Document Layout` is used as an **attribute** of the `setting` tag. Thus we cannot blindly assign the whole term (block with tags) to the attribute when upgrading to saas-16.1, it is only safe to update the translation from xml to text. Updating a text entry with something that seems to have other xml elements is unsafe and can lead to the issue showcased here. For more context, at the time of updating the terms here is the situation: * `closest_matches` is `['Document Layout']` * `closest_term` is `Document Layout` * `old_term` is ``` Document Layout ``` closes odoo/odoo#123540 X-original-commit: 6cd49293fe4d0d86fbbfa2476e113deadeba7348 Signed-off-by: Wang Chong (cwg) Signed-off-by: Alvaro Fuentes Suarez (afu) Co-authored-by: Chong Wang(cwg) --- odoo/addons/base/tests/test_translate.py | 22 ++++++++++++++++++++++ odoo/fields.py | 5 ++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/odoo/addons/base/tests/test_translate.py b/odoo/addons/base/tests/test_translate.py index 0006c831e67..beda9616116 100644 --- a/odoo/addons/base/tests/test_translate.py +++ b/odoo/addons/base/tests/test_translate.py @@ -1022,6 +1022,28 @@ class TestXMLTranslation(TransactionCase): self.assertEqual(view.with_env(env_fr).arch_db, archf % terms_fr) self.assertEqual(view.with_env(env_nl).arch_db, archf % terms_nl) + def test_sync_text_to_xml(self): + """ Check translations of 'arch' after xml tags changes in source terms. """ + archf = '
%s
' + terms_en = ('Hi',) + terms_fr = ('Salut',) + terms_nl = ('Hallo',) + view = self.create_view(archf, terms_en, en_US=terms_en, fr_FR=terms_fr, nl_NL=terms_nl) + + env_nolang = self.env(context={}) + env_en = self.env(context={'lang': 'en_US'}) + env_fr = self.env(context={'lang': 'fr_FR'}) + + # modify the arch view, keep the same text content: 'Hi' + terms_en = 'Hi' + archf = '
' + view.with_env(env_en).write({'arch_db': archf % terms_en}) + + self.assertEqual(view.with_env(env_nolang).arch_db, archf % terms_en) + self.assertEqual(view.with_env(env_en).arch_db, archf % terms_en) + # check that we didn't set string="<span>Salut</span>" + self.assertEqual(view.with_env(env_fr).arch_db, archf % terms_en) + def test_sync_xml_collision(self): """ Check translations of 'arch' after xml tags changes in source terms when the same term appears in different elements with different diff --git a/odoo/fields.py b/odoo/fields.py index 6a316689f9c..100ed964bc6 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -1822,7 +1822,10 @@ class _String(Field): matches = get_close_matches(old_term_text, text2terms, 1, 0.9) if matches: closest_term = get_close_matches(old_term, text2terms[matches[0]], 1, 0)[0] - translation_dictionary[closest_term] = translation_dictionary.pop(old_term) + old_is_text = old_term == self.get_text_content(old_term) + closest_is_text = closest_term == self.get_text_content(closest_term) + if old_is_text or not closest_is_text: + translation_dictionary[closest_term] = translation_dictionary.pop(old_term) # pylint: disable=not-callable new_translations = { l: self.translate(lambda term: translation_dictionary.get(term, {l: None})[l], cache_value)