Compare commits

...

4 Commits

Author SHA1 Message Date
Emmy D'Anello 1b24e90635
Fix team reorder for 5-teams pools in draw recap
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-07-09 13:51:50 +02:00
Emmy D'Anello 338f0d456a
Fix undo draw step
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-07-09 13:47:59 +02:00
Emmy D'Anello 2c4de8cec3
Adapt the random draw for the next rounds of ETEAM
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-07-09 13:26:39 +02:00
Emmy D'Anello 6b7d52c79b
Fix the passage table with observers
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2024-07-09 12:44:04 +02:00
6 changed files with 181 additions and 93 deletions

View File

@ -1021,14 +1021,18 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
if not await Draw.objects.filter(tournament=self.tournament).aexists(): if not await Draw.objects.filter(tournament=self.tournament).aexists():
return await self.alert(_("The draw has not started yet."), 'danger') return await self.alert(_("The draw has not started yet."), 'danger')
if not self.tournament.final: if not self.tournament.final and settings.TFJM_APP == "TFJM":
return await self.alert(_("This is only available for the final tournament."), 'danger') return await self.alert(_("This is only available for the final tournament."), 'danger')
r2 = await self.tournament.draw.round_set.filter(number=2).aget() r2 = await self.tournament.draw.round_set.filter(number=self.tournament.draw.current_round.number + 1).aget()
self.tournament.draw.current_round = r2 self.tournament.draw.current_round = r2
msg = _("The draw of the round 2 is starting. " if settings.TFJM_APP == "TFJM":
"The passage order is determined from the ranking of the first round, " msg = str(_("The draw of the round {round} is starting. "
"in order to mix the teams between the two days.") "The passage order is determined from the ranking of the first round, "
"in order to mix the teams between the two days.").format(round=r2.number))
else:
msg = str(_("The draw of the round {round} is starting. "
"The passage order is another time randomly drawn.").format(round=r2.number))
self.tournament.draw.last_message = msg self.tournament.draw.last_message = msg
await self.tournament.draw.asave() await self.tournament.draw.asave()
@ -1036,29 +1040,30 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await self.channel_layer.group_send(f"tournament-{self.tournament.id}", await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.notify', {'tid': self.tournament_id, 'type': 'draw.notify',
'title': _("Draw") + " " + settings.APP_NAME, 'title': _("Draw") + " " + settings.APP_NAME,
'body': _("The draw of the second round is starting!")}) 'body': str(_("The draw of the second round is starting!"))})
# Set the first pool of the second round as the active pool if settings.TFJM_APP == "TFJM":
pool = await Pool.objects.filter(round=self.tournament.draw.current_round, letter=1).aget() # Set the first pool of the second round as the active pool
r2.current_pool = pool pool = await Pool.objects.filter(round=self.tournament.draw.current_round, letter=1).aget()
await r2.asave() r2.current_pool = pool
await r2.asave()
# Fetch notes from the first round # Fetch notes from the first round
notes = dict() notes = dict()
async for participation in self.tournament.participations.filter(valid=True).prefetch_related('team').all(): async for participation in self.tournament.participations.filter(valid=True).prefetch_related('team').all():
notes[participation] = sum([await pool.aaverage(participation) notes[participation] = sum([await pool.aaverage(participation)
async for pool in self.tournament.pools.filter(participations=participation) async for pool in self.tournament.pools.filter(participations=participation)
.prefetch_related('passages')]) .prefetch_related('passages')])
# Sort notes in a decreasing order # Sort notes in a decreasing order
ordered_participations = sorted(notes.keys(), key=lambda x: -notes[x]) ordered_participations = sorted(notes.keys(), key=lambda x: -notes[x])
# Define pools and passage orders from the ranking of the first round # Define pools and passage orders from the ranking of the first round
async for pool in r2.pool_set.order_by('letter').all(): async for pool in r2.pool_set.order_by('letter').all():
for i in range(pool.size): for i in range(pool.size):
participation = ordered_participations.pop(0) participation = ordered_participations.pop(0)
td = await TeamDraw.objects.aget(round=r2, participation=participation) td = await TeamDraw.objects.aget(round=r2, participation=participation)
td.pool = pool td.pool = pool
td.passage_index = i td.passage_index = i
await td.asave() await td.asave()
# Send pools to users # Send pools to users
await self.channel_layer.group_send(f"tournament-{self.tournament.id}", await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
@ -1078,16 +1083,23 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
f"tournament-{self.tournament.id}", f"tournament-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.dice', 'team': participation.team.trigram, 'result': None}) {'tid': self.tournament_id, 'type': 'draw.dice', 'team': participation.team.trigram, 'result': None})
async for td in r2.current_pool.team_draws.prefetch_related('participation__team'): if settings.TFJM_APP == "TFJM":
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}", async for td in r2.current_pool.team_draws.prefetch_related('participation__team'):
{'tid': self.tournament_id, 'type': 'draw.dice_visibility', await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
'visible': True}) {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
'visible': True})
# Notify the team that it can draw a problem
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
{'tid': self.tournament_id, 'type': 'draw.notify',
'title': _("Your turn!"),
'body': _("It's your turn to draw a problem!")})
else:
async for td in r2.team_draws.prefetch_related('participation__team'):
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
{'tid': self.tournament_id, 'type': 'draw.dice_visibility',
'visible': True})
# Notify the team that it can draw a problem
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
{'tid': self.tournament_id, 'type': 'draw.notify',
'title': _("Your turn!"),
'body': _("It's your turn to draw a problem!")})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}", await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.dice_visibility', {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
@ -1102,7 +1114,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await self.channel_layer.group_send(f"tournament-{self.tournament.id}", await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.set_active', {'tid': self.tournament_id, 'type': 'draw.set_active',
'round': r2.number, 'round': r2.number,
'pool': r2.current_pool.get_letter_display()}) 'pool': r2.current_pool.get_letter_display() if r2.current_pool else None})
@ensure_orga @ensure_orga
async def cancel_last_step(self, **kwargs): async def cancel_last_step(self, **kwargs):
@ -1376,7 +1388,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
'round': r.number, 'round': r.number,
'team': td.participation.team.trigram, 'team': td.participation.team.trigram,
'problem': td.accepted}) 'problem': td.accepted})
elif r.number >= 2: elif r.number >= 2 and settings.TFJM_APP == "TFJM":
if not self.tournament.final: if not self.tournament.final:
# Go to the previous round # Go to the previous round
previous_round = await self.tournament.draw.round_set \ previous_round = await self.tournament.draw.round_set \
@ -1390,21 +1402,6 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
'team': td.participation.team.trigram, 'team': td.participation.team.trigram,
'result': td.choice_dice}) 'result': td.choice_dice})
await self.channel_layer.group_send(
f"tournament-{self.tournament.id}",
{
'tid': self.tournament_id,
'type': 'draw.send_poules',
'round': previous_round.number,
'poules': [
{
'letter': pool.get_letter_display(),
'teams': await pool.atrigrams(),
}
async for pool in previous_round.pool_set.order_by('letter').all()
]
})
previous_pool = previous_round.current_pool previous_pool = previous_round.current_pool
td = previous_pool.current_team td = previous_pool.current_team
@ -1468,17 +1465,31 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
'visible': True}) 'visible': True})
else: else:
# Go to the dice order # Go to the dice order
async for r0 in self.tournament.draw.round_set.all(): async for td in r.teamdraw_set.all():
async for td in r0.teamdraw_set.all(): td.pool = None
td.pool = None td.passage_index = None
td.passage_index = None td.choose_index = None
td.choose_index = None td.choice_dice = None
td.choice_dice = None await td.asave()
await td.asave()
r.current_pool = None r.current_pool = None
await r.asave() await r.asave()
await self.channel_layer.group_send(
f"tournament-{self.tournament.id}",
{
'tid': self.tournament_id,
'type': 'draw.send_poules',
'round': r.number,
'poules': [
{
'letter': pool.get_letter_display(),
'teams': await pool.atrigrams(),
}
async for pool in r.pool_set.order_by('letter').all()
]
})
round_tds = {td.id: td async for td in r.team_draws.prefetch_related('participation__team')} round_tds = {td.id: td async for td in r.team_draws.prefetch_related('participation__team')}
# Reset the last dice # Reset the last dice
@ -1548,8 +1559,45 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
'team': last_td.participation.team.trigram, 'team': last_td.participation.team.trigram,
'result': None}) 'result': None})
break break
else: elif r.number == 1:
# Cancel the draw if it is the first round
await self.abort() await self.abort()
else:
# Go back to the first round after resetting all
previous_round = await self.tournament.draw.round_set \
.prefetch_related('current_pool__current_team__participation__team').aget(number=r.number - 1)
self.tournament.draw.current_round = previous_round
await self.tournament.draw.asave()
async for td in previous_round.team_draws.prefetch_related('participation__team').all():
await self.channel_layer.group_send(
f"tournament-{self.tournament.id}", {'tid': self.tournament_id, 'type': 'draw.dice',
'team': td.participation.team.trigram,
'result': td.choice_dice})
previous_pool = previous_round.current_pool
td = previous_pool.current_team
td.purposed = td.accepted
td.accepted = None
await td.asave()
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.dice_visibility',
'visible': False})
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
{'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
'visible': True})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.set_problem',
'round': previous_round.number,
'team': td.participation.team.trigram,
'problem': td.accepted})
async def draw_alert(self, content): async def draw_alert(self, content):
""" """

View File

@ -0,0 +1,27 @@
# Generated by Django 5.0.6 on 2024-07-09 11:07
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("draw", "0005_alter_round_number_alter_teamdraw_accepted_and_more"),
]
operations = [
migrations.AlterField(
model_name="round",
name="current_pool",
field=models.ForeignKey(
default=None,
help_text="The current pool where teams select their problems.",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to="draw.pool",
verbose_name="current pool",
),
),
]

View File

@ -82,7 +82,7 @@ class Draw(models.Model):
elif self.current_round.current_pool.current_team is None: elif self.current_round.current_pool.current_team is None:
return 'DICE_ORDER_POULE' return 'DICE_ORDER_POULE'
elif self.current_round.current_pool.current_team.accepted is not None: elif self.current_round.current_pool.current_team.accepted is not None:
if self.current_round.number == 1: if self.current_round.number < settings.NB_ROUNDS:
# The last step can be the last problem acceptation after the first round # The last step can be the last problem acceptation after the first round
# only for the final between the two rounds # only for the final between the two rounds
return 'WAITING_FINAL' return 'WAITING_FINAL'
@ -205,7 +205,7 @@ class Round(models.Model):
current_pool = models.ForeignKey( current_pool = models.ForeignKey(
'Pool', 'Pool',
on_delete=models.CASCADE, on_delete=models.SET_NULL,
null=True, null=True,
default=None, default=None,
related_name='+', related_name='+',

View File

@ -700,6 +700,9 @@ document.addEventListener('DOMContentLoaded', () => {
let problem = problems[i] let problem = problems[i]
setProblemAccepted(tid, round, team, problem) setProblemAccepted(tid, round, team, problem)
let recapTeam = document.getElementById(`recap-${tid}-round-${round}-team-${team}`)
recapTeam.style.order = i.toString()
} }
} }

View File

@ -176,7 +176,7 @@
📁 {% trans "Export" %} 📁 {% trans "Export" %}
</button> </button>
</div> </div>
{% if tournament.final %} {% if tournament.final or TFJM.APP == "ETEAM" %}
{# Volunteers can continue the second round for the final tournament #} {# Volunteers can continue the second round for the final tournament #}
<div id="continue-{{ tournament.id }}" <div id="continue-{{ tournament.id }}"
class="card-footer text-center{% if tournament.draw.get_state != 'WAITING_FINAL' %} d-none{% endif %}"> class="card-footer text-center{% if tournament.draw.get_state != 'WAITING_FINAL' %} d-none{% endif %}">
@ -344,33 +344,33 @@
{% elif pool.size == 5 %} {% elif pool.size == 5 %}
{% if forloop.counter == 1 %} {% if forloop.counter == 1 %}
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
<td class="text-center"></td> <td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
{% elif forloop.counter == 2 %}
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
<td class="text-center"></td> <td class="text-center"></td>
{% elif forloop.counter == 2 %}
<td class="text-center"></td>
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
{% elif forloop.counter == 3 %} {% elif forloop.counter == 3 %}
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
<td class="text-center"></td> <td class="text-center"></td>
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
{% elif forloop.counter == 4 %} {% elif forloop.counter == 4 %}
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td> <td class="text-center"></td>
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
<td class="text-center"></td> <td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
{% elif forloop.counter == 5 %} {% elif forloop.counter == 5 %}
<td class="text-center"></td> <td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td> <td class="text-center"></td>
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td> <td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
{% endif %} {% endif %}
{% endif %} {% endif %}

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: TFJM\n" "Project-Id-Version: TFJM\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-06 22:34+0200\n" "POT-Creation-Date: 2024-07-09 13:22+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n" "Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -269,7 +269,7 @@ msgstr "équipes"
msgid "round" msgid "round"
msgstr "tour" msgstr "tour"
#: draw/apps.py:10 draw/consumers.py:1038 tfjm/templates/navbar.html:68 #: draw/apps.py:10 draw/consumers.py:1042 tfjm/templates/navbar.html:68
msgid "Draw" msgid "Draw"
msgstr "Tirage au sort" msgstr "Tirage au sort"
@ -311,7 +311,7 @@ msgstr "Le tirage au sort du tournoi {tournament} va commencer."
#: draw/consumers.py:256 draw/consumers.py:282 draw/consumers.py:692 #: draw/consumers.py:256 draw/consumers.py:282 draw/consumers.py:692
#: draw/consumers.py:910 draw/consumers.py:1000 draw/consumers.py:1022 #: draw/consumers.py:910 draw/consumers.py:1000 draw/consumers.py:1022
#: draw/consumers.py:1113 draw/templates/draw/tournament_content.html:5 #: draw/consumers.py:1125 draw/templates/draw/tournament_content.html:5
msgid "The draw has not started yet." msgid "The draw has not started yet."
msgstr "Le tirage au sort n'a pas encore commencé." msgstr "Le tirage au sort n'a pas encore commencé."
@ -363,12 +363,12 @@ msgstr ""
"sont déterminés à partir des ordres de passage du premier tour." "sont déterminés à partir des ordres de passage du premier tour."
#: draw/consumers.py:615 draw/consumers.py:755 draw/consumers.py:832 #: draw/consumers.py:615 draw/consumers.py:755 draw/consumers.py:832
#: draw/consumers.py:866 draw/consumers.py:991 draw/consumers.py:1089 #: draw/consumers.py:866 draw/consumers.py:991 draw/consumers.py:1095
msgid "Your turn!" msgid "Your turn!"
msgstr "À votre tour !" msgstr "À votre tour !"
#: draw/consumers.py:616 draw/consumers.py:756 draw/consumers.py:992 #: draw/consumers.py:616 draw/consumers.py:756 draw/consumers.py:992
#: draw/consumers.py:1090 #: draw/consumers.py:1096
msgid "It's your turn to draw a problem!" msgid "It's your turn to draw a problem!"
msgstr "C'est à vous de tirer un problème !" msgstr "C'est à vous de tirer un problème !"
@ -439,17 +439,27 @@ msgstr ""
msgid "This is only available for the final tournament." msgid "This is only available for the final tournament."
msgstr "Cela n'est possible que pour la finale." msgstr "Cela n'est possible que pour la finale."
#: draw/consumers.py:1029 #: draw/consumers.py:1030
#, python-brace-format
msgid "" msgid ""
"The draw of the round 2 is starting. The passage order is determined from " "The draw of the round {round} is starting. The passage order is determined "
"the ranking of the first round, in order to mix the teams between the two " "from the ranking of the first round, in order to mix the teams between the "
"days." "two days."
msgstr "" msgstr ""
"Le tirage au sort du tour 2 commence. L'ordre de passage est déterminé à " "Le tirage au sort du tour {round} commence. L'ordre de passage est déterminé à "
"partir du classement du premier tour, afin de mélanger les équipes entre les " "partir du classement du premier tour, afin de mélanger les équipes entre les "
"deux jours." "deux jours."
#: draw/consumers.py:1039 #: draw/consumers.py:1034
#, python-brace-format
msgid ""
"The draw of the round {round} is starting. The passage order is another time "
"randomly drawn."
msgstr ""
"Le tirage au sort du tour {round} commence. L'ordre de passage est à nouveau tiré "
"au hasard."
#: draw/consumers.py:1043
msgid "The draw of the second round is starting!" msgid "The draw of the second round is starting!"
msgstr "Le tirage au sort du deuxième tour commence !" msgstr "Le tirage au sort du deuxième tour commence !"
@ -866,11 +876,11 @@ msgstr "Opp"
#: draw/templates/draw/tournament_content.html:331 #: draw/templates/draw/tournament_content.html:331
#: draw/templates/draw/tournament_content.html:337 #: draw/templates/draw/tournament_content.html:337
#: draw/templates/draw/tournament_content.html:339 #: draw/templates/draw/tournament_content.html:339
#: draw/templates/draw/tournament_content.html:350 #: draw/templates/draw/tournament_content.html:347
#: draw/templates/draw/tournament_content.html:352 #: draw/templates/draw/tournament_content.html:354
#: draw/templates/draw/tournament_content.html:359 #: draw/templates/draw/tournament_content.html:361
#: draw/templates/draw/tournament_content.html:366 #: draw/templates/draw/tournament_content.html:368
#: draw/templates/draw/tournament_content.html:373 #: draw/templates/draw/tournament_content.html:370
msgctxt "Role abbreviation" msgctxt "Role abbreviation"
msgid "Obs" msgid "Obs"
msgstr "Obs" msgstr "Obs"
@ -2847,17 +2857,17 @@ msgstr "L'utilisateur⋅rice suivant n'est pas inscrit⋅e en tant que juré⋅e
msgid "Notes were successfully uploaded." msgid "Notes were successfully uploaded."
msgstr "Les notes ont bien été envoyées." msgstr "Les notes ont bien été envoyées."
#: participation/views.py:1902 #: participation/views.py:1904
#, python-brace-format #, python-brace-format
msgid "Notation sheets of pool {pool} of {tournament}.zip" msgid "Notation sheets of pool {pool} of {tournament}.zip"
msgstr "Feuilles de notations pour la poule {pool} du tournoi {tournament}.zip" msgstr "Feuilles de notations pour la poule {pool} du tournoi {tournament}.zip"
#: participation/views.py:1907 #: participation/views.py:1909
#, python-brace-format #, python-brace-format
msgid "Notation sheets of {tournament}.zip" msgid "Notation sheets of {tournament}.zip"
msgstr "Feuilles de notation de {tournament}.zip" msgstr "Feuilles de notation de {tournament}.zip"
#: participation/views.py:2074 #: participation/views.py:2076
msgid "You can't upload a written review after the deadline." msgid "You can't upload a written review after the deadline."
msgstr "Vous ne pouvez pas envoyer de note de synthèse après la date limite." msgstr "Vous ne pouvez pas envoyer de note de synthèse après la date limite."