[FIX] translate.py: fallback on base lang if noterm

When there is a language and its base language translation files in a
module, in 12.0 an empty translation in the language translation file
will not fallback on the base language.

eg.

 fr.po : {'one': 'un', 'seventy': 'soixante-dix'}
 fr_BE.po: {'one': '', 'seventy': 'septante'}

 => the translation in fr_BE will be {'one': '', 'seventy': 'septante'}

 but before 7288b477 it would have been {'one': 'un', 'seventy': 'septante'}

With this commit, an empty translation is no longer created so does not
override base language.

Also the intention of d84b795b0a that was also lost is restored by
upserting only noupdate==false translation, and inserting the other
ones.

opw-1904638
closes #28297
This commit is contained in:
Nicolas Lempereur
2018-11-07 09:07:02 +00:00
parent d63e72853b
commit 233bae7de9
4 changed files with 96 additions and 19 deletions
+14 -9
View File
@@ -132,20 +132,23 @@ class IrTranslationImport(object):
if hasattr(field, 'translate') and callable(field.translate):
src_relevant_fields.append("%s,%s" % (model, field_name))
# Step 2: insert new or upsert translations
count = 0
# Step 2: insert new or upsert non-noupdate translations
if self._overwrite:
cr.execute(""" INSERT INTO %s(name, lang, res_id, src, type, value, module, state, comments)
SELECT name, lang, res_id, src, type, value, module, state, comments
FROM %s
WHERE type = 'code'
AND noupdate IS NOT TRUE
ON CONFLICT (type, lang, md5(src)) WHERE type = 'code'
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);
""" % (self._model_table, self._table))
count = cr.rowcount
count += cr.rowcount
cr.execute(""" INSERT INTO %s(name, lang, res_id, src, type, value, module, state, comments)
SELECT name, lang, res_id, src, type, value, module, state, comments
FROM %s
WHERE type = 'model'
AND noupdate IS NOT TRUE
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);
""" % (self._model_table, self._table))
@@ -154,6 +157,7 @@ class IrTranslationImport(object):
SELECT name, lang, res_id, src, type, value, module, state, comments
FROM %s
WHERE type IN ('selection', 'constraint', 'sql_constraint')
AND noupdate IS NOT TRUE
ON CONFLICT (type, lang, name, md5(src)) WHERE type IN ('selection', 'constraint', 'sql_constraint')
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);
""" % (self._model_table, self._table))
@@ -162,17 +166,18 @@ class IrTranslationImport(object):
SELECT name, lang, res_id, src, type, value, module, state, comments
FROM %s
WHERE type = 'model_terms'
AND noupdate IS NOT TRUE
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);
""" % (self._model_table, self._table))
count += cr.rowcount
else:
cr.execute(""" INSERT INTO %s(name, lang, res_id, src, type, value, module, state, comments)
SELECT name, lang, res_id, src, type, value, module, state, comments
FROM %s
ON CONFLICT DO NOTHING;
""" % (self._model_table, self._table))
count = cr.rowcount
cr.execute(""" INSERT INTO %s(name, lang, res_id, src, type, value, module, state, comments)
SELECT name, lang, res_id, src, type, value, module, state, comments
FROM %s
WHERE %s
ON CONFLICT DO NOTHING;
""" % (self._model_table, self._table, 'noupdate IS TRUE' if self._overwrite else 'TRUE'))
count += cr.rowcount
if self._debug:
cr.execute("SELECT COUNT(*) FROM ONLY %s" % self._model_table)
@@ -0,0 +1,35 @@
# This is a test PO file, not a true french translation.
# See the POT file for further information.
msgid ""
msgstr ""
"Project-Id-Version: OpenERP Server 6.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-10-17 12:36+0000\n"
"PO-Revision-Date: 2012-10-17 12:36+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: test_translation_import
#: code:addons/test_translation_import/models.py:14
#, python-format
msgid "Ijkl"
msgstr "Ijkl in belgian french"
#. module: test_translation_import
#: model:ir.model,name:test_translation_import.model_test_translation_import
msgid "test.translation.import"
msgstr "test.translation.import in belgian french"
#. module: test_translation_import
#: model:ir.model.fields,help:test_translation_import.field_test_translation_import__name
msgid "Efgh"
msgstr ""
#. module: test_translation_import
#: code:addons/base/models/ford.py:43
msgid "Test translation with a code type but different line number in pot"
msgstr ""
@@ -17,8 +17,10 @@ class TestTermCount(common.TransactionCase):
Just make sure we have as many translation entries as we wanted.
"""
odoo.tools.trans_load(self.cr, 'test_translation_import/i18n/fr.po', 'fr_FR', module_name='test_translation_import', verbose=False)
ids = self.env['ir.translation'].search(
[('src', '=', '1XBUO5PUYH2RYZSA1FTLRYS8SPCNU1UYXMEYMM25ASV7JC2KTJZQESZYRV9L8CGB')])
ids = self.env['ir.translation'].search([
('lang', '=', 'fr_FR'),
('src', '=', '1XBUO5PUYH2RYZSA1FTLRYS8SPCNU1UYXMEYMM25ASV7JC2KTJZQESZYRV9L8CGB'),
])
self.assertEqual(len(ids), 2)
def test_noupdate(self):
@@ -34,25 +36,56 @@ class TestTermCount(common.TransactionCase):
odoo.tools.trans_load(self.cr, 'test_translation_import/i18n/fr.po', 'fr_FR', module_name='test_translation_import', verbose=False, context={'overwrite': True})
# trans_load invalidates ormcache but not record cache
menu.clear_caches()
menu.env.cache.invalidate()
self.assertEqual(menu.name, "New Name")
self.assertEqual(menu.with_context(lang='fr_FR').name, "Nouveau nom")
def test_lang_with_base(self):
odoo.tools.trans_load(self.cr, 'test_translation_import/i18n/fr.po', 'fr_BE', module_name='test_translation_import', verbose=False)
odoo.tools.trans_load(self.cr, 'test_translation_import/i18n/fr_BE.po', 'fr_BE', module_name='test_translation_import', verbose=False, context={'overwrite': True})
# language override base language
translations = self.env['ir.translation'].search([
('lang', '=', 'fr_BE'),
('value', '=like', '% belgian french'),
])
self.assertEqual(len(translations), 2)
# not specified localized language fallback on base language
translations = self.env['ir.translation'].search([
('lang', '=', 'fr_BE'),
('src', '=', 'Efgh'),
('value', '=', 'Efgh in french'),
])
self.assertEqual(len(translations), 1)
translations = self.env['ir.translation'].search([
('lang', '=', 'fr_BE'),
('src', '=', 'Test translation with a code type but different line number in pot'),
('value', '=', 'Test traduction avec un type code mais différent numéro de ligne dans le pot'),
])
self.assertEqual(len(translations), 1)
def test_no_duplicate(self):
"""
Just make sure we do not create duplicated translation with 'code' type
"""
odoo.tools.trans_load(self.cr, 'test_translation_import/i18n/fr.po', 'fr_FR', module_name='test_translation_import', verbose=False)
ids = self.env['ir.translation'].search(
[('src', '=', 'Test translation with two code lines')])
ids = self.env['ir.translation'].search([
('lang', '=', 'fr_FR'),
('src', '=', 'Test translation with two code lines'),
])
self.assertEqual(len(ids), 1)
ids = self.env['ir.translation'].search(
[('src', '=', 'Test translation with a code type but different line number in pot')])
ids = self.env['ir.translation'].search([
('lang', '=', 'fr_FR'),
('src', '=', 'Test translation with a code type but different line number in pot'),
])
self.assertEqual(len(ids), 1)
ids = self.env['ir.translation'].search(
[('src', '=', 'Test translation with two code type and model')])
ids = self.env['ir.translation'].search([
('lang', '=', 'fr_FR'),
('src', '=', 'Test translation with two code type and model'),
])
self.assertEqual(len(ids), 2)
self.assertEqual(len(ids.filtered(lambda t: t.type == 'code')), 1)
@@ -68,7 +101,7 @@ class TestTermCount(common.TransactionCase):
# Check if the not translated key is empty string
update_translations()
translation = self.env['ir.translation'].search_count([('src', '=', 'Efgh'), ('value', '=', '')])
self.assertTrue(translation, 'The translation of "Efgh" should be empty')
self.assertFalse(translation, 'An empty translation is not imported')
# Modify the value translated for the equal value of the key
menu = self.env.ref('test_translation_import.menu_test_translation_import')
+4
View File
@@ -1102,6 +1102,10 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True,
dic['lang'] = lang
dic.update(pycompat.izip(fields, row))
# ignore empty value that may be set from base language
if not dic['value']:
return
if use_pot_reference:
# discard the target from the POT targets.
src = dic['src']