[FIX] core: do not udpate translation terms from text to xml

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
```
<span class="o_form_label">Mise en page du document</span> <span class="fa fa-lg fa-building-o" title="Les valeurs définies ici sont spécifiques à l'entreprise." aria-label="Values set here are company-specific." groups="base.group_multi_company" role="img"/>
```
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 `<span>` 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
  ```
  <span class="o_form_label">Document Layout</span>
                                        <span class="fa fa-lg fa-building-o" title="Values set here are company-specific." aria-label="Values set here are company-specific." groups="base.group_multi_company" role="img"/>
  ```

closes odoo/odoo#123540

X-original-commit: 6cd49293fe4d0d86fbbfa2476e113deadeba7348
Signed-off-by: Wang Chong (cwg) <cwg@odoo.com>
Signed-off-by: Alvaro Fuentes Suarez (afu) <afu@odoo.com>
Co-authored-by: Chong Wang(cwg) <cwg@odoo.com>
This commit is contained in:
Alvaro Fuentes
2023-06-02 23:38:58 +02:00
co-authored by Chong Wang
parent 03b37ffc5c
commit f7fca3faf9
2 changed files with 26 additions and 1 deletions
+22
View File
@@ -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 = '<form string="X">%s</form>'
terms_en = ('<span>Hi</span>',)
terms_fr = ('<span>Salut</span>',)
terms_nl = ('<span>Hallo</span>',)
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 = '<form string="X"><setting string="%s"><span color="red"/></setting></form>'
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="&lt;span&gt;Salut&lt;/span&gt;"
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
+4 -1
View File
@@ -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)