Skip to content
Browse files

[FIX] website: language prefixed URL on website

In 10.0 and before, if we were eg. on website page /fr_FR/contact, if
`fr_FR` language (french) is installed and not the default website
language we would have all URL towards translated content (route with
multilang=True) prefixed with /fr_FR/ (the language code).

With 9cd982b some improvments were done to CDN but this also breaks
language prefixing, so this cause an unecessary redirect:

- we are on /fr_FR/contact and click on "Shop"
- we go to /shop
- odoo redirects US /fr_FR/shop

With this PR, URLs are prefixed with language once again.

note: the added test is hackish but the function tested depends on a lot
of odoo.http things that are hard to use for test (request.render,
request.context, request.httpreqest).

closes #31792
  • Loading branch information...
nle-odoo committed Mar 12, 2019
1 parent 3a0bedd commit e67f4fdb743a516b7dda0949b2ca95f153a033aa
Showing with 102 additions and 2 deletions.
  1. +8 −1 addons/website/models/
  2. +94 −1 addons/website/tests/
@@ -6,6 +6,7 @@
from odoo import models
from odoo.http import request

from odoo.addons.http_routing.models.ir_http import url_for

re_background_image = re.compile(r"(background-image\s*:\s*url\(\s*['\"]?\s*)([^)'\"]+)")

@@ -37,10 +38,16 @@ def _post_processing_att(self, tagName, atts, options):
if not website and options.get('website_id'):
website = self.env['website'].browse(options['website_id'])

if not website or not website.cdn_activated:
if not website:
return atts

name = self.URL_ATTRS.get(tagName)
if request and name and name in atts:
atts[name] = url_for(atts[name])

if not website.cdn_activated:
return atts

if name and name in atts:
atts = OrderedDict(atts)
atts[name] = website.get_cdn_url(atts[name])
@@ -3,11 +3,11 @@

import re

import odoo
from odoo import tools
from odoo.modules.module import get_module_resource
from odoo.tests.common import TransactionCase

class TestQweb(TransactionCase):
def _load(self, module, *args):
tools.convert_file(, 'website',
@@ -63,3 +63,96 @@ def test_qweb_cdn(self):
"css": attachments[1].url,

class MockObject(object):
def __init__(self, *args, **kwargs):
self.__dict__ = kwargs
def __call__(self, *args, **kwargs):
return self
def __getitem__(self, index):
return self

class MockRequest(object):
""" Class with context manager mocking odoo.http.request for tests """
def __init__(self, env, website=None, context=None, multilang=True):
app = MockObject(routing={
'type': 'http',
'website': True,
'multilang': multilang,
app.get_db_router = app.bind = app.match = app
self.request = MockObject(
env=env, context=context or {}, db=None, debug=False,
website=website, httprequest=MockObject(
def __enter__(self):
return self.request
def __exit__(self, exc_type, exc_value, traceback):

class TestQwebProcessAtt(TransactionCase):
def setUp(self):
super(TestQwebProcessAtt, self).setUp() = self.env['website'].browse(1) = self.env.ref('base.lang_en') + self.env.ref('base.lang_fr') = self.env.ref('base.lang_en') = True = "http://test.cdn" = "\n".join(["^(/[a-z]{2}_[A-Z]{2})?/a$", "^/b$"])

def _test_att(self, url, expect, tag='a', attribute='href'):
self.env['ir.qweb']._post_processing_att(tag, {attribute: url}, {}),

def test_process_att_no_request(self):
# no request so no URL rewriting
self._test_att('/', {'href': '/'})
self._test_att('/en_US/', {'href': '/en_US/'})
self._test_att('/fr_FR/', {'href': '/fr_FR/'})
# no URL rewritting for CDN
self._test_att('/a', {'href': '/a'})

def test_process_att_no_website(self):
with MockRequest(self.env) as request:
# no website so URL rewriting
self._test_att('/', {'href': '/'})
self._test_att('/en_US/', {'href': '/en_US/'})
self._test_att('/fr_FR/', {'href': '/fr_FR/'})
# no URL rewritting for CDN
self._test_att('/a', {'href': '/a'})

def test_process_att_monolang_route(self):
with MockRequest(self.env,, multilang=False) as request:
# lang not changed in URL but CDN enabled
self._test_att('/a', {'href': 'http://test.cdn/a'})
self._test_att('/en_US/a', {'href': 'http://test.cdn/en_US/a'})
self._test_att('/b', {'href': 'http://test.cdn/b'})
self._test_att('/en_US/b', {'href': '/en_US/b'})

def test_process_att_no_request_lang(self):
with MockRequest(self.env, as request:
self._test_att('/', {'href': '/'})
self._test_att('/en_US/', {'href': '/'})
self._test_att('/fr_FR/', {'href': '/fr_FR/'})

def test_process_att_with_request_lang(self):
with MockRequest(self.env,, context={'lang': 'fr_FR'}) as request:
self._test_att('/', {'href': '/fr_FR/'})
self._test_att('/en_US/', {'href': '/'})
self._test_att('/fr_FR/', {'href': '/fr_FR/'})

def test_process_att_matching_cdn_and_lang(self):
with MockRequest(self.env, as request:
# lang prefix is added before CDN
self._test_att('/a', {'href': 'http://test.cdn/a'})
self._test_att('/en_US/a', {'href': 'http://test.cdn/a'})
self._test_att('/fr_FR/a', {'href': 'http://test.cdn/fr_FR/a'})
self._test_att('/b', {'href': 'http://test.cdn/b'})
self._test_att('/en_US/b', {'href': 'http://test.cdn/b'})
self._test_att('/fr_FR/b', {'href': '/fr_FR/b'})

0 comments on commit e67f4fd

Please sign in to comment.
You can’t perform that action at this time.