diff --git a/odoo/addons/base/models/ir_translation.py b/odoo/addons/base/models/ir_translation.py index 2639d258347..60616552967 100644 --- a/odoo/addons/base/models/ir_translation.py +++ b/odoo/addons/base/models/ir_translation.py @@ -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) diff --git a/odoo/addons/test_translation_import/i18n/fr_BE.po b/odoo/addons/test_translation_import/i18n/fr_BE.po new file mode 100644 index 00000000000..1d41cc94dcb --- /dev/null +++ b/odoo/addons/test_translation_import/i18n/fr_BE.po @@ -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 "" diff --git a/odoo/addons/test_translation_import/tests/test_term_count.py b/odoo/addons/test_translation_import/tests/test_term_count.py index 7e224bfdd7b..8a4976e1771 100644 --- a/odoo/addons/test_translation_import/tests/test_term_count.py +++ b/odoo/addons/test_translation_import/tests/test_term_count.py @@ -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') diff --git a/odoo/tools/translate.py b/odoo/tools/translate.py index cb672b9d3b4..3854e9436d4 100644 --- a/odoo/tools/translate.py +++ b/odoo/tools/translate.py @@ -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']