mirror of
https://github.com/pretix/pretix.git
synced 2026-09-13 16:14:40 +00:00
Add region setting to supplement localization (#1875)
This commit is contained in:
@@ -574,6 +574,7 @@ class EventSettingsSerializer(serializers.Serializer):
|
|||||||
'presale_start_show_date',
|
'presale_start_show_date',
|
||||||
'locales',
|
'locales',
|
||||||
'locale',
|
'locale',
|
||||||
|
'region',
|
||||||
'last_order_modification_date',
|
'last_order_modification_date',
|
||||||
'show_quota_left',
|
'show_quota_left',
|
||||||
'waiting_list_enabled',
|
'waiting_list_enabled',
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ class PdfDataSerializer(serializers.Field):
|
|||||||
res = {}
|
res = {}
|
||||||
|
|
||||||
ev = instance.subevent or instance.order.event
|
ev = instance.subevent or instance.order.event
|
||||||
with language(instance.order.locale):
|
with language(instance.order.locale, instance.order.event.settings.region):
|
||||||
# This needs to have some extra performance improvements to avoid creating hundreds of queries when
|
# This needs to have some extra performance improvements to avoid creating hundreds of queries when
|
||||||
# we serialize a list.
|
# we serialize a list.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.utils.translation import get_language, gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from hierarkey.proxy import HierarkeyProxy
|
from hierarkey.proxy import HierarkeyProxy
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
@@ -9,6 +9,7 @@ from rest_framework.exceptions import ValidationError
|
|||||||
from pretix.api.serializers.i18n import I18nAwareModelSerializer
|
from pretix.api.serializers.i18n import I18nAwareModelSerializer
|
||||||
from pretix.api.serializers.order import CompatibleJSONField
|
from pretix.api.serializers.order import CompatibleJSONField
|
||||||
from pretix.base.auth import get_auth_backends
|
from pretix.base.auth import get_auth_backends
|
||||||
|
from pretix.base.i18n import get_language_without_region
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
Device, GiftCard, GiftCardTransaction, Organizer, SeatingPlan, Team,
|
Device, GiftCard, GiftCardTransaction, Organizer, SeatingPlan, Team,
|
||||||
TeamAPIToken, TeamInvite, User,
|
TeamAPIToken, TeamInvite, User,
|
||||||
@@ -145,7 +146,7 @@ class TeamInviteSerializer(serializers.ModelSerializer):
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
event=None,
|
event=None,
|
||||||
locale=get_language() # TODO: expose?
|
locale=get_language_without_region() # TODO: expose?
|
||||||
)
|
)
|
||||||
except SendMailException:
|
except SendMailException:
|
||||||
pass # Already logged
|
pass # Already logged
|
||||||
@@ -217,6 +218,7 @@ class OrganizerSettingsSerializer(serializers.Serializer):
|
|||||||
'giftcard_length',
|
'giftcard_length',
|
||||||
'giftcard_expiry_years',
|
'giftcard_expiry_years',
|
||||||
'locales',
|
'locales',
|
||||||
|
'region',
|
||||||
'event_team_provisioning',
|
'event_team_provisioning',
|
||||||
'primary_color',
|
'primary_color',
|
||||||
'theme_color_success',
|
'theme_color_success',
|
||||||
|
|||||||
@@ -582,7 +582,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
|||||||
auth=request.auth,
|
auth=request.auth,
|
||||||
)
|
)
|
||||||
|
|
||||||
with language(order.locale):
|
with language(order.locale, self.request.event.settings.region):
|
||||||
order_placed.send(self.request.event, order=order)
|
order_placed.send(self.request.event, order=order)
|
||||||
if order.status == Order.STATUS_PAID:
|
if order.status == Order.STATUS_PAID:
|
||||||
order_paid.send(self.request.event, order=order)
|
order_paid.send(self.request.event, order=order)
|
||||||
@@ -886,7 +886,7 @@ class OrderPositionViewSet(mixins.DestroyModelMixin, viewsets.ReadOnlyModelViewS
|
|||||||
|
|
||||||
price = get_price(**kwargs)
|
price = get_price(**kwargs)
|
||||||
tr = kwargs.get('tax_rule', kwargs.get('item').tax_rule)
|
tr = kwargs.get('tax_rule', kwargs.get('item').tax_rule)
|
||||||
with language(data.get('locale') or self.request.event.settings.locale):
|
with language(data.get('locale') or self.request.event.settings.locale, self.request.event.settings.region):
|
||||||
return Response({
|
return Response({
|
||||||
'gross': price.gross,
|
'gross': price.gross,
|
||||||
'gross_formatted': money_filter(price.gross, self.request.event.currency, hide_currency=True),
|
'gross_formatted': money_filter(price.gross, self.request.event.currency, hide_currency=True),
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ class TemplateBasedMailRenderer(BaseHTMLMailRenderer):
|
|||||||
'body': body_md,
|
'body': body_md,
|
||||||
'subject': str(subject),
|
'subject': str(subject),
|
||||||
'color': settings.PRETIX_PRIMARY_COLOR,
|
'color': settings.PRETIX_PRIMARY_COLOR,
|
||||||
'rtl': get_language() in settings.LANGUAGES_RTL
|
'rtl': get_language() in settings.LANGUAGES_RTL or get_language().split('-')[0] in settings.LANGUAGES_RTL,
|
||||||
}
|
}
|
||||||
if self.event:
|
if self.event:
|
||||||
htmlctx['event'] = self.event
|
htmlctx['event'] = self.event
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ from pretix.base.forms.widgets import (
|
|||||||
BusinessBooleanRadio, DatePickerWidget, SplitDateTimePickerWidget,
|
BusinessBooleanRadio, DatePickerWidget, SplitDateTimePickerWidget,
|
||||||
TimePickerWidget, UploadedFileWidget,
|
TimePickerWidget, UploadedFileWidget,
|
||||||
)
|
)
|
||||||
from pretix.base.i18n import language
|
from pretix.base.i18n import get_language_without_region, language
|
||||||
from pretix.base.models import InvoiceAddress, Question, QuestionOption
|
from pretix.base.models import InvoiceAddress, Question, QuestionOption
|
||||||
from pretix.base.models.tax import (
|
from pretix.base.models.tax import (
|
||||||
EU_COUNTRIES, cc_to_vat_prefix, is_eu_country,
|
EU_COUNTRIES, cc_to_vat_prefix, is_eu_country,
|
||||||
@@ -216,8 +216,8 @@ class WrappedPhoneNumberPrefixWidget(PhoneNumberPrefixWidget):
|
|||||||
def guess_country(event):
|
def guess_country(event):
|
||||||
# Try to guess the initial country from either the country of the merchant
|
# Try to guess the initial country from either the country of the merchant
|
||||||
# or the locale. This will hopefully save at least some users some scrolling :)
|
# or the locale. This will hopefully save at least some users some scrolling :)
|
||||||
locale = get_language()
|
locale = get_language_without_region()
|
||||||
country = event.settings.invoice_address_from_country
|
country = event.settings.region or event.settings.invoice_address_from_country
|
||||||
if not country:
|
if not country:
|
||||||
valid_countries = countries.countries
|
valid_countries = countries.countries
|
||||||
if '-' in locale:
|
if '-' in locale:
|
||||||
|
|||||||
+34
-2
@@ -66,10 +66,42 @@ class LazyNumber:
|
|||||||
return number_format(self.value, decimal_pos=self.decimal_pos)
|
return number_format(self.value, decimal_pos=self.decimal_pos)
|
||||||
|
|
||||||
|
|
||||||
|
ALLOWED_LANGUAGES = dict(settings.LANGUAGES)
|
||||||
|
|
||||||
|
|
||||||
|
def get_language_without_region(lng=None):
|
||||||
|
"""
|
||||||
|
Returns the currently active language, but strips what pretix calls a ``region``. For example,
|
||||||
|
if the currently active language is ``en-us``, you will be returned ``en`` since pretix does not
|
||||||
|
ship with separate language files for ``en-us``. If the currently active language is ``pt-br``,
|
||||||
|
you will be returned ``pt-br`` since there are separate language files for ``pt-br``.
|
||||||
|
|
||||||
|
tl;dr: You will be always passed a language that is defined in settings.LANGUAGES.
|
||||||
|
"""
|
||||||
|
lng = lng or translation.get_language() or settings.LANGUAGE_CODE
|
||||||
|
if lng not in ALLOWED_LANGUAGES:
|
||||||
|
lng = lng.split('-')[0]
|
||||||
|
if lng not in ALLOWED_LANGUAGES:
|
||||||
|
lng = settings.LANGUAGE_CODE
|
||||||
|
return lng
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def language(lng):
|
def language(lng, region=None):
|
||||||
|
"""
|
||||||
|
Temporarily change the active language to ``lng``. Will automatically be rolled back when the
|
||||||
|
context manager returns.
|
||||||
|
|
||||||
|
You can optionally pass a "region". For example, if you pass ``en`` as ``lng`` and ``US`` as
|
||||||
|
``region``, the active language will be ``en-us``, which will mostly affect date/time
|
||||||
|
formatting. If you pass a ``lng`` that already contains a region, e.g. ``pt-br``, the ``region``
|
||||||
|
attribute will be ignored.
|
||||||
|
"""
|
||||||
_lng = translation.get_language()
|
_lng = translation.get_language()
|
||||||
translation.activate(lng or settings.LANGUAGE_CODE)
|
lng = lng or settings.LANGUAGE_CODE
|
||||||
|
if '-' not in lng and region:
|
||||||
|
lng += '-' + region.lower()
|
||||||
|
translation.activate(lng)
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ class BaseReportlabInvoiceRenderer(BaseInvoiceRenderer):
|
|||||||
|
|
||||||
def _upper(self, val):
|
def _upper(self, val):
|
||||||
# We uppercase labels, but not in every language
|
# We uppercase labels, but not in every language
|
||||||
if get_language() == 'el':
|
if get_language().startswith('el'):
|
||||||
return val
|
return val
|
||||||
return val.upper()
|
return val.upper()
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ from django.utils.translation.trans_real import (
|
|||||||
parse_accept_lang_header,
|
parse_accept_lang_header,
|
||||||
)
|
)
|
||||||
|
|
||||||
from pretix.base.settings import GlobalSettingsObject
|
from pretix.base.i18n import get_language_without_region
|
||||||
|
from pretix.base.settings import global_settings_object
|
||||||
from pretix.multidomain.urlreverse import (
|
from pretix.multidomain.urlreverse import (
|
||||||
get_event_domain, get_organizer_domain,
|
get_event_domain, get_organizer_domain,
|
||||||
)
|
)
|
||||||
@@ -35,19 +36,30 @@ class LocaleMiddleware(MiddlewareMixin):
|
|||||||
# Normally, this middleware runs *before* the event is set. However, on event frontend pages it
|
# Normally, this middleware runs *before* the event is set. However, on event frontend pages it
|
||||||
# might be run a second time by pretix.presale.EventMiddleware and in this case the event is already
|
# might be run a second time by pretix.presale.EventMiddleware and in this case the event is already
|
||||||
# set and can be taken into account for the decision.
|
# set and can be taken into account for the decision.
|
||||||
if hasattr(request, 'event') and not request.path.startswith(get_script_prefix() + 'control'):
|
if not request.path.startswith(get_script_prefix() + 'control'):
|
||||||
if language not in request.event.settings.locales:
|
if hasattr(request, 'event'):
|
||||||
firstpart = language.split('-')[0]
|
if language not in request.event.settings.locales:
|
||||||
if firstpart in request.event.settings.locales:
|
firstpart = language.split('-')[0]
|
||||||
language = firstpart
|
if firstpart in request.event.settings.locales:
|
||||||
else:
|
language = firstpart
|
||||||
language = request.event.settings.locale
|
else:
|
||||||
for lang in request.event.settings.locales:
|
language = request.event.settings.locale
|
||||||
if lang.startswith(firstpart + '-'):
|
for lang in request.event.settings.locales:
|
||||||
language = lang
|
if lang.startswith(firstpart + '-'):
|
||||||
break
|
language = lang
|
||||||
|
break
|
||||||
|
if '-' not in language and request.event.settings.region:
|
||||||
|
language += '-' + request.event.settings.region
|
||||||
|
elif hasattr(request, 'organizer'):
|
||||||
|
if '-' not in language and request.organizer.settings.region:
|
||||||
|
language += '-' + request.organizer.settings.region
|
||||||
|
else:
|
||||||
|
gs = global_settings_object(request)
|
||||||
|
if '-' not in language and gs.settings.region:
|
||||||
|
language += '-' + gs.settings.region
|
||||||
|
|
||||||
translation.activate(language)
|
translation.activate(language)
|
||||||
request.LANGUAGE_CODE = translation.get_language()
|
request.LANGUAGE_CODE = get_language_without_region()
|
||||||
|
|
||||||
tzname = None
|
tzname = None
|
||||||
if hasattr(request, 'event'):
|
if hasattr(request, 'event'):
|
||||||
@@ -192,7 +204,7 @@ class SecurityMiddleware(MiddlewareMixin):
|
|||||||
resp['P3P'] = 'CP=\"ALL DSP COR CUR ADM TAI OUR IND COM NAV INT\"'
|
resp['P3P'] = 'CP=\"ALL DSP COR CUR ADM TAI OUR IND COM NAV INT\"'
|
||||||
|
|
||||||
img_src = []
|
img_src = []
|
||||||
gs = GlobalSettingsObject()
|
gs = global_settings_object(request)
|
||||||
if gs.settings.leaflet_tiles:
|
if gs.settings.leaflet_tiles:
|
||||||
img_src.append(gs.settings.leaflet_tiles[:gs.settings.leaflet_tiles.index("/", 10)].replace("{s}", "*"))
|
img_src.append(gs.settings.leaflet_tiles[:gs.settings.leaflet_tiles.index("/", 10)].replace("{s}", "*"))
|
||||||
|
|
||||||
|
|||||||
@@ -857,7 +857,7 @@ class Order(LockModel, LoggedModel):
|
|||||||
for k, v in self.event.meta_data.items():
|
for k, v in self.event.meta_data.items():
|
||||||
context['meta_' + k] = v
|
context['meta_' + k] = v
|
||||||
|
|
||||||
with language(self.locale):
|
with language(self.locale, self.event.settings.region):
|
||||||
recipient = self.email
|
recipient = self.email
|
||||||
if position and position.attendee_email:
|
if position and position.attendee_email:
|
||||||
recipient = position.attendee_email
|
recipient = position.attendee_email
|
||||||
@@ -890,7 +890,7 @@ class Order(LockModel, LoggedModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def resend_link(self, user=None, auth=None):
|
def resend_link(self, user=None, auth=None):
|
||||||
with language(self.locale):
|
with language(self.locale, self.event.settings.region):
|
||||||
email_template = self.event.settings.mail_text_resend_link
|
email_template = self.event.settings.mail_text_resend_link
|
||||||
email_context = get_email_context(event=self.event, order=self)
|
email_context = get_email_context(event=self.event, order=self)
|
||||||
email_subject = _('Your order: %(code)s') % {'code': self.code}
|
email_subject = _('Your order: %(code)s') % {'code': self.code}
|
||||||
@@ -1514,7 +1514,7 @@ class OrderPayment(models.Model):
|
|||||||
def _send_paid_mail_attendee(self, position, user):
|
def _send_paid_mail_attendee(self, position, user):
|
||||||
from pretix.base.services.mail import SendMailException
|
from pretix.base.services.mail import SendMailException
|
||||||
|
|
||||||
with language(self.order.locale):
|
with language(self.order.locale, self.order.event.settings.region):
|
||||||
email_template = self.order.event.settings.mail_text_order_paid_attendee
|
email_template = self.order.event.settings.mail_text_order_paid_attendee
|
||||||
email_context = get_email_context(event=self.order.event, order=self.order, position=position)
|
email_context = get_email_context(event=self.order.event, order=self.order, position=position)
|
||||||
email_subject = _('Event registration confirmed: %(code)s') % {'code': self.order.code}
|
email_subject = _('Event registration confirmed: %(code)s') % {'code': self.order.code}
|
||||||
@@ -1532,7 +1532,7 @@ class OrderPayment(models.Model):
|
|||||||
def _send_paid_mail(self, invoice, user, mail_text):
|
def _send_paid_mail(self, invoice, user, mail_text):
|
||||||
from pretix.base.services.mail import SendMailException
|
from pretix.base.services.mail import SendMailException
|
||||||
|
|
||||||
with language(self.order.locale):
|
with language(self.order.locale, self.order.event.settings.region):
|
||||||
email_template = self.order.event.settings.mail_text_order_paid
|
email_template = self.order.event.settings.mail_text_order_paid
|
||||||
email_context = get_email_context(event=self.order.event, order=self.order, payment_info=mail_text)
|
email_context = get_email_context(event=self.order.event, order=self.order, payment_info=mail_text)
|
||||||
email_subject = _('Payment received for your order: %(code)s') % {'code': self.order.code}
|
email_subject = _('Payment received for your order: %(code)s') % {'code': self.order.code}
|
||||||
@@ -2104,7 +2104,7 @@ class OrderPosition(AbstractPosition):
|
|||||||
for k, v in self.event.meta_data.items():
|
for k, v in self.event.meta_data.items():
|
||||||
context['meta_' + k] = v
|
context['meta_' + k] = v
|
||||||
|
|
||||||
with language(self.order.locale):
|
with language(self.order.locale, self.order.event.settings.region):
|
||||||
recipient = self.attendee_email
|
recipient = self.attendee_email
|
||||||
try:
|
try:
|
||||||
email_content = render_mail(template, context)
|
email_content = render_mail(template, context)
|
||||||
@@ -2132,7 +2132,7 @@ class OrderPosition(AbstractPosition):
|
|||||||
|
|
||||||
def resend_link(self, user=None, auth=None):
|
def resend_link(self, user=None, auth=None):
|
||||||
|
|
||||||
with language(self.order.locale):
|
with language(self.order.locale, self.order.event.settings.region):
|
||||||
email_template = self.event.settings.mail_text_resend_link
|
email_template = self.event.settings.mail_text_resend_link
|
||||||
email_context = get_email_context(event=self.order.event, order=self.order, position=self)
|
email_context = get_email_context(event=self.order.event, order=self.order, position=self)
|
||||||
email_subject = _('Your event registration: %(code)s') % {'code': self.order.code}
|
email_subject = _('Your event registration: %(code)s') % {'code': self.order.code}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ class WaitingListEntry(LoggedModel):
|
|||||||
self.voucher = v
|
self.voucher = v
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
with language(self.locale):
|
with language(self.locale, self.event.settings.region):
|
||||||
mail(
|
mail(
|
||||||
self.email,
|
self.email,
|
||||||
_('You have been selected from the waitinglist for {event}').format(event=str(self.event)),
|
_('You have been selected from the waitinglist for {event}').format(event=str(self.event)),
|
||||||
|
|||||||
@@ -421,6 +421,7 @@ class Renderer:
|
|||||||
self.layout = layout
|
self.layout = layout
|
||||||
self.background_file = background_file
|
self.background_file = background_file
|
||||||
self.variables = get_variables(event)
|
self.variables = get_variables(event)
|
||||||
|
self.event = event
|
||||||
if self.background_file:
|
if self.background_file:
|
||||||
self.bg_bytes = self.background_file.read()
|
self.bg_bytes = self.background_file.read()
|
||||||
self.bg_pdf = PdfFileReader(BytesIO(self.bg_bytes), strict=False)
|
self.bg_pdf = PdfFileReader(BytesIO(self.bg_bytes), strict=False)
|
||||||
@@ -487,7 +488,7 @@ class Renderer:
|
|||||||
|
|
||||||
def _get_text_content(self, op: OrderPosition, order: Order, o: dict, inner=False):
|
def _get_text_content(self, op: OrderPosition, order: Order, o: dict, inner=False):
|
||||||
if o.get('locale', None) and not inner:
|
if o.get('locale', None) and not inner:
|
||||||
with language(o['locale']):
|
with language(o['locale'], self.event.settings.region):
|
||||||
return self._get_text_content(op, order, o, True)
|
return self._get_text_content(op, order, o, True)
|
||||||
|
|
||||||
ev = self._get_ev(op, order)
|
ev = self._get_ev(op, order)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def _send_wle_mail(wle: WaitingListEntry, subject: LazyI18nString, message: LazyI18nString, subevent: SubEvent):
|
def _send_wle_mail(wle: WaitingListEntry, subject: LazyI18nString, message: LazyI18nString, subevent: SubEvent):
|
||||||
with language(wle.locale):
|
with language(wle.locale, wle.event.settings.region):
|
||||||
email_context = get_email_context(event_or_subevent=subevent or wle.event, event=wle.event)
|
email_context = get_email_context(event_or_subevent=subevent or wle.event, event=wle.event)
|
||||||
try:
|
try:
|
||||||
mail(
|
mail(
|
||||||
@@ -41,7 +41,7 @@ def _send_wle_mail(wle: WaitingListEntry, subject: LazyI18nString, message: Lazy
|
|||||||
|
|
||||||
def _send_mail(order: Order, subject: LazyI18nString, message: LazyI18nString, subevent: SubEvent,
|
def _send_mail(order: Order, subject: LazyI18nString, message: LazyI18nString, subevent: SubEvent,
|
||||||
refund_amount: Decimal, user: User, positions: list):
|
refund_amount: Decimal, user: User, positions: list):
|
||||||
with language(order.locale):
|
with language(order.locale, order.event.settings.region):
|
||||||
try:
|
try:
|
||||||
ia = order.invoice_address
|
ia = order.invoice_address
|
||||||
except InvoiceAddress.DoesNotExist:
|
except InvoiceAddress.DoesNotExist:
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ def export(self, event: Event, fileid: str, provider: str, form_data: Dict[str,
|
|||||||
)
|
)
|
||||||
|
|
||||||
file = CachedFile.objects.get(id=fileid)
|
file = CachedFile.objects.get(id=fileid)
|
||||||
with language(event.settings.locale), override(event.settings.timezone):
|
with language(event.settings.locale, event.settings.region), override(event.settings.timezone):
|
||||||
responses = register_data_exporters.send(event)
|
responses = register_data_exporters.send(event)
|
||||||
for receiver, response in responses:
|
for receiver, response in responses:
|
||||||
ex = response(event, set_progress)
|
ex = response(event, set_progress)
|
||||||
@@ -67,15 +67,18 @@ def multiexport(self, organizer: Organizer, user: User, device: int, token: int,
|
|||||||
if user:
|
if user:
|
||||||
locale = user.locale
|
locale = user.locale
|
||||||
timezone = user.timezone
|
timezone = user.timezone
|
||||||
|
region = None # todo: add to user?
|
||||||
else:
|
else:
|
||||||
e = allowed_events.first()
|
e = allowed_events.first()
|
||||||
if e:
|
if e:
|
||||||
locale = e.settings.locale
|
locale = e.settings.locale
|
||||||
timezone = e.settings.timezone
|
timezone = e.settings.timezone
|
||||||
|
region = e.settings.region
|
||||||
else:
|
else:
|
||||||
locale = settings.LANGUAGE_CODE
|
locale = settings.LANGUAGE_CODE
|
||||||
timezone = settings.TIME_ZONE
|
timezone = settings.TIME_ZONE
|
||||||
with language(locale), override(timezone):
|
region = None
|
||||||
|
with language(locale, region), override(timezone):
|
||||||
if isinstance(form_data['events'][0], str):
|
if isinstance(form_data['events'][0], str):
|
||||||
events = allowed_events.filter(slug__in=form_data.get('events'), organizer=organizer)
|
events = allowed_events.filter(slug__in=form_data.get('events'), organizer=organizer)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ def build_invoice(invoice: Invoice) -> Invoice:
|
|||||||
|
|
||||||
lp = invoice.order.payments.last()
|
lp = invoice.order.payments.last()
|
||||||
|
|
||||||
with language(invoice.locale):
|
with language(invoice.locale, invoice.event.settings.region):
|
||||||
invoice.invoice_from = invoice.event.settings.get('invoice_address_from')
|
invoice.invoice_from = invoice.event.settings.get('invoice_address_from')
|
||||||
invoice.invoice_from_name = invoice.event.settings.get('invoice_address_from_name')
|
invoice.invoice_from_name = invoice.event.settings.get('invoice_address_from_name')
|
||||||
invoice.invoice_from_zipcode = invoice.event.settings.get('invoice_address_from_zipcode')
|
invoice.invoice_from_zipcode = invoice.event.settings.get('invoice_address_from_zipcode')
|
||||||
@@ -244,7 +244,7 @@ def generate_cancellation(invoice: Invoice, trigger_pdf=True):
|
|||||||
cancellation.date = timezone.now().date()
|
cancellation.date = timezone.now().date()
|
||||||
cancellation.payment_provider_text = ''
|
cancellation.payment_provider_text = ''
|
||||||
cancellation.file = None
|
cancellation.file = None
|
||||||
with language(invoice.locale):
|
with language(invoice.locale, invoice.event.settings.region):
|
||||||
cancellation.invoice_from = invoice.event.settings.get('invoice_address_from')
|
cancellation.invoice_from = invoice.event.settings.get('invoice_address_from')
|
||||||
cancellation.invoice_from_name = invoice.event.settings.get('invoice_address_from_name')
|
cancellation.invoice_from_name = invoice.event.settings.get('invoice_address_from_name')
|
||||||
cancellation.invoice_from_zipcode = invoice.event.settings.get('invoice_address_from_zipcode')
|
cancellation.invoice_from_zipcode = invoice.event.settings.get('invoice_address_from_zipcode')
|
||||||
@@ -297,7 +297,7 @@ def invoice_pdf_task(invoice: int):
|
|||||||
return None
|
return None
|
||||||
if i.file:
|
if i.file:
|
||||||
i.file.delete()
|
i.file.delete()
|
||||||
with language(i.locale):
|
with language(i.locale, i.event.settings.region):
|
||||||
fname, ftype, fcontent = i.event.invoice_renderer.generate(i)
|
fname, ftype, fcontent = i.event.invoice_renderer.generate(i)
|
||||||
i.file.save(fname, ContentFile(fcontent))
|
i.file.save(fname, ContentFile(fcontent))
|
||||||
i.save()
|
i.save()
|
||||||
@@ -328,7 +328,7 @@ def build_preview_invoice_pdf(event):
|
|||||||
if not locale or locale == '__user__':
|
if not locale or locale == '__user__':
|
||||||
locale = event.settings.locale
|
locale = event.settings.locale
|
||||||
|
|
||||||
with rolledback_transaction(), language(locale):
|
with rolledback_transaction(), language(locale, event.settings.region):
|
||||||
order = event.orders.create(status=Order.STATUS_PENDING, datetime=timezone.now(),
|
order = event.orders.create(status=Order.STATUS_PENDING, datetime=timezone.now(),
|
||||||
expires=timezone.now(), code="PREVIEW", total=100 * event.tax_rules.count())
|
expires=timezone.now(), code="PREVIEW", total=100 * event.tax_rules.count())
|
||||||
invoice = Invoice(
|
invoice = Invoice(
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
|
|||||||
except Order.DoesNotExist:
|
except Order.DoesNotExist:
|
||||||
order = None
|
order = None
|
||||||
else:
|
else:
|
||||||
with language(order.locale):
|
with language(order.locale, event.settings.region):
|
||||||
if position:
|
if position:
|
||||||
try:
|
try:
|
||||||
position = order.positions.get(pk=position)
|
position = order.positions.get(pk=position)
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user)
|
|||||||
# TODO: quotacheck?
|
# TODO: quotacheck?
|
||||||
cf = CachedFile.objects.get(id=fileid)
|
cf = CachedFile.objects.get(id=fileid)
|
||||||
user = User.objects.get(pk=user)
|
user = User.objects.get(pk=user)
|
||||||
with language(locale):
|
with language(locale, event.settings.region):
|
||||||
cols = get_all_columns(event)
|
cols = get_all_columns(event)
|
||||||
parsed = parse_csv(cf.file)
|
parsed = parse_csv(cf.file)
|
||||||
orders = []
|
orders = []
|
||||||
@@ -163,7 +163,7 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user)
|
|||||||
)
|
)
|
||||||
|
|
||||||
for o in orders:
|
for o in orders:
|
||||||
with language(o.locale):
|
with language(o.locale, event.settings.region):
|
||||||
order_placed.send(event, order=o)
|
order_placed.send(event, order=o)
|
||||||
if o.status == Order.STATUS_PAID:
|
if o.status == Order.STATUS_PAID:
|
||||||
order_paid.send(event, order=o)
|
order_paid.send(event, order=o)
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ from django_scopes import scopes_disabled
|
|||||||
from pretix.api.models import OAuthApplication
|
from pretix.api.models import OAuthApplication
|
||||||
from pretix.base.channels import get_all_sales_channels
|
from pretix.base.channels import get_all_sales_channels
|
||||||
from pretix.base.email import get_email_context
|
from pretix.base.email import get_email_context
|
||||||
from pretix.base.i18n import LazyLocaleException, language
|
from pretix.base.i18n import (
|
||||||
|
LazyLocaleException, get_language_without_region, language,
|
||||||
|
)
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
CartPosition, Device, Event, GiftCard, Item, ItemVariation, Order,
|
CartPosition, Device, Event, GiftCard, Item, ItemVariation, Order,
|
||||||
OrderPayment, OrderPosition, Quota, Seat, SeatCategoryMapping, User,
|
OrderPayment, OrderPosition, Quota, Seat, SeatCategoryMapping, User,
|
||||||
@@ -260,7 +262,7 @@ def approve_order(order, user=None, send_mail: bool=True, auth=None, force=False
|
|||||||
# send_mail will trigger PDF generation later
|
# send_mail will trigger PDF generation later
|
||||||
|
|
||||||
if send_mail:
|
if send_mail:
|
||||||
with language(order.locale):
|
with language(order.locale, order.event.settings.region):
|
||||||
if order.total == Decimal('0.00'):
|
if order.total == Decimal('0.00'):
|
||||||
email_template = order.event.settings.mail_text_order_approved_free
|
email_template = order.event.settings.mail_text_order_approved_free
|
||||||
email_subject = _('Order approved and confirmed: %(code)s') % {'code': order.code}
|
email_subject = _('Order approved and confirmed: %(code)s') % {'code': order.code}
|
||||||
@@ -311,7 +313,7 @@ def deny_order(order, comment='', user=None, send_mail: bool=True, auth=None):
|
|||||||
if send_mail:
|
if send_mail:
|
||||||
email_template = order.event.settings.mail_text_order_denied
|
email_template = order.event.settings.mail_text_order_denied
|
||||||
email_context = get_email_context(event=order.event, order=order, comment=comment)
|
email_context = get_email_context(event=order.event, order=order, comment=comment)
|
||||||
with language(order.locale):
|
with language(order.locale, order.event.settings.region):
|
||||||
email_subject = _('Order denied: %(code)s') % {'code': order.code}
|
email_subject = _('Order denied: %(code)s') % {'code': order.code}
|
||||||
try:
|
try:
|
||||||
order.send_mail(
|
order.send_mail(
|
||||||
@@ -422,7 +424,7 @@ def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, device
|
|||||||
|
|
||||||
if send_mail:
|
if send_mail:
|
||||||
email_template = order.event.settings.mail_text_order_canceled
|
email_template = order.event.settings.mail_text_order_canceled
|
||||||
with language(order.locale):
|
with language(order.locale, order.event.settings.region):
|
||||||
email_context = get_email_context(event=order.event, order=order)
|
email_context = get_email_context(event=order.event, order=order)
|
||||||
email_subject = _('Order canceled: %(code)s') % {'code': order.code}
|
email_subject = _('Order canceled: %(code)s') % {'code': order.code}
|
||||||
try:
|
try:
|
||||||
@@ -777,7 +779,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
|
|||||||
event=event,
|
event=event,
|
||||||
email=email,
|
email=email,
|
||||||
datetime=now_dt,
|
datetime=now_dt,
|
||||||
locale=locale,
|
locale=get_language_without_region(locale),
|
||||||
total=total,
|
total=total,
|
||||||
testmode=True if sales_channel.testmode_supported and event.testmode else False,
|
testmode=True if sales_channel.testmode_supported and event.testmode else False,
|
||||||
meta_info=json.dumps(meta_info or {}),
|
meta_info=json.dumps(meta_info or {}),
|
||||||
@@ -1033,7 +1035,7 @@ def send_expiry_warnings(sender, **kwargs):
|
|||||||
# Race condition
|
# Race condition
|
||||||
continue
|
continue
|
||||||
|
|
||||||
with language(o.locale):
|
with language(o.locale, settings.region):
|
||||||
o.expiry_reminder_sent = True
|
o.expiry_reminder_sent = True
|
||||||
o.save(update_fields=['expiry_reminder_sent'])
|
o.save(update_fields=['expiry_reminder_sent'])
|
||||||
email_template = settings.mail_text_order_expire_warning
|
email_template = settings.mail_text_order_expire_warning
|
||||||
@@ -1110,7 +1112,7 @@ def send_download_reminders(sender, **kwargs):
|
|||||||
if not send:
|
if not send:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
with language(o.locale):
|
with language(o.locale, o.event.settings.region):
|
||||||
o.download_reminder_sent = True
|
o.download_reminder_sent = True
|
||||||
o.save(update_fields=['download_reminder_sent'])
|
o.save(update_fields=['download_reminder_sent'])
|
||||||
email_template = event.settings.mail_text_download_reminder
|
email_template = event.settings.mail_text_download_reminder
|
||||||
@@ -1150,7 +1152,7 @@ def send_download_reminders(sender, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
def notify_user_changed_order(order, user=None, auth=None, invoices=[]):
|
def notify_user_changed_order(order, user=None, auth=None, invoices=[]):
|
||||||
with language(order.locale):
|
with language(order.locale, order.event.settings.region):
|
||||||
email_template = order.event.settings.mail_text_order_changed
|
email_template = order.event.settings.mail_text_order_changed
|
||||||
email_context = get_email_context(event=order.event, order=order)
|
email_context = get_email_context(event=order.event, order=order)
|
||||||
email_subject = _('Your order has been changed: %(code)s') % {'code': order.code}
|
email_subject = _('Your order has been changed: %(code)s') % {'code': order.code}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ logger = logging.getLogger(__name__)
|
|||||||
def generate_orderposition(order_position: int, provider: str):
|
def generate_orderposition(order_position: int, provider: str):
|
||||||
order_position = OrderPosition.objects.select_related('order', 'order__event').get(id=order_position)
|
order_position = OrderPosition.objects.select_related('order', 'order__event').get(id=order_position)
|
||||||
|
|
||||||
with language(order_position.order.locale):
|
with language(order_position.order.locale, order_position.order.event.settings.region):
|
||||||
responses = register_ticket_outputs.send(order_position.order.event)
|
responses = register_ticket_outputs.send(order_position.order.event)
|
||||||
for receiver, response in responses:
|
for receiver, response in responses:
|
||||||
prov = response(order_position.order.event)
|
prov = response(order_position.order.event)
|
||||||
@@ -41,7 +41,7 @@ def generate_orderposition(order_position: int, provider: str):
|
|||||||
def generate_order(order: int, provider: str):
|
def generate_order(order: int, provider: str):
|
||||||
order = Order.objects.select_related('event').get(id=order)
|
order = Order.objects.select_related('event').get(id=order)
|
||||||
|
|
||||||
with language(order.locale):
|
with language(order.locale, order.event.settings.region):
|
||||||
responses = register_ticket_outputs.send(order.event)
|
responses = register_ticket_outputs.send(order.event)
|
||||||
for receiver, response in responses:
|
for receiver, response in responses:
|
||||||
prov = response(order.event)
|
prov = response(order.event)
|
||||||
@@ -75,7 +75,7 @@ class DummyRollbackException(Exception):
|
|||||||
def preview(event: int, provider: str):
|
def preview(event: int, provider: str):
|
||||||
event = Event.objects.get(id=event)
|
event = Event.objects.get(id=event)
|
||||||
|
|
||||||
with rolledback_transaction(), language(event.settings.locale):
|
with rolledback_transaction(), language(event.settings.locale, event.settings.region):
|
||||||
item = event.items.create(name=_("Sample product"), default_price=42.23,
|
item = event.items.create(name=_("Sample product"), default_price=42.23,
|
||||||
description=_("Sample product description"))
|
description=_("Sample product description"))
|
||||||
item2 = event.items.create(name=_("Sample workshop"), default_price=23.40)
|
item2 = event.items.create(name=_("Sample workshop"), default_price=23.40)
|
||||||
|
|||||||
@@ -832,6 +832,20 @@ DEFAULTS = {
|
|||||||
label=_("Default language"),
|
label=_("Default language"),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
'region': {
|
||||||
|
'default': None,
|
||||||
|
'type': str,
|
||||||
|
'form_class': forms.ChoiceField,
|
||||||
|
'serializer_class': serializers.ChoiceField,
|
||||||
|
'serializer_kwargs': lambda: dict(**country_choice_kwargs()),
|
||||||
|
'form_kwargs': lambda: dict(
|
||||||
|
label=_('Region'),
|
||||||
|
help_text=_('Will be used to determine date and time formatting as well as default country for customer '
|
||||||
|
'addresses and phone numbers. For formatting, this takes less priority than the language and '
|
||||||
|
'is therefore mostly relevant for languages used in different regions globally (like English).'),
|
||||||
|
**country_choice_kwargs()
|
||||||
|
),
|
||||||
|
},
|
||||||
'show_dates_on_frontpage': {
|
'show_dates_on_frontpage': {
|
||||||
'default': 'True',
|
'default': 'True',
|
||||||
'type': bool,
|
'type': bool,
|
||||||
@@ -2403,3 +2417,9 @@ def validate_organizer_settings(organizer, settings_dict):
|
|||||||
#
|
#
|
||||||
# N.B.: When actually fleshing out this stub, adding it to the OrganizerUpdateForm should be considered.
|
# N.B.: When actually fleshing out this stub, adding it to the OrganizerUpdateForm should be considered.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def global_settings_object(holder):
|
||||||
|
if not hasattr(holder, '_global_settings_object'):
|
||||||
|
holder._global_settings_object = GlobalSettingsObject()
|
||||||
|
return holder._global_settings_object
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ from pytz import common_timezones, timezone
|
|||||||
|
|
||||||
from pretix.base.channels import get_all_sales_channels
|
from pretix.base.channels import get_all_sales_channels
|
||||||
from pretix.base.email import get_available_placeholders
|
from pretix.base.email import get_available_placeholders
|
||||||
from pretix.base.forms import (
|
from pretix.base.forms import I18nModelForm, PlaceholderValidator, SettingsForm
|
||||||
I18nModelForm, PlaceholderValidator, SettingsForm,
|
|
||||||
)
|
|
||||||
from pretix.base.models import Event, Organizer, TaxRule, Team
|
from pretix.base.models import Event, Organizer, TaxRule, Team
|
||||||
from pretix.base.models.event import EventMetaValue, SubEvent
|
from pretix.base.models.event import EventMetaValue, SubEvent
|
||||||
from pretix.base.reldate import RelativeDateField, RelativeDateTimeField
|
from pretix.base.reldate import RelativeDateField, RelativeDateTimeField
|
||||||
@@ -459,6 +457,7 @@ class EventSettingsForm(SettingsForm):
|
|||||||
'presale_start_show_date',
|
'presale_start_show_date',
|
||||||
'locales',
|
'locales',
|
||||||
'locale',
|
'locale',
|
||||||
|
'region',
|
||||||
'show_quota_left',
|
'show_quota_left',
|
||||||
'waiting_list_enabled',
|
'waiting_list_enabled',
|
||||||
'waiting_list_hours',
|
'waiting_list_hours',
|
||||||
|
|||||||
@@ -10,11 +10,15 @@ from pretix.base.signals import register_global_settings
|
|||||||
|
|
||||||
|
|
||||||
class GlobalSettingsForm(SettingsForm):
|
class GlobalSettingsForm(SettingsForm):
|
||||||
|
auto_fields = [
|
||||||
|
'region'
|
||||||
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.obj = GlobalSettingsObject()
|
self.obj = GlobalSettingsObject()
|
||||||
super().__init__(*args, obj=self.obj, **kwargs)
|
super().__init__(*args, obj=self.obj, **kwargs)
|
||||||
|
|
||||||
self.fields = OrderedDict([
|
self.fields = OrderedDict(list(self.fields.items()) + [
|
||||||
('footer_text', I18nFormField(
|
('footer_text', I18nFormField(
|
||||||
widget=I18nTextInput,
|
widget=I18nTextInput,
|
||||||
required=False,
|
required=False,
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ class OrganizerSettingsForm(SettingsForm):
|
|||||||
'giftcard_length',
|
'giftcard_length',
|
||||||
'giftcard_expiry_years',
|
'giftcard_expiry_years',
|
||||||
'locales',
|
'locales',
|
||||||
|
'region',
|
||||||
'event_team_provisioning',
|
'event_team_provisioning',
|
||||||
'primary_color',
|
'primary_color',
|
||||||
'theme_color_success',
|
'theme_color_success',
|
||||||
|
|||||||
@@ -83,6 +83,7 @@
|
|||||||
{% bootstrap_field sform.locales layout="control" %}
|
{% bootstrap_field sform.locales layout="control" %}
|
||||||
{% bootstrap_field sform.locale layout="control" %}
|
{% bootstrap_field sform.locale layout="control" %}
|
||||||
{% bootstrap_field sform.timezone layout="control" %}
|
{% bootstrap_field sform.timezone layout="control" %}
|
||||||
|
{% bootstrap_field sform.region layout="control" %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{% trans "Attendee data" %}</legend>
|
<legend>{% trans "Attendee data" %}</legend>
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{% trans "Localization" %}</legend>
|
<legend>{% trans "Localization" %}</legend>
|
||||||
{% bootstrap_field sform.locales layout="control" %}
|
{% bootstrap_field sform.locales layout="control" %}
|
||||||
|
{% bootstrap_field sform.region layout="control" %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{% trans "Shop design" %}</legend>
|
<legend>{% trans "Shop design" %}</legend>
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ from django.http import (
|
|||||||
)
|
)
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import translation
|
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import gettext, gettext_lazy as _
|
from django.utils.translation import gettext, gettext_lazy as _
|
||||||
@@ -55,6 +54,7 @@ from pretix.multidomain.urlreverse import get_event_domain
|
|||||||
from pretix.plugins.stripe.payment import StripeSettingsHolder
|
from pretix.plugins.stripe.payment import StripeSettingsHolder
|
||||||
from pretix.presale.style import regenerate_css
|
from pretix.presale.style import regenerate_css
|
||||||
|
|
||||||
|
from ...base.i18n import language
|
||||||
from ...base.models.items import ItemMetaProperty
|
from ...base.models.items import ItemMetaProperty
|
||||||
from ...base.settings import SETTINGS_AFFECTING_CSS, LazyI18nStringList
|
from ...base.settings import SETTINGS_AFFECTING_CSS, LazyI18nStringList
|
||||||
from ..logdisplay import OVERVIEW_BANLIST
|
from ..logdisplay import OVERVIEW_BANLIST
|
||||||
@@ -659,7 +659,7 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View):
|
|||||||
if matched is not None:
|
if matched is not None:
|
||||||
idx = matched.group('idx')
|
idx = matched.group('idx')
|
||||||
if idx in self.supported_locale:
|
if idx in self.supported_locale:
|
||||||
with translation.override(self.supported_locale[idx]):
|
with language(self.supported_locale[idx], self.request.event.settings.region):
|
||||||
msgs[self.supported_locale[idx]] = markdown_compile_email(
|
msgs[self.supported_locale[idx]] = markdown_compile_email(
|
||||||
v.format_map(self.placeholders(preview_item))
|
v.format_map(self.placeholders(preview_item))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -666,7 +666,7 @@ class OrderCancellationRequestDelete(OrderView):
|
|||||||
}, user=self.request.user)
|
}, user=self.request.user)
|
||||||
|
|
||||||
messages.success(self.request, _('The request has been removed. If you want, you can now inform the user.'))
|
messages.success(self.request, _('The request has been removed. If you want, you can now inform the user.'))
|
||||||
with language(self.order.locale):
|
with language(self.order.locale, self.request.event.settings.region):
|
||||||
return redirect(reverse('control:event.order.sendmail', kwargs={
|
return redirect(reverse('control:event.order.sendmail', kwargs={
|
||||||
'event': self.request.event.slug,
|
'event': self.request.event.slug,
|
||||||
'organizer': self.request.event.organizer.slug,
|
'organizer': self.request.event.organizer.slug,
|
||||||
@@ -937,7 +937,7 @@ class OrderRefundView(OrderView):
|
|||||||
if giftcard_value and self.order.email:
|
if giftcard_value and self.order.email:
|
||||||
messages.success(self.request, _('A new gift card was created. You can now send the user their '
|
messages.success(self.request, _('A new gift card was created. You can now send the user their '
|
||||||
'gift card code.'))
|
'gift card code.'))
|
||||||
with language(self.order.locale):
|
with language(self.order.locale, self.request.event.settings.region):
|
||||||
return redirect(reverse('control:event.order.sendmail', kwargs={
|
return redirect(reverse('control:event.order.sendmail', kwargs={
|
||||||
'event': self.request.event.slug,
|
'event': self.request.event.slug,
|
||||||
'organizer': self.request.event.organizer.slug,
|
'organizer': self.request.event.organizer.slug,
|
||||||
@@ -1779,7 +1779,7 @@ class OrderSendMail(EventPermissionRequiredMixin, OrderViewMixin, FormView):
|
|||||||
code=self.kwargs['code'].upper()
|
code=self.kwargs['code'].upper()
|
||||||
)
|
)
|
||||||
self.preview_output = {}
|
self.preview_output = {}
|
||||||
with language(order.locale):
|
with language(order.locale, self.request.event.settings.region):
|
||||||
email_context = get_email_context(event=order.event, order=order)
|
email_context = get_email_context(event=order.event, order=order)
|
||||||
email_template = LazyI18nString(form.cleaned_data['message'])
|
email_template = LazyI18nString(form.cleaned_data['message'])
|
||||||
email_subject = str(form.cleaned_data['subject']).format_map(TolerantDict(email_context))
|
email_subject = str(form.cleaned_data['subject']).format_map(TolerantDict(email_context))
|
||||||
@@ -1842,7 +1842,7 @@ class OrderPositionSendMail(OrderSendMail):
|
|||||||
attendee_email__isnull=False
|
attendee_email__isnull=False
|
||||||
)
|
)
|
||||||
self.preview_output = {}
|
self.preview_output = {}
|
||||||
with language(position.order.locale):
|
with language(position.order.locale, self.request.event.settings.region):
|
||||||
email_context = get_email_context(event=position.order.event, order=position.order, position=position)
|
email_context = get_email_context(event=position.order.event, order=position.order, position=position)
|
||||||
email_template = LazyI18nString(form.cleaned_data['message'])
|
email_template = LazyI18nString(form.cleaned_data['message'])
|
||||||
email_subject = str(form.cleaned_data['subject']).format_map(TolerantDict(email_context))
|
email_subject = str(form.cleaned_data['subject']).format_map(TolerantDict(email_context))
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if "preview" in request.POST:
|
if "preview" in request.POST:
|
||||||
with rolledback_transaction(), language(request.event.settings.locale):
|
with rolledback_transaction(), language(request.event.settings.locale, request.event.settings.region):
|
||||||
p = self._get_preview_position()
|
p = self._get_preview_position()
|
||||||
fname, mimet, data = self.generate(
|
fname, mimet, data = self.generate(
|
||||||
p,
|
p,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.utils.translation import get_language
|
|
||||||
from django_countries import Countries
|
from django_countries import Countries
|
||||||
from django_countries.fields import CountryField
|
from django_countries.fields import CountryField
|
||||||
|
|
||||||
|
from pretix.base.i18n import get_language_without_region
|
||||||
|
|
||||||
|
|
||||||
class CachedCountries(Countries):
|
class CachedCountries(Countries):
|
||||||
_cached_lists = {}
|
_cached_lists = {}
|
||||||
@@ -14,7 +15,7 @@ class CachedCountries(Countries):
|
|||||||
django-countries performs a unicode-aware sorting based on pyuca which is incredibly
|
django-countries performs a unicode-aware sorting based on pyuca which is incredibly
|
||||||
slow.
|
slow.
|
||||||
"""
|
"""
|
||||||
cache_key = "countries:all:{}".format(get_language())
|
cache_key = "countries:all:{}".format(get_language_without_region())
|
||||||
if self.cache_subkey:
|
if self.cache_subkey:
|
||||||
cache_key += ":" + self.cache_subkey
|
cache_key += ":" + self.cache_subkey
|
||||||
if cache_key in self._cached_lists:
|
if cache_key in self._cached_lists:
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Date according to https://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
|
||||||
|
SHORT_DATE_FORMAT = 'm/d/Y'
|
||||||
|
SHORT_DATETIME_FORMAT = 'm/d/Y P'
|
||||||
|
TIME_FORMAT = 'P'
|
||||||
|
WEEK_FORMAT = '\\W W, o'
|
||||||
|
WEEK_DAY_FORMAT = 'D, M jS'
|
||||||
|
|
||||||
|
DATE_INPUT_FORMATS = [
|
||||||
|
'%m/%d/%Y',
|
||||||
|
'%Y-%m-%d',
|
||||||
|
'%m/%d/%y',
|
||||||
|
]
|
||||||
|
TIME_INPUT_FORMATS = [
|
||||||
|
'%I:%M %p',
|
||||||
|
'%H:%M:%S', # '14:30:59'
|
||||||
|
'%H:%M:%S.%f', # '14:30:59.000200'
|
||||||
|
'%H:%M', # '14:30'
|
||||||
|
]
|
||||||
@@ -126,6 +126,7 @@ def get_javascript_format_without_seconds(format_name):
|
|||||||
|
|
||||||
def get_moment_locale(locale=None):
|
def get_moment_locale(locale=None):
|
||||||
cur_lang = locale or translation.get_language()
|
cur_lang = locale or translation.get_language()
|
||||||
|
cur_lang = cur_lang.lower()
|
||||||
if cur_lang in moment_locales:
|
if cur_lang in moment_locales:
|
||||||
return cur_lang
|
return cur_lang
|
||||||
if '-' in cur_lang or '_' in cur_lang:
|
if '-' in cur_lang or '_' in cur_lang:
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ def render_pdf(event, positions, opt):
|
|||||||
offsetx = opt['margins'][3] + (i % opt['cols']) * opt['offsets'][0]
|
offsetx = opt['margins'][3] + (i % opt['cols']) * opt['offsets'][0]
|
||||||
offsety = opt['margins'][2] + (opt['rows'] - 1 - i // opt['cols']) * opt['offsets'][1]
|
offsety = opt['margins'][2] + (opt['rows'] - 1 - i // opt['cols']) * opt['offsets'][1]
|
||||||
p.translate(offsetx, offsety)
|
p.translate(offsetx, offsety)
|
||||||
with language(op.order.locale):
|
with language(op.order.locale, op.order.event.settings.region):
|
||||||
r.draw_page(p, op.order, op, show_page=False)
|
r.draw_page(p, op.order, op, show_page=False)
|
||||||
p.translate(-offsetx, -offsety)
|
p.translate(-offsetx, -offsety)
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def notify_incomplete_payment(o: Order):
|
def notify_incomplete_payment(o: Order):
|
||||||
with language(o.locale):
|
with language(o.locale, o.event.settings.region):
|
||||||
email_template = o.event.settings.mail_text_order_expire_warning
|
email_template = o.event.settings.mail_text_order_expire_warning
|
||||||
email_context = get_email_context(event=o.event, order=o)
|
email_context = get_email_context(event=o.event, order=o)
|
||||||
email_subject = gettext('Your order received an incomplete payment: %(code)s') % {'code': o.code}
|
email_subject = gettext('Your order received an incomplete payment: %(code)s') % {'code': o.code}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ def send_mails(event: Event, user: int, subject: dict, message: dict, orders: li
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with language(o.locale):
|
with language(o.locale, event.settings.region):
|
||||||
email_context = get_email_context(event=event, order=o, position_or_address=p, position=p)
|
email_context = get_email_context(event=event, order=o, position_or_address=p, position=p)
|
||||||
mail(
|
mail(
|
||||||
p.attendee_email,
|
p.attendee_email,
|
||||||
@@ -80,7 +80,7 @@ def send_mails(event: Event, user: int, subject: dict, message: dict, orders: li
|
|||||||
|
|
||||||
if send_to_order and o.email:
|
if send_to_order and o.email:
|
||||||
try:
|
try:
|
||||||
with language(o.locale):
|
with language(o.locale, event.settings.region):
|
||||||
email_context = get_email_context(event=event, order=o, position_or_address=ia)
|
email_context = get_email_context(event=event, order=o, position_or_address=ia)
|
||||||
mail(
|
mail(
|
||||||
o.email,
|
o.email,
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ class SenderView(EventPermissionRequiredMixin, FormView):
|
|||||||
|
|
||||||
if self.request.POST.get("action") == "preview":
|
if self.request.POST.get("action") == "preview":
|
||||||
for l in self.request.event.settings.locales:
|
for l in self.request.event.settings.locales:
|
||||||
with language(l):
|
with language(l, self.request.event.settings.region):
|
||||||
context_dict = TolerantDict()
|
context_dict = TolerantDict()
|
||||||
for k, v in get_available_placeholders(self.request.event, ['event', 'order',
|
for k, v in get_available_placeholders(self.request.event, ['event', 'order',
|
||||||
'position_or_address']).items():
|
'position_or_address']).items():
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class AllTicketsPDF(BaseExporter):
|
|||||||
if op.order.event != o.event:
|
if op.order.event != o.event:
|
||||||
o = PdfTicketOutput(op.event)
|
o = PdfTicketOutput(op.event)
|
||||||
|
|
||||||
with language(op.order.locale):
|
with language(op.order.locale, o.event.settings.region):
|
||||||
layout = o.layout_map.get(
|
layout = o.layout_map.get(
|
||||||
(op.item_id, op.order.sales_channel),
|
(op.item_id, op.order.sales_channel),
|
||||||
o.layout_map.get(
|
o.layout_map.get(
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class PdfTicketOutput(BaseTicketOutput):
|
|||||||
|
|
||||||
def generate_order(self, order: Order):
|
def generate_order(self, order: Order):
|
||||||
merger = PdfFileMerger()
|
merger = PdfFileMerger()
|
||||||
with language(order.locale):
|
with language(order.locale, self.event.settings.region):
|
||||||
for op in order.positions_with_tickets:
|
for op in order.positions_with_tickets:
|
||||||
layout = override_layout.send_chained(
|
layout = override_layout.send_chained(
|
||||||
order.event, 'layout', orderposition=op, layout=self.layout_map.get(
|
order.event, 'layout', orderposition=op, layout=self.layout_map.get(
|
||||||
@@ -111,7 +111,7 @@ class PdfTicketOutput(BaseTicketOutput):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
with language(order.locale):
|
with language(order.locale, self.event.settings.region):
|
||||||
outbuffer = self._draw_page(layout, op, order)
|
outbuffer = self._draw_page(layout, op, order)
|
||||||
return 'order%s%s.pdf' % (self.event.slug, order.code), 'application/pdf', outbuffer.read()
|
return 'order%s%s.pdf' % (self.event.slug, order.code), 'application/pdf', outbuffer.read()
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from pretix.helpers.i18n import (
|
|||||||
get_javascript_format_without_seconds, get_moment_locale,
|
get_javascript_format_without_seconds, get_moment_locale,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from ..base.i18n import get_language_without_region
|
||||||
from .signals import (
|
from .signals import (
|
||||||
footer_link, global_html_footer, global_html_head, global_html_page_header,
|
footer_link, global_html_footer, global_html_head, global_html_page_header,
|
||||||
html_footer, html_head, html_page_header,
|
html_footer, html_head, html_page_header,
|
||||||
@@ -116,7 +117,7 @@ def _default_context(request):
|
|||||||
ctx['js_date_format'] = get_javascript_format_without_seconds('DATE_INPUT_FORMATS')
|
ctx['js_date_format'] = get_javascript_format_without_seconds('DATE_INPUT_FORMATS')
|
||||||
ctx['js_time_format'] = get_javascript_format_without_seconds('TIME_INPUT_FORMATS')
|
ctx['js_time_format'] = get_javascript_format_without_seconds('TIME_INPUT_FORMATS')
|
||||||
ctx['js_locale'] = get_moment_locale()
|
ctx['js_locale'] = get_moment_locale()
|
||||||
ctx['html_locale'] = translation.get_language_info(translation.get_language()).get('public_code', translation.get_language())
|
ctx['html_locale'] = translation.get_language_info(get_language_without_region()).get('public_code', translation.get_language())
|
||||||
ctx['settings'] = pretix_settings
|
ctx['settings'] = pretix_settings
|
||||||
ctx['django_settings'] = settings
|
ctx['django_settings'] = settings
|
||||||
|
|
||||||
|
|||||||
@@ -329,7 +329,10 @@ def iframe_entry_view_wrapper(view_func):
|
|||||||
|
|
||||||
locale = request.GET.get('locale')
|
locale = request.GET.get('locale')
|
||||||
if locale and locale in [lc for lc, ll in settings.LANGUAGES]:
|
if locale and locale in [lc for lc, ll in settings.LANGUAGES]:
|
||||||
with language(locale):
|
region = None
|
||||||
|
if hasattr(request, 'event'):
|
||||||
|
region = request.event.settings.region
|
||||||
|
with language(locale, region):
|
||||||
resp = view_func(request, *args, **kwargs)
|
resp = view_func(request, *args, **kwargs)
|
||||||
max_age = 10 * 365 * 24 * 60 * 60
|
max_age = 10 * 365 * 24 * 60 * 60
|
||||||
set_cookie_without_samesite(
|
set_cookie_without_samesite(
|
||||||
|
|||||||
@@ -599,7 +599,7 @@ class OrganizerIcalDownload(OrganizerViewMixin, View):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if 'locale' in request.GET and request.GET.get('locale') in dict(settings.LANGUAGES):
|
if 'locale' in request.GET and request.GET.get('locale') in dict(settings.LANGUAGES):
|
||||||
with language(request.GET.get('locale')):
|
with language(request.GET.get('locale'), self.request.organizer.settings.region):
|
||||||
cal = get_ical(events)
|
cal = get_ical(events)
|
||||||
else:
|
else:
|
||||||
cal = get_ical(events)
|
cal = get_ical(events)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.utils import translation
|
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||||
@@ -12,6 +11,7 @@ from pretix.base.templatetags.urlreplace import url_replace
|
|||||||
from pretix.multidomain.urlreverse import eventreverse
|
from pretix.multidomain.urlreverse import eventreverse
|
||||||
from pretix.presale.views import EventViewMixin
|
from pretix.presale.views import EventViewMixin
|
||||||
|
|
||||||
|
from ...base.i18n import get_language_without_region
|
||||||
from ...base.models import Item, ItemVariation, WaitingListEntry
|
from ...base.models import Item, ItemVariation, WaitingListEntry
|
||||||
from ..forms.waitinglist import WaitingListForm
|
from ..forms.waitinglist import WaitingListForm
|
||||||
from . import allow_frame_if_namespaced
|
from . import allow_frame_if_namespaced
|
||||||
@@ -27,7 +27,7 @@ class WaitingView(EventViewMixin, FormView):
|
|||||||
kwargs['event'] = self.request.event
|
kwargs['event'] = self.request.event
|
||||||
kwargs['instance'] = WaitingListEntry(
|
kwargs['instance'] = WaitingListEntry(
|
||||||
item=self.item_and_variation[0], variation=self.item_and_variation[1],
|
item=self.item_and_variation[0], variation=self.item_and_variation[1],
|
||||||
event=self.request.event, locale=translation.get_language(),
|
event=self.request.event, locale=get_language_without_region(),
|
||||||
subevent=self.subevent
|
subevent=self.subevent
|
||||||
)
|
)
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|||||||
@@ -302,8 +302,9 @@ class WidgetAPIProductList(EventListMixin, View):
|
|||||||
return self._get_event_view(request, **kwargs)
|
return self._get_event_view(request, **kwargs)
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
o = getattr(request, 'event', request.organizer)
|
||||||
if 'lang' in request.GET and request.GET.get('lang') in [lc for lc, ll in settings.LANGUAGES]:
|
if 'lang' in request.GET and request.GET.get('lang') in [lc for lc, ll in settings.LANGUAGES]:
|
||||||
with language(request.GET.get('lang')):
|
with language(request.GET.get('lang'), o.settings.region):
|
||||||
return self.get(request, **kwargs)
|
return self.get(request, **kwargs)
|
||||||
else:
|
else:
|
||||||
return self.get(request, **kwargs)
|
return self.get(request, **kwargs)
|
||||||
|
|||||||
@@ -1,15 +1,42 @@
|
|||||||
from pretix.base.i18n import language
|
from django.utils.translation import get_language
|
||||||
|
|
||||||
|
from pretix.base.i18n import get_language_without_region, language
|
||||||
from pretix.helpers.i18n import get_javascript_format, get_moment_locale
|
from pretix.helpers.i18n import get_javascript_format, get_moment_locale
|
||||||
|
|
||||||
|
|
||||||
def test_js_formats():
|
def test_js_formats():
|
||||||
with language('de'):
|
with language('de'):
|
||||||
assert get_javascript_format('DATETIME_INPUT_FORMATS') == 'DD.MM.YYYY HH:mm:ss'
|
assert get_javascript_format('DATE_INPUT_FORMATS') == 'DD.MM.YYYY'
|
||||||
with language('en'):
|
with language('en'):
|
||||||
assert get_javascript_format('DATETIME_INPUT_FORMATS') == 'YYYY-MM-DD HH:mm:ss'
|
assert get_javascript_format('DATE_INPUT_FORMATS') == 'YYYY-MM-DD'
|
||||||
|
with language('en-US'):
|
||||||
|
assert get_javascript_format('DATE_INPUT_FORMATS') == 'MM/DD/YYYY'
|
||||||
|
|
||||||
|
|
||||||
def test_get_locale():
|
def test_get_locale():
|
||||||
get_moment_locale('af') == 'af'
|
assert get_moment_locale('af') == 'af'
|
||||||
get_moment_locale('de_Informal') == 'de'
|
assert get_moment_locale('de_Informal') == 'de'
|
||||||
get_moment_locale('de-AT') == 'de'
|
assert get_moment_locale('de-US') == 'de'
|
||||||
|
assert get_moment_locale('en-US') == 'en'
|
||||||
|
assert get_moment_locale('en-CA') == 'en-ca'
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_region():
|
||||||
|
with language('de'):
|
||||||
|
assert get_language() == 'de'
|
||||||
|
assert get_language_without_region() == 'de'
|
||||||
|
with language('de', 'US'):
|
||||||
|
assert get_language() == 'de-us'
|
||||||
|
assert get_language_without_region() == 'de'
|
||||||
|
with language('de', 'DE'):
|
||||||
|
assert get_language() == 'de-de'
|
||||||
|
assert get_language_without_region() == 'de'
|
||||||
|
with language('de-informal', 'DE'):
|
||||||
|
assert get_language() == 'de-informal'
|
||||||
|
assert get_language_without_region() == 'de-informal'
|
||||||
|
with language('pt', 'PT'):
|
||||||
|
assert get_language() == 'pt-pt'
|
||||||
|
assert get_language_without_region() == 'pt-pt'
|
||||||
|
with language('pt-pt', 'BR'):
|
||||||
|
assert get_language() == 'pt-pt'
|
||||||
|
assert get_language_without_region() == 'pt-pt'
|
||||||
|
|||||||
@@ -2683,6 +2683,20 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
|||||||
o.payments.first().confirm()
|
o.payments.first().confirm()
|
||||||
assert len(djmail.outbox) == 0
|
assert len(djmail.outbox) == 0
|
||||||
|
|
||||||
|
def test_locale_region_not_saved(self):
|
||||||
|
self.event.settings.origin = 'US'
|
||||||
|
self.event.settings.locales = ['de']
|
||||||
|
self.event.settings.locale = 'de'
|
||||||
|
with scopes_disabled():
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||||
|
price=0, expires=now() + timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||||
|
with scopes_disabled():
|
||||||
|
self.assertEqual(Order.objects.first().locale, 'de')
|
||||||
|
|
||||||
|
|
||||||
class QuestionsTestCase(BaseCheckoutTestCase, TestCase):
|
class QuestionsTestCase(BaseCheckoutTestCase, TestCase):
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class EventTestMixin:
|
|||||||
self.orga = Organizer.objects.create(name='CCC', slug='ccc')
|
self.orga = Organizer.objects.create(name='CCC', slug='ccc')
|
||||||
self.event = Event.objects.create(
|
self.event = Event.objects.create(
|
||||||
organizer=self.orga, name='30C3', slug='30c3',
|
organizer=self.orga, name='30C3', slug='30c3',
|
||||||
date_from=datetime.datetime(now().year + 1, 12, 26, tzinfo=datetime.timezone.utc),
|
date_from=datetime.datetime(now().year + 1, 12, 26, 14, 0, tzinfo=datetime.timezone.utc),
|
||||||
live=True, sales_channels=['web', 'bar']
|
live=True, sales_channels=['web', 'bar']
|
||||||
)
|
)
|
||||||
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
|
||||||
@@ -1306,3 +1306,49 @@ class EventSlugBanlistValidatorTest(EventTestMixin, SoupTest):
|
|||||||
event.save()
|
event.save()
|
||||||
|
|
||||||
self.assertEqual(Event.objects.filter(name='download').count(), 0)
|
self.assertEqual(Event.objects.filter(name='download').count(), 0)
|
||||||
|
|
||||||
|
|
||||||
|
class EventLocaleTest(EventTestMixin, SoupTest):
|
||||||
|
@scopes_disabled()
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.event.settings.locales = ['de', 'en']
|
||||||
|
self.event.settings.locale = 'de'
|
||||||
|
self.event.settings.timezone = 'UTC'
|
||||||
|
|
||||||
|
def test_german_by_default(self):
|
||||||
|
response = self.client.get(
|
||||||
|
'/%s/%s/' % (self.orga.slug, self.event.slug)
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertIn('26. Dezember', response.rendered_content)
|
||||||
|
self.assertIn('14:00', response.rendered_content)
|
||||||
|
|
||||||
|
def test_english_no_region_set(self):
|
||||||
|
self.client.get('/locale/set?locale=en')
|
||||||
|
response = self.client.get(
|
||||||
|
'/%s/%s/' % (self.orga.slug, self.event.slug)
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertIn('Dec. 26,', response.rendered_content)
|
||||||
|
self.assertIn('14:00', response.rendered_content)
|
||||||
|
|
||||||
|
def test_english_region_US(self):
|
||||||
|
self.event.settings.region = 'US'
|
||||||
|
self.client.get('/locale/set?locale=en')
|
||||||
|
response = self.client.get(
|
||||||
|
'/%s/%s/' % (self.orga.slug, self.event.slug)
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertIn('Dec. 26,', response.rendered_content)
|
||||||
|
self.assertIn('2 p.m.', response.rendered_content)
|
||||||
|
|
||||||
|
def test_german_region_US(self):
|
||||||
|
self.event.settings.region = 'US'
|
||||||
|
self.client.get('/locale/set?locale=de')
|
||||||
|
response = self.client.get(
|
||||||
|
'/%s/%s/' % (self.orga.slug, self.event.slug)
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertIn('26. Dezember', response.rendered_content)
|
||||||
|
self.assertIn('14:00', response.rendered_content)
|
||||||
|
|||||||
Reference in New Issue
Block a user