[FIX] translate: upgrade interraction with l10n_multilang

When upgrading a database with `l10n_multilang` installed, the
translations kept were not the right ones.
Here is the process that was executed during the upgrade:
* `base` is loaded: registry is loaded with `translate=True`, which
  calls `convert_column_translatable`. This has the effect of setting
  the value of the field to `{'en_US': name}`, with only that language
  installed.
* `l10n_multilang` is loaded: the function `lang_install` is extended to
  copy the translations of the templates on the instanciated records.
* `l10n_*` is loaded: the translation values are loaded from the `.po`
  files. `lang_install` is called after the loading on the templates,
  copying the value on the records. The value on the records is now
  something like `{'en_US': name, 'fr_BE': nom, 'nl_BE': naam}`.
* `base/end-migrate` is executed: it copies the values coming from
  `ir_translation`, without overriding the values that are already on
  the record because of the order of the `||` operator.

This means that any value inputed by the user[^1] will be overriden by
the value in the `.po` files.

opw-3175383

closes odoo/odoo#115254

X-original-commit: 5d46cdee878d752b9a61a74762a8710be0890e9d
Signed-off-by: Christophe Simonis <chs@odoo.com>
Co-authored-by: william-andre <wan@odoo.com>
Co-authored-by: HydrionBurst <cwg@odoo.com>
This commit is contained in:
HydrionBurst
2023-03-14 20:42:11 +01:00
committed by Chong Wang (cwg)
co-authored by william-andre
parent 5f6c758adb
commit 4feb7ba3c8
+22 -18
View File
@@ -1562,17 +1562,19 @@ def _get_translation_upgrade_queries(cr, field):
if field.translate is True:
query = f"""
WITH t AS (
SELECT res_id, jsonb_object_agg(lang, value) AS value
FROM _ir_translation
WHERE type = 'model' AND name = %s AND state = 'translated'
GROUP BY res_id
SELECT it.res_id as res_id, jsonb_object_agg(it.lang, it.value) AS value, bool_or(imd.noupdate) AS noupdate
FROM _ir_translation it
LEFT JOIN ir_model_data imd
ON imd.model = %s AND imd.res_id = it.res_id
WHERE it.type = 'model' AND it.name = %s AND it.state = 'translated'
GROUP BY it.res_id
)
UPDATE {Model._table} m
SET "{field.name}" = t.value || m."{field.name}"
SET "{field.name}" = CASE WHEN t.noupdate THEN m."{field.name}" || t.value ELSE t.value || m."{field.name}" END
FROM t
WHERE t.res_id = m.id
"""
migrate_queries.append(cr.mogrify(query, [translation_name]).decode())
migrate_queries.append(cr.mogrify(query, [Model._name, translation_name]).decode())
query = "DELETE FROM _ir_translation WHERE type = 'model' AND name = %s"
cleanup_queries.append(cr.mogrify(query, [translation_name]).decode())
@@ -1589,27 +1591,29 @@ def _get_translation_upgrade_queries(cr, field):
),
t AS (
-- aggregate translations by lang --
SELECT res_id, jsonb_object_agg(lang, value) AS value
SELECT t0.res_id AS res_id, jsonb_object_agg(t0.lang, t0.value) AS value, bool_or(imd.noupdate) AS noupdate
FROM t0
GROUP BY res_id
LEFT JOIN ir_model_data imd
ON imd.model = %s AND imd.res_id = t0.res_id
GROUP BY t0.res_id
)
SELECT t.res_id, m."{field.name}", t.value
SELECT t.res_id, m."{field.name}", t.value, t.noupdate
FROM t
JOIN "{Model._table}" m ON t.res_id = m.id
""", [translation_name])
for id_, old_values, translations in cr.fetchall():
if not old_values:
""", [translation_name, Model._name])
for id_, new_translations, translations, noupdate in cr.fetchall():
if not new_translations:
continue
# 'old_values' contain terms possibly updated from PO files during
# the upgrade of modules; prefer those terms over the ones from
# the out-of-date 'translations' dict
src_value = old_values.pop('en_US')
# new_translations contains translations updated from the latest po files
src_value = new_translations.pop('en_US')
src_terms = field.get_trans_terms(src_value)
for lang, dst_value in old_values.items():
for lang, dst_value in new_translations.items():
terms_mapping = translations.setdefault(lang, {})
dst_terms = field.get_trans_terms(dst_value)
for src_term, dst_term in zip(src_terms, dst_terms):
if src_term != dst_term:
if src_term == dst_term or noupdate:
terms_mapping.setdefault(src_term, dst_term)
else:
terms_mapping[src_term] = dst_term
new_values = {
lang: field.translate(terms_mapping.get, src_value)