Skip to content

Commit d8a5585

Browse files
committed
[FIX] Preserve all translated fields on v16 migration
Currently, the upgrade process preserves translations only for Odoo CE+EE fields. However, databases usually have more modules (or even custom fields) and those translations get lost when upgrading to Odoo 16. With this script, all translated fields will inherit their translations in all languages. Since it is executed in the `pre` phase of `base`, it should be able to still find the `ir_translation` table. @moduon MT-7120
1 parent c8c1a6e commit d8a5585

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""Store ir.translation records in jsonb fields."""
2+
3+
import logging
4+
5+
from psycopg2.errors import InvalidTableDefinition
6+
from psycopg2.extras import Json
7+
from psycopg2.sql import SQL, Identifier
8+
9+
from odoo.upgrade import util
10+
11+
_logger = logging.getLogger(__name__)
12+
13+
14+
def migrate(cr, version):
15+
already_converted = set()
16+
missing_tables = set()
17+
missing_columns = set()
18+
cr.execute(
19+
"""
20+
SELECT name, res_id, src, jsonb_agg(lang) AS langs, jsonb_agg(value) AS values
21+
FROM ir_translation
22+
WHERE res_id != 0 AND type = 'model' AND state in ('translated', 'to_translate')
23+
GROUP BY name, res_id, src
24+
ORDER BY src IS NOT NULL
25+
"""
26+
)
27+
for name, res_id, src, langs, values in cr.fetchall():
28+
# Build a dict with all translations
29+
all_values = dict(zip(langs, values), en_US=src)
30+
if not all_values["en_US"]:
31+
all_values["en_US"] = all_values[langs[0]]
32+
# Find the translation target table and column
33+
model, field = name.split(",")
34+
table = util.table_of_model(cr, model)
35+
# Skip early if the translation is no longer usable
36+
if not util.table_exists(cr, table):
37+
missing_tables.add(table)
38+
continue
39+
if not util.column_exists(cr, table, field):
40+
missing_columns.add("{}.{}".format(table, field))
41+
continue
42+
# Make sure the field is translatable in JSONB format (noop if done already)
43+
if (model, field) not in already_converted:
44+
already_converted.add((model, field))
45+
try:
46+
with cr.savepoint():
47+
util.convert_field_to_translatable(cr, model, field)
48+
except InvalidTableDefinition:
49+
_logger.debug("Couldn't convert %s.%s to jsonb", table, field, exc_info=True)
50+
_logger.info("Skipping translation recovery for %s.%s", table, field)
51+
# Store updated translation
52+
cr.execute(
53+
SQL("UPDATE {table} SET {field} = %s WHERE id = %s").format(
54+
table=Identifier(table),
55+
field=Identifier(field),
56+
),
57+
(Json(all_values), res_id),
58+
)
59+
# Log missing tables and columns
60+
if missing_tables:
61+
_logger.warning(
62+
"Couldn't recover translation for these missing tables: %s",
63+
", ".join(sorted(missing_tables)),
64+
)
65+
if missing_columns:
66+
_logger.warning(
67+
"Couldn't recover translation for these missing columns: %s",
68+
", ".join(sorted(missing_columns)),
69+
)

0 commit comments

Comments
 (0)