diff options
| author | Martin Trigaux <mat@odoo.com> | 2019-10-16 12:05:02 +0200 |
|---|---|---|
| committer | Martin Trigaux <mat@odoo.com> | 2019-11-19 10:37:01 +0100 |
| commit | 49fbab5329fb95e759c3f90d4e9efb1717a9695c (patch) | |
| tree | 5ced82c181feb5f9155b27f7ac2aca7b824080c6 | |
| parent | 7bf6992869804973b41a785037fc176cd608320e (diff) | |
[IMP] base: split and deprecate load_lang
load_lang was a kind of hybrid method trying to active or creating a
language if not found. This was error prone.
Instead rely on two methods with clear purpose:
ResLang._create_lang(lang, lang_name=None)
- create a new res.lang entry using the locale of the server
return the res.lang record to match the API of _activate_lang
ResLang._active_lang(code)
- activate the given code lang
Most of the time, _active_lang is what is expected
tools.trans_load_data and IrTranslation._load_module_terms no longer
activate the language if not active.
Loading the translations should be explicit on an activated language,
it is too error prone to silently activate/create a language if not
found.
Remove lang_name from trans_load_data as no longer needed.
23 files changed, 64 insertions, 48 deletions
diff --git a/addons/test_mail_full/tests/test_sms_composer.py b/addons/test_mail_full/tests/test_sms_composer.py index 060863e4f02..5e0f74fe1b5 100644 --- a/addons/test_mail_full/tests/test_sms_composer.py +++ b/addons/test_mail_full/tests/test_sms_composer.py @@ -368,7 +368,7 @@ class TestSMSComposerMass(test_mail_full_common.BaseFunctionalTest, sms_common.M self.assertSMSOutgoing(record.customer_id, None, 'Dear %s this is an SMS.' % record.display_name) def test_composer_mass_active_ids_w_template_and_lang(self): - self.env.ref('base.lang_fr').write({'active': True}) + self.env['res.lang']._activate_lang('fr_FR') self.env['ir.translation'].create({ 'type': 'model', 'name': 'sms.template,body', @@ -425,7 +425,7 @@ class TestSMSComposerMass(test_mail_full_common.BaseFunctionalTest, sms_common.M """ Test the context action from a SMS template (Add context action button) and the usage with the sms composer """ # Create the lang info - self.env.ref('base.lang_fr').write({'active': True}) + self.env['res.lang']._activate_lang('fr_FR') self.env['ir.translation'].create({ 'type': 'model', 'name': 'sms.template,body', diff --git a/addons/test_mail_full/tests/test_sms_template.py b/addons/test_mail_full/tests/test_sms_template.py index a1c754511ab..ec5b7cf9f39 100644 --- a/addons/test_mail_full/tests/test_sms_template.py +++ b/addons/test_mail_full/tests/test_sms_template.py @@ -25,7 +25,7 @@ class TestSmsTemplate(test_mail_full_common.BaseFunctionalTest, sms_common.MockS self.assertEqual(rendered_body[self.test_record.id], 'Dear %s this is an SMS.' % self.test_record.display_name) def test_sms_template_lang(self): - self.env.ref('base.lang_fr').write({'active': True}) + self.env['res.lang']._activate_lang('fr_FR') self.user_admin.write({'lang': 'en_US'}) self.env['ir.translation'].create({ 'type': 'model', diff --git a/addons/website/tests/test_base_url.py b/addons/website/tests/test_base_url.py index 18d296f38e9..c14a6bc34e9 100644 --- a/addons/website/tests/test_base_url.py +++ b/addons/website/tests/test_base_url.py @@ -15,8 +15,7 @@ class TestUrlCommon(odoo.tests.HttpCase): 'domain': self.domain, }) - lang_fr = self.env.ref('base.lang_fr') - lang_fr.write({'active': True}) + lang_fr = self.env['res.lang']._activate_lang('fr_FR') self.website.language_ids = self.env.ref('base.lang_en') + lang_fr self.website.default_lang_id = self.env.ref('base.lang_en') diff --git a/addons/website/tests/test_lang_url.py b/addons/website/tests/test_lang_url.py index 1c08b866fa4..8e0f5c78da9 100644 --- a/addons/website/tests/test_lang_url.py +++ b/addons/website/tests/test_lang_url.py @@ -13,8 +13,8 @@ class TestLangUrl(HttpCase): # Simulate multi lang without loading translations self.website = self.env.ref('website.default_website') - lang_fr = self.env.ref('base.lang_fr') - lang_fr.write({'active': True, 'url_code': 'fr'}) + lang_fr = self.env['res.lang']._activate_lang('fr_FR') + lang_fr.write({'url_code': 'fr'}) self.website.language_ids = self.env.ref('base.lang_en') + lang_fr self.website.default_lang_id = self.env.ref('base.lang_en') diff --git a/addons/website/tests/test_qweb.py b/addons/website/tests/test_qweb.py index 1c2c1dbe573..99f53078310 100644 --- a/addons/website/tests/test_qweb.py +++ b/addons/website/tests/test_qweb.py @@ -73,7 +73,7 @@ class TestQwebProcessAtt(TransactionCase): def setUp(self): super(TestQwebProcessAtt, self).setUp() self.website = self.env.ref('website.default_website') - self.env.ref('base.lang_fr').active = True + self.env['res.lang']._activate_lang('fr_FR') self.website.language_ids = self.env.ref('base.lang_en') + self.env.ref('base.lang_fr') self.website.default_lang_id = self.env.ref('base.lang_en') self.website.cdn_activated = True diff --git a/odoo/addons/base/models/ir_translation.py b/odoo/addons/base/models/ir_translation.py index caf6be2a4a5..cc8ef945cde 100644 --- a/odoo/addons/base/models/ir_translation.py +++ b/odoo/addons/base/models/ir_translation.py @@ -781,10 +781,6 @@ class IrTranslation(models.Model): def _load_module_terms(self, modules, langs): """ Load PO files of the given modules for the given languages. """ - # make sure the given languages are active - res_lang = self.env['res.lang'].sudo() - for lang in langs: - res_lang.load_lang(lang) # load i18n files for module_name in modules: modpath = get_module_path(module_name) diff --git a/odoo/addons/base/models/res_lang.py b/odoo/addons/base/models/res_lang.py index eccb6b09c93..15e475addeb 100644 --- a/odoo/addons/base/models/res_lang.py +++ b/odoo/addons/base/models/res_lang.py @@ -88,15 +88,24 @@ class Lang(models.Model): if not self.search_count([]): _logger.error("No language is active.") - @api.model + # TODO remove me after v14 def load_lang(self, lang, lang_name=None): - """ Create the given language if necessary, and make it active. """ - # if the language exists, simply make it active - language = self.with_context(active_test=False).search([('code', '=', lang)], limit=1) - if language: - language.write({'active': True}) - return language.id + _logger.warning("Call to deprecated method load_lang, use _create_lang or _activate_lang instead") + language = self._activate_lang(lang) or self._create_lang(lang, lang_name) + return language.id + + def _activate_lang(self, code): + """ Activate languages + :param code: code of the language to activate + :return: the language matching 'code' activated + """ + lang = self.with_context(active_test=False).search([('code', '=', code)]) + if lang and not lang.active: + lang.active = True + return lang + def _create_lang(self, lang, lang_name=None): + """ Create the given language and make it active. """ # create the language with locale information fail = True iso_lang = tools.get_iso_codes(lang) @@ -149,7 +158,7 @@ class Lang(models.Model): 'grouping' : str(conv.get('grouping', [])), } try: - return self.create(lang_info).id + return self.create(lang_info) finally: tools.resetlocale() @@ -166,9 +175,7 @@ class Lang(models.Model): """ # config['load_language'] is a comma-separated list or None lang_code = (tools.config.get('load_language') or 'en_US').split(',')[0] - lang = self._lang_get(lang_code) - if not lang: - self.load_lang(lang_code) + lang = self._activate_lang(lang_code) or self._create_lang(lang_code) IrDefault = self.env['ir.default'] default_value = IrDefault.get('res.partner', 'lang') if default_value is None: diff --git a/odoo/addons/base/tests/test_expression.py b/odoo/addons/base/tests/test_expression.py index 61d470e094c..28103e9e474 100644 --- a/odoo/addons/base/tests/test_expression.py +++ b/odoo/addons/base/tests/test_expression.py @@ -672,6 +672,7 @@ class TestExpression(SavepointCaseWithUserDemo): def test_lp1071710(self): """ Check that we can exclude translated fields (bug lp:1071710) """ # first install french language + self.env['res.lang']._activate_lang('fr_FR') self.env['ir.translation']._load_module_terms(['base'], ['fr_FR']) self.env['res.partner'].search([('name', '=', 'Pepper Street')]).country_id = self.env.ref('base.be') # actual test diff --git a/odoo/addons/base/tests/test_misc.py b/odoo/addons/base/tests/test_misc.py index 29d0a021558..5276b2ed6f0 100644 --- a/odoo/addons/base/tests/test_misc.py +++ b/odoo/addons/base/tests/test_misc.py @@ -220,7 +220,8 @@ class TestFormatLangDate(TransactionCase): lang = self.env['res.lang'] # Activate French and Simplified Chinese (test with non-ASCII characters) - lang.search([('active', '=', False), ('code', 'in', ['fr_FR', 'zh_CN'])]).write({'active': True}) + lang._activate_lang('fr_FR') + lang._activate_lang('zh_CN') # -- test `date` # Change a single parameter diff --git a/odoo/addons/base/tests/test_qweb.py b/odoo/addons/base/tests/test_qweb.py index 13b95926f47..780dc6a0cc5 100644 --- a/odoo/addons/base/tests/test_qweb.py +++ b/odoo/addons/base/tests/test_qweb.py @@ -522,10 +522,8 @@ class TestQWebNS(TransactionCase): current_lang = 'en_US' other_lang = 'fr_FR' - self.env['res.lang'].load_lang(lang=other_lang) - - self.env['res.lang']._lang_get(other_lang).write({ - 'active': True, + lang = self.env['res.lang']._activate_lang(other_lang) + lang.write({ 'decimal_point': '*', 'thousands_sep': '/' }) diff --git a/odoo/addons/base/tests/test_translate.py b/odoo/addons/base/tests/test_translate.py index 12c3f8b2d96..411aa82f1f1 100644 --- a/odoo/addons/base/tests/test_translate.py +++ b/odoo/addons/base/tests/test_translate.py @@ -247,6 +247,7 @@ class TestTranslation(TransactionCase): def setUp(self): super(TestTranslation, self).setUp() + lang = self.env['res.lang']._activate_lang('fr_FR') self.env['ir.translation']._load_module_terms(['base'], ['fr_FR']) self.customers = self.env['res.partner.category'].create({'name': 'Customers'}) self.env['ir.translation'].create({ @@ -436,7 +437,7 @@ class TestTranslationWrite(TransactionCase): self.assertEqual(source_name[0]['name'], "English Name", "Reference field not updated") def test_03_fr_single(self): - self.env['res.lang'].load_lang('fr_FR') + self.env['res.lang']._activate_lang('fr_FR') self.env['res.users'].with_context(active_test=False).search([]).write({'lang': 'fr_FR'}) self.env.ref('base.lang_en').active = False @@ -454,7 +455,7 @@ class TestTranslationWrite(TransactionCase): self.assertEqual(len(translations), 0, "No French translation should be created when writing in French") def test_04_fr_multi(self): - self.env['res.lang'].load_lang('fr_FR') + self.env['res.lang']._activate_lang('fr_FR') langs = self.env['res.lang'].get_installed() self.assertEqual([('en_US', 'English (US)'), ('fr_FR', 'French / Français')], langs, @@ -481,9 +482,9 @@ class TestTranslationWrite(TransactionCase): ]) def test_04_fr_multi_no_en(self): - self.env['res.lang'].load_lang('fr_FR') + self.env['res.lang']._activate_lang('fr_FR') + self.env['res.lang']._activate_lang('es_ES') self.env['res.users'].with_context(active_test=False).search([]).write({'lang': 'fr_FR'}) - self.env['res.lang'].load_lang('es_ES') self.env.ref('base.lang_en').active = False langs = self.env['res.lang'].get_installed() @@ -504,7 +505,7 @@ class TestTranslationWrite(TransactionCase): ]) def test_05_remove_multi(self): - self.env['res.lang'].load_lang('fr_FR') + self.env['res.lang']._activate_lang('fr_FR') langs = self.env['res.lang'].get_installed() self.assertEqual([('en_US', 'English (US)'), ('fr_FR', 'French / Français')], langs, @@ -576,6 +577,8 @@ class TestTranslationWrite(TransactionCase): class TestXMLTranslation(TransactionCase): def setUp(self): super(TestXMLTranslation, self).setUp() + self.env['res.lang']._activate_lang('fr_FR') + self.env['res.lang']._activate_lang('nl_NL') self.env['ir.translation']._load_module_terms(['base'], ['fr_FR', 'nl_NL']) def create_view(self, archf, terms, **kwargs): diff --git a/odoo/addons/base/tests/test_views.py b/odoo/addons/base/tests/test_views.py index 4440ac4a1eb..14e5786a937 100644 --- a/odoo/addons/base/tests/test_views.py +++ b/odoo/addons/base/tests/test_views.py @@ -606,7 +606,7 @@ class TestNoModel(ViewCase): """ Test if translations work correctly without a model """ - self.env['res.lang'].load_lang('fr_FR') + self.env['res.lang']._activate_lang('fr_FR') ARCH = '<template name="foo">%s</template>' TEXT_EN = "Copyright copyrighter" TEXT_FR = u"Copyrighter, tous droits réservés" diff --git a/odoo/addons/base/wizard/base_import_language.py b/odoo/addons/base/wizard/base_import_language.py index 461c95958c3..8a0992f2380 100644 --- a/odoo/addons/base/wizard/base_import_language.py +++ b/odoo/addons/base/wizard/base_import_language.py @@ -37,8 +37,12 @@ class BaseLanguageImport(models.TransientModel): buf.seek(0) fileformat = os.path.splitext(this.filename)[-1][1:].lower() - tools.trans_load_data(this._cr, buf, fileformat, this.code, - lang_name=this.name, context=this._context) + Lang = self.env["res.lang"] + lang = Lang._activate_lang(self.code) or Lang._create_lang( + self.code, lang_name=self.name + ) + + tools.trans_load_data(this._cr, buf, fileformat, this.code, context=this._context) except Exception as e: _logger.exception('File unsuccessfully imported, due to format mismatch.') raise UserError( diff --git a/odoo/addons/base/wizard/base_language_install.py b/odoo/addons/base/wizard/base_language_install.py index e8bd93991ac..07d9a6dd110 100644 --- a/odoo/addons/base/wizard/base_language_install.py +++ b/odoo/addons/base/wizard/base_language_install.py @@ -33,6 +33,7 @@ class BaseLanguageInstall(models.TransientModel): def lang_install(self): self.ensure_one() mods = self.env['ir.module.module'].search([('state', '=', 'installed')]) + self.env['res.lang']._activate_lang(self.lang) mods.with_context(overwrite=self.overwrite)._update_translations(self.lang) self.state = 'done' self.env.cr.execute('ANALYZE ir_translation') diff --git a/odoo/addons/base/wizard/base_update_translations.py b/odoo/addons/base/wizard/base_update_translations.py index bfe94fcb3a6..7cdc05d3c95 100644 --- a/odoo/addons/base/wizard/base_update_translations.py +++ b/odoo/addons/base/wizard/base_update_translations.py @@ -27,9 +27,8 @@ class BaseUpdateTranslations(models.TransientModel): def act_update(self): this = self[0] - lang_name = self._get_lang_name(this.lang) with tempfile.NamedTemporaryFile() as buf: tools.trans_export(this.lang, ['all'], buf, 'po', self._cr) context = {'create_empty_translation': True} - tools.trans_load_data(self._cr, buf, 'po', this.lang, lang_name=lang_name, context=context) + tools.trans_load_data(self._cr, buf, 'po', this.lang, context=context) return {'type': 'ir.actions.act_window_close'} diff --git a/odoo/addons/test_assetsbundle/tests/test_assetsbundle.py b/odoo/addons/test_assetsbundle/tests/test_assetsbundle.py index 98b0e00dd45..c38245eb19e 100644 --- a/odoo/addons/test_assetsbundle/tests/test_assetsbundle.py +++ b/odoo/addons/test_assetsbundle/tests/test_assetsbundle.py @@ -33,7 +33,7 @@ class TestJavascriptAssetsBundle(FileTouchable): super(TestJavascriptAssetsBundle, self).setUp() self.jsbundle_xmlid = 'test_assetsbundle.bundle1' self.cssbundle_xmlid = 'test_assetsbundle.bundle2' - self.env['res.lang'].load_lang('ar_SY') + self.env['res.lang']._activate_lang('ar_SY') def _get_asset(self, xmlid, env=None): diff --git a/odoo/addons/test_converter/tests/test_html.py b/odoo/addons/test_converter/tests/test_html.py index cf3f4c198ec..5bae2a063d7 100644 --- a/odoo/addons/test_converter/tests/test_html.py +++ b/odoo/addons/test_converter/tests/test_html.py @@ -291,7 +291,7 @@ class TestDurationExport(TestBasicExport): def setUp(self): super(TestDurationExport, self).setUp() # needs to have lang installed otherwise falls back on en_US - self.env['res.lang'].load_lang('fr_FR') + self.env['res.lang']._activate_lang('fr_FR') def test_default_unit(self): converter = self.get_converter('float', 'duration') @@ -332,7 +332,7 @@ class TestRelativeDatetime(TestBasicExport): def setUp(self): super(TestRelativeDatetime, self).setUp() # needs to have lang installed otherwise falls back on en_US - self.env['res.lang'].load_lang('fr_FR') + self.env['res.lang']._activate_lang('fr_FR') def test_basic(self): converter = self.get_converter('datetime', 'relative') diff --git a/odoo/addons/test_impex/tests/test_export.py b/odoo/addons/test_impex/tests/test_export.py index 28a1c7472bd..3d76ec925e6 100644 --- a/odoo/addons/test_impex/tests/test_export.py +++ b/odoo/addons/test_impex/tests/test_export.py @@ -285,7 +285,7 @@ class test_selection(CreatorCase): [[u"Bar"]]) def test_localized_export(self): - self.env['res.lang'].load_lang('fr_FR') + self.env['res.lang']._activate_lang('fr_FR') ir_field = self.env['ir.model.fields']._get('export.selection', 'value') selection = ir_field.selection_ids translations = dict(self.translations_fr) diff --git a/odoo/addons/test_impex/tests/test_load.py b/odoo/addons/test_impex/tests/test_load.py index d2bd80f7e56..35a3b55d31b 100644 --- a/odoo/addons/test_impex/tests/test_load.py +++ b/odoo/addons/test_impex/tests/test_load.py @@ -73,7 +73,7 @@ class ImporterCase(common.TransactionCase): return '__test__.' + name def add_translations(self, name, type, code, *tnx): - self.env['res.lang'].load_lang(code) + self.env['res.lang']._activate_lang(code) Translations = self.env['ir.translation'] for source, value in tnx: Translations.create({ diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py index 1bc0bc78f76..b68ae8220fb 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -1412,7 +1412,7 @@ class TestFields(TransactionCaseWithUserDemo): email = self.env.ref('test_new_api.emailmessage_0_0') self.assertEqual(email.message, message) - self.env['res.lang'].load_lang('fr_FR') + self.env['res.lang']._activate_lang('fr_FR') def count(msg): # return the number of translations of msg.label diff --git a/odoo/addons/test_new_api/tests/test_ui.py b/odoo/addons/test_new_api/tests/test_ui.py index 979bf8064a9..03c38c9b09d 100644 --- a/odoo/addons/test_new_api/tests/test_ui.py +++ b/odoo/addons/test_new_api/tests/test_ui.py @@ -27,6 +27,7 @@ class TestUiTranslation(odoo.tests.HttpCase): @mute_logger('odoo.sql_db', 'odoo.http') def test_01_sql_constraints(self): # Raise an SQL constraint and test the message + self.env['res.lang']._activate_lang('fr_FR') self.env['ir.translation']._load_module_terms(['test_new_api'], ['fr_FR']) constraint = self.env.ref('test_new_api.constraint_test_new_api_category_positive_color') message = constraint.with_context(lang='fr_FR').message 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 fb98e78661f..5eb4908eb65 100644 --- a/odoo/addons/test_translation_import/tests/test_term_count.py +++ b/odoo/addons/test_translation_import/tests/test_term_count.py @@ -18,6 +18,7 @@ class TestTermCount(common.TransactionCase): """ Just make sure we have as many translation entries as we wanted. """ + self.env['res.lang']._activate_lang('fr_FR') odoo.tools.trans_load(self.cr, 'test_translation_import/i18n/fr.po', 'fr_FR', module_name='test_translation_import', verbose=False) translations = self.env['ir.translation'].search([ ('lang', '=', 'fr_FR'), @@ -40,6 +41,7 @@ class TestTermCount(common.TransactionCase): """ Just make sure we have as many translation entries as we wanted and module deducted from file content """ + self.env['res.lang']._activate_lang('fr_FR') odoo.tools.trans_load(self.cr, 'test_translation_import/i18n/fr.po', 'fr_FR', verbose=False) translations = self.env['ir.translation'].search([ ('lang', '=', 'fr_FR'), @@ -56,6 +58,7 @@ class TestTermCount(common.TransactionCase): menu = self.env.ref('test_translation_import.menu_test_translation_import') menu.name = "New Name" # install french and change translation content + self.env['res.lang']._activate_lang('fr_FR') odoo.tools.trans_load(self.cr, 'test_translation_import/i18n/fr.po', 'fr_FR', module_name='test_translation_import', verbose=False) menu.with_context(lang='fr_FR').name = "Nouveau nom" # reload with overwrite @@ -67,6 +70,7 @@ class TestTermCount(common.TransactionCase): self.assertEqual(menu.with_context(lang='fr_FR').name, "Nouveau nom") def test_lang_with_base(self): + self.env['res.lang']._activate_lang('fr_BE') 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}) @@ -95,6 +99,7 @@ class TestTermCount(common.TransactionCase): """ Just make sure we do not create duplicated translation with 'code' type """ + self.env['res.lang']._activate_lang('fr_FR') 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([ ('lang', '=', 'fr_FR'), @@ -120,6 +125,7 @@ class TestTermCount(common.TransactionCase): # Export the translations def update_translations(context=None): context = dict(context or {}, overwrite=True) + self.env['res.lang']._activate_lang('fr_FR') with closing(io.BytesIO()) as bufferobj: odoo.tools.trans_export('fr_FR', ['test_translation_import'], bufferobj, 'po', self.cr) bufferobj.name = 'test_translation_import/i18n/fr.po' diff --git a/odoo/tools/translate.py b/odoo/tools/translate.py index e185f9c809c..cf40a326179 100644 --- a/odoo/tools/translate.py +++ b/odoo/tools/translate.py @@ -1046,7 +1046,7 @@ def trans_load(cr, filename, lang, verbose=True, module_name=None, context=None) return None -def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True, module_name=None, context=None): +def trans_load_data(cr, fileobj, fileformat, lang, verbose=True, module_name=None, context=None): """Populates the ir_translation table.""" if verbose: _logger.info('loading translation file for language %s', lang) @@ -1056,9 +1056,9 @@ def trans_load_data(cr, fileobj, fileformat, lang, lang_name=None, verbose=True, Translation = env['ir.translation'] try: - if not Lang.search_count([('code', '=', lang)]): - # lets create the language with locale information - Lang.load_lang(lang=lang, lang_name=lang_name) + if not Lang._lang_get(lang): + _logger.error("Couldn't read translation for lang '%s', language not found", lang) + return None # now, the serious things: we read the language file fileobj.seek(0) |
