Fix #707 -- Setup automated spell-checking for translations (#896)

This will:
  * set up potypo
  * add wordlists, edgecases and phrases
  * fix english typos across the codebase
  * fix german typos and translation
This commit is contained in:
Jakob Schnell
2018-05-27 11:59:10 +02:00
committed by Raphael Michel
parent 4d249553bf
commit 1689925508
19 changed files with 415 additions and 19 deletions

View File

@@ -25,7 +25,7 @@ if [ "$1" == "doctests" ]; then
cd doc cd doc
make doctest make doctest
fi fi
if [ "$1" == "spelling" ]; then if [ "$1" == "doc-spelling" ]; then
XDG_CACHE_HOME=/cache pip3 install -Ur doc/requirements.txt XDG_CACHE_HOME=/cache pip3 install -Ur doc/requirements.txt
cd doc cd doc
make spelling make spelling
@@ -33,6 +33,11 @@ if [ "$1" == "spelling" ]; then
exit 1 exit 1
fi fi
fi fi
if [ "$1" == "translation-spelling" ]; then
XDG_CACHE_HOME=/cache pip3 install -Ur src/requirements/dev.txt
cd src
potypo
fi
if [ "$1" == "tests" ]; then if [ "$1" == "tests" ]; then
pip3 install -r src/requirements.txt -Ur src/requirements/dev.txt -r src/requirements/py34.txt pip3 install -r src/requirements.txt -Ur src/requirements/dev.txt -r src/requirements/py34.txt
cd src cd src

View File

@@ -37,12 +37,16 @@ matrix:
- python: 3.6 - python: 3.6
env: JOB=plugins env: JOB=plugins
- python: 3.6 - python: 3.6
env: JOB=spelling env: JOB=doc-spelling
- python: 3.6
env: JOB=translation-spelling
addons: addons:
postgresql: "9.4" postgresql: "9.4"
apt: apt:
packages: packages:
- enchant - enchant
- myspell-de-de
- aspell-en
branches: branches:
except: except:
- /^weblate-.*/ - /^weblate-.*/

View File

@@ -93,7 +93,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
verbose_name=_('Timezone')) verbose_name=_('Timezone'))
require_2fa = models.BooleanField( require_2fa = models.BooleanField(
default=False, default=False,
verbose_name=_('Two-factor authentification is required to log in') verbose_name=_('Two-factor authentication is required to log in')
) )
notifications_send = models.BooleanField( notifications_send = models.BooleanField(
default=True, default=True,

View File

@@ -679,7 +679,7 @@ class OrderChangeManager:
'no quota is available.'), 'no quota is available.'),
'paid_price_change': _('Currently, paid orders can only be changed in a way that does not change the total ' 'paid_price_change': _('Currently, paid orders can only be changed in a way that does not change the total '
'price of the order as partial payments or refunds are not yet supported.'), 'price of the order as partial payments or refunds are not yet supported.'),
'addon_to_required': _('This is an addon product, please select the base position it should be added to.'), 'addon_to_required': _('This is an add-on product, please select the base position it should be added to.'),
'addon_invalid': _('The selected base position does not allow you to add this product as an add-on.'), 'addon_invalid': _('The selected base position does not allow you to add this product as an add-on.'),
'subevent_required': _('You need to choose a subevent for the new position.'), 'subevent_required': _('You need to choose a subevent for the new position.'),
} }

View File

@@ -430,8 +430,8 @@ class PaymentSettingsForm(SettingsForm):
) )
payment_term_weekdays = forms.BooleanField( payment_term_weekdays = forms.BooleanField(
label=_('Only end payment terms on weekdays'), label=_('Only end payment terms on weekdays'),
help_text=_("If this is activated and the payment term of any order ends on a saturday or sunday, it will be " help_text=_("If this is activated and the payment term of any order ends on a Saturday or Sunday, it will be "
"moved to the next monday instead. This is required in some countries by civil law. This will " "moved to the next Monday instead. This is required in some countries by civil law. This will "
"not effect the last date of payments configured above."), "not effect the last date of payments configured above."),
required=False, required=False,
) )

View File

@@ -348,7 +348,7 @@ class ItemVariationsFormSet(I18nFormSet):
f.fields['DELETE'].disabled = True f.fields['DELETE'].disabled = True
raise ValidationError( raise ValidationError(
message=_('The variation "%s" cannot be deleted because it has already been ordered by a user or ' message=_('The variation "%s" cannot be deleted because it has already been ordered by a user or '
'currently is in a users\'s cart. Please set the variation as "inactive" instead.'), 'currently is in a user\'s cart. Please set the variation as "inactive" instead.'),
params=(str(f.instance),) params=(str(f.instance),)
) )

View File

@@ -8,7 +8,7 @@
{% csrf_token %} {% csrf_token %}
<h3>{% trans "Welcome back!" %}</h3> <h3>{% trans "Welcome back!" %}</h3>
<p> <p>
{% trans "You configured your account to require authentification with a second medium, e.g. your phone. Please enter your verification code here:" %} {% trans "You configured your account to require authentication with a second medium, e.g. your phone. Please enter your verification code here:" %}
</p> </p>
<div class="form-group"> <div class="form-group">
<input class="form-control" name="token" placeholder="{% trans "Token" %}" <input class="form-control" name="token" placeholder="{% trans "Token" %}"

View File

@@ -11,7 +11,7 @@
</span> </span>
{% elif not widget.official %} {% elif not widget.official %}
<span class="label label-warning" data-toggle="tooltip" title="{% trans "This translation is not maintained by the pretix team. We cannot vouch for its correctness and new or recently changed features might not be translated and will show in English instead. You can help translating at translate.pretix.eu." %}"> <span class="label label-warning" data-toggle="tooltip" title="{% trans "This translation is not maintained by the pretix team. We cannot vouch for its correctness and new or recently changed features might not be translated and will show in English instead. You can help translating at translate.pretix.eu." %}">
{% trans "Inofficial translation" %} {% trans "Unofficial translation" %}
</span> </span>
{% endif %} {% endif %}
</label> </label>

View File

@@ -4,7 +4,7 @@
{% block inner %} {% block inner %}
<h2>{% trans "Delete team:" %} {{ team.name }}</h2> <h2>{% trans "Delete team:" %} {{ team.name }}</h2>
{% if not possible %} {% if not possible %}
<p>{% blocktrans %}You cannot delete the team because there would be noone left who could change team permissions afterwards.{% endblocktrans %}</p> <p>{% blocktrans %}You cannot delete the team because there would be no one left who could change team permissions afterwards.{% endblocktrans %}</p>
<div class="form-group submit-group"> <div class="form-group submit-group">
<a href="{% url "control:organizer.teams" organizer=request.organizer.slug %}" class="btn btn-default btn-cancel"> <a href="{% url "control:organizer.teams" organizer=request.organizer.slug %}" class="btn btn-default btn-cancel">
{% trans "Cancel" %} {% trans "Cancel" %}

View File

@@ -1006,7 +1006,7 @@ class ItemAddOns(ItemDetailMixin, EventPermissionRequiredMixin, TemplateView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if self.get_object().category and self.get_object().category.is_addon: if self.get_object().category and self.get_object().category.is_addon:
messages.error(self.request, _('You cannot add addons to a product that is only available as an add-on ' messages.error(self.request, _('You cannot add add-ons to a product that is only available as an add-on '
'itself.')) 'itself.'))
return redirect(self.get_previous_url()) return redirect(self.get_previous_url())

View File

@@ -474,7 +474,7 @@ class TeamMemberView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
can_change_teams=True, members__isnull=False can_change_teams=True, members__isnull=False
).exists() ).exists()
if not other_admin_teams and self.object.can_change_teams and self.object.members.count() == 1: if not other_admin_teams and self.object.can_change_teams and self.object.members.count() == 1:
messages.error(self.request, _('You cannot remove the last member from this team as noone would ' messages.error(self.request, _('You cannot remove the last member from this team as no one would '
'be left with the permission to change teams.')) 'be left with the permission to change teams.'))
return redirect(self.get_success_url()) return redirect(self.get_success_url())
else: else:

View File

@@ -0,0 +1,148 @@
Admin
Adminbereich
Alipay
and
App
Apps
ausgeklappt
auswahl
Authenticator
Bancontact
Banking
Beispielevent
Benachrichtigungs
Benachrichtigungsart
Benachrichtigungseinstellungen
Berechtigungs
Bestellbestätigungs
Bestellungsstatus
Bestätigungs
bez
Blackberry
Browsereinstellungen
bspw
chardet
charge
Checkout
Chrome
Cronjob
csv
Debug
Doe
Downloadseite
Drag
Droid
Drop
Edge
Einlassdatum
Einlassuhrzeit
Erweiterungs
etc
Event
Eventeingang
Eventfirma
evtl
Explorer
Footer
geht's
GENEXAMPLE
gescannt
giropay
Gutscheineinlöser
herunterscrollen
hochlädst
HTTPS
iCal
ID
iDEAL
Inc
inkl
Installations
invalidiert
iOS
iTunes
JavaScript
Kategoriebeschreibung
Konfigurations
loszulegen
Ltd
Meta
Metadaten
MwSt
Nr
Opera
Output
PayPal
PayPals
Play
Plugin
Plugins
prefix
pretix
pretixdesk
pretixdroid
Professional
pt
QR
Rechnungs
Referer
Registrierungsdatum
Request
Requests
Reservierungszeitraum
reverse
Revisionssicherheit
Rundungsdifferenzen
Scan
Scanergebnis
schiefgeht
Secret
SEPA
Shirts
SOFORT
SSL
STARTTLS
Steuerschuldnerschaft
Store
Stornobeleg
Strg
Stripe
Stripes
systemweiten
Tab
Teammitglied
Teamname
Tokengenerator
Toolbar
TOTP
unkategorisiert
untenstehende
untenstehenden
unzugeordnete
unzugeordneten
Ursprüngl
USt
Veranstaltereinstellungen
Veranstalterkonten
Veranstalterkonto
Veranstaltername
Veranstalterseite
Veranstaltungs
Verfügbarkeitsberechnung
Veröffentlichbarer
VIP
Webhook
Widget
Yubikey
Zahlungs
Zahlungsbestätigungs
zahlungspflichtig
Zahlungsplugins
zeitbasiert
zubuchbaren
zurückbuchen
zurückgeleitet
zzgl
überbuchen
überbucht
überbuchten

View File

@@ -6347,7 +6347,7 @@ msgstr ""
#: pretix/control/permissions.py:29 pretix/control/permissions.py:66 #: pretix/control/permissions.py:29 pretix/control/permissions.py:66
#: pretix/control/permissions.py:97 pretix/control/permissions.py:114 #: pretix/control/permissions.py:97 pretix/control/permissions.py:114
msgid "You do not have permission to view this content." msgid "You do not have permission to view this content."
msgstr "Du has keine Berechtigung, diese Inhalte aufzurufen." msgstr "Du hast keine Berechtigung, diese Inhalte aufzurufen."
#: pretix/control/templates/pretixcontrol/auth/forgot.html:14 #: pretix/control/templates/pretixcontrol/auth/forgot.html:14
msgid "Send recovery information" msgid "Send recovery information"
@@ -11946,7 +11946,7 @@ msgstr "Hier klicken um das Fenster zu öffnen."
#: pretix/plugins/paypal/views.py:70 #: pretix/plugins/paypal/views.py:70
msgid "Invalid response from PayPal received." msgid "Invalid response from PayPal received."
msgstr "Paypal hat uns eine ungültige Antwort geschickt." msgstr "PayPal hat uns eine ungültige Antwort geschickt."
#: pretix/plugins/paypal/views.py:86 #: pretix/plugins/paypal/views.py:86
msgid "It looks like you canceled the PayPal payment" msgid "It looks like you canceled the PayPal payment"

View File

@@ -0,0 +1,148 @@
Admin
Adminbereich
Alipay
and
App
Apps
ausgeklappt
auswahl
Authenticator
Bancontact
Banking
Beispielevent
Benachrichtigungs
Benachrichtigungsart
Benachrichtigungseinstellungen
Berechtigungs
Bestellbestätigungs
Bestellungsstatus
Bestätigungs
bez
Blackberry
Browsereinstellungen
bspw
chardet
charge
Checkout
Chrome
Cronjob
csv
Debug
Doe
Downloadseite
Drag
Droid
Drop
Edge
Einlassdatum
Einlassuhrzeit
Erweiterungs
etc
Event
Eventeingang
Eventfirma
evtl
Explorer
Footer
geht's
GENEXAMPLE
gescannt
giropay
Gutscheineinlöser
herunterscrollen
hochlädst
HTTPS
iCal
ID
iDEAL
Inc
inkl
Installations
invalidiert
iOS
iTunes
JavaScript
Kategoriebeschreibung
Konfigurations
loszulegen
Ltd
Meta
Metadaten
MwSt
Nr
Opera
Output
PayPal
PayPals
Play
Plugin
Plugins
prefix
pretix
pretixdesk
pretixdroid
Professional
pt
QR
Rechnungs
Referer
Registrierungsdatum
Request
Requests
Reservierungszeitraum
reverse
Revisionssicherheit
Rundungsdifferenzen
Scan
Scanergebnis
schiefgeht
Secret
SEPA
Shirts
SOFORT
SSL
STARTTLS
Steuerschuldnerschaft
Store
Stornobeleg
Strg
Stripe
Stripes
systemweiten
Tab
Teammitglied
Teamname
Tokengenerator
Toolbar
TOTP
unkategorisiert
untenstehende
untenstehenden
unzugeordnete
unzugeordneten
Ursprüngl
USt
Veranstaltereinstellungen
Veranstalterkonten
Veranstalterkonto
Veranstaltername
Veranstalterseite
Veranstaltungs
Verfügbarkeitsberechnung
Veröffentlichbarer
VIP
Webhook
Widget
Yubikey
Zahlungs
Zahlungsbestätigungs
zahlungspflichtig
Zahlungsplugins
zeitbasiert
zubuchbaren
zurückbuchen
zurückgeleitet
zzgl
überbuchen
überbucht
überbuchten

View File

@@ -0,0 +1,55 @@
Alipay
authenticator
availabilities
Bancontact
barcode
chardet
checkboxes
cronjob
CSRF
CSV
csv
Ctrl
datetime
filetype
frontend
frontpage
GENEXAMPLE
giropay
hostname
HTTPS
IBAN
iCal
iDEAL
iOS
LLC
multiline
prepended
presale
pretix
pretixdesk
pretixdroid
redemptions
Referer
renderer
Samplecity
Somecity
SEPA
smtp
SOFORT
SSL
STARTTLS
subevent
substracted
timeframe
timesaver
timezones
TOTP
trustable
uncategorized
unredeemed
waitinglist
webhook
webserver
whitespace
Yubikey

View File

@@ -55,7 +55,7 @@
<p> <p>
{% blocktrans trimmed %} {% blocktrans trimmed %}
If this link does not open the pretixdesk application or if you want to set the application up on a If this link does not open the pretixdesk application or if you want to set the application up on a
seperate device, copy the following code and paste it into the application: separate device, copy the following code and paste it into the application:
{% endblocktrans %} {% endblocktrans %}
</p> </p>
<p> <p>

View File

@@ -48,13 +48,13 @@ def redirect_view(request, *args, **kwargs):
def oauth_return(request, *args, **kwargs): def oauth_return(request, *args, **kwargs):
if 'payment_stripe_oauth_event' not in request.session: if 'payment_stripe_oauth_event' not in request.session:
messages.error(request, _('An error occured during connecting with Stripe, please try again.')) messages.error(request, _('An error occurred during connecting with Stripe, please try again.'))
return redirect(reverse('control:index')) return redirect(reverse('control:index'))
event = get_object_or_404(Event, pk=request.session['payment_stripe_oauth_event']) event = get_object_or_404(Event, pk=request.session['payment_stripe_oauth_event'])
if request.GET.get('state') != request.session['payment_stripe_oauth_token']: if request.GET.get('state') != request.session['payment_stripe_oauth_token']:
messages.error(request, _('An error occured during connecting with Stripe, please try again.')) messages.error(request, _('An error occurred during connecting with Stripe, please try again.'))
return redirect(reverse('control:event.settings.payment.provider', kwargs={ return redirect(reverse('control:event.settings.payment.provider', kwargs={
'organizer': event.organizer.slug, 'organizer': event.organizer.slug,
'event': event.slug, 'event': event.slug,
@@ -81,7 +81,7 @@ def oauth_return(request, *args, **kwargs):
) )
except: except:
logger.exception('Failed to obtain OAuth token') logger.exception('Failed to obtain OAuth token')
messages.error(request, _('An error occured during connecting with Stripe, please try again.')) messages.error(request, _('An error occurred during connecting with Stripe, please try again.'))
else: else:
if 'error' not in data and data['livemode']: if 'error' not in data and data['livemode']:
try: try:
@@ -93,7 +93,7 @@ def oauth_return(request, *args, **kwargs):
testdata = testresp.json() testdata = testresp.json()
except: except:
logger.exception('Failed to obtain OAuth token') logger.exception('Failed to obtain OAuth token')
messages.error(request, _('An error occured during connecting with Stripe, please try again.')) messages.error(request, _('An error occurred during connecting with Stripe, please try again.'))
return redirect(reverse('control:event.settings.payment.provider', kwargs={ return redirect(reverse('control:event.settings.payment.provider', kwargs={
'organizer': event.organizer.slug, 'organizer': event.organizer.slug,
'event': event.slug, 'event': event.slug,

View File

@@ -16,3 +16,4 @@ pytest-warnings
pytest-cache pytest-cache
pytest-sugar pytest-sugar
responses responses
potypo

View File

@@ -14,3 +14,38 @@ known_standard_library = typing,enum,mimetypes
multi_line_output = 5 multi_line_output = 5
not_skip = __init__.py not_skip = __init__.py
skip = make_testdata.py,wsgi.py,bootstrap,celery_app.py,settings.py skip = make_testdata.py,wsgi.py,bootstrap,celery_app.py,settings.py
[potypo]
default_language = en_US
locales_dir = pretix/locale
no_fail =
ar
cs
da
es
fr
it
nl
nl_BE
pt_BR
wl_dir = pretix/locale
edgecase_words =
add-ons
add-on's
same-origin"-requests
MT940
MT940-Format
pre-selected
pretix.eu
pretix.eu-Blog
pretix.eu-Server
Prüf-Ergebnisse
translate.pretix.eu
4th
214th
phrases =
ticketing powered by
powered by
Stripe Connect
chunkers = enchant.tokenize.HTMLChunker
filters = PythonFormatFilter,enchant.tokenize.URLFilter,HTMLFilter