Neue Event-Eigenschaften

This commit is contained in:
Daniel Grams 2020-07-08 11:28:09 +02:00
parent c8c3e1a8c1
commit 38ebac81fe
14 changed files with 585 additions and 148 deletions

26
app.py
View File

@ -14,7 +14,6 @@ import pytz
import json
from urllib.parse import quote_plus
from dateutil.rrule import rrulestr, rruleset, rrule
from jsonld import DateTimeEncoder, get_sd_for_event_date
# Create app
app = Flask(__name__)
@ -41,11 +40,12 @@ babel = Babel(app)
app.jinja_env.filters['quote_plus'] = lambda u: quote_plus(u)
app.json_encoder = DateTimeEncoder
# create db
db = SQLAlchemy(app)
from jsonld import DateTimeEncoder, get_sd_for_event_date
app.json_encoder = DateTimeEncoder
# Setup Flask-Security
# Define models
from models import EventCategory, Image, EventSuggestion, EventSuggestionDate, OrgOrAdminUnit, Actor, Place, Location, User, Role, AdminUnit, AdminUnitMember, AdminUnitMemberRole, OrgMember, OrgMemberRole, Organization, AdminUnitOrg, AdminUnitOrgRole, Event, EventDate
@ -68,6 +68,11 @@ def get_event_category_name(category):
app.jinja_env.filters['event_category_name'] = lambda u: get_event_category_name(u)
def get_localized_enum_name(enum):
return lazy_gettext(enum.__class__.__name__ + '.' + enum.name)
app.jinja_env.filters['loc_enum'] = lambda u: get_localized_enum_name(u)
def print_dynamic_texts():
gettext('Event_Art')
gettext('Event_Book')
@ -87,6 +92,7 @@ def print_dynamic_texts():
gettext('Event_Fitness')
gettext('Event_Sports')
gettext('Event_Other')
gettext('Typical Age range')
def handleSqlError(e):
message = str(e.__dict__['orig'])
@ -951,6 +957,14 @@ def create_initial_data():
db.session.commit()
def flash_errors(form):
for field, errors in form.errors.items():
for error in errors:
flash(gettext("Error in the %s field - %s") % (
getattr(form, field).label.text,
error
), 'danger')
# Views
@app.route("/")
def home():
@ -1228,7 +1242,7 @@ from forms.admin_unit import CreateAdminUnitForm, UpdateAdminUnitForm
def update_event_with_form(event, form):
form.populate_obj(event)
eventDate = EventDate(event_id = event.id, start=form.start.data)
eventDate = EventDate(event_id = event.id, start=form.start.data, end=form.end.data)
event.dates = [eventDate]
if form.photo_file.data:
@ -1272,7 +1286,7 @@ def event_update(event_id):
if not can_update_event(event):
abort(401)
form = UpdateEventForm(obj=event,start=event.dates[0].start)
form = UpdateEventForm(obj=event,start=event.dates[0].start,end=event.dates[0].end)
prepare_event_form(form)
if form.validate_on_submit():
@ -1284,6 +1298,8 @@ def event_update(event_id):
return redirect(url_for('event', event_id=event.id))
except SQLAlchemyError as e:
flash(handleSqlError(e), 'danger')
else:
flash_errors(form)
return render_template('event/update.html',
form=form,

View File

@ -1,3 +1,4 @@
[python: *.py]
[ignore: env/**]
[python: **.py]
[jinja2: templates/**.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_

16
db.py Normal file
View File

@ -0,0 +1,16 @@
from sqlalchemy.types import TypeDecorator
from sqlalchemy import Integer
class IntegerEnum(TypeDecorator):
impl = Integer
def __init__(self, enumtype, *args, **kwargs):
super().__init__(*args, **kwargs)
self._enumtype = enumtype
def process_bind_param(self, value, dialect):
return value
def process_result_value(self, value, dialect):
if value:
return self._enumtype(value)
return None

View File

@ -1,9 +1,10 @@
from flask_babelex import lazy_gettext
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed
from wtforms import StringField, SubmitField, TextAreaField, SelectField
from wtforms import StringField, SubmitField, TextAreaField, SelectField, BooleanField, IntegerField
from wtforms.fields.html5 import DateTimeLocalField
from wtforms.validators import DataRequired, Optional
from models import EventTargetGroupOrigin, EventAttendanceMode, EventStatus
class CreateEventForm(FlaskForm):
submit = SubmitField(lazy_gettext("Create event"))
@ -12,12 +13,37 @@ class CreateEventForm(FlaskForm):
ticket_link = StringField(lazy_gettext('Ticket Link URL'), validators=[Optional()])
description = TextAreaField(lazy_gettext('Description'), validators=[DataRequired()])
start = DateTimeLocalField(lazy_gettext('Start'), format='%Y-%m-%dT%H:%M', validators=[DataRequired()])
end = DateTimeLocalField(lazy_gettext('End'), format='%Y-%m-%dT%H:%M', validators=[Optional()])
previous_start_date = DateTimeLocalField(lazy_gettext('Previous start date'), format='%Y-%m-%dT%H:%M', validators=[Optional()])
tags = StringField(lazy_gettext('Tags'), validators=[Optional()])
place_id = SelectField(lazy_gettext('Place'), validators=[DataRequired()], coerce=int)
host_id = SelectField(lazy_gettext('Host'), validators=[DataRequired()], coerce=int)
category_id = SelectField(lazy_gettext('Category'), validators=[DataRequired()], coerce=int)
admin_unit_id = SelectField(lazy_gettext('Admin unit'), validators=[DataRequired()], coerce=int)
kid_friendly = BooleanField(lazy_gettext('Kid friendly'), validators=[Optional()])
accessible_for_free = BooleanField(lazy_gettext('Accessible for free'), validators=[Optional()])
age_from = IntegerField(lazy_gettext('Typical Age from'), validators=[Optional()])
age_to = IntegerField(lazy_gettext('Typical Age to'), validators=[Optional()])
target_group_origin = SelectField(lazy_gettext('Target group origin'), coerce=int, choices=[
(int(EventTargetGroupOrigin.both), lazy_gettext('EventTargetGroupOrigin.both')),
(int(EventTargetGroupOrigin.tourist), lazy_gettext('EventTargetGroupOrigin.tourist')),
(int(EventTargetGroupOrigin.resident), lazy_gettext('EventTargetGroupOrigin.resident'))])
attendance_mode = SelectField(lazy_gettext('Attendance mode'), coerce=int, choices=[
(int(EventAttendanceMode.offline), lazy_gettext('EventAttendanceMode.offline')),
(int(EventAttendanceMode.online), lazy_gettext('EventAttendanceMode.online')),
(int(EventAttendanceMode.mixed), lazy_gettext('EventAttendanceMode.mixed'))])
status = SelectField(lazy_gettext('Status'), coerce=int, choices=[
(int(EventStatus.scheduled), lazy_gettext('EventStatus.scheduled')),
(int(EventStatus.cancelled), lazy_gettext('EventStatus.cancelled')),
(int(EventStatus.movedOnline), lazy_gettext('EventStatus.movedOnline')),
(int(EventStatus.postponed), lazy_gettext('EventStatus.postponed')),
(int(EventStatus.rescheduled), lazy_gettext('EventStatus.rescheduled'))])
photo_file = FileField(lazy_gettext('Photo'), validators=[FileAllowed(['jpg', 'jpeg', 'png'], lazy_gettext('Images only!'))])
class UpdateEventForm(CreateEventForm):

View File

@ -2,6 +2,7 @@ import datetime
import decimal
from json import JSONEncoder
from flask import url_for
from models import EventAttendanceMode, EventStatus
# subclass JSONEncoder
class DateTimeEncoder(JSONEncoder):
@ -97,6 +98,38 @@ def get_sd_for_event_date(event_date):
result["location"] = get_sd_for_place(event.place)
result["organizer"] = get_sd_for_ooa(event.host)
if event_date.end:
result["endDate"] = event_date.end
if event.previous_start_date:
result["previousStartDate"] = event.previous_start_date
if event.accessible_for_free:
result["accessible_for_free"] = event.accessible_for_free
if event.age_from or event.age_to:
result["typicalAgeRange"] = "%d-%d" % (event.age_from, event.age_to)
if event.attendance_mode:
if event.attendance_mode == EventAttendanceMode.offline:
result["eventAttendanceMode"] = "OfflineEventAttendanceMode"
elif event.attendance_mode == EventAttendanceMode.online:
result["eventAttendanceMode"] = "OnlineEventAttendanceMode"
elif event.attendance_mode == EventAttendanceMode.mixed:
result["eventAttendanceMode"] = "MixedEventAttendanceMode"
if event.status:
if event.status == EventStatus.scheduled:
result["eventStatus"] = "EventScheduled"
elif event.status == EventStatus.cancelled:
result["eventStatus"] = "EventCancelled"
elif event.status == EventStatus.movedOnline:
result["eventStatus"] = "EventMovedOnline"
elif event.status == EventStatus.postponed:
result["eventStatus"] = "EventPostponed"
elif event.status == EventStatus.rescheduled:
result["eventStatus"] = "EventRescheduled"
if event.photo_id:
result["image"] = url_for('image', id=event.photo_id)

View File

@ -8,6 +8,7 @@ Create Date: ${create_date}
from alembic import op
import sqlalchemy as sa
import sqlalchemy_utils
import db
${imports if imports else ""}
# revision identifiers, used by Alembic.

View File

@ -0,0 +1,32 @@
"""empty message
Revision ID: ed6bb2084bbd
Revises: f1bc3fa623c7
Create Date: 2020-07-08 08:53:44.373606
"""
from alembic import op
import sqlalchemy as sa
import sqlalchemy_utils
import db
# revision identifiers, used by Alembic.
revision = 'ed6bb2084bbd'
down_revision = 'f1bc3fa623c7'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('event', sa.Column('previous_start_date', sa.DateTime(timezone=True), nullable=True))
op.add_column('eventdate', sa.Column('end', sa.DateTime(timezone=True), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('eventdate', 'end')
op.drop_column('event', 'previous_start_date')
# ### end Alembic commands ###

View File

@ -0,0 +1,44 @@
"""empty message
Revision ID: f1bc3fa623c7
Revises: 75c07cb9cfe3
Create Date: 2020-07-07 15:49:58.653888
"""
from alembic import op
import sqlalchemy as sa
import sqlalchemy_utils
import db
from models import EventTargetGroupOrigin, EventAttendanceMode, EventStatus
# revision identifiers, used by Alembic.
revision = 'f1bc3fa623c7'
down_revision = '75c07cb9cfe3'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('event', sa.Column('accessible_for_free', sa.Boolean(), nullable=True))
op.add_column('event', sa.Column('age_from', sa.Integer(), nullable=True))
op.add_column('event', sa.Column('age_to', sa.Integer(), nullable=True))
op.add_column('event', sa.Column('attendance_mode', db.IntegerEnum(EventAttendanceMode), nullable=True))
op.add_column('event', sa.Column('kid_friendly', sa.Boolean(), nullable=True))
op.add_column('event', sa.Column('status', db.IntegerEnum(EventStatus), nullable=True))
op.add_column('event', sa.Column('tags', sa.UnicodeText(), nullable=True))
op.add_column('event', sa.Column('target_group_origin', db.IntegerEnum(EventTargetGroupOrigin), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('event', 'target_group_origin')
op.drop_column('event', 'tags')
op.drop_column('event', 'status')
op.drop_column('event', 'kid_friendly')
op.drop_column('event', 'attendance_mode')
op.drop_column('event', 'age_to')
op.drop_column('event', 'age_from')
op.drop_column('event', 'accessible_for_free')
# ### end Alembic commands ###

View File

@ -2,10 +2,13 @@ from app import db
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.orm import relationship, backref
from sqlalchemy.schema import CheckConstraint
from sqlalchemy.types import TypeDecorator
from sqlalchemy import UniqueConstraint, Boolean, DateTime, Column, Integer, String, ForeignKey, Unicode, UnicodeText, Numeric, LargeBinary
from flask_security import UserMixin, RoleMixin
from flask_dance.consumer.storage.sqla import OAuthConsumerMixin
from enum import IntEnum
import datetime
from db import IntegerEnum
### Base
@ -240,6 +243,23 @@ class EventSuggestionDate(db.Model):
start = db.Column(db.DateTime(timezone=True), nullable=False)
#end: date_time
class EventTargetGroupOrigin(IntEnum):
both = 1
tourist = 2
resident = 3
class EventAttendanceMode(IntEnum):
offline = 1
online = 2
mixed = 3
class EventStatus(IntEnum):
scheduled = 1
cancelled = 2
movedOnline = 3
postponed = 4
rescheduled = 5
class Event(db.Model, TrackableMixin):
__tablename__ = 'event'
id = Column(Integer(), primary_key=True)
@ -258,6 +278,15 @@ class Event(db.Model, TrackableMixin):
photo = db.relationship('Image', uselist=False)
category_id = db.Column(db.Integer, db.ForeignKey('eventcategory.id'), nullable=False)
category = relationship('EventCategory', uselist=False)
tags = Column(UnicodeText())
kid_friendly = Column(Boolean())
accessible_for_free = Column(Boolean())
age_from = Column(Integer())
age_to = Column(Integer())
target_group_origin = Column(IntegerEnum(EventTargetGroupOrigin))
attendance_mode = Column(IntegerEnum(EventAttendanceMode))
status = Column(IntegerEnum(EventStatus))
previous_start_date = db.Column(db.DateTime(timezone=True), nullable=True)
recurrence_rule = Column(UnicodeText())
dates = relationship('EventDate', backref=backref('event', lazy=False), cascade="all, delete-orphan")
@ -267,4 +296,4 @@ class EventDate(db.Model):
id = Column(Integer(), primary_key=True)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False)
start = db.Column(db.DateTime(timezone=True), nullable=False)
#end: date_time
end = db.Column(db.DateTime(timezone=True), nullable=True)

View File

@ -145,6 +145,42 @@
{% endif %}
{% endmacro %}
{% macro render_bool_prop(prop, icon, label_key) %}
{% if prop %}
<div>
<i class="fa fa-fw {{ icon }}" data-toggle="tooltip" title="{{ _(label_key) }}"></i>
{{ _(label_key) }}
</div>
{% endif %}
{% endmacro %}
{% macro render_enum_prop(prop, icon, label_key) %}
{% if prop and prop.value > 1 %}
<div>
<i class="fa fa-fw {{ icon }}" data-toggle="tooltip" title="{{ _(label_key) }}"></i>
{{ prop | loc_enum }}
</div>
{% endif %}
{% endmacro %}
{% macro render_range_prop(from, to, icon, label_key) %}
{% if from or to %}
<div>
<i class="fa fa-fw {{ icon }}" data-toggle="tooltip" title="{{ _(label_key) }}"></i>
{{ from }} - {{ to }}
</div>
{% endif %}
{% endmacro %}
{% macro render_tag_prop(tags) %}
{% if tags %}
<div>
<i class="fa fa-fw fa-tags" data-toggle="tooltip" title="{{ _('Tags') }}"></i>
{{ tags }}
</div>
{% endif %}
{% endmacro %}
{% macro render_link_prop(link) %}
{% if link %}
<div>
@ -201,7 +237,11 @@
<div class="card-body">
<h5 class="card-title">{{ event.name }}</h5>
<div><i class="fa fa-fw fa-calendar" data-toggle="tooltip" title="{{ _('Date') }}"></i> {{ date.start | datetimeformat('short') }}</div>
<div><i class="fa fa-fw fa-calendar" data-toggle="tooltip" title="{{ _('Date') }}"></i> {{ date.start | datetimeformat('short') }} {% if date.end %}- {{ date.end | datetimeformat('short') }}{% endif %}</div>
{{ render_enum_prop(event.status, 'fa-info-circle', 'Status') }}
{% if event.previous_start_date %}
<div><i class="fa fa-fw fa-calendar-times" data-toggle="tooltip" title="{{ _('Previous start date') }}"></i> {{ event.previous_start_date | datetimeformat('short') }}</div>
{% endif %}
<!--<div><i class="fa fa-fw fa-map-marker" data-toggle="tooltip" title="{{ _('Location') }}"></i> <a href="{{ url_for('place', place_id=event.place.id) }}">{{ render_place(event.place) }}</a></div>-->
{% if event.verified %}
<div><i class="fa fa-fw fa-check-circle text-success" data-toggle="tooltip" title="{{ _('Verified') }}"></i> {{ _('Verified') }}</div>
@ -219,6 +259,12 @@
{% if event.category_id %}
<div><i class="fa fa-fw fa-archive" data-toggle="tooltip" title="{{ _('Category') }}"></i> {{ event.category | event_category_name }}</div>
{% endif %}
{{ render_tag_prop(event.tags) }}
{{ render_bool_prop(event.kid_friendly, 'fa-child', 'Kid friendly') }}
{{ render_bool_prop(event.accessible_for_free, 'fa-door-open', 'Accessible for free') }}
{{ render_range_prop(event.age_from, event.age_to, 'fa-people-arrows', 'Typical Age range') }}
{{ render_enum_prop(event.target_group_origin, 'fa-users', 'Target group origin') }}
{{ render_enum_prop(event.attendance_mode, 'fa-mouse-pointer', 'Attendance mode') }}
<!--<div><i class="fa fa-fw fa-users" data-toggle="tooltip" title="{{ _('Host') }}"></i> {{ render_ooa_with_link(event.host) }}</div>-->
</div>
</div>

View File

@ -16,6 +16,9 @@
{{ render_field_with_errors(form.name) }}
{{ render_field_with_errors(form.description) }}
{{ render_field_with_errors(form.start) }}
{{ render_field_with_errors(form.end) }}
{{ render_field_with_errors(form.status, class="autocomplete w-100") }}
{{ render_field_with_errors(form.previous_start_date) }}
<!-- <textarea name="repeat"></textarea>
<script type="text/javascript">
@ -42,6 +45,18 @@
</div>
</div>
<div class="card mb-4">
<div class="card-header">
{{ _('Target group') }}
</div>
<div class="card-body">
{{ render_field_with_errors(form.target_group_origin, class="autocomplete w-100") }}
{{ render_field_with_errors(form.kid_friendly, style="width: fit-content; flex: initial;") }}
{{ render_field_with_errors(form.age_from) }}
{{ render_field_with_errors(form.age_to) }}
</div>
</div>
<div class="card mb-4">
<div class="card-header">
{{ _('Additional information') }}
@ -51,6 +66,9 @@
{{ render_field_with_errors(form.category_id, class="autocomplete w-100") }}
{{ render_field_with_errors(form.external_link) }}
{{ render_field_with_errors(form.ticket_link) }}
{{ render_field_with_errors(form.tags) }}
{{ render_field_with_errors(form.attendance_mode, class="autocomplete w-100") }}
{{ render_field_with_errors(form.accessible_for_free, style="width: fit-content; flex: initial;") }}
</div>
</div>

View File

@ -16,6 +16,9 @@
{{ render_field_with_errors(form.name) }}
{{ render_field_with_errors(form.description) }}
{{ render_field_with_errors(form.start) }}
{{ render_field_with_errors(form.end) }}
{{ render_field_with_errors(form.status, class="autocomplete w-100") }}
{{ render_field_with_errors(form.previous_start_date) }}
<!-- <textarea name="repeat"></textarea>
<script type="text/javascript">
@ -42,6 +45,18 @@
</div>
</div>
<div class="card mb-4">
<div class="card-header">
{{ _('Target group') }}
</div>
<div class="card-body">
{{ render_field_with_errors(form.target_group_origin, class="autocomplete w-100") }}
{{ render_field_with_errors(form.kid_friendly, style="width: fit-content; flex: initial;") }}
{{ render_field_with_errors(form.age_from) }}
{{ render_field_with_errors(form.age_to) }}
</div>
</div>
<div class="card mb-4">
<div class="card-header">
{{ _('Additional information') }}
@ -51,6 +66,9 @@
{{ render_field_with_errors(form.category_id, class="autocomplete w-100") }}
{{ render_field_with_errors(form.external_link) }}
{{ render_field_with_errors(form.ticket_link) }}
{{ render_field_with_errors(form.tags) }}
{{ render_field_with_errors(form.attendance_mode, class="autocomplete w-100") }}
{{ render_field_with_errors(form.accessible_for_free, style="width: fit-content; flex: initial;") }}
</div>
</div>

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2020-07-07 11:37+0200\n"
"POT-Creation-Date: 2020-07-08 09:13+0200\n"
"PO-Revision-Date: 2020-06-07 18:51+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: de\n"
@ -23,106 +23,119 @@ msgid "Event_"
msgstr ""
#: app.py:72
msgid "."
msgstr ""
#: app.py:77
msgid "Event_Art"
msgstr "Kunst"
#: app.py:73
#: app.py:78
msgid "Event_Book"
msgstr "Literatur"
#: app.py:74
#: app.py:79
msgid "Event_Movie"
msgstr "Film"
#: app.py:75
#: app.py:80
msgid "Event_Family"
msgstr "Familie"
#: app.py:76
#: app.py:81
msgid "Event_Festival"
msgstr "Festival"
#: app.py:77
#: app.py:82
msgid "Event_Religious"
msgstr "Religion"
#: app.py:78
#: app.py:83
msgid "Event_Shopping"
msgstr "Shopping"
#: app.py:79
#: app.py:84
msgid "Event_Comedy"
msgstr "Comedy"
#: app.py:80
#: app.py:85
msgid "Event_Music"
msgstr "Musik"
#: app.py:81
#: app.py:86
msgid "Event_Dance"
msgstr "Tanz"
#: app.py:82
#: app.py:87
msgid "Event_Nightlife"
msgstr "Party"
#: app.py:83
#: app.py:88
msgid "Event_Theater"
msgstr "Theater"
#: app.py:84
#: app.py:89
msgid "Event_Dining"
msgstr "Essen"
#: app.py:85
#: app.py:90
msgid "Event_Conference"
msgstr "Konferenz"
#: app.py:86
#: app.py:91
msgid "Event_Meetup"
msgstr "Networking"
#: app.py:87
#: app.py:92
msgid "Event_Fitness"
msgstr "Fitness"
#: app.py:88
#: app.py:93
msgid "Event_Sports"
msgstr "Sport"
#: app.py:89
#: app.py:94
msgid "Event_Other"
msgstr "Sonstiges"
#: app.py:1005
#: app.py:95
msgid "Typical Age range"
msgstr "Typische Altersspanne"
#: app.py:963
#, python-format
msgid "Error in the %s field - %s"
msgstr "Fehler im Feld %s: %s"
#: app.py:1019
msgid "Admin unit successfully updated"
msgstr "Verwaltungseinheit erfolgreich aktualisiert"
#: app.py:1062
#: app.py:1076
msgid "Organization successfully created"
msgstr "Organisation erfolgreich erstellt"
#: app.py:1082
#: app.py:1096
msgid "Organization successfully updated"
msgstr "Organisation erfolgreich aktualisiert"
#: app.py:1137
#: app.py:1151
msgid "Place successfully updated"
msgstr "Ort erfolgreich aktualisiert"
#: app.py:1160
#: app.py:1174
msgid "Place successfully created"
msgstr "Ort erfolgreich erstellt"
#: app.py:1262
#: app.py:1276
msgid "Event successfully created"
msgstr "Veranstaltung erfolgreich erstellt"
#: app.py:1283
#: app.py:1297
msgid "Event successfully updated"
msgstr "Veranstaltung erfolgreich aktualisiert"
#: app.py:1320
#: app.py:1336
msgid "Event suggestion successfully created"
msgstr "Veranstaltungsvorschlag erfolgreich erstellt"
@ -130,44 +143,267 @@ msgstr "Veranstaltungsvorschlag erfolgreich erstellt"
msgid "Successfully signed in."
msgstr "Erfolgreich eingeloggt."
#: templates/_macros.html:78 templates/event/create.html:6
#: forms/admin_unit.py:11 forms/event_suggestion.py:15 forms/organization.py:10
#: forms/place.py:9 templates/event_suggestion/read.html:50
msgid "Street"
msgstr "Straße"
#: forms/admin_unit.py:12 forms/event_suggestion.py:16 forms/organization.py:11
#: forms/place.py:10 templates/event_suggestion/read.html:54
msgid "Postal code"
msgstr "Postleitzahl"
#: forms/admin_unit.py:13 forms/event_suggestion.py:17 forms/organization.py:12
#: forms/place.py:11 templates/event_suggestion/read.html:58
msgid "City"
msgstr "Stadt/Ort"
#: forms/admin_unit.py:14 forms/organization.py:13 forms/place.py:12
msgid "State"
msgstr "Bundesland"
#: forms/admin_unit.py:15 forms/organization.py:14 forms/place.py:13
msgid "Latitude"
msgstr "Breitengrad"
#: forms/admin_unit.py:16 forms/organization.py:15 forms/place.py:14
msgid "Longitude"
msgstr "Längengrad"
#: forms/admin_unit.py:19 forms/event.py:11 forms/event_suggestion.py:9
#: forms/organization.py:18 forms/place.py:19 templates/_macros.html:100
#: templates/admin/admin_units.html:18 templates/admin_unit/list.html:13
#: templates/admin_unit/read.html:65 templates/admin_unit/read.html:87
#: templates/event/list.html:17 templates/event_suggestion/list.html:14
#: templates/home.html:22 templates/home.html:44
#: templates/organization/list.html:19 templates/organization/read.html:66
#: templates/place/list.html:19 templates/profile.html:15
#: templates/profile.html:37
msgid "Name"
msgstr "Name"
#: forms/admin_unit.py:20 forms/event.py:12 forms/event_suggestion.py:12
#: forms/organization.py:19 forms/place.py:20
#: templates/event_suggestion/read.html:30
msgid "Link URL"
msgstr "Link URL"
#: forms/admin_unit.py:21 forms/organization.py:20 templates/_macros.html:196
msgid "Email"
msgstr "Email"
#: forms/admin_unit.py:22 forms/organization.py:21 templates/_macros.html:205
msgid "Phone"
msgstr "Telefon"
#: forms/admin_unit.py:23 forms/organization.py:22
msgid "Logo"
msgstr "Logo"
#: forms/admin_unit.py:23 forms/event.py:47 forms/organization.py:22
#: forms/place.py:21
msgid "Images only!"
msgstr "Nur Fotos!"
#: forms/admin_unit.py:27
msgid "Create admin unit"
msgstr "Verwaltungseinheit erstellen"
#: forms/admin_unit.py:30 templates/admin_unit/read.html:12
#: templates/admin_unit/update.html:10
msgid "Update admin unit"
msgstr "Verwaltungseinheit aktualisieren"
#: forms/event.py:10 templates/_macros.html:78 templates/event/create.html:6
msgid "Create event"
msgstr "Veranstaltung erstellen"
#: templates/_macros.html:80 templates/event_suggestion/create.html:6
#: forms/event.py:13
msgid "Ticket Link URL"
msgstr "Ticket Link"
#: forms/event.py:14 forms/event_suggestion.py:10 forms/place.py:22
#: templates/event_suggestion/read.html:26
msgid "Description"
msgstr "Beschreibung"
#: forms/event.py:15 forms/event_suggestion.py:11
msgid "Start"
msgstr "Beginn"
#: forms/event.py:16
msgid "End"
msgstr "Ende"
#: forms/event.py:17 templates/_macros.html:243
msgid "Previous start date"
msgstr "Vorheriges Startdatum"
#: forms/event.py:18 templates/_macros.html:178
msgid "Tags"
msgstr "Stichworte"
#: forms/event.py:20 templates/_macros.html:275 templates/event/create.html:41
#: templates/event/update.html:41 templates/place/create.html:20
#: templates/place/update.html:20
msgid "Place"
msgstr "Ort"
#: forms/event.py:21 templates/_macros.html:101 templates/_macros.html:268
#: templates/_macros.html:301 templates/event/create.html:32
#: templates/event/list.html:18 templates/event/update.html:32
#: templates/event_suggestion/list.html:15
msgid "Host"
msgstr "Veranstalter"
#: forms/event.py:22 templates/_macros.html:260
msgid "Category"
msgstr "Kategorie"
#: forms/event.py:23 forms/organization.py:28
#: templates/admin_unit/update.html:16 templates/event/create.html:77
#: templates/event/update.html:77 templates/organization/create.html:56
msgid "Admin unit"
msgstr "Verwaltungseinheit"
#: forms/event.py:25
msgid "Kid friendly"
msgstr "Für Kinder geeignet"
#: forms/event.py:26
msgid "Accessible for free"
msgstr "Kostenlos zugänglich"
#: forms/event.py:27
msgid "Typical Age from"
msgstr "Typisches Alter von"
#: forms/event.py:28
msgid "Typical Age to"
msgstr "Typisches Alter bis"
#: forms/event.py:30
msgid "Target group origin"
msgstr "Für Touristen/Einwohner geeignet"
#: forms/event.py:31
msgid "EventTargetGroupOrigin.both"
msgstr "Für Touristen und Einwohner"
#: forms/event.py:32
msgid "EventTargetGroupOrigin.tourist"
msgstr "Hauptsächlich für Touristen"
#: forms/event.py:33
msgid "EventTargetGroupOrigin.resident"
msgstr "Hauptsächlich für Einwohner"
#: forms/event.py:35
msgid "Attendance mode"
msgstr "Teilnahme"
#: forms/event.py:36
msgid "EventAttendanceMode.offline"
msgstr "Offline"
#: forms/event.py:37
msgid "EventAttendanceMode.online"
msgstr "Online"
#: forms/event.py:38
msgid "EventAttendanceMode.mixed"
msgstr "Online und offline"
#: forms/event.py:40
msgid "Status"
msgstr "Status"
#: forms/event.py:41
msgid "EventStatus.scheduled"
msgstr "Geplant"
#: forms/event.py:42
msgid "EventStatus.cancelled"
msgstr "Abgesagt"
#: forms/event.py:43
msgid "EventStatus.movedOnline"
msgstr "Online verschoben"
#: forms/event.py:44
msgid "EventStatus.postponed"
msgstr "Verschoben"
#: forms/event.py:45
msgid "EventStatus.rescheduled"
msgstr "Neu angesetzt"
#: forms/event.py:47 forms/place.py:21
msgid "Photo"
msgstr "Foto"
#: forms/event.py:50 templates/event/read.html:31 templates/event/update.html:6
msgid "Update event"
msgstr "Veranstaltung aktualisieren"
#: forms/event_suggestion.py:8 templates/_macros.html:80
#: templates/event_suggestion/create.html:6
msgid "Suggest event"
msgstr "Veranstaltung vorschlagen"
#: forms/event_suggestion.py:14 templates/event_suggestion/read.html:46
msgid "Event place"
msgstr "Veranstaltungsort"
#: forms/event_suggestion.py:19 templates/event_suggestion/read.html:74
msgid "Event host"
msgstr "Veranstalter"
#: forms/event_suggestion.py:20 templates/event_suggestion/read.html:78
msgid "Contact name"
msgstr "Kontakt Name"
#: forms/event_suggestion.py:21 templates/event_suggestion/read.html:82
msgid "Contact email"
msgstr "Kontakt Email"
#: forms/organization.py:23
msgid "Legal name"
msgstr "Offizieller Name"
#: forms/organization.py:27 templates/organization/create.html:10
#: templates/organization/list.html:11
msgid "Create organization"
msgstr "Organisation hinzufügen"
#: forms/organization.py:31 templates/organization/read.html:12
#: templates/organization/update.html:10
msgid "Update organization"
msgstr "Organisation aktualisieren"
#: forms/place.py:17 templates/place/create.html:10
#: templates/place/list.html:11
msgid "Create place"
msgstr "Ort hinzufügen"
#: forms/place.py:26 templates/place/read.html:12
#: templates/place/update.html:10
msgid "Update place"
msgstr "Ort aktualisieren"
#: templates/_macros.html:86 templates/event_suggestion/list.html:3
#: templates/event_suggestion/list.html:7
msgid "Event suggestions"
msgstr "Veranstaltungsvorschläge"
#: templates/_macros.html:99 templates/_macros.html:204
#: templates/_macros.html:99 templates/_macros.html:240
#: templates/event/list.html:16 templates/event_suggestion/list.html:13
#: templates/event_suggestion/read.html:18
msgid "Date"
msgstr "Datum"
#: templates/_macros.html:100 templates/admin/admin_units.html:18
#: templates/admin_unit/list.html:13 templates/admin_unit/read.html:65
#: templates/admin_unit/read.html:87 templates/event/list.html:17
#: templates/event_suggestion/list.html:14 templates/home.html:22
#: templates/home.html:44 templates/organization/list.html:19
#: templates/organization/read.html:66 templates/place/list.html:19
#: templates/profile.html:15 templates/profile.html:37
msgid "Name"
msgstr "Name"
#: templates/_macros.html:101 templates/_macros.html:222
#: templates/_macros.html:255 templates/event/create.html:29
#: templates/event/list.html:18 templates/event/update.html:29
#: templates/event_suggestion/list.html:15
msgid "Host"
msgstr "Veranstalter"
#: templates/_macros.html:102 templates/_macros.html:178
#: templates/_macros.html:205 templates/admin_unit/update.html:25
#: templates/_macros.html:102 templates/_macros.html:214
#: templates/_macros.html:245 templates/admin_unit/update.html:25
#: templates/event/list.html:19 templates/event_suggestion/list.html:16
#: templates/event_suggestion/read.html:41
#: templates/organization/create.html:26 templates/organization/update.html:26
@ -175,7 +411,7 @@ msgstr "Veranstalter"
msgid "Location"
msgstr "Standort"
#: templates/_macros.html:112 templates/_macros.html:207
#: templates/_macros.html:112 templates/_macros.html:247
#: templates/event/list.html:29
msgid "Verified"
msgstr "Verifiziert"
@ -188,42 +424,24 @@ msgstr "Alle Veranstaltungen anzeigen"
msgid "Show on Google Maps"
msgstr "Auf Google Maps anzeigen"
#: templates/_macros.html:151
#: templates/_macros.html:187
msgid "Link"
msgstr "Link"
#: templates/_macros.html:160
msgid "Email"
msgstr "Email"
#: templates/_macros.html:169
msgid "Phone"
msgstr "Telefon"
#: templates/_macros.html:199 templates/event/create.html:13
#: templates/_macros.html:235 templates/event/create.html:13
#: templates/event/update.html:13 templates/event_suggestion/read.html:13
msgid "Event"
msgstr "Veranstaltung"
#: templates/_macros.html:220
msgid "Category"
msgstr "Kategorie"
#: templates/_macros.html:229 templates/event/create.html:38
#: templates/event/update.html:38 templates/place/create.html:20
#: templates/place/update.html:20
msgid "Place"
msgstr "Ort"
#: templates/_macros.html:248
#: templates/_macros.html:294
msgid "Show directions"
msgstr "Anreise planen"
#: templates/_macros.html:296
#: templates/_macros.html:342
msgid "Sign in with Google"
msgstr "Mit Google anmelden"
#: templates/_macros.html:356
#: templates/_macros.html:402
msgid "Search location on Google"
msgstr "Ort bei Google suchen"
@ -295,10 +513,6 @@ msgstr "Administration"
msgid "Logout"
msgstr "Ausloggen"
#: templates/admin_unit/read.html:12 templates/admin_unit/update.html:10
msgid "Update admin unit"
msgstr "Verwaltungseinheit aktualisieren"
#: templates/admin_unit/read.html:19 templates/organization/read.html:19
#: templates/place/read.html:19
msgid "Info"
@ -312,18 +526,17 @@ msgstr "Mitglieder"
msgid "You are a member of this admin unit."
msgstr "Du bist Mitglied dieser Verwaltungseinheit"
#: templates/admin_unit/update.html:16 templates/event/create.html:59
#: templates/event/update.html:59 templates/organization/create.html:56
msgid "Admin unit"
msgstr "Verwaltungseinheit"
#: templates/admin_unit/update.html:43 templates/event/create.html:47
#: templates/event/update.html:47 templates/organization/create.html:44
#: templates/admin_unit/update.html:43 templates/event/create.html:62
#: templates/event/update.html:62 templates/organization/create.html:44
#: templates/organization/update.html:44 templates/place/create.html:44
#: templates/place/update.html:44
msgid "Additional information"
msgstr "Zusätzliche Informationen"
#: templates/event/create.html:50 templates/event/update.html:50
msgid "Target group"
msgstr "Zielgruppe"
#: templates/event/read.html:20
msgid "Mark event as unverified"
msgstr "Diese Veranstaltung als nicht verifiziert markieren"
@ -332,10 +545,6 @@ msgstr "Diese Veranstaltung als nicht verifiziert markieren"
msgid "Mark event as verified"
msgstr "Diese Veranstaltung als verifiziert markieren"
#: templates/event/read.html:31 templates/event/update.html:6
msgid "Update event"
msgstr "Veranstaltung aktualisieren"
#: templates/event_suggestion/list.html:17
#: templates/event_suggestion/read.html:86
msgid "Created at"
@ -345,70 +554,18 @@ msgstr "Erstellt am"
msgid "Event name"
msgstr "Name"
#: templates/event_suggestion/read.html:26
msgid "Description"
msgstr "Beschreibung"
#: templates/event_suggestion/read.html:30
msgid "Link URL"
msgstr "Link URL"
#: templates/event_suggestion/read.html:46
msgid "Event place"
msgstr "Veranstaltungsort"
#: templates/event_suggestion/read.html:50
msgid "Street"
msgstr "Straße"
#: templates/event_suggestion/read.html:54
msgid "Postal code"
msgstr "Postleitzahl"
#: templates/event_suggestion/read.html:58
msgid "City"
msgstr "Stadt/Ort"
#: templates/event_suggestion/read.html:69
msgid "Contact"
msgstr "Kontakt"
#: templates/event_suggestion/read.html:74
msgid "Event host"
msgstr "Veranstalter"
#: templates/event_suggestion/read.html:78
msgid "Contact name"
msgstr "Kontakt Name"
#: templates/event_suggestion/read.html:82
msgid "Contact email"
msgstr "Kontakt Email"
#: templates/organization/create.html:10 templates/organization/list.html:11
msgid "Create organization"
msgstr "Organisation hinzufügen"
#: templates/organization/create.html:16 templates/organization/update.html:16
msgid "Organization"
msgstr "Organisation"
#: templates/organization/read.html:12 templates/organization/update.html:10
msgid "Update organization"
msgstr "Organisation aktualisieren"
#: templates/organization/read.html:56
msgid "You are a member of this organization."
msgstr "Du bist Mitglied dieser Organisation"
#: templates/place/create.html:10 templates/place/list.html:11
msgid "Create place"
msgstr "Ort hinzufügen"
#: templates/place/read.html:12 templates/place/update.html:10
msgid "Update place"
msgstr "Ort aktualisieren"
#~ msgid "You"
#~ msgstr "Du"