1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2024-12-25 06:22:22 +00:00

Upload notes from a CSV sheet

This commit is contained in:
Yohann D'ANELLO 2022-05-15 12:23:17 +02:00
parent 5f2cd16071
commit d18f76cf80
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
7 changed files with 311 additions and 132 deletions

View File

@ -1,11 +1,16 @@
# Copyright (C) 2020 by Animath # Copyright (C) 2020 by Animath
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import csv
import re import re
from io import StringIO
from typing import Iterable
from bootstrap_datepicker_plus.widgets import DatePickerInput, DateTimePickerInput from bootstrap_datepicker_plus.widgets import DatePickerInput, DateTimePickerInput
from django import forms from django import forms
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.validators import FileExtensionValidator
from django.utils import formats from django.utils import formats
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from PyPDF3 import PdfFileReader from PyPDF3 import PdfFileReader
@ -190,6 +195,69 @@ class PoolTeamsForm(forms.ModelForm):
} }
class UploadNotesForm(forms.Form):
file = forms.FileField(
label=_("CSV file:"),
validators=[FileExtensionValidator(allowed_extensions=["csv"])],
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['file'].widget.attrs['accept'] = 'text/csv'
def clean(self):
cleaned_data = super().clean()
if 'file' in cleaned_data:
file = cleaned_data['file']
with file:
try:
csvfile = csv.reader(StringIO(file.read().decode()))
except UnicodeDecodeError:
self.add_error('file', _("This file contains non-UTF-8 content. "
"Please send your sheet as a CSV file."))
self.process(csvfile, cleaned_data)
return cleaned_data
def process(self, csvfile: Iterable[str], cleaned_data: dict):
parsed_notes = {}
for line in csvfile:
line = [s for s in line if s]
if len(line) < 19:
continue
name = line[0]
notes = line[1:19]
if not all(s.isnumeric() for s in notes):
continue
notes = list(map(int, notes))
if max(notes) < 3 or min(notes) < 0:
continue
max_notes = 3 * [20, 16, 9, 10, 9, 10]
for n, max_n in zip(notes, max_notes):
if n > max_n:
self.add_error('file',
_("The following note is higher of the maximum expected value:")
+ str(n) + " > " + str(max_n))
first_name, last_name = tuple(name.split(' ', 1))
jury = User.objects.filter(first_name=first_name, last_name=last_name)
if jury.count() != 1:
self.form.add_error('file', _("The following user was not found:") + " " + name)
continue
jury = jury.get()
vr = jury.registration
parsed_notes[vr] = notes
cleaned_data['parsed_notes'] = parsed_notes
return cleaned_data
class PassageForm(forms.ModelForm): class PassageForm(forms.ModelForm):
def clean(self): def clean(self):
cleaned_data = super().clean() cleaned_data = super().clean()

View File

@ -654,6 +654,15 @@ class Note(models.Model):
default=0, default=0,
) )
def set_all(self, defender_writing: int, defender_oral: int, opponent_writing: int, opponent_oral: int,
reporter_writing: int, reporter_oral: int):
self.defender_writing = defender_writing
self.defender_oral = defender_oral
self.opponent_writing = opponent_writing
self.opponent_oral = opponent_oral
self.reporter_writing = reporter_writing
self.reporter_oral = reporter_oral
def get_absolute_url(self): def get_absolute_url(self):
return reverse_lazy("participation:passage_detail", args=(self.passage.pk,)) return reverse_lazy("participation:passage_detail", args=(self.passage.pk,))

View File

@ -54,6 +54,7 @@
<button class="btn btn-success" data-toggle="modal" data-target="#addPassageModal">{% trans "Add passage" %}</button> <button class="btn btn-success" data-toggle="modal" data-target="#addPassageModal">{% trans "Add passage" %}</button>
<button class="btn btn-primary" data-toggle="modal" data-target="#updatePoolModal">{% trans "Update" %}</button> <button class="btn btn-primary" data-toggle="modal" data-target="#updatePoolModal">{% trans "Update" %}</button>
<button class="btn btn-primary" data-toggle="modal" data-target="#updateTeamsModal">{% trans "Update teams" %}</button> <button class="btn btn-primary" data-toggle="modal" data-target="#updateTeamsModal">{% trans "Update teams" %}</button>
<button class="btn btn-primary" data-toggle="modal" data-target="#uploadNotesModal">{% trans "Upload notes from a CSV file" %}</button>
</div> </div>
{% endif %} {% endif %}
</div> </div>
@ -78,6 +79,11 @@
{% trans "Update" as modal_button %} {% trans "Update" as modal_button %}
{% url "participation:pool_update_teams" pk=pool.pk as modal_action %} {% url "participation:pool_update_teams" pk=pool.pk as modal_action %}
{% include "base_modal.html" with modal_id="updateTeams" %} {% include "base_modal.html" with modal_id="updateTeams" %}
{% trans "Upload notes" as modal_title %}
{% trans "Upload" as modal_button %}
{% url "participation:pool_upload_notes" pk=pool.pk as modal_action %}
{% include "base_modal.html" with modal_id="uploadNotes" modal_button_type="success" modal_enctype="multipart/form-data" %}
{% endblock %} {% endblock %}
{% block extrajavascript %} {% block extrajavascript %}
@ -100,6 +106,12 @@
if (!modalBody.html().trim()) if (!modalBody.html().trim())
modalBody.load("{% url "participation:passage_create" pk=pool.pk %} #form-content") modalBody.load("{% url "participation:passage_create" pk=pool.pk %} #form-content")
}); });
$('button[data-target="#uploadNotesModal"]').click(function() {
let modalBody = $("#uploadNotesModal div.modal-body");
if (!modalBody.html().trim())
modalBody.load("{% url "participation:pool_upload_notes" pk=pool.pk %} #form-content")
});
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,14 @@
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load i18n %}
{% block content %}
<form method="post" enctype="multipart/form-data">
<div id="form-content">
{% csrf_token %}
{{ form|crispy }}
</div>
<button class="btn btn-primary" type="submit">{% trans "Upload" %}</button>
</form>
{% endblock %}

View File

@ -6,9 +6,10 @@ from django.views.generic import TemplateView
from .views import CreateTeamView, JoinTeamView, MyParticipationDetailView, MyTeamDetailView, NoteUpdateView, \ from .views import CreateTeamView, JoinTeamView, MyParticipationDetailView, MyTeamDetailView, NoteUpdateView, \
ParticipationDetailView, PassageCreateView, PassageDetailView, PassageUpdateView, PoolCreateView, PoolDetailView, \ ParticipationDetailView, PassageCreateView, PassageDetailView, PassageUpdateView, PoolCreateView, PoolDetailView, \
PoolUpdateTeamsView, PoolUpdateView, SolutionUploadView, SynthesisUploadView, TeamAuthorizationsView, \ PoolUpdateTeamsView, PoolUpdateView, PoolUploadNotesView, SolutionUploadView, SynthesisUploadView,\
TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, TeamUploadMotivationLetterView, TournamentCreateView, \ TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \
TournamentDetailView, TournamentExportCSVView, TournamentListView, TournamentUpdateView TeamUploadMotivationLetterView, TournamentCreateView, TournamentDetailView, TournamentExportCSVView, \
TournamentListView, TournamentUpdateView
app_name = "participation" app_name = "participation"
@ -36,6 +37,7 @@ urlpatterns = [
path("pools/<int:pk>/", PoolDetailView.as_view(), name="pool_detail"), path("pools/<int:pk>/", PoolDetailView.as_view(), name="pool_detail"),
path("pools/<int:pk>/update/", PoolUpdateView.as_view(), name="pool_update"), path("pools/<int:pk>/update/", PoolUpdateView.as_view(), name="pool_update"),
path("pools/<int:pk>/update-teams/", PoolUpdateTeamsView.as_view(), name="pool_update_teams"), path("pools/<int:pk>/update-teams/", PoolUpdateTeamsView.as_view(), name="pool_update_teams"),
path("pools/<int:pk>/upload-notes/", PoolUploadNotesView.as_view(), name="pool_upload_notes"),
path("pools/passages/add/<int:pk>/", PassageCreateView.as_view(), name="passage_create"), path("pools/passages/add/<int:pk>/", PassageCreateView.as_view(), name="passage_create"),
path("pools/passages/<int:pk>/", PassageDetailView.as_view(), name="passage_detail"), path("pools/passages/<int:pk>/", PassageDetailView.as_view(), name="passage_detail"),
path("pools/passages/<int:pk>/update/", PassageUpdateView.as_view(), name="passage_update"), path("pools/passages/<int:pk>/update/", PassageUpdateView.as_view(), name="passage_update"),

View File

@ -6,6 +6,7 @@ import os
from zipfile import ZipFile from zipfile import ZipFile
from django.conf import settings from django.conf import settings
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
@ -18,6 +19,7 @@ from django.urls import reverse_lazy
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.generic import CreateView, DetailView, FormView, RedirectView, TemplateView, UpdateView, View from django.views.generic import CreateView, DetailView, FormView, RedirectView, TemplateView, UpdateView, View
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import FormMixin, ProcessFormView from django.views.generic.edit import FormMixin, ProcessFormView
from django_tables2 import SingleTableView from django_tables2 import SingleTableView
from magic import Magic from magic import Magic
@ -28,7 +30,7 @@ from tfjm.views import AdminMixin, VolunteerMixin
from .forms import JoinTeamForm, MotivationLetterForm, NoteForm, ParticipationForm, PassageForm, PoolForm, \ from .forms import JoinTeamForm, MotivationLetterForm, NoteForm, ParticipationForm, PassageForm, PoolForm, \
PoolTeamsForm, RequestValidationForm, SolutionForm, SynthesisForm, TeamForm, TournamentForm, \ PoolTeamsForm, RequestValidationForm, SolutionForm, SynthesisForm, TeamForm, TournamentForm, \
ValidateParticipationForm UploadNotesForm, ValidateParticipationForm
from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament
from .tables import NoteTable, ParticipationTable, PassageTable, PoolTable, TeamTable, TournamentTable from .tables import NoteTable, ParticipationTable, PassageTable, PoolTable, TeamTable, TournamentTable
@ -703,6 +705,43 @@ class PoolUpdateTeamsView(VolunteerMixin, UpdateView):
return self.handle_no_permission() return self.handle_no_permission()
class PoolUploadNotesView(VolunteerMixin, FormView, DetailView):
model = Pool
form_class = UploadNotesForm
template_name = 'participation/upload_notes.html'
def dispatch(self, request, *args, **kwargs):
self.object = self.get_object()
if request.user.registration.is_admin or request.user.registration.is_volunteer \
and (self.object.tournament in request.user.registration.organized_tournaments.all()
or request.user.registration in self.object.juries.all()):
return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission()
@transaction.atomic
def form_valid(self, form):
pool = self.get_object()
parsed_notes = form.cleaned_data['parsed_notes']
for vr, notes in parsed_notes.items():
if vr not in pool.juries.all():
form.add_error('file', _("The following user is not registered as a jury:") + " " + str(vr))
for i, passage in enumerate(pool.passages.all()):
note = Note.objects.get(jury=vr, passage=passage)
passage_notes = notes[6 * i:6 * (i + 1)]
note.set_all(*passage_notes)
note.save()
messages.success(self.request, _("Notes were successfully uploaded."))
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy('participation:pool_detail', args=(self.kwargs['pk'],))
class PassageCreateView(VolunteerMixin, CreateView): class PassageCreateView(VolunteerMixin, CreateView):
model = Passage model = Passage
form_class = PassageForm form_class = PassageForm

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: 2022-04-26 15:09+0200\n" "POT-Creation-Date: 2022-05-15 12:23+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Yohann D'ANELLO <yohann.danello@animath.fr>\n" "Last-Translator: Yohann D'ANELLO <yohann.danello@animath.fr>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -104,59 +104,78 @@ msgstr "Changelog de type \"{action}\" pour le modèle {model} le {timestamp}"
msgid "valid" msgid "valid"
msgstr "valide" msgstr "valide"
#: apps/participation/forms.py:25 #: apps/participation/forms.py:30
msgid "This name is already used." msgid "This name is already used."
msgstr "Ce nom est déjà utilisé." msgstr "Ce nom est déjà utilisé."
#: apps/participation/forms.py:32 apps/participation/models.py:41 #: apps/participation/forms.py:37 apps/participation/models.py:41
msgid "The trigram must be composed of three uppercase letters." msgid "The trigram must be composed of three uppercase letters."
msgstr "Le trigramme doit être composé de trois lettres majuscules." msgstr "Le trigramme doit être composé de trois lettres majuscules."
#: apps/participation/forms.py:35 #: apps/participation/forms.py:40
msgid "This trigram is already used." msgid "This trigram is already used."
msgstr "Ce trigramme est déjà utilisé." msgstr "Ce trigramme est déjà utilisé."
#: apps/participation/forms.py:50 #: apps/participation/forms.py:55
msgid "No team was found with this access code." msgid "No team was found with this access code."
msgstr "Aucune équipe n'a été trouvée avec ce code d'accès." msgstr "Aucune équipe n'a été trouvée avec ce code d'accès."
#: apps/participation/forms.py:79 apps/participation/forms.py:215 #: apps/participation/forms.py:84 apps/participation/forms.py:283
#: apps/registration/forms.py:117 apps/registration/forms.py:139 #: apps/registration/forms.py:117 apps/registration/forms.py:139
#: apps/registration/forms.py:161 apps/registration/forms.py:215 #: apps/registration/forms.py:161 apps/registration/forms.py:215
msgid "The uploaded file size must be under 2 Mo." msgid "The uploaded file size must be under 2 Mo."
msgstr "Le fichier envoyé doit peser moins de 2 Mo." msgstr "Le fichier envoyé doit peser moins de 2 Mo."
#: apps/participation/forms.py:81 apps/registration/forms.py:119 #: apps/participation/forms.py:86 apps/registration/forms.py:119
#: apps/registration/forms.py:141 apps/registration/forms.py:163 #: apps/registration/forms.py:141 apps/registration/forms.py:163
#: apps/registration/forms.py:217 #: apps/registration/forms.py:217
msgid "The uploaded file must be a PDF, PNG of JPEG file." msgid "The uploaded file must be a PDF, PNG of JPEG file."
msgstr "Le fichier envoyé doit être au format PDF, PNG ou JPEG." msgstr "Le fichier envoyé doit être au format PDF, PNG ou JPEG."
#: apps/participation/forms.py:99 #: apps/participation/forms.py:104
msgid "I engage myself to participate to the whole TFJM²." msgid "I engage myself to participate to the whole TFJM²."
msgstr "Je m'engage à participer à l'intégralité du TFJM²." msgstr "Je m'engage à participer à l'intégralité du TFJM²."
#: apps/participation/forms.py:114 #: apps/participation/forms.py:119
msgid "Message to address to the team:" msgid "Message to address to the team:"
msgstr "Message à adresser à l'équipe :" msgstr "Message à adresser à l'équipe :"
#: apps/participation/forms.py:152 #: apps/participation/forms.py:157
msgid "The uploaded file size must be under 5 Mo." msgid "The uploaded file size must be under 5 Mo."
msgstr "Le fichier envoyé doit peser moins de 5 Mo." msgstr "Le fichier envoyé doit peser moins de 5 Mo."
#: apps/participation/forms.py:154 apps/participation/forms.py:217 #: apps/participation/forms.py:159 apps/participation/forms.py:285
msgid "The uploaded file must be a PDF file." msgid "The uploaded file must be a PDF file."
msgstr "Le fichier envoyé doit être au format PDF." msgstr "Le fichier envoyé doit être au format PDF."
#: apps/participation/forms.py:158 #: apps/participation/forms.py:163
msgid "The PDF file must not have more than 30 pages." msgid "The PDF file must not have more than 30 pages."
msgstr "Le fichier PDF ne doit pas avoir plus de 30 pages." msgstr "Le fichier PDF ne doit pas avoir plus de 30 pages."
#: apps/participation/forms.py:198 #: apps/participation/forms.py:200
msgid "CSV file:"
msgstr "Tableur au format CSV :"
#: apps/participation/forms.py:217
msgid ""
"This file contains non-UTF-8 content. Please send your sheet as a CSV file."
msgstr ""
"Ce fichier contient des éléments non-UTF-8. Merci d'envoyer votre tableur au "
"format CSV."
#: apps/participation/forms.py:242
msgid "The following note is higher of the maximum expected value:"
msgstr "La note suivante est supérieure au maximum attendu :"
#: apps/participation/forms.py:249
msgid "The following user was not found:"
msgstr "L'utilisateur suivant n'a pas été trouvé :"
#: apps/participation/forms.py:266
msgid "The defender, the opponent and the reporter must be different." msgid "The defender, the opponent and the reporter must be different."
msgstr "Le défenseur, l'opposant et le rapporteur doivent être différents." msgstr "Le défenseur, l'opposant et le rapporteur doivent être différents."
#: apps/participation/forms.py:202 #: apps/participation/forms.py:270
msgid "This defender did not work on this problem." msgid "This defender did not work on this problem."
msgstr "Ce défenseur ne travaille pas sur ce problème." msgstr "Ce défenseur ne travaille pas sur ce problème."
@ -203,7 +222,7 @@ msgstr "début"
msgid "end" msgid "end"
msgstr "fin" msgstr "fin"
#: apps/participation/models.py:147 apps/participation/models.py:408 #: apps/participation/models.py:147
#: apps/participation/templates/participation/tournament_detail.html:18 #: apps/participation/templates/participation/tournament_detail.html:18
msgid "place" msgid "place"
msgstr "lieu" msgstr "lieu"
@ -286,8 +305,8 @@ msgstr "L'équipe est sélectionnée pour la finale."
msgid "Participation of the team {name} ({trigram})" msgid "Participation of the team {name} ({trigram})"
msgstr "Participation de l'équipe {name} ({trigram})" msgstr "Participation de l'équipe {name} ({trigram})"
#: apps/participation/models.py:331 apps/participation/models.py:537 #: apps/participation/models.py:331 apps/participation/models.py:530
#: apps/participation/models.py:577 #: apps/participation/models.py:568
msgid "participation" msgid "participation"
msgstr "participation" msgstr "participation"
@ -342,36 +361,32 @@ msgstr "poule"
msgid "pools" msgid "pools"
msgstr "poules" msgstr "poules"
#: apps/participation/models.py:410 #: apps/participation/models.py:408
msgid "Where the solution is presented?"
msgstr "Où est-ce que les solutions sont défendues ?"
#: apps/participation/models.py:415
msgid "defended solution" msgid "defended solution"
msgstr "solution défendue" msgstr "solution défendue"
#: apps/participation/models.py:417 apps/participation/models.py:544 #: apps/participation/models.py:410 apps/participation/models.py:537
#, python-brace-format #, python-brace-format
msgid "Problem #{problem}" msgid "Problem #{problem}"
msgstr "Problème n°{problem}" msgstr "Problème n°{problem}"
#: apps/participation/models.py:424 apps/participation/tables.py:106 #: apps/participation/models.py:417 apps/participation/tables.py:106
msgid "defender" msgid "defender"
msgstr "défenseur" msgstr "défenseur"
#: apps/participation/models.py:431 apps/participation/models.py:589 #: apps/participation/models.py:424 apps/participation/models.py:580
msgid "opponent" msgid "opponent"
msgstr "opposant" msgstr "opposant"
#: apps/participation/models.py:438 apps/participation/models.py:590 #: apps/participation/models.py:431 apps/participation/models.py:581
msgid "reporter" msgid "reporter"
msgstr "rapporteur" msgstr "rapporteur"
#: apps/participation/models.py:443 #: apps/participation/models.py:436
msgid "penalties" msgid "penalties"
msgstr "pénalités" msgstr "pénalités"
#: apps/participation/models.py:445 #: apps/participation/models.py:438
msgid "" msgid ""
"Number of penalties for the defender. The defender will loose a 0.5 " "Number of penalties for the defender. The defender will loose a 0.5 "
"coefficient per penalty." "coefficient per penalty."
@ -379,108 +394,108 @@ msgstr ""
"Nombre de pénalités pour le défenseur. Le défenseur perd un coefficient 0.5 " "Nombre de pénalités pour le défenseur. Le défenseur perd un coefficient 0.5 "
"sur sa solution écrite par pénalité." "sur sa solution écrite par pénalité."
#: apps/participation/models.py:505 apps/participation/models.py:508 #: apps/participation/models.py:498 apps/participation/models.py:501
#: apps/participation/models.py:511 #: apps/participation/models.py:504
#, python-brace-format #, python-brace-format
msgid "Team {trigram} is not registered in the pool." msgid "Team {trigram} is not registered in the pool."
msgstr "L'équipe {trigram} n'est pas inscrite dans la poule." msgstr "L'équipe {trigram} n'est pas inscrite dans la poule."
#: apps/participation/models.py:516 #: apps/participation/models.py:509
#, python-brace-format #, python-brace-format
msgid "Passage of {defender} for problem {problem}" msgid "Passage of {defender} for problem {problem}"
msgstr "Passage de {defender} pour le problème {problem}" msgstr "Passage de {defender} pour le problème {problem}"
#: apps/participation/models.py:520 apps/participation/models.py:584 #: apps/participation/models.py:513 apps/participation/models.py:575
#: apps/participation/models.py:628 #: apps/participation/models.py:617
msgid "passage" msgid "passage"
msgstr "passage" msgstr "passage"
#: apps/participation/models.py:521 #: apps/participation/models.py:514
msgid "passages" msgid "passages"
msgstr "passages" msgstr "passages"
#: apps/participation/models.py:542 #: apps/participation/models.py:535
msgid "problem" msgid "problem"
msgstr "numéro de problème" msgstr "numéro de problème"
#: apps/participation/models.py:549 #: apps/participation/models.py:542
msgid "solution for the final tournament" msgid "solution for the final tournament"
msgstr "solution pour la finale" msgstr "solution pour la finale"
#: apps/participation/models.py:554 apps/participation/models.py:595 #: apps/participation/models.py:547 apps/participation/models.py:586
msgid "file" msgid "file"
msgstr "fichier" msgstr "fichier"
#: apps/participation/models.py:562 #: apps/participation/models.py:553
#, python-brace-format #, python-brace-format
msgid "Solution of team {team} for problem {problem}" msgid "Solution of team {team} for problem {problem}"
msgstr "Solution de l'équipe {team} pour le problème {problem}" msgstr "Solution de l'équipe {team} pour le problème {problem}"
#: apps/participation/models.py:564 #: apps/participation/models.py:555
msgid "for final" msgid "for final"
msgstr "pour la finale" msgstr "pour la finale"
#: apps/participation/models.py:567 #: apps/participation/models.py:558
msgid "solution" msgid "solution"
msgstr "solution" msgstr "solution"
#: apps/participation/models.py:568 #: apps/participation/models.py:559
msgid "solutions" msgid "solutions"
msgstr "solutions" msgstr "solutions"
#: apps/participation/models.py:603 #: apps/participation/models.py:592
#, python-brace-format #, python-brace-format
msgid "Synthesis of {team} as {type} for problem {problem} of {defender}" msgid "Synthesis of {team} as {type} for problem {problem} of {defender}"
msgstr "" msgstr ""
"Note de synthèse de l'équipe {team} en tant que {type} pour le problème " "Note de synthèse de l'équipe {team} en tant que {type} pour le problème "
"{problem} de {defender}" "{problem} de {defender}"
#: apps/participation/models.py:611 #: apps/participation/models.py:600
msgid "synthesis" msgid "synthesis"
msgstr "note de synthèse" msgstr "note de synthèse"
#: apps/participation/models.py:612 #: apps/participation/models.py:601
msgid "syntheses" msgid "syntheses"
msgstr "notes de synthèse" msgstr "notes de synthèse"
#: apps/participation/models.py:621 #: apps/participation/models.py:610
msgid "jury" msgid "jury"
msgstr "jury" msgstr "jury"
#: apps/participation/models.py:633 #: apps/participation/models.py:622
msgid "defender writing note" msgid "defender writing note"
msgstr "note d'écrit du défenseur" msgstr "note d'écrit du défenseur"
#: apps/participation/models.py:639 #: apps/participation/models.py:628
msgid "defender oral note" msgid "defender oral note"
msgstr "note d'oral du défenseur" msgstr "note d'oral du défenseur"
#: apps/participation/models.py:645 #: apps/participation/models.py:634
msgid "opponent writing note" msgid "opponent writing note"
msgstr "note d'écrit de l'opposant" msgstr "note d'écrit de l'opposant"
#: apps/participation/models.py:651 #: apps/participation/models.py:640
msgid "opponent oral note" msgid "opponent oral note"
msgstr "note d'oral de l'opposant" msgstr "note d'oral de l'opposant"
#: apps/participation/models.py:657 #: apps/participation/models.py:646
msgid "reporter writing note" msgid "reporter writing note"
msgstr "not d'écrit du rapporteur" msgstr "note d'écrit du rapporteur"
#: apps/participation/models.py:663 #: apps/participation/models.py:652
msgid "reporter oral note" msgid "reporter oral note"
msgstr "note d'oral du rapporteur" msgstr "note d'oral du rapporteur"
#: apps/participation/models.py:672 #: apps/participation/models.py:670
#, python-brace-format #, python-brace-format
msgid "Notes of {jury} for {passage}" msgid "Notes of {jury} for {passage}"
msgstr "Notes de {jury} pour le {passage}" msgstr "Notes de {jury} pour le {passage}"
#: apps/participation/models.py:679 #: apps/participation/models.py:677
msgid "note" msgid "note"
msgstr "note" msgstr "note"
#: apps/participation/models.py:680 #: apps/participation/models.py:678
msgid "notes" msgid "notes"
msgstr "notes" msgstr "notes"
@ -555,12 +570,12 @@ msgid "Join"
msgstr "Rejoindre" msgstr "Rejoindre"
#: apps/participation/templates/participation/note_form.html:11 #: apps/participation/templates/participation/note_form.html:11
#: apps/participation/templates/participation/passage_detail.html:49 #: apps/participation/templates/participation/passage_detail.html:46
#: apps/participation/templates/participation/passage_detail.html:105 #: apps/participation/templates/participation/passage_detail.html:102
#: apps/participation/templates/participation/passage_detail.html:111 #: apps/participation/templates/participation/passage_detail.html:108
#: apps/participation/templates/participation/pool_detail.html:55 #: apps/participation/templates/participation/pool_detail.html:55
#: apps/participation/templates/participation/pool_detail.html:73 #: apps/participation/templates/participation/pool_detail.html:74
#: apps/participation/templates/participation/pool_detail.html:78 #: apps/participation/templates/participation/pool_detail.html:79
#: apps/participation/templates/participation/team_detail.html:113 #: apps/participation/templates/participation/team_detail.html:113
#: apps/participation/templates/participation/team_detail.html:177 #: apps/participation/templates/participation/team_detail.html:177
#: apps/participation/templates/participation/tournament_form.html:12 #: apps/participation/templates/participation/tournament_form.html:12
@ -623,9 +638,11 @@ msgid "Upload solution"
msgstr "Envoyer une solution" msgstr "Envoyer une solution"
#: apps/participation/templates/participation/participation_detail.html:59 #: apps/participation/templates/participation/participation_detail.html:59
#: apps/participation/templates/participation/passage_detail.html:117 #: apps/participation/templates/participation/passage_detail.html:114
#: apps/participation/templates/participation/pool_detail.html:84
#: apps/participation/templates/participation/team_detail.html:172 #: apps/participation/templates/participation/team_detail.html:172
#: apps/participation/templates/participation/upload_motivation_letter.html:13 #: apps/participation/templates/participation/upload_motivation_letter.html:13
#: apps/participation/templates/participation/upload_notes.html:12
#: apps/participation/templates/participation/upload_solution.html:11 #: apps/participation/templates/participation/upload_solution.html:11
#: apps/participation/templates/participation/upload_synthesis.html:16 #: apps/participation/templates/participation/upload_synthesis.html:16
#: apps/registration/templates/registration/upload_health_sheet.html:17 #: apps/registration/templates/registration/upload_health_sheet.html:17
@ -659,72 +676,68 @@ msgid "Defended solution:"
msgstr "Solution défendue" msgstr "Solution défendue"
#: apps/participation/templates/participation/passage_detail.html:28 #: apps/participation/templates/participation/passage_detail.html:28
msgid "Place:"
msgstr "Lieu :"
#: apps/participation/templates/participation/passage_detail.html:31
msgid "Defender penalties count:" msgid "Defender penalties count:"
msgstr "Nombre de pénalités :" msgstr "Nombre de pénalités :"
#: apps/participation/templates/participation/passage_detail.html:34 #: apps/participation/templates/participation/passage_detail.html:31
msgid "Syntheses:" msgid "Syntheses:"
msgstr "Notes de synthèse :" msgstr "Notes de synthèse :"
#: apps/participation/templates/participation/passage_detail.html:39 #: apps/participation/templates/participation/passage_detail.html:36
msgid "No synthesis was uploaded yet." msgid "No synthesis was uploaded yet."
msgstr "Aucune note de synthèse n'a encore été envoyée." msgstr "Aucune note de synthèse n'a encore été envoyée."
#: apps/participation/templates/participation/passage_detail.html:47 #: apps/participation/templates/participation/passage_detail.html:44
#: apps/participation/templates/participation/passage_detail.html:110 #: apps/participation/templates/participation/passage_detail.html:107
msgid "Update notes" msgid "Update notes"
msgstr "Modifier les notes" msgstr "Modifier les notes"
#: apps/participation/templates/participation/passage_detail.html:53 #: apps/participation/templates/participation/passage_detail.html:50
#: apps/participation/templates/participation/passage_detail.html:116 #: apps/participation/templates/participation/passage_detail.html:113
msgid "Upload synthesis" msgid "Upload synthesis"
msgstr "Envoyer une note de synthèse" msgstr "Envoyer une note de synthèse"
#: apps/participation/templates/participation/passage_detail.html:61 #: apps/participation/templates/participation/passage_detail.html:58
msgid "Notes detail" msgid "Notes detail"
msgstr "Détails des notes" msgstr "Détails des notes"
#: apps/participation/templates/participation/passage_detail.html:68 #: apps/participation/templates/participation/passage_detail.html:65
msgid "Average points for the defender writing:" msgid "Average points for the defender writing:"
msgstr "Moyenne de l'écrit du défenseur :" msgstr "Moyenne de l'écrit du défenseur :"
#: apps/participation/templates/participation/passage_detail.html:71 #: apps/participation/templates/participation/passage_detail.html:68
msgid "Average points for the defender oral:" msgid "Average points for the defender oral:"
msgstr "Moyenne de l'oral du défenseur :" msgstr "Moyenne de l'oral du défenseur :"
#: apps/participation/templates/participation/passage_detail.html:74 #: apps/participation/templates/participation/passage_detail.html:71
msgid "Average points for the opponent writing:" msgid "Average points for the opponent writing:"
msgstr "Moyenne de l'écrit de l'opposant :" msgstr "Moyenne de l'écrit de l'opposant :"
#: apps/participation/templates/participation/passage_detail.html:77 #: apps/participation/templates/participation/passage_detail.html:74
msgid "Average points for the opponent oral:" msgid "Average points for the opponent oral:"
msgstr "Moyenne de l'oral de l'opposant :" msgstr "Moyenne de l'oral de l'opposant :"
#: apps/participation/templates/participation/passage_detail.html:80 #: apps/participation/templates/participation/passage_detail.html:77
msgid "Average points for the reporter writing:" msgid "Average points for the reporter writing:"
msgstr "Moyenne de l'écrit du rapporteur :" msgstr "Moyenne de l'écrit du rapporteur :"
#: apps/participation/templates/participation/passage_detail.html:83 #: apps/participation/templates/participation/passage_detail.html:80
msgid "Average points for the reporter oral:" msgid "Average points for the reporter oral:"
msgstr "Moyenne de l'oral du rapporteur :" msgstr "Moyenne de l'oral du rapporteur :"
#: apps/participation/templates/participation/passage_detail.html:90 #: apps/participation/templates/participation/passage_detail.html:87
msgid "Defender points:" msgid "Defender points:"
msgstr "Points du défenseur :" msgstr "Points du défenseur :"
#: apps/participation/templates/participation/passage_detail.html:93 #: apps/participation/templates/participation/passage_detail.html:90
msgid "Opponent points:" msgid "Opponent points:"
msgstr "Points de l'opposant :" msgstr "Points de l'opposant :"
#: apps/participation/templates/participation/passage_detail.html:96 #: apps/participation/templates/participation/passage_detail.html:93
msgid "Reporter points:" msgid "Reporter points:"
msgstr "Points du rapporteur :" msgstr "Points du rapporteur :"
#: apps/participation/templates/participation/passage_detail.html:104 #: apps/participation/templates/participation/passage_detail.html:101
#: apps/participation/templates/participation/passage_form.html:11 #: apps/participation/templates/participation/passage_form.html:11
msgid "Update passage" msgid "Update passage"
msgstr "Modifier le passage" msgstr "Modifier le passage"
@ -755,29 +768,37 @@ msgid "Ranking"
msgstr "Classement" msgstr "Classement"
#: apps/participation/templates/participation/pool_detail.html:54 #: apps/participation/templates/participation/pool_detail.html:54
#: apps/participation/templates/participation/pool_detail.html:67 #: apps/participation/templates/participation/pool_detail.html:68
msgid "Add passage" msgid "Add passage"
msgstr "Ajouter un passage" msgstr "Ajouter un passage"
#: apps/participation/templates/participation/pool_detail.html:56 #: apps/participation/templates/participation/pool_detail.html:56
#: apps/participation/templates/participation/pool_detail.html:77 #: apps/participation/templates/participation/pool_detail.html:78
msgid "Update teams" msgid "Update teams"
msgstr "Modifier les équipes" msgstr "Modifier les équipes"
#: apps/participation/templates/participation/pool_detail.html:63 #: apps/participation/templates/participation/pool_detail.html:57
msgid "Upload notes from a CSV file"
msgstr "Soumettre les notes à partir d'un fichier CSV"
#: apps/participation/templates/participation/pool_detail.html:64
msgid "Passages" msgid "Passages"
msgstr "Passages" msgstr "Passages"
#: apps/participation/templates/participation/pool_detail.html:68 #: apps/participation/templates/participation/pool_detail.html:69
#: apps/participation/templates/participation/tournament_detail.html:109 #: apps/participation/templates/participation/tournament_detail.html:109
msgid "Add" msgid "Add"
msgstr "Ajouter" msgstr "Ajouter"
#: apps/participation/templates/participation/pool_detail.html:72 #: apps/participation/templates/participation/pool_detail.html:73
#: apps/participation/templates/participation/pool_form.html:11 #: apps/participation/templates/participation/pool_form.html:11
msgid "Update pool" msgid "Update pool"
msgstr "Modifier la poule" msgstr "Modifier la poule"
#: apps/participation/templates/participation/pool_detail.html:83
msgid "Upload notes"
msgstr "Envoyer les notes"
#: apps/participation/templates/participation/team_detail.html:13 #: apps/participation/templates/participation/team_detail.html:13
msgid "Name:" msgid "Name:"
msgstr "Nom :" msgstr "Nom :"
@ -901,7 +922,7 @@ msgid "Invalidate"
msgstr "Invalider" msgstr "Invalider"
#: apps/participation/templates/participation/team_detail.html:171 #: apps/participation/templates/participation/team_detail.html:171
#: apps/participation/views.py:327 #: apps/participation/views.py:329
msgid "Upload motivation letter" msgid "Upload motivation letter"
msgstr "Envoyer la lettre de motivation" msgstr "Envoyer la lettre de motivation"
@ -910,7 +931,7 @@ msgid "Update team"
msgstr "Modifier l'équipe" msgstr "Modifier l'équipe"
#: apps/participation/templates/participation/team_detail.html:181 #: apps/participation/templates/participation/team_detail.html:181
#: apps/participation/views.py:430 #: apps/participation/views.py:432
msgid "Leave team" msgid "Leave team"
msgstr "Quitter l'équipe" msgstr "Quitter l'équipe"
@ -1022,49 +1043,49 @@ msgstr "Retour aux détails de l'utilisateur"
msgid "Templates:" msgid "Templates:"
msgstr "Modèles :" msgstr "Modèles :"
#: apps/participation/views.py:43 tfjm/templates/base.html:71 #: apps/participation/views.py:45 tfjm/templates/base.html:71
#: tfjm/templates/base.html:230 #: tfjm/templates/base.html:230
msgid "Create team" msgid "Create team"
msgstr "Créer une équipe" msgstr "Créer une équipe"
#: apps/participation/views.py:52 apps/participation/views.py:97 #: apps/participation/views.py:54 apps/participation/views.py:99
msgid "You don't participate, so you can't create a team." msgid "You don't participate, so you can't create a team."
msgstr "Vous ne participez pas, vous ne pouvez pas créer d'équipe." msgstr "Vous ne participez pas, vous ne pouvez pas créer d'équipe."
#: apps/participation/views.py:54 apps/participation/views.py:99 #: apps/participation/views.py:56 apps/participation/views.py:101
msgid "You are already in a team." msgid "You are already in a team."
msgstr "Vous êtes déjà dans une équipe." msgstr "Vous êtes déjà dans une équipe."
#: apps/participation/views.py:88 tfjm/templates/base.html:76 #: apps/participation/views.py:90 tfjm/templates/base.html:76
#: tfjm/templates/base.html:225 #: tfjm/templates/base.html:225
msgid "Join team" msgid "Join team"
msgstr "Rejoindre une équipe" msgstr "Rejoindre une équipe"
#: apps/participation/views.py:150 apps/participation/views.py:436 #: apps/participation/views.py:152 apps/participation/views.py:438
#: apps/participation/views.py:470 #: apps/participation/views.py:472
msgid "You are not in a team." msgid "You are not in a team."
msgstr "Vous n'êtes pas dans une équipe." msgstr "Vous n'êtes pas dans une équipe."
#: apps/participation/views.py:151 apps/participation/views.py:471 #: apps/participation/views.py:153 apps/participation/views.py:473
msgid "You don't participate, so you don't have any team." msgid "You don't participate, so you don't have any team."
msgstr "Vous ne participez pas, vous n'avez donc pas d'équipe." msgstr "Vous ne participez pas, vous n'avez donc pas d'équipe."
#: apps/participation/views.py:177 #: apps/participation/views.py:179
#, python-brace-format #, python-brace-format
msgid "Detail of team {trigram}" msgid "Detail of team {trigram}"
msgstr "Détails de l'équipe {trigram}" msgstr "Détails de l'équipe {trigram}"
#: apps/participation/views.py:213 #: apps/participation/views.py:215
msgid "You don't participate, so you can't request the validation of the team." msgid "You don't participate, so you can't request the validation of the team."
msgstr "" msgstr ""
"Vous ne participez pas, vous ne pouvez pas demander la validation de " "Vous ne participez pas, vous ne pouvez pas demander la validation de "
"l'équipe." "l'équipe."
#: apps/participation/views.py:216 #: apps/participation/views.py:218
msgid "The validation of the team is already done or pending." msgid "The validation of the team is already done or pending."
msgstr "La validation de l'équipe est déjà faite ou en cours." msgstr "La validation de l'équipe est déjà faite ou en cours."
#: apps/participation/views.py:219 #: apps/participation/views.py:221
msgid "" msgid ""
"The team can't be validated: missing email address confirmations, " "The team can't be validated: missing email address confirmations, "
"authorizations, people, motivation letter or the tournament is not set." "authorizations, people, motivation letter or the tournament is not set."
@ -1073,66 +1094,74 @@ msgstr ""
"d'adresse e-mail, soit une autorisation, soit des personnes, soit la lettre " "d'adresse e-mail, soit une autorisation, soit des personnes, soit la lettre "
"de motivation, soit le tournoi n'a pas été choisi." "de motivation, soit le tournoi n'a pas été choisi."
#: apps/participation/views.py:241 #: apps/participation/views.py:243
msgid "You are not an organizer of the tournament." msgid "You are not an organizer of the tournament."
msgstr "Vous n'êtes pas un organisateur du tournoi." msgstr "Vous n'êtes pas un organisateur du tournoi."
#: apps/participation/views.py:244 #: apps/participation/views.py:246
msgid "This team has no pending validation." msgid "This team has no pending validation."
msgstr "L'équipe n'a pas de validation en attente." msgstr "L'équipe n'a pas de validation en attente."
#: apps/participation/views.py:274 #: apps/participation/views.py:276
msgid "You must specify if you validate the registration or not." msgid "You must specify if you validate the registration or not."
msgstr "Vous devez spécifier si vous validez l'inscription ou non." msgstr "Vous devez spécifier si vous validez l'inscription ou non."
#: apps/participation/views.py:307 #: apps/participation/views.py:309
#, python-brace-format #, python-brace-format
msgid "Update team {trigram}" msgid "Update team {trigram}"
msgstr "Mise à jour de l'équipe {trigram}" msgstr "Mise à jour de l'équipe {trigram}"
#: apps/participation/views.py:366 apps/participation/views.py:416 #: apps/participation/views.py:368 apps/participation/views.py:418
#, python-brace-format #, python-brace-format
msgid "Motivation letter of {team}.{ext}" msgid "Motivation letter of {team}.{ext}"
msgstr "Lettre de motivation de {team}.{ext}" msgstr "Lettre de motivation de {team}.{ext}"
#: apps/participation/views.py:397 #: apps/participation/views.py:399
#, python-brace-format #, python-brace-format
msgid "Photo authorization of {participant}.{ext}" msgid "Photo authorization of {participant}.{ext}"
msgstr "Autorisation de droit à l'image de {participant}.{ext}" msgstr "Autorisation de droit à l'image de {participant}.{ext}"
#: apps/participation/views.py:403 #: apps/participation/views.py:405
#, python-brace-format #, python-brace-format
msgid "Parental authorization of {participant}.{ext}" msgid "Parental authorization of {participant}.{ext}"
msgstr "Autorisation parentale de {participant}.{ext}" msgstr "Autorisation parentale de {participant}.{ext}"
#: apps/participation/views.py:410 #: apps/participation/views.py:412
#, python-brace-format #, python-brace-format
msgid "Health sheet of {participant}.{ext}" msgid "Health sheet of {participant}.{ext}"
msgstr "Fiche sanitaire de {participant}.{ext}" msgstr "Fiche sanitaire de {participant}.{ext}"
#: apps/participation/views.py:420 #: apps/participation/views.py:422
#, python-brace-format #, python-brace-format
msgid "Photo authorizations of team {trigram}.zip" msgid "Photo authorizations of team {trigram}.zip"
msgstr "Autorisations de droit à l'image de l'équipe {trigram}.zip" msgstr "Autorisations de droit à l'image de l'équipe {trigram}.zip"
#: apps/participation/views.py:438 #: apps/participation/views.py:440
msgid "The team is already validated or the validation is pending." msgid "The team is already validated or the validation is pending."
msgstr "La validation de l'équipe est déjà faite ou en cours." msgstr "La validation de l'équipe est déjà faite ou en cours."
#: apps/participation/views.py:485 #: apps/participation/views.py:487
msgid "The team is not validated yet." msgid "The team is not validated yet."
msgstr "L'équipe n'est pas encore validée." msgstr "L'équipe n'est pas encore validée."
#: apps/participation/views.py:499 #: apps/participation/views.py:501
#, python-brace-format #, python-brace-format
msgid "Participation of team {trigram}" msgid "Participation of team {trigram}"
msgstr "Participation de l'équipe {trigram}" msgstr "Participation de l'équipe {trigram}"
#: apps/participation/views.py:625 #: apps/participation/views.py:627
msgid "You can't upload a solution after the deadline." msgid "You can't upload a solution after the deadline."
msgstr "Vous ne pouvez pas envoyer de solution après la date limite." msgstr "Vous ne pouvez pas envoyer de solution après la date limite."
#: apps/participation/views.py:811 #: apps/participation/views.py:724
msgid "The following user is not registered as a jury:"
msgstr "L'utilisateur suivant n'est pas inscrit en tant que juré⋅e :"
#: apps/participation/views.py:732
msgid "Notes were successfully uploaded."
msgstr "Les notes ont bien été envoyées."
#: apps/participation/views.py:844
msgid "You can't upload a synthesis after the deadline." msgid "You can't upload a synthesis 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."
@ -1535,16 +1564,16 @@ msgstr ""
#: apps/registration/templates/registration/payment_form.html:17 #: apps/registration/templates/registration/payment_form.html:17
msgid "" msgid ""
"You can pay with a credit card through <a class=\"alert-link\" href=" "You can pay with a credit card through <a class=\"alert-link\" "
"\"https://www.helloasso.com/associations/animath/evenements/tfjm-2022-" "href=\"https://www.helloasso.com/associations/animath/evenements/tfjm-2022-"
"tournois-regionaux\">our Hello Asso page</a>. To make the validation of the " "tournois-regionaux\">our Hello Asso page</a>. To make the validation of the "
"payment easier, <span class=\"text-danger\">please use the same e-mail " "payment easier, <span class=\"text-danger\">please use the same e-mail "
"address that you use on this platform.</span> The payment verification will " "address that you use on this platform.</span> The payment verification will "
"be checked automatically under 10 minutes, you don't necessary need to fill " "be checked automatically under 10 minutes, you don't necessary need to fill "
"this form." "this form."
msgstr "" msgstr ""
"Vous pouvez payer par carte bancaire sur <a class=\"alert-link\" href=" "Vous pouvez payer par carte bancaire sur <a class=\"alert-link\" "
"\"https://www.helloasso.com/associations/animath/evenements/tfjm-2022-" "href=\"https://www.helloasso.com/associations/animath/evenements/tfjm-2022-"
"tournois-regionaux\">notre page Hello Asso</a>. Pour rendre la validation du " "tournois-regionaux\">notre page Hello Asso</a>. Pour rendre la validation du "
"paiement plus facile, <span class=\"text-danger\">merci d'utiliser la même " "paiement plus facile, <span class=\"text-danger\">merci d'utiliser la même "
"adresse e-mail que vous utilisez sur cette plateforme.</span> La " "adresse e-mail que vous utilisez sur cette plateforme.</span> La "
@ -1563,14 +1592,14 @@ msgstr ""
#: apps/registration/templates/registration/payment_form.html:39 #: apps/registration/templates/registration/payment_form.html:39
msgid "" msgid ""
"If any payment mean is available to you, please contact us at <a class=" "If any payment mean is available to you, please contact us at <a "
"\"alert-link\" href=\"mailto:contact@tfjm.org\">contact@tfjm.org</a> to find " "class=\"alert-link\" href=\"mailto:contact@tfjm.org\">contact@tfjm.org</a> "
"a solution to your difficulties." "to find a solution to your difficulties."
msgstr "" msgstr ""
"Si aucun moyen de paiement ne vous convient, merci de nous contecter à " "Si aucun moyen de paiement ne vous convient, merci de nous contecter à "
"l'adresse <a class=\"alert-link\" href=\"mailto:contact@tfjm.org" "l'adresse <a class=\"alert-link\" href=\"mailto:contact@tfjm."
"\">contact@tfjm.org</a> pour que nous puissions trouver une solution à vos " "org\">contact@tfjm.org</a> pour que nous puissions trouver une solution à "
"difficultés." "vos difficultés."
#: apps/registration/templates/registration/signup.html:5 #: apps/registration/templates/registration/signup.html:5
#: apps/registration/templates/registration/signup.html:12 #: apps/registration/templates/registration/signup.html:12
@ -1902,12 +1931,12 @@ msgstr "Déconnexion"
#, python-format #, python-format
msgid "" msgid ""
"Your email address is not validated. Please click on the link you received " "Your email address is not validated. Please click on the link you received "
"by email. You can resend a mail by clicking on <a href=\"%(send_email_url)s" "by email. You can resend a mail by clicking on <a "
"\">this link</a>." "href=\"%(send_email_url)s\">this link</a>."
msgstr "" msgstr ""
"Votre adresse mail n'est pas validée. Merci de cliquer sur le lien que vous " "Votre adresse mail n'est pas validée. Merci de cliquer sur le lien que vous "
"avez reçu par mail. Vous pouvez renvoyer un mail en cliquant sur <a href=" "avez reçu par mail. Vous pouvez renvoyer un mail en cliquant sur <a "
"\"%(send_email_url)s\">ce lien</a>." "href=\"%(send_email_url)s\">ce lien</a>."
#: tfjm/templates/base.html:180 #: tfjm/templates/base.html:180
msgid "Contact us" msgid "Contact us"
@ -1953,3 +1982,9 @@ msgstr "Résultats"
#: tfjm/templates/search/search.html:25 #: tfjm/templates/search/search.html:25
msgid "No results found." msgid "No results found."
msgstr "Aucun résultat." msgstr "Aucun résultat."
#~ msgid "Where the solution is presented?"
#~ msgstr "Où est-ce que les solutions sont défendues ?"
#~ msgid "Place:"
#~ msgstr "Lieu :"