diff --git a/odoo/addons/base/models/ir_http.py b/odoo/addons/base/models/ir_http.py index b89a846110b..1dbb94cca5b 100644 --- a/odoo/addons/base/models/ir_http.py +++ b/odoo/addons/base/models/ir_http.py @@ -29,7 +29,7 @@ from odoo.exceptions import AccessDenied, AccessError, MissingError from odoo.http import request, Response, ROUTING_KEYS, Stream from odoo.modules.registry import Registry from odoo.service import security -from odoo.tools import consteq, submap +from odoo.tools import get_lang, submap from odoo.tools.translate import code_translations from odoo.modules.module import get_resource_path, get_module_path @@ -144,6 +144,11 @@ class IrHttp(models.AbstractModel): if isinstance(val, models.BaseModel) and isinstance(val._uid, RequestUID): args[key] = val.with_user(request.env.uid) + # verify the default language set in the context is valid, + # otherwise fallback on the company lang, english or the first + # lang installed + request.update_context(lang=get_lang(request.env)._get_cached('code')) + @classmethod def _dispatch(cls, endpoint): result = endpoint(**request.params) diff --git a/odoo/addons/test_http/controllers.py b/odoo/addons/test_http/controllers.py index 242174ab1bc..9933c0862f6 100644 --- a/odoo/addons/test_http/controllers.py +++ b/odoo/addons/test_http/controllers.py @@ -67,6 +67,10 @@ class TestHttp(http.Controller): def echo_http_csrf(self, **kwargs): return str(kwargs) + @http.route('/test_http/echo-http-context-lang', type='http', auth='public', methods=['GET'], csrf=False) + def echo_http_context_lang(self, **kwargs): + return request.env.context.get('lang', '') + @http.route('/test_http/echo-json', type='json', auth='none', methods=['POST'], csrf=False) def echo_json(self, **kwargs): return kwargs diff --git a/odoo/addons/test_http/tests/test_session.py b/odoo/addons/test_http/tests/test_session.py index 6a0ea900745..647dc744a8c 100644 --- a/odoo/addons/test_http/tests/test_session.py +++ b/odoo/addons/test_http/tests/test_session.py @@ -88,3 +88,46 @@ class TestHttpSession(TestHttpBase): res = self.multidb_url_open('/test_http/greeting-user') res.raise_for_status() self.assertEqual(res.status_code, 200, "Should not be redirected to /web/login") + + def test_session5_default_lang(self): + self.env['res.lang']._activate_lang('en_US') # default lang + lang_fr = self.env['res.lang']._activate_lang('fr_FR') + + with self.subTest(case='no preferred lang'): + res = self.url_open('/test_http/echo-http-context-lang') + self.assertEqual(res.text, 'en_US') + + with self.subTest(case='fr preferred and fr_FR enabled'): + res = self.url_open('/test_http/echo-http-context-lang', headers={ + 'Accept-Language': 'fr', + }) + self.assertEqual(res.text, 'fr_FR') + + with self.subTest(case='fr preferred but fr_FR disabled'): + lang_fr.active = False + res = self.url_open('/test_http/echo-http-context-lang', headers={ + 'Accept-Language': 'fr', + }) + self.assertEqual(res.text, 'en_US') + + def test_session6_saved_lang(self): + session = self.authenticate('demo', 'demo') + self.env['res.lang']._activate_lang('en_US') # default lang + lang_fr = self.env['res.lang']._activate_lang('fr_FR') + + with self.subTest(case='no saved lang'): + res = self.url_open('/test_http/echo-http-context-lang') + self.assertEqual(res.text, 'en_US') + + with self.subTest(case='fr saved and fr_FR enabled'): + session.context['lang'] = 'fr_FR' + odoo.http.root.session_store.save(session) + res = self.url_open('/test_http/echo-http-context-lang') + self.assertEqual(res.text, 'fr_FR') + + with self.subTest(case='fr saved but fr_FR disabled'): + session['lang'] = 'fr_FR' + odoo.http.root.session_store.save(session) + lang_fr.active = False + res = self.url_open('/test_http/echo-http-context-lang') + self.assertEqual(res.text, 'en_US') diff --git a/odoo/tools/misc.py b/odoo/tools/misc.py index 3b2b0b95656..979ea936cbf 100644 --- a/odoo/tools/misc.py +++ b/odoo/tools/misc.py @@ -1312,14 +1312,14 @@ def get_lang(env, lang_code=False): """ Retrieve the first lang object installed, by checking the parameter lang_code, the context and then the company. If no lang is installed from those variables, - fallback on the first lang installed in the system. + fallback on english or on the first lang installed in the system. :param env: :param str lang_code: the locale (i.e. en_US) :return res.lang: the first lang found that is installed on the system. """ langs = [code for code, _ in env['res.lang'].get_installed()] - lang = langs[0] + lang = 'en_US' if 'en_US' in langs else langs[0] if lang_code and lang_code in langs: lang = lang_code elif env.context.get('lang') in langs: