[FIX] base: upsert translations during copy_translations
When doing a copy, create the new translations directly in SQL and handle potential conflicts. Conflicts can occure in case of reinstallation as showed in opw-1955062 and opw-1950117. In case of "leftovers" of translations (e.g. remaining after the uninstallation of a module), creating the new translations (when reinstalling the module) may produce a conflict with (type, name, res_id, lang) and raise an error. This is NOT a problem of reading .po file during installation (which handles correctly conflicts) but of business code creating new records and linked translations (e.g. website copying website.menu records). Removing old translations during uninstall is handled in a previous commit in ir.model.fields _drop_column method. This commit fixes the reinstallation on instances with leftover translations and fixes the issue without needing a manual intervention (i.e. delete the old translations manually). Closes odoo/odoo#32056 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
This commit is contained in:
committed by
Raphael Collet
parent
112bd835d8
commit
489494e733
@@ -670,6 +670,47 @@ class IrTranslation(models.Model):
|
||||
})
|
||||
self._modified_model(field.model_name)
|
||||
|
||||
@api.model
|
||||
def _upsert_translations(self, vals_list):
|
||||
""" Insert or update translations of type 'model' or 'model_terms'.
|
||||
|
||||
This method is used for creations of translations where the given
|
||||
``vals_list`` is trusted to be the right values and potential
|
||||
conflicts should be updated to the new given value.
|
||||
"""
|
||||
rows_by_type = defaultdict(list)
|
||||
for vals in vals_list:
|
||||
rows_by_type[vals['type']].append((
|
||||
vals['name'], vals['lang'], vals['res_id'], vals['src'], vals['type'],
|
||||
vals.get('module'), vals['value'], vals.get('state'), vals.get('comments'),
|
||||
))
|
||||
|
||||
if rows_by_type['model']:
|
||||
query = """
|
||||
INSERT INTO ir_translation (name, lang, res_id, src, type,
|
||||
module, value, state, comments)
|
||||
VALUES {}
|
||||
ON CONFLICT (type, lang, name, res_id) WHERE type='model'
|
||||
DO UPDATE SET (name, lang, res_id, src, type, value, module, state, comments) =
|
||||
(EXCLUDED.name, EXCLUDED.lang, EXCLUDED.res_id, EXCLUDED.src, EXCLUDED.type,
|
||||
EXCLUDED.value, EXCLUDED.module, EXCLUDED.state, EXCLUDED.comments)
|
||||
WHERE EXCLUDED.value IS NOT NULL AND EXCLUDED.value != '';
|
||||
""".format(", ".join(["%s"] * len(rows_by_type['model'])))
|
||||
self.env.cr.execute(query, rows_by_type['model'])
|
||||
|
||||
if rows_by_type['model_terms']:
|
||||
query = """
|
||||
INSERT INTO ir_translation (name, lang, res_id, src, type,
|
||||
module, value, state, comments)
|
||||
VALUES {}
|
||||
ON CONFLICT (type, name, lang, res_id, md5(src))
|
||||
DO UPDATE SET (name, lang, res_id, src, type, value, module, state, comments) =
|
||||
(EXCLUDED.name, EXCLUDED.lang, EXCLUDED.res_id, EXCLUDED.src, EXCLUDED.type,
|
||||
EXCLUDED.value, EXCLUDED.module, EXCLUDED.state, EXCLUDED.comments)
|
||||
WHERE EXCLUDED.value IS NOT NULL AND EXCLUDED.value != '';
|
||||
""".format(", ".join(["%s"] * len(rows_by_type['model_terms'])))
|
||||
self.env.cr.execute(query, rows_by_type['model_terms'])
|
||||
|
||||
@api.model
|
||||
def translate_fields(self, model, id, field=None):
|
||||
""" Open a view for translating the field(s) of the record (model, id). """
|
||||
|
||||
+3
-2
@@ -4242,11 +4242,12 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
if vals['lang'] == old.env.lang and field.translate is True:
|
||||
# force a source if the new_val was not changed by copy override
|
||||
if new_val == old[name]:
|
||||
vals['source'] = old_wo_lang[name]
|
||||
new_wo_lang[name] = old_wo_lang[name]
|
||||
vals['src'] = old_wo_lang[name]
|
||||
# the value should be the new value (given by copy())
|
||||
vals['value'] = new_val
|
||||
vals_list.append(vals)
|
||||
Translation.create(vals_list)
|
||||
Translation._upsert_translations(vals_list)
|
||||
|
||||
@api.multi
|
||||
@api.returns('self', lambda value: value.id)
|
||||
|
||||
Reference in New Issue
Block a user