fix: language switcher uses translated page URLs

This commit is contained in:
2026-05-02 21:20:13 +02:00
parent 3bf0c72ce5
commit 6b46751fe3
2 changed files with 78 additions and 12 deletions

View File

@@ -1,9 +1,10 @@
{% load i18n %} {% load i18n localized_navigation %}
<div class="header-right"> <div class="header-right">
{% get_current_language as current_language %} {% get_current_language as current_language %}
{% get_available_languages as available_languages %} {% get_available_languages as available_languages %}
{% get_language_info_list for available_languages as languages %} {% get_language_info_list for available_languages as languages %}
{% request_language_options as language_options %}
<div class="dropdown language-dropdown me-2"> <div class="dropdown language-dropdown me-2">
<button <button
@@ -27,18 +28,18 @@
</svg> </svg>
</button> </button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="header-language-switcher"> <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="header-language-switcher">
<form action="{% url 'set_language' %}" method="post" class="language_form"> {% for option in language_options %}
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.path }}"/>
{% for language in languages %} {% for language in languages %}
<li> {% if language.code == option.code %}
<button class="dropdown-item d-flex align-items-center gap-2" type="submit" value="{{ language.code }}" name="language"> <li>
{% include "oxyan/partials/flags/"|add:language.code|add:".svg" %} <a class="dropdown-item d-flex align-items-center gap-2" href="{{ option.url }}">
<span>{{ language.name_local|title }}</span> {% include "oxyan/partials/flags/"|add:language.code|add:".svg" %}
</button> <span>{{ language.name_local|title }}</span>
</li> </a>
</li>
{% endif %}
{% endfor %} {% endfor %}
</form> {% endfor %}
</ul> </ul>
</div> </div>

View File

@@ -3,7 +3,7 @@ from __future__ import annotations
from django import template from django import template
from django.conf import settings from django.conf import settings
from wagtail.models import Page from wagtail.models import Locale, Page, Site
register = template.Library() register = template.Library()
@@ -47,6 +47,63 @@ def _build_absolute_url(request, path: str | None, page=None) -> str:
return path or "" return path or ""
def _resolve_page_from_request(request) -> Page | None:
"""
Best-effort resolution of the Wagtail page for the current request.
This is used by the language switcher ESI fragment where `page/self` isn't
available in the template context.
"""
if request is None:
return None
try:
site = Site.find_for_request(request)
except Exception: # pragma: no cover
site = None
if site is None:
site = Site.objects.filter(is_default_site=True).first()
if site is None:
return None
path = getattr(request, "path_info", None) or getattr(request, "path", "/")
path_components = [c for c in path.strip("/").split("/") if c]
try:
locale_codes = set(Locale.objects.values_list("language_code", flat=True))
except Exception: # pragma: no cover
locale_codes = set()
if path_components and path_components[0] in locale_codes:
path_components = path_components[1:]
root = site.root_page
language_code = getattr(request, "LANGUAGE_CODE", None)
locale = None
if language_code:
try:
locale = Locale.objects.get(
language_code=_normalize_language_code(language_code)
)
except Locale.DoesNotExist:
locale = None
if locale is not None:
translated_root = (
Page.objects.filter(translation_key=root.translation_key, locale=locale)
.specific()
.first()
)
if translated_root is not None:
root = translated_root
try:
return root.specific.route(request, path_components).page.specific
except Exception:
return None
@register.simple_tag @register.simple_tag
def page_language_options(page): def page_language_options(page):
labels = { labels = {
@@ -82,6 +139,14 @@ def page_language_options(page):
return options return options
@register.simple_tag(takes_context=True)
def request_language_options(context):
page = context.get("page") or context.get("self")
if page is None:
page = _resolve_page_from_request(context.get("request"))
return page_language_options(page)
@register.simple_tag(takes_context=True) @register.simple_tag(takes_context=True)
def page_canonical_url(context): def page_canonical_url(context):
request = context.get("request") request = context.get("request")