[IMP] portal, *: move language switcher to portal
*: base, http_routing, website Make the language switcher available on portal without website installed. Part of https://github.com/odoo/odoo/pull/55300 task-2203383 Co-authored-by: Jeremy Kersten <jke@odoo.com> Co-authored-by: qsm-odoo <qsm@odoo.com>
This commit is contained in:
committed by
qsm-odoo
co-authored by
Jeremy Kersten
qsm-odoo
parent
0b2f2b5d96
commit
704bcc5527
@@ -147,7 +147,7 @@ def url_lang(path_or_uri, lang_code=None):
|
||||
# relative URL with either a path or a force_lang
|
||||
if not url.netloc and not url.scheme and (url.path or force_lang):
|
||||
location = werkzeug.urls.url_join(request.httprequest.path, location)
|
||||
lang_url_codes = [url_code for _, url_code, _ in Lang.get_available()]
|
||||
lang_url_codes = [url_code for _, url_code, *_ in Lang.get_available()]
|
||||
lang_code = pycompat.to_text(lang_code or request.context['lang'])
|
||||
lang_url_code = Lang._lang_code_to_urlcode(lang_code)
|
||||
lang_url_code = lang_url_code if lang_url_code in lang_url_codes else lang_code
|
||||
@@ -208,7 +208,7 @@ def is_multilang_url(local_url, lang_url_codes=None):
|
||||
2. If not matching 1., everything not under /static/ will be translatable
|
||||
'''
|
||||
if not lang_url_codes:
|
||||
lang_url_codes = [url_code for _, url_code, _ in request.env['res.lang'].get_available()]
|
||||
lang_url_codes = [url_code for _, url_code, *_ in request.env['res.lang'].get_available()]
|
||||
spath = local_url.split('/')
|
||||
# if a language is already in the path, remove it
|
||||
if spath[1] in lang_url_codes:
|
||||
@@ -388,8 +388,7 @@ class IrHttp(models.AbstractModel):
|
||||
path = request.httprequest.path.split('/')
|
||||
is_a_bot = cls.is_a_bot()
|
||||
|
||||
available_langs = Lang.get_available()
|
||||
lang_codes = [code for code, _, _ in available_langs]
|
||||
lang_codes = [code for code, *_ in Lang.get_available()]
|
||||
nearest_lang = not func and cls.get_nearest_lang(Lang._lang_get_code(path[1]))
|
||||
cook_lang = request.httprequest.cookies.get('frontend_lang')
|
||||
cook_lang = cook_lang in lang_codes and cook_lang
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import ir_http
|
||||
from . import ir_ui_view
|
||||
from . import mail_thread
|
||||
from . import mail_message
|
||||
from . import portal_mixin
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import models
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
class IrHttp(models.AbstractModel):
|
||||
@@ -11,3 +12,9 @@ class IrHttp(models.AbstractModel):
|
||||
def _get_translation_frontend_modules_name(cls):
|
||||
mods = super(IrHttp, cls)._get_translation_frontend_modules_name()
|
||||
return mods + ['portal']
|
||||
|
||||
@classmethod
|
||||
def _get_frontend_langs(cls):
|
||||
if request and request.is_frontend:
|
||||
return [lang[0] for lang in filter(lambda l: l[3], request.env['res.lang'].get_available())]
|
||||
return super()._get_frontend_langs()
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models
|
||||
from odoo.http import request
|
||||
from odoo.addons.http_routing.models.ir_http import url_for
|
||||
|
||||
|
||||
class View(models.Model):
|
||||
_inherit = "ir.ui.view"
|
||||
|
||||
@api.model
|
||||
def _prepare_qcontext(self):
|
||||
""" Returns the qcontext : rendering context with portal specific value (required
|
||||
to render portal layout template)
|
||||
"""
|
||||
qcontext = super(View, self)._prepare_qcontext()
|
||||
if request and getattr(request, 'is_frontend', False):
|
||||
Lang = request.env['res.lang']
|
||||
portal_lang_code = request.env['ir.http']._get_frontend_langs()
|
||||
qcontext.update(dict(
|
||||
self._context.copy(),
|
||||
languages=[lang for lang in Lang.get_available() if lang[0] in portal_lang_code],
|
||||
url_for=url_for,
|
||||
))
|
||||
return qcontext
|
||||
@@ -535,3 +535,19 @@ form label {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copyright
|
||||
.o_footer_copyright {
|
||||
|
||||
.js_language_selector {
|
||||
display: inline-block;
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
.row {
|
||||
display: flex;
|
||||
> div {
|
||||
margin: auto 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,32 @@
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//*[hasclass('o_footer_copyright_name')]" position="after">
|
||||
<t t-call="portal.language_selector"/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="language_selector" name="Language Selector">
|
||||
<t t-set="language_selector_visible" t-value="len(languages) > 1"/>
|
||||
<ul class="js_language_selector mb0 list-inline" t-if="language_selector_visible">
|
||||
<li class="list-inline-item">
|
||||
<div class="dropup">
|
||||
<button class="btn btn-sm btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<span t-esc="list(filter(lambda lg : lg[0] == lang, languages))[0][2].split('/').pop()"/>
|
||||
<span class="caret ml4"/>
|
||||
</button>
|
||||
<div class="dropdown-menu" role="menu">
|
||||
<t t-foreach="languages" t-as="lg">
|
||||
<a t-att-href="url_for(request.httprequest.path + '?' + keep_query(), lang_code=lg[0])"
|
||||
class="dropdown-item js_change_lang"
|
||||
t-att-data-url_code="lg[1]">
|
||||
<t t-esc="lg[2].split('/').pop()"/>
|
||||
</a>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<template id="portal_breadcrumbs" name="Portal Breadcrumbs">
|
||||
|
||||
@@ -216,7 +216,7 @@ class Http(models.AbstractModel):
|
||||
@classmethod
|
||||
def _get_frontend_langs(cls):
|
||||
if get_request_website():
|
||||
return [code for code, _, _ in request.env['res.lang'].get_available()]
|
||||
return [code for code, *_ in request.env['res.lang'].get_available()]
|
||||
else:
|
||||
return super()._get_frontend_langs()
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import werkzeug
|
||||
from odoo import api, fields, models
|
||||
from odoo import tools
|
||||
from odoo.addons import website
|
||||
from odoo.addons.http_routing.models.ir_http import url_for
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo.osv import expression
|
||||
from odoo.http import request
|
||||
@@ -431,13 +430,10 @@ class View(models.Model):
|
||||
]
|
||||
|
||||
qcontext.update(dict(
|
||||
self._context.copy(),
|
||||
main_object=self,
|
||||
website=request.website,
|
||||
is_view_active=request.website.is_view_active,
|
||||
url_for=url_for,
|
||||
res_company=request.website.company_id.sudo(),
|
||||
languages=request.env['res.lang'].get_available(),
|
||||
translatable=translatable,
|
||||
editable=editable,
|
||||
))
|
||||
|
||||
@@ -19,8 +19,8 @@ class Lang(models.Model):
|
||||
@api.model
|
||||
@tools.ormcache_context(keys=("website_id",))
|
||||
def get_available(self):
|
||||
""" Return the available languages as a list of (code, name) sorted by name. """
|
||||
website = ir_http.get_request_website()
|
||||
if website:
|
||||
return sorted([(lang.code, lang.url_code, lang.name) for lang in request.website.language_ids])
|
||||
return super(Lang, self).get_available()
|
||||
if not website:
|
||||
return super().get_available()
|
||||
# Return the website-available ones in this case
|
||||
return request.website.language_ids.get_sorted()
|
||||
|
||||
@@ -864,22 +864,6 @@ header {
|
||||
}
|
||||
}
|
||||
|
||||
// Copyright
|
||||
.o_footer_copyright {
|
||||
|
||||
.js_language_selector {
|
||||
display: inline-block;
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
.row {
|
||||
display: flex;
|
||||
> div {
|
||||
margin: auto 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Figure with special style
|
||||
.o_figure_relative_layout {
|
||||
position: relative;
|
||||
|
||||
@@ -156,9 +156,6 @@
|
||||
<!-- Background now controlled by css configuration, using color combinations -->
|
||||
<attribute name="class" add="o_colored_level o_cc" separator=" "/>
|
||||
</xpath>
|
||||
<xpath expr="//div[hasclass('o_footer_copyright')]//span[hasclass('o_footer_copyright_name')]" position="after">
|
||||
<t t-call="website.language_selector"/>
|
||||
</xpath>
|
||||
<xpath expr="//t[@t-call='web.brand_promotion']/.." position="attributes">
|
||||
<attribute name="class" add="o_not_editable" separator=" "/>
|
||||
<attribute name="t-if">not editable</attribute>
|
||||
@@ -594,25 +591,14 @@
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="language_selector" name="Language Selector">
|
||||
<ul class="js_language_selector mb0 list-inline" t-if="(request and request.is_frontend_multilang and len(languages) > 1) or (website and (editable or translatable))">
|
||||
<li class="list-inline-item">
|
||||
<div class="dropup">
|
||||
<button class="btn btn-sm btn-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<span t-esc="list(filter(lambda lg : lg[0] == lang, languages))[0][2].split('/').pop()"/>
|
||||
<span class="caret ml4"/>
|
||||
</button>
|
||||
<div class="dropdown-menu" role="menu">
|
||||
<t t-foreach="languages" t-as="lg">
|
||||
<a t-att-href="url_for(request.httprequest.path + '?' + keep_query(), lang_code=lg[0])"
|
||||
class="dropdown-item js_change_lang"
|
||||
t-att-data-url_code="lg[1]">
|
||||
<t t-esc="lg[2].split('/').pop()"/>
|
||||
</a>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<template id="language_selector" inherit_id="portal.language_selector">
|
||||
<!-- Always show the language selector on editable websites -->
|
||||
<xpath expr="//t[@t-set='language_selector_visible']" position="after">
|
||||
<t t-set="language_selector_visible" t-value="language_selector_visible or (website and (editable or translatable))"/>
|
||||
</xpath>
|
||||
|
||||
<!-- Add the button to add a language -->
|
||||
<xpath expr="//ul/li" position="after">
|
||||
<li groups="website.group_website_publisher" class="list-inline-item">
|
||||
<t t-set="url_return" t-value="quote_plus(url_for('', '[lang]') + '?' + keep_query())"/>
|
||||
<a class="d-none d-sm-block" t-attf-href="/web#action=base.action_view_base_language_install&website_id=#{website.id if website else ''}&url_return=#{url_return}">
|
||||
@@ -620,7 +606,7 @@
|
||||
Add a language...
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="record_cover">
|
||||
|
||||
@@ -209,9 +209,14 @@ class Lang(models.Model):
|
||||
@api.model
|
||||
@tools.ormcache()
|
||||
def get_available(self):
|
||||
""" Return the available languages as a list of (code, name) sorted by name. """
|
||||
""" Return the available languages as a list of (code, url_code, name,
|
||||
active) sorted by name.
|
||||
"""
|
||||
langs = self.with_context(active_test=False).search([])
|
||||
return sorted([(lang.code, lang.url_code, lang.name) for lang in langs], key=itemgetter(2))
|
||||
return langs.get_sorted()
|
||||
|
||||
def get_sorted(self):
|
||||
return sorted([(lang.code, lang.url_code, lang.name, lang.active) for lang in self], key=itemgetter(2))
|
||||
|
||||
@tools.ormcache('self.id')
|
||||
def _get_cached_values(self):
|
||||
@@ -229,7 +234,7 @@ class Lang(models.Model):
|
||||
@api.model
|
||||
@tools.ormcache('code')
|
||||
def _lang_code_to_urlcode(self, code):
|
||||
for c, urlc, name in self.get_available():
|
||||
for c, urlc, name, *_ in self.get_available():
|
||||
if c == code:
|
||||
return urlc
|
||||
return self._lang_get(code).url_code
|
||||
|
||||
@@ -20,7 +20,7 @@ class BaseLanguageInstall(models.TransientModel):
|
||||
|
||||
@api.model
|
||||
def _get_languages(self):
|
||||
return [[code, name] for code, _, name in self.env['res.lang'].get_available()]
|
||||
return [[code, name] for code, _, name, *_ in self.env['res.lang'].get_available()]
|
||||
|
||||
lang = fields.Selection(_get_languages, string='Language', required=True,
|
||||
default=_default_language)
|
||||
|
||||
Reference in New Issue
Block a user