[FIX] base: single lang behaviour

If a db is in single lang (en_US or not) but still has translations, the
translation should be updated in addition to updating the referenced record
Add tests to formalise the expected behaviour:

If one language only (en_US or not), when writing on a translatable field:
- record field should updated
- value of potential existing en_US translation should be updated
- src of potential existing translations should be updated
- no new translation should be created

If en_US and fr_FR, when writing on a translatable field in en_US:
- record field should updated
- value of potential existing en_US translation should be updated
- src of potential existing translations should be updated
- new en_US translation should be created if was not present

If en_US and fr_FR, when writing on a translatable field in fr_FR:
- record field should not be updated
- value of potential existing fr_FR translation should be updated
- src of potential existing translations should not be updated
- new fr_FR translation should be created if was not present

Adapt test_new_api test
get_installed is ormcached, just putting active = True is not enough
This commit is contained in:
Martin Trigaux
2019-08-01 09:06:25 +00:00
parent 66ef641f33
commit 18d9c2cab2
4 changed files with 121 additions and 5 deletions
+24
View File
@@ -649,6 +649,30 @@ class IrTranslation(models.Model):
""".format(", ".join(["%s"] * len(rows_by_type['model_terms'])))
self.env.cr.execute(query, rows_by_type['model_terms'])
def _update_translations(self, vals_list):
""" Update translations of type 'model' or 'model_terms'.
This method is used for update of translations where the given
``vals_list`` is trusted to be the right values
No new translation will be created
"""
grouped_rows = {}
for vals in vals_list:
key = (vals['lang'], vals['type'], vals['name'])
grouped_rows.setdefault(key, [vals['value'], vals['src'], vals['state'], []])
grouped_rows[key][3].append(vals['res_id'])
for where, values in grouped_rows.items():
self._cr.execute(
""" UPDATE ir_translation
SET value=%s,
src=%s,
state=%s
WHERE lang=%s AND type=%s AND name=%s AND res_id in %s
""",
(values[0], values[1], values[2], where[0], where[1], where[2], tuple(values[3]))
)
@api.model
def translate_fields(self, model, id, field=None):
""" Open a view for translating the field(s) of the record (model, id). """
+86
View File
@@ -393,6 +393,92 @@ class TestTranslation(TransactionCase):
])
self.assertEqual(translation_fr.src, 'Customers', "Did not set English version as source")
class TestTranslationWrite(TransactionCase):
def setUp(self):
super().setUp()
self.category = self.env['res.partner.category'].create({'name': 'Reblochon'})
def test_01_en(self):
langs = self.env['res.lang'].get_installed()
self.assertEqual([('en_US', 'English (US)')], langs, "Test did not started with expected languages")
self.category.with_context(lang='en_US').write({'name': 'English Name'})
name = self.category.with_context(lang=None).read(['name'])
self.assertEqual(name[0]['name'], "English Name", "Reference field not updated")
translations = self.env['ir.translation'].search([
('name', '=', 'res.partner.category,name'),
('res_id', '=', self.category.id),
('lang', '=', 'en_US'),
])
self.assertEqual(len(translations), 0, "No English translation should be created when writing in English")
def test_02_en_translated(self):
langs = self.env['res.lang'].get_installed()
self.assertEqual([('en_US', 'English (US)')], langs, "Test did not started with expected languages")
translation = self.env['ir.translation'].create({
'type': 'model',
'name': 'res.partner.category,name',
'lang': 'en_US',
'res_id': self.category.id,
'src': 'Reblochon',
'value': 'Translated Name',
'state': 'translated',
})
self.category.with_context(lang='en_US').write({'name': 'English Name'})
translation_value = translation.read(['value'])
self.assertEqual(translation_value[0]['value'], "English Name", "Existing translation was not updated")
source_name = self.category.with_context(lang=None).read(['name'])
self.assertEqual(source_name[0]['name'], "English Name", "Reference field not updated")
def test_03_fr_single(self):
self.env['res.lang'].load_lang('fr_FR')
self.env['res.users'].with_context(active_test=False).search([]).write({'lang': 'fr_FR'})
self.env.ref('base.lang_en').active = False
langs = self.env['res.lang'].get_installed()
self.assertEqual([('fr_FR', 'French / Français')], langs, "Test did not started with expected languages")
self.category.with_context(lang='fr_FR').write({'name': 'French Name'})
source_name = self.category.with_context(lang=None).read(['name'])
self.assertEqual(source_name[0]['name'], "French Name", "Reference field not updated")
translations = self.env['ir.translation'].search([
('name', '=', 'res.partner.category,name'),
('res_id', '=', self.category.id),
('lang', '=', 'fr_FR'),
])
self.assertEqual(len(translations), 0, "No French translation should be created when writing in French")
def test_04_fr_multi(self):
self.env['res.lang'].load_lang('fr_FR')
langs = self.env['res.lang'].get_installed()
self.assertEqual([('en_US', 'English (US)'), ('fr_FR', 'French / Français')], langs,
"Test did not started with expected languages")
self.env['ir.translation'].create({
'type': 'model',
'name': 'res.partner.category,name',
'lang': 'en_US',
'res_id': self.category.id,
'src': 'Reblochon',
'value': 'Translated Name',
'state': 'translated',
})
self.category.with_context(lang='fr_FR').write({'name': 'French Name'})
self.category.with_context(lang='en_US').write({'name': 'English Name'})
translations = self.env['ir.translation'].search([
('name', '=', 'res.partner.category,name'),
('res_id', '=', self.category.id),
], order='lang')
self.assertRecordValues(translations, [
{'src': 'English Name', 'value': 'English Name', 'lang': 'en_US'},
{'src': 'English Name', 'value': 'French Name', 'lang': 'fr_FR'}
])
class TestXMLTranslation(TransactionCase):
def setUp(self):
@@ -1230,8 +1230,7 @@ class TestFields(common.TransactionCase):
email = self.env.ref('test_new_api.emailmessage_0_0')
self.assertEqual(email.message, message)
french = self.env['res.lang']._lang_get('fr_FR')
french.active = True
self.env['res.lang'].load_lang('fr_FR')
def count(msg):
# return the number of translations of msg.label
+10 -3
View File
@@ -3397,6 +3397,12 @@ Fields:
other_fields = [] # list of non-column fields
single_lang = len(self.env['res.lang'].get_installed()) <= 1
has_translation = self.env.lang and self.env.lang != 'en_US'
# when there is only one language, update existing translations but
# do not create new ones
if single_lang:
process_translations = self.env['ir.translation']._update_translations
else:
process_translations = self.env['ir.translation']._upsert_translations
for name, val in vals.items():
field = self._fields[name]
@@ -3411,7 +3417,7 @@ Fields:
val = field.convert_to_column(val, self, vals)
columns.append((name, field.column_format, val))
tname = "%s,%s" % (self._name, name)
if field.translate is True and not single_lang:
if field.translate is True and self.env.lang:
self.env['ir.translation']._set_source(tname, self.ids, val)
updated.append(name)
else:
@@ -3451,7 +3457,7 @@ Fields:
# synchronize translated terms when possible.
self.env['ir.translation']._sync_terms_translations(field, self)
elif has_translation and field.translate:
elif self.env.lang and field.translate:
# The translated value of a field has been modified.
src_trans = self.with_context(lang=None).read([name])[0][name]
if not src_trans:
@@ -3469,7 +3475,8 @@ Fields:
state='translated',
res_id=res_id) for res_id in self.ids]
self.env['ir.translation']._upsert_translations(translation_values)
if translation_values:
process_translations(translation_values)
# mark fields to recompute; do this before setting other fields, because
# the latter can require the value of computed fields, e.g., a one2many