forked from CGM_Public/pretix_original
Add region setting to supplement localization (#1875)
This commit is contained in:
@@ -574,6 +574,7 @@ class EventSettingsSerializer(serializers.Serializer):
|
||||
'presale_start_show_date',
|
||||
'locales',
|
||||
'locale',
|
||||
'region',
|
||||
'last_order_modification_date',
|
||||
'show_quota_left',
|
||||
'waiting_list_enabled',
|
||||
|
||||
@@ -180,7 +180,7 @@ class PdfDataSerializer(serializers.Field):
|
||||
res = {}
|
||||
|
||||
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
|
||||
# we serialize a list.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from decimal import Decimal
|
||||
|
||||
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 rest_framework import serializers
|
||||
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.order import CompatibleJSONField
|
||||
from pretix.base.auth import get_auth_backends
|
||||
from pretix.base.i18n import get_language_without_region
|
||||
from pretix.base.models import (
|
||||
Device, GiftCard, GiftCardTransaction, Organizer, SeatingPlan, Team,
|
||||
TeamAPIToken, TeamInvite, User,
|
||||
@@ -145,7 +146,7 @@ class TeamInviteSerializer(serializers.ModelSerializer):
|
||||
})
|
||||
},
|
||||
event=None,
|
||||
locale=get_language() # TODO: expose?
|
||||
locale=get_language_without_region() # TODO: expose?
|
||||
)
|
||||
except SendMailException:
|
||||
pass # Already logged
|
||||
@@ -217,6 +218,7 @@ class OrganizerSettingsSerializer(serializers.Serializer):
|
||||
'giftcard_length',
|
||||
'giftcard_expiry_years',
|
||||
'locales',
|
||||
'region',
|
||||
'event_team_provisioning',
|
||||
'primary_color',
|
||||
'theme_color_success',
|
||||
|
||||
@@ -582,7 +582,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
||||
auth=request.auth,
|
||||
)
|
||||
|
||||
with language(order.locale):
|
||||
with language(order.locale, self.request.event.settings.region):
|
||||
order_placed.send(self.request.event, order=order)
|
||||
if order.status == Order.STATUS_PAID:
|
||||
order_paid.send(self.request.event, order=order)
|
||||
@@ -886,7 +886,7 @@ class OrderPositionViewSet(mixins.DestroyModelMixin, viewsets.ReadOnlyModelViewS
|
||||
|
||||
price = get_price(**kwargs)
|
||||
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({
|
||||
'gross': price.gross,
|
||||
'gross_formatted': money_filter(price.gross, self.request.event.currency, hide_currency=True),
|
||||
|
||||
@@ -115,7 +115,7 @@ class TemplateBasedMailRenderer(BaseHTMLMailRenderer):
|
||||
'body': body_md,
|
||||
'subject': str(subject),
|
||||
'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:
|
||||
htmlctx['event'] = self.event
|
||||
|
||||
@@ -35,7 +35,7 @@ from pretix.base.forms.widgets import (
|
||||
BusinessBooleanRadio, DatePickerWidget, SplitDateTimePickerWidget,
|
||||
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.tax import (
|
||||
EU_COUNTRIES, cc_to_vat_prefix, is_eu_country,
|
||||
@@ -216,8 +216,8 @@ class WrappedPhoneNumberPrefixWidget(PhoneNumberPrefixWidget):
|
||||
def guess_country(event):
|
||||
# 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 :)
|
||||
locale = get_language()
|
||||
country = event.settings.invoice_address_from_country
|
||||
locale = get_language_without_region()
|
||||
country = event.settings.region or event.settings.invoice_address_from_country
|
||||
if not country:
|
||||
valid_countries = countries.countries
|
||||
if '-' in locale:
|
||||
|
||||
@@ -66,10 +66,42 @@ class LazyNumber:
|
||||
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
|
||||
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()
|
||||
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:
|
||||
yield
|
||||
finally:
|
||||
|
||||
@@ -144,7 +144,7 @@ class BaseReportlabInvoiceRenderer(BaseInvoiceRenderer):
|
||||
|
||||
def _upper(self, val):
|
||||
# We uppercase labels, but not in every language
|
||||
if get_language() == 'el':
|
||||
if get_language().startswith('el'):
|
||||
return val
|
||||
return val.upper()
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ from django.utils.translation.trans_real import (
|
||||
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 (
|
||||
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
|
||||
# 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.
|
||||
if hasattr(request, 'event') and not request.path.startswith(get_script_prefix() + 'control'):
|
||||
if language not in request.event.settings.locales:
|
||||
firstpart = language.split('-')[0]
|
||||
if firstpart in request.event.settings.locales:
|
||||
language = firstpart
|
||||
else:
|
||||
language = request.event.settings.locale
|
||||
for lang in request.event.settings.locales:
|
||||
if lang.startswith(firstpart + '-'):
|
||||
language = lang
|
||||
break
|
||||
if not request.path.startswith(get_script_prefix() + 'control'):
|
||||
if hasattr(request, 'event'):
|
||||
if language not in request.event.settings.locales:
|
||||
firstpart = language.split('-')[0]
|
||||
if firstpart in request.event.settings.locales:
|
||||
language = firstpart
|
||||
else:
|
||||
language = request.event.settings.locale
|
||||
for lang in request.event.settings.locales:
|
||||
if lang.startswith(firstpart + '-'):
|
||||
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)
|
||||
request.LANGUAGE_CODE = translation.get_language()
|
||||
request.LANGUAGE_CODE = get_language_without_region()
|
||||
|
||||
tzname = None
|
||||
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\"'
|
||||
|
||||
img_src = []
|
||||
gs = GlobalSettingsObject()
|
||||
gs = global_settings_object(request)
|
||||
if gs.settings.leaflet_tiles:
|
||||
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():
|
||||
context['meta_' + k] = v
|
||||
|
||||
with language(self.locale):
|
||||
with language(self.locale, self.event.settings.region):
|
||||
recipient = self.email
|
||||
if position and position.attendee_email:
|
||||
recipient = position.attendee_email
|
||||
@@ -890,7 +890,7 @@ class Order(LockModel, LoggedModel):
|
||||
)
|
||||
|
||||
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_context = get_email_context(event=self.event, order=self)
|
||||
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):
|
||||
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_context = get_email_context(event=self.order.event, order=self.order, position=position)
|
||||
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):
|
||||
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_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}
|
||||
@@ -2104,7 +2104,7 @@ class OrderPosition(AbstractPosition):
|
||||
for k, v in self.event.meta_data.items():
|
||||
context['meta_' + k] = v
|
||||
|
||||
with language(self.order.locale):
|
||||
with language(self.order.locale, self.order.event.settings.region):
|
||||
recipient = self.attendee_email
|
||||
try:
|
||||
email_content = render_mail(template, context)
|
||||
@@ -2132,7 +2132,7 @@ class OrderPosition(AbstractPosition):
|
||||
|
||||
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_context = get_email_context(event=self.order.event, order=self.order, position=self)
|
||||
email_subject = _('Your event registration: %(code)s') % {'code': self.order.code}
|
||||
|
||||
@@ -125,7 +125,7 @@ class WaitingListEntry(LoggedModel):
|
||||
self.voucher = v
|
||||
self.save()
|
||||
|
||||
with language(self.locale):
|
||||
with language(self.locale, self.event.settings.region):
|
||||
mail(
|
||||
self.email,
|
||||
_('You have been selected from the waitinglist for {event}').format(event=str(self.event)),
|
||||
|
||||
@@ -421,6 +421,7 @@ class Renderer:
|
||||
self.layout = layout
|
||||
self.background_file = background_file
|
||||
self.variables = get_variables(event)
|
||||
self.event = event
|
||||
if self.background_file:
|
||||
self.bg_bytes = self.background_file.read()
|
||||
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):
|
||||
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)
|
||||
|
||||
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):
|
||||
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)
|
||||
try:
|
||||
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,
|
||||
refund_amount: Decimal, user: User, positions: list):
|
||||
with language(order.locale):
|
||||
with language(order.locale, order.event.settings.region):
|
||||
try:
|
||||
ia = order.invoice_address
|
||||
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)
|
||||
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)
|
||||
for receiver, response in responses:
|
||||
ex = response(event, set_progress)
|
||||
@@ -67,15 +67,18 @@ def multiexport(self, organizer: Organizer, user: User, device: int, token: int,
|
||||
if user:
|
||||
locale = user.locale
|
||||
timezone = user.timezone
|
||||
region = None # todo: add to user?
|
||||
else:
|
||||
e = allowed_events.first()
|
||||
if e:
|
||||
locale = e.settings.locale
|
||||
timezone = e.settings.timezone
|
||||
region = e.settings.region
|
||||
else:
|
||||
locale = settings.LANGUAGE_CODE
|
||||
timezone = settings.TIME_ZONE
|
||||
with language(locale), override(timezone):
|
||||
region = None
|
||||
with language(locale, region), override(timezone):
|
||||
if isinstance(form_data['events'][0], str):
|
||||
events = allowed_events.filter(slug__in=form_data.get('events'), organizer=organizer)
|
||||
else:
|
||||
|
||||
@@ -43,7 +43,7 @@ def build_invoice(invoice: Invoice) -> Invoice:
|
||||
|
||||
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_name = invoice.event.settings.get('invoice_address_from_name')
|
||||
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.payment_provider_text = ''
|
||||
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_name = invoice.event.settings.get('invoice_address_from_name')
|
||||
cancellation.invoice_from_zipcode = invoice.event.settings.get('invoice_address_from_zipcode')
|
||||
@@ -297,7 +297,7 @@ def invoice_pdf_task(invoice: int):
|
||||
return None
|
||||
if i.file:
|
||||
i.file.delete()
|
||||
with language(i.locale):
|
||||
with language(i.locale, i.event.settings.region):
|
||||
fname, ftype, fcontent = i.event.invoice_renderer.generate(i)
|
||||
i.file.save(fname, ContentFile(fcontent))
|
||||
i.save()
|
||||
@@ -328,7 +328,7 @@ def build_preview_invoice_pdf(event):
|
||||
if not locale or locale == '__user__':
|
||||
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(),
|
||||
expires=timezone.now(), code="PREVIEW", total=100 * event.tax_rules.count())
|
||||
invoice = Invoice(
|
||||
|
||||
@@ -290,7 +290,7 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
|
||||
except Order.DoesNotExist:
|
||||
order = None
|
||||
else:
|
||||
with language(order.locale):
|
||||
with language(order.locale, event.settings.region):
|
||||
if position:
|
||||
try:
|
||||
position = order.positions.get(pk=position)
|
||||
|
||||
@@ -65,7 +65,7 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user)
|
||||
# TODO: quotacheck?
|
||||
cf = CachedFile.objects.get(id=fileid)
|
||||
user = User.objects.get(pk=user)
|
||||
with language(locale):
|
||||
with language(locale, event.settings.region):
|
||||
cols = get_all_columns(event)
|
||||
parsed = parse_csv(cf.file)
|
||||
orders = []
|
||||
@@ -163,7 +163,7 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user)
|
||||
)
|
||||
|
||||
for o in orders:
|
||||
with language(o.locale):
|
||||
with language(o.locale, event.settings.region):
|
||||
order_placed.send(event, order=o)
|
||||
if o.status == Order.STATUS_PAID:
|
||||
order_paid.send(event, order=o)
|
||||
|
||||
@@ -23,7 +23,9 @@ from django_scopes import scopes_disabled
|
||||
from pretix.api.models import OAuthApplication
|
||||
from pretix.base.channels import get_all_sales_channels
|
||||
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 (
|
||||
CartPosition, Device, Event, GiftCard, Item, ItemVariation, Order,
|
||||
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
|
||||
|
||||
if send_mail:
|
||||
with language(order.locale):
|
||||
with language(order.locale, order.event.settings.region):
|
||||
if order.total == Decimal('0.00'):
|
||||
email_template = order.event.settings.mail_text_order_approved_free
|
||||
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:
|
||||
email_template = order.event.settings.mail_text_order_denied
|
||||
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}
|
||||
try:
|
||||
order.send_mail(
|
||||
@@ -422,7 +424,7 @@ def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, device
|
||||
|
||||
if send_mail:
|
||||
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_subject = _('Order canceled: %(code)s') % {'code': order.code}
|
||||
try:
|
||||
@@ -777,7 +779,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
|
||||
event=event,
|
||||
email=email,
|
||||
datetime=now_dt,
|
||||
locale=locale,
|
||||
locale=get_language_without_region(locale),
|
||||
total=total,
|
||||
testmode=True if sales_channel.testmode_supported and event.testmode else False,
|
||||
meta_info=json.dumps(meta_info or {}),
|
||||
@@ -1033,7 +1035,7 @@ def send_expiry_warnings(sender, **kwargs):
|
||||
# Race condition
|
||||
continue
|
||||
|
||||
with language(o.locale):
|
||||
with language(o.locale, settings.region):
|
||||
o.expiry_reminder_sent = True
|
||||
o.save(update_fields=['expiry_reminder_sent'])
|
||||
email_template = settings.mail_text_order_expire_warning
|
||||
@@ -1110,7 +1112,7 @@ def send_download_reminders(sender, **kwargs):
|
||||
if not send:
|
||||
continue
|
||||
|
||||
with language(o.locale):
|
||||
with language(o.locale, o.event.settings.region):
|
||||
o.download_reminder_sent = True
|
||||
o.save(update_fields=['download_reminder_sent'])
|
||||
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=[]):
|
||||
with language(order.locale):
|
||||
with language(order.locale, order.event.settings.region):
|
||||
email_template = order.event.settings.mail_text_order_changed
|
||||
email_context = get_email_context(event=order.event, order=order)
|
||||
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):
|
||||
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)
|
||||
for receiver, response in responses:
|
||||
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):
|
||||
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)
|
||||
for receiver, response in responses:
|
||||
prov = response(order.event)
|
||||
@@ -75,7 +75,7 @@ class DummyRollbackException(Exception):
|
||||
def preview(event: int, provider: str):
|
||||
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,
|
||||
description=_("Sample product description"))
|
||||
item2 = event.items.create(name=_("Sample workshop"), default_price=23.40)
|
||||
|
||||
@@ -832,6 +832,20 @@ DEFAULTS = {
|
||||
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': {
|
||||
'default': 'True',
|
||||
'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.
|
||||
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.email import get_available_placeholders
|
||||
from pretix.base.forms import (
|
||||
I18nModelForm, PlaceholderValidator, SettingsForm,
|
||||
)
|
||||
from pretix.base.forms import I18nModelForm, PlaceholderValidator, SettingsForm
|
||||
from pretix.base.models import Event, Organizer, TaxRule, Team
|
||||
from pretix.base.models.event import EventMetaValue, SubEvent
|
||||
from pretix.base.reldate import RelativeDateField, RelativeDateTimeField
|
||||
@@ -459,6 +457,7 @@ class EventSettingsForm(SettingsForm):
|
||||
'presale_start_show_date',
|
||||
'locales',
|
||||
'locale',
|
||||
'region',
|
||||
'show_quota_left',
|
||||
'waiting_list_enabled',
|
||||
'waiting_list_hours',
|
||||
|
||||
@@ -10,11 +10,15 @@ from pretix.base.signals import register_global_settings
|
||||
|
||||
|
||||
class GlobalSettingsForm(SettingsForm):
|
||||
auto_fields = [
|
||||
'region'
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.obj = GlobalSettingsObject()
|
||||
super().__init__(*args, obj=self.obj, **kwargs)
|
||||
|
||||
self.fields = OrderedDict([
|
||||
self.fields = OrderedDict(list(self.fields.items()) + [
|
||||
('footer_text', I18nFormField(
|
||||
widget=I18nTextInput,
|
||||
required=False,
|
||||
|
||||
@@ -223,6 +223,7 @@ class OrganizerSettingsForm(SettingsForm):
|
||||
'giftcard_length',
|
||||
'giftcard_expiry_years',
|
||||
'locales',
|
||||
'region',
|
||||
'event_team_provisioning',
|
||||
'primary_color',
|
||||
'theme_color_success',
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
{% bootstrap_field sform.locales layout="control" %}
|
||||
{% bootstrap_field sform.locale layout="control" %}
|
||||
{% bootstrap_field sform.timezone layout="control" %}
|
||||
{% bootstrap_field sform.region layout="control" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Attendee data" %}</legend>
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
<fieldset>
|
||||
<legend>{% trans "Localization" %}</legend>
|
||||
{% bootstrap_field sform.locales layout="control" %}
|
||||
{% bootstrap_field sform.region layout="control" %}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Shop design" %}</legend>
|
||||
|
||||
@@ -19,7 +19,6 @@ from django.http import (
|
||||
)
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.utils import translation
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
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.presale.style import regenerate_css
|
||||
|
||||
from ...base.i18n import language
|
||||
from ...base.models.items import ItemMetaProperty
|
||||
from ...base.settings import SETTINGS_AFFECTING_CSS, LazyI18nStringList
|
||||
from ..logdisplay import OVERVIEW_BANLIST
|
||||
@@ -659,7 +659,7 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View):
|
||||
if matched is not None:
|
||||
idx = matched.group('idx')
|
||||
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(
|
||||
v.format_map(self.placeholders(preview_item))
|
||||
)
|
||||
|
||||
@@ -666,7 +666,7 @@ class OrderCancellationRequestDelete(OrderView):
|
||||
}, user=self.request.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={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
@@ -937,7 +937,7 @@ class OrderRefundView(OrderView):
|
||||
if giftcard_value and self.order.email:
|
||||
messages.success(self.request, _('A new gift card was created. You can now send the user their '
|
||||
'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={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
@@ -1779,7 +1779,7 @@ class OrderSendMail(EventPermissionRequiredMixin, OrderViewMixin, FormView):
|
||||
code=self.kwargs['code'].upper()
|
||||
)
|
||||
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_template = LazyI18nString(form.cleaned_data['message'])
|
||||
email_subject = str(form.cleaned_data['subject']).format_map(TolerantDict(email_context))
|
||||
@@ -1842,7 +1842,7 @@ class OrderPositionSendMail(OrderSendMail):
|
||||
attendee_email__isnull=False
|
||||
)
|
||||
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_template = LazyI18nString(form.cleaned_data['message'])
|
||||
email_subject = str(form.cleaned_data['subject']).format_map(TolerantDict(email_context))
|
||||
|
||||
@@ -188,7 +188,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
|
||||
pass
|
||||
|
||||
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()
|
||||
fname, mimet, data = self.generate(
|
||||
p,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
from django.core.cache import cache
|
||||
from django.utils.translation import get_language
|
||||
from django_countries import Countries
|
||||
from django_countries.fields import CountryField
|
||||
|
||||
from pretix.base.i18n import get_language_without_region
|
||||
|
||||
|
||||
class CachedCountries(Countries):
|
||||
_cached_lists = {}
|
||||
@@ -14,7 +15,7 @@ class CachedCountries(Countries):
|
||||
django-countries performs a unicode-aware sorting based on pyuca which is incredibly
|
||||
slow.
|
||||
"""
|
||||
cache_key = "countries:all:{}".format(get_language())
|
||||
cache_key = "countries:all:{}".format(get_language_without_region())
|
||||
if self.cache_subkey:
|
||||
cache_key += ":" + self.cache_subkey
|
||||
if cache_key in self._cached_lists:
|
||||
|
||||
0
src/pretix/helpers/formats/en_US/__init__.py
Normal file
0
src/pretix/helpers/formats/en_US/__init__.py
Normal file
18
src/pretix/helpers/formats/en_US/formats.py
Normal file
18
src/pretix/helpers/formats/en_US/formats.py
Normal file
@@ -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):
|
||||
cur_lang = locale or translation.get_language()
|
||||
cur_lang = cur_lang.lower()
|
||||
if cur_lang in moment_locales:
|
||||
return 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]
|
||||
offsety = opt['margins'][2] + (opt['rows'] - 1 - i // opt['cols']) * opt['offsets'][1]
|
||||
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)
|
||||
p.translate(-offsetx, -offsety)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
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_context = get_email_context(event=o.event, order=o)
|
||||
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
|
||||
|
||||
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)
|
||||
mail(
|
||||
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:
|
||||
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)
|
||||
mail(
|
||||
o.email,
|
||||
|
||||
@@ -127,7 +127,7 @@ class SenderView(EventPermissionRequiredMixin, FormView):
|
||||
|
||||
if self.request.POST.get("action") == "preview":
|
||||
for l in self.request.event.settings.locales:
|
||||
with language(l):
|
||||
with language(l, self.request.event.settings.region):
|
||||
context_dict = TolerantDict()
|
||||
for k, v in get_available_placeholders(self.request.event, ['event', 'order',
|
||||
'position_or_address']).items():
|
||||
|
||||
@@ -82,7 +82,7 @@ class AllTicketsPDF(BaseExporter):
|
||||
if op.order.event != o.event:
|
||||
o = PdfTicketOutput(op.event)
|
||||
|
||||
with language(op.order.locale):
|
||||
with language(op.order.locale, o.event.settings.region):
|
||||
layout = o.layout_map.get(
|
||||
(op.item_id, op.order.sales_channel),
|
||||
o.layout_map.get(
|
||||
|
||||
@@ -79,7 +79,7 @@ class PdfTicketOutput(BaseTicketOutput):
|
||||
|
||||
def generate_order(self, order: Order):
|
||||
merger = PdfFileMerger()
|
||||
with language(order.locale):
|
||||
with language(order.locale, self.event.settings.region):
|
||||
for op in order.positions_with_tickets:
|
||||
layout = override_layout.send_chained(
|
||||
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)
|
||||
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,
|
||||
)
|
||||
|
||||
from ..base.i18n import get_language_without_region
|
||||
from .signals import (
|
||||
footer_link, global_html_footer, global_html_head, global_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_time_format'] = get_javascript_format_without_seconds('TIME_INPUT_FORMATS')
|
||||
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['django_settings'] = settings
|
||||
|
||||
|
||||
@@ -329,7 +329,10 @@ def iframe_entry_view_wrapper(view_func):
|
||||
|
||||
locale = request.GET.get('locale')
|
||||
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)
|
||||
max_age = 10 * 365 * 24 * 60 * 60
|
||||
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):
|
||||
with language(request.GET.get('locale')):
|
||||
with language(request.GET.get('locale'), self.request.organizer.settings.region):
|
||||
cal = get_ical(events)
|
||||
else:
|
||||
cal = get_ical(events)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
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.functional import cached_property
|
||||
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.presale.views import EventViewMixin
|
||||
|
||||
from ...base.i18n import get_language_without_region
|
||||
from ...base.models import Item, ItemVariation, WaitingListEntry
|
||||
from ..forms.waitinglist import WaitingListForm
|
||||
from . import allow_frame_if_namespaced
|
||||
@@ -27,7 +27,7 @@ class WaitingView(EventViewMixin, FormView):
|
||||
kwargs['event'] = self.request.event
|
||||
kwargs['instance'] = WaitingListEntry(
|
||||
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
|
||||
)
|
||||
return kwargs
|
||||
|
||||
@@ -302,8 +302,9 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
return self._get_event_view(request, **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]:
|
||||
with language(request.GET.get('lang')):
|
||||
with language(request.GET.get('lang'), o.settings.region):
|
||||
return self.get(request, **kwargs)
|
||||
else:
|
||||
return self.get(request, **kwargs)
|
||||
|
||||
Reference in New Issue
Block a user