diff --git a/poetry.lock b/poetry.lock index c8cfdcd94..9a17db4b9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1651,17 +1651,6 @@ files = [ {file = "sorl_thumbnail-12.10.0-py3-none-any.whl", hash = "sha256:733eb2eee392d4a874f88fb3ed6f0572fa9c361b06e0411b83e435ba69c51f52"}, ] -[[package]] -name = "sortedcontainers" -version = "2.4.0" -description = "Sorted Containers -- Sorted List, Sorted Dict, Sorted Set" -optional = false -python-versions = "*" -files = [ - {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, - {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, -] - [[package]] name = "sqlparse" version = "0.5.0" @@ -1861,4 +1850,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "~3.10.0" -content-hash = "9cc3edd81f19cae7b6b3111fad25d06943108f5483fd9b81734d9f4bced8251a" +content-hash = "da9e9f78cdefddcc430a60795a9be354aec21c9204b6e89834f4d98879740cf8" diff --git a/pyproject.toml b/pyproject.toml index 8ea6e44fa..94bea5ce8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,6 @@ psycopg2 = "2.9.9" pytz = "2024.1" requests = "2.31.0" sorl-thumbnail = "12.10.0" -sortedcontainers = "2.4.0" tabulate = "0.9.0" uwsgi = "2.0.24" Pillow = "10.3.0" diff --git a/src/core/context_processors.py b/src/core/context_processors.py index 8c69cf1ff..5ceb6e392 100644 --- a/src/core/context_processors.py +++ b/src/core/context_processors.py @@ -54,9 +54,5 @@ def sponsors(request): } -def events(request): - return {'schedule_redirect_url': settings.SCHEDULE_REDIRECT_URL} - - def frontend_host(request): return {'FRONTEND_HOST': settings.FRONTEND_HOST} diff --git a/src/core/tests/test_views.py b/src/core/tests/test_views.py index 16f148970..5e0be86db 100644 --- a/src/core/tests/test_views.py +++ b/src/core/tests/test_views.py @@ -2,11 +2,7 @@ import os import pytest -from django.conf import settings from django.utils.translation import activate -from pytest_django.asserts import assertRedirects - -from events.models import Schedule @pytest.mark.django_db @@ -97,14 +93,8 @@ def test_content_pages(client, parser, content_page_full_path): assert response.status_code == 200, content_page_full_path -@pytest.fixture -def schedule(db): - """Generate a schedule to prevent the schedule page from returning 404. - """ - return Schedule.objects.create(html='
') - - -def test_content_pages_links(client, parser, schedule, content_page_full_path): +@pytest.mark.django_db +def test_content_pages_links(client, parser, content_page_full_path): """Test to make sure all in-site links in a content page work. """ if '/surveys/conference/' in content_page_full_path: @@ -116,14 +106,6 @@ def test_content_pages_links(client, parser, schedule, content_page_full_path): link_status_codes = [] for tag in link_tags: link = tag.get('href') - if "/events/schedule/" in link \ - and settings.SCHEDULE_REDIRECT_URL: - assertRedirects( - client.get(link), - settings.SCHEDULE_REDIRECT_URL, - fetch_redirect_response=False - ) - continue try: status = client.get(link, follow=True).status_code except Exception: # Catch internal server error for better reporting. diff --git a/src/events/admin.py b/src/events/admin.py index f5ba89006..79e283794 100644 --- a/src/events/admin.py +++ b/src/events/admin.py @@ -23,7 +23,6 @@ KeynoteEvent, ProposedTalkEvent, ProposedTutorialEvent, - Schedule, SponsoredEvent, Time, ) @@ -208,10 +207,3 @@ class SponsoredEventAdmin(admin.ModelAdmin): search_fields = ['title', 'abstract'] prepopulated_fields = {'slug': ['title']} raw_id_fields = ['host'] - - -@admin.register(Schedule) -class ScheduleAdmin(admin.ModelAdmin): - fields = ['html', 'created_at'] - readonly_fields = ['created_at'] - list_display = ['created_at'] diff --git a/src/events/forms.py b/src/events/forms.py index 77e08f395..ab564e4ab 100644 --- a/src/events/forms.py +++ b/src/events/forms.py @@ -1,12 +1,6 @@ from django import forms -from .models import CustomEvent, Schedule - - -class ScheduleCreationForm(forms.ModelForm): - class Meta: - model = Schedule - fields = ['html'] +from .models import CustomEvent class CustomEventForm(forms.ModelForm): diff --git a/src/events/management/commands/import_events.py b/src/events/management/commands/import_events.py index 527d6288a..64dc26f24 100644 --- a/src/events/management/commands/import_events.py +++ b/src/events/management/commands/import_events.py @@ -7,11 +7,11 @@ from django.core.management.base import BaseCommand from django.utils.dateparse import parse_time -from events.models import Location, Time -from events.renderers import EVENT_CLASSES +from events.models import CustomEvent, KeynoteEvent, Location, ProposedTalkEvent, SponsoredEvent, Time cst = pytz.timezone('Asia/Taipei') +EVENT_CLASSES = (CustomEvent, KeynoteEvent, ProposedTalkEvent, SponsoredEvent) DAYS = list(settings.EVENTS_DAY_NAMES.keys()) diff --git a/src/events/migrations/0053_delete_schedule.py b/src/events/migrations/0053_delete_schedule.py new file mode 100644 index 000000000..9daf95bc2 --- /dev/null +++ b/src/events/migrations/0053_delete_schedule.py @@ -0,0 +1,16 @@ +# Generated by Django 3.2.25 on 2024-04-15 09:07 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('events', '0052_remove_sponsoredevent_prefer_time'), + ] + + operations = [ + migrations.DeleteModel( + name='Schedule', + ), + ] diff --git a/src/events/models.py b/src/events/models.py index d5b0229d4..01caaf93a 100644 --- a/src/events/models.py +++ b/src/events/models.py @@ -117,22 +117,6 @@ class Location: R4 = '7-r4' OTHER = '8-oth' - @classmethod - def get_md_width(cls, value): - return { - '2-all': 4, - '3-r012': 3, - '4-r0': 1, - '5-r1': 1, - '6-r2': 1, - '1-r3': 1, - '7-r4': 1, - '8-oth': 1, - }[value] - - -EVENT_ROOMS = {Location.R0, Location.R1, Location.R2, Location.R3, Location.R4} - class BaseEvent(ConferenceRelated): """Base interface for all events in the schedule. @@ -455,23 +439,3 @@ def get_absolute_url(self): return reverse('events_tutorial_detail', kwargs={ 'pk': self.proposal.pk, }) - - -class Schedule(ConferenceRelated): - - html = models.TextField( - verbose_name=_('HTML'), - ) - created_at = models.DateTimeField( - verbose_name=_('created at'), - auto_now_add=True, - ) - - class Meta: - verbose_name = _('Schedule') - verbose_name_plural = _('Schedules') - ordering = ['-created_at'] - get_latest_by = 'created_at' - - def __str__(self): - return gettext('Schedule created at {}').format(self.created_at) diff --git a/src/events/renderers.py b/src/events/renderers.py deleted file mode 100644 index f72cce981..000000000 --- a/src/events/renderers.py +++ /dev/null @@ -1,405 +0,0 @@ -import itertools - -import sortedcontainers -from django.conf import settings -from django.utils.html import format_html, format_html_join -from django.utils.safestring import mark_safe -from django.utils.timezone import make_naive -from django.utils.translation import gettext -from django.utils.translation import gettext_lazy as _ - -from core.utils import html_join -from events.models import ( - CustomEvent, - KeynoteEvent, - Location, - ProposedTalkEvent, - SponsoredEvent, -) -from proposals.utils import format_names - - -def render_customevent(e): - return format_html( - '
' - '
{title}
' - '
', - title=e.title, - ) - - -def render_keynoteevent(e): - return format_html( - '
' - '
{title}
' - '{speaker}' - '
', - title=gettext('Keynote'), - link=e.get_absolute_url(), - speaker=e.speaker_name, - ) - - -LANG_DISPLAY_MAP = { - 'ENEN': 'EN', - 'ZHZH': 'ZH', - 'ZHEN': _('EN Slides'), - 'TAI': 'TAI', -} - - -def render_proposedtalkevent(e): - proposal = e.proposal - speaker_names = [info.user.speaker_name for info in proposal.speakers] - return format_html( - '
' - '{title}' - '{speakers}' - '
{lang}
' - '
', - link=e.get_absolute_url(), - title=proposal.title, - speakers=format_names(speaker_names), - lang=LANG_DISPLAY_MAP[proposal.language], - ) - - -def render_sponsoredevent(e): - return format_html( - '', - link=e.get_absolute_url(), - title=e.title, - speaker=e.host.speaker_name, - lang=LANG_DISPLAY_MAP[e.language], - ) - - -def render_event(e): - func_name = f'render_{type(e).__name__.lower()}' - try: - func = globals()[func_name] - except KeyError as err: - raise ValueError( - f'No suitable renderer for {e!r} of {type(e)!r}', - ) from err - return func(e) - - -def render_block_location(location): - return format_html( - '
' - '{display}
', - key=location.split('-', 1)[-1], - display={ - Location.ALL: '', - Location.R012: 'R0 R1 R2', - Location.R0: 'R0', - Location.R1: 'R1', - Location.R2: 'R2', - Location.R3: 'R3', - Location.R4: 'R4', - }.get(location), - ) - - -def _has_tall_event(events): - return any( - isinstance(e, ProposedTalkEvent) or isinstance(e, SponsoredEvent) - for e in events - ) - - -def render_block( - event, time_map, events, extra_classes=None, *, - min_height=0, max_height=None): - location = event.location - height = time_map[event.end_time] - time_map[event.begin_time] - if max_height is not None: - height = min(height, max_height) - if height == 1 and min_height < 1 and not _has_tall_event(events): - height = 'small' - return format_html( - '
' - '{location}{event}
', - w=Location.get_md_width(location), - h=height, - location=render_block_location(location), - event=render_event(event), - classes=(' ' + ' '.join(extra_classes) if extra_classes else ''), - ) - - -def render_attached_period(begin, end): - begin = make_naive(begin.value) - end = make_naive(end.value) - return format_html( - '
' - '{begin_h}:{begin_m} – {end_h}:{end_m}
', - begin_h=begin.hour, begin_m=begin.strftime(r'%M'), - end_h=end.hour, end_m=end.strftime(r'%M'), - ) - - -def _render_blocks(events, time_map): - """Render a R0-3 belt, a R0-2 partial belt (plus optionally a R3 event), - or an all-block (with or without R3) format. - """ - if events[0].location == Location.R3: - # If this contains R3, shuffle it to the back. - r3_event, *events = events - - # If this is not a smooth row, we need to prevent any block from - # being rendered as short because we can't handle it with multi-height. - if any(r3_event.end_time != e.end_time for e in events): - min_height = 1 - else: - min_height = 0 - r3_block = render_block( - r3_event, time_map, events, min_height=min_height, - ) - else: - r3_event = None - r3_block = '' - - # Render period block for R3. - # We cheat a little here: Times in R0-2 are supposed to be identical; - # only R3 can be different. We just compare the first event's times - # and R3's. If they are identical, R3 does not need its own period block, - # otherwise it does. - r3_period = '' - rx_begin, rx_end = events[0].begin_time, events[0].end_time - if r3_event: - r3_begin = r3_event.begin_time - r3_end = r3_event.end_time - if r3_begin != rx_begin or r3_end != rx_end: - r3_period = render_attached_period(r3_begin, r3_end) - - return format_html( - '{r012_period}{r012_blocks}{r3_period}{r3_block}', - r012_period=render_attached_period(rx_begin, rx_end), - r012_blocks=html_join( - '', - (render_block(e, time_map, events) for e in events), - ), - r3_period=r3_period, - r3_block=r3_block, - ) - - -def _render_multirow_subrow(event_iter, time_map, events): - # Render period block for this row, and the first event. - e0 = next(event_iter) - cells = [ - render_attached_period(e0.begin_time, e0.end_time), - render_block(e0, time_map, events) - ] - cols = Location.get_md_width(e0.location) - - # Keep rendering until we fill a row. - while cols < 3: - try: - e = next(event_iter) - except StopIteration: - break - cells.append(render_block(e, time_map, events)) - cols += Location.get_md_width(e.location) - return cells - - -def _render_multirow(events, time_map, max_height): - """Render a complex format that contains a multi-row R3 event. - """ - sp_event, *events = events - # Sort events by time, and then location. This is done here because - # we need to exclude the R3 event (by putting it first). - events = sorted(events, key=lambda e: (e.begin_time.value, e.location)) - event_iter = iter(events) - - # Render R0-R2 events in the first time period. - cells = _render_multirow_subrow(event_iter, time_map, events) - - # Render the multi-row R3 event. - cells.extend([ - render_attached_period(sp_event.begin_time, sp_event.end_time), - render_block( - sp_event, time_map, events, ['pull-right'], - max_height=max_height, - ), - ]) - - # Render the rest of the events. - try: - while True: - cells += _render_multirow_subrow(event_iter, time_map, events) - except StopIteration: - pass - - # Join the results. - return html_join('', cells) - - -def render_columned_period(times, events): - cell_args = [ - _get_column_period_args(begin, end) - for begin, end in zip(times[:-1], times[1:]) - if any(e.end_time == end for e in events) - ] - cells = format_html_join( - '', - '
{}:{}
|
{}:{}
', - iter(cell_args), - ) - height = len(cell_args) - if height == 1 and not _has_tall_event(events): - height = 'small' - html = format_html( - '
{cells}
', - height=height, - cells=cells, - ) - return html, height - - -def _get_column_period_args(begin_time, end_time): - begin_naive = make_naive(begin_time.value) - end_naive = make_naive(end_time.value) - return ( - begin_naive.hour, - begin_naive.strftime('%M'), - end_naive.hour, - end_naive.strftime('%M'), - ) - - -def render_row(times, events): - events = sorted(events, key=lambda e: e.location) - times = sorted(times) - time_map = {t: i for i, t in enumerate(times)} - - period_block, max_height = render_columned_period(times, events) - try: - sp_event = events[0] - except IndexError: # No events in this time period. - content = '' - else: - if (sp_event.location != Location.R3 or sp_event.end_time <= times[1]): - # If there's no R3 event, or if R3 event is not multi-row. - content = _render_blocks(events, time_map) - else: - # If there is a multi-row R3 event. - content = _render_multirow(events, time_map, max_height) - return format_html( - '{period}' - '
{content}
', - period=period_block, - content=content, - ) - - -# This is made global so that we can easily test for equality. -def group_key(e): - return e.location - - -def make_group(*events): - return sortedcontainers.SortedListWithKey(events, key=group_key) - - -def collect_event_groups(events): - # Map of (sorted-tuple-of-times): [list-of-events]. - # This automatically sorts the keys by ``begin_time``. - groups = sortedcontainers.SortedDict() - - for e in events: - - e_begin_time = e.begin_time - e_end_time = e.end_time - - # Short circuit: If there's an identical group, just join it. - if (e_begin_time, e_end_time) in groups: - groups[(e_begin_time, e_end_time)].add(e) - continue - - # Look for a suitable group. - for key in groups.keys(): - begin_time, *_, end_time = key - if ((begin_time <= e_begin_time and end_time >= e_end_time) or - (e_begin_time <= begin_time and e_end_time >= end_time)): - # Either key can contain event, or event can contain key. - events = groups.pop(key) - events.add(e) - times = sorted(set(key) | {e_begin_time, e_end_time}) - groups[tuple(times)] = events - break - else: - # No suitable group. Let's make a new one. - # This automatically sorts the items by location. - groups[(e_begin_time, e_end_time)] = make_group(e) - - return groups - - -EVENT_CLASSES = (CustomEvent, KeynoteEvent, ProposedTalkEvent, SponsoredEvent) - - -def _filter_events(kls, day): - return ( - kls.objects - .filter(begin_time__value__date=day, end_time__value__date=day) - .select_related('begin_time', 'end_time') - ) - - -def render_table(day): - events = itertools.chain.from_iterable( - _filter_events(Cls, day) - for Cls in EVENT_CLASSES - ) - groups = collect_event_groups(events) - - head = mark_safe(""" -
-
-
-
-
R0
-
R1
-
R2
-
R3
-
-
-
- """) - body = html_join('', ( - render_row(times, group) for times, group in groups.items() - )) - return format_html( - '
{head}{body}
', - head=head, body=body, - ) - - -def render_day(day, display): - events = list(itertools.chain.from_iterable( - _filter_events(Cls, day) - for Cls in EVENT_CLASSES - )) - if not events: - return '' - return format_html( - '

{display}

{table}', - slug=day.strftime(r'%Y-%m-%d'), - display=display, table=render_table(day), - ) - - -def render_all(): - return html_join('', ( - render_day(day, display) - for day, display in settings.EVENTS_DAY_NAMES.items() - )) diff --git a/src/events/templatetags/events.py b/src/events/templatetags/events.py index f8d2919a5..3ba31e503 100644 --- a/src/events/templatetags/events.py +++ b/src/events/templatetags/events.py @@ -1,161 +1,12 @@ -from datetime import datetime, timedelta -from math import floor - from django.conf import settings from django.template import Library -from django.template.loader import get_template -from django.utils import translation -from django.utils.translation import gettext_lazy as _ -from events.models import KeynoteEvent, Location -from proposals.utils import format_names +from events.models import KeynoteEvent from sponsors.models import OpenRole, Sponsor -LOCATION_DISPLAY_DICT = { - Location.R0: _('R1'), - Location.R1: _('R2'), - Location.R2: _('R3'), - Location.R3: _('Multifunction room'), - Location.R4: _('Goodideas Studio'), - Location.R012: _('R1, R2, R3'), - Location.OTHER: _('Other'), -} -ROW_UNIT = 5 * 60 # in seconds -MARKER_UNIT = 30 * 60 # in seconds - register = Library() -@register.simple_tag -def calc_grid_row(begin, end, timeline_start='08:30'): - d_format = '%H:%M' - start_point = datetime.strptime(timeline_start, d_format) - - def get_row(t): - diff = datetime.strptime(t, d_format) - start_point - return int(diff.seconds / ROW_UNIT) + 1 - - start_row = get_row(begin) - end_row = get_row(end) - return {'start_row': start_row, 'end_row': end_row} - - -@register.filter -def gen_timeline(start, end): - timeline = [{'time': start, 'row_start': 1, 'row_end': 6}] - d_format = '%H:%M' - - time_start = datetime.strptime(start, d_format) - time_end = datetime.strptime(end, d_format) - ticks_count = floor((time_end - time_start).seconds / MARKER_UNIT) - - scale_unit_multiplier = int(MARKER_UNIT / ROW_UNIT) # 6 (magic number) - time_next = time_start - row_start_next = 1 - row_end_next = 6 - for __ in range(ticks_count): - time_next += timedelta(seconds=MARKER_UNIT) - row_start_next += scale_unit_multiplier - row_end_next += scale_unit_multiplier - t = datetime.strftime(time_next, d_format) - c = '--hour' if t.endswith('00') else '--half-an-hour' - timeline.append({ - 'time': t, - 'row_start': row_start_next, - 'row_end': row_end_next, - 'class': c - }) - - return timeline - - -@register.filter -def event_cell_class(event): - event_class = { - 'events.customevent': 'custom', - 'events.keynoteevent': 'keynote', - 'events.proposedtalkevent': 'talk', - 'events.proposedtutorialevent': 'tutorial', - 'events.sponsoredevent': 'talk', - }[event._meta.label_lower] - classes = [event_class] - if getattr(event, 'break_event', False): - classes.append('is-break') - return ' '.join(classes) - - -@register.filter -def event_tr_class(slot_info): - for __, event in slot_info: - if event._meta.label_lower == 'events.customevent': - return 'custom' - return '' - - -@register.filter -def room_display(value): - return LOCATION_DISPLAY_DICT.get(value, '') - - -def get_custom_event_display(event): - template = get_template('events/_includes/schedule_custom_event.html') - return template.render({'event': event}) - - -def get_keynote_event_display(event): - template = get_template('events/_includes/schedule_keynote_event.html') - return template.render({'event': event, 'is_remote': event.is_remote}) - - -def _render_talk_event_template(event, info, speaker_names, sponsored, is_remote=False): - template = get_template('events/_includes/schedule_talk_event.html') - return template.render({ - 'event': event, 'info': info, 'sponsored': sponsored, - 'speakers': format_names(speaker_names), 'is_remote': is_remote, - }) - - -def get_talk_event_display(event): - proposal = event.proposal - speaker_names = [proposal.submitter.speaker_name] - if getattr(event, '_additional_speaker_count', 1): - speaker_names.extend( - proposal.additionalspeaker_set - .values_list('user__speaker_name', flat=True), - ) - return _render_talk_event_template(event, proposal, speaker_names, False, event.is_remote) - - -def get_tutorial_event_display(event): - proposal = event.proposal - speaker_names = [proposal.submitter.speaker_name] - if getattr(event, '_additional_speaker_count', 1): - speaker_names.extend( - proposal.additionalspeaker_set - .values_list('user__speaker_name', flat=True), - ) - return _render_talk_event_template(event, proposal, speaker_names, False, event.is_remote) - - -def get_sponsored_event_display(event): - return _render_talk_event_template( - event, event, [event.host.speaker_name], True, - ) - - -@register.filter -def event_display(event): - with translation.override('en-us'): - f = { - 'events.customevent': get_custom_event_display, - 'events.keynoteevent': get_keynote_event_display, - 'events.proposedtalkevent': get_talk_event_display, - 'events.proposedtutorialevent': get_tutorial_event_display, - 'events.sponsoredevent': get_sponsored_event_display, - }[event._meta.label_lower] - return f(event) - - @register.filter def event_date_display(event): try: diff --git a/src/events/tests/renderers/__init__.py b/src/events/tests/renderers/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/events/tests/renderers/conftest.py b/src/events/tests/renderers/conftest.py deleted file mode 100644 index c097f6fe6..000000000 --- a/src/events/tests/renderers/conftest.py +++ /dev/null @@ -1,329 +0,0 @@ -import datetime - -import pytest -import pytz - -from events.models import ( - CustomEvent, - KeynoteEvent, - Location, - ProposedTalkEvent, - Time, -) -from proposals.models import AdditionalSpeaker - -cst = pytz.timezone('Asia/Taipei') - - -class RendererTestUtils: - @staticmethod - def is_safe(s): - """Check whether a string is safe. - - This is Django's internal API, but we exploit it for easy testing. - """ - return not s or hasattr(s, '__html__') - - -@pytest.fixture -def utils(): - return RendererTestUtils - - -@pytest.fixture -def keynote_belt_event(db, get_time): - return KeynoteEvent.objects.create( - speaker_name='Amber Brown', - slug='amber-brown', - begin_time=get_time('2016-06-05 9:00'), - end_time=get_time('2016-06-05 10:00'), - location=Location.ALL, - ) - - -@pytest.fixture -def custom_partial_belt_event(db, get_time): - return CustomEvent.objects.create( - title='Job Fair', - begin_time=get_time('2016-06-04 14:45'), - end_time=get_time('2016-06-04 15:15'), - location=Location.R012, - ) - - -@pytest.fixture -def proposed_talk_block_event(accepted_talk_proposal, another_user, get_time): - e = ProposedTalkEvent.objects.create( - proposal=accepted_talk_proposal, - begin_time=get_time('2016-06-03 16:00'), - end_time=get_time('2016-06-03 16:45'), - location=Location.R0, - ) - AdditionalSpeaker.objects.create( - user=another_user, proposal=accepted_talk_proposal, - ) - return e - - -@pytest.fixture -def events( - custom_partial_belt_event, keynote_belt_event, - proposed_talk_block_event, sponsored_block_event): - return { - 'custom_event': custom_partial_belt_event, - 'keynote_event': keynote_belt_event, - 'proposed_talk_event': proposed_talk_block_event, - 'sponsored_event': sponsored_block_event, - } - - -@pytest.fixture -def day(): - return datetime.date(2016, 8, 19) - - -@pytest.fixture -def make_time(day): - - def _make_time(h, m=0): - dt = datetime.datetime.combine(day, datetime.time(h, m)) - return Time(value=cst.localize(dt)) - - return _make_time - - -@pytest.fixture -def belt_begin_time(make_time): - return make_time(15) - - -@pytest.fixture -def belt_end_time(make_time): - return make_time(16) - - -@pytest.fixture -def belt_event(belt_begin_time, belt_end_time): - return KeynoteEvent( - speaker_name='Amber Brown', - slug='amber-brown', - begin_time=belt_begin_time, - end_time=belt_end_time, - ) - - -@pytest.fixture -def partial_belt_begin_time(make_time): - return make_time(1) - - -@pytest.fixture -def partial_belt_end_time(make_time): - return make_time(2) - - -@pytest.fixture -def partial_belt_events(partial_belt_begin_time, partial_belt_end_time): - event = CustomEvent( - title='Refreshment', - location=Location.R012, - begin_time=partial_belt_begin_time, - end_time=partial_belt_end_time, - ) - return [event] - - -@pytest.fixture -def partial_belt_block_begin_time(make_time): - return make_time(3) - - -@pytest.fixture -def partial_belt_block_end_time(make_time): - return make_time(4) - - -@pytest.fixture -def partial_belt_block_events( - partial_belt_block_begin_time, partial_belt_block_end_time): - events = [ - CustomEvent( - title='Refreshment', - location=Location.R012, - begin_time=partial_belt_block_begin_time, - end_time=partial_belt_block_end_time, - ), - CustomEvent( - title='Free-market sub-orbital tattoo', - location=Location.R3, - begin_time=partial_belt_block_begin_time, - end_time=partial_belt_block_end_time, - ), - ] - return events - - -@pytest.fixture -def partial_block_begin_time(make_time): - return make_time(5) - - -@pytest.fixture -def partial_block_end_time(make_time): - return make_time(6) - - -@pytest.fixture -def partial_block_events(partial_block_begin_time, partial_block_end_time): - events = [ - CustomEvent( - title='Boost Maintainability', - location=Location.R0, - begin_time=partial_block_begin_time, - end_time=partial_block_end_time, - ), - CustomEvent( - title='We Made the PyCon TW 2016 Website', - location=Location.R1, - begin_time=partial_block_begin_time, - end_time=partial_block_end_time, - ), - CustomEvent( - title='Deep Learning and Application in Python', - location=Location.R2, - begin_time=partial_block_begin_time, - end_time=partial_block_end_time, - ), - ] - return events - - -@pytest.fixture -def block_begin_time(make_time): - return make_time(7) - - -@pytest.fixture -def block_end_time(make_time): - return make_time(8) - - -@pytest.fixture -def block_events(block_begin_time, block_end_time): - events = [ - CustomEvent( - title='Boost Maintainability', - location=Location.R0, - begin_time=block_begin_time, - end_time=block_end_time, - ), - CustomEvent( - title='We Made the PyCon TW 2016 Website', - location=Location.R1, - begin_time=block_begin_time, - end_time=block_end_time, - ), - CustomEvent( - title='Deep Learning and Application in Python', - location=Location.R2, - begin_time=block_begin_time, - end_time=block_end_time, - ), - CustomEvent( - title='Free-market sub-orbital tattoo', - location=Location.R3, - begin_time=block_begin_time, - end_time=block_end_time, - ), - ] - return events - - -@pytest.fixture -def mismatch_block_begin_time(make_time): - return make_time(9) - - -@pytest.fixture -def mismatch_block_mid_time(make_time): - return make_time(10) - - -@pytest.fixture -def mismatch_block_end_time(make_time): - return make_time(11) - - -@pytest.fixture -def mismatch_block_events( - mismatch_block_begin_time, mismatch_block_mid_time, - mismatch_block_end_time): - events = [ - CustomEvent( - title='Refreshment', - location=Location.R012, - begin_time=mismatch_block_begin_time, - end_time=mismatch_block_end_time, - ), - CustomEvent( - title='Free-market sub-orbital tattoo', - location=Location.R3, - begin_time=mismatch_block_begin_time, - end_time=mismatch_block_mid_time, - ), - ] - return events - - -@pytest.fixture -def multirow_block_begin_time(make_time): - return make_time(12) - - -@pytest.fixture -def multirow_block_mid_time(make_time): - return make_time(13) - - -@pytest.fixture -def multirow_block_end_time(make_time): - return make_time(14) - - -@pytest.fixture -def multirow_block_events( - multirow_block_begin_time, multirow_block_mid_time, - multirow_block_end_time): - events = [ - CustomEvent( - title='Boost Maintainability', - location=Location.R0, - begin_time=multirow_block_begin_time, - end_time=multirow_block_mid_time, - ), - CustomEvent( - title='We Made the PyCon TW 2016 Website', - location=Location.R1, - begin_time=multirow_block_begin_time, - end_time=multirow_block_mid_time, - ), - CustomEvent( - title='Deep Learning and Application in Python', - location=Location.R2, - begin_time=multirow_block_begin_time, - end_time=multirow_block_mid_time, - ), - CustomEvent( - title='Free-market sub-orbital tattoo', - location=Location.R3, - begin_time=multirow_block_begin_time, - end_time=multirow_block_end_time, - ), - CustomEvent( - title='Refreshment', - location=Location.R012, - begin_time=multirow_block_mid_time, - end_time=multirow_block_end_time, - ), - ] - return events diff --git a/src/events/tests/renderers/test_collect.py b/src/events/tests/renderers/test_collect.py deleted file mode 100644 index cda922946..000000000 --- a/src/events/tests/renderers/test_collect.py +++ /dev/null @@ -1,37 +0,0 @@ -import itertools - -import pytest -import sortedcontainers - -from events import renderers -from events.renderers import make_group - - -@pytest.fixture -def events( - belt_event, partial_belt_events, partial_belt_block_events, - partial_block_events, block_events, mismatch_block_events, - multirow_block_events): - return itertools.chain( - [belt_event], partial_belt_events, partial_belt_block_events, - partial_block_events, block_events, mismatch_block_events, - multirow_block_events, - ) - - -def test_collect_event_groups( - belt_event, partial_belt_events, partial_belt_block_events, - partial_block_events, block_events, mismatch_block_events, - multirow_block_events, make_time, events): - groups = renderers.collect_event_groups(events) - assert groups == sortedcontainers.SortedDict({ - (make_time(1), make_time(2)): make_group(*partial_belt_events), - (make_time(3), make_time(4)): make_group(*partial_belt_block_events), - (make_time(5), make_time(6)): make_group(*partial_block_events), - (make_time(7), make_time(8)): make_group(*block_events), - (make_time(9), make_time(10), make_time(11)): make_group( - *mismatch_block_events), - (make_time(12), make_time(13), make_time(14)): make_group( - *multirow_block_events), - (make_time(15), make_time(16)): make_group(belt_event), - }) diff --git a/src/events/tests/renderers/test_render_block.py b/src/events/tests/renderers/test_render_block.py deleted file mode 100644 index cfbacccdd..000000000 --- a/src/events/tests/renderers/test_render_block.py +++ /dev/null @@ -1,150 +0,0 @@ -import pytest - -from events import renderers -from events.models import CustomEvent, Location - - -@pytest.fixture -def simple_component_renderer(mocker): - mocker.patch.multiple( - 'events.renderers', - render_event=str, - render_block_location=lambda v: f'{v} ', - ) - - -@pytest.fixture -def time_map(events): - times = set() - for e in events.values(): - times.add(e.begin_time) - times.add(e.end_time) - return {time: i for i, time in enumerate(sorted(times))} - - -# Hack to get all possible location values by introspection. -POSSIBLE_LOCATIONS = sorted( - getattr(Location, k) - for k in Location.__dict__ if k.isupper() and k != 'OTHER' -) - - -@pytest.mark.parametrize('location', POSSIBLE_LOCATIONS) -def test_render_block_location(parser, utils, location): - rendered = renderers.render_block_location(location) - assert utils.is_safe(rendered) - - expected = { - Location.ALL: ( - '
' - ), - Location.R012: ( - '
' - 'R0 R1 R2
' - ), - Location.R0: ( - '
' - 'R0
' - ), - Location.R1: ( - '
' - 'R1
' - ), - Location.R2: ( - '
' - 'R2
' - ), - Location.R3: ( - '
' - 'R3
' - ), - Location.R4: ( - '
' - 'R4
' - ), - }.get(location) - if expected: - assert parser.arrange(rendered) == parser.arrange(expected) - - -@pytest.mark.parametrize('event_key', [ - 'custom_event', 'keynote_event', 'proposed_talk_event', 'sponsored_event', -]) -@pytest.mark.usefixtures('simple_component_renderer') -def test_render_block(parser, utils, time_map, events, event_key): - e = events[event_key] - rendered = renderers.render_block(e, time_map, [e]) - assert utils.is_safe(rendered) - - expected = { - 'custom_event': """ -
- 3-r012 Job Fair -
""", - 'keynote_event': """ -
- 2-all Keynote: Amber Brown -
""", - 'proposed_talk_event': """ -
- 4-r0 Beyond the Style Guides<br> -
""", - 'sponsored_event': """ -
- 6-r2 Camera engine office woman lights -
""", - }[event_key] - assert parser.arrange(rendered) == parser.arrange(expected) - - -@pytest.mark.parametrize('event_key,begin,end', [ - ('custom_event', '14:45', '15:15'), - ('keynote_event', '9:00', '10:00'), - ('proposed_talk_event', '16:00', '16:45'), - ('sponsored_event', '11:00', '11:25'), -]) -def test_render_attached_period(utils, events, event_key, begin, end): - e = events[event_key] - rendered = renderers.render_attached_period(e.begin_time, e.end_time) - assert utils.is_safe(rendered) - assert rendered == ( - f'
{begin} – {end}
' - ) - - -@pytest.mark.parametrize('time_count', [2, 3, 4]) -def test_render_columned_period(parser, utils, make_time, time_count): - times = [make_time(h) for h in range(time_count)] - rendered, _ = renderers.render_columned_period(times, [ - CustomEvent( - title='M<3', location=Location.ALL, - begin_time=begin_time, end_time=end_time, - ) - for begin_time, end_time in zip(times[:-1], times[1:]) - ]) - assert utils.is_safe(rendered) - - expected = { - 2: ( - '
' - '
0:00
|
1:00
' - '
' - ), - 3: ( - '
' - '
0:00
|
1:00
' - '
1:00
|
2:00
' - '
' - ), - 4: ( - '
' - '
0:00
|
1:00
' - '
1:00
|
2:00
' - '
2:00
|
3:00
' - '
' - ), - }[time_count] - assert parser.arrange(rendered) == parser.arrange(expected) diff --git a/src/events/tests/renderers/test_render_row.py b/src/events/tests/renderers/test_render_row.py deleted file mode 100644 index d3fcc5ea1..000000000 --- a/src/events/tests/renderers/test_render_row.py +++ /dev/null @@ -1,183 +0,0 @@ -import pytest -from django.utils.timezone import make_naive - -from events import renderers - - -@pytest.fixture -def simple_renderer(mocker): - - def _simple_block_renderer( - event, time_map, events, extra_classes=None, *, - min_height=0, max_height=None): - if extra_classes: - fmt = '|{event} ({classes})| ' - else: - fmt = '|{event}| ' - return fmt.format(classes=' '.join(extra_classes or []), event=event) - - def _simple_attached_period_renderer(begin, end): - return '|{0.hour}:{0:%M} {1.hour}:{1:%M}| '.format( - make_naive(begin.value), make_naive(end.value), - ) - - def _simple_columned_period_renderer(times, events): - html = '|{}| '.format( - ' '.join( - '{0.hour}:{0:%M}'.format(make_naive(time.value)) - for time in times - ) - ) - return html, len(events) - - mocker.patch.multiple( - 'events.renderers', - render_block=_simple_block_renderer, - render_attached_period=_simple_attached_period_renderer, - render_columned_period=_simple_columned_period_renderer, - ) - - -@pytest.mark.usefixtures('simple_renderer') -def test_render_belt_events_row(parser, utils, keynote_belt_event): - times = [keynote_belt_event.begin_time, keynote_belt_event.end_time] - rendered = renderers.render_row(times, [keynote_belt_event]) - assert utils.is_safe(rendered) - assert parser.arrange(rendered) == parser.arrange(""" - |9:00 10:00| -
-
- |9:00 10:00| - |Keynote: Amber Brown| -
-
- """) - - -@pytest.mark.usefixtures('simple_renderer') -def test_render_partial_belt_events_row( - parser, utils, - partial_belt_begin_time, partial_belt_end_time, partial_belt_events): - times = [partial_belt_begin_time, partial_belt_end_time] - rendered = renderers.render_row(times, partial_belt_events) - assert utils.is_safe(rendered) - assert parser.arrange(rendered) == parser.arrange(""" - |1:00 2:00| -
-
- |1:00 2:00| - |Refreshment| -
-
- """) - - -@pytest.mark.usefixtures('simple_renderer') -def test_render_partial_belt_block_events_row( - parser, utils, partial_belt_block_begin_time, - partial_belt_block_end_time, partial_belt_block_events): - times = [partial_belt_block_begin_time, partial_belt_block_end_time] - rendered = renderers.render_row(times, partial_belt_block_events) - assert utils.is_safe(rendered) - assert parser.arrange(rendered) == parser.arrange(""" - |3:00 4:00| -
-
- |3:00 4:00| - |Refreshment| - |Free-market sub-orbital tattoo| -
-
- """) - - -@pytest.mark.usefixtures('simple_renderer') -def test_render_partial_block_events_row( - parser, utils, partial_block_begin_time, - partial_block_end_time, partial_block_events): - times = [partial_block_begin_time, partial_block_end_time] - rendered = renderers.render_row(times, partial_block_events) - assert utils.is_safe(rendered) - assert parser.arrange(rendered) == parser.arrange(""" - |5:00 6:00| -
-
- |5:00 6:00| - |Boost Maintainability| - |We Made the PyCon TW 2016 Website| - |Deep Learning and Application in Python| -
-
- """) - - -@pytest.mark.usefixtures('simple_renderer') -def test_render_block_events_row( - parser, utils, block_begin_time, block_end_time, block_events): - times = [block_begin_time, block_end_time] - rendered = renderers.render_row(times, block_events) - assert utils.is_safe(rendered) - assert parser.arrange(rendered) == parser.arrange(""" - |7:00 8:00| -
-
- |7:00 8:00| - |Boost Maintainability| - |We Made the PyCon TW 2016 Website| - |Deep Learning and Application in Python| - |Free-market sub-orbital tattoo| -
-
- """) - - -@pytest.mark.usefixtures('simple_renderer') -def test_render_mismatch_block_events_row( - parser, utils, mismatch_block_begin_time, mismatch_block_mid_time, - mismatch_block_end_time, mismatch_block_events): - times = [ - mismatch_block_begin_time, - mismatch_block_mid_time, - mismatch_block_end_time, - ] - rendered = renderers.render_row(times, mismatch_block_events) - assert utils.is_safe(rendered) - assert parser.arrange(rendered) == parser.arrange(""" - |9:00 10:00 11:00| -
-
- |9:00 11:00| - |Refreshment| - |9:00 10:00| - |Free-market sub-orbital tattoo| -
-
- """) - - -@pytest.mark.usefixtures('simple_renderer') -def test_render_multirow_block_events_row( - parser, utils, multirow_block_begin_time, multirow_block_mid_time, - multirow_block_end_time, multirow_block_events): - times = [ - multirow_block_begin_time, - multirow_block_mid_time, - multirow_block_end_time, - ] - rendered = renderers.render_row(times, multirow_block_events) - assert utils.is_safe(rendered) - assert parser.arrange(rendered) == parser.arrange(""" - |12:00 13:00 14:00| -
-
- |12:00 13:00| - |Boost Maintainability| - |We Made the PyCon TW 2016 Website| - |Deep Learning and Application in Python| - |12:00 14:00| - |Free-market sub-orbital tattoo (pull-right)| - |13:00 14:00| - |Refreshment| -
-
- """) diff --git a/src/events/urls.py b/src/events/urls.py index a32dbdee2..4c112d9d3 100644 --- a/src/events/urls.py +++ b/src/events/urls.py @@ -4,10 +4,6 @@ from events import views urlpatterns = [ - url(r'^schedule/$', views.ScheduleView.as_view(), name='events_schedule'), - url(r'^schedule/new/$', views.ScheduleCreateView.as_view()), - - url(r'^talks/$', views.TalkListView.as_view(), name='events_talk_list'), url(r'^tutorials/$', views.TutorialListView.as_view(), diff --git a/src/events/views.py b/src/events/views.py index dc4f5ed7a..9604dfbf7 100644 --- a/src/events/views.py +++ b/src/events/views.py @@ -1,33 +1,12 @@ -import collections -import itertools import logging -from django.conf import settings -from django.contrib.auth.mixins import PermissionRequiredMixin from django.db.models import Count, Prefetch -from django.http import HttpResponseNotFound, HttpResponseRedirect -from django.urls import reverse -from django.utils import translation -from django.utils.translation import gettext_lazy as _ -from django.views.generic import CreateView, DetailView, ListView, TemplateView +from django.views.generic import DetailView, ListView -from core.mixins import FormValidMessageMixin from core.utils import OrderedDefaultDict, TemplateExistanceStatusResponse from proposals.models import AdditionalSpeaker, TalkProposal, TutorialProposal -from .forms import ScheduleCreationForm -from .models import ( - EVENT_ROOMS, - CustomEvent, - KeynoteEvent, - Location, - ProposedTalkEvent, - ProposedTutorialEvent, - Schedule, - SponsoredEvent, - Time, -) -from .renderers import render_all +from .models import ProposedTalkEvent, ProposedTutorialEvent, SponsoredEvent logger = logging.getLogger(__name__) @@ -96,143 +75,6 @@ def get_queryset(self): return qs -class ScheduleView(TemplateView): - template_name = 'events/schedule.html' - response_class = TemplateExistanceStatusResponse - - def get(self, request, *args, **kwargs): - try: - self.schedule = Schedule.objects.latest() - except Schedule.DoesNotExist: - redirect_url = settings.SCHEDULE_REDIRECT_URL - if not redirect_url: - return HttpResponseNotFound() - return HttpResponseRedirect(redirect_url) - return super().get(request, *args, **kwargs) - - def get_context_data(self, **kwargs): - return super().get_context_data( - schedule_html=self.schedule.html, - schedule_days=collections.OrderedDict([ - (key, {'name': value}) - for key, value in settings.EVENTS_DAY_NAMES.items() - ]), - **kwargs - ) - - -class ScheduleCreateMixin: - form_class = ScheduleCreationForm - form_valid_message = _('New talk schedule generated successfully.') - permission_required = ['events.add_schedule'] - template_name = 'events/schedule_create.html' - response_class = TemplateExistanceStatusResponse - - def get_success_url(self): - return reverse('events_schedule') - - -class ScheduleCreate2016View( - ScheduleCreateMixin, FormValidMessageMixin, PermissionRequiredMixin, CreateView -): - def get_context_data(self, **kwargs): - return super().get_context_data(content=render_all(), **kwargs) - - -def _room_sort_key(room): - return room.split('-', 1)[-1] - - -class ScheduleCreateView( - ScheduleCreateMixin, FormValidMessageMixin, PermissionRequiredMixin, CreateView -): - event_querysets = [ - CustomEvent.objects.all().exclude(location=Location.OTHER), - KeynoteEvent.objects.all().exclude(location=Location.OTHER), - ( - ProposedTalkEvent.objects - .select_related('proposal__submitter') - .annotate(_additional_speaker_count=Count( - 'proposal__additionalspeaker_set', - )).exclude(location=Location.OTHER) - ), - SponsoredEvent.objects.select_related('host').exclude(location=Location.OTHER), - ( - ProposedTutorialEvent.objects - .select_related('proposal__submitter') - .annotate(_additional_speaker_count=Count( - 'proposal__additionalspeaker_set', - )).exclude(location=Location.OTHER) - ), - ] - - def get_day_grouped_events(self): - begin_time_event_dict = collections.defaultdict(set) - for qs in self.event_querysets: - for event in qs.select_related('begin_time', 'end_time'): - begin_time_event_dict[event.begin_time].add(event) - - day_info_dict = collections.OrderedDict( - (date, { - 'name': name, - 'rooms': set(), - 'slots': {}, - 'slots_mobile': {}, - 'timeline': {}, - }) for date, name in settings.EVENTS_DAY_NAMES.items() - ) - - times = list(Time.objects.order_by('value')) - end_time_iter = iter(times) - next(end_time_iter, None) - - for begin, __ in zip(times, end_time_iter): - try: - day_info = day_info_dict[begin.value.date()] - except KeyError: - logger.warn(f'Invalid time sot dropped: {begin}') - continue - for event in begin_time_event_dict[begin]: - location = event.location - day_info['slots'].setdefault(location, []) - day_info['slots_mobile'].setdefault(event.begin_time, []) - day_info['timeline'].setdefault('begin', event.begin_time) - day_info['timeline'].setdefault('end', event.end_time) - - day_info['slots'][location].append(event) - day_info['slots_mobile'][event.begin_time].append(event) - day_info['timeline']['begin'] = min( - day_info['timeline']['begin'], - event.begin_time - ) - day_info['timeline']['end'] = max( - day_info['timeline']['end'], - event.end_time - ) - if location in EVENT_ROOMS: - day_info['rooms'].add(location) - - for info in day_info_dict.values(): - # Sort rooms. - info['rooms'] = sorted(info['rooms'], key=_room_sort_key) - - return day_info_dict - - def get_context_data(self, **kwargs): - with translation.override('en-us'): - schedule_days = self.get_day_grouped_events() - - all_rooms = sorted(set(itertools.chain.from_iterable( - info['rooms'] for info in schedule_days.values() - )), key=_room_sort_key) - - return super().get_context_data( - schedule_days=schedule_days, - all_rooms=all_rooms, - **kwargs - ) - - class EventInfoMixin: def is_event_sponsored(self): diff --git a/src/locale/en_US/LC_MESSAGES/django.po b/src/locale/en_US/LC_MESSAGES/django.po index ab539105a..97ad6e3ca 100644 --- a/src/locale/en_US/LC_MESSAGES/django.po +++ b/src/locale/en_US/LC_MESSAGES/django.po @@ -13,7 +13,7 @@ msgid "" msgstr "" "Project-Id-Version: PyCon TW\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-24 10:21+0800\n" +"POT-Creation-Date: 2024-04-15 16:57+0800\n" "PO-Revision-Date: 2022-07-11 02:23+0800\n" "Last-Translator: Tom Chen \n" "Language-Team: English (United States) (http://www.transifex.com/pycon-" @@ -29,11 +29,11 @@ msgstr "" msgid "token" msgstr "token" -#: attendee/models.py:7 users/models.py:166 +#: attendee/models.py:7 users/models.py:164 msgid "verified" msgstr "verified" -#: attendee/models.py:9 core/models.py:162 events/models.py:469 +#: attendee/models.py:9 core/models.py:162 msgid "created at" msgstr "created at" @@ -49,46 +49,45 @@ msgstr "attendee" msgid "attendees" msgstr "attendees" -#: ccip/views.py:209 +#: ccip/views.py:210 msgctxt "CCIP event type" msgid "event" msgstr "event" -#: ccip/views.py:217 +#: ccip/views.py:218 msgctxt "CCIP event type" msgid "break" msgstr "break" -#: ccip/views.py:225 +#: ccip/views.py:226 msgctxt "CCIP event type" msgid "keynote" msgstr "keynote" -#: ccip/views.py:231 +#: ccip/views.py:232 msgctxt "CCIP event type" msgid "sponsored" msgstr "sponsored" -#: ccip/views.py:239 +#: ccip/views.py:240 msgctxt "CCIP event type" msgid "tutorial" msgstr "tutorial" -#: ccip/views.py:251 +#: ccip/views.py:252 msgctxt "CCIP event type" msgid "talk" msgstr "talk" -#: core/admin.py:15 +#: core/admin.py:14 msgid "Current" msgstr "" -#: core/admin.py:16 core/choices.py:24 events/models.py:157 -#: events/templatetags/events.py:21 +#: core/admin.py:15 core/choices.py:24 events/models.py:151 msgid "Other" msgstr "Other" -#: core/admin.py:17 +#: core/admin.py:16 msgid "All" msgstr "" @@ -214,29 +213,13 @@ msgstr "Intermediate" msgid "Experienced" msgstr "Experienced" -#: core/choices.py:41 -msgid "Day 1, September 21st, 2024 Morning" -msgstr "Day 1, September 21st, 2024 Morning with Taiwan Standard Time(UTC+8)" - -#: core/choices.py:42 -msgid "Day 1, September 21st, 2024 Afternoon" -msgstr "Day 1, September 21st, 2024 Afternoon with Taiwan Standard Time(UTC+8)" - -#: core/choices.py:43 -msgid "Day 2, September 22nd, 2024 Morning" -msgstr "Day 2, September 22nd, 2024 Morning with Taiwan Standard Time(UTC+8)" - -#: core/choices.py:44 -msgid "Day 2, September 22nd, 2024 Afternoon" -msgstr "Day 2, September 22nd, 2024 Afternoon with Taiwan Standard Time(UTC+8)" - -#: core/choices.py:48 core/choices.py:53 core/choices.py:58 core/choices.py:63 -#: core/choices.py:68 reviews/models.py:122 reviews/models.py:137 +#: core/choices.py:41 core/choices.py:46 core/choices.py:51 core/choices.py:56 +#: core/choices.py:61 reviews/models.py:121 reviews/models.py:136 msgid "Yes" msgstr "Yes" -#: core/choices.py:49 core/choices.py:54 core/choices.py:59 core/choices.py:64 -#: core/choices.py:69 reviews/models.py:123 reviews/models.py:138 +#: core/choices.py:42 core/choices.py:47 core/choices.py:52 core/choices.py:57 +#: core/choices.py:62 reviews/models.py:122 reviews/models.py:137 msgid "No" msgstr "No" @@ -249,7 +232,7 @@ msgstr "{model_name_cap} creation requires a request object." msgid "conference" msgstr "conference" -#: core/models.py:93 events/models.py:193 +#: core/models.py:93 events/models.py:187 msgid "title" msgstr "title" @@ -293,7 +276,7 @@ msgstr "slide link" msgid "slido embed link" msgstr "Slido embed link" -#: core/models.py:156 events/models.py:258 +#: core/models.py:156 events/models.py:252 msgid "HackMD embed link" msgstr "HackMD embed link" @@ -313,8 +296,8 @@ msgstr "attending PyCon TW in person" msgid "Key" msgstr "Key" -#: core/models.py:215 proposals/models.py:62 users/models.py:198 -#: users/models.py:313 +#: core/models.py:215 proposals/models.py:67 users/models.py:196 +#: users/models.py:311 msgid "user" msgstr "user" @@ -330,99 +313,96 @@ msgstr "" msgid "Tokens" msgstr "" -#: events/admin.py:26 +#: events/admin.py:34 msgid "time value" msgstr "time value" -#: events/admin.py:100 events/models.py:173 +#: events/admin.py:108 events/models.py:167 msgid "begin time" msgstr "begin time" -#: events/admin.py:106 events/models.py:182 +#: events/admin.py:114 events/models.py:176 msgid "end time" msgstr "end time" -#: events/admin.py:128 +#: events/admin.py:136 #: templates/default/users/_includes/dashboard_proposal_table.html:32 msgid "Edit" msgstr "Edit" -#: events/models.py:73 +#: events/models.py:70 msgid "value" msgstr "value" -#: events/models.py:80 +#: events/models.py:77 msgid "time" msgstr "time" -#: events/models.py:81 +#: events/models.py:78 msgid "times" msgstr "times" -#: events/models.py:144 +#: events/models.py:138 msgid "All rooms" msgstr "All rooms" -#: events/models.py:145 +#: events/models.py:139 msgid "R0, R1, R2" msgstr "R1, R2, R3" -#: events/models.py:146 +#: events/models.py:140 msgid "R0" msgstr "R0" -#: events/models.py:147 +#: events/models.py:141 msgid "R0_1" msgstr "R0_1" -#: events/models.py:148 +#: events/models.py:142 msgid "R0_2" msgstr "R0_2" -# #: events/models.py:122 -# msgid "R0" -# msgstr "R0" -#: events/models.py:149 events/templatetags/events.py:15 +#: events/models.py:143 msgid "R1" msgstr "R1" -#: events/models.py:150 +#: events/models.py:144 msgid "R1_1" msgstr "R1_1" -#: events/models.py:151 +#: events/models.py:145 msgid "R1_2" msgstr "R1_2" -#: events/models.py:152 events/templatetags/events.py:16 +#: events/models.py:146 msgid "R2" msgstr "R2" -#: events/models.py:153 +#: events/models.py:147 msgid "R2_1" msgstr "R2_1" -#: events/models.py:154 +#: events/models.py:148 msgid "R2_2" msgstr "R2_2" -#: events/models.py:155 events/templatetags/events.py:17 +#: events/models.py:149 msgid "R3" msgstr "R3" -#: events/models.py:156 +#: events/models.py:150 msgid "Open Space" msgstr "Open Spaces" -#: events/models.py:165 +#: events/models.py:159 msgid "location" msgstr "location" -#: events/models.py:197 +#: events/models.py:191 msgid "is break event" msgstr "is break event" -#: events/models.py:200 +#: events/models.py:194 msgid "" "Whether this event is displays as a break. A break can be visually " "distinguished from \"real\" conference sessions, such as keynotes, talks, " @@ -431,71 +411,71 @@ msgstr "" "Whether this event is displays as a break. A break can be visually " "distinguished from “real” conference sessions, such as keynotes, talks, etc." -#: events/models.py:206 +#: events/models.py:200 msgid "event description" msgstr "event description" -#: events/models.py:209 +#: events/models.py:203 msgid "link path" msgstr "link path" -#: events/models.py:214 +#: events/models.py:208 msgid "custom event" msgstr "custom event" -#: events/models.py:215 +#: events/models.py:209 msgid "custom events" msgstr "custom events" -#: events/models.py:224 users/models.py:118 +#: events/models.py:218 users/models.py:116 msgid "speaker name" msgstr "speaker name" -#: events/models.py:229 +#: events/models.py:223 msgid "speaker bio" msgstr "speaker bio" -#: events/models.py:233 +#: events/models.py:227 msgid "speaker photo" msgstr "speaker photo" -#: events/models.py:237 +#: events/models.py:231 msgid "Raster format of the speaker's photo, e.g. PNG, JPEG." msgstr "Raster format of the speaker's photo, e.g. PNG, JPEG." -#: events/models.py:241 +#: events/models.py:235 msgid "keynote session title" msgstr "keynote session title" -#: events/models.py:246 +#: events/models.py:240 msgid "keynote session description" msgstr "keynote session description" -#: events/models.py:250 +#: events/models.py:244 msgid "session slides" msgstr "session slides" -#: events/models.py:254 +#: events/models.py:248 msgid "slido" msgstr "Slido" -#: events/models.py:263 +#: events/models.py:257 msgid "social linkedin" msgstr "Linkedin" -#: events/models.py:267 +#: events/models.py:261 msgid "social twitter" msgstr "Twitter" -#: events/models.py:271 +#: events/models.py:265 msgid "social github" msgstr "Github" -#: events/models.py:275 events/models.py:360 +#: events/models.py:269 events/models.py:354 msgid "slug" msgstr "slug" -#: events/models.py:277 +#: events/models.py:271 #, python-brace-format msgid "" "This is used to link to the speaker's introduction on the Keynote page, e.g. " @@ -504,33 +484,33 @@ msgstr "" "This is used to link to the speaker's introduction on the Keynote page, e.g. " "'liang2' will link to '{link}#keynote-speaker-liang2'." -#: events/models.py:284 events/models.py:403 events/models.py:439 +#: events/models.py:278 events/models.py:397 events/models.py:433 msgid "is remote" msgstr "is remote" -#: events/models.py:288 events/models.py:363 events/models.py:407 -#: events/models.py:443 +#: events/models.py:282 events/models.py:357 events/models.py:401 +#: events/models.py:437 msgid "youtube id" msgstr "youtube id" -#: events/models.py:294 +#: events/models.py:288 msgid "keynote event" msgstr "keynote event" -#: events/models.py:295 +#: events/models.py:289 msgid "keynote events" msgstr "keynote events" -#: events/models.py:298 +#: events/models.py:292 #, python-brace-format msgid "Keynote: {speaker}" msgstr "Keynote: {speaker}" -#: events/models.py:337 sponsors/models.py:101 sponsors/models.py:117 +#: events/models.py:331 sponsors/models.py:97 sponsors/models.py:113 msgid "sponsor" msgstr "sponsor" -#: events/models.py:342 events/models.py:343 +#: events/models.py:336 events/models.py:337 #: templates/pycontw-2020/_includes/menu.html:104 #: templates/pycontw-2020/contents/_default/events/job-listings.html:33 #: templates/pycontw-2021/contents/_default/events/job-listings.html:33 @@ -540,120 +520,48 @@ msgstr "sponsor" msgid "Job Listings" msgstr "Job Listings" -#: events/models.py:346 +#: events/models.py:340 #, python-brace-format msgid "Open Role of Sponsor: {sponsor}" msgstr "Open Role of Sponsor: {sponsor}" -#: events/models.py:355 +#: events/models.py:349 msgid "host" msgstr "host" -#: events/models.py:369 +#: events/models.py:363 msgid "sponsored event" msgstr "sponsored event" -#: events/models.py:370 +#: events/models.py:364 msgid "sponsored events" msgstr "sponsored events" -#: events/models.py:398 events/models.py:429 reviews/models.py:76 -#: reviews/models.py:197 +#: events/models.py:392 events/models.py:423 reviews/models.py:75 +#: reviews/models.py:196 msgid "proposal" msgstr "proposal" -#: events/models.py:415 +#: events/models.py:409 msgid "talk event" msgstr "talk event" -#: events/models.py:416 +#: events/models.py:410 msgid "talk events" msgstr "talk events" -#: events/models.py:434 +#: events/models.py:428 msgid "registration link" msgstr "registration link" -#: events/models.py:451 +#: events/models.py:445 msgid "tutorial event" msgstr "tutorial event" -#: events/models.py:452 +#: events/models.py:446 msgid "tutorial events" msgstr "tutorial events" -#: events/models.py:466 -msgid "HTML" -msgstr "HTML" - -#: events/models.py:474 templates/pycontw-2016/_includes/nav/front_nav.html:40 -#: templates/pycontw-2016/events/schedule.html:6 -#: templates/pycontw-2016/events/schedule.html:8 -#: templates/pycontw-2017/contents/_default/portal.html:16 -#: templates/pycontw-2017/events/schedule.html:6 -#: templates/pycontw-2017/events/schedule.html:17 -#: templates/pycontw-2018/_includes/menu.html:54 -#: templates/pycontw-2018/contents/_default/portal.html:17 -#: templates/pycontw-2018/events/schedule.html:6 -#: templates/pycontw-2018/events/schedule.html:20 -#: templates/pycontw-2019/_includes/menu.html:59 -#: templates/pycontw-2019/_includes/portal.html:4 -#: templates/pycontw-2019/events/schedule.html:6 -#: templates/pycontw-2019/events/schedule.html:20 -#: templates/pycontw-2020/_includes/menu.html:80 -#: templates/pycontw-2020/_includes/portal.html:4 -#: templates/pycontw-2020/events/schedule.html:6 -#: templates/pycontw-2020/events/schedule.html:21 -#: templates/pycontw-2021/_includes/portal.html:4 -#: templates/pycontw-2021/events/schedule.html:6 -#: templates/pycontw-2021/events/schedule.html:21 -#: templates/pycontw-2022/_includes/portal.html:4 -#: templates/pycontw-2022/events/schedule.html:6 -#: templates/pycontw-2022/events/schedule.html:21 -#: templates/pycontw-2023/_includes/portal.html:4 -#: templates/pycontw-2023/events/schedule.html:6 -#: templates/pycontw-2023/events/schedule.html:21 -#: templates/pycontw-2024/_includes/portal.html:4 -#: templates/pycontw-2024/events/schedule.html:6 -#: templates/pycontw-2024/events/schedule.html:21 -msgid "Schedule" -msgstr "Schedule" - -#: events/models.py:475 -msgid "Schedules" -msgstr "Schedules" - -#: events/models.py:480 -msgid "Schedule created at {}" -msgstr "Schedule created at {}" - -#: events/renderers.py:34 -msgid "Keynote" -msgstr "Keynote" - -#: events/renderers.py:43 -msgid "EN Slides" -msgstr "EN Slides" - -# #: events/models.py:125 -# msgid "R4" -# msgstr "R4" -#: events/templatetags/events.py:18 -msgid "Multifunction room" -msgstr "Multifunction room" - -#: events/templatetags/events.py:19 -msgid "Goodideas Studio" -msgstr "Goodideas Studio" - -#: events/templatetags/events.py:20 -msgid "R1, R2, R3" -msgstr "R1, R2, R3" - -#: events/views.py:121 -msgid "New talk schedule generated successfully." -msgstr "New talk schedule generated successfully." - #: proposals/forms/mixins.py:16 #, python-brace-format msgid "" @@ -852,11 +760,11 @@ msgstr "" msgid "duration" msgstr "Duration" -#: proposals/forms/speakers.py:19 +#: proposals/forms/speakers.py:18 msgid "speaker email" msgstr "speaker email" -#: proposals/forms/speakers.py:21 +#: proposals/forms/speakers.py:20 msgid "" "The speaker should have a registered account, and have completed both email " "validation and the speaker profile." @@ -864,7 +772,7 @@ msgstr "" "The speaker should have a registered account, and have completed both email " "validation and the speaker profile." -#: proposals/forms/speakers.py:29 +#: proposals/forms/speakers.py:28 #, python-brace-format msgid "" "Only authenticated user with complete speaker profile may create an " @@ -873,161 +781,161 @@ msgstr "" "Only authenticated user with complete speaker profile may create an " "{model_name}." -#: proposals/forms/speakers.py:33 +#: proposals/forms/speakers.py:32 msgid "Additional speaker creation requires a proposal instance." msgstr "Additional speaker creation requires a proposal instance." -#: proposals/forms/speakers.py:36 +#: proposals/forms/speakers.py:35 msgid "User can only add additional speakers to owned proposals." msgstr "User can only add additional speakers to owned proposals." -#: proposals/forms/speakers.py:39 +#: proposals/forms/speakers.py:38 msgid "This user is already a speaker for the proposal." msgstr "This user is already a speaker for the proposal." -#: proposals/forms/speakers.py:41 +#: proposals/forms/speakers.py:40 msgid "No valid speaker found with your selection." msgstr "No valid speaker found with your selection." -#: proposals/models.py:55 +#: proposals/models.py:60 msgid "Proposal author" msgstr "Proposal author" -#: proposals/models.py:68 +#: proposals/models.py:73 msgid "proposal model type" msgstr "proposal model type" -#: proposals/models.py:72 +#: proposals/models.py:77 msgid "proposal ID" msgstr "proposal ID" -#: proposals/models.py:80 +#: proposals/models.py:85 msgid "Pending" msgstr "Pending" -#: proposals/models.py:81 proposals/models.py:160 +#: proposals/models.py:86 proposals/models.py:162 msgid "Accepted" msgstr "Accepted" -#: proposals/models.py:82 +#: proposals/models.py:87 msgid "Declined" msgstr "Declined" -#: proposals/models.py:91 proposals/models.py:153 +#: proposals/models.py:96 proposals/models.py:155 msgid "cancelled" msgstr "cancelled" -#: proposals/models.py:99 +#: proposals/models.py:104 msgid "additional speaker" msgstr "additional speaker" -#: proposals/models.py:100 +#: proposals/models.py:105 msgid "additional speakers" msgstr "additional speakers" -#: proposals/models.py:132 +#: proposals/models.py:134 msgid "submitter" msgstr "submitter" -#: proposals/models.py:137 +#: proposals/models.py:139 msgid "outline" msgstr "outline" -#: proposals/models.py:142 +#: proposals/models.py:144 msgid "objective" msgstr "objective" -#: proposals/models.py:147 +#: proposals/models.py:149 msgid "supplementary" msgstr "supplementary" -#: proposals/models.py:161 +#: proposals/models.py:163 msgid "Rejected" msgstr "Rejected" -#: proposals/models.py:164 +#: proposals/models.py:166 msgid "accepted" msgstr "accepted" -#: proposals/models.py:178 +#: proposals/models.py:180 msgid "labels" msgstr "" -#: proposals/models.py:263 proposals/models.py:317 +#: proposals/models.py:264 proposals/models.py:318 #: templates/default/_includes/proposal_example_modal.html:50 #: templates/default/_includes/proposal_example_modal.html:67 #: templates/default/reviews/review_form.html:40 msgid "Duration" msgstr "Duration" -#: proposals/models.py:268 +#: proposals/models.py:269 msgid "Yes, it is my first time speaking at PyCon Taiwan." msgstr "Yes, it is my first time speaking at PyCon Taiwan." -#: proposals/models.py:269 +#: proposals/models.py:270 msgid "No, I have given talks at PyCon Taiwan in the past." msgstr "No, I have given talks at PyCon Taiwan in the past." -#: proposals/models.py:273 +#: proposals/models.py:274 msgid "first time speaker" msgstr "first time speaker" -#: proposals/models.py:278 +#: proposals/models.py:279 msgid "talk proposal" msgstr "talk proposal" -#: proposals/models.py:279 +#: proposals/models.py:280 msgid "talk proposals" msgstr "talk proposals" -#: proposals/models.py:313 +#: proposals/models.py:314 msgid "1.5hr" msgstr "1.5hr" -#: proposals/models.py:324 +#: proposals/models.py:325 msgid "tutorial proposal" msgstr "tutorial proposal" -#: proposals/models.py:325 +#: proposals/models.py:326 msgid "tutorial proposals" msgstr "tutorial proposals" -#: proposals/utils.py:4 +#: proposals/utils.py:3 msgctxt "speaker name default separator" msgid ", " msgstr ", " -#: proposals/utils.py:5 +#: proposals/utils.py:4 msgctxt "speaker name last separator" msgid " and " msgstr " and " -#: proposals/views/cancel.py:36 +#: proposals/views/cancel.py:35 #, python-brace-format msgid "Talk proposal {title} withdrawn." msgstr "Talk proposal {title} withdrawn." -#: proposals/views/cancel.py:40 +#: proposals/views/cancel.py:39 #, python-brace-format msgid "Talk proposal {title} reactivated." msgstr "Talk proposal {title} reactivated." -#: proposals/views/cancel.py:58 +#: proposals/views/cancel.py:57 #, python-brace-format msgid "Tutorial proposal {title} withdrawn." msgstr "Tutorial proposal {title} withdrawn." -#: proposals/views/cancel.py:62 +#: proposals/views/cancel.py:61 #, python-brace-format msgid "Tutorial proposal {title} reactivated." msgstr "Tutorial proposal {title} reactivated." -#: proposals/views/create.py:42 +#: proposals/views/create.py:41 #, python-brace-format msgid "Talk proposal {title} created." msgstr "Talk proposal {title} created." -#: proposals/views/create.py:52 +#: proposals/views/create.py:51 #, python-brace-format msgid "Tutorial proposal {title} created." msgstr "Tutorial proposal {title} created." @@ -1235,62 +1143,60 @@ msgstr "" " - Final resulting work\n" "5. Q&A [5min]\n" -#: proposals/views/update.py:61 +#: proposals/views/update.py:64 #, python-brace-format msgid "Talk proposal {title} updated." msgstr "Talk proposal {title} updated." -#: proposals/views/update.py:70 +#: proposals/views/update.py:73 #, python-brace-format msgid "Tutorial proposal {title} updated." msgstr "Tutorial proposal {title} updated." -#: pycontw2016/settings/base.py:301 +#: pycontw2016/settings/base.py:306 msgid "PyCon Taiwan 2016" msgstr "PyCon Taiwan 2016" -#: pycontw2016/settings/base.py:302 templates/pycontw-2017/index.html:6 +#: pycontw2016/settings/base.py:307 templates/pycontw-2017/index.html:6 msgid "PyCon Taiwan 2017" msgstr "PyCon Taiwan 2017" -#: pycontw2016/settings/base.py:303 templates/pycontw-2018/index.html:14 +#: pycontw2016/settings/base.py:308 templates/pycontw-2018/index.html:14 msgid "PyCon Taiwan 2018" msgstr "PyCon Taiwan 2018" -#: pycontw2016/settings/base.py:304 templates/pycontw-2019/index.html:14 +#: pycontw2016/settings/base.py:309 templates/pycontw-2019/index.html:14 msgid "PyCon Taiwan 2019" msgstr "PyCon Taiwan 2019" -#: pycontw2016/settings/base.py:305 templates/pycontw-2020/index.html:14 +#: pycontw2016/settings/base.py:310 templates/pycontw-2020/index.html:14 msgid "PyCon Taiwan 2020" msgstr "PyCon Taiwan 2020" -#: pycontw2016/settings/base.py:306 templates/pycontw-2021/index.html:14 +#: pycontw2016/settings/base.py:311 templates/pycontw-2021/index.html:14 #: templates/pycontw-2022/index.html:14 templates/pycontw-2023/index.html:14 #: templates/pycontw-2024/index.html:14 msgid "PyCon Taiwan 2021" msgstr "PyCon Taiwan 2021" -#: pycontw2016/settings/base.py:307 +#: pycontw2016/settings/base.py:312 msgid "PyCon Taiwan 2022" msgstr "PyCon Taiwan 2022" -#: pycontw2016/settings/base.py:308 +#: pycontw2016/settings/base.py:313 msgid "PyCon Taiwan 2023" msgstr "PyCon Taiwan 2023" -#: pycontw2016/settings/base.py:309 -#, fuzzy -#| msgid "PyCon Taiwan 2020" +#: pycontw2016/settings/base.py:314 msgid "PyCon Taiwan 2024" -msgstr "PyCon Taiwan 2020" +msgstr "PyCon Taiwan 2024" -#: pycontw2016/settings/base.py:322 +#: pycontw2016/settings/base.py:327 #: pycontw2016/settings/production/pycontw2016.py:16 -#: pycontw2016/settings/production/pycontw2021.py:15 -#: pycontw2016/settings/production/pycontw2022.py:14 -#: pycontw2016/settings/production/pycontw2023.py:14 -#: pycontw2016/settings/production/pycontw2024.py:14 +#: pycontw2016/settings/production/pycontw2021.py:16 +#: pycontw2016/settings/production/pycontw2022.py:16 +#: pycontw2016/settings/production/pycontw2023.py:16 +#: pycontw2016/settings/production/pycontw2024.py:16 #: pycontw2016/settings/testing/pycontw2021.py:11 #: pycontw2016/settings/testing/pycontw2022.py:11 #: pycontw2016/settings/testing/pycontw2023.py:11 @@ -1298,11 +1204,11 @@ msgstr "PyCon Taiwan 2020" msgid "No preference" msgstr "No preference" -#: pycontw2016/settings/base.py:323 -#: pycontw2016/settings/production/pycontw2021.py:16 -#: pycontw2016/settings/production/pycontw2022.py:15 -#: pycontw2016/settings/production/pycontw2023.py:15 -#: pycontw2016/settings/production/pycontw2024.py:15 +#: pycontw2016/settings/base.py:328 +#: pycontw2016/settings/production/pycontw2021.py:17 +#: pycontw2016/settings/production/pycontw2022.py:17 +#: pycontw2016/settings/production/pycontw2023.py:17 +#: pycontw2016/settings/production/pycontw2024.py:17 #: pycontw2016/settings/testing/pycontw2021.py:12 #: pycontw2016/settings/testing/pycontw2022.py:12 #: pycontw2016/settings/testing/pycontw2023.py:12 @@ -1310,11 +1216,11 @@ msgstr "No preference" msgid "Prefer 15min" msgstr "Prefer 15min" -#: pycontw2016/settings/base.py:324 -#: pycontw2016/settings/production/pycontw2021.py:17 -#: pycontw2016/settings/production/pycontw2022.py:16 -#: pycontw2016/settings/production/pycontw2023.py:16 -#: pycontw2016/settings/production/pycontw2024.py:16 +#: pycontw2016/settings/base.py:329 +#: pycontw2016/settings/production/pycontw2021.py:18 +#: pycontw2016/settings/production/pycontw2022.py:18 +#: pycontw2016/settings/production/pycontw2023.py:18 +#: pycontw2016/settings/production/pycontw2024.py:18 #: pycontw2016/settings/testing/pycontw2021.py:13 #: pycontw2016/settings/testing/pycontw2022.py:13 #: pycontw2016/settings/testing/pycontw2023.py:13 @@ -1322,13 +1228,13 @@ msgstr "Prefer 15min" msgid "Prefer 30min" msgstr "Prefer 30min" -#: pycontw2016/settings/base.py:328 +#: pycontw2016/settings/base.py:333 #: pycontw2016/settings/production/pycontw2016.py:22 #: templates/pycontw-2016/events/schedule.html:42 msgid "Day 1" msgstr "Day 1" -#: pycontw2016/settings/base.py:329 +#: pycontw2016/settings/base.py:334 #: pycontw2016/settings/production/pycontw2016.py:23 #: templates/pycontw-2016/events/schedule.html:45 msgid "Day 2" @@ -1339,10 +1245,10 @@ msgid "Prefer 25min" msgstr "Prefer 25min" #: pycontw2016/settings/production/pycontw2016.py:18 -#: pycontw2016/settings/production/pycontw2021.py:18 -#: pycontw2016/settings/production/pycontw2022.py:17 -#: pycontw2016/settings/production/pycontw2023.py:17 -#: pycontw2016/settings/production/pycontw2024.py:17 +#: pycontw2016/settings/production/pycontw2021.py:19 +#: pycontw2016/settings/production/pycontw2022.py:19 +#: pycontw2016/settings/production/pycontw2023.py:19 +#: pycontw2016/settings/production/pycontw2024.py:19 #: pycontw2016/settings/testing/pycontw2021.py:14 #: pycontw2016/settings/testing/pycontw2022.py:14 #: pycontw2016/settings/testing/pycontw2023.py:14 @@ -1378,35 +1284,35 @@ msgstr "{model_name_cap} creation requires a proposal object." msgid "Could not review proposal {proposal}." msgstr "Could not review proposal {proposal}." -#: reviews/models.py:66 +#: reviews/models.py:65 msgid "reviewer" msgstr "reviewer" -#: reviews/models.py:71 reviews/models.py:202 +#: reviews/models.py:70 reviews/models.py:201 msgid "stage" msgstr "stage" -#: reviews/models.py:90 +#: reviews/models.py:89 msgid "+1 (strong accept)" msgstr "+1 (strong accept)" -#: reviews/models.py:91 +#: reviews/models.py:90 msgid "+0 (weak accept)" msgstr "+0 (weak accept)" -#: reviews/models.py:92 +#: reviews/models.py:91 msgid "-0 (weak reject)" msgstr "–0 (weak reject)" -#: reviews/models.py:93 +#: reviews/models.py:92 msgid "-1 (strong reject)" msgstr "–1 (strong reject)" -#: reviews/models.py:102 +#: reviews/models.py:101 msgid "vote" msgstr "vote" -#: reviews/models.py:104 +#: reviews/models.py:103 msgid "" "Your vote to accept or reject this talk. More information about the scoring " "and acceptance criteria can be found at the GitBook Review Guideline." -#: reviews/models.py:113 +#: reviews/models.py:112 msgid "comment" msgstr "comment" -#: reviews/models.py:115 +#: reviews/models.py:114 msgid "" "Comments to this proposal. This may be available for other reviewers in " "later review stages, and you can choose whether or not to disclose it to the " @@ -1432,11 +1338,11 @@ msgstr "" "later review stages, and you can choose whether or not to disclose it to the " "proposal's submitter." -#: reviews/models.py:128 +#: reviews/models.py:127 msgid "discloses comment to proposal submitter" msgstr "discloses comment to proposal submitter" -#: reviews/models.py:130 +#: reviews/models.py:129 msgid "" "Whether the proposal submitter can read you comments. We will include your " "comments in the proposal acceptance/rejection notice sent to the submitter " @@ -1446,11 +1352,11 @@ msgstr "" "comments in the proposal acceptance/rejection notice sent to the submitter " "if you allow us to." -#: reviews/models.py:143 +#: reviews/models.py:142 msgid "is appropriate" msgstr "is appropriate" -#: reviews/models.py:145 +#: reviews/models.py:144 msgid "" "Administrators can use this field to hide a review from submitters, even if " "the reviewer enables disclosure. The review may be shown to the submitter " @@ -1460,11 +1366,11 @@ msgstr "" "the reviewer enables disclosure. The review may be shown to the submitter " "only if this is set to True." -#: reviews/models.py:153 +#: reviews/models.py:152 msgid "note" msgstr "note" -#: reviews/models.py:155 +#: reviews/models.py:154 msgid "" "Personal notes about this proposal. You can use this field to record " "anything you like during the review process. We promise to never disclose " @@ -1474,65 +1380,65 @@ msgstr "" "anything you like during the review process. We promise to never disclose " "them to anyone." -#: reviews/models.py:163 +#: reviews/models.py:162 msgid "updated" msgstr "updated" -#: reviews/models.py:168 +#: reviews/models.py:167 msgid "review" msgstr "review" -#: reviews/models.py:169 +#: reviews/models.py:168 msgid "reviews" msgstr "reviews" -#: reviews/models.py:174 +#: reviews/models.py:173 #, python-brace-format msgid "Review {proposal} by {reviewer}: {vote}" msgstr "Review {proposal} by {reviewer}: {vote}" -#: reviews/models.py:206 +#: reviews/models.py:205 msgid "dumped JSON" msgstr "dumped JSON" -#: reviews/models.py:210 +#: reviews/models.py:209 msgid "dumped at" msgstr "dumped at" -#: reviews/models.py:215 +#: reviews/models.py:214 msgid "talk proposal snapshot" msgstr "talk proposal snapshot" -#: reviews/models.py:216 +#: reviews/models.py:215 msgid "talk proposal snapshots" msgstr "talk proposal snapshots" -#: reviews/models.py:220 +#: reviews/models.py:219 #, python-brace-format msgid "Stage {stage} dump for {proposal}" msgstr "Stage {stage} dump for {proposal}" -#: sponsors/models.py:27 +#: sponsors/models.py:23 msgid "name" msgstr "name" -#: sponsors/models.py:31 +#: sponsors/models.py:27 msgid "website URL" msgstr "website URL" -#: sponsors/models.py:35 +#: sponsors/models.py:31 msgid "introduction" msgstr "introduction" -#: sponsors/models.py:38 +#: sponsors/models.py:34 msgid "subtitle" msgstr "subtitle" -#: sponsors/models.py:43 +#: sponsors/models.py:39 msgid "logo (SVG)" msgstr "logo (SVG)" -#: sponsors/models.py:46 +#: sponsors/models.py:42 msgid "" "Vector format of the logo, in SVG. This takes precedence to the raster " "format, if available." @@ -1540,11 +1446,11 @@ msgstr "" "Vector format of the logo, in SVG. This takes precedence to the raster " "format, if available." -#: sponsors/models.py:51 +#: sponsors/models.py:47 msgid "logo (image)" msgstr "logo (image)" -#: sponsors/models.py:55 +#: sponsors/models.py:51 msgid "" "Raster format of the logo, e.g. PNG, JPEG. This is used as fallback when the " "SVG file is not available." @@ -1552,71 +1458,71 @@ msgstr "" "Raster format of the logo, e.g. PNG, JPEG. This is used as fallback when the " "SVG file is not available." -#: sponsors/models.py:60 +#: sponsors/models.py:56 msgid "order" msgstr "order" -#: sponsors/models.py:80 +#: sponsors/models.py:76 msgid "platinum" msgstr "platinum" -#: sponsors/models.py:81 +#: sponsors/models.py:77 msgid "gold" msgstr "gold" -#: sponsors/models.py:82 +#: sponsors/models.py:78 msgid "silver" msgstr "silver" -#: sponsors/models.py:83 +#: sponsors/models.py:79 msgid "bronze" msgstr "bronze" -#: sponsors/models.py:84 +#: sponsors/models.py:80 msgid "special" msgstr "special" -#: sponsors/models.py:85 +#: sponsors/models.py:81 msgid "special-thanks" msgstr "special-thanks" -#: sponsors/models.py:86 +#: sponsors/models.py:82 msgid "organizer" msgstr "organizer" -#: sponsors/models.py:87 +#: sponsors/models.py:83 msgid "co-organizer" msgstr "co-organizer" -#: sponsors/models.py:96 +#: sponsors/models.py:92 msgid "level" msgstr "level" -#: sponsors/models.py:102 +#: sponsors/models.py:98 msgid "sponsors" msgstr "sponsors" -#: sponsors/models.py:122 +#: sponsors/models.py:118 msgid "open role name" msgstr "open role name" -#: sponsors/models.py:127 +#: sponsors/models.py:123 msgid "open role descsription" msgstr "open role description" -#: sponsors/models.py:131 +#: sponsors/models.py:127 msgid "open role requirements" msgstr "open role requirements" -#: sponsors/models.py:136 +#: sponsors/models.py:132 msgid "open role URL" msgstr "open role URL" -#: sponsors/models.py:141 +#: sponsors/models.py:137 msgid "open role" msgstr "open role" -#: sponsors/models.py:142 +#: sponsors/models.py:138 msgid "open Roles" msgstr "open Roles" @@ -1875,7 +1781,7 @@ msgstr "Edit Tutorial Proposal %(proposal_title)s" #: templates/default/registration/login.html:5 #: templates/default/registration/login.html:7 #: templates/pycontw-2016/registration/login.html:7 -#: templates/pycontw-2016/registration/login.html:21 users/forms.py:261 +#: templates/pycontw-2016/registration/login.html:21 users/forms.py:265 msgid "Log In" msgstr "Log In" @@ -1978,7 +1884,7 @@ msgid "Stage" msgstr "Stage" #: templates/default/reviews/_includes/previous_review_table.html:7 -#: users/models.py:223 +#: users/models.py:221 msgid "Reviewer ID" msgstr "Reviewer ID" @@ -2349,10 +2255,10 @@ msgstr "We screwed up. It’s not your fault." #: templates/pycontw-2018/_includes/menu.html:29 #: templates/pycontw-2019/_includes/menu.html:31 #: templates/pycontw-2020/_includes/menu.html:42 -#: templates/pycontw-2021/_includes/menu.html:42 -#: templates/pycontw-2022/_includes/menu.html:42 -#: templates/pycontw-2023/_includes/menu.html:42 -#: templates/pycontw-2024/_includes/menu.html:42 +#: templates/pycontw-2021/_includes/menu.html:41 +#: templates/pycontw-2022/_includes/menu.html:41 +#: templates/pycontw-2023/_includes/menu.html:41 +#: templates/pycontw-2024/_includes/menu.html:41 msgid "About" msgstr "About" @@ -2419,6 +2325,27 @@ msgstr "Events" msgid "Overview" msgstr "Overview" +#: templates/pycontw-2016/_includes/nav/front_nav.html:40 +#: templates/pycontw-2016/events/schedule.html:6 +#: templates/pycontw-2016/events/schedule.html:8 +#: templates/pycontw-2017/contents/_default/portal.html:16 +#: templates/pycontw-2017/events/schedule.html:6 +#: templates/pycontw-2017/events/schedule.html:17 +#: templates/pycontw-2018/_includes/menu.html:54 +#: templates/pycontw-2018/contents/_default/portal.html:17 +#: templates/pycontw-2018/events/schedule.html:6 +#: templates/pycontw-2018/events/schedule.html:20 +#: templates/pycontw-2019/_includes/menu.html:59 +#: templates/pycontw-2019/_includes/portal.html:4 +#: templates/pycontw-2019/events/schedule.html:6 +#: templates/pycontw-2019/events/schedule.html:20 +#: templates/pycontw-2020/_includes/menu.html:80 +#: templates/pycontw-2020/_includes/portal.html:4 +#: templates/pycontw-2020/events/schedule.html:6 +#: templates/pycontw-2020/events/schedule.html:21 +msgid "Schedule" +msgstr "Schedule" + #: templates/pycontw-2016/_includes/nav/front_nav.html:41 #: templates/pycontw-2018/_includes/menu.html:55 #: templates/pycontw-2018/contents/en/events/overview.html:38 @@ -2616,10 +2543,6 @@ msgstr "Quick Jump" #: templates/pycontw-2018/events/schedule_create.html:64 #: templates/pycontw-2019/events/schedule_create.html:60 #: templates/pycontw-2020/events/schedule_create.html:100 -#: templates/pycontw-2021/events/schedule_create.html:100 -#: templates/pycontw-2022/events/schedule_create.html:100 -#: templates/pycontw-2023/events/schedule_create.html:100 -#: templates/pycontw-2024/events/schedule_create.html:100 msgid "Schedule table generation requires JavaScript. Please. (´・_・`)" msgstr "Schedule table generation requires JavaScript. Please. (´・_・`)" @@ -2628,10 +2551,6 @@ msgstr "Schedule table generation requires JavaScript. Please. (´・_・`)" #: templates/pycontw-2018/events/schedule_create.html:73 #: templates/pycontw-2019/events/schedule_create.html:69 #: templates/pycontw-2020/events/schedule_create.html:109 -#: templates/pycontw-2021/events/schedule_create.html:109 -#: templates/pycontw-2022/events/schedule_create.html:109 -#: templates/pycontw-2023/events/schedule_create.html:109 -#: templates/pycontw-2024/events/schedule_create.html:109 msgid "Generate" msgstr "Generate" @@ -2966,10 +2885,10 @@ msgstr "Portal" #: templates/pycontw-2018/contents/_default/portal.html:21 #: templates/pycontw-2019/_includes/portal.html:8 #: templates/pycontw-2020/_includes/portal.html:8 -#: templates/pycontw-2021/_includes/portal.html:8 -#: templates/pycontw-2022/_includes/portal.html:8 -#: templates/pycontw-2023/_includes/portal.html:8 -#: templates/pycontw-2024/_includes/portal.html:8 +#: templates/pycontw-2021/_includes/portal.html:4 +#: templates/pycontw-2022/_includes/portal.html:4 +#: templates/pycontw-2023/_includes/portal.html:4 +#: templates/pycontw-2024/_includes/portal.html:4 msgid "Collaborative Notes" msgstr "Collaborative Notes" @@ -2988,10 +2907,10 @@ msgstr "Quiz Leaderboard" #: templates/pycontw-2018/contents/_default/portal.html:29 #: templates/pycontw-2019/_includes/portal.html:16 #: templates/pycontw-2020/_includes/portal.html:16 -#: templates/pycontw-2021/_includes/portal.html:16 -#: templates/pycontw-2022/_includes/portal.html:16 -#: templates/pycontw-2023/_includes/portal.html:16 -#: templates/pycontw-2024/_includes/portal.html:16 +#: templates/pycontw-2021/_includes/portal.html:12 +#: templates/pycontw-2022/_includes/portal.html:12 +#: templates/pycontw-2023/_includes/portal.html:12 +#: templates/pycontw-2024/_includes/portal.html:12 msgid "Facebook Fan Page" msgstr "Facebook Fan Page" @@ -3031,14 +2950,6 @@ msgstr "Unconference" #: templates/pycontw-2019/events/schedule_create.html:15 #: templates/pycontw-2020/events/schedule_create.html:7 #: templates/pycontw-2020/events/schedule_create.html:16 -#: templates/pycontw-2021/events/schedule_create.html:7 -#: templates/pycontw-2021/events/schedule_create.html:16 -#: templates/pycontw-2022/events/schedule_create.html:7 -#: templates/pycontw-2022/events/schedule_create.html:16 -#: templates/pycontw-2023/events/schedule_create.html:7 -#: templates/pycontw-2023/events/schedule_create.html:16 -#: templates/pycontw-2024/events/schedule_create.html:7 -#: templates/pycontw-2024/events/schedule_create.html:16 msgid "Export New Schedule" msgstr "Export New Schedule" @@ -3255,10 +3166,10 @@ msgstr "Registration" #: templates/pycontw-2018/_includes/menu.html:89 #: templates/pycontw-2019/_includes/menu.html:94 #: templates/pycontw-2020/_includes/menu.html:138 -#: templates/pycontw-2021/_includes/menu.html:152 -#: templates/pycontw-2022/_includes/menu.html:152 -#: templates/pycontw-2023/_includes/menu.html:152 -#: templates/pycontw-2024/_includes/menu.html:152 +#: templates/pycontw-2021/_includes/menu.html:150 +#: templates/pycontw-2022/_includes/menu.html:150 +#: templates/pycontw-2023/_includes/menu.html:150 +#: templates/pycontw-2024/_includes/menu.html:150 msgid "My PyCon" msgstr "My PyCon" @@ -4424,27 +4335,27 @@ msgid "Warm-Up Session" msgstr "Warm-Up Session" #: templates/pycontw-2020/_includes/menu.html:132 -#: templates/pycontw-2021/_includes/menu.html:146 -#: templates/pycontw-2022/_includes/menu.html:146 -#: templates/pycontw-2023/_includes/menu.html:146 -#: templates/pycontw-2024/_includes/menu.html:146 +#: templates/pycontw-2021/_includes/menu.html:144 +#: templates/pycontw-2022/_includes/menu.html:144 +#: templates/pycontw-2023/_includes/menu.html:144 +#: templates/pycontw-2024/_includes/menu.html:144 msgctxt "COVID-19 Guidelines" msgid "COVID-19 Guidelines" msgstr "COVID-19 Guidelines" #: templates/pycontw-2020/_includes/portal.html:12 -#: templates/pycontw-2021/_includes/portal.html:12 -#: templates/pycontw-2022/_includes/portal.html:12 -#: templates/pycontw-2023/_includes/portal.html:12 -#: templates/pycontw-2024/_includes/portal.html:12 +#: templates/pycontw-2021/_includes/portal.html:8 +#: templates/pycontw-2022/_includes/portal.html:8 +#: templates/pycontw-2023/_includes/portal.html:8 +#: templates/pycontw-2024/_includes/portal.html:8 msgid "Discord Chat Room" msgstr "Discord 聊天室" #: templates/pycontw-2020/_includes/portal.html:20 -#: templates/pycontw-2021/_includes/portal.html:20 -#: templates/pycontw-2022/_includes/portal.html:20 -#: templates/pycontw-2023/_includes/portal.html:20 -#: templates/pycontw-2024/_includes/portal.html:20 +#: templates/pycontw-2021/_includes/portal.html:16 +#: templates/pycontw-2022/_includes/portal.html:16 +#: templates/pycontw-2023/_includes/portal.html:16 +#: templates/pycontw-2024/_includes/portal.html:16 msgid "Open space" msgstr "Open space" @@ -5035,40 +4946,40 @@ msgstr "Permissions" msgid "Important dates" msgstr "Important dates" -#: users/forms.py:28 +#: users/forms.py:32 msgid "A user with that email already exists." msgstr "A user with that email already exists." -#: users/forms.py:29 +#: users/forms.py:33 msgid "The two password fields didn't match." msgstr "The two password fields didn’t match." -#: users/forms.py:32 users/forms.py:201 +#: users/forms.py:36 users/forms.py:205 msgid "Password" msgstr "Password" -#: users/forms.py:36 +#: users/forms.py:40 msgid "Password confirmation" msgstr "Password confirmation" -#: users/forms.py:117 +#: users/forms.py:121 msgid "Create Account" msgstr "Create Account" -#: users/forms.py:148 +#: users/forms.py:152 #, python-brace-format msgid "Your image is too small ({width}\\u00d7{height} pixels)." msgstr "Your image is too small ({width}\\u00d7{height} pixels)." -#: users/forms.py:150 +#: users/forms.py:154 msgid "The image you provided is not quadrate." msgstr "The image you provided is not quadrate." -#: users/forms.py:151 +#: users/forms.py:155 msgid "Your image size is too big (>10M)" msgstr "Your image size is too big (>10M)" -#: users/forms.py:202 +#: users/forms.py:206 msgid "" "Raw passwords are not stored, so there is no way to see this user's " "password, but you can change the password using this " @@ -5078,61 +4989,61 @@ msgstr "" "password, but you can change the password using this " "form." -#: users/forms.py:251 +#: users/forms.py:255 #, python-brace-format msgid "" "Forgot Password" msgstr "" "Forgot Password" -#: users/forms.py:255 +#: users/forms.py:259 #, python-brace-format msgid "Sign up now" msgstr "Sign up now" -#: users/forms.py:272 +#: users/forms.py:276 msgid "Email Address" msgstr "Email Address" -#: users/forms.py:291 +#: users/forms.py:295 msgid "Request Password Reset" msgstr "Request Password Reset" -#: users/forms.py:327 +#: users/forms.py:331 msgid "Set Password" msgstr "Set Password" -#: users/forms.py:339 +#: users/forms.py:343 msgid "I agree to the code of conduct." msgstr "I agree to the code of conduct." -#: users/forms.py:344 +#: users/forms.py:348 msgid "You must agree to continue." msgstr "You must agree to continue." -#: users/models.py:114 +#: users/models.py:112 msgid "email address" msgstr "email address" -#: users/models.py:122 +#: users/models.py:120 msgid "biography" msgstr "biography" -#: users/models.py:125 +#: users/models.py:123 msgid "" "Describe yourself with 1000 characters or less. There will be no formatting." msgstr "" "Describe yourself with 1000 characters or less. There will be no formatting." -#: users/models.py:130 +#: users/models.py:128 msgid "photo" msgstr "photo" -#: users/models.py:134 +#: users/models.py:132 msgid "Facebook" msgstr "Facebook" -#: users/models.py:137 +#: users/models.py:135 msgid "" "Link to your Facebook profile page. This will be shown when we display your " "public information. If you do not know what your profile page link is, click " @@ -5144,11 +5055,11 @@ msgstr "" "on this link, and " "copy-paste the URL of the page opened. Remember to log in to Facebook first!" -#: users/models.py:146 +#: users/models.py:144 msgid "Twitter" msgstr "Twitter" -#: users/models.py:151 +#: users/models.py:149 msgid "" "Your Twitter handle, without the \"@\" sign. This will be shown when we " "display your public information." @@ -5156,11 +5067,11 @@ msgstr "" "Your Twitter handle, without the “@” sign. This will be shown when we " "display your public information." -#: users/models.py:156 +#: users/models.py:154 msgid "GitHub" msgstr "GitHub" -#: users/models.py:161 +#: users/models.py:159 msgid "" "Your GitHub account, without the \"@\" sign. This will be shown when we " "display your public information." @@ -5168,23 +5079,23 @@ msgstr "" "Your GitHub account, without the “@” sign. This will be shown when we " "display your public information." -#: users/models.py:169 +#: users/models.py:167 msgid "Designates whether the user has verified email ownership." msgstr "Designates whether the user has verified email ownership." -#: users/models.py:173 +#: users/models.py:171 msgid "staff status" msgstr "staff status" -#: users/models.py:176 +#: users/models.py:174 msgid "Designates whether the user can log into this admin site." msgstr "Designates whether the user can log into this admin site." -#: users/models.py:180 +#: users/models.py:178 msgid "active" msgstr "active" -#: users/models.py:183 +#: users/models.py:181 msgid "" "Designates whether this user should be treated as active. Unselect this " "instead of deleting accounts." @@ -5192,49 +5103,49 @@ msgstr "" "Designates whether this user should be treated as active. Unselect this " "instead of deleting accounts." -#: users/models.py:188 +#: users/models.py:186 msgid "date joined" msgstr "date joined" -#: users/models.py:199 +#: users/models.py:197 msgid "users" msgstr "users" -#: users/models.py:299 +#: users/models.py:297 #, python-brace-format msgid "Verify your email address on {host}" msgstr "Verify your email address on {host}" -#: users/models.py:317 +#: users/models.py:315 msgid "latest agreed CoC version" msgstr "latest agreed CoC version" -#: users/models.py:321 +#: users/models.py:319 msgid "agreed at" msgstr "agreed at" -#: users/views.py:42 +#: users/views.py:44 msgid "Sign up successful. You are now logged in." msgstr "Sign up successful. You are now logged in." -#: users/views.py:59 +#: users/views.py:61 msgid "Email verification successful." msgstr "Email verification successful." -#: users/views.py:71 +#: users/views.py:73 #, python-brace-format msgid "A verification email has been sent to {email}" msgstr "A verification email has been sent to {email}" -#: users/views.py:101 +#: users/views.py:103 msgid "Your profile has been updated successfully." msgstr "Your profile has been updated successfully." -#: users/views.py:114 +#: users/views.py:116 msgid "Your new password has been applied successfully." msgstr "Your new password has been applied successfully." -#: users/views.py:121 +#: users/views.py:123 msgid "" "An email is sent to your email account. Please check your inbox for furthur " "instructions to reset your password." @@ -5242,6 +5153,18 @@ msgstr "" "An email is sent to your email account. Please check your inbox for furthur " "instructions to reset your password." -#: users/views.py:129 +#: users/views.py:131 msgid "Password reset successful. You can now login." msgstr "Password reset successful. You can now login." + +#~ msgid "HTML" +#~ msgstr "HTML" + +#~ msgid "Keynote" +#~ msgstr "Keynote" + +#~ msgid "EN Slides" +#~ msgstr "EN Slides" + +#~ msgid "R1, R2, R3" +#~ msgstr "R1, R2, R3" diff --git a/src/locale/zh_Hant/LC_MESSAGES/django.po b/src/locale/zh_Hant/LC_MESSAGES/django.po index 52a8c64b8..2cd23cbca 100644 --- a/src/locale/zh_Hant/LC_MESSAGES/django.po +++ b/src/locale/zh_Hant/LC_MESSAGES/django.po @@ -20,7 +20,7 @@ msgid "" msgstr "" "Project-Id-Version: PyCon TW\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-02-24 10:21+0800\n" +"POT-Creation-Date: 2024-04-15 16:57+0800\n" "PO-Revision-Date: 2022-07-11 02:25+0800\n" "Last-Translator: Tom Chen \n" "Language-Team: Chinese Traditional (http://www.transifex.com/pycon-taiwan/" @@ -36,11 +36,11 @@ msgstr "" msgid "token" msgstr "驗證碼" -#: attendee/models.py:7 users/models.py:166 +#: attendee/models.py:7 users/models.py:164 msgid "verified" msgstr "已認證" -#: attendee/models.py:9 core/models.py:162 events/models.py:469 +#: attendee/models.py:9 core/models.py:162 msgid "created at" msgstr "建立時間" @@ -56,46 +56,45 @@ msgstr "會眾" msgid "attendees" msgstr "會眾" -#: ccip/views.py:209 +#: ccip/views.py:210 msgctxt "CCIP event type" msgid "event" msgstr "活動" -#: ccip/views.py:217 +#: ccip/views.py:218 msgctxt "CCIP event type" msgid "break" msgstr "休息" -#: ccip/views.py:225 +#: ccip/views.py:226 msgctxt "CCIP event type" msgid "keynote" msgstr "基調演講" -#: ccip/views.py:231 +#: ccip/views.py:232 msgctxt "CCIP event type" msgid "sponsored" msgstr "贊助" -#: ccip/views.py:239 +#: ccip/views.py:240 msgctxt "CCIP event type" msgid "tutorial" msgstr "專業課程" -#: ccip/views.py:251 +#: ccip/views.py:252 msgctxt "CCIP event type" msgid "talk" msgstr "演講" -#: core/admin.py:15 +#: core/admin.py:14 msgid "Current" msgstr "" -#: core/admin.py:16 core/choices.py:24 events/models.py:157 -#: events/templatetags/events.py:21 +#: core/admin.py:15 core/choices.py:24 events/models.py:151 msgid "Other" msgstr "其他" -#: core/admin.py:17 +#: core/admin.py:16 msgid "All" msgstr "" @@ -221,29 +220,13 @@ msgstr "中階" msgid "Experienced" msgstr "進階" -#: core/choices.py:41 -msgid "Day 1, September 21st, 2024 Morning" -msgstr "第一天(2024/09/21)早上" - -#: core/choices.py:42 -msgid "Day 1, September 21st, 2024 Afternoon" -msgstr "第一天(2024/09/21)下午" - -#: core/choices.py:43 -msgid "Day 2, September 22nd, 2024 Morning" -msgstr "第二天(2024/09/22)早上" - -#: core/choices.py:44 -msgid "Day 2, September 22nd, 2024 Afternoon" -msgstr "第二天(2024/09/22)下午" - -#: core/choices.py:48 core/choices.py:53 core/choices.py:58 core/choices.py:63 -#: core/choices.py:68 reviews/models.py:122 reviews/models.py:137 +#: core/choices.py:41 core/choices.py:46 core/choices.py:51 core/choices.py:56 +#: core/choices.py:61 reviews/models.py:121 reviews/models.py:136 msgid "Yes" msgstr "是" -#: core/choices.py:49 core/choices.py:54 core/choices.py:59 core/choices.py:64 -#: core/choices.py:69 reviews/models.py:123 reviews/models.py:138 +#: core/choices.py:42 core/choices.py:47 core/choices.py:52 core/choices.py:57 +#: core/choices.py:62 reviews/models.py:122 reviews/models.py:137 msgid "No" msgstr "否" @@ -256,7 +239,7 @@ msgstr "建立 {model_name_cap} 需要一個 request 物件。" msgid "conference" msgstr "會議" -#: core/models.py:93 events/models.py:193 +#: core/models.py:93 events/models.py:187 msgid "title" msgstr "題目" @@ -300,7 +283,7 @@ msgstr "投影片連結" msgid "slido embed link" msgstr "Slido 嵌入連結" -#: core/models.py:156 events/models.py:258 +#: core/models.py:156 events/models.py:252 msgid "HackMD embed link" msgstr "HackMD 嵌入連結" @@ -320,8 +303,8 @@ msgstr "是否願意以實體方式與會" msgid "Key" msgstr "鍵" -#: core/models.py:215 proposals/models.py:62 users/models.py:198 -#: users/models.py:313 +#: core/models.py:215 proposals/models.py:67 users/models.py:196 +#: users/models.py:311 msgid "user" msgstr "使用者" @@ -337,99 +320,96 @@ msgstr "驗證碼" msgid "Tokens" msgstr "驗證碼" -#: events/admin.py:26 +#: events/admin.py:34 msgid "time value" msgstr "時間值" -#: events/admin.py:100 events/models.py:173 +#: events/admin.py:108 events/models.py:167 msgid "begin time" msgstr "開始時間" -#: events/admin.py:106 events/models.py:182 +#: events/admin.py:114 events/models.py:176 msgid "end time" msgstr "結束時間" -#: events/admin.py:128 +#: events/admin.py:136 #: templates/default/users/_includes/dashboard_proposal_table.html:32 msgid "Edit" msgstr "編輯" -#: events/models.py:73 +#: events/models.py:70 msgid "value" msgstr "值" -#: events/models.py:80 +#: events/models.py:77 msgid "time" msgstr "時間" -#: events/models.py:81 +#: events/models.py:78 msgid "times" msgstr "時間" -#: events/models.py:144 +#: events/models.py:138 msgid "All rooms" msgstr "全體會議" -#: events/models.py:145 +#: events/models.py:139 msgid "R0, R1, R2" msgstr "R1、R2、R3" -#: events/models.py:146 +#: events/models.py:140 msgid "R0" msgstr "" -#: events/models.py:147 +#: events/models.py:141 msgid "R0_1" msgstr "" -#: events/models.py:148 +#: events/models.py:142 msgid "R0_2" msgstr "" -# #: events/models.py:122 -# msgid "R0" -# msgstr "R0" -#: events/models.py:149 events/templatetags/events.py:15 +#: events/models.py:143 msgid "R1" msgstr "R1" -#: events/models.py:150 +#: events/models.py:144 msgid "R1_1" msgstr "" -#: events/models.py:151 +#: events/models.py:145 msgid "R1_2" msgstr "" -#: events/models.py:152 events/templatetags/events.py:16 +#: events/models.py:146 msgid "R2" msgstr "R2" -#: events/models.py:153 +#: events/models.py:147 msgid "R2_1" msgstr "" -#: events/models.py:154 +#: events/models.py:148 msgid "R2_2" msgstr "" -#: events/models.py:155 events/templatetags/events.py:17 +#: events/models.py:149 msgid "R3" msgstr "R3" -#: events/models.py:156 +#: events/models.py:150 msgid "Open Space" msgstr "開放空間" -#: events/models.py:165 +#: events/models.py:159 msgid "location" msgstr "地點" -#: events/models.py:197 +#: events/models.py:191 msgid "is break event" msgstr "休息" -#: events/models.py:200 +#: events/models.py:194 msgid "" "Whether this event is displays as a break. A break can be visually " "distinguished from \"real\" conference sessions, such as keynotes, talks, " @@ -438,71 +418,71 @@ msgstr "" "此活動是否應該被顯示為休息時間。休息時間的顯示會與「真的」會議時段,例如基調" "演講、一般演講不同。" -#: events/models.py:206 +#: events/models.py:200 msgid "event description" msgstr "活動說明" -#: events/models.py:209 +#: events/models.py:203 msgid "link path" msgstr "連結路徑" -#: events/models.py:214 +#: events/models.py:208 msgid "custom event" msgstr "自訂活動" -#: events/models.py:215 +#: events/models.py:209 msgid "custom events" msgstr "自訂活動" -#: events/models.py:224 users/models.py:118 +#: events/models.py:218 users/models.py:116 msgid "speaker name" msgstr "演講者" -#: events/models.py:229 +#: events/models.py:223 msgid "speaker bio" msgstr "演講者介紹" -#: events/models.py:233 +#: events/models.py:227 msgid "speaker photo" msgstr "演講者照片" -#: events/models.py:237 +#: events/models.py:231 msgid "Raster format of the speaker's photo, e.g. PNG, JPEG." msgstr "演講者照片使用點陣格式,例如PNG, JPEG" -#: events/models.py:241 +#: events/models.py:235 msgid "keynote session title" msgstr "演講標題" -#: events/models.py:246 +#: events/models.py:240 msgid "keynote session description" msgstr "演講介紹" -#: events/models.py:250 +#: events/models.py:244 msgid "session slides" msgstr "演講投影片" -#: events/models.py:254 +#: events/models.py:248 msgid "slido" msgstr "Slido" -#: events/models.py:263 +#: events/models.py:257 msgid "social linkedin" msgstr "Linkedin" -#: events/models.py:267 +#: events/models.py:261 msgid "social twitter" msgstr "Twitter" -#: events/models.py:271 +#: events/models.py:265 msgid "social github" msgstr "Github" -#: events/models.py:275 events/models.py:360 +#: events/models.py:269 events/models.py:354 msgid "slug" msgstr "網址文字" -#: events/models.py:277 +#: events/models.py:271 #, python-brace-format msgid "" "This is used to link to the speaker's introduction on the Keynote page, e.g. " @@ -511,33 +491,33 @@ msgstr "" "用來連結至基調演講頁面上的講者簡介,如「liang2」可連結至「{link}#keynote-" "speaker-liang2」。" -#: events/models.py:284 events/models.py:403 events/models.py:439 +#: events/models.py:278 events/models.py:397 events/models.py:433 msgid "is remote" msgstr "遠端演講" -#: events/models.py:288 events/models.py:363 events/models.py:407 -#: events/models.py:443 +#: events/models.py:282 events/models.py:357 events/models.py:401 +#: events/models.py:437 msgid "youtube id" msgstr "youtube id" -#: events/models.py:294 +#: events/models.py:288 msgid "keynote event" msgstr "基調演講" -#: events/models.py:295 +#: events/models.py:289 msgid "keynote events" msgstr "基調演講" -#: events/models.py:298 +#: events/models.py:292 #, python-brace-format msgid "Keynote: {speaker}" msgstr "基調演講:{speaker}" -#: events/models.py:337 sponsors/models.py:101 sponsors/models.py:117 +#: events/models.py:331 sponsors/models.py:97 sponsors/models.py:113 msgid "sponsor" msgstr "贊助" -#: events/models.py:342 events/models.py:343 +#: events/models.py:336 events/models.py:337 #: templates/pycontw-2020/_includes/menu.html:104 #: templates/pycontw-2020/contents/_default/events/job-listings.html:33 #: templates/pycontw-2021/contents/_default/events/job-listings.html:33 @@ -547,120 +527,48 @@ msgstr "贊助" msgid "Job Listings" msgstr "徵才資訊" -#: events/models.py:346 +#: events/models.py:340 #, python-brace-format msgid "Open Role of Sponsor: {sponsor}" msgstr "徵才中贊助商: {sponsor}" -#: events/models.py:355 +#: events/models.py:349 msgid "host" msgstr "主持人" -#: events/models.py:369 +#: events/models.py:363 msgid "sponsored event" msgstr "贊助演講" -#: events/models.py:370 +#: events/models.py:364 msgid "sponsored events" msgstr "贊助演講" -#: events/models.py:398 events/models.py:429 reviews/models.py:76 -#: reviews/models.py:197 +#: events/models.py:392 events/models.py:423 reviews/models.py:75 +#: reviews/models.py:196 msgid "proposal" msgstr "提案" -#: events/models.py:415 +#: events/models.py:409 msgid "talk event" msgstr "演講" -#: events/models.py:416 +#: events/models.py:410 msgid "talk events" msgstr "演講" -#: events/models.py:434 +#: events/models.py:428 msgid "registration link" msgstr "報名連結" -#: events/models.py:451 +#: events/models.py:445 msgid "tutorial event" msgstr "專業課程" -#: events/models.py:452 +#: events/models.py:446 msgid "tutorial events" msgstr "專業課程" -#: events/models.py:466 -msgid "HTML" -msgstr "HTML" - -#: events/models.py:474 templates/pycontw-2016/_includes/nav/front_nav.html:40 -#: templates/pycontw-2016/events/schedule.html:6 -#: templates/pycontw-2016/events/schedule.html:8 -#: templates/pycontw-2017/contents/_default/portal.html:16 -#: templates/pycontw-2017/events/schedule.html:6 -#: templates/pycontw-2017/events/schedule.html:17 -#: templates/pycontw-2018/_includes/menu.html:54 -#: templates/pycontw-2018/contents/_default/portal.html:17 -#: templates/pycontw-2018/events/schedule.html:6 -#: templates/pycontw-2018/events/schedule.html:20 -#: templates/pycontw-2019/_includes/menu.html:59 -#: templates/pycontw-2019/_includes/portal.html:4 -#: templates/pycontw-2019/events/schedule.html:6 -#: templates/pycontw-2019/events/schedule.html:20 -#: templates/pycontw-2020/_includes/menu.html:80 -#: templates/pycontw-2020/_includes/portal.html:4 -#: templates/pycontw-2020/events/schedule.html:6 -#: templates/pycontw-2020/events/schedule.html:21 -#: templates/pycontw-2021/_includes/portal.html:4 -#: templates/pycontw-2021/events/schedule.html:6 -#: templates/pycontw-2021/events/schedule.html:21 -#: templates/pycontw-2022/_includes/portal.html:4 -#: templates/pycontw-2022/events/schedule.html:6 -#: templates/pycontw-2022/events/schedule.html:21 -#: templates/pycontw-2023/_includes/portal.html:4 -#: templates/pycontw-2023/events/schedule.html:6 -#: templates/pycontw-2023/events/schedule.html:21 -#: templates/pycontw-2024/_includes/portal.html:4 -#: templates/pycontw-2024/events/schedule.html:6 -#: templates/pycontw-2024/events/schedule.html:21 -msgid "Schedule" -msgstr "時間表" - -#: events/models.py:475 -msgid "Schedules" -msgstr "時間表" - -#: events/models.py:480 -msgid "Schedule created at {}" -msgstr "時間表建立於 {}" - -#: events/renderers.py:34 -msgid "Keynote" -msgstr "基調演講" - -#: events/renderers.py:43 -msgid "EN Slides" -msgstr "英文投影片" - -# #: events/models.py:126 -# msgid "R4" -# msgstr "R4" -#: events/templatetags/events.py:18 -msgid "Multifunction room" -msgstr "多功能廳" - -#: events/templatetags/events.py:19 -msgid "Goodideas Studio" -msgstr "好想工作室" - -#: events/templatetags/events.py:20 -msgid "R1, R2, R3" -msgstr "R1、R2、R3" - -#: events/views.py:121 -msgid "New talk schedule generated successfully." -msgstr "演講時間表產生成功。" - #: proposals/forms/mixins.py:16 #, python-brace-format msgid "" @@ -840,178 +748,178 @@ msgstr "" msgid "duration" msgstr "時間長度" -#: proposals/forms/speakers.py:19 +#: proposals/forms/speakers.py:18 msgid "speaker email" msgstr "講者 email" -#: proposals/forms/speakers.py:21 +#: proposals/forms/speakers.py:20 msgid "" "The speaker should have a registered account, and have completed both email " "validation and the speaker profile." msgstr "講者應該已於 tw.pycon.org 註冊帳號,並且完成 email 認證與講者資訊。" -#: proposals/forms/speakers.py:29 +#: proposals/forms/speakers.py:28 #, python-brace-format msgid "" "Only authenticated user with complete speaker profile may create an " "{model_name}." msgstr "只有完成認證並填寫講者資訊的人才能建立 {model_name}。" -#: proposals/forms/speakers.py:33 +#: proposals/forms/speakers.py:32 msgid "Additional speaker creation requires a proposal instance." msgstr "增加額外講者需要一個已建立的提案。" -#: proposals/forms/speakers.py:36 +#: proposals/forms/speakers.py:35 msgid "User can only add additional speakers to owned proposals." msgstr "使用者只能對自己的提案增加額外講者。" -#: proposals/forms/speakers.py:39 +#: proposals/forms/speakers.py:38 msgid "This user is already a speaker for the proposal." msgstr "本使用者已經是此提案的講者。" -#: proposals/forms/speakers.py:41 +#: proposals/forms/speakers.py:40 msgid "No valid speaker found with your selection." msgstr "您的選擇找不到對應講者。" -#: proposals/models.py:55 +#: proposals/models.py:60 msgid "Proposal author" msgstr "提案人" -#: proposals/models.py:68 +#: proposals/models.py:73 msgid "proposal model type" msgstr "提案 model 類型" -#: proposals/models.py:72 +#: proposals/models.py:77 msgid "proposal ID" msgstr "提案 ID" -#: proposals/models.py:80 +#: proposals/models.py:85 msgid "Pending" msgstr "待回覆" -#: proposals/models.py:81 proposals/models.py:160 +#: proposals/models.py:86 proposals/models.py:162 msgid "Accepted" msgstr "已接受" -#: proposals/models.py:82 +#: proposals/models.py:87 msgid "Declined" msgstr "被拒絕" -#: proposals/models.py:91 proposals/models.py:153 +#: proposals/models.py:96 proposals/models.py:155 msgid "cancelled" msgstr "已取消" -#: proposals/models.py:99 +#: proposals/models.py:104 msgid "additional speaker" msgstr "額外講者" -#: proposals/models.py:100 +#: proposals/models.py:105 msgid "additional speakers" msgstr "額外講者" -#: proposals/models.py:132 +#: proposals/models.py:134 msgid "submitter" msgstr "提案人" -#: proposals/models.py:137 +#: proposals/models.py:139 msgid "outline" msgstr "大綱" -#: proposals/models.py:142 +#: proposals/models.py:144 msgid "objective" msgstr "演講目標" -#: proposals/models.py:147 +#: proposals/models.py:149 msgid "supplementary" msgstr "補充資訊" -#: proposals/models.py:161 +#: proposals/models.py:163 msgid "Rejected" msgstr "已拒絕" -#: proposals/models.py:164 +#: proposals/models.py:166 msgid "accepted" msgstr "已接受" -#: proposals/models.py:178 +#: proposals/models.py:180 msgid "labels" msgstr "" -#: proposals/models.py:263 proposals/models.py:317 +#: proposals/models.py:264 proposals/models.py:318 #: templates/default/_includes/proposal_example_modal.html:50 #: templates/default/_includes/proposal_example_modal.html:67 #: templates/default/reviews/review_form.html:40 msgid "Duration" msgstr "時間長度" -#: proposals/models.py:268 +#: proposals/models.py:269 msgid "Yes, it is my first time speaking at PyCon Taiwan." msgstr "是,我第一次擔任 PyCon Taiwan 講者" -#: proposals/models.py:269 +#: proposals/models.py:270 msgid "No, I have given talks at PyCon Taiwan in the past." msgstr "否,我過去曾擔任過 PyCon Taiwan 講者" -#: proposals/models.py:273 +#: proposals/models.py:274 msgid "first time speaker" msgstr "第一次擔任講者" -#: proposals/models.py:278 +#: proposals/models.py:279 msgid "talk proposal" msgstr "演講提案" -#: proposals/models.py:279 +#: proposals/models.py:280 msgid "talk proposals" msgstr "演講提案" -#: proposals/models.py:313 +#: proposals/models.py:314 msgid "1.5hr" msgstr "1.5 小時" -#: proposals/models.py:324 +#: proposals/models.py:325 msgid "tutorial proposal" msgstr "專業課程提案" -#: proposals/models.py:325 +#: proposals/models.py:326 msgid "tutorial proposals" msgstr "專業課程提案" -#: proposals/utils.py:4 +#: proposals/utils.py:3 msgctxt "speaker name default separator" msgid ", " msgstr "、" -#: proposals/utils.py:5 +#: proposals/utils.py:4 msgctxt "speaker name last separator" msgid " and " msgstr "、" -#: proposals/views/cancel.py:36 +#: proposals/views/cancel.py:35 #, python-brace-format msgid "Talk proposal {title} withdrawn." msgstr "《{title}》演講提案已撤回。" -#: proposals/views/cancel.py:40 +#: proposals/views/cancel.py:39 #, python-brace-format msgid "Talk proposal {title} reactivated." msgstr "《{title}》演講提案已重新提交。" -#: proposals/views/cancel.py:58 +#: proposals/views/cancel.py:57 #, python-brace-format msgid "Tutorial proposal {title} withdrawn." msgstr "《{title}》專業課程提案已撤回。" -#: proposals/views/cancel.py:62 +#: proposals/views/cancel.py:61 #, python-brace-format msgid "Tutorial proposal {title} reactivated." msgstr "《{title}》專業課程提案已重新提交。" -#: proposals/views/create.py:42 +#: proposals/views/create.py:41 #, python-brace-format msgid "Talk proposal {title} created." msgstr "已建立題目為《{title}》的演講提案。" -#: proposals/views/create.py:52 +#: proposals/views/create.py:51 #, python-brace-format msgid "Tutorial proposal {title} created." msgstr "已建立題目為《{title}》的專業課程提案。" @@ -1197,62 +1105,60 @@ msgstr "" "5. Q&A [5min]\n" "\n" -#: proposals/views/update.py:61 +#: proposals/views/update.py:64 #, python-brace-format msgid "Talk proposal {title} updated." msgstr "已完成更新《{title}》演講提案。" -#: proposals/views/update.py:70 +#: proposals/views/update.py:73 #, python-brace-format msgid "Tutorial proposal {title} updated." msgstr "已完成更新《{title}》專業課程提案。" -#: pycontw2016/settings/base.py:301 +#: pycontw2016/settings/base.py:306 msgid "PyCon Taiwan 2016" msgstr "PyCon Taiwan 2016" -#: pycontw2016/settings/base.py:302 templates/pycontw-2017/index.html:6 +#: pycontw2016/settings/base.py:307 templates/pycontw-2017/index.html:6 msgid "PyCon Taiwan 2017" msgstr "PyCon Taiwan 2017" -#: pycontw2016/settings/base.py:303 templates/pycontw-2018/index.html:14 +#: pycontw2016/settings/base.py:308 templates/pycontw-2018/index.html:14 msgid "PyCon Taiwan 2018" msgstr "PyCon Taiwan 2018" -#: pycontw2016/settings/base.py:304 templates/pycontw-2019/index.html:14 +#: pycontw2016/settings/base.py:309 templates/pycontw-2019/index.html:14 msgid "PyCon Taiwan 2019" msgstr "PyCon Taiwan 2019" -#: pycontw2016/settings/base.py:305 templates/pycontw-2020/index.html:14 +#: pycontw2016/settings/base.py:310 templates/pycontw-2020/index.html:14 msgid "PyCon Taiwan 2020" msgstr "PyCon Taiwan 2020" -#: pycontw2016/settings/base.py:306 templates/pycontw-2021/index.html:14 +#: pycontw2016/settings/base.py:311 templates/pycontw-2021/index.html:14 #: templates/pycontw-2022/index.html:14 templates/pycontw-2023/index.html:14 #: templates/pycontw-2024/index.html:14 msgid "PyCon Taiwan 2021" msgstr "PyCon Taiwan 2021" -#: pycontw2016/settings/base.py:307 +#: pycontw2016/settings/base.py:312 msgid "PyCon Taiwan 2022" msgstr "PyCon Taiwan 2022" -#: pycontw2016/settings/base.py:308 +#: pycontw2016/settings/base.py:313 msgid "PyCon Taiwan 2023" msgstr "PyCon Taiwan 2023" -#: pycontw2016/settings/base.py:309 -#, fuzzy -#| msgid "PyCon Taiwan 2020" +#: pycontw2016/settings/base.py:314 msgid "PyCon Taiwan 2024" -msgstr "PyCon Taiwan 2020" +msgstr "PyCon Taiwan 2024" -#: pycontw2016/settings/base.py:322 +#: pycontw2016/settings/base.py:327 #: pycontw2016/settings/production/pycontw2016.py:16 -#: pycontw2016/settings/production/pycontw2021.py:15 -#: pycontw2016/settings/production/pycontw2022.py:14 -#: pycontw2016/settings/production/pycontw2023.py:14 -#: pycontw2016/settings/production/pycontw2024.py:14 +#: pycontw2016/settings/production/pycontw2021.py:16 +#: pycontw2016/settings/production/pycontw2022.py:16 +#: pycontw2016/settings/production/pycontw2023.py:16 +#: pycontw2016/settings/production/pycontw2024.py:16 #: pycontw2016/settings/testing/pycontw2021.py:11 #: pycontw2016/settings/testing/pycontw2022.py:11 #: pycontw2016/settings/testing/pycontw2023.py:11 @@ -1260,11 +1166,11 @@ msgstr "PyCon Taiwan 2020" msgid "No preference" msgstr "無偏好" -#: pycontw2016/settings/base.py:323 -#: pycontw2016/settings/production/pycontw2021.py:16 -#: pycontw2016/settings/production/pycontw2022.py:15 -#: pycontw2016/settings/production/pycontw2023.py:15 -#: pycontw2016/settings/production/pycontw2024.py:15 +#: pycontw2016/settings/base.py:328 +#: pycontw2016/settings/production/pycontw2021.py:17 +#: pycontw2016/settings/production/pycontw2022.py:17 +#: pycontw2016/settings/production/pycontw2023.py:17 +#: pycontw2016/settings/production/pycontw2024.py:17 #: pycontw2016/settings/testing/pycontw2021.py:12 #: pycontw2016/settings/testing/pycontw2022.py:12 #: pycontw2016/settings/testing/pycontw2023.py:12 @@ -1272,11 +1178,11 @@ msgstr "無偏好" msgid "Prefer 15min" msgstr "偏好 15 分鐘" -#: pycontw2016/settings/base.py:324 -#: pycontw2016/settings/production/pycontw2021.py:17 -#: pycontw2016/settings/production/pycontw2022.py:16 -#: pycontw2016/settings/production/pycontw2023.py:16 -#: pycontw2016/settings/production/pycontw2024.py:16 +#: pycontw2016/settings/base.py:329 +#: pycontw2016/settings/production/pycontw2021.py:18 +#: pycontw2016/settings/production/pycontw2022.py:18 +#: pycontw2016/settings/production/pycontw2023.py:18 +#: pycontw2016/settings/production/pycontw2024.py:18 #: pycontw2016/settings/testing/pycontw2021.py:13 #: pycontw2016/settings/testing/pycontw2022.py:13 #: pycontw2016/settings/testing/pycontw2023.py:13 @@ -1284,13 +1190,13 @@ msgstr "偏好 15 分鐘" msgid "Prefer 30min" msgstr "偏好 30 分鐘" -#: pycontw2016/settings/base.py:328 +#: pycontw2016/settings/base.py:333 #: pycontw2016/settings/production/pycontw2016.py:22 #: templates/pycontw-2016/events/schedule.html:42 msgid "Day 1" msgstr "第 1 天" -#: pycontw2016/settings/base.py:329 +#: pycontw2016/settings/base.py:334 #: pycontw2016/settings/production/pycontw2016.py:23 #: templates/pycontw-2016/events/schedule.html:45 msgid "Day 2" @@ -1301,10 +1207,10 @@ msgid "Prefer 25min" msgstr "偏好 25 分鐘" #: pycontw2016/settings/production/pycontw2016.py:18 -#: pycontw2016/settings/production/pycontw2021.py:18 -#: pycontw2016/settings/production/pycontw2022.py:17 -#: pycontw2016/settings/production/pycontw2023.py:17 -#: pycontw2016/settings/production/pycontw2024.py:17 +#: pycontw2016/settings/production/pycontw2021.py:19 +#: pycontw2016/settings/production/pycontw2022.py:19 +#: pycontw2016/settings/production/pycontw2023.py:19 +#: pycontw2016/settings/production/pycontw2024.py:19 #: pycontw2016/settings/testing/pycontw2021.py:14 #: pycontw2016/settings/testing/pycontw2022.py:14 #: pycontw2016/settings/testing/pycontw2023.py:14 @@ -1340,35 +1246,35 @@ msgstr "{model_name_cap} 的建立需要一個 proposal 物件。" msgid "Could not review proposal {proposal}." msgstr "無法審查提案 {proposal}。" -#: reviews/models.py:66 +#: reviews/models.py:65 msgid "reviewer" msgstr "審查者" -#: reviews/models.py:71 reviews/models.py:202 +#: reviews/models.py:70 reviews/models.py:201 msgid "stage" msgstr "階段" -#: reviews/models.py:90 +#: reviews/models.py:89 msgid "+1 (strong accept)" msgstr "+1(高度肯定地接受)" -#: reviews/models.py:91 +#: reviews/models.py:90 msgid "+0 (weak accept)" msgstr "+0(輕微贊成)" -#: reviews/models.py:92 +#: reviews/models.py:91 msgid "-0 (weak reject)" msgstr "−0(輕微反對)" -#: reviews/models.py:93 +#: reviews/models.py:92 msgid "-1 (strong reject)" msgstr "–1(高度肯定地拒絕)" -#: reviews/models.py:102 +#: reviews/models.py:101 msgid "vote" msgstr "投票" -#: reviews/models.py:104 +#: reviews/models.py:103 msgid "" "Your vote to accept or reject this talk. More information about the scoring " "and acceptance criteria can be found at the GitBook 審稿指南 " "GitBook。" -#: reviews/models.py:113 +#: reviews/models.py:112 msgid "comment" msgstr "評論" -#: reviews/models.py:115 +#: reviews/models.py:114 msgid "" "Comments to this proposal. This may be available for other reviewers in " "later review stages, and you can choose whether or not to disclose it to the " @@ -1392,11 +1298,11 @@ msgstr "" "對於本提案的評論。本欄位內容將在之後的審查階段讓其他審查者看見,您可以選擇要" "或不要讓本提案的投稿者知道您的評論。 " -#: reviews/models.py:128 +#: reviews/models.py:127 msgid "discloses comment to proposal submitter" msgstr "讓本提案的投稿者知道您的評論" -#: reviews/models.py:130 +#: reviews/models.py:129 msgid "" "Whether the proposal submitter can read you comments. We will include your " "comments in the proposal acceptance/rejection notice sent to the submitter " @@ -1405,11 +1311,11 @@ msgstr "" "本提案的投稿者是否能知道您的評論。我們會在通知提案接受或拒絕結果時,如果您同" "意讓投稿者知道,將這些評論加在通知結果中。" -#: reviews/models.py:143 +#: reviews/models.py:142 msgid "is appropriate" msgstr "認可" -#: reviews/models.py:145 +#: reviews/models.py:144 msgid "" "Administrators can use this field to hide a review from submitters, even if " "the reviewer enables disclosure. The review may be shown to the submitter " @@ -1418,11 +1324,11 @@ msgstr "" "管理員可以用這個欄位隱藏某個審稿意見,不讓投稿人看見(即使審稿人要求揭露)。" "只有當這個欄位設為 True 時,審稿意見才會被顯示給投稿人。" -#: reviews/models.py:153 +#: reviews/models.py:152 msgid "note" msgstr "附註" -#: reviews/models.py:155 +#: reviews/models.py:154 msgid "" "Personal notes about this proposal. You can use this field to record " "anything you like during the review process. We promise to never disclose " @@ -1431,146 +1337,146 @@ msgstr "" "個人對本投稿的附註。您可以使用這個欄位記錄有關審查的任何資訊。我們不會把這欄" "位的資訊公布給任何人,只有您知道。" -#: reviews/models.py:163 +#: reviews/models.py:162 msgid "updated" msgstr "更新時間" -#: reviews/models.py:168 +#: reviews/models.py:167 msgid "review" msgstr "審查" -#: reviews/models.py:169 +#: reviews/models.py:168 msgid "reviews" msgstr "審查" -#: reviews/models.py:174 +#: reviews/models.py:173 #, python-brace-format msgid "Review {proposal} by {reviewer}: {vote}" msgstr "提案《{proposal}》審查:{vote}({reviewer})" -#: reviews/models.py:206 +#: reviews/models.py:205 msgid "dumped JSON" msgstr "匯出 JSON" -#: reviews/models.py:210 +#: reviews/models.py:209 msgid "dumped at" msgstr "匯出於" -#: reviews/models.py:215 +#: reviews/models.py:214 msgid "talk proposal snapshot" msgstr "演講投稿封存" -#: reviews/models.py:216 +#: reviews/models.py:215 msgid "talk proposal snapshots" msgstr "演講投稿封存" -#: reviews/models.py:220 +#: reviews/models.py:219 #, python-brace-format msgid "Stage {stage} dump for {proposal}" msgstr "第 {stage} 階段封存《{proposal}》" -#: sponsors/models.py:27 +#: sponsors/models.py:23 msgid "name" msgstr "名稱" -#: sponsors/models.py:31 +#: sponsors/models.py:27 msgid "website URL" msgstr "網站 URL" -#: sponsors/models.py:35 +#: sponsors/models.py:31 msgid "introduction" msgstr "簡介" -#: sponsors/models.py:38 +#: sponsors/models.py:34 msgid "subtitle" msgstr "副標題" -#: sponsors/models.py:43 +#: sponsors/models.py:39 msgid "logo (SVG)" msgstr "logo (SVG)" -#: sponsors/models.py:46 +#: sponsors/models.py:42 msgid "" "Vector format of the logo, in SVG. This takes precedence to the raster " "format, if available." msgstr "即使有點陣式圖形格式的圖標,還是會優先採用向量式SVG格式的圖標。" -#: sponsors/models.py:51 +#: sponsors/models.py:47 msgid "logo (image)" msgstr "logo (圖片)" -#: sponsors/models.py:55 +#: sponsors/models.py:51 msgid "" "Raster format of the logo, e.g. PNG, JPEG. This is used as fallback when the " "SVG file is not available." msgstr "" "當SVG格式的檔案不存在時,會回過頭來使用點陣式格式的圖標,例如PNG、JPEG。" -#: sponsors/models.py:60 +#: sponsors/models.py:56 msgid "order" msgstr "排序" -#: sponsors/models.py:80 +#: sponsors/models.py:76 msgid "platinum" msgstr "白金級" -#: sponsors/models.py:81 +#: sponsors/models.py:77 msgid "gold" msgstr "金級" -#: sponsors/models.py:82 +#: sponsors/models.py:78 msgid "silver" msgstr "銀級" -#: sponsors/models.py:83 +#: sponsors/models.py:79 msgid "bronze" msgstr "銅級" -#: sponsors/models.py:84 +#: sponsors/models.py:80 msgid "special" msgstr "特別贊助" -#: sponsors/models.py:85 +#: sponsors/models.py:81 msgid "special-thanks" msgstr "特別感謝" -#: sponsors/models.py:86 +#: sponsors/models.py:82 msgid "organizer" msgstr "主辦單位" -#: sponsors/models.py:87 +#: sponsors/models.py:83 msgid "co-organizer" msgstr "協辦單位" -#: sponsors/models.py:96 +#: sponsors/models.py:92 msgid "level" msgstr "等級" -#: sponsors/models.py:102 +#: sponsors/models.py:98 msgid "sponsors" msgstr "贊助" -#: sponsors/models.py:122 +#: sponsors/models.py:118 msgid "open role name" msgstr "職缺名稱" -#: sponsors/models.py:127 +#: sponsors/models.py:123 msgid "open role descsription" msgstr "職缺說明" -#: sponsors/models.py:131 +#: sponsors/models.py:127 msgid "open role requirements" msgstr "職缺需求" -#: sponsors/models.py:136 +#: sponsors/models.py:132 msgid "open role URL" msgstr "職缺 URL" -#: sponsors/models.py:141 +#: sponsors/models.py:137 msgid "open role" msgstr "職缺" -#: sponsors/models.py:142 +#: sponsors/models.py:138 msgid "open Roles" msgstr "職缺" @@ -1823,7 +1729,7 @@ msgstr "修改專業課程提案《%(proposal_title)s》" #: templates/default/registration/login.html:5 #: templates/default/registration/login.html:7 #: templates/pycontw-2016/registration/login.html:7 -#: templates/pycontw-2016/registration/login.html:21 users/forms.py:261 +#: templates/pycontw-2016/registration/login.html:21 users/forms.py:265 msgid "Log In" msgstr "登入" @@ -1923,7 +1829,7 @@ msgid "Stage" msgstr "階段" #: templates/default/reviews/_includes/previous_review_table.html:7 -#: users/models.py:223 +#: users/models.py:221 msgid "Reviewer ID" msgstr "審稿人代號" @@ -2287,10 +2193,10 @@ msgstr "我們搞砸了,這不是你的問題。" #: templates/pycontw-2018/_includes/menu.html:29 #: templates/pycontw-2019/_includes/menu.html:31 #: templates/pycontw-2020/_includes/menu.html:42 -#: templates/pycontw-2021/_includes/menu.html:42 -#: templates/pycontw-2022/_includes/menu.html:42 -#: templates/pycontw-2023/_includes/menu.html:42 -#: templates/pycontw-2024/_includes/menu.html:42 +#: templates/pycontw-2021/_includes/menu.html:41 +#: templates/pycontw-2022/_includes/menu.html:41 +#: templates/pycontw-2023/_includes/menu.html:41 +#: templates/pycontw-2024/_includes/menu.html:41 msgid "About" msgstr "關於" @@ -2357,6 +2263,27 @@ msgstr "活動" msgid "Overview" msgstr "總覽" +#: templates/pycontw-2016/_includes/nav/front_nav.html:40 +#: templates/pycontw-2016/events/schedule.html:6 +#: templates/pycontw-2016/events/schedule.html:8 +#: templates/pycontw-2017/contents/_default/portal.html:16 +#: templates/pycontw-2017/events/schedule.html:6 +#: templates/pycontw-2017/events/schedule.html:17 +#: templates/pycontw-2018/_includes/menu.html:54 +#: templates/pycontw-2018/contents/_default/portal.html:17 +#: templates/pycontw-2018/events/schedule.html:6 +#: templates/pycontw-2018/events/schedule.html:20 +#: templates/pycontw-2019/_includes/menu.html:59 +#: templates/pycontw-2019/_includes/portal.html:4 +#: templates/pycontw-2019/events/schedule.html:6 +#: templates/pycontw-2019/events/schedule.html:20 +#: templates/pycontw-2020/_includes/menu.html:80 +#: templates/pycontw-2020/_includes/portal.html:4 +#: templates/pycontw-2020/events/schedule.html:6 +#: templates/pycontw-2020/events/schedule.html:21 +msgid "Schedule" +msgstr "時間表" + #: templates/pycontw-2016/_includes/nav/front_nav.html:41 #: templates/pycontw-2018/_includes/menu.html:55 #: templates/pycontw-2018/contents/en/events/overview.html:38 @@ -2553,10 +2480,6 @@ msgstr "跳至" #: templates/pycontw-2018/events/schedule_create.html:64 #: templates/pycontw-2019/events/schedule_create.html:60 #: templates/pycontw-2020/events/schedule_create.html:100 -#: templates/pycontw-2021/events/schedule_create.html:100 -#: templates/pycontw-2022/events/schedule_create.html:100 -#: templates/pycontw-2023/events/schedule_create.html:100 -#: templates/pycontw-2024/events/schedule_create.html:100 msgid "Schedule table generation requires JavaScript. Please. (´・_・`)" msgstr "需要 JavaScript 才能產生時間表。求求你~ (´・_・`)" @@ -2565,10 +2488,6 @@ msgstr "需要 JavaScript 才能產生時間表。求求你~ (´・_・`)" #: templates/pycontw-2018/events/schedule_create.html:73 #: templates/pycontw-2019/events/schedule_create.html:69 #: templates/pycontw-2020/events/schedule_create.html:109 -#: templates/pycontw-2021/events/schedule_create.html:109 -#: templates/pycontw-2022/events/schedule_create.html:109 -#: templates/pycontw-2023/events/schedule_create.html:109 -#: templates/pycontw-2024/events/schedule_create.html:109 msgid "Generate" msgstr "產生" @@ -2899,10 +2818,10 @@ msgstr "傳送門" #: templates/pycontw-2018/contents/_default/portal.html:21 #: templates/pycontw-2019/_includes/portal.html:8 #: templates/pycontw-2020/_includes/portal.html:8 -#: templates/pycontw-2021/_includes/portal.html:8 -#: templates/pycontw-2022/_includes/portal.html:8 -#: templates/pycontw-2023/_includes/portal.html:8 -#: templates/pycontw-2024/_includes/portal.html:8 +#: templates/pycontw-2021/_includes/portal.html:4 +#: templates/pycontw-2022/_includes/portal.html:4 +#: templates/pycontw-2023/_includes/portal.html:4 +#: templates/pycontw-2024/_includes/portal.html:4 msgid "Collaborative Notes" msgstr "共筆" @@ -2921,10 +2840,10 @@ msgstr "猜謎排行榜" #: templates/pycontw-2018/contents/_default/portal.html:29 #: templates/pycontw-2019/_includes/portal.html:16 #: templates/pycontw-2020/_includes/portal.html:16 -#: templates/pycontw-2021/_includes/portal.html:16 -#: templates/pycontw-2022/_includes/portal.html:16 -#: templates/pycontw-2023/_includes/portal.html:16 -#: templates/pycontw-2024/_includes/portal.html:16 +#: templates/pycontw-2021/_includes/portal.html:12 +#: templates/pycontw-2022/_includes/portal.html:12 +#: templates/pycontw-2023/_includes/portal.html:12 +#: templates/pycontw-2024/_includes/portal.html:12 msgid "Facebook Fan Page" msgstr "Facebook 粉絲頁" @@ -2964,14 +2883,6 @@ msgstr "非正式會議" #: templates/pycontw-2019/events/schedule_create.html:15 #: templates/pycontw-2020/events/schedule_create.html:7 #: templates/pycontw-2020/events/schedule_create.html:16 -#: templates/pycontw-2021/events/schedule_create.html:7 -#: templates/pycontw-2021/events/schedule_create.html:16 -#: templates/pycontw-2022/events/schedule_create.html:7 -#: templates/pycontw-2022/events/schedule_create.html:16 -#: templates/pycontw-2023/events/schedule_create.html:7 -#: templates/pycontw-2023/events/schedule_create.html:16 -#: templates/pycontw-2024/events/schedule_create.html:7 -#: templates/pycontw-2024/events/schedule_create.html:16 msgid "Export New Schedule" msgstr "輸出新時間表" @@ -3180,10 +3091,10 @@ msgstr "報到" #: templates/pycontw-2018/_includes/menu.html:89 #: templates/pycontw-2019/_includes/menu.html:94 #: templates/pycontw-2020/_includes/menu.html:138 -#: templates/pycontw-2021/_includes/menu.html:152 -#: templates/pycontw-2022/_includes/menu.html:152 -#: templates/pycontw-2023/_includes/menu.html:152 -#: templates/pycontw-2024/_includes/menu.html:152 +#: templates/pycontw-2021/_includes/menu.html:150 +#: templates/pycontw-2022/_includes/menu.html:150 +#: templates/pycontw-2023/_includes/menu.html:150 +#: templates/pycontw-2024/_includes/menu.html:150 msgid "My PyCon" msgstr "My PyCon" @@ -4310,27 +4221,27 @@ msgid "Warm-Up Session" msgstr "暖身活動" #: templates/pycontw-2020/_includes/menu.html:132 -#: templates/pycontw-2021/_includes/menu.html:146 -#: templates/pycontw-2022/_includes/menu.html:146 -#: templates/pycontw-2023/_includes/menu.html:146 -#: templates/pycontw-2024/_includes/menu.html:146 +#: templates/pycontw-2021/_includes/menu.html:144 +#: templates/pycontw-2022/_includes/menu.html:144 +#: templates/pycontw-2023/_includes/menu.html:144 +#: templates/pycontw-2024/_includes/menu.html:144 msgctxt "COVID-19 Guidelines" msgid "COVID-19 Guidelines" msgstr "COVID-19 防疫守則" #: templates/pycontw-2020/_includes/portal.html:12 -#: templates/pycontw-2021/_includes/portal.html:12 -#: templates/pycontw-2022/_includes/portal.html:12 -#: templates/pycontw-2023/_includes/portal.html:12 -#: templates/pycontw-2024/_includes/portal.html:12 +#: templates/pycontw-2021/_includes/portal.html:8 +#: templates/pycontw-2022/_includes/portal.html:8 +#: templates/pycontw-2023/_includes/portal.html:8 +#: templates/pycontw-2024/_includes/portal.html:8 msgid "Discord Chat Room" msgstr "Discord 聊天室" #: templates/pycontw-2020/_includes/portal.html:20 -#: templates/pycontw-2021/_includes/portal.html:20 -#: templates/pycontw-2022/_includes/portal.html:20 -#: templates/pycontw-2023/_includes/portal.html:20 -#: templates/pycontw-2024/_includes/portal.html:20 +#: templates/pycontw-2021/_includes/portal.html:16 +#: templates/pycontw-2022/_includes/portal.html:16 +#: templates/pycontw-2023/_includes/portal.html:16 +#: templates/pycontw-2024/_includes/portal.html:16 msgid "Open space" msgstr "Open space 揪團" @@ -4920,40 +4831,40 @@ msgstr "權限" msgid "Important dates" msgstr "重要日期" -#: users/forms.py:28 +#: users/forms.py:32 msgid "A user with that email already exists." msgstr "此電子郵件信箱已被使用。" -#: users/forms.py:29 +#: users/forms.py:33 msgid "The two password fields didn't match." msgstr "密碼欄位內容不一致。" -#: users/forms.py:32 users/forms.py:201 +#: users/forms.py:36 users/forms.py:205 msgid "Password" msgstr "密碼" -#: users/forms.py:36 +#: users/forms.py:40 msgid "Password confirmation" msgstr "密碼確認" -#: users/forms.py:117 +#: users/forms.py:121 msgid "Create Account" msgstr "新建帳號" -#: users/forms.py:148 +#: users/forms.py:152 #, python-brace-format msgid "Your image is too small ({width}\\u00d7{height} pixels)." msgstr "提供的圖片過小({width}\\u00d7{height} 像素)。" -#: users/forms.py:150 +#: users/forms.py:154 msgid "The image you provided is not quadrate." msgstr "提供的圖片並非方型。" -#: users/forms.py:151 +#: users/forms.py:155 msgid "Your image size is too big (>10M)" msgstr "提供的圖片檔案過大 (>10M)" -#: users/forms.py:202 +#: users/forms.py:206 msgid "" "Raw passwords are not stored, so there is no way to see this user's " "password, but you can change the password using this " @@ -4962,59 +4873,59 @@ msgstr "" "原始的密碼並沒有儲存在資料庫中,因此沒有任何方法能看到本使用者的密碼,但你可" "以透過本表單更改密碼。" -#: users/forms.py:251 +#: users/forms.py:255 #, python-brace-format msgid "" "Forgot Password" msgstr "忘記密碼" -#: users/forms.py:255 +#: users/forms.py:259 #, python-brace-format msgid "Sign up now" msgstr "註冊帳號" -#: users/forms.py:272 +#: users/forms.py:276 msgid "Email Address" msgstr "電子郵件信箱" -#: users/forms.py:291 +#: users/forms.py:295 msgid "Request Password Reset" msgstr "申請密碼重設" -#: users/forms.py:327 +#: users/forms.py:331 msgid "Set Password" msgstr "設定密碼" -#: users/forms.py:339 +#: users/forms.py:343 msgid "I agree to the code of conduct." msgstr "我同意行為準則。" -#: users/forms.py:344 +#: users/forms.py:348 msgid "You must agree to continue." msgstr "你必須同意才能繼續下一步。" -#: users/models.py:114 +#: users/models.py:112 msgid "email address" msgstr "電子郵件信箱" -#: users/models.py:122 +#: users/models.py:120 msgid "biography" msgstr "自我介紹" -#: users/models.py:125 +#: users/models.py:123 msgid "" "Describe yourself with 1000 characters or less. There will be no formatting." msgstr "使用少於 1000 個字元介紹您自己。本欄位不含任何格式。" -#: users/models.py:130 +#: users/models.py:128 msgid "photo" msgstr "個人照" -#: users/models.py:134 +#: users/models.py:132 msgid "Facebook" msgstr "Facebook" -#: users/models.py:137 +#: users/models.py:135 msgid "" "Link to your Facebook profile page. This will be shown when we display your " "public information. If you do not know what your profile page link is, click " @@ -5025,97 +4936,109 @@ msgstr "" "人頁連結為何,可以使用" "這個連結,並將開啟頁面的網址列內容貼至本欄位。記得先登入 Facebook!" -#: users/models.py:146 +#: users/models.py:144 msgid "Twitter" msgstr "Twitter" -#: users/models.py:151 +#: users/models.py:149 msgid "" "Your Twitter handle, without the \"@\" sign. This will be shown when we " "display your public information." msgstr "您的 Twitter 帳號,不包含 @ 符號。這個名稱會出現在您的公開資料中。" -#: users/models.py:156 +#: users/models.py:154 msgid "GitHub" msgstr "GitHub" -#: users/models.py:161 +#: users/models.py:159 msgid "" "Your GitHub account, without the \"@\" sign. This will be shown when we " "display your public information." msgstr "您的 GitHub 帳號,不包含 @ 符號。這個名稱會出現在您的公開資料中。" -#: users/models.py:169 +#: users/models.py:167 msgid "Designates whether the user has verified email ownership." msgstr "指定本使用者是否已完成 email 認證。" -#: users/models.py:173 +#: users/models.py:171 msgid "staff status" msgstr "管理員權限" -#: users/models.py:176 +#: users/models.py:174 msgid "Designates whether the user can log into this admin site." msgstr "指定本使用者是否可以登入本管理站台。" -#: users/models.py:180 +#: users/models.py:178 msgid "active" msgstr "已啟用" -#: users/models.py:183 +#: users/models.py:181 msgid "" "Designates whether this user should be treated as active. Unselect this " "instead of deleting accounts." msgstr "指定本使用者是否被視為 active。取消勾選此選項而非刪除帳號。" -#: users/models.py:188 +#: users/models.py:186 msgid "date joined" msgstr "註冊日期" -#: users/models.py:199 +#: users/models.py:197 msgid "users" msgstr "使用者" -#: users/models.py:299 +#: users/models.py:297 #, python-brace-format msgid "Verify your email address on {host}" msgstr "於 {host} 認證您的信箱地址" -#: users/models.py:317 +#: users/models.py:315 msgid "latest agreed CoC version" msgstr "最後同意的 CoC 版本" -#: users/models.py:321 +#: users/models.py:319 msgid "agreed at" msgstr "同意於" -#: users/views.py:42 +#: users/views.py:44 msgid "Sign up successful. You are now logged in." msgstr "註冊成功。您現在已被登入。" -#: users/views.py:59 +#: users/views.py:61 msgid "Email verification successful." msgstr "Email 認證成功。" -#: users/views.py:71 +#: users/views.py:73 #, python-brace-format msgid "A verification email has been sent to {email}" msgstr "一封認證用的 email 已經寄送至 {email}" -#: users/views.py:101 +#: users/views.py:103 msgid "Your profile has been updated successfully." msgstr "您的講者資訊已成功地更新。" -#: users/views.py:114 +#: users/views.py:116 msgid "Your new password has been applied successfully." msgstr "已成功地使用您的新密碼。" -#: users/views.py:121 +#: users/views.py:123 msgid "" "An email is sent to your email account. Please check your inbox for furthur " "instructions to reset your password." msgstr "" "一封電子郵件已經發送至您的信箱。請檢查您的收件匣並參照信中指示重設密碼。" -#: users/views.py:129 +#: users/views.py:131 msgid "Password reset successful. You can now login." msgstr "密碼重設成功。您現在即可登入。" + +#~ msgid "HTML" +#~ msgstr "HTML" + +#~ msgid "Keynote" +#~ msgstr "基調演講" + +#~ msgid "EN Slides" +#~ msgstr "英文投影片" + +#~ msgid "R1, R2, R3" +#~ msgstr "R1、R2、R3" diff --git a/src/pycontw2016/settings/base.py b/src/pycontw2016/settings/base.py index bcd6f63e6..e4f61fde9 100644 --- a/src/pycontw2016/settings/base.py +++ b/src/pycontw2016/settings/base.py @@ -44,7 +44,6 @@ 'django.template.context_processors.request', 'core.context_processors.script_prefix', 'core.context_processors.pycontw', - 'core.context_processors.events', 'core.context_processors.sponsors', 'core.context_processors.frontend_host', ], @@ -335,8 +334,6 @@ def node_bin(name): (datetime.date(2024, 9, 22), _('Day 2')), ]) -SCHEDULE_REDIRECT_URL = None - COC_VERSION = '2024.0' # Since 2021, pycon.tw has indivisual server hosting the attendee-facing pages diff --git a/src/static/css/main.scss b/src/static/css/main.scss index 565e2116f..4656ab34a 100644 --- a/src/static/css/main.scss +++ b/src/static/css/main.scss @@ -32,7 +32,6 @@ @import "pages/sponsors"; @import "pages/talks"; @import "pages/venue"; -@import "pages/schedule"; body { @@ -64,42 +63,6 @@ body { text-align: center; } -// schedule - -.schedule-wrapper { - @include make-xs-column(10); - @include make-xs-column-offset(1); - @include make-sm-column(12); - @include make-sm-column-offset(0); - @include make-md-column(10); - @include make-md-column-offset(1); -} -.schedule { - background-color: #fff; - padding-top: .6em; - border-radius: 4px; -} - -.schedule-block { - @include make-sm-column(4); - text-align: center; - color: $schedule-color; - font-size:24px; -} - -// visible in viewport > xs -.schedule__title--lg { - @include make-sm-column(4); - @extend .hidden-xs; - text-align: center; - color: $schedule__title-color; -} - -// visible when viewport < xs -.schedule__title { - @extend .visible-xs-block; - padding-top: .5em; -} // latest-news @@ -348,14 +311,6 @@ body { background-color: white; } -@media (max-width: $screen-sm){ - .schedule{ - padding-top: 0; - } - .schedule__title{ - padding-top: 0; - } -} @media (max-width: $screen-xs) { .sponsorship__call{ diff --git a/src/static/js/events/schedule.js b/src/static/js/events/schedule.js deleted file mode 100644 index 42b10e081..000000000 --- a/src/static/js/events/schedule.js +++ /dev/null @@ -1,28 +0,0 @@ -(function () { - -// $('.talk__title').addClass('hyphenate'); -// Hyphenator.config({useCSS3hyphenation: true}); -// Hyphenator.run(); - -$('.talk__title').dotdotdot({wrap: 'word', watch: true, fallbackToLetter: true}); - -// Scrollspy-like behavior to update the hash on scroll. -if (window.history && window.history.replaceState) { - $(document).on('scroll', function () { - var $document = $(this); - var ids = ['2016-06-05', '2016-06-04', '2016-06-03']; - var hash = ''; - $.each(ids, function () { - if ($document.scrollTop() >= $('#' + this).offset().top - 1) { - hash = '#' + this; - return false; - } - }); - if (hash !== window.location.hash) { - var nurl = window.location.pathname + window.location.search; - window.history.replaceState('', '', nurl + hash); - } - }); -} - -})(); diff --git a/src/static/js/events/schedule_gen.js b/src/static/js/events/schedule_gen.js deleted file mode 100644 index 103de3296..000000000 --- a/src/static/js/events/schedule_gen.js +++ /dev/null @@ -1,7 +0,0 @@ -(function ($) { - -var $form = $('.generation-form'); -$form.removeClass('hide'); -$form.find('input[name="html"]').val($('.schedule').html()); - -})(jQuery); diff --git a/src/static/pycontw-2021/_includes/base/_variables.scss b/src/static/pycontw-2021/_includes/base/_variables.scss index e45223f99..d52a722a0 100644 --- a/src/static/pycontw-2021/_includes/base/_variables.scss +++ b/src/static/pycontw-2021/_includes/base/_variables.scss @@ -10,10 +10,6 @@ $quote-color: $theme-focus; // section $section__heading-color: $theme-color; -// schedule -$schedule-color: #F58454; -$schedule__title-color: #ADCDFF; - // intro $intro__heading-color: $theme-color; $intro-color: #686868; diff --git a/src/static/pycontw-2021/scripts/schedule.js b/src/static/pycontw-2021/scripts/schedule.js deleted file mode 100644 index 478756338..000000000 --- a/src/static/pycontw-2021/scripts/schedule.js +++ /dev/null @@ -1,32 +0,0 @@ -// Schedule generation. -const form = document.querySelector('.generation-form') -if (form) { - const html = document.querySelector('.schedule-content').innerHTML - form.querySelector('input[name="html"]').value = html - form.style.display = 'block' -} - - -// Replace localed URL with current locale prefix. -const I18N = JSON.parse(document.getElementById('i18n_variables').textContent) -function findPrefix(u) { - const possiblePrefixes = [] - for (const prefix of I18N.LANGUAGE_PREFIXES) { - if (u.startsWith(prefix)) { - return prefix - } - } - return '' -} -for (const el of document.querySelectorAll('.localed-url')) { - const original = el.getAttribute('href') - if (!original) { - continue - } - const prefix = findPrefix(original) - if (!prefix) { - continue - } - const sub = original.substr(prefix.length) - el.setAttribute('href', `${I18N.LANGUAGE_PREFIX}${sub}`) -} diff --git a/src/static/pycontw-2021/styles/page.scss b/src/static/pycontw-2021/styles/page.scss index afab90859..0c57b6300 100644 --- a/src/static/pycontw-2021/styles/page.scss +++ b/src/static/pycontw-2021/styles/page.scss @@ -407,7 +407,6 @@ ul.custom_ul { @import "pages/ticket-info"; @import "pages/tutorials"; @import "pages/venue"; -@import "pages/schedule"; @import "pages/staff"; @import "pages/portal"; @import "pages/sponsorship-prospectus"; diff --git a/src/static/pycontw-2021/styles/pages/_events.scss b/src/static/pycontw-2021/styles/pages/_events.scss index 33fbad935..a343665ca 100644 --- a/src/static/pycontw-2021/styles/pages/_events.scss +++ b/src/static/pycontw-2021/styles/pages/_events.scss @@ -228,236 +228,3 @@ $icon-height: 26px; @include rooms(); } - -@mixin toggleTimetableOrTimeList() { - @media (min-width: 901px) { - .py-schedule-timetable { - display: initial; - - .room-tag { - display: none; - } - } - - .py-schedule-time-list { - display: none; - } - } - - @media (max-width: 900px) { - .py-schedule-timetable { - display: none; - } - - .py-schedule-time-list { - display: initial; - - .room-tag::before { - white-space: initial; - } - } - - .py-schedule-tabs__tab { - padding: 24px; - } - } -} - -main { - max-width: unset; - margin: unset; - padding: 24px; - - .py-schedule { - &-tabs { - display: flex; - justify-content: center; - align-items: center; - - &__tab { - margin: 0 24px 24px; - padding: 24px 72px; - font-family: $header-font-family; - font-size: 20px; - border-radius: 8px; - cursor: default; - - &:hover:not(.--active) { - color: red; - cursor: pointer; - } - - &.--active { - color: $jinger-bread; - background: $salmon; - } - } - } - - &-timetable { - &-header { - position: sticky; - top: 0; - z-index: 1000; - display: flex; - background: transparentize($brick, 0.3); - - &-column { - @include roomDisplayStyle(); - - margin: 8px 8px 8px 0; - padding: 12px 0; - font-size: 18px; - - &:last-child { - margin-right: 0; - } - - &.--timeline { - flex: 1; - background: transparent; - } - - &.--room { - flex: 2; - } - } - - @include rooms(); - - &:not(.--active) { - display: none; - } - } - - &-body { - display: grid; - grid-template-columns: - [times] 1fr - [room-4-r0-start] 2fr - [room-4-r0-end room-5-r1-start] 2fr - [room-5-r1-end room-6-r2-start] 2fr - [room-6-r2-end room-8-r3-start] 2fr - [room-8-r3-end room-7-r4-start] 2fr - [room-7-r4-end]; - grid-column-gap: 8px; - grid-row-gap: 8px; - - &-item { - @include eventItem(); - } - - .room-3-r012 { - grid-column: room-4-r0-start / room-6-r2-end; - } - - .room-4-r0 { - grid-column: room-4-r0-start / room-4-r0-end; - } - - .room-5-r1 { - grid-column: room-5-r1-start / room-5-r1-end; - } - - .room-6-r2 { - grid-column: room-6-r2-start / room-6-r2-end; - } - - .room-7-r4 { - grid-column: room-7-r4-start / room-7-r4-end; - } - - .room-1-r3 { - grid-column: room-8-r3-start / room-8-r3-end; - } - - .room-2-all { - grid-column: room-4-r0-start / room-8-r3-end; - } - - .timeline { - grid-column: times; - justify-self: center; - @include time(); - - &.--hour { - font-size: 20px; - font-weight: 500; - } - - &.--half-an-hour { - font-size: 18px; - } - } - - &:not(.--active) { - display: none; - } - } - } - - &-time-list { - &-section { - &-header { - position: sticky; - position: -webkit-sticky; - top: 0; - z-index: 10; - padding: 16px 0; - background: $brick; - - & > .time { - @include time(); - - font-size: 22px; - } - } - - &-items { - display: flex; - flex-direction: column; - margin: 12px 0; - - &-item { - @include eventItem(); - margin-bottom: 12px; - } - - .room-2-all { - order: 1; - } - - .room-3-r012 { - order: 2; - } - - .room-4-r0 { - order: 3; - } - - .room-5-r1 { - order: 4; - } - - .room-6-r2 { - order: 5; - } - - .room-1-r3 { - order: 6; - } - - .room-7-r4 { - order: 7; - } - } - } - - &:not(.--active) { - display: none; - } - } - } - - @include toggleTimetableOrTimeList(); -} diff --git a/src/static/pycontw-2021/styles/pages/_schedule.scss b/src/static/pycontw-2021/styles/pages/_schedule.scss deleted file mode 100644 index 96379039b..000000000 --- a/src/static/pycontw-2021/styles/pages/_schedule.scss +++ /dev/null @@ -1,342 +0,0 @@ -.schedule-page { - form .button-round { - @include button(276deg, $dark-peach, $maize); - width: 160px; - margin: 24px 0; - text-align: center; - cursor: pointer; - } - - // Icon - $icon-width: 26px; - $icon-height: 26px; - - @mixin icon($name, $margin-top: 0, $x: left, $width: $icon-width) { - &::before { - width: $width; - margin-top: $margin-top; // Visual compensation. - background: url('../assets/icon-#{$name}.svg') top $x no-repeat; - } - } - - @mixin icon-info() { - ul { - @include list-reset(); - text-indent: 0; - li { - - display: flex; - align-content: baseline; - align-items: flex-start; - - > * { - flex: 1; - min-height: 24px; - margin-bottom: 12px; - } - - &:before { - content: ' '; - height: $icon-height; - margin-right: 1rem; - } - - &.speech-en { - @include icon('language-enen', -1px); - } - &.speech-zh { - @include icon('language-zhzh', -1px); - } - &.slides-en { - @include icon('language-enen', 0, right); - } - &.slides-zh { - @include icon('language-zhzh', 0, right); - } - &.language-enen { - @include icon('language-enen', 0, center, 2 * $icon-width); - } - &.language-zhen { - @include icon('language-zhen', 0, center, 2 * $icon-width); - } - &.language-zhzh { - @include icon('language-zhzh', 0, center, 2 * $icon-width); - } - &.python-level-novice { - @include icon('level-1'); - } - &.python-level-intermediate { - @include icon('level-2'); - } - &.python-level-experienced { - @include icon('level-3'); - } - &.no-recording { - @include icon('no-recording', 1px); - } - &.room-R0 { - @include icon('room-R0', 1px, center); - } - &.room-R1 { - @include icon('room-R1', 1px, center); - } - &.room-R2 { - @include icon('room-R2', 1px, center); - } - &.room-R3 { - @include icon('room-R3', 1px, center); - } - &.grass { - @include icon('grass-group', 0, right); - &:before { - background-size: contain; - @include on-desktop() { - height: $icon-height * 1.5; - width: $icon-width * 1.5; - } - } - } - &.snake { - @include icon('snake', 0, right); - &:before { - background-size: contain; - @include on-desktop() { - height: $icon-height * 1.5; - width: $icon-width * 1.5; - } - } - } - } - } - } - - .schedule-legend { - - background: $pale-grey; - word-wrap: break-word; - padding: 32px 24px; - border-radius: 2px; - - @include on-desktop() { - padding: 32px; - columns: 2; - } - @include icon-info(); - } - - .time-table { - width: calc(100% + 50px); - margin: -16px; - background: transparent; - text-align: center; - - // Fonts. - @include text(16px); - tbody, tr, th, td, ul { - // display: block; - @include text(16px); - font-weight: normal; - } - - $border-color: $pale-grey; - // Round corners. - th, td, .time-stack-ribbon[class~='2-all'] + .event-info { - border-radius: 0; - } - .time-stack-ribbon + .event-info { - border-radius: 0; - } - .time-stack-ribbon { - border-radius: 0; - } - - // Not actually a table! - display: block; - thead, tfoot { - display: none; - } - tbody, tr, th, td, ul { - display: block; - } - - th, td, tr{ - display: flex; - align-items: stretch; - justify-content: left; - margin: 0; - padding: 0; - } - - tr { - align-items: flex-start; - - &.slot { - min-height: 100px; - - border-style: solid; - border-width: 0px; - border-left-width: 3px; - border-color: transparent; - border-radius: 4px; - background: $ghost-gray; - - &.custom { - background-color: $light-grayish-yellow; - border: 0px; - } - - &.first-slot { - border-top-color: $gold-yellow; - border-top-width: 1px; - margin-top: 10px; - } - &:hover { - border-left-color: $gold-yellow; - } - - @each $name, $color in ("R123": $gold-yellow, "R0": $gold-yellow, "R1": $egyptian-blue, "R2": $forest-green, "R3": $dark-orange) { - &.slot-room-#{$name} { - &.first-slot { - border-top-color: $gold-yellow; - } - &:hover { - border-left-color: $color; - background: $white; - } - } - } - } - } - - - td { - $slot-padding-top: 20px; - - &.event { - flex: 3; - - .event-info { - display: flex; - flex: 1; - text-align: left; - flex-direction: column; - padding-top: $slot-padding-top; - font-weight: 400; - - a:hover { - text-decoration: none; - } - - .talk-info { - flex: 3; - p { - &.talk-speakers { - color: $light-gray; - } - } - } - - .talk-tags { - @include list-reset(); - display: flex; - justify-content: left; - margin: 0.375rem; - text-indent: 0; - flex: 1; - - > li::before { - content: ' '; - margin-right: 5px; - } - @include on-desktop() { - justify-content: center; - } - } - - @include on-desktop() { - flex-direction: row; - } - } - - &.event-not-first { - border-top: dashed 1px $light-gray; - } - - &.talk, &.tutorial { - @include list-reset(); - @include icon-info(); - } - &.keynote { - .event-info { - flex-direction: column; - } - } - &.custom { - align-self: center; - width: 100%; - .event-info { - @include list-reset(); - @include icon-info(); - padding-top: 0; - justify-content: center; - ul { - display: flex; - justify-content: center; - align-items: center; - li { - margin: 0px 5px 0px 0px; - font-weight: 500; - &:before { - margin-right: 0; - } - &.info { - text-align: center; - &:before { - content: none; - } - } - @include on-desktop { - margin: 0px 10px 0px 0px; - } - } - } - } - } - } - - &.time-table-time { - flex: 1; - flex-direction: column; - @include list-reset(); - @include icon-info(); - padding-top: $slot-padding-top; - padding-left: 20px; - &.custom { - display: none; - } - ul { - margin: 0; - li { - &.time { - text-align: left; - font-size: 16px; - &:before { - content: none; - } - } - } - } - } - } - } - - .room-info { - @include icon-info(); - ul { - margin: 0; - display: flex; - justify-content: center; - text-indent: $icon-width; - } - } -} diff --git a/src/static/pycontw-2022/_includes/base/_variables.scss b/src/static/pycontw-2022/_includes/base/_variables.scss index 56fb3a410..e297dde3b 100644 --- a/src/static/pycontw-2022/_includes/base/_variables.scss +++ b/src/static/pycontw-2022/_includes/base/_variables.scss @@ -10,10 +10,6 @@ $quote-color: $theme-focus; // section $section__heading-color: $theme-color; -// schedule -$schedule-color: #F58454; -$schedule__title-color: #ADCDFF; - // intro $intro__heading-color: $theme-color; $intro-color: #686868; diff --git a/src/static/pycontw-2022/scripts/schedule.js b/src/static/pycontw-2022/scripts/schedule.js deleted file mode 100644 index 478756338..000000000 --- a/src/static/pycontw-2022/scripts/schedule.js +++ /dev/null @@ -1,32 +0,0 @@ -// Schedule generation. -const form = document.querySelector('.generation-form') -if (form) { - const html = document.querySelector('.schedule-content').innerHTML - form.querySelector('input[name="html"]').value = html - form.style.display = 'block' -} - - -// Replace localed URL with current locale prefix. -const I18N = JSON.parse(document.getElementById('i18n_variables').textContent) -function findPrefix(u) { - const possiblePrefixes = [] - for (const prefix of I18N.LANGUAGE_PREFIXES) { - if (u.startsWith(prefix)) { - return prefix - } - } - return '' -} -for (const el of document.querySelectorAll('.localed-url')) { - const original = el.getAttribute('href') - if (!original) { - continue - } - const prefix = findPrefix(original) - if (!prefix) { - continue - } - const sub = original.substr(prefix.length) - el.setAttribute('href', `${I18N.LANGUAGE_PREFIX}${sub}`) -} diff --git a/src/static/pycontw-2022/styles/page.scss b/src/static/pycontw-2022/styles/page.scss index afab90859..0c57b6300 100644 --- a/src/static/pycontw-2022/styles/page.scss +++ b/src/static/pycontw-2022/styles/page.scss @@ -407,7 +407,6 @@ ul.custom_ul { @import "pages/ticket-info"; @import "pages/tutorials"; @import "pages/venue"; -@import "pages/schedule"; @import "pages/staff"; @import "pages/portal"; @import "pages/sponsorship-prospectus"; diff --git a/src/static/pycontw-2022/styles/pages/_events.scss b/src/static/pycontw-2022/styles/pages/_events.scss index 33fbad935..a343665ca 100644 --- a/src/static/pycontw-2022/styles/pages/_events.scss +++ b/src/static/pycontw-2022/styles/pages/_events.scss @@ -228,236 +228,3 @@ $icon-height: 26px; @include rooms(); } - -@mixin toggleTimetableOrTimeList() { - @media (min-width: 901px) { - .py-schedule-timetable { - display: initial; - - .room-tag { - display: none; - } - } - - .py-schedule-time-list { - display: none; - } - } - - @media (max-width: 900px) { - .py-schedule-timetable { - display: none; - } - - .py-schedule-time-list { - display: initial; - - .room-tag::before { - white-space: initial; - } - } - - .py-schedule-tabs__tab { - padding: 24px; - } - } -} - -main { - max-width: unset; - margin: unset; - padding: 24px; - - .py-schedule { - &-tabs { - display: flex; - justify-content: center; - align-items: center; - - &__tab { - margin: 0 24px 24px; - padding: 24px 72px; - font-family: $header-font-family; - font-size: 20px; - border-radius: 8px; - cursor: default; - - &:hover:not(.--active) { - color: red; - cursor: pointer; - } - - &.--active { - color: $jinger-bread; - background: $salmon; - } - } - } - - &-timetable { - &-header { - position: sticky; - top: 0; - z-index: 1000; - display: flex; - background: transparentize($brick, 0.3); - - &-column { - @include roomDisplayStyle(); - - margin: 8px 8px 8px 0; - padding: 12px 0; - font-size: 18px; - - &:last-child { - margin-right: 0; - } - - &.--timeline { - flex: 1; - background: transparent; - } - - &.--room { - flex: 2; - } - } - - @include rooms(); - - &:not(.--active) { - display: none; - } - } - - &-body { - display: grid; - grid-template-columns: - [times] 1fr - [room-4-r0-start] 2fr - [room-4-r0-end room-5-r1-start] 2fr - [room-5-r1-end room-6-r2-start] 2fr - [room-6-r2-end room-8-r3-start] 2fr - [room-8-r3-end room-7-r4-start] 2fr - [room-7-r4-end]; - grid-column-gap: 8px; - grid-row-gap: 8px; - - &-item { - @include eventItem(); - } - - .room-3-r012 { - grid-column: room-4-r0-start / room-6-r2-end; - } - - .room-4-r0 { - grid-column: room-4-r0-start / room-4-r0-end; - } - - .room-5-r1 { - grid-column: room-5-r1-start / room-5-r1-end; - } - - .room-6-r2 { - grid-column: room-6-r2-start / room-6-r2-end; - } - - .room-7-r4 { - grid-column: room-7-r4-start / room-7-r4-end; - } - - .room-1-r3 { - grid-column: room-8-r3-start / room-8-r3-end; - } - - .room-2-all { - grid-column: room-4-r0-start / room-8-r3-end; - } - - .timeline { - grid-column: times; - justify-self: center; - @include time(); - - &.--hour { - font-size: 20px; - font-weight: 500; - } - - &.--half-an-hour { - font-size: 18px; - } - } - - &:not(.--active) { - display: none; - } - } - } - - &-time-list { - &-section { - &-header { - position: sticky; - position: -webkit-sticky; - top: 0; - z-index: 10; - padding: 16px 0; - background: $brick; - - & > .time { - @include time(); - - font-size: 22px; - } - } - - &-items { - display: flex; - flex-direction: column; - margin: 12px 0; - - &-item { - @include eventItem(); - margin-bottom: 12px; - } - - .room-2-all { - order: 1; - } - - .room-3-r012 { - order: 2; - } - - .room-4-r0 { - order: 3; - } - - .room-5-r1 { - order: 4; - } - - .room-6-r2 { - order: 5; - } - - .room-1-r3 { - order: 6; - } - - .room-7-r4 { - order: 7; - } - } - } - - &:not(.--active) { - display: none; - } - } - } - - @include toggleTimetableOrTimeList(); -} diff --git a/src/static/pycontw-2022/styles/pages/_schedule.scss b/src/static/pycontw-2022/styles/pages/_schedule.scss deleted file mode 100644 index 96379039b..000000000 --- a/src/static/pycontw-2022/styles/pages/_schedule.scss +++ /dev/null @@ -1,342 +0,0 @@ -.schedule-page { - form .button-round { - @include button(276deg, $dark-peach, $maize); - width: 160px; - margin: 24px 0; - text-align: center; - cursor: pointer; - } - - // Icon - $icon-width: 26px; - $icon-height: 26px; - - @mixin icon($name, $margin-top: 0, $x: left, $width: $icon-width) { - &::before { - width: $width; - margin-top: $margin-top; // Visual compensation. - background: url('../assets/icon-#{$name}.svg') top $x no-repeat; - } - } - - @mixin icon-info() { - ul { - @include list-reset(); - text-indent: 0; - li { - - display: flex; - align-content: baseline; - align-items: flex-start; - - > * { - flex: 1; - min-height: 24px; - margin-bottom: 12px; - } - - &:before { - content: ' '; - height: $icon-height; - margin-right: 1rem; - } - - &.speech-en { - @include icon('language-enen', -1px); - } - &.speech-zh { - @include icon('language-zhzh', -1px); - } - &.slides-en { - @include icon('language-enen', 0, right); - } - &.slides-zh { - @include icon('language-zhzh', 0, right); - } - &.language-enen { - @include icon('language-enen', 0, center, 2 * $icon-width); - } - &.language-zhen { - @include icon('language-zhen', 0, center, 2 * $icon-width); - } - &.language-zhzh { - @include icon('language-zhzh', 0, center, 2 * $icon-width); - } - &.python-level-novice { - @include icon('level-1'); - } - &.python-level-intermediate { - @include icon('level-2'); - } - &.python-level-experienced { - @include icon('level-3'); - } - &.no-recording { - @include icon('no-recording', 1px); - } - &.room-R0 { - @include icon('room-R0', 1px, center); - } - &.room-R1 { - @include icon('room-R1', 1px, center); - } - &.room-R2 { - @include icon('room-R2', 1px, center); - } - &.room-R3 { - @include icon('room-R3', 1px, center); - } - &.grass { - @include icon('grass-group', 0, right); - &:before { - background-size: contain; - @include on-desktop() { - height: $icon-height * 1.5; - width: $icon-width * 1.5; - } - } - } - &.snake { - @include icon('snake', 0, right); - &:before { - background-size: contain; - @include on-desktop() { - height: $icon-height * 1.5; - width: $icon-width * 1.5; - } - } - } - } - } - } - - .schedule-legend { - - background: $pale-grey; - word-wrap: break-word; - padding: 32px 24px; - border-radius: 2px; - - @include on-desktop() { - padding: 32px; - columns: 2; - } - @include icon-info(); - } - - .time-table { - width: calc(100% + 50px); - margin: -16px; - background: transparent; - text-align: center; - - // Fonts. - @include text(16px); - tbody, tr, th, td, ul { - // display: block; - @include text(16px); - font-weight: normal; - } - - $border-color: $pale-grey; - // Round corners. - th, td, .time-stack-ribbon[class~='2-all'] + .event-info { - border-radius: 0; - } - .time-stack-ribbon + .event-info { - border-radius: 0; - } - .time-stack-ribbon { - border-radius: 0; - } - - // Not actually a table! - display: block; - thead, tfoot { - display: none; - } - tbody, tr, th, td, ul { - display: block; - } - - th, td, tr{ - display: flex; - align-items: stretch; - justify-content: left; - margin: 0; - padding: 0; - } - - tr { - align-items: flex-start; - - &.slot { - min-height: 100px; - - border-style: solid; - border-width: 0px; - border-left-width: 3px; - border-color: transparent; - border-radius: 4px; - background: $ghost-gray; - - &.custom { - background-color: $light-grayish-yellow; - border: 0px; - } - - &.first-slot { - border-top-color: $gold-yellow; - border-top-width: 1px; - margin-top: 10px; - } - &:hover { - border-left-color: $gold-yellow; - } - - @each $name, $color in ("R123": $gold-yellow, "R0": $gold-yellow, "R1": $egyptian-blue, "R2": $forest-green, "R3": $dark-orange) { - &.slot-room-#{$name} { - &.first-slot { - border-top-color: $gold-yellow; - } - &:hover { - border-left-color: $color; - background: $white; - } - } - } - } - } - - - td { - $slot-padding-top: 20px; - - &.event { - flex: 3; - - .event-info { - display: flex; - flex: 1; - text-align: left; - flex-direction: column; - padding-top: $slot-padding-top; - font-weight: 400; - - a:hover { - text-decoration: none; - } - - .talk-info { - flex: 3; - p { - &.talk-speakers { - color: $light-gray; - } - } - } - - .talk-tags { - @include list-reset(); - display: flex; - justify-content: left; - margin: 0.375rem; - text-indent: 0; - flex: 1; - - > li::before { - content: ' '; - margin-right: 5px; - } - @include on-desktop() { - justify-content: center; - } - } - - @include on-desktop() { - flex-direction: row; - } - } - - &.event-not-first { - border-top: dashed 1px $light-gray; - } - - &.talk, &.tutorial { - @include list-reset(); - @include icon-info(); - } - &.keynote { - .event-info { - flex-direction: column; - } - } - &.custom { - align-self: center; - width: 100%; - .event-info { - @include list-reset(); - @include icon-info(); - padding-top: 0; - justify-content: center; - ul { - display: flex; - justify-content: center; - align-items: center; - li { - margin: 0px 5px 0px 0px; - font-weight: 500; - &:before { - margin-right: 0; - } - &.info { - text-align: center; - &:before { - content: none; - } - } - @include on-desktop { - margin: 0px 10px 0px 0px; - } - } - } - } - } - } - - &.time-table-time { - flex: 1; - flex-direction: column; - @include list-reset(); - @include icon-info(); - padding-top: $slot-padding-top; - padding-left: 20px; - &.custom { - display: none; - } - ul { - margin: 0; - li { - &.time { - text-align: left; - font-size: 16px; - &:before { - content: none; - } - } - } - } - } - } - } - - .room-info { - @include icon-info(); - ul { - margin: 0; - display: flex; - justify-content: center; - text-indent: $icon-width; - } - } -} diff --git a/src/static/pycontw-2023/_includes/base/_variables.scss b/src/static/pycontw-2023/_includes/base/_variables.scss index 2af268b93..be9d2ed16 100644 --- a/src/static/pycontw-2023/_includes/base/_variables.scss +++ b/src/static/pycontw-2023/_includes/base/_variables.scss @@ -10,10 +10,6 @@ $quote-color: $theme-focus; // section $section__heading-color: $theme-color; -// schedule -$schedule-color: #F58454; -$schedule__title-color: #ADCDFF; - // intro $intro__heading-color: $theme-color; $intro-color: #686868; diff --git a/src/static/pycontw-2023/scripts/schedule.js b/src/static/pycontw-2023/scripts/schedule.js deleted file mode 100644 index 478756338..000000000 --- a/src/static/pycontw-2023/scripts/schedule.js +++ /dev/null @@ -1,32 +0,0 @@ -// Schedule generation. -const form = document.querySelector('.generation-form') -if (form) { - const html = document.querySelector('.schedule-content').innerHTML - form.querySelector('input[name="html"]').value = html - form.style.display = 'block' -} - - -// Replace localed URL with current locale prefix. -const I18N = JSON.parse(document.getElementById('i18n_variables').textContent) -function findPrefix(u) { - const possiblePrefixes = [] - for (const prefix of I18N.LANGUAGE_PREFIXES) { - if (u.startsWith(prefix)) { - return prefix - } - } - return '' -} -for (const el of document.querySelectorAll('.localed-url')) { - const original = el.getAttribute('href') - if (!original) { - continue - } - const prefix = findPrefix(original) - if (!prefix) { - continue - } - const sub = original.substr(prefix.length) - el.setAttribute('href', `${I18N.LANGUAGE_PREFIX}${sub}`) -} diff --git a/src/static/pycontw-2023/styles/page.scss b/src/static/pycontw-2023/styles/page.scss index 7c9b94569..3261152c0 100644 --- a/src/static/pycontw-2023/styles/page.scss +++ b/src/static/pycontw-2023/styles/page.scss @@ -407,7 +407,6 @@ ul.custom_ul { @import "pages/ticket-info"; @import "pages/tutorials"; @import "pages/venue"; -@import "pages/schedule"; @import "pages/staff"; @import "pages/portal"; @import "pages/sponsorship-prospectus"; diff --git a/src/static/pycontw-2023/styles/pages/_events.scss b/src/static/pycontw-2023/styles/pages/_events.scss index 33fbad935..a343665ca 100644 --- a/src/static/pycontw-2023/styles/pages/_events.scss +++ b/src/static/pycontw-2023/styles/pages/_events.scss @@ -228,236 +228,3 @@ $icon-height: 26px; @include rooms(); } - -@mixin toggleTimetableOrTimeList() { - @media (min-width: 901px) { - .py-schedule-timetable { - display: initial; - - .room-tag { - display: none; - } - } - - .py-schedule-time-list { - display: none; - } - } - - @media (max-width: 900px) { - .py-schedule-timetable { - display: none; - } - - .py-schedule-time-list { - display: initial; - - .room-tag::before { - white-space: initial; - } - } - - .py-schedule-tabs__tab { - padding: 24px; - } - } -} - -main { - max-width: unset; - margin: unset; - padding: 24px; - - .py-schedule { - &-tabs { - display: flex; - justify-content: center; - align-items: center; - - &__tab { - margin: 0 24px 24px; - padding: 24px 72px; - font-family: $header-font-family; - font-size: 20px; - border-radius: 8px; - cursor: default; - - &:hover:not(.--active) { - color: red; - cursor: pointer; - } - - &.--active { - color: $jinger-bread; - background: $salmon; - } - } - } - - &-timetable { - &-header { - position: sticky; - top: 0; - z-index: 1000; - display: flex; - background: transparentize($brick, 0.3); - - &-column { - @include roomDisplayStyle(); - - margin: 8px 8px 8px 0; - padding: 12px 0; - font-size: 18px; - - &:last-child { - margin-right: 0; - } - - &.--timeline { - flex: 1; - background: transparent; - } - - &.--room { - flex: 2; - } - } - - @include rooms(); - - &:not(.--active) { - display: none; - } - } - - &-body { - display: grid; - grid-template-columns: - [times] 1fr - [room-4-r0-start] 2fr - [room-4-r0-end room-5-r1-start] 2fr - [room-5-r1-end room-6-r2-start] 2fr - [room-6-r2-end room-8-r3-start] 2fr - [room-8-r3-end room-7-r4-start] 2fr - [room-7-r4-end]; - grid-column-gap: 8px; - grid-row-gap: 8px; - - &-item { - @include eventItem(); - } - - .room-3-r012 { - grid-column: room-4-r0-start / room-6-r2-end; - } - - .room-4-r0 { - grid-column: room-4-r0-start / room-4-r0-end; - } - - .room-5-r1 { - grid-column: room-5-r1-start / room-5-r1-end; - } - - .room-6-r2 { - grid-column: room-6-r2-start / room-6-r2-end; - } - - .room-7-r4 { - grid-column: room-7-r4-start / room-7-r4-end; - } - - .room-1-r3 { - grid-column: room-8-r3-start / room-8-r3-end; - } - - .room-2-all { - grid-column: room-4-r0-start / room-8-r3-end; - } - - .timeline { - grid-column: times; - justify-self: center; - @include time(); - - &.--hour { - font-size: 20px; - font-weight: 500; - } - - &.--half-an-hour { - font-size: 18px; - } - } - - &:not(.--active) { - display: none; - } - } - } - - &-time-list { - &-section { - &-header { - position: sticky; - position: -webkit-sticky; - top: 0; - z-index: 10; - padding: 16px 0; - background: $brick; - - & > .time { - @include time(); - - font-size: 22px; - } - } - - &-items { - display: flex; - flex-direction: column; - margin: 12px 0; - - &-item { - @include eventItem(); - margin-bottom: 12px; - } - - .room-2-all { - order: 1; - } - - .room-3-r012 { - order: 2; - } - - .room-4-r0 { - order: 3; - } - - .room-5-r1 { - order: 4; - } - - .room-6-r2 { - order: 5; - } - - .room-1-r3 { - order: 6; - } - - .room-7-r4 { - order: 7; - } - } - } - - &:not(.--active) { - display: none; - } - } - } - - @include toggleTimetableOrTimeList(); -} diff --git a/src/static/pycontw-2023/styles/pages/_schedule.scss b/src/static/pycontw-2023/styles/pages/_schedule.scss deleted file mode 100644 index 96379039b..000000000 --- a/src/static/pycontw-2023/styles/pages/_schedule.scss +++ /dev/null @@ -1,342 +0,0 @@ -.schedule-page { - form .button-round { - @include button(276deg, $dark-peach, $maize); - width: 160px; - margin: 24px 0; - text-align: center; - cursor: pointer; - } - - // Icon - $icon-width: 26px; - $icon-height: 26px; - - @mixin icon($name, $margin-top: 0, $x: left, $width: $icon-width) { - &::before { - width: $width; - margin-top: $margin-top; // Visual compensation. - background: url('../assets/icon-#{$name}.svg') top $x no-repeat; - } - } - - @mixin icon-info() { - ul { - @include list-reset(); - text-indent: 0; - li { - - display: flex; - align-content: baseline; - align-items: flex-start; - - > * { - flex: 1; - min-height: 24px; - margin-bottom: 12px; - } - - &:before { - content: ' '; - height: $icon-height; - margin-right: 1rem; - } - - &.speech-en { - @include icon('language-enen', -1px); - } - &.speech-zh { - @include icon('language-zhzh', -1px); - } - &.slides-en { - @include icon('language-enen', 0, right); - } - &.slides-zh { - @include icon('language-zhzh', 0, right); - } - &.language-enen { - @include icon('language-enen', 0, center, 2 * $icon-width); - } - &.language-zhen { - @include icon('language-zhen', 0, center, 2 * $icon-width); - } - &.language-zhzh { - @include icon('language-zhzh', 0, center, 2 * $icon-width); - } - &.python-level-novice { - @include icon('level-1'); - } - &.python-level-intermediate { - @include icon('level-2'); - } - &.python-level-experienced { - @include icon('level-3'); - } - &.no-recording { - @include icon('no-recording', 1px); - } - &.room-R0 { - @include icon('room-R0', 1px, center); - } - &.room-R1 { - @include icon('room-R1', 1px, center); - } - &.room-R2 { - @include icon('room-R2', 1px, center); - } - &.room-R3 { - @include icon('room-R3', 1px, center); - } - &.grass { - @include icon('grass-group', 0, right); - &:before { - background-size: contain; - @include on-desktop() { - height: $icon-height * 1.5; - width: $icon-width * 1.5; - } - } - } - &.snake { - @include icon('snake', 0, right); - &:before { - background-size: contain; - @include on-desktop() { - height: $icon-height * 1.5; - width: $icon-width * 1.5; - } - } - } - } - } - } - - .schedule-legend { - - background: $pale-grey; - word-wrap: break-word; - padding: 32px 24px; - border-radius: 2px; - - @include on-desktop() { - padding: 32px; - columns: 2; - } - @include icon-info(); - } - - .time-table { - width: calc(100% + 50px); - margin: -16px; - background: transparent; - text-align: center; - - // Fonts. - @include text(16px); - tbody, tr, th, td, ul { - // display: block; - @include text(16px); - font-weight: normal; - } - - $border-color: $pale-grey; - // Round corners. - th, td, .time-stack-ribbon[class~='2-all'] + .event-info { - border-radius: 0; - } - .time-stack-ribbon + .event-info { - border-radius: 0; - } - .time-stack-ribbon { - border-radius: 0; - } - - // Not actually a table! - display: block; - thead, tfoot { - display: none; - } - tbody, tr, th, td, ul { - display: block; - } - - th, td, tr{ - display: flex; - align-items: stretch; - justify-content: left; - margin: 0; - padding: 0; - } - - tr { - align-items: flex-start; - - &.slot { - min-height: 100px; - - border-style: solid; - border-width: 0px; - border-left-width: 3px; - border-color: transparent; - border-radius: 4px; - background: $ghost-gray; - - &.custom { - background-color: $light-grayish-yellow; - border: 0px; - } - - &.first-slot { - border-top-color: $gold-yellow; - border-top-width: 1px; - margin-top: 10px; - } - &:hover { - border-left-color: $gold-yellow; - } - - @each $name, $color in ("R123": $gold-yellow, "R0": $gold-yellow, "R1": $egyptian-blue, "R2": $forest-green, "R3": $dark-orange) { - &.slot-room-#{$name} { - &.first-slot { - border-top-color: $gold-yellow; - } - &:hover { - border-left-color: $color; - background: $white; - } - } - } - } - } - - - td { - $slot-padding-top: 20px; - - &.event { - flex: 3; - - .event-info { - display: flex; - flex: 1; - text-align: left; - flex-direction: column; - padding-top: $slot-padding-top; - font-weight: 400; - - a:hover { - text-decoration: none; - } - - .talk-info { - flex: 3; - p { - &.talk-speakers { - color: $light-gray; - } - } - } - - .talk-tags { - @include list-reset(); - display: flex; - justify-content: left; - margin: 0.375rem; - text-indent: 0; - flex: 1; - - > li::before { - content: ' '; - margin-right: 5px; - } - @include on-desktop() { - justify-content: center; - } - } - - @include on-desktop() { - flex-direction: row; - } - } - - &.event-not-first { - border-top: dashed 1px $light-gray; - } - - &.talk, &.tutorial { - @include list-reset(); - @include icon-info(); - } - &.keynote { - .event-info { - flex-direction: column; - } - } - &.custom { - align-self: center; - width: 100%; - .event-info { - @include list-reset(); - @include icon-info(); - padding-top: 0; - justify-content: center; - ul { - display: flex; - justify-content: center; - align-items: center; - li { - margin: 0px 5px 0px 0px; - font-weight: 500; - &:before { - margin-right: 0; - } - &.info { - text-align: center; - &:before { - content: none; - } - } - @include on-desktop { - margin: 0px 10px 0px 0px; - } - } - } - } - } - } - - &.time-table-time { - flex: 1; - flex-direction: column; - @include list-reset(); - @include icon-info(); - padding-top: $slot-padding-top; - padding-left: 20px; - &.custom { - display: none; - } - ul { - margin: 0; - li { - &.time { - text-align: left; - font-size: 16px; - &:before { - content: none; - } - } - } - } - } - } - } - - .room-info { - @include icon-info(); - ul { - margin: 0; - display: flex; - justify-content: center; - text-indent: $icon-width; - } - } -} diff --git a/src/static/pycontw-2024/_includes/base/_variables.scss b/src/static/pycontw-2024/_includes/base/_variables.scss index 0133d965a..e899cb95d 100644 --- a/src/static/pycontw-2024/_includes/base/_variables.scss +++ b/src/static/pycontw-2024/_includes/base/_variables.scss @@ -10,10 +10,6 @@ $quote-color: $theme-focus; // section $section__heading-color: $theme-color; -// schedule -$schedule-color: #F58454; -$schedule__title-color: #ADCDFF; - // intro $intro__heading-color: $theme-color; $intro-color: #686868; diff --git a/src/static/pycontw-2024/scripts/schedule.js b/src/static/pycontw-2024/scripts/schedule.js deleted file mode 100644 index 478756338..000000000 --- a/src/static/pycontw-2024/scripts/schedule.js +++ /dev/null @@ -1,32 +0,0 @@ -// Schedule generation. -const form = document.querySelector('.generation-form') -if (form) { - const html = document.querySelector('.schedule-content').innerHTML - form.querySelector('input[name="html"]').value = html - form.style.display = 'block' -} - - -// Replace localed URL with current locale prefix. -const I18N = JSON.parse(document.getElementById('i18n_variables').textContent) -function findPrefix(u) { - const possiblePrefixes = [] - for (const prefix of I18N.LANGUAGE_PREFIXES) { - if (u.startsWith(prefix)) { - return prefix - } - } - return '' -} -for (const el of document.querySelectorAll('.localed-url')) { - const original = el.getAttribute('href') - if (!original) { - continue - } - const prefix = findPrefix(original) - if (!prefix) { - continue - } - const sub = original.substr(prefix.length) - el.setAttribute('href', `${I18N.LANGUAGE_PREFIX}${sub}`) -} diff --git a/src/static/pycontw-2024/styles/page.scss b/src/static/pycontw-2024/styles/page.scss index 7c9b94569..3261152c0 100644 --- a/src/static/pycontw-2024/styles/page.scss +++ b/src/static/pycontw-2024/styles/page.scss @@ -407,7 +407,6 @@ ul.custom_ul { @import "pages/ticket-info"; @import "pages/tutorials"; @import "pages/venue"; -@import "pages/schedule"; @import "pages/staff"; @import "pages/portal"; @import "pages/sponsorship-prospectus"; diff --git a/src/static/pycontw-2024/styles/pages/_events.scss b/src/static/pycontw-2024/styles/pages/_events.scss index 33fbad935..a343665ca 100644 --- a/src/static/pycontw-2024/styles/pages/_events.scss +++ b/src/static/pycontw-2024/styles/pages/_events.scss @@ -228,236 +228,3 @@ $icon-height: 26px; @include rooms(); } - -@mixin toggleTimetableOrTimeList() { - @media (min-width: 901px) { - .py-schedule-timetable { - display: initial; - - .room-tag { - display: none; - } - } - - .py-schedule-time-list { - display: none; - } - } - - @media (max-width: 900px) { - .py-schedule-timetable { - display: none; - } - - .py-schedule-time-list { - display: initial; - - .room-tag::before { - white-space: initial; - } - } - - .py-schedule-tabs__tab { - padding: 24px; - } - } -} - -main { - max-width: unset; - margin: unset; - padding: 24px; - - .py-schedule { - &-tabs { - display: flex; - justify-content: center; - align-items: center; - - &__tab { - margin: 0 24px 24px; - padding: 24px 72px; - font-family: $header-font-family; - font-size: 20px; - border-radius: 8px; - cursor: default; - - &:hover:not(.--active) { - color: red; - cursor: pointer; - } - - &.--active { - color: $jinger-bread; - background: $salmon; - } - } - } - - &-timetable { - &-header { - position: sticky; - top: 0; - z-index: 1000; - display: flex; - background: transparentize($brick, 0.3); - - &-column { - @include roomDisplayStyle(); - - margin: 8px 8px 8px 0; - padding: 12px 0; - font-size: 18px; - - &:last-child { - margin-right: 0; - } - - &.--timeline { - flex: 1; - background: transparent; - } - - &.--room { - flex: 2; - } - } - - @include rooms(); - - &:not(.--active) { - display: none; - } - } - - &-body { - display: grid; - grid-template-columns: - [times] 1fr - [room-4-r0-start] 2fr - [room-4-r0-end room-5-r1-start] 2fr - [room-5-r1-end room-6-r2-start] 2fr - [room-6-r2-end room-8-r3-start] 2fr - [room-8-r3-end room-7-r4-start] 2fr - [room-7-r4-end]; - grid-column-gap: 8px; - grid-row-gap: 8px; - - &-item { - @include eventItem(); - } - - .room-3-r012 { - grid-column: room-4-r0-start / room-6-r2-end; - } - - .room-4-r0 { - grid-column: room-4-r0-start / room-4-r0-end; - } - - .room-5-r1 { - grid-column: room-5-r1-start / room-5-r1-end; - } - - .room-6-r2 { - grid-column: room-6-r2-start / room-6-r2-end; - } - - .room-7-r4 { - grid-column: room-7-r4-start / room-7-r4-end; - } - - .room-1-r3 { - grid-column: room-8-r3-start / room-8-r3-end; - } - - .room-2-all { - grid-column: room-4-r0-start / room-8-r3-end; - } - - .timeline { - grid-column: times; - justify-self: center; - @include time(); - - &.--hour { - font-size: 20px; - font-weight: 500; - } - - &.--half-an-hour { - font-size: 18px; - } - } - - &:not(.--active) { - display: none; - } - } - } - - &-time-list { - &-section { - &-header { - position: sticky; - position: -webkit-sticky; - top: 0; - z-index: 10; - padding: 16px 0; - background: $brick; - - & > .time { - @include time(); - - font-size: 22px; - } - } - - &-items { - display: flex; - flex-direction: column; - margin: 12px 0; - - &-item { - @include eventItem(); - margin-bottom: 12px; - } - - .room-2-all { - order: 1; - } - - .room-3-r012 { - order: 2; - } - - .room-4-r0 { - order: 3; - } - - .room-5-r1 { - order: 4; - } - - .room-6-r2 { - order: 5; - } - - .room-1-r3 { - order: 6; - } - - .room-7-r4 { - order: 7; - } - } - } - - &:not(.--active) { - display: none; - } - } - } - - @include toggleTimetableOrTimeList(); -} diff --git a/src/static/pycontw-2024/styles/pages/_schedule.scss b/src/static/pycontw-2024/styles/pages/_schedule.scss deleted file mode 100644 index 96379039b..000000000 --- a/src/static/pycontw-2024/styles/pages/_schedule.scss +++ /dev/null @@ -1,342 +0,0 @@ -.schedule-page { - form .button-round { - @include button(276deg, $dark-peach, $maize); - width: 160px; - margin: 24px 0; - text-align: center; - cursor: pointer; - } - - // Icon - $icon-width: 26px; - $icon-height: 26px; - - @mixin icon($name, $margin-top: 0, $x: left, $width: $icon-width) { - &::before { - width: $width; - margin-top: $margin-top; // Visual compensation. - background: url('../assets/icon-#{$name}.svg') top $x no-repeat; - } - } - - @mixin icon-info() { - ul { - @include list-reset(); - text-indent: 0; - li { - - display: flex; - align-content: baseline; - align-items: flex-start; - - > * { - flex: 1; - min-height: 24px; - margin-bottom: 12px; - } - - &:before { - content: ' '; - height: $icon-height; - margin-right: 1rem; - } - - &.speech-en { - @include icon('language-enen', -1px); - } - &.speech-zh { - @include icon('language-zhzh', -1px); - } - &.slides-en { - @include icon('language-enen', 0, right); - } - &.slides-zh { - @include icon('language-zhzh', 0, right); - } - &.language-enen { - @include icon('language-enen', 0, center, 2 * $icon-width); - } - &.language-zhen { - @include icon('language-zhen', 0, center, 2 * $icon-width); - } - &.language-zhzh { - @include icon('language-zhzh', 0, center, 2 * $icon-width); - } - &.python-level-novice { - @include icon('level-1'); - } - &.python-level-intermediate { - @include icon('level-2'); - } - &.python-level-experienced { - @include icon('level-3'); - } - &.no-recording { - @include icon('no-recording', 1px); - } - &.room-R0 { - @include icon('room-R0', 1px, center); - } - &.room-R1 { - @include icon('room-R1', 1px, center); - } - &.room-R2 { - @include icon('room-R2', 1px, center); - } - &.room-R3 { - @include icon('room-R3', 1px, center); - } - &.grass { - @include icon('grass-group', 0, right); - &:before { - background-size: contain; - @include on-desktop() { - height: $icon-height * 1.5; - width: $icon-width * 1.5; - } - } - } - &.snake { - @include icon('snake', 0, right); - &:before { - background-size: contain; - @include on-desktop() { - height: $icon-height * 1.5; - width: $icon-width * 1.5; - } - } - } - } - } - } - - .schedule-legend { - - background: $pale-grey; - word-wrap: break-word; - padding: 32px 24px; - border-radius: 2px; - - @include on-desktop() { - padding: 32px; - columns: 2; - } - @include icon-info(); - } - - .time-table { - width: calc(100% + 50px); - margin: -16px; - background: transparent; - text-align: center; - - // Fonts. - @include text(16px); - tbody, tr, th, td, ul { - // display: block; - @include text(16px); - font-weight: normal; - } - - $border-color: $pale-grey; - // Round corners. - th, td, .time-stack-ribbon[class~='2-all'] + .event-info { - border-radius: 0; - } - .time-stack-ribbon + .event-info { - border-radius: 0; - } - .time-stack-ribbon { - border-radius: 0; - } - - // Not actually a table! - display: block; - thead, tfoot { - display: none; - } - tbody, tr, th, td, ul { - display: block; - } - - th, td, tr{ - display: flex; - align-items: stretch; - justify-content: left; - margin: 0; - padding: 0; - } - - tr { - align-items: flex-start; - - &.slot { - min-height: 100px; - - border-style: solid; - border-width: 0px; - border-left-width: 3px; - border-color: transparent; - border-radius: 4px; - background: $ghost-gray; - - &.custom { - background-color: $light-grayish-yellow; - border: 0px; - } - - &.first-slot { - border-top-color: $gold-yellow; - border-top-width: 1px; - margin-top: 10px; - } - &:hover { - border-left-color: $gold-yellow; - } - - @each $name, $color in ("R123": $gold-yellow, "R0": $gold-yellow, "R1": $egyptian-blue, "R2": $forest-green, "R3": $dark-orange) { - &.slot-room-#{$name} { - &.first-slot { - border-top-color: $gold-yellow; - } - &:hover { - border-left-color: $color; - background: $white; - } - } - } - } - } - - - td { - $slot-padding-top: 20px; - - &.event { - flex: 3; - - .event-info { - display: flex; - flex: 1; - text-align: left; - flex-direction: column; - padding-top: $slot-padding-top; - font-weight: 400; - - a:hover { - text-decoration: none; - } - - .talk-info { - flex: 3; - p { - &.talk-speakers { - color: $light-gray; - } - } - } - - .talk-tags { - @include list-reset(); - display: flex; - justify-content: left; - margin: 0.375rem; - text-indent: 0; - flex: 1; - - > li::before { - content: ' '; - margin-right: 5px; - } - @include on-desktop() { - justify-content: center; - } - } - - @include on-desktop() { - flex-direction: row; - } - } - - &.event-not-first { - border-top: dashed 1px $light-gray; - } - - &.talk, &.tutorial { - @include list-reset(); - @include icon-info(); - } - &.keynote { - .event-info { - flex-direction: column; - } - } - &.custom { - align-self: center; - width: 100%; - .event-info { - @include list-reset(); - @include icon-info(); - padding-top: 0; - justify-content: center; - ul { - display: flex; - justify-content: center; - align-items: center; - li { - margin: 0px 5px 0px 0px; - font-weight: 500; - &:before { - margin-right: 0; - } - &.info { - text-align: center; - &:before { - content: none; - } - } - @include on-desktop { - margin: 0px 10px 0px 0px; - } - } - } - } - } - } - - &.time-table-time { - flex: 1; - flex-direction: column; - @include list-reset(); - @include icon-info(); - padding-top: $slot-padding-top; - padding-left: 20px; - &.custom { - display: none; - } - ul { - margin: 0; - li { - &.time { - text-align: left; - font-size: 16px; - &:before { - content: none; - } - } - } - } - } - } - } - - .room-info { - @include icon-info(); - ul { - margin: 0; - display: flex; - justify-content: center; - text-indent: $icon-width; - } - } -} diff --git a/src/template_tests/conftest.py b/src/template_tests/conftest.py deleted file mode 100644 index 3138a844f..000000000 --- a/src/template_tests/conftest.py +++ /dev/null @@ -1,8 +0,0 @@ -import pytest - -from events.models import Schedule - - -@pytest.fixture -def schedule(db): - return Schedule.objects.create(html='mmm') diff --git a/src/template_tests/test_pycontw2016.py b/src/template_tests/test_pycontw2016.py index c85a50c40..90314bb64 100644 --- a/src/template_tests/test_pycontw2016.py +++ b/src/template_tests/test_pycontw2016.py @@ -15,17 +15,6 @@ User = get_user_model() -def test_schedule(client, parser, schedule): - r = client.get('/en-us/events/schedule/') - body = parser.parse(r) - - # Make sure every cross-page intra-site link is good. - link_tags = body.cssselect('a[href^="/"]') - assert len(link_tags) != 0 - for tag in link_tags: - assert client.get(tag.get('href'), follow=True).status_code == 200 - - @pytest.mark.django_db @override_settings( # Make sure we don't really send an email. SECRET_KEY='Footage order-flow long-chain hydrocarbons hacker', diff --git a/src/templates/pycontw-2021/_includes/menu.html b/src/templates/pycontw-2021/_includes/menu.html index a55756f5c..ab336e69a 100644 --- a/src/templates/pycontw-2021/_includes/menu.html +++ b/src/templates/pycontw-2021/_includes/menu.html @@ -13,7 +13,6 @@ {% url 'page' path='speaking/tutorial' as speaking_tutorial_url %} {% url 'page' path='speaking/recording' as speaking_recording_url %} -{% url 'events_schedule' as events_schedule_url %} {% url 'page' path='conference/keynotes' as events_keynote_url %} {% url 'events_talk_list' as events_talk_list_url %} {% url 'events_tutorial_list' as events_tutorial_list_url %} @@ -78,7 +77,6 @@