feat: Adds language dropdown to subevent

This commit is contained in:
Vincent Mahnke 2025-11-12 13:41:30 +01:00
commit 5a349822d7
Signed by: ViMaSter
GPG key ID: 6D787326BA7D6469
4 changed files with 139 additions and 10 deletions

View file

@ -62,6 +62,21 @@ Development setup
6. Restart your local pretix server. You can now use the plugin from this repository for your events by enabling it in 6. Restart your local pretix server. You can now use the plugin from this repository for your events by enabling it in
the 'plugins' tab in the settings. the 'plugins' tab in the settings.
Changelog
---------
1.1.0
~~~~~
- Add subevent-level "Language" field and use it to emit ``<language>`` per subevent (defaults to ``none``).
1.0.0
~~~~~
- Initial release
License License
------- -------

View file

@ -1 +1 @@
__version__ = "1.0.0" __version__ = "1.1.0"

View file

@ -1,6 +1,10 @@
from django.http import HttpResponse from django.http import HttpResponse
from rest_framework import views from rest_framework import views
from pretix.base.models import Event, SubEvent from pretix.base.models import Event, SubEvent
try:
from pretix.base.models import SubEventMetaValue
except Exception: # pragma: no cover
SubEventMetaValue = None
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from collections import defaultdict from collections import defaultdict
from datetime import timedelta from datetime import timedelta
@ -182,10 +186,31 @@ class CongressScheduleView(views.APIView):
# track use room name as a simple track assignment # track use room name as a simple track assignment
ET.SubElement(ev_el, 'track').text = slugify(room_name) or 'general' ET.SubElement(ev_el, 'track').text = slugify(room_name) or 'general'
# Optional elements: keep minimal but include language if available # Optional elements: language per subevent via SubEventMetaValue
lang = getattr(ev.settings, 'locale', None) def _get_lang(subevent: SubEvent) -> str:
if lang: if SubEventMetaValue is not None:
ET.SubElement(ev_el, 'language').text = str(lang) try:
v = (
SubEventMetaValue.objects
.filter(subevent=subevent, key='congressschedule_language')
.values_list('value', flat=True)
.first()
)
return (v or 'none').strip() or 'none'
except Exception:
pass
# Fallbacks for environments without pretix DB access
md = getattr(subevent, 'meta_data', None) or {}
if isinstance(md, dict) and 'congressschedule_language' in md:
return (md.get('congressschedule_language') or 'none')
se_settings = getattr(subevent, 'settings', None)
try:
return se_settings.get('congressschedule_language', 'none') if se_settings is not None else 'none'
except Exception:
return 'none'
lang = _get_lang(se)
ET.SubElement(ev_el, 'language').text = str(lang or 'none')
# Leave optional complex children (persons, recording, links, attachments) empty for now # Leave optional complex children (persons, recording, links, attachments) empty for now
@ -257,11 +282,13 @@ class HackertoursMarkdownView(views.APIView):
title = _localize(se.name) title = _localize(se.name)
tmin = to_minutes(se.date_from) tmin = to_minutes(se.date_from)
hhmm = se.date_from.strftime('%H:%M') hhmm = se.date_from.strftime('%H:%M')
try: v = (
se_settings = getattr(se, 'settings', None) SubEventMetaValue.objects
lang = se_settings.get('congressschedule_language', 'de') if se_settings is not None else 'none' .filter(subevent=se, property__name='congressschedule_language')
except Exception: .values_list('value', flat=True)
lang = 'none' .first()
)
lang = (v or 'deen').strip() or 'deen'
link = f"./{slugify(title)}/" link = f"./{slugify(title)}/"
md_item = f"{hhmm} [{title}]({link}) {{< lang {lang} >}}" md_item = f"{hhmm} [{title}]({link}) {{< lang {lang} >}}"
day_slots[d][tmin].append(md_item) day_slots[d][tmin].append(md_item)

View file

@ -0,0 +1,87 @@
from django import forms
from django.utils.translation import gettext_lazy as _
try:
# Available in pretix runtime
from pretix.base.models import SubEventMetaValue
except Exception: # pragma: no cover - during docs build or without pretix
SubEventMetaValue = None
class SubEventLanguageForm(forms.Form):
language = forms.ChoiceField(
label=_("Language"),
required=False,
help_text=_("Select the language for this tour."),
choices=[
('deen', _("Bilingual")),
('de', _("German")),
('en', _("English")),
],
)
def __init__(self, *args, **kwargs):
self.event = kwargs.pop('event')
self.subevent = kwargs.pop('subevent', None)
super().__init__(*args, **kwargs)
# Pre-fill from subevent meta if available
if self.subevent:
val = (
SubEventMetaValue.objects
.filter(subevent=self.subevent, property__name='congressschedule_language')
.values_list('value', flat=True)
.first()
)
self.fields['language'].initial = val or ''
elif self.subevent and hasattr(self.subevent, 'settings'):
# Fallback (older pretix): might be event-wide, keep as last resort
self.fields['language'].initial = "deen"
@property
def title(self):
return _("Language")
def save(self):
if not self.subevent:
return
val = (self.cleaned_data.get('language') or '').strip() or 'none'
# Persist as real subevent meta value so it's scoped per subevent
from pretix.base.models import EventMetaProperty
property_obj, _ = EventMetaProperty.objects.get_or_create(
name='congressschedule_language',
defaults={'default': '', 'organizer': self.event.organizer}
)
SubEventMetaValue.objects.update_or_create(
subevent=self.subevent,
property=property_obj,
defaults={'value': val},
)
def subevent_forms(sender, request, subevent, **kwargs):
# Provide our additional subevent form
import logging
logger = logging.getLogger(__name__)
logger.debug("Providing congressschedule subevent form for event %s, subevent %s", sender.slug, getattr(subevent, 'name', 'no-subevent'))
form = SubEventLanguageForm(
data=request.POST if request.method == 'POST' else None,
event=sender,
subevent=subevent,
prefix='congressschedule',
)
return form
def connect_signals():
# Connect to pretix.control.signals.subevent_forms at import time
try:
from pretix.control import signals as control_signals
control_signals.subevent_forms.connect(subevent_forms, dispatch_uid='pretix_congressschedule_subevent_language')
except Exception:
# Pretix not fully loaded in some contexts (e.g., docs build)
pass
# Connect immediately when module is imported via AppConfig.ready()
connect_signals()