Compare commits
4 Commits
f398bedcf3
...
1b24e90635
Author | SHA1 | Date |
---|---|---|
Emmy D'Anello | 1b24e90635 | |
Emmy D'Anello | 338f0d456a | |
Emmy D'Anello | 2c4de8cec3 | |
Emmy D'Anello | 6b7d52c79b |
|
@ -1021,14 +1021,18 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
if not await Draw.objects.filter(tournament=self.tournament).aexists():
|
||||
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')
|
||||
|
||||
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
|
||||
msg = _("The draw of the round 2 is starting. "
|
||||
"The passage order is determined from the ranking of the first round, "
|
||||
"in order to mix the teams between the two days.")
|
||||
if settings.TFJM_APP == "TFJM":
|
||||
msg = str(_("The draw of the round {round} is starting. "
|
||||
"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
|
||||
await self.tournament.draw.asave()
|
||||
|
||||
|
@ -1036,29 +1040,30 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
|
||||
{'tid': self.tournament_id, 'type': 'draw.notify',
|
||||
'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
|
||||
pool = await Pool.objects.filter(round=self.tournament.draw.current_round, letter=1).aget()
|
||||
r2.current_pool = pool
|
||||
await r2.asave()
|
||||
if settings.TFJM_APP == "TFJM":
|
||||
# Set the first pool of the second round as the active pool
|
||||
pool = await Pool.objects.filter(round=self.tournament.draw.current_round, letter=1).aget()
|
||||
r2.current_pool = pool
|
||||
await r2.asave()
|
||||
|
||||
# Fetch notes from the first round
|
||||
notes = dict()
|
||||
async for participation in self.tournament.participations.filter(valid=True).prefetch_related('team').all():
|
||||
notes[participation] = sum([await pool.aaverage(participation)
|
||||
async for pool in self.tournament.pools.filter(participations=participation)
|
||||
.prefetch_related('passages')])
|
||||
# Sort notes in a decreasing order
|
||||
ordered_participations = sorted(notes.keys(), key=lambda x: -notes[x])
|
||||
# Define pools and passage orders from the ranking of the first round
|
||||
async for pool in r2.pool_set.order_by('letter').all():
|
||||
for i in range(pool.size):
|
||||
participation = ordered_participations.pop(0)
|
||||
td = await TeamDraw.objects.aget(round=r2, participation=participation)
|
||||
td.pool = pool
|
||||
td.passage_index = i
|
||||
await td.asave()
|
||||
# Fetch notes from the first round
|
||||
notes = dict()
|
||||
async for participation in self.tournament.participations.filter(valid=True).prefetch_related('team').all():
|
||||
notes[participation] = sum([await pool.aaverage(participation)
|
||||
async for pool in self.tournament.pools.filter(participations=participation)
|
||||
.prefetch_related('passages')])
|
||||
# Sort notes in a decreasing order
|
||||
ordered_participations = sorted(notes.keys(), key=lambda x: -notes[x])
|
||||
# Define pools and passage orders from the ranking of the first round
|
||||
async for pool in r2.pool_set.order_by('letter').all():
|
||||
for i in range(pool.size):
|
||||
participation = ordered_participations.pop(0)
|
||||
td = await TeamDraw.objects.aget(round=r2, participation=participation)
|
||||
td.pool = pool
|
||||
td.passage_index = i
|
||||
await td.asave()
|
||||
|
||||
# Send pools to users
|
||||
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
|
||||
|
@ -1078,16 +1083,23 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
f"tournament-{self.tournament.id}",
|
||||
{'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'):
|
||||
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
|
||||
{'tid': self.tournament_id, 'type': 'draw.dice_visibility',
|
||||
'visible': True})
|
||||
if settings.TFJM_APP == "TFJM":
|
||||
async for td in r2.current_pool.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!")})
|
||||
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}",
|
||||
{'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}",
|
||||
{'tid': self.tournament_id, 'type': 'draw.set_active',
|
||||
'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
|
||||
async def cancel_last_step(self, **kwargs):
|
||||
|
@ -1376,7 +1388,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
'round': r.number,
|
||||
'team': td.participation.team.trigram,
|
||||
'problem': td.accepted})
|
||||
elif r.number >= 2:
|
||||
elif r.number >= 2 and settings.TFJM_APP == "TFJM":
|
||||
if not self.tournament.final:
|
||||
# Go to the previous round
|
||||
previous_round = await self.tournament.draw.round_set \
|
||||
|
@ -1390,21 +1402,6 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
'team': td.participation.team.trigram,
|
||||
'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
|
||||
|
||||
td = previous_pool.current_team
|
||||
|
@ -1468,17 +1465,31 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
'visible': True})
|
||||
else:
|
||||
# Go to the dice order
|
||||
async for r0 in self.tournament.draw.round_set.all():
|
||||
async for td in r0.teamdraw_set.all():
|
||||
td.pool = None
|
||||
td.passage_index = None
|
||||
td.choose_index = None
|
||||
td.choice_dice = None
|
||||
await td.asave()
|
||||
async for td in r.teamdraw_set.all():
|
||||
td.pool = None
|
||||
td.passage_index = None
|
||||
td.choose_index = None
|
||||
td.choice_dice = None
|
||||
await td.asave()
|
||||
|
||||
r.current_pool = None
|
||||
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')}
|
||||
|
||||
# Reset the last dice
|
||||
|
@ -1548,8 +1559,45 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
'team': last_td.participation.team.trigram,
|
||||
'result': None})
|
||||
break
|
||||
else:
|
||||
elif r.number == 1:
|
||||
# Cancel the draw if it is the first round
|
||||
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):
|
||||
"""
|
||||
|
|
|
@ -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",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -82,7 +82,7 @@ class Draw(models.Model):
|
|||
elif self.current_round.current_pool.current_team is None:
|
||||
return 'DICE_ORDER_POULE'
|
||||
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
|
||||
# only for the final between the two rounds
|
||||
return 'WAITING_FINAL'
|
||||
|
@ -205,7 +205,7 @@ class Round(models.Model):
|
|||
|
||||
current_pool = models.ForeignKey(
|
||||
'Pool',
|
||||
on_delete=models.CASCADE,
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
default=None,
|
||||
related_name='+',
|
||||
|
|
|
@ -700,6 +700,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
let problem = problems[i]
|
||||
|
||||
setProblemAccepted(tid, round, team, problem)
|
||||
|
||||
let recapTeam = document.getElementById(`recap-${tid}-round-${round}-team-${team}`)
|
||||
recapTeam.style.order = i.toString()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@
|
|||
📁 {% trans "Export" %}
|
||||
</button>
|
||||
</div>
|
||||
{% if tournament.final %}
|
||||
{% if tournament.final or TFJM.APP == "ETEAM" %}
|
||||
{# Volunteers can continue the second round for the final tournament #}
|
||||
<div id="continue-{{ tournament.id }}"
|
||||
class="card-footer text-center{% if tournament.draw.get_state != 'WAITING_FINAL' %} d-none{% endif %}">
|
||||
|
@ -344,33 +344,33 @@
|
|||
{% elif pool.size == 5 %}
|
||||
{% if forloop.counter == 1 %}
|
||||
<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 "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>
|
||||
{% 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 "Opp" context "Role abbreviation" %}</td>
|
||||
{% elif forloop.counter == 3 %}
|
||||
<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">{% 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>
|
||||
{% elif forloop.counter == 4 %}
|
||||
<td class="text-center">{% trans "Rev" 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"></td>
|
||||
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
|
||||
{% 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 "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>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: TFJM\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"
|
||||
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -269,7 +269,7 @@ msgstr "équipes"
|
|||
msgid "round"
|
||||
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"
|
||||
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: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."
|
||||
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."
|
||||
|
||||
#: 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!"
|
||||
msgstr "À votre tour !"
|
||||
|
||||
#: 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!"
|
||||
msgstr "C'est à vous de tirer un problème !"
|
||||
|
||||
|
@ -439,17 +439,27 @@ msgstr ""
|
|||
msgid "This is only available for the final tournament."
|
||||
msgstr "Cela n'est possible que pour la finale."
|
||||
|
||||
#: draw/consumers.py:1029
|
||||
#: draw/consumers.py:1030
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"The draw of the round 2 is starting. The passage order is determined from "
|
||||
"the ranking of the first round, in order to mix the teams between the two "
|
||||
"days."
|
||||
"The draw of the round {round} is starting. The passage order is determined "
|
||||
"from the ranking of the first round, in order to mix the teams between the "
|
||||
"two days."
|
||||
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 "
|
||||
"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!"
|
||||
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:337
|
||||
#: draw/templates/draw/tournament_content.html:339
|
||||
#: draw/templates/draw/tournament_content.html:350
|
||||
#: draw/templates/draw/tournament_content.html:352
|
||||
#: draw/templates/draw/tournament_content.html:359
|
||||
#: draw/templates/draw/tournament_content.html:366
|
||||
#: draw/templates/draw/tournament_content.html:373
|
||||
#: draw/templates/draw/tournament_content.html:347
|
||||
#: draw/templates/draw/tournament_content.html:354
|
||||
#: draw/templates/draw/tournament_content.html:361
|
||||
#: draw/templates/draw/tournament_content.html:368
|
||||
#: draw/templates/draw/tournament_content.html:370
|
||||
msgctxt "Role abbreviation"
|
||||
msgid "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."
|
||||
msgstr "Les notes ont bien été envoyées."
|
||||
|
||||
#: participation/views.py:1902
|
||||
#: participation/views.py:1904
|
||||
#, python-brace-format
|
||||
msgid "Notation sheets of pool {pool} of {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
|
||||
msgid "Notation sheets of {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."
|
||||
msgstr "Vous ne pouvez pas envoyer de note de synthèse après la date limite."
|
||||
|
||||
|
|
Loading…
Reference in New Issue