[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.
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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': '/'
|
||||
})
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user