Fix #308 -- Preview for email templates (#438)

* add ajax and dummy api response

* add preview <p> blocks

* finalise order_placed setup

- use <pre> for mail preview
- create dummy data in backend

* fix i18n text conversion

* create fragment template for mail preview

* support i18n in mail preview view

* apply mail fragment in all mail settings

fix mistake in input[lang=en] flag style
add dummy data for all placeholders
apply fragment template to all fields
add exclude option to fragment template

* remove migration file

* add translation mapping & fix field label

remove hardcoded field label
add transblock for translation file

* add test for mail setting preview

* fix code style in preview class

* bug fix in mail preview view

- fixed localised date values
- added locale index mapping
- added tests on multi-language event
- enhanced dummy data
This commit is contained in:
jlwt90
2017-04-14 18:19:58 +09:00
committed by Raphael Michel
parent 5ee79c8148
commit bc6b84f900
9 changed files with 823 additions and 345 deletions

View File

@@ -32,6 +32,7 @@
<script type="text/javascript" src="{% static "pretixcontrol/js/ui/main.js" %}"></script>
<script type="text/javascript" src="{% static "pretixcontrol/js/ui/quota.js" %}"></script>
<script type="text/javascript" src="{% static "pretixcontrol/js/ui/question.js" %}"></script>
<script type="text/javascript" src="{% static "pretixcontrol/js/ui/mail.js" %}"></script>
<script type="text/javascript" src="{% static "pretixbase/js/asynctask.js" %}"></script>
<script type="text/javascript" src="{% static "pretixbase/js/asyncdownload.js" %}"></script>
{% endcompress %}

View File

@@ -2,7 +2,8 @@
{% load i18n %}
{% load bootstrap3 %}
{% block inside %}
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data"
mail-preview-url="{% url "control:event.settings.mail.preview" event=request.event.slug organizer=request.event.organizer.slug %}">
{% csrf_token %}
{% bootstrap_form_errors form %}
<fieldset>
@@ -13,106 +14,26 @@
<fieldset>
<legend>{% trans "E-mail content" %}</legend>
<div class="panel-group" id="questions_group">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#order_placed">
<strong>{% trans "Placed order" %}</strong>
</a>
</h4>
</div>
<div id="order_placed" class="panel-collapse collapse">
<div class="panel-body">
{% bootstrap_field form.mail_text_order_placed layout="horizontal" %}
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#order_paid">
<strong>{% trans "Paid order" %}</strong>
</a>
</h4>
</div>
<div id="order_paid" class="panel-collapse collapse">
<div class="panel-body">
{% bootstrap_field form.mail_text_order_paid layout="horizontal" %}
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#order_free">
<strong>{% trans "Free order" %}</strong>
</a>
</h4>
</div>
<div id="order_free" class="panel-collapse collapse">
<div class="panel-body">
{% bootstrap_field form.mail_text_order_free layout="horizontal" %}
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#resend_link">
<strong>{% trans "Resend link" %}</strong>
</a>
</h4>
</div>
<div id="resend_link" class="panel-collapse collapse">
<div class="panel-body">
{% bootstrap_field form.mail_text_resend_link layout="horizontal" %}
{% bootstrap_field form.mail_text_resend_all_links layout="horizontal" %}
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#order_changed">
<strong>{% trans "Order changed" %}</strong>
</a>
</h4>
</div>
<div id="order_changed" class="panel-collapse collapse">
<div class="panel-body">
{% bootstrap_field form.mail_text_order_changed layout="horizontal" %}
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#order_expirew">
<strong>{% trans "Payment reminder" %}</strong>
</a>
</h4>
</div>
<div id="order_expirew" class="panel-collapse collapse">
<div class="panel-body">
{% bootstrap_field form.mail_days_order_expire_warning layout="horizontal" %}
{% bootstrap_field form.mail_text_order_expire_warning layout="horizontal" %}
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#waiting_list">
<strong>{% trans "Waiting list notification" %}</strong>
</a>
</h4>
</div>
<div id="waiting_list" class="panel-collapse collapse">
<div class="panel-body">
{% bootstrap_field form.mail_text_waiting_list layout="horizontal" %}
</div>
</div>
</div>
{% blocktrans asvar title_placed_order %}Placed order{% endblocktrans %}
{% include "pretixcontrol/event/mail_settings_fragment.html" with pid="order_placed" title=title_placed_order items="mail_text_order_placed" %}
{% blocktrans asvar title_paid_order %}Paid order{% endblocktrans %}
{% include "pretixcontrol/event/mail_settings_fragment.html" with pid="order_paid" title=title_paid_order items="mail_text_order_paid" %}
{% blocktrans asvar title_free_order %}Free order{% endblocktrans %}
{% include "pretixcontrol/event/mail_settings_fragment.html" with pid="order_free" title=title_free_order items="mail_text_order_free" %}
{% blocktrans asvar title_resend_link %}Resend link{% endblocktrans %}
{% include "pretixcontrol/event/mail_settings_fragment.html" with pid="resend_link" title=title_resend_link items="mail_text_resend_link,mail_text_resend_all_links" %}
{% blocktrans asvar title_order_changed %}Order changed{% endblocktrans %}
{% include "pretixcontrol/event/mail_settings_fragment.html" with pid="order_changed" title=title_order_changed items="mail_text_order_changed" %}
{% blocktrans asvar title_payment_reminder %}Payment reminder{% endblocktrans %}
{% include "pretixcontrol/event/mail_settings_fragment.html" with pid="order_expirew" title=title_payment_reminder items="mail_days_order_expire_warning,mail_text_order_expire_warning" exclude="mail_days_order_expire_warning" %}
{% blocktrans asvar title_waiting_list_notification %}Waiting list notification{% endblocktrans %}
{% include "pretixcontrol/event/mail_settings_fragment.html" with pid="waiting_list" title=title_waiting_list_notification items="mail_text_waiting_list" %}
</div>
</fieldset>
<fieldset>

View File

@@ -0,0 +1,53 @@
{% load i18n %}
{% load bootstrap3 %}
{% load mail_settings_preview %}
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#{{ pid }}">
<strong>{% trans title %}</strong>
</a>
</h4>
</div>
<div id="{{ pid }}" class="panel-collapse collapse">
<div class="panel-body">
{% with exclude|split as exclusion %}
{% with items|split as item_list %}
{% for item in item_list %}
{% if item in exclusion %}
{% with form|getattr:item as field %}
{% bootstrap_field field layout="horizontal" %}
{% endwith %}
{% else %}
<div id="{{ item }}_panel" class="preview-panel form-group" for="{{ item }}">
{% with form|getattr:item as field %}
<label class="col-md-3 control-label">{{ field.label }}</label>
<div class="col-md-9">
<div class="tab-content">
<div id="{{ item }}_edit" class="tab-pane fade in active">
{% bootstrap_field field show_label=False form_group_class="" %}
</div>
<div id="{{ item }}_preview" class="tab-pane">
{% for l in request.event.settings.locales %}
<pre lang="{{ l }}" for="{{ item }}"></pre>
{% endfor %}
</div>
</div>
<ul class="nav nav-pills pull-right">
<li role="presentation" class="active">
<a data-toggle="pill" type="edit" href="#{{ item }}_edit"><i class="fa fa-pencil-square-o fa-fw"></i> {% trans "Edit" %}</a>
</li>
<li role="presentation">
<a data-toggle="pill" type="preview" href="#{{ item }}_preview"><i class="fa fa-tv fa-fw"></i> {% trans "Preview" %}</a>
</li>
</ul>
</div>
{% endwith %}
</div>
{% endif %}
{% endfor %}
{% endwith %}
{% endwith %}
</div>
</div>
</div>

View File

@@ -0,0 +1,13 @@
from django import template
register = template.Library()
@register.filter(name='split', delimiter=",")
def split(value, delimiter=","):
return value.split(delimiter)
@register.filter(name="getattr")
def get_attribute(value, key):
return value[key]

View File

@@ -52,6 +52,7 @@ urlpatterns = [
url(r'^settings/tickets/preview/(?P<output>[^/]+)$', event.TicketSettingsPreview.as_view(),
name='event.settings.tickets.preview'),
url(r'^settings/email$', event.MailSettings.as_view(), name='event.settings.mail'),
url(r'^settings/email/preview$', event.MailSettingsPreview.as_view(), name='event.settings.mail.preview'),
url(r'^settings/invoice$', event.InvoiceSettings.as_view(), name='event.settings.invoice'),
url(r'^settings/invoice/preview$', event.InvoicePreview.as_view(), name='event.settings.invoice.preview'),
url(r'^settings/display', event.DisplaySettings.as_view(), name='event.settings.display'),

View File

@@ -1,15 +1,21 @@
import re
from collections import OrderedDict
from datetime import timedelta
from django import forms
from django.conf import settings
from django.contrib import messages
from django.contrib.contenttypes.models import ContentType
from django.core.files import File
from django.core.urlresolvers import reverse
from django.db import transaction
from django.forms import modelformset_factory
from django.http import HttpResponse
from django.http import HttpResponse, HttpResponseBadRequest, JsonResponse
from django.shortcuts import get_object_or_404, redirect
from django.utils import translation
from django.utils.formats import date_format
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django.views.generic import FormView, ListView
from django.views.generic.base import TemplateView, View
@@ -400,6 +406,112 @@ class MailSettings(EventSettingsFormView):
return self.get(request)
class MailSettingsPreview(EventPermissionRequiredMixin, View):
permission = 'can_change_settings'
# return the origin text if key is missing in dict
class SafeDict(dict):
def __missing__(self, key):
return '{' + key + '}'
@staticmethod
def generate_order_fullname(slug, code):
return '{event}-{code}'.format(event=slug.upper(), code=code)
# create data which depend on locale
def localized_data(self):
return {
'date': date_format(now() + timedelta(days=7), 'SHORT_DATE_FORMAT'),
'expire_date': date_format(now() + timedelta(days=15), 'SHORT_DATE_FORMAT'),
'payment_info': _('{} {} has been transferred to account<9999-9999-9999-9999> at {}').format(
42.23, self.request.event.currency, date_format(now(), 'SHORT_DATETIME_FORMAT'))
}
# create index-language mapping
@cached_property
def supported_locale(self):
locales = {}
for idx, val in enumerate(settings.LANGUAGES):
if val[0] in self.request.event.settings.locales:
locales[str(idx)] = val[0]
return locales
@cached_property
def items(self):
return {
'mail_text_order_placed': ['total', 'currency', 'date', 'invoice_company',
'event', 'paymentinfo', 'url', 'invoice_name'],
'mail_text_order_paid': ['event', 'url', 'invoice_name', 'invoice_company', 'payment_info'],
'mail_text_order_free': ['event', 'url', 'invoice_name', 'invoice_company'],
'mail_text_resend_link': ['event', 'url', 'invoice_name', 'invoice_company'],
'mail_text_resend_all_links': ['event', 'orders'],
'mail_text_order_changed': ['event', 'url', 'invoice_name', 'invoice_company'],
'mail_text_order_expire_warning': ['event', 'url', 'expire_date', 'invoice_name', 'invoice_company'],
'mail_text_waiting_list': ['event', 'url', 'product', 'hours', 'code']
}
@cached_property
def base_data(self):
user_orders = [
{'code': 'F8VVL', 'secret': '6zzjnumtsx136ddy'},
{'code': 'HIDHK', 'secret': '98kusd8ofsj8dnkd'},
{'code': 'OPKSB', 'secret': '09pjdksflosk3njd'}
]
orders = [' - {} - {}'.format(self.generate_order_fullname(self.request.event.slug, order['code']),
self.generate_order_url(order['code'], order['secret']))
for order in user_orders]
return {
'event': self.request.event.name,
'total': 42.23,
'currency': self.request.event.currency,
'url': self.generate_order_url(user_orders[0]['code'], user_orders[0]['secret']),
'orders': '\n'.join(orders),
'hours': self.request.event.settings.waiting_list_hours,
'product': _('Sample Admission Ticket'),
'code': '68CYU2H6ZTP3WLK5',
'invoice_name': _('John Doe'),
'invoice_company': _('Sample Corporation'),
'paymentinfo': _('Please transfer money to this bank account: 9999-9999-9999-9999')
}
def generate_order_url(self, code, secret):
return build_absolute_uri('presale:event.order', kwargs={
'event': self.request.event.slug,
'organizer': self.request.event.organizer.slug,
'order': code,
'secret': secret
})
# get all supported placeholders with dummy values
def placeholders(self, item):
supported = {}
local_data = self.localized_data()
for key in self.items.get(item):
supported[key] = self.base_data.get(key) if key in self.base_data else local_data.get(key)
return self.SafeDict(supported)
def post(self, request, *args, **kwargs):
preview_item = request.POST.get('item', '')
if preview_item not in self.items:
return HttpResponseBadRequest(_('invalid item'))
regex = r"^" + re.escape(preview_item) + r"_(?P<idx>[\d+])$"
msgs = {}
for k, v in request.POST.items():
# only accept allowed fields
matched = re.search(regex, k)
if matched is not None:
idx = matched.group('idx')
if idx in self.supported_locale:
with translation.override(self.supported_locale[idx]):
msgs[self.supported_locale[idx]] = v.format_map(self.placeholders(preview_item))
return JsonResponse({
'item': preview_item,
'msgs': msgs
})
class TicketSettingsPreview(EventPermissionRequiredMixin, View):
permission = 'can_change_settings'

View File

@@ -0,0 +1,67 @@
function preview_task_callback(data, jqXHR, status) {
"use strict";
if (data.item) {
$('#' + data.item + '_panel').data('ajaxing', false);
for (var m in data.msgs){
var target = $('pre[for=' + data.item + '][lang=' + m +']');
if (target.length === 1){
target.text(data.msgs[m]);
}
}
}
}
function preview_task_error(item) {
"use strict";
return function(jqXHR, textStatus, errorThrown) {
$('#' + item + '_panel').data('ajaxing', false);
$('#' + item + '_preview pre').text(gettext('An error has occurred.'));
if (textStatus === "timeout") {
alert(gettext("The request took to long. Please try again."));
} else {
if (jqXHR.status >= 400 && jqXHR.status < 500) {
alert(gettext('An error of type {code} occurred.').replace(/\{code\}/, jqXHR.status));
} else {
alert(gettext('We currently cannot reach the server. Please try again. ' +
'Error code: {code}').replace(/\{code\}/, jqXHR.status));
}
}
}
}
$(function () {
"use strict";
$('a[type=preview]').on('click', function () {
var itemName = $(this).closest('.preview-panel').attr('for');
if ($('#' + itemName + '_panel').data('ajaxing') || $(this).parent('.active').length !== 0) {
return;
}
// gathering data
var parentForm = $(this).closest('form');
var previewUrl = $(parentForm).attr('mail-preview-url');
var token = $(parentForm).find('input[name=csrfmiddlewaretoken]').val();
var dataString = 'item=' + itemName + '&csrfmiddlewaretoken=' + token;
$('#' + itemName + '_edit textarea').each(function () {
dataString += '&' + $(this).serialize();
});
// prepare for ajax
$('#' + itemName + '_panel').data('ajaxing', true);
$('#' + itemName + '_preview pre').text(gettext('Generating messages …'));
$.ajax(
{
'type': 'POST',
'url': previewUrl,
'data': dataString,
'success': preview_task_callback,
'error': preview_task_error(itemName),
'dataType': 'json',
'timeout': 60000,
}
);
});
});

View File

@@ -6,247 +6,254 @@ textarea[lang] {
background: no-repeat 10px 10px;
padding-left: 34px;
}
input[lang=ad], textarea[lang=ad] { background-image: url(static('pretixbase/img/flags/ad.png')); }
input[lang=ae], textarea[lang=ae] { background-image: url(static('pretixbase/img/flags/ae.png')); }
input[lang=af], textarea[lang=af] { background-image: url(static('pretixbase/img/flags/af.png')); }
input[lang=ag], textarea[lang=ag] { background-image: url(static('pretixbase/img/flags/ag.png')); }
input[lang=ai], textarea[lang=ai] { background-image: url(static('pretixbase/img/flags/ai.png')); }
input[lang=al], textarea[lang=al] { background-image: url(static('pretixbase/img/flags/al.png')); }
input[lang=am], textarea[lang=am] { background-image: url(static('pretixbase/img/flags/am.png')); }
input[lang=an], textarea[lang=an] { background-image: url(static('pretixbase/img/flags/an.png')); }
input[lang=ao], textarea[lang=ao] { background-image: url(static('pretixbase/img/flags/ao.png')); }
input[lang=ar], textarea[lang=ar] { background-image: url(static('pretixbase/img/flags/ar.png')); }
input[lang=as], textarea[lang=as] { background-image: url(static('pretixbase/img/flags/as.png')); }
input[lang=at], textarea[lang=at] { background-image: url(static('pretixbase/img/flags/at.png')); }
input[lang=au], textarea[lang=au] { background-image: url(static('pretixbase/img/flags/au.png')); }
input[lang=aw], textarea[lang=aw] { background-image: url(static('pretixbase/img/flags/aw.png')); }
input[lang=ax], textarea[lang=ax] { background-image: url(static('pretixbase/img/flags/ax.png')); }
input[lang=az], textarea[lang=az] { background-image: url(static('pretixbase/img/flags/az.png')); }
input[lang=ba], textarea[lang=ba] { background-image: url(static('pretixbase/img/flags/ba.png')); }
input[lang=bb], textarea[lang=bb] { background-image: url(static('pretixbase/img/flags/bb.png')); }
input[lang=bd], textarea[lang=bd] { background-image: url(static('pretixbase/img/flags/bd.png')); }
input[lang=be], textarea[lang=be] { background-image: url(static('pretixbase/img/flags/be.png')); }
input[lang=bf], textarea[lang=bf] { background-image: url(static('pretixbase/img/flags/bf.png')); }
input[lang=bg], textarea[lang=bg] { background-image: url(static('pretixbase/img/flags/bg.png')); }
input[lang=bh], textarea[lang=bh] { background-image: url(static('pretixbase/img/flags/bh.png')); }
input[lang=bi], textarea[lang=bi] { background-image: url(static('pretixbase/img/flags/bi.png')); }
input[lang=bj], textarea[lang=bj] { background-image: url(static('pretixbase/img/flags/bj.png')); }
input[lang=bm], textarea[lang=bm] { background-image: url(static('pretixbase/img/flags/bm.png')); }
input[lang=bn], textarea[lang=bn] { background-image: url(static('pretixbase/img/flags/bn.png')); }
input[lang=bo], textarea[lang=bo] { background-image: url(static('pretixbase/img/flags/bo.png')); }
input[lang=br], textarea[lang=br] { background-image: url(static('pretixbase/img/flags/br.png')); }
input[lang=bs], textarea[lang=bs] { background-image: url(static('pretixbase/img/flags/bs.png')); }
input[lang=bt], textarea[lang=bt] { background-image: url(static('pretixbase/img/flags/bt.png')); }
input[lang=bv], textarea[lang=bv] { background-image: url(static('pretixbase/img/flags/bv.png')); }
input[lang=bw], textarea[lang=bw] { background-image: url(static('pretixbase/img/flags/bw.png')); }
input[lang=by], textarea[lang=by] { background-image: url(static('pretixbase/img/flags/by.png')); }
input[lang=bz], textarea[lang=bz] { background-image: url(static('pretixbase/img/flags/bz.png')); }
input[lang=ca], textarea[lang=ca] { background-image: url(static('pretixbase/img/flags/ca.png')); }
input[lang=cc], textarea[lang=cc] { background-image: url(static('pretixbase/img/flags/cc.png')); }
input[lang=cd], textarea[lang=cd] { background-image: url(static('pretixbase/img/flags/cd.png')); }
input[lang=cf], textarea[lang=cf] { background-image: url(static('pretixbase/img/flags/cf.png')); }
input[lang=cg], textarea[lang=cg] { background-image: url(static('pretixbase/img/flags/cg.png')); }
input[lang=ch], textarea[lang=ch] { background-image: url(static('pretixbase/img/flags/ch.png')); }
input[lang=ci], textarea[lang=ci] { background-image: url(static('pretixbase/img/flags/ci.png')); }
input[lang=ck], textarea[lang=ck] { background-image: url(static('pretixbase/img/flags/ck.png')); }
input[lang=cl], textarea[lang=cl] { background-image: url(static('pretixbase/img/flags/cl.png')); }
input[lang=cm], textarea[lang=cm] { background-image: url(static('pretixbase/img/flags/cm.png')); }
input[lang=cn], textarea[lang=cn] { background-image: url(static('pretixbase/img/flags/cn.png')); }
input[lang=co], textarea[lang=co] { background-image: url(static('pretixbase/img/flags/co.png')); }
input[lang=cr], textarea[lang=cr] { background-image: url(static('pretixbase/img/flags/cr.png')); }
input[lang=cs], textarea[lang=cs] { background-image: url(static('pretixbase/img/flags/cs.png')); }
input[lang=cu], textarea[lang=cu] { background-image: url(static('pretixbase/img/flags/cu.png')); }
input[lang=cv], textarea[lang=cv] { background-image: url(static('pretixbase/img/flags/cv.png')); }
input[lang=cx], textarea[lang=cx] { background-image: url(static('pretixbase/img/flags/cx.png')); }
input[lang=cy], textarea[lang=cy] { background-image: url(static('pretixbase/img/flags/cy.png')); }
input[lang=cz], textarea[lang=cz] { background-image: url(static('pretixbase/img/flags/cz.png')); }
input[lang=de], textarea[lang=de] { background-image: url(static('pretixbase/img/flags/de.png')); }
input[lang=de-informal], textarea[lang=de-informal] { background-image: url(static('pretixbase/img/flags/de-informal.png')); }
input[lang=dj], textarea[lang=dj] { background-image: url(static('pretixbase/img/flags/dj.png')); }
input[lang=dk], textarea[lang=dk] { background-image: url(static('pretixbase/img/flags/dk.png')); }
input[lang=dm], textarea[lang=dm] { background-image: url(static('pretixbase/img/flags/dm.png')); }
input[lang=do], textarea[lang=do] { background-image: url(static('pretixbase/img/flags/do.png')); }
input[lang=dz], textarea[lang=dz] { background-image: url(static('pretixbase/img/flags/dz.png')); }
input[lang=ec], textarea[lang=ec] { background-image: url(static('pretixbase/img/flags/ec.png')); }
input[lang=ee], textarea[lang=ee] { background-image: url(static('pretixbase/img/flags/ee.png')); }
input[lang=eg], textarea[lang=eg] { background-image: url(static('pretixbase/img/flags/eg.png')); }
input[lang=eh], textarea[lang=eh] { background-image: url(static('pretixbase/img/flags/eh.png')); }
input[lang=er], textarea[lang=er] { background-image: url(static('pretixbase/img/flags/er.png')); }
input[lang=es], textarea[lang=es] { background-image: url(static('pretixbase/img/flags/es.png')); }
input[lang=et], textarea[lang=et] { background-image: url(static('pretixbase/img/flags/et.png')); }
input[lang=fi], textarea[lang=fi] { background-image: url(static('pretixbase/img/flags/fi.png')); }
input[lang=fj], textarea[lang=fj] { background-image: url(static('pretixbase/img/flags/fj.png')); }
input[lang=fk], textarea[lang=fk] { background-image: url(static('pretixbase/img/flags/fk.png')); }
input[lang=fm], textarea[lang=fm] { background-image: url(static('pretixbase/img/flags/fm.png')); }
input[lang=fo], textarea[lang=fo] { background-image: url(static('pretixbase/img/flags/fo.png')); }
input[lang=fr], textarea[lang=fr] { background-image: url(static('pretixbase/img/flags/fr.png')); }
input[lang=ga], textarea[lang=ga] { background-image: url(static('pretixbase/img/flags/ga.png')); }
input[lang=gb], textarea[lang=gb] { background-image: url(static('pretixbase/img/flags/gb.png')); }
input[lang=gd], textarea[lang=gd] { background-image: url(static('pretixbase/img/flags/gd.png')); }
input[lang=ge], textarea[lang=ge] { background-image: url(static('pretixbase/img/flags/ge.png')); }
input[lang=gf], textarea[lang=gf] { background-image: url(static('pretixbase/img/flags/gf.png')); }
input[lang=gh], textarea[lang=gh] { background-image: url(static('pretixbase/img/flags/gh.png')); }
input[lang=gi], textarea[lang=gi] { background-image: url(static('pretixbase/img/flags/gi.png')); }
input[lang=gl], textarea[lang=gl] { background-image: url(static('pretixbase/img/flags/gl.png')); }
input[lang=gm], textarea[lang=gm] { background-image: url(static('pretixbase/img/flags/gm.png')); }
input[lang=gn], textarea[lang=gn] { background-image: url(static('pretixbase/img/flags/gn.png')); }
input[lang=gp], textarea[lang=gp] { background-image: url(static('pretixbase/img/flags/gp.png')); }
input[lang=gq], textarea[lang=gq] { background-image: url(static('pretixbase/img/flags/gq.png')); }
input[lang=gr], textarea[lang=gr] { background-image: url(static('pretixbase/img/flags/gr.png')); }
input[lang=gs], textarea[lang=gs] { background-image: url(static('pretixbase/img/flags/gs.png')); }
input[lang=gt], textarea[lang=gt] { background-image: url(static('pretixbase/img/flags/gt.png')); }
input[lang=gu], textarea[lang=gu] { background-image: url(static('pretixbase/img/flags/gu.png')); }
input[lang=gw], textarea[lang=gw] { background-image: url(static('pretixbase/img/flags/gw.png')); }
input[lang=gy], textarea[lang=gy] { background-image: url(static('pretixbase/img/flags/gy.png')); }
input[lang=hk], textarea[lang=hk] { background-image: url(static('pretixbase/img/flags/hk.png')); }
input[lang=hm], textarea[lang=hm] { background-image: url(static('pretixbase/img/flags/hm.png')); }
input[lang=hn], textarea[lang=hn] { background-image: url(static('pretixbase/img/flags/hn.png')); }
input[lang=hr], textarea[lang=hr] { background-image: url(static('pretixbase/img/flags/hr.png')); }
input[lang=ht], textarea[lang=ht] { background-image: url(static('pretixbase/img/flags/ht.png')); }
input[lang=hu], textarea[lang=hu] { background-image: url(static('pretixbase/img/flags/hu.png')); }
input[lang=id], textarea[lang=id] { background-image: url(static('pretixbase/img/flags/id.png')); }
input[lang=ie], textarea[lang=ie] { background-image: url(static('pretixbase/img/flags/ie.png')); }
input[lang=il], textarea[lang=il] { background-image: url(static('pretixbase/img/flags/il.png')); }
input[lang=in], textarea[lang=in] { background-image: url(static('pretixbase/img/flags/in.png')); }
input[lang=io], textarea[lang=io] { background-image: url(static('pretixbase/img/flags/io.png')); }
input[lang=iq], textarea[lang=iq] { background-image: url(static('pretixbase/img/flags/iq.png')); }
input[lang=ir], textarea[lang=ir] { background-image: url(static('pretixbase/img/flags/ir.png')); }
input[lang=is], textarea[lang=is] { background-image: url(static('pretixbase/img/flags/is.png')); }
input[lang=it], textarea[lang=it] { background-image: url(static('pretixbase/img/flags/it.png')); }
input[lang=jm], textarea[lang=jm] { background-image: url(static('pretixbase/img/flags/jm.png')); }
input[lang=jo], textarea[lang=jo] { background-image: url(static('pretixbase/img/flags/jo.png')); }
input[lang=jp], textarea[lang=jp] { background-image: url(static('pretixbase/img/flags/jp.png')); }
input[lang=ke], textarea[lang=ke] { background-image: url(static('pretixbase/img/flags/ke.png')); }
input[lang=kg], textarea[lang=kg] { background-image: url(static('pretixbase/img/flags/kg.png')); }
input[lang=kh], textarea[lang=kh] { background-image: url(static('pretixbase/img/flags/kh.png')); }
input[lang=ki], textarea[lang=ki] { background-image: url(static('pretixbase/img/flags/ki.png')); }
input[lang=km], textarea[lang=km] { background-image: url(static('pretixbase/img/flags/km.png')); }
input[lang=kn], textarea[lang=kn] { background-image: url(static('pretixbase/img/flags/kn.png')); }
input[lang=kp], textarea[lang=kp] { background-image: url(static('pretixbase/img/flags/kp.png')); }
input[lang=kr], textarea[lang=kr] { background-image: url(static('pretixbase/img/flags/kr.png')); }
input[lang=kw], textarea[lang=kw] { background-image: url(static('pretixbase/img/flags/kw.png')); }
input[lang=ky], textarea[lang=ky] { background-image: url(static('pretixbase/img/flags/ky.png')); }
input[lang=kz], textarea[lang=kz] { background-image: url(static('pretixbase/img/flags/kz.png')); }
input[lang=la], textarea[lang=la] { background-image: url(static('pretixbase/img/flags/la.png')); }
input[lang=lb], textarea[lang=lb] { background-image: url(static('pretixbase/img/flags/lb.png')); }
input[lang=lc], textarea[lang=lc] { background-image: url(static('pretixbase/img/flags/lc.png')); }
input[lang=li], textarea[lang=li] { background-image: url(static('pretixbase/img/flags/li.png')); }
input[lang=lk], textarea[lang=lk] { background-image: url(static('pretixbase/img/flags/lk.png')); }
input[lang=lr], textarea[lang=lr] { background-image: url(static('pretixbase/img/flags/lr.png')); }
input[lang=ls], textarea[lang=ls] { background-image: url(static('pretixbase/img/flags/ls.png')); }
input[lang=lt], textarea[lang=lt] { background-image: url(static('pretixbase/img/flags/lt.png')); }
input[lang=lu], textarea[lang=lu] { background-image: url(static('pretixbase/img/flags/lu.png')); }
input[lang=lv], textarea[lang=lv] { background-image: url(static('pretixbase/img/flags/lv.png')); }
input[lang=ly], textarea[lang=ly] { background-image: url(static('pretixbase/img/flags/ly.png')); }
input[lang=ma], textarea[lang=ma] { background-image: url(static('pretixbase/img/flags/ma.png')); }
input[lang=mc], textarea[lang=mc] { background-image: url(static('pretixbase/img/flags/mc.png')); }
input[lang=md], textarea[lang=md] { background-image: url(static('pretixbase/img/flags/md.png')); }
input[lang=me], textarea[lang=me] { background-image: url(static('pretixbase/img/flags/me.png')); }
input[lang=mg], textarea[lang=mg] { background-image: url(static('pretixbase/img/flags/mg.png')); }
input[lang=mh], textarea[lang=mh] { background-image: url(static('pretixbase/img/flags/mh.png')); }
input[lang=mk], textarea[lang=mk] { background-image: url(static('pretixbase/img/flags/mk.png')); }
input[lang=ml], textarea[lang=ml] { background-image: url(static('pretixbase/img/flags/ml.png')); }
input[lang=mm], textarea[lang=mm] { background-image: url(static('pretixbase/img/flags/mm.png')); }
input[lang=mn], textarea[lang=mn] { background-image: url(static('pretixbase/img/flags/mn.png')); }
input[lang=mo], textarea[lang=mo] { background-image: url(static('pretixbase/img/flags/mo.png')); }
input[lang=mp], textarea[lang=mp] { background-image: url(static('pretixbase/img/flags/mp.png')); }
input[lang=mq], textarea[lang=mq] { background-image: url(static('pretixbase/img/flags/mq.png')); }
input[lang=mr], textarea[lang=mr] { background-image: url(static('pretixbase/img/flags/mr.png')); }
input[lang=ms], textarea[lang=ms] { background-image: url(static('pretixbase/img/flags/ms.png')); }
input[lang=mt], textarea[lang=mt] { background-image: url(static('pretixbase/img/flags/mt.png')); }
input[lang=mu], textarea[lang=mu] { background-image: url(static('pretixbase/img/flags/mu.png')); }
input[lang=mv], textarea[lang=mv] { background-image: url(static('pretixbase/img/flags/mv.png')); }
input[lang=mw], textarea[lang=mw] { background-image: url(static('pretixbase/img/flags/mw.png')); }
input[lang=mx], textarea[lang=mx] { background-image: url(static('pretixbase/img/flags/mx.png')); }
input[lang=my], textarea[lang=my] { background-image: url(static('pretixbase/img/flags/my.png')); }
input[lang=mz], textarea[lang=mz] { background-image: url(static('pretixbase/img/flags/mz.png')); }
input[lang=na], textarea[lang=na] { background-image: url(static('pretixbase/img/flags/na.png')); }
input[lang=nc], textarea[lang=nc] { background-image: url(static('pretixbase/img/flags/nc.png')); }
input[lang=ne], textarea[lang=ne] { background-image: url(static('pretixbase/img/flags/ne.png')); }
input[lang=nf], textarea[lang=nf] { background-image: url(static('pretixbase/img/flags/nf.png')); }
input[lang=ng], textarea[lang=ng] { background-image: url(static('pretixbase/img/flags/ng.png')); }
input[lang=ni], textarea[lang=ni] { background-image: url(static('pretixbase/img/flags/ni.png')); }
input[lang=nl], textarea[lang=nl] { background-image: url(static('pretixbase/img/flags/nl.png')); }
input[lang=no], textarea[lang=no] { background-image: url(static('pretixbase/img/flags/no.png')); }
input[lang=np], textarea[lang=np] { background-image: url(static('pretixbase/img/flags/np.png')); }
input[lang=nr], textarea[lang=nr] { background-image: url(static('pretixbase/img/flags/nr.png')); }
input[lang=nu], textarea[lang=nu] { background-image: url(static('pretixbase/img/flags/nu.png')); }
input[lang=nz], textarea[lang=nz] { background-image: url(static('pretixbase/img/flags/nz.png')); }
input[lang=om], textarea[lang=om] { background-image: url(static('pretixbase/img/flags/om.png')); }
input[lang=pa], textarea[lang=pa] { background-image: url(static('pretixbase/img/flags/pa.png')); }
input[lang=pe], textarea[lang=pe] { background-image: url(static('pretixbase/img/flags/pe.png')); }
input[lang=pf], textarea[lang=pf] { background-image: url(static('pretixbase/img/flags/pf.png')); }
input[lang=pg], textarea[lang=pg] { background-image: url(static('pretixbase/img/flags/pg.png')); }
input[lang=ph], textarea[lang=ph] { background-image: url(static('pretixbase/img/flags/ph.png')); }
input[lang=pk], textarea[lang=pk] { background-image: url(static('pretixbase/img/flags/pk.png')); }
input[lang=pl], textarea[lang=pl] { background-image: url(static('pretixbase/img/flags/pl.png')); }
input[lang=pm], textarea[lang=pm] { background-image: url(static('pretixbase/img/flags/pm.png')); }
input[lang=pn], textarea[lang=pn] { background-image: url(static('pretixbase/img/flags/pn.png')); }
input[lang=pr], textarea[lang=pr] { background-image: url(static('pretixbase/img/flags/pr.png')); }
input[lang=ps], textarea[lang=ps] { background-image: url(static('pretixbase/img/flags/ps.png')); }
input[lang=pt], textarea[lang=pt] { background-image: url(static('pretixbase/img/flags/pt.png')); }
input[lang=pw], textarea[lang=pw] { background-image: url(static('pretixbase/img/flags/pw.png')); }
input[lang=py], textarea[lang=py] { background-image: url(static('pretixbase/img/flags/py.png')); }
input[lang=qa], textarea[lang=qa] { background-image: url(static('pretixbase/img/flags/qa.png')); }
input[lang=re], textarea[lang=re] { background-image: url(static('pretixbase/img/flags/re.png')); }
input[lang=ro], textarea[lang=ro] { background-image: url(static('pretixbase/img/flags/ro.png')); }
input[lang=rs], textarea[lang=rs] { background-image: url(static('pretixbase/img/flags/rs.png')); }
input[lang=ru], textarea[lang=ru] { background-image: url(static('pretixbase/img/flags/ru.png')); }
input[lang=rw], textarea[lang=rw] { background-image: url(static('pretixbase/img/flags/rw.png')); }
input[lang=sa], textarea[lang=sa] { background-image: url(static('pretixbase/img/flags/sa.png')); }
input[lang=sb], textarea[lang=sb] { background-image: url(static('pretixbase/img/flags/sb.png')); }
input[lang=sc], textarea[lang=sc] { background-image: url(static('pretixbase/img/flags/sc.png')); }
input[lang=sd], textarea[lang=sd] { background-image: url(static('pretixbase/img/flags/sd.png')); }
input[lang=se], textarea[lang=se] { background-image: url(static('pretixbase/img/flags/se.png')); }
input[lang=sg], textarea[lang=sg] { background-image: url(static('pretixbase/img/flags/sg.png')); }
input[lang=sh], textarea[lang=sh] { background-image: url(static('pretixbase/img/flags/sh.png')); }
input[lang=si], textarea[lang=si] { background-image: url(static('pretixbase/img/flags/si.png')); }
input[lang=sj], textarea[lang=sj] { background-image: url(static('pretixbase/img/flags/sj.png')); }
input[lang=sk], textarea[lang=sk] { background-image: url(static('pretixbase/img/flags/sk.png')); }
input[lang=sl], textarea[lang=sl] { background-image: url(static('pretixbase/img/flags/sl.png')); }
input[lang=sm], textarea[lang=sm] { background-image: url(static('pretixbase/img/flags/sm.png')); }
input[lang=sn], textarea[lang=sn] { background-image: url(static('pretixbase/img/flags/sn.png')); }
input[lang=so], textarea[lang=so] { background-image: url(static('pretixbase/img/flags/so.png')); }
input[lang=sr], textarea[lang=sr] { background-image: url(static('pretixbase/img/flags/sr.png')); }
input[lang=st], textarea[lang=st] { background-image: url(static('pretixbase/img/flags/st.png')); }
input[lang=sv], textarea[lang=sv] { background-image: url(static('pretixbase/img/flags/sv.png')); }
input[lang=sy], textarea[lang=sy] { background-image: url(static('pretixbase/img/flags/sy.png')); }
input[lang=sz], textarea[lang=sz] { background-image: url(static('pretixbase/img/flags/sz.png')); }
input[lang=tc], textarea[lang=tc] { background-image: url(static('pretixbase/img/flags/tc.png')); }
input[lang=td], textarea[lang=td] { background-image: url(static('pretixbase/img/flags/td.png')); }
input[lang=tf], textarea[lang=tf] { background-image: url(static('pretixbase/img/flags/tf.png')); }
input[lang=tg], textarea[lang=tg] { background-image: url(static('pretixbase/img/flags/tg.png')); }
input[lang=th], textarea[lang=th] { background-image: url(static('pretixbase/img/flags/th.png')); }
input[lang=tj], textarea[lang=tj] { background-image: url(static('pretixbase/img/flags/tj.png')); }
input[lang=tk], textarea[lang=tk] { background-image: url(static('pretixbase/img/flags/tk.png')); }
input[lang=tl], textarea[lang=tl] { background-image: url(static('pretixbase/img/flags/tl.png')); }
input[lang=tm], textarea[lang=tm] { background-image: url(static('pretixbase/img/flags/tm.png')); }
input[lang=tn], textarea[lang=tn] { background-image: url(static('pretixbase/img/flags/tn.png')); }
input[lang=to], textarea[lang=to] { background-image: url(static('pretixbase/img/flags/to.png')); }
input[lang=tr], textarea[lang=tr] { background-image: url(static('pretixbase/img/flags/tr.png')); }
input[lang=tt], textarea[lang=tt] { background-image: url(static('pretixbase/img/flags/tt.png')); }
input[lang=tv], textarea[lang=tv] { background-image: url(static('pretixbase/img/flags/tv.png')); }
input[lang=tw], textarea[lang=tw] { background-image: url(static('pretixbase/img/flags/tw.png')); }
input[lang=tz], textarea[lang=tz] { background-image: url(static('pretixbase/img/flags/tz.png')); }
input[lang=ua], textarea[lang=ua] { background-image: url(static('pretixbase/img/flags/ua.png')); }
input[lang=ug], textarea[lang=ug] { background-image: url(static('pretixbase/img/flags/ug.png')); }
input[lang=um], textarea[lang=um] { background-image: url(static('pretixbase/img/flags/um.png')); }
input[lang=us], textarea[lang=us] { background-image: url(static('pretixbase/img/flags/us.png')); }
input[lang=uy], textarea[lang=uy] { background-image: url(static('pretixbase/img/flags/uy.png')); }
input[lang=uz], textarea[lang=uz] { background-image: url(static('pretixbase/img/flags/uz.png')); }
input[lang=va], textarea[lang=va] { background-image: url(static('pretixbase/img/flags/va.png')); }
input[lang=vc], textarea[lang=vc] { background-image: url(static('pretixbase/img/flags/vc.png')); }
input[lang=ve], textarea[lang=ve] { background-image: url(static('pretixbase/img/flags/ve.png')); }
input[lang=vg], textarea[lang=vg] { background-image: url(static('pretixbase/img/flags/vg.png')); }
input[lang=vi], textarea[lang=vi] { background-image: url(static('pretixbase/img/flags/vi.png')); }
input[lang=vn], textarea[lang=vn] { background-image: url(static('pretixbase/img/flags/vn.png')); }
input[lang=vu], textarea[lang=vu] { background-image: url(static('pretixbase/img/flags/vu.png')); }
input[lang=wf], textarea[lang=wf] { background-image: url(static('pretixbase/img/flags/wf.png')); }
input[lang=ws], textarea[lang=ws] { background-image: url(static('pretixbase/img/flags/ws.png')); }
input[lang=ye], textarea[lang=ye] { background-image: url(static('pretixbase/img/flags/ye.png')); }
input[lang=yt], textarea[lang=yt] { background-image: url(static('pretixbase/img/flags/yt.png')); }
input[lang=za], textarea[lang=za] { background-image: url(static('pretixbase/img/flags/za.png')); }
input[lang=zm], textarea[lang=zm] { background-image: url(static('pretixbase/img/flags/zm.png')); }
input[lang=zw], textarea[lang=zw] { background-image: url(static('pretixbase/img/flags/zw.png')); }
pre[lang] {
background: no-repeat 10px 10px;
padding-left: 34px;
padding-top: 5px;
margin-bottom: 20px;
}
input[lang=en], textarea[lang=en] { background-image: url(static('pretixbase/img/flags/gb.png')); }
pre[lang=ad], input[lang=ad], textarea[lang=ad] { background-image: url(static('pretixbase/img/flags/ad.png')); }
pre[lang=ae], input[lang=ae], textarea[lang=ae] { background-image: url(static('pretixbase/img/flags/ae.png')); }
pre[lang=af], input[lang=af], textarea[lang=af] { background-image: url(static('pretixbase/img/flags/af.png')); }
pre[lang=ag], input[lang=ag], textarea[lang=ag] { background-image: url(static('pretixbase/img/flags/ag.png')); }
pre[lang=ai], input[lang=ai], textarea[lang=ai] { background-image: url(static('pretixbase/img/flags/ai.png')); }
pre[lang=al], input[lang=al], textarea[lang=al] { background-image: url(static('pretixbase/img/flags/al.png')); }
pre[lang=am], input[lang=am], textarea[lang=am] { background-image: url(static('pretixbase/img/flags/am.png')); }
pre[lang=an], input[lang=an], textarea[lang=an] { background-image: url(static('pretixbase/img/flags/an.png')); }
pre[lang=ao], input[lang=ao], textarea[lang=ao] { background-image: url(static('pretixbase/img/flags/ao.png')); }
pre[lang=ar], input[lang=ar], textarea[lang=ar] { background-image: url(static('pretixbase/img/flags/ar.png')); }
pre[lang=as], input[lang=as], textarea[lang=as] { background-image: url(static('pretixbase/img/flags/as.png')); }
pre[lang=at], input[lang=at], textarea[lang=at] { background-image: url(static('pretixbase/img/flags/at.png')); }
pre[lang=au], input[lang=au], textarea[lang=au] { background-image: url(static('pretixbase/img/flags/au.png')); }
pre[lang=aw], input[lang=aw], textarea[lang=aw] { background-image: url(static('pretixbase/img/flags/aw.png')); }
pre[lang=ax], input[lang=ax], textarea[lang=ax] { background-image: url(static('pretixbase/img/flags/ax.png')); }
pre[lang=az], input[lang=az], textarea[lang=az] { background-image: url(static('pretixbase/img/flags/az.png')); }
pre[lang=ba], input[lang=ba], textarea[lang=ba] { background-image: url(static('pretixbase/img/flags/ba.png')); }
pre[lang=bb], input[lang=bb], textarea[lang=bb] { background-image: url(static('pretixbase/img/flags/bb.png')); }
pre[lang=bd], input[lang=bd], textarea[lang=bd] { background-image: url(static('pretixbase/img/flags/bd.png')); }
pre[lang=be], input[lang=be], textarea[lang=be] { background-image: url(static('pretixbase/img/flags/be.png')); }
pre[lang=bf], input[lang=bf], textarea[lang=bf] { background-image: url(static('pretixbase/img/flags/bf.png')); }
pre[lang=bg], input[lang=bg], textarea[lang=bg] { background-image: url(static('pretixbase/img/flags/bg.png')); }
pre[lang=bh], input[lang=bh], textarea[lang=bh] { background-image: url(static('pretixbase/img/flags/bh.png')); }
pre[lang=bi], input[lang=bi], textarea[lang=bi] { background-image: url(static('pretixbase/img/flags/bi.png')); }
pre[lang=bj], input[lang=bj], textarea[lang=bj] { background-image: url(static('pretixbase/img/flags/bj.png')); }
pre[lang=bm], input[lang=bm], textarea[lang=bm] { background-image: url(static('pretixbase/img/flags/bm.png')); }
pre[lang=bn], input[lang=bn], textarea[lang=bn] { background-image: url(static('pretixbase/img/flags/bn.png')); }
pre[lang=bo], input[lang=bo], textarea[lang=bo] { background-image: url(static('pretixbase/img/flags/bo.png')); }
pre[lang=br], input[lang=br], textarea[lang=br] { background-image: url(static('pretixbase/img/flags/br.png')); }
pre[lang=bs], input[lang=bs], textarea[lang=bs] { background-image: url(static('pretixbase/img/flags/bs.png')); }
pre[lang=bt], input[lang=bt], textarea[lang=bt] { background-image: url(static('pretixbase/img/flags/bt.png')); }
pre[lang=bv], input[lang=bv], textarea[lang=bv] { background-image: url(static('pretixbase/img/flags/bv.png')); }
pre[lang=bw], input[lang=bw], textarea[lang=bw] { background-image: url(static('pretixbase/img/flags/bw.png')); }
pre[lang=by], input[lang=by], textarea[lang=by] { background-image: url(static('pretixbase/img/flags/by.png')); }
pre[lang=bz], input[lang=bz], textarea[lang=bz] { background-image: url(static('pretixbase/img/flags/bz.png')); }
pre[lang=ca], input[lang=ca], textarea[lang=ca] { background-image: url(static('pretixbase/img/flags/ca.png')); }
pre[lang=cc], input[lang=cc], textarea[lang=cc] { background-image: url(static('pretixbase/img/flags/cc.png')); }
pre[lang=cd], input[lang=cd], textarea[lang=cd] { background-image: url(static('pretixbase/img/flags/cd.png')); }
pre[lang=cf], input[lang=cf], textarea[lang=cf] { background-image: url(static('pretixbase/img/flags/cf.png')); }
pre[lang=cg], input[lang=cg], textarea[lang=cg] { background-image: url(static('pretixbase/img/flags/cg.png')); }
pre[lang=ch], input[lang=ch], textarea[lang=ch] { background-image: url(static('pretixbase/img/flags/ch.png')); }
pre[lang=ci], input[lang=ci], textarea[lang=ci] { background-image: url(static('pretixbase/img/flags/ci.png')); }
pre[lang=ck], input[lang=ck], textarea[lang=ck] { background-image: url(static('pretixbase/img/flags/ck.png')); }
pre[lang=cl], input[lang=cl], textarea[lang=cl] { background-image: url(static('pretixbase/img/flags/cl.png')); }
pre[lang=cm], input[lang=cm], textarea[lang=cm] { background-image: url(static('pretixbase/img/flags/cm.png')); }
pre[lang=cn], input[lang=cn], textarea[lang=cn] { background-image: url(static('pretixbase/img/flags/cn.png')); }
pre[lang=co], input[lang=co], textarea[lang=co] { background-image: url(static('pretixbase/img/flags/co.png')); }
pre[lang=cr], input[lang=cr], textarea[lang=cr] { background-image: url(static('pretixbase/img/flags/cr.png')); }
pre[lang=cs], input[lang=cs], textarea[lang=cs] { background-image: url(static('pretixbase/img/flags/cs.png')); }
pre[lang=cu], input[lang=cu], textarea[lang=cu] { background-image: url(static('pretixbase/img/flags/cu.png')); }
pre[lang=cv], input[lang=cv], textarea[lang=cv] { background-image: url(static('pretixbase/img/flags/cv.png')); }
pre[lang=cx], input[lang=cx], textarea[lang=cx] { background-image: url(static('pretixbase/img/flags/cx.png')); }
pre[lang=cy], input[lang=cy], textarea[lang=cy] { background-image: url(static('pretixbase/img/flags/cy.png')); }
pre[lang=cz], input[lang=cz], textarea[lang=cz] { background-image: url(static('pretixbase/img/flags/cz.png')); }
pre[lang=de], input[lang=de], textarea[lang=de] { background-image: url(static('pretixbase/img/flags/de.png')); }
pre[lang=de-informal], input[lang=de-informal], textarea[lang=de-informal] { background-image: url(static('pretixbase/img/flags/de-informal.png')); }
pre[lang=dj], input[lang=dj], textarea[lang=dj] { background-image: url(static('pretixbase/img/flags/dj.png')); }
pre[lang=dk], input[lang=dk], textarea[lang=dk] { background-image: url(static('pretixbase/img/flags/dk.png')); }
pre[lang=dm], input[lang=dm], textarea[lang=dm] { background-image: url(static('pretixbase/img/flags/dm.png')); }
pre[lang=do], input[lang=do], textarea[lang=do] { background-image: url(static('pretixbase/img/flags/do.png')); }
pre[lang=dz], input[lang=dz], textarea[lang=dz] { background-image: url(static('pretixbase/img/flags/dz.png')); }
pre[lang=ec], input[lang=ec], textarea[lang=ec] { background-image: url(static('pretixbase/img/flags/ec.png')); }
pre[lang=ee], input[lang=ee], textarea[lang=ee] { background-image: url(static('pretixbase/img/flags/ee.png')); }
pre[lang=eg], input[lang=eg], textarea[lang=eg] { background-image: url(static('pretixbase/img/flags/eg.png')); }
pre[lang=eh], input[lang=eh], textarea[lang=eh] { background-image: url(static('pretixbase/img/flags/eh.png')); }
pre[lang=er], input[lang=er], textarea[lang=er] { background-image: url(static('pretixbase/img/flags/er.png')); }
pre[lang=es], input[lang=es], textarea[lang=es] { background-image: url(static('pretixbase/img/flags/es.png')); }
pre[lang=et], input[lang=et], textarea[lang=et] { background-image: url(static('pretixbase/img/flags/et.png')); }
pre[lang=fi], input[lang=fi], textarea[lang=fi] { background-image: url(static('pretixbase/img/flags/fi.png')); }
pre[lang=fj], input[lang=fj], textarea[lang=fj] { background-image: url(static('pretixbase/img/flags/fj.png')); }
pre[lang=fk], input[lang=fk], textarea[lang=fk] { background-image: url(static('pretixbase/img/flags/fk.png')); }
pre[lang=fm], input[lang=fm], textarea[lang=fm] { background-image: url(static('pretixbase/img/flags/fm.png')); }
pre[lang=fo], input[lang=fo], textarea[lang=fo] { background-image: url(static('pretixbase/img/flags/fo.png')); }
pre[lang=fr], input[lang=fr], textarea[lang=fr] { background-image: url(static('pretixbase/img/flags/fr.png')); }
pre[lang=ga], input[lang=ga], textarea[lang=ga] { background-image: url(static('pretixbase/img/flags/ga.png')); }
pre[lang=gb], input[lang=gb], textarea[lang=gb] { background-image: url(static('pretixbase/img/flags/gb.png')); }
pre[lang=gd], input[lang=gd], textarea[lang=gd] { background-image: url(static('pretixbase/img/flags/gd.png')); }
pre[lang=ge], input[lang=ge], textarea[lang=ge] { background-image: url(static('pretixbase/img/flags/ge.png')); }
pre[lang=gf], input[lang=gf], textarea[lang=gf] { background-image: url(static('pretixbase/img/flags/gf.png')); }
pre[lang=gh], input[lang=gh], textarea[lang=gh] { background-image: url(static('pretixbase/img/flags/gh.png')); }
pre[lang=gi], input[lang=gi], textarea[lang=gi] { background-image: url(static('pretixbase/img/flags/gi.png')); }
pre[lang=gl], input[lang=gl], textarea[lang=gl] { background-image: url(static('pretixbase/img/flags/gl.png')); }
pre[lang=gm], input[lang=gm], textarea[lang=gm] { background-image: url(static('pretixbase/img/flags/gm.png')); }
pre[lang=gn], input[lang=gn], textarea[lang=gn] { background-image: url(static('pretixbase/img/flags/gn.png')); }
pre[lang=gp], input[lang=gp], textarea[lang=gp] { background-image: url(static('pretixbase/img/flags/gp.png')); }
pre[lang=gq], input[lang=gq], textarea[lang=gq] { background-image: url(static('pretixbase/img/flags/gq.png')); }
pre[lang=gr], input[lang=gr], textarea[lang=gr] { background-image: url(static('pretixbase/img/flags/gr.png')); }
pre[lang=gs], input[lang=gs], textarea[lang=gs] { background-image: url(static('pretixbase/img/flags/gs.png')); }
pre[lang=gt], input[lang=gt], textarea[lang=gt] { background-image: url(static('pretixbase/img/flags/gt.png')); }
pre[lang=gu], input[lang=gu], textarea[lang=gu] { background-image: url(static('pretixbase/img/flags/gu.png')); }
pre[lang=gw], input[lang=gw], textarea[lang=gw] { background-image: url(static('pretixbase/img/flags/gw.png')); }
pre[lang=gy], input[lang=gy], textarea[lang=gy] { background-image: url(static('pretixbase/img/flags/gy.png')); }
pre[lang=hk], input[lang=hk], textarea[lang=hk] { background-image: url(static('pretixbase/img/flags/hk.png')); }
pre[lang=hm], input[lang=hm], textarea[lang=hm] { background-image: url(static('pretixbase/img/flags/hm.png')); }
pre[lang=hn], input[lang=hn], textarea[lang=hn] { background-image: url(static('pretixbase/img/flags/hn.png')); }
pre[lang=hr], input[lang=hr], textarea[lang=hr] { background-image: url(static('pretixbase/img/flags/hr.png')); }
pre[lang=ht], input[lang=ht], textarea[lang=ht] { background-image: url(static('pretixbase/img/flags/ht.png')); }
pre[lang=hu], input[lang=hu], textarea[lang=hu] { background-image: url(static('pretixbase/img/flags/hu.png')); }
pre[lang=id], input[lang=id], textarea[lang=id] { background-image: url(static('pretixbase/img/flags/id.png')); }
pre[lang=ie], input[lang=ie], textarea[lang=ie] { background-image: url(static('pretixbase/img/flags/ie.png')); }
pre[lang=il], input[lang=il], textarea[lang=il] { background-image: url(static('pretixbase/img/flags/il.png')); }
pre[lang=in], input[lang=in], textarea[lang=in] { background-image: url(static('pretixbase/img/flags/in.png')); }
pre[lang=io], input[lang=io], textarea[lang=io] { background-image: url(static('pretixbase/img/flags/io.png')); }
pre[lang=iq], input[lang=iq], textarea[lang=iq] { background-image: url(static('pretixbase/img/flags/iq.png')); }
pre[lang=ir], input[lang=ir], textarea[lang=ir] { background-image: url(static('pretixbase/img/flags/ir.png')); }
pre[lang=is], input[lang=is], textarea[lang=is] { background-image: url(static('pretixbase/img/flags/is.png')); }
pre[lang=it], input[lang=it], textarea[lang=it] { background-image: url(static('pretixbase/img/flags/it.png')); }
pre[lang=jm], input[lang=jm], textarea[lang=jm] { background-image: url(static('pretixbase/img/flags/jm.png')); }
pre[lang=jo], input[lang=jo], textarea[lang=jo] { background-image: url(static('pretixbase/img/flags/jo.png')); }
pre[lang=jp], input[lang=jp], textarea[lang=jp] { background-image: url(static('pretixbase/img/flags/jp.png')); }
pre[lang=ke], input[lang=ke], textarea[lang=ke] { background-image: url(static('pretixbase/img/flags/ke.png')); }
pre[lang=kg], input[lang=kg], textarea[lang=kg] { background-image: url(static('pretixbase/img/flags/kg.png')); }
pre[lang=kh], input[lang=kh], textarea[lang=kh] { background-image: url(static('pretixbase/img/flags/kh.png')); }
pre[lang=ki], input[lang=ki], textarea[lang=ki] { background-image: url(static('pretixbase/img/flags/ki.png')); }
pre[lang=km], input[lang=km], textarea[lang=km] { background-image: url(static('pretixbase/img/flags/km.png')); }
pre[lang=kn], input[lang=kn], textarea[lang=kn] { background-image: url(static('pretixbase/img/flags/kn.png')); }
pre[lang=kp], input[lang=kp], textarea[lang=kp] { background-image: url(static('pretixbase/img/flags/kp.png')); }
pre[lang=kr], input[lang=kr], textarea[lang=kr] { background-image: url(static('pretixbase/img/flags/kr.png')); }
pre[lang=kw], input[lang=kw], textarea[lang=kw] { background-image: url(static('pretixbase/img/flags/kw.png')); }
pre[lang=ky], input[lang=ky], textarea[lang=ky] { background-image: url(static('pretixbase/img/flags/ky.png')); }
pre[lang=kz], input[lang=kz], textarea[lang=kz] { background-image: url(static('pretixbase/img/flags/kz.png')); }
pre[lang=la], input[lang=la], textarea[lang=la] { background-image: url(static('pretixbase/img/flags/la.png')); }
pre[lang=lb], input[lang=lb], textarea[lang=lb] { background-image: url(static('pretixbase/img/flags/lb.png')); }
pre[lang=lc], input[lang=lc], textarea[lang=lc] { background-image: url(static('pretixbase/img/flags/lc.png')); }
pre[lang=li], input[lang=li], textarea[lang=li] { background-image: url(static('pretixbase/img/flags/li.png')); }
pre[lang=lk], input[lang=lk], textarea[lang=lk] { background-image: url(static('pretixbase/img/flags/lk.png')); }
pre[lang=lr], input[lang=lr], textarea[lang=lr] { background-image: url(static('pretixbase/img/flags/lr.png')); }
pre[lang=ls], input[lang=ls], textarea[lang=ls] { background-image: url(static('pretixbase/img/flags/ls.png')); }
pre[lang=lt], input[lang=lt], textarea[lang=lt] { background-image: url(static('pretixbase/img/flags/lt.png')); }
pre[lang=lu], input[lang=lu], textarea[lang=lu] { background-image: url(static('pretixbase/img/flags/lu.png')); }
pre[lang=lv], input[lang=lv], textarea[lang=lv] { background-image: url(static('pretixbase/img/flags/lv.png')); }
pre[lang=ly], input[lang=ly], textarea[lang=ly] { background-image: url(static('pretixbase/img/flags/ly.png')); }
pre[lang=ma], input[lang=ma], textarea[lang=ma] { background-image: url(static('pretixbase/img/flags/ma.png')); }
pre[lang=mc], input[lang=mc], textarea[lang=mc] { background-image: url(static('pretixbase/img/flags/mc.png')); }
pre[lang=md], input[lang=md], textarea[lang=md] { background-image: url(static('pretixbase/img/flags/md.png')); }
pre[lang=me], input[lang=me], textarea[lang=me] { background-image: url(static('pretixbase/img/flags/me.png')); }
pre[lang=mg], input[lang=mg], textarea[lang=mg] { background-image: url(static('pretixbase/img/flags/mg.png')); }
pre[lang=mh], input[lang=mh], textarea[lang=mh] { background-image: url(static('pretixbase/img/flags/mh.png')); }
pre[lang=mk], input[lang=mk], textarea[lang=mk] { background-image: url(static('pretixbase/img/flags/mk.png')); }
pre[lang=ml], input[lang=ml], textarea[lang=ml] { background-image: url(static('pretixbase/img/flags/ml.png')); }
pre[lang=mm], input[lang=mm], textarea[lang=mm] { background-image: url(static('pretixbase/img/flags/mm.png')); }
pre[lang=mn], input[lang=mn], textarea[lang=mn] { background-image: url(static('pretixbase/img/flags/mn.png')); }
pre[lang=mo], input[lang=mo], textarea[lang=mo] { background-image: url(static('pretixbase/img/flags/mo.png')); }
pre[lang=mp], input[lang=mp], textarea[lang=mp] { background-image: url(static('pretixbase/img/flags/mp.png')); }
pre[lang=mq], input[lang=mq], textarea[lang=mq] { background-image: url(static('pretixbase/img/flags/mq.png')); }
pre[lang=mr], input[lang=mr], textarea[lang=mr] { background-image: url(static('pretixbase/img/flags/mr.png')); }
pre[lang=ms], input[lang=ms], textarea[lang=ms] { background-image: url(static('pretixbase/img/flags/ms.png')); }
pre[lang=mt], input[lang=mt], textarea[lang=mt] { background-image: url(static('pretixbase/img/flags/mt.png')); }
pre[lang=mu], input[lang=mu], textarea[lang=mu] { background-image: url(static('pretixbase/img/flags/mu.png')); }
pre[lang=mv], input[lang=mv], textarea[lang=mv] { background-image: url(static('pretixbase/img/flags/mv.png')); }
pre[lang=mw], input[lang=mw], textarea[lang=mw] { background-image: url(static('pretixbase/img/flags/mw.png')); }
pre[lang=mx], input[lang=mx], textarea[lang=mx] { background-image: url(static('pretixbase/img/flags/mx.png')); }
pre[lang=my], input[lang=my], textarea[lang=my] { background-image: url(static('pretixbase/img/flags/my.png')); }
pre[lang=mz], input[lang=mz], textarea[lang=mz] { background-image: url(static('pretixbase/img/flags/mz.png')); }
pre[lang=na], input[lang=na], textarea[lang=na] { background-image: url(static('pretixbase/img/flags/na.png')); }
pre[lang=nc], input[lang=nc], textarea[lang=nc] { background-image: url(static('pretixbase/img/flags/nc.png')); }
pre[lang=ne], input[lang=ne], textarea[lang=ne] { background-image: url(static('pretixbase/img/flags/ne.png')); }
pre[lang=nf], input[lang=nf], textarea[lang=nf] { background-image: url(static('pretixbase/img/flags/nf.png')); }
pre[lang=ng], input[lang=ng], textarea[lang=ng] { background-image: url(static('pretixbase/img/flags/ng.png')); }
pre[lang=ni], input[lang=ni], textarea[lang=ni] { background-image: url(static('pretixbase/img/flags/ni.png')); }
pre[lang=nl], input[lang=nl], textarea[lang=nl] { background-image: url(static('pretixbase/img/flags/nl.png')); }
pre[lang=no], input[lang=no], textarea[lang=no] { background-image: url(static('pretixbase/img/flags/no.png')); }
pre[lang=np], input[lang=np], textarea[lang=np] { background-image: url(static('pretixbase/img/flags/np.png')); }
pre[lang=nr], input[lang=nr], textarea[lang=nr] { background-image: url(static('pretixbase/img/flags/nr.png')); }
pre[lang=nu], input[lang=nu], textarea[lang=nu] { background-image: url(static('pretixbase/img/flags/nu.png')); }
pre[lang=nz], input[lang=nz], textarea[lang=nz] { background-image: url(static('pretixbase/img/flags/nz.png')); }
pre[lang=om], input[lang=om], textarea[lang=om] { background-image: url(static('pretixbase/img/flags/om.png')); }
pre[lang=pa], input[lang=pa], textarea[lang=pa] { background-image: url(static('pretixbase/img/flags/pa.png')); }
pre[lang=pe], input[lang=pe], textarea[lang=pe] { background-image: url(static('pretixbase/img/flags/pe.png')); }
pre[lang=pf], input[lang=pf], textarea[lang=pf] { background-image: url(static('pretixbase/img/flags/pf.png')); }
pre[lang=pg], input[lang=pg], textarea[lang=pg] { background-image: url(static('pretixbase/img/flags/pg.png')); }
pre[lang=ph], input[lang=ph], textarea[lang=ph] { background-image: url(static('pretixbase/img/flags/ph.png')); }
pre[lang=pk], input[lang=pk], textarea[lang=pk] { background-image: url(static('pretixbase/img/flags/pk.png')); }
pre[lang=pl], input[lang=pl], textarea[lang=pl] { background-image: url(static('pretixbase/img/flags/pl.png')); }
pre[lang=pm], input[lang=pm], textarea[lang=pm] { background-image: url(static('pretixbase/img/flags/pm.png')); }
pre[lang=pn], input[lang=pn], textarea[lang=pn] { background-image: url(static('pretixbase/img/flags/pn.png')); }
pre[lang=pr], input[lang=pr], textarea[lang=pr] { background-image: url(static('pretixbase/img/flags/pr.png')); }
pre[lang=ps], input[lang=ps], textarea[lang=ps] { background-image: url(static('pretixbase/img/flags/ps.png')); }
pre[lang=pt], input[lang=pt], textarea[lang=pt] { background-image: url(static('pretixbase/img/flags/pt.png')); }
pre[lang=pw], input[lang=pw], textarea[lang=pw] { background-image: url(static('pretixbase/img/flags/pw.png')); }
pre[lang=py], input[lang=py], textarea[lang=py] { background-image: url(static('pretixbase/img/flags/py.png')); }
pre[lang=qa], input[lang=qa], textarea[lang=qa] { background-image: url(static('pretixbase/img/flags/qa.png')); }
pre[lang=re], input[lang=re], textarea[lang=re] { background-image: url(static('pretixbase/img/flags/re.png')); }
pre[lang=ro], input[lang=ro], textarea[lang=ro] { background-image: url(static('pretixbase/img/flags/ro.png')); }
pre[lang=rs], input[lang=rs], textarea[lang=rs] { background-image: url(static('pretixbase/img/flags/rs.png')); }
pre[lang=ru], input[lang=ru], textarea[lang=ru] { background-image: url(static('pretixbase/img/flags/ru.png')); }
pre[lang=rw], input[lang=rw], textarea[lang=rw] { background-image: url(static('pretixbase/img/flags/rw.png')); }
pre[lang=sa], input[lang=sa], textarea[lang=sa] { background-image: url(static('pretixbase/img/flags/sa.png')); }
pre[lang=sb], input[lang=sb], textarea[lang=sb] { background-image: url(static('pretixbase/img/flags/sb.png')); }
pre[lang=sc], input[lang=sc], textarea[lang=sc] { background-image: url(static('pretixbase/img/flags/sc.png')); }
pre[lang=sd], input[lang=sd], textarea[lang=sd] { background-image: url(static('pretixbase/img/flags/sd.png')); }
pre[lang=se], input[lang=se], textarea[lang=se] { background-image: url(static('pretixbase/img/flags/se.png')); }
pre[lang=sg], input[lang=sg], textarea[lang=sg] { background-image: url(static('pretixbase/img/flags/sg.png')); }
pre[lang=sh], input[lang=sh], textarea[lang=sh] { background-image: url(static('pretixbase/img/flags/sh.png')); }
pre[lang=si], input[lang=si], textarea[lang=si] { background-image: url(static('pretixbase/img/flags/si.png')); }
pre[lang=sj], input[lang=sj], textarea[lang=sj] { background-image: url(static('pretixbase/img/flags/sj.png')); }
pre[lang=sk], input[lang=sk], textarea[lang=sk] { background-image: url(static('pretixbase/img/flags/sk.png')); }
pre[lang=sl], input[lang=sl], textarea[lang=sl] { background-image: url(static('pretixbase/img/flags/sl.png')); }
pre[lang=sm], input[lang=sm], textarea[lang=sm] { background-image: url(static('pretixbase/img/flags/sm.png')); }
pre[lang=sn], input[lang=sn], textarea[lang=sn] { background-image: url(static('pretixbase/img/flags/sn.png')); }
pre[lang=so], input[lang=so], textarea[lang=so] { background-image: url(static('pretixbase/img/flags/so.png')); }
pre[lang=sr], input[lang=sr], textarea[lang=sr] { background-image: url(static('pretixbase/img/flags/sr.png')); }
pre[lang=st], input[lang=st], textarea[lang=st] { background-image: url(static('pretixbase/img/flags/st.png')); }
pre[lang=sv], input[lang=sv], textarea[lang=sv] { background-image: url(static('pretixbase/img/flags/sv.png')); }
pre[lang=sy], input[lang=sy], textarea[lang=sy] { background-image: url(static('pretixbase/img/flags/sy.png')); }
pre[lang=sz], input[lang=sz], textarea[lang=sz] { background-image: url(static('pretixbase/img/flags/sz.png')); }
pre[lang=tc], input[lang=tc], textarea[lang=tc] { background-image: url(static('pretixbase/img/flags/tc.png')); }
pre[lang=td], input[lang=td], textarea[lang=td] { background-image: url(static('pretixbase/img/flags/td.png')); }
pre[lang=tf], input[lang=tf], textarea[lang=tf] { background-image: url(static('pretixbase/img/flags/tf.png')); }
pre[lang=tg], input[lang=tg], textarea[lang=tg] { background-image: url(static('pretixbase/img/flags/tg.png')); }
pre[lang=th], input[lang=th], textarea[lang=th] { background-image: url(static('pretixbase/img/flags/th.png')); }
pre[lang=tj], input[lang=tj], textarea[lang=tj] { background-image: url(static('pretixbase/img/flags/tj.png')); }
pre[lang=tk], input[lang=tk], textarea[lang=tk] { background-image: url(static('pretixbase/img/flags/tk.png')); }
pre[lang=tl], input[lang=tl], textarea[lang=tl] { background-image: url(static('pretixbase/img/flags/tl.png')); }
pre[lang=tm], input[lang=tm], textarea[lang=tm] { background-image: url(static('pretixbase/img/flags/tm.png')); }
pre[lang=tn], input[lang=tn], textarea[lang=tn] { background-image: url(static('pretixbase/img/flags/tn.png')); }
pre[lang=to], input[lang=to], textarea[lang=to] { background-image: url(static('pretixbase/img/flags/to.png')); }
pre[lang=tr], input[lang=tr], textarea[lang=tr] { background-image: url(static('pretixbase/img/flags/tr.png')); }
pre[lang=tt], input[lang=tt], textarea[lang=tt] { background-image: url(static('pretixbase/img/flags/tt.png')); }
pre[lang=tv], input[lang=tv], textarea[lang=tv] { background-image: url(static('pretixbase/img/flags/tv.png')); }
pre[lang=tw], input[lang=tw], textarea[lang=tw] { background-image: url(static('pretixbase/img/flags/tw.png')); }
pre[lang=tz], input[lang=tz], textarea[lang=tz] { background-image: url(static('pretixbase/img/flags/tz.png')); }
pre[lang=ua], input[lang=ua], textarea[lang=ua] { background-image: url(static('pretixbase/img/flags/ua.png')); }
pre[lang=ug], input[lang=ug], textarea[lang=ug] { background-image: url(static('pretixbase/img/flags/ug.png')); }
pre[lang=um], input[lang=um], textarea[lang=um] { background-image: url(static('pretixbase/img/flags/um.png')); }
pre[lang=us], input[lang=us], textarea[lang=us] { background-image: url(static('pretixbase/img/flags/us.png')); }
pre[lang=uy], input[lang=uy], textarea[lang=uy] { background-image: url(static('pretixbase/img/flags/uy.png')); }
pre[lang=uz], input[lang=uz], textarea[lang=uz] { background-image: url(static('pretixbase/img/flags/uz.png')); }
pre[lang=va], input[lang=va], textarea[lang=va] { background-image: url(static('pretixbase/img/flags/va.png')); }
pre[lang=vc], input[lang=vc], textarea[lang=vc] { background-image: url(static('pretixbase/img/flags/vc.png')); }
pre[lang=ve], input[lang=ve], textarea[lang=ve] { background-image: url(static('pretixbase/img/flags/ve.png')); }
pre[lang=vg], input[lang=vg], textarea[lang=vg] { background-image: url(static('pretixbase/img/flags/vg.png')); }
pre[lang=vi], input[lang=vi], textarea[lang=vi] { background-image: url(static('pretixbase/img/flags/vi.png')); }
pre[lang=vn], input[lang=vn], textarea[lang=vn] { background-image: url(static('pretixbase/img/flags/vn.png')); }
pre[lang=vu], input[lang=vu], textarea[lang=vu] { background-image: url(static('pretixbase/img/flags/vu.png')); }
pre[lang=wf], input[lang=wf], textarea[lang=wf] { background-image: url(static('pretixbase/img/flags/wf.png')); }
pre[lang=ws], input[lang=ws], textarea[lang=ws] { background-image: url(static('pretixbase/img/flags/ws.png')); }
pre[lang=ye], input[lang=ye], textarea[lang=ye] { background-image: url(static('pretixbase/img/flags/ye.png')); }
pre[lang=yt], input[lang=yt], textarea[lang=yt] { background-image: url(static('pretixbase/img/flags/yt.png')); }
pre[lang=za], input[lang=za], textarea[lang=za] { background-image: url(static('pretixbase/img/flags/za.png')); }
pre[lang=zm], input[lang=zm], textarea[lang=zm] { background-image: url(static('pretixbase/img/flags/zm.png')); }
pre[lang=zw], input[lang=zw], textarea[lang=zw] { background-image: url(static('pretixbase/img/flags/zw.png')); }
pre[lang=en], input[lang=en], textarea[lang=en] { background-image: url(static('pretixbase/img/flags/gb.png')); }

View File

@@ -0,0 +1,303 @@
import datetime
import json
import re
from tests.base import SoupTest
from pretix.base.models import (
Event, EventPermission, Organizer, OrganizerPermission, User,
)
class MailSettingPreviewTest(SoupTest):
def setUp(self):
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
self.orga1 = Organizer.objects.create(name='CCC', slug='ccc')
self.orga2 = Organizer.objects.create(name='MRM', slug='mrm')
self.event1 = Event.objects.create(
organizer=self.orga1, name='30C3', slug='30c3',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
)
# event with locale
self.locale_event = Event.objects.create(
organizer=self.orga1, name={'en': '40C4-en', 'de-informal': '40C4-de'}, slug='40c4',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
)
self.locale_event.settings.locales = ['en', 'de-informal']
self.locale_event.save()
OrganizerPermission.objects.create(organizer=self.orga1, user=self.user)
EventPermission.objects.create(event=self.event1, user=self.user, can_change_items=True,
can_change_settings=True)
EventPermission.objects.create(event=self.locale_event, user=self.user, can_change_items=True,
can_change_settings=True)
self.client.login(email='dummy@dummy.dummy', password='dummy')
self.target = '/control/event/{}/{}/settings/email/preview'
def test_permission(self):
self.event2 = Event.objects.create(
organizer=self.orga2, name='30M3', slug='30m3',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
)
response = self.client.post(self.target.format(
self.orga2.slug, self.event2.slug), {
'test': 'test1'
})
assert response.status_code == 404
def test_missing_item_key(self):
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'dummy',
'mail_text_order_free_0': 'sss',
'mail_text_order_free_1': 'ttt'
})
assert response.status_code == 400
def test_invalid_item_field(self):
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_order_free',
'mail_text_order_free_w': 'sss'
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_free'
assert len(res['msgs']) == 0
def test_invalid_language_index(self):
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_order_free',
'mail_text_order_free_1': 'sss'
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_free'
assert len(res['msgs']) == 0
def test_no_item_field(self):
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'mail_text_order_free_0': 'sss'
})
assert response.status_code == 400
def test_only_en(self):
dummy_text = 'This is dummy sentence for test'
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_order_free',
'mail_text_order_free_0': dummy_text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_free'
assert len(res['msgs']) == 1
assert res['msgs']['en'] == dummy_text
def test_multiple_languages(self):
dummy_text = 'This is dummy sentence for test'
response = self.client.post(self.target.format(
self.orga1.slug, self.locale_event.slug), {
'item': 'mail_text_order_free',
'mail_text_order_free_0': dummy_text,
'mail_text_order_free_2': dummy_text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_free'
assert len(res['msgs']) == 2
assert res['msgs']['en'] == dummy_text
assert res['msgs']['de-informal'] == dummy_text
def test_i18n_placeholders(self):
dummy_text = '{event}'
response = self.client.post(self.target.format(
self.orga1.slug, self.locale_event.slug), {
'item': 'mail_text_order_placed',
'mail_text_order_placed_0': dummy_text,
'mail_text_order_placed_2': dummy_text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_placed'
assert len(res['msgs']) == 2
assert res['msgs']['en'] == self.locale_event.name['en']
assert res['msgs']['de-informal'] == self.locale_event.name['de-informal']
def test_i18n_locale_order(self):
self.locale_event.settings.locales = ['de-informal', 'en']
self.locale_event.save()
dummy_text = '{event}'
response = self.client.post(self.target.format(
self.orga1.slug, self.locale_event.slug), {
'item': 'mail_text_order_placed',
'mail_text_order_placed_0': dummy_text,
'mail_text_order_placed_2': dummy_text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_placed'
assert len(res['msgs']) == 2
assert res['msgs']['de-informal'] == self.locale_event.name['de-informal']
assert res['msgs']['en'] == self.locale_event.name['en']
def test_mail_text_order_placed(self):
text = '{event}{total}{currency}{date}{paymentinfo}{url}{invoice_name}{invoice_company}'
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_order_placed',
'mail_text_order_placed_0': text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_placed'
assert len(res['msgs']) == 1
assert re.match('.*{.*}.*', res['msgs']['en']) is None
def test_mail_text_order_paid(self):
text = '{event}{url}{invoice_name}{invoice_company}{payment_info}'
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_order_paid',
'mail_text_order_paid_0': text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_paid'
assert len(res['msgs']) == 1
assert re.match('.*{.*}.*', res['msgs']['en']) is None
def test_mail_text_order_free(self):
text = '{event}{url}{invoice_name}{invoice_company}'
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_order_free',
'mail_text_order_free_0': text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_free'
assert len(res['msgs']) == 1
assert re.match('.*{.*}.*', res['msgs']['en']) is None
def test_mail_text_resend_link(self):
text = '{event}{url}{invoice_name}{invoice_company}'
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_resend_link',
'mail_text_resend_link_0': text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_resend_link'
assert len(res['msgs']) == 1
assert re.match('.*{.*}.*', res['msgs']['en']) is None
def test_mail_text_resend_all_links(self):
text = '{event}{orders}'
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_resend_all_links',
'mail_text_resend_all_links_0': text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_resend_all_links'
assert len(res['msgs']) == 1
assert re.match('.*{.*}.*', res['msgs']['en']) is None
def test_mail_text_order_changed(self):
text = '{event}{url}{invoice_name}{invoice_company}'
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_order_changed',
'mail_text_order_changed_0': text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_changed'
assert len(res['msgs']) == 1
assert re.match('.*{.*}.*', res['msgs']['en']) is None
def test_mail_text_order_expire_warning(self):
text = '{event}{url}{expire_date}{invoice_name}{invoice_company}'
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_order_expire_warning',
'mail_text_order_expire_warning_0': text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_expire_warning'
assert len(res['msgs']) == 1
assert re.match('.*{.*}.*', res['msgs']['en']) is None
def test_mail_text_waiting_list(self):
text = '{event}{url}{product}{hours}{code}'
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_waiting_list',
'mail_text_waiting_list_0': text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_waiting_list'
assert len(res['msgs']) == 1
assert re.match('.*{.*}.*', res['msgs']['en']) is None
def test_unsupported_placeholders(self):
text = '{event1}'
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_waiting_list',
'mail_text_waiting_list_0': text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_waiting_list'
assert len(res['msgs']) == 1
assert res['msgs']['en'] == text
def test_localised_date(self):
dummy_text = '{date}'
response = self.client.post(self.target.format(
self.orga1.slug, self.locale_event.slug), {
'item': 'mail_text_order_placed',
'mail_text_order_placed_0': dummy_text,
'mail_text_order_placed_2': dummy_text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_placed'
assert len(res['msgs']) == 2
assert res['msgs']['en'] != res['msgs']['de-informal']
def test_localised_expire_date(self):
dummy_text = '{expire_date}'
response = self.client.post(self.target.format(
self.orga1.slug, self.locale_event.slug), {
'item': 'mail_text_order_expire_warning',
'mail_text_order_expire_warning_0': dummy_text,
'mail_text_order_expire_warning_2': dummy_text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_expire_warning'
assert len(res['msgs']) == 2
assert res['msgs']['en'] != res['msgs']['de-informal']
def test_localised_payment_info(self):
dummy_text = '{payment_info}'
response = self.client.post(self.target.format(
self.orga1.slug, self.locale_event.slug), {
'item': 'mail_text_order_paid',
'mail_text_order_paid_0': dummy_text,
'mail_text_order_paid_2': dummy_text
})
assert response.status_code == 200
res = json.loads(response.content.decode())
assert res['item'] == 'mail_text_order_paid'
assert len(res['msgs']) == 2
assert res['msgs']['en'] != res['msgs']['de-informal']