diff --git a/doc/development/translation/index.rst b/doc/development/translation/index.rst index 1a98ac7345..8378dbc698 100644 --- a/doc/development/translation/index.rst +++ b/doc/development/translation/index.rst @@ -24,7 +24,8 @@ Inofficial languages guarantee that new or changed features in pretix will be translated in time. Incubating languages - are currently in the process of being translated. They can not yet be selected in pretix by end users. + are currently in the process of being translated. They can not yet be selected in pretix by end users on + production installations and are only available in development mode for testing. Please contact translate@pretix.eu if you think an incubated language should be promoted to an inofficial one or if you are interested in a partnership to make your language official. @@ -61,6 +62,12 @@ Going back to the dashboard by clicking on the logo in the top-left corner, you of translation projects. You can either filter by projects that already have a translation in your language, or you go to the `pretix project page`_ where you can select specific components. +.. note:: + + If you want to translate pretix to a new language that is not yet listed here, you are very welcome to do so! + While you technically can add the language to the portal yourself, we ask you to drop us a short mail to + translate@pretix.eu so we can add it to all components at once and also make it selectabel in pretix itself. + .. image:: img/weblate4.png :class: screenshot diff --git a/src/pretix/base/forms/user.py b/src/pretix/base/forms/user.py index 2cdaba94f7..f7d00dc70a 100644 --- a/src/pretix/base/forms/user.py +++ b/src/pretix/base/forms/user.py @@ -8,6 +8,7 @@ from django.utils.translation import ugettext_lazy as _ from pytz import common_timezones from pretix.base.models import User +from pretix.control.forms import SingleLanguageWidget class UserSettingsForm(forms.ModelForm): @@ -47,6 +48,9 @@ class UserSettingsForm(forms.ModelForm): 'timezone', 'email' ] + widgets = { + 'locale': SingleLanguageWidget + } def __init__(self, *args, **kwargs): self.user = kwargs.pop('user') diff --git a/src/pretix/control/forms/__init__.py b/src/pretix/control/forms/__init__.py index f2565b34c8..6d1bc762ff 100644 --- a/src/pretix/control/forms/__init__.py +++ b/src/pretix/control/forms/__init__.py @@ -1,6 +1,7 @@ import os from django import forms +from django.conf import settings from django.utils.html import conditional_escape from django.utils.translation import ugettext_lazy as _ @@ -102,3 +103,68 @@ class SlugWidget(forms.TextInput): ctx = super().get_context(name, value, attrs) ctx['pre'] = self.prefix return ctx + + +class MultipleLanguagesWidget(forms.CheckboxSelectMultiple): + option_template_name = 'pretixcontrol/multi_languages_widget.html' + + def sort(self): + self.choices = sorted(self.choices, key=lambda l: ( + ( + 0 if l[0] in settings.LANGUAGES_OFFICIAL + else ( + 1 if l[0] not in settings.LANGUAGES_INCUBATING + else 2 + ) + ), str(l[1]) + )) + + def options(self, name, value, attrs=None): + self.sort() + return super().options(name, value, attrs) + + def optgroups(self, name, value, attrs=None): + self.sort() + return super().optgroups(name, value, attrs) + + def create_option(self, name, value, label, selected, index, subindex=None, attrs=None): + opt = super().create_option(name, value, label, selected, index, subindex, attrs) + opt['official'] = value in settings.LANGUAGES_OFFICIAL + opt['incubating'] = value in settings.LANGUAGES_INCUBATING + return opt + + +class SingleLanguageWidget(forms.Select): + + def modify(self): + if hasattr(self, '_modified'): + return self.choices + self.choices = sorted(self.choices, key=lambda l: ( + ( + 0 if l[0] in settings.LANGUAGES_OFFICIAL + else ( + 1 if l[0] not in settings.LANGUAGES_INCUBATING + else 2 + ) + ), str(l[1]) + )) + new_choices = [] + for k, v in self.choices: + new_choices.append(( + k, + v if k in settings.LANGUAGES_OFFICIAL + else ( + '{} (inofficial translation)'.format(v) if k not in settings.LANGUAGES_INCUBATING + else '{} (translation in progress)'.format(v) + ) + )) + self._modified = True + self.choices = new_choices + + def options(self, name, value, attrs=None): + self.modify() + return super().options(name, value, attrs) + + def optgroups(self, name, value, attrs=None): + self.modify() + return super().optgroups(name, value, attrs) diff --git a/src/pretix/control/forms/event.py b/src/pretix/control/forms/event.py index a47d6254f6..2fba6775ff 100644 --- a/src/pretix/control/forms/event.py +++ b/src/pretix/control/forms/event.py @@ -17,7 +17,8 @@ from pretix.base.models import Event, Organizer, TaxRule from pretix.base.models.event import EventMetaValue, SubEvent from pretix.base.reldate import RelativeDateField, RelativeDateTimeField from pretix.control.forms import ( - ExtFileField, SlugWidget, SplitDateTimePickerWidget, + ExtFileField, MultipleLanguagesWidget, SingleLanguageWidget, SlugWidget, + SplitDateTimePickerWidget, ) from pretix.multidomain.urlreverse import build_absolute_uri from pretix.presale.style import get_fonts @@ -27,7 +28,7 @@ class EventWizardFoundationForm(forms.Form): locales = forms.MultipleChoiceField( choices=settings.LANGUAGES, label=_("Use languages"), - widget=forms.CheckboxSelectMultiple, + widget=MultipleLanguagesWidget, help_text=_('Choose all languages that your event should be available in.') ) has_subevents = forms.BooleanField( @@ -279,11 +280,12 @@ class EventSettingsForm(SettingsForm): ) locales = forms.MultipleChoiceField( choices=settings.LANGUAGES, - widget=forms.CheckboxSelectMultiple, + widget=MultipleLanguagesWidget, label=_("Available languages"), ) locale = forms.ChoiceField( choices=settings.LANGUAGES, + widget=SingleLanguageWidget, label=_("Default language"), ) show_quota_left = forms.BooleanField( @@ -637,6 +639,8 @@ class InvoiceSettingsForm(SettingsForm): (r.identifier, r.verbose_name) for r in event.get_invoice_renderers().values() ] self.fields['invoice_numbers_prefix'].widget.attrs['placeholder'] = event.slug.upper() + '-' + locale_names = dict(settings.LANGUAGES) + self.fields['invoice_language'].choices = [('__user__', _('The user\'s language'))] + [(a, locale_names[a]) for a in event.settings.locales] class MailSettingsForm(SettingsForm): diff --git a/src/pretix/control/forms/organizer.py b/src/pretix/control/forms/organizer.py index 797c10cd98..a2dd5b4b8e 100644 --- a/src/pretix/control/forms/organizer.py +++ b/src/pretix/control/forms/organizer.py @@ -7,7 +7,7 @@ from i18nfield.forms import I18nFormField, I18nTextarea from pretix.base.forms import I18nModelForm, SettingsForm from pretix.base.models import Organizer, Team -from pretix.control.forms import ExtFileField +from pretix.control.forms import ExtFileField, MultipleLanguagesWidget from pretix.multidomain.models import KnownDomain from pretix.presale.style import get_fonts @@ -158,7 +158,7 @@ class OrganizerDisplaySettingsForm(SettingsForm): locales = forms.MultipleChoiceField( choices=settings.LANGUAGES, label=_("Use languages"), - widget=forms.CheckboxSelectMultiple, + widget=MultipleLanguagesWidget, help_text=_('Choose all languages that your organizer homepage should be available in.') ) primary_font = forms.ChoiceField( diff --git a/src/pretix/control/templates/pretixcontrol/multi_languages_widget.html b/src/pretix/control/templates/pretixcontrol/multi_languages_widget.html new file mode 100644 index 0000000000..084e15473c --- /dev/null +++ b/src/pretix/control/templates/pretixcontrol/multi_languages_widget.html @@ -0,0 +1,18 @@ +{% load i18n %} +{% if wrap_label %} + +{% endif %} +{% include "django/forms/widgets/input.html" %} +{% if wrap_label %} + {{ widget.label }} + {% if widget.incubating %} + + {% trans "Translation in development" %} + + {% elif not widget.official %} + + {% trans "Inofficial translation" %} + + {% endif %} + +{% endif %} diff --git a/src/pretix/plugins/stripe/utils.py b/src/pretix/plugins/stripe/utils.py new file mode 100644 index 0000000000..7b6a66313e --- /dev/null +++ b/src/pretix/plugins/stripe/utils.py @@ -0,0 +1,6 @@ +def refresh_order(order): + if not order.payment_provider.startswith('stripe_'): + raise ValueError("Not a stripe payment") + + prov = order.event.get_payment_providers()[order.payment_provider] + prov._init_api() diff --git a/src/pretix/settings.py b/src/pretix/settings.py index f1c8332625..108ea41b0f 100644 --- a/src/pretix/settings.py +++ b/src/pretix/settings.py @@ -343,11 +343,26 @@ FORMAT_MODULE_PATH = [ 'pretix.helpers.formats', ] -LANGUAGES = [ +ALL_LANGUAGES = [ ('en', _('English')), ('de', _('German')), ('de-informal', _('German (informal)')), + ('nl', _('Dutch')), + ('da', _('Danish')), + ('pt-br', _('Portuguese (Brazil)')), ] +LANGUAGES_OFFICIAL = { + 'en', 'de', 'de-informal' +} +LANGUAGES_INCUBATING = { + 'nl', 'pt-br', 'da' +} + +if DEBUG: + LANGUAGES = ALL_LANGUAGES +else: + LANGUAGES = [(k, v) for k, v in ALL_LANGUAGES if k not in LANGUAGES_INCUBATING] + EXTRA_LANG_INFO = { 'de-informal': {