Merge branch 'thubrecht/faq' into 'master'

Création de l'application de faq

See merge request klub-dev-ens/kadenios!6
This commit is contained in:
Tom Hubrecht 2021-06-18 19:25:50 +00:00
commit 191144c234
17 changed files with 560 additions and 113 deletions

0
faqs/__init__.py Normal file
View file

28
faqs/forms.py Normal file
View file

@ -0,0 +1,28 @@
from translated_fields import language_code_formfield_callback
from django import forms
from .models import Faq
class FaqForm(forms.ModelForm):
formfield_callback = language_code_formfield_callback
class Meta:
model = Faq
fields = [
*Faq.title.fields,
"anchor",
*Faq.description.fields,
*Faq.content.fields,
]
widgets = {
"description_en": forms.Textarea(
attrs={"rows": 4, "class": "is-family-monospace"}
),
"description_fr": forms.Textarea(
attrs={"rows": 4, "class": "is-family-monospace"}
),
"content_en": forms.Textarea(attrs={"class": "is-family-monospace"}),
"content_fr": forms.Textarea(attrs={"class": "is-family-monospace"}),
}

View file

@ -0,0 +1,66 @@
# Generated by Django 3.2.4 on 2021-06-15 08:34
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="Faq",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("title_fr", models.CharField(max_length=255, verbose_name="titre")),
(
"title_en",
models.CharField(blank=True, max_length=255, verbose_name="titre"),
),
("description_fr", models.TextField(verbose_name="description")),
(
"description_en",
models.TextField(blank=True, verbose_name="description"),
),
("content_fr", models.TextField(blank=True, verbose_name="contenu")),
("content_en", models.TextField(blank=True, verbose_name="contenu")),
(
"last_modified",
models.DateField(auto_now=True, verbose_name="mise à jour"),
),
("anchor", models.CharField(max_length=20, verbose_name="ancre")),
(
"author",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="faqs",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"permissions": [("is_author", "Can create faqs")],
},
),
migrations.AddConstraint(
model_name="faq",
constraint=models.UniqueConstraint(
fields=("anchor",), name="unique_faq_anchor"
),
),
]

View file

14
faqs/mixins.py Normal file
View file

@ -0,0 +1,14 @@
from django.contrib.auth.mixins import PermissionRequiredMixin
class AdminOnlyMixin(PermissionRequiredMixin):
"""Restreint l'accès aux admins"""
permission_required = "faqs.is_author"
class CreatorOnlyMixin(AdminOnlyMixin):
"""Restreint l'accès à l'auteur"""
def get_queryset(self):
return super().get_queryset().filter(author=self.request.user)

32
faqs/models.py Normal file
View file

@ -0,0 +1,32 @@
from translated_fields import TranslatedFieldWithFallback
from django.contrib.auth import get_user_model
from django.db import models
from django.utils.translation import gettext_lazy as _
User = get_user_model()
class Faq(models.Model):
title = TranslatedFieldWithFallback(
models.CharField(_("titre"), blank=False, max_length=255)
)
description = TranslatedFieldWithFallback(
models.TextField(_("description"), blank=False)
)
content = TranslatedFieldWithFallback(models.TextField(_("contenu"), blank=True))
author = models.ForeignKey(
User, related_name="faqs", null=True, on_delete=models.SET_NULL
)
last_modified = models.DateField(_("mise à jour"), auto_now=True)
anchor = models.CharField(_("ancre"), max_length=20)
class Meta:
permissions = [
("is_author", "Can create faqs"),
]
constraints = [
models.UniqueConstraint(fields=["anchor"], name="unique_faq_anchor")
]

View file

@ -0,0 +1,43 @@
{% extends "base.html" %}
{% load i18n markdown %}
{% block content %}
<div class="level">
{# Titre de la FAQ #}
<div class="level-left is-flex-shrink-1">
<h1 class="title">{{ faq.title }}</h1>
</div>
<div class="level-right">
{# Date de dernière modification #}
<div class="level-item">
<span class="tag is-primary is-light is-outlined">{% blocktrans with maj=faq.last_modified|date:'d/m/Y' %}Mis à jour le {{ maj }}{% endblocktrans %}</span>
</div>
{# Lien vers la page d'édition #}
{% if faq.author == user %}
<div class="level-item">
<a class="button has-tooltip-primary" href="{% url 'faq.edit' faq.anchor %}" data-tooltip="{% trans "Modifier" %}">
<span class="icon">
<i class="fas fa-cog"></i>
</span>
</a>
</div>
{% endif %}
</div>
</div>
<hr>
{# Description #}
<div class="message is-primary">
<div class="message-body content">{{ faq.description|markdown|safe }}</div>
</div>
{# Contenu #}
<div class="content">
{{ faq.content|markdown|safe }}
</div>
{% endblock %}

View file

@ -0,0 +1,20 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
{% for error in form.non_field_errors %}
<div class="notification is-danger">
{{ error }}
</div>
{% endfor %}
<h1 class="title">{% trans "Nouvelle FAQ" %}</h1>
<hr>
{% url 'faq.list' as r_url %}
{% include "forms/common-form.html" with c_size="is-9" errors=False %}
{% endblock %}

View file

@ -0,0 +1,20 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
{% for error in form.non_field_errors %}
<div class="notification is-danger">
{{ error }}
</div>
{% endfor %}
<h1 class="title">{% trans "Modification de la FAQ" %}</h1>
<hr>
{% url 'faq.view' faq.anchor as r_url %}
{% include "forms/common-form.html" with c_size="is-9" errors=False %}
{% endblock %}

View file

@ -0,0 +1,48 @@
{% extends "base.html" %}
{% load i18n markdown %}
{% block content %}
<div class="level">
<div class="level-left">
<div class="level-item">
<h1 class="title">{% trans "Liste des FAQ" %}</h1>
</div>
</div>
{% if perms.faqs.is_author %}
<div class="level-right">
<div class="level-item">
<a class="button is-light is-outlined is-primary" href={% url 'faq.create' %}>
<span class="icon">
<i class="fas fa-plus"></i>
</span>
<span>{% trans "Créer une FAQ" %}</span>
</a>
</div>
</div>
{% endif %}
</div>
<hr>
{% for f in faq_list %}
<div class="panel is-primary is-radiusless">
<div class="panel-heading is-size-6 is-radiusless">
<a class="has-text-primary-light" href="{% url 'faq.view' f.anchor %}"><u>{{ f.title }}</u></a>
</div>
{% if f.description %}
<div class="panel-block">
<div class="content is-flex-grow-1">
{{ f.description|markdown|safe }}
</div>
</div>
{% endif %}
</div>
{% if not forloop.last %}
<br>
{% endif %}
{% endfor %}
{% endblock %}

12
faqs/urls.py Normal file
View file

@ -0,0 +1,12 @@
from django.urls import path
from . import views
urlpatterns = [
# Admin views
path("create", views.FaqCreateView.as_view(), name="faq.create"),
path("edit/<slug:slug>", views.FaqEditView.as_view(), name="faq.edit"),
# Public views
path("", views.FaqListView.as_view(), name="faq.list"),
path("view/<slug:slug>", views.FaqView.as_view(), name="faq.view"),
]

54
faqs/views.py Normal file
View file

@ -0,0 +1,54 @@
from django.contrib.messages.views import SuccessMessageMixin
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.views.generic import CreateView, DetailView, ListView, UpdateView
from .forms import FaqForm
from .mixins import AdminOnlyMixin, CreatorOnlyMixin
from .models import Faq
# #############################################################################
# Administration Views
# #############################################################################
class FaqCreateView(AdminOnlyMixin, SuccessMessageMixin, CreateView):
model = Faq
form_class = FaqForm
success_message = _("Faq créée avec succès !")
template_name = "faqs/faq_create.html"
def get_success_url(self):
return reverse("faq.view", args=[self.object.anchor])
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class FaqEditView(CreatorOnlyMixin, SuccessMessageMixin, UpdateView):
model = Faq
form_class = FaqForm
slug_field = "anchor"
success_message = _("Faq modifiée avec succès !")
template_name = "faqs/faq_edit.html"
def get_success_url(self):
return reverse("faq.view", args=[self.object.anchor])
# #############################################################################
# Public Views
# #############################################################################
class FaqListView(ListView):
model = Faq
template_name = "faqs/faq_list.html"
class FaqView(DetailView):
model = Faq
template_name = "faqs/faq.html"
slug_field = "anchor"

View file

@ -55,6 +55,7 @@ INSTALLED_APPS = [
"kadenios.apps.IgnoreSrcStaticFilesConfig", "kadenios.apps.IgnoreSrcStaticFilesConfig",
"shared", "shared",
"elections", "elections",
"faqs",
"authens", "authens",
] ]

View file

@ -8,6 +8,7 @@ urlpatterns = [
path("", HomeView.as_view(), name="kadenios"), path("", HomeView.as_view(), name="kadenios"),
path("admin/", admin.site.urls), path("admin/", admin.site.urls),
path("elections/", include("elections.urls")), path("elections/", include("elections.urls")),
path("faqs/", include("faqs.urls")),
path("auth/", include("shared.auth.urls")), path("auth/", include("shared.auth.urls")),
path("authens/", include("authens.urls")), path("authens/", include("authens.urls")),
path("i18n/", include("django.conf.urls.i18n")), path("i18n/", include("django.conf.urls.i18n")),

View file

@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 0.1\n" "Project-Id-Version: 0.1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-05-28 10:58+0200\n" "POT-Creation-Date: 2021-06-18 19:34+0200\n"
"PO-Revision-Date: 2021-05-28 10:59+0200\n" "PO-Revision-Date: 2021-06-18 21:19+0200\n"
"Last-Translator: Test Translator <test@translator>\n" "Last-Translator: Test Translator <test@translator>\n"
"Language-Team: \n" "Language-Team: \n"
"Language: en\n" "Language: en\n"
@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.4.3\n" "X-Generator: Poedit 3.0\n"
#: elections/forms.py:19 #: elections/forms.py:19
msgid "Impossible de faire débuter l'élection dans le passé" msgid "Impossible de faire débuter l'élection dans le passé"
@ -31,20 +31,22 @@ msgid ""
"Le mail d'annonce a déjà été envoyé, il n'est pas possible d'ouvrir " "Le mail d'annonce a déjà été envoyé, il n'est pas possible d'ouvrir "
"l'élection à tout le monde" "l'élection à tout le monde"
msgstr "" msgstr ""
"The announcement email has already been sent, it is not possible to open the "
"election to everyone"
#: elections/forms.py:55 #: elections/forms.py:63
msgid "Sélectionnez un fichier .csv" msgid "Sélectionnez un fichier .csv"
msgstr "Select a .csv file" msgstr "Select a .csv file"
#: elections/forms.py:65 #: elections/forms.py:73
msgid "Extension de fichier invalide, il faut un fichier au format CSV." msgid "Extension de fichier invalide, il faut un fichier au format CSV."
msgstr "Invalid file extension, a CSV file is required." msgstr "Invalid file extension, a CSV file is required."
#: elections/forms.py:72 #: elections/forms.py:80
msgid "Objet" msgid "Objet"
msgstr "Subject" msgstr "Subject"
#: elections/forms.py:94 #: elections/forms.py:102
msgid "" msgid ""
"L'abréviation est optionnelle et sert à identifier plus facilement les " "L'abréviation est optionnelle et sert à identifier plus facilement les "
"différentes options. Elle est affiché sans espaces et en majuscules." "différentes options. Elle est affiché sans espaces et en majuscules."
@ -52,116 +54,120 @@ msgstr ""
"The abbreviation is optional and serves to identify the different options " "The abbreviation is optional and serves to identify the different options "
"more easily. It is displayed without spaces and in capital letters." "more easily. It is displayed without spaces and in capital letters."
#: elections/forms.py:105 #: elections/forms.py:113
msgid "Supprimer le vote de {} ({}) ?" msgid "Supprimer le vote de {} ({}) ?"
msgstr "Delete the vote of {} ({}) ?" msgstr "Delete the vote of {} ({}) ?"
#: elections/forms.py:110 elections/templates/elections/election_admin.html:191 #: elections/forms.py:118 elections/templates/elections/election_admin.html:243
#: elections/templates/elections/election_admin.html:218 #: elections/templates/elections/election_admin.html:270
#: elections/templates/elections/election_voters.html:82 #: elections/templates/elections/election_voters.html:82
msgid "Supprimer" msgid "Supprimer"
msgstr "Delete" msgstr "Delete"
#: elections/forms.py:110 #: elections/forms.py:118
msgid "Non" msgid "Non"
msgstr "No" msgstr "No"
#: elections/forms.py:110 #: elections/forms.py:118
msgid "Oui" msgid "Oui"
msgstr "Yes" msgstr "Yes"
#: elections/models.py:31 #: elections/models.py:33
msgid "nom" msgid "nom"
msgstr "name" msgstr "name"
#: elections/models.py:32 #: elections/models.py:34
msgid "nom bref" msgid "nom bref"
msgstr "short name" msgstr "short name"
#: elections/models.py:34 #: elections/models.py:36 faqs/models.py:15
msgid "description" msgid "description"
msgstr "description" msgstr "description"
#: elections/models.py:37 #: elections/models.py:39
msgid "date et heure de début" msgid "date et heure de début"
msgstr "start date and time" msgstr "start date and time"
#: elections/models.py:38 #: elections/models.py:40
msgid "date et heure de fin" msgid "date et heure de fin"
msgstr "end date and time" msgstr "end date and time"
#: elections/models.py:41 #: elections/models.py:42
msgid "visible au public"
msgstr "visible to everyone"
#: elections/models.py:45
msgid "conditions de vote" msgid "conditions de vote"
msgstr "voting requirements" msgstr "voting requirements"
#: elections/models.py:45 #: elections/models.py:49
msgid "restreint le vote à une liste de personnes" msgid "restreint le vote à une liste de personnes"
msgstr "restricts the vote to a list of people" msgstr "restricts the vote to a list of people"
#: elections/models.py:49 #: elections/models.py:53
msgid "mail avec les identifiants envoyé" msgid "mail avec les identifiants envoyé"
msgstr "mail with credentials sent" msgstr "mail with credentials sent"
#: elections/models.py:66 #: elections/models.py:70
msgid "résultats publics" msgid "résultats publics"
msgstr "results published" msgstr "results published"
#: elections/models.py:67 #: elections/models.py:71
msgid "dépouillée" msgid "dépouillée"
msgstr "counted" msgstr "counted"
#: elections/models.py:69 #: elections/models.py:73
msgid "archivée" msgid "archivée"
msgstr "archived" msgstr "archived"
#: elections/models.py:79 #: elections/models.py:77
msgid "Peut administrer des élections"
msgstr "Can manage elections"
#: elections/models.py:87
msgid "question" msgid "question"
msgstr "question" msgstr "question"
#: elections/models.py:81 #: elections/models.py:90
msgid "type de question" msgid "type de question"
msgstr "type of question" msgstr "type of question"
#: elections/models.py:88 #: elections/models.py:97
msgid "nombre maximal de votes reçus" msgid "nombre maximal de votes reçus"
msgstr "maximal number of votes received" msgstr "maximal number of votes received"
#: elections/models.py:139 #: elections/models.py:154
msgid "texte" msgid "texte"
msgstr "text" msgstr "text"
#: elections/models.py:140 #: elections/models.py:155
msgid "abréviation" msgid "abréviation"
msgstr "abbreviation" msgstr "abbreviation"
#: elections/models.py:142 #: elections/models.py:157
msgid "option gagnante" msgid "option gagnante"
msgstr "winning option" msgstr "winning option"
#: elections/models.py:150 #: elections/models.py:165
msgid "nombre de votes reçus" msgid "nombre de votes reçus"
msgstr "number of votes received" msgstr "number of votes received"
#: elections/models.py:177 #: elections/models.py:192
msgid "rang de l'option" msgid "rang de l'option"
msgstr "option's ranking" msgstr "option's ranking"
#: elections/models.py:193 #: elections/models.py:208
msgid "votes supplémentaires" msgid "votes supplémentaires"
msgstr "extra votes" msgstr "extra votes"
#: elections/models.py:209 #: elections/models.py:224
msgid "Nom et Prénom" msgid "Nom et Prénom"
msgstr "Name and surname" msgstr "Name and surname"
#: elections/models.py:232 elections/tests/test_models.py:57 #: elections/models.py:247 elections/tests/test_models.py:57
msgid "identifiants spécifiques" msgid "identifiants spécifiques"
msgstr "dedicated credentials" msgstr "dedicated credentials"
#: elections/models.py:236
msgid "Peut administrer des élections"
msgstr "Can manage elections"
#: elections/staticdefs.py:26 elections/tests/test_models.py:56 #: elections/staticdefs.py:26 elections/tests/test_models.py:56
msgid "mot de passe" msgid "mot de passe"
msgstr "password" msgstr "password"
@ -235,7 +241,7 @@ msgid "Élection en cours"
msgstr "Election in progress" msgstr "Election in progress"
#: elections/templates/elections/election.html:52 #: elections/templates/elections/election.html:52
#: elections/templates/elections/election_list.html:72 #: elections/templates/elections/election_list.html:83
msgid "Administrer" msgid "Administrer"
msgstr "Manage" msgstr "Manage"
@ -280,70 +286,92 @@ msgstr "Login with credentials"
msgid "Connexion via CAS" msgid "Connexion via CAS"
msgstr "Login via CAS" msgstr "Login via CAS"
#: elections/templates/elections/election.html:189 #: elections/templates/elections/election.html:194
msgid "A voté" msgid "A voté"
msgstr "Voted" msgstr "Voted"
#: elections/templates/elections/election_admin.html:21 #: elections/templates/elections/election_admin.html:51
#: elections/templates/elections/election_admin.html:282 #: elections/templates/elections/election_list.html:58
#: elections/templates/elections/election_admin.html:291 msgid "Élection invisible"
msgid "Rajouter une question" msgstr "Invisible election"
msgstr "Add a question"
#: elections/templates/elections/election_admin.html:21 #: elections/templates/elections/election_admin.html:58
msgid "Modifier la question" msgid "Élection visible"
msgstr "Change the question" msgstr "Visible election"
#: elections/templates/elections/election_admin.html:26 #: elections/templates/elections/election_admin.html:72
#: elections/templates/elections/election_admin.html:267
#: elections/templates/elections/election_admin.html:278
msgid "Rajouter une option"
msgstr "Add an option"
#: elections/templates/elections/election_admin.html:26
msgid "Modifier l'option"
msgstr "Change the option"
#: elections/templates/elections/election_admin.html:53
msgid "Actions" msgid "Actions"
msgstr "Actions" msgstr "Actions"
#: elections/templates/elections/election_admin.html:65 #: elections/templates/elections/election_admin.html:84
msgid "Vue classique"
msgstr "Classic view"
#: elections/templates/elections/election_admin.html:95
msgid "Rendre l'élection visible"
msgstr "Make the election visible"
#: elections/templates/elections/election_admin.html:104
msgid "Exporter les votant·e·s" msgid "Exporter les votant·e·s"
msgstr "Export the list of voters" msgstr "Export the list of voters"
#: elections/templates/elections/election_admin.html:74 #: elections/templates/elections/election_admin.html:113
#: elections/templates/elections/election_admin.html:200 #: elections/templates/elections/election_admin.html:252
#: elections/templates/elections/election_admin.html:224 #: elections/templates/elections/election_admin.html:276
#: faqs/templates/faqs/faq.html:22
msgid "Modifier" msgid "Modifier"
msgstr "Edit" msgstr "Edit"
#: elections/templates/elections/election_admin.html:83 #: elections/templates/elections/election_admin.html:122
#: elections/templates/elections/upload_voters.html:27 #: elections/templates/elections/upload_voters.html:27
msgid "Gestion de la liste de votant·e·s" msgid "Gestion de la liste de votant·e·s"
msgstr "Management of the voters' list" msgstr "Management of the voters' list"
#: elections/templates/elections/election_admin.html:95 #: elections/templates/elections/election_admin.html:134
#: elections/templates/elections/election_voters.html:48 #: elections/templates/elections/election_voters.html:48
msgid "Liste des votant·e·s" msgid "Liste des votant·e·s"
msgstr "Voters' list" msgstr "Voters' list"
#: elections/templates/elections/election_admin.html:103 #: elections/templates/elections/election_admin.html:142
msgid "Dépouiller" msgid "Dépouiller"
msgstr "Count" msgstr "Count"
#: elections/templates/elections/election_admin.html:115 #: elections/templates/elections/election_admin.html:154
msgid "Publier" msgid "Publier"
msgstr "Publish" msgstr "Publish"
#: elections/templates/elections/election_admin.html:117 #: elections/templates/elections/election_admin.html:156
msgid "Dépublier" msgid "Dépublier"
msgstr "De-publish" msgstr "De-publish"
#: elections/templates/elections/election_admin.html:128 #: elections/templates/elections/election_admin.html:166
msgid "Télécharger les résultats"
msgstr "Download the results"
#: elections/templates/elections/election_admin.html:175
msgid "Archiver" msgid "Archiver"
msgstr "Archive" msgstr "Archive"
#: elections/templates/elections/election_admin.html:247
msgid "Modifier la question"
msgstr "Change the question"
#: elections/templates/elections/election_admin.html:276
msgid "Modifier l'option"
msgstr "Change the option"
#: elections/templates/elections/election_admin.html:315
#: elections/templates/elections/election_admin.html:319
#: elections/templates/elections/election_admin.html:330
msgid "Rajouter une option"
msgstr "Add an option"
#: elections/templates/elections/election_admin.html:334
#: elections/templates/elections/election_admin.html:339
#: elections/templates/elections/election_admin.html:343
msgid "Rajouter une question"
msgstr "Add a question"
#: elections/templates/elections/election_ballots.html:18 #: elections/templates/elections/election_ballots.html:18
#: elections/templates/elections/election_voters.html:40 #: elections/templates/elections/election_voters.html:40
#: elections/templates/elections/upload_voters.html:48 #: elections/templates/elections/upload_voters.html:48
@ -359,7 +387,7 @@ msgstr "Back"
msgid "Liste des bulletins" msgid "Liste des bulletins"
msgstr "List of ballots" msgstr "List of ballots"
#: elections/templates/elections/election_create.html:31 #: elections/templates/elections/election_create.html:32
msgid "Création d'une élection" msgid "Création d'une élection"
msgstr "Creating an election" msgstr "Creating an election"
@ -371,19 +399,19 @@ msgstr "List of elections"
msgid "Créer une élection" msgid "Créer une élection"
msgstr "Create an election" msgstr "Create an election"
#: elections/templates/elections/election_list.html:54 #: elections/templates/elections/election_list.html:65
msgid "Élection dépouillée" msgid "Élection dépouillée"
msgstr "Election counted" msgstr "Election counted"
#: elections/templates/elections/election_list.html:60 #: elections/templates/elections/election_list.html:71
msgid "Élection publiée" msgid "Élection publiée"
msgstr "Published election" msgstr "Published election"
#: elections/templates/elections/election_list.html:66 #: elections/templates/elections/election_list.html:77
msgid "Élection archivée" msgid "Élection archivée"
msgstr "Archived election" msgstr "Archived election"
#: elections/templates/elections/election_update.html:31 #: elections/templates/elections/election_update.html:32
msgid "Modification d'une élection" msgid "Modification d'une élection"
msgstr "Editing an election" msgstr "Editing an election"
@ -519,50 +547,50 @@ msgstr "Confirm"
msgid "Annuler" msgid "Annuler"
msgstr "Cancel" msgstr "Cancel"
#: elections/templates/elections/vote/rank.html:150 #: elections/templates/elections/vote/rank.html:154
msgid "Classement" msgid "Classement"
msgstr "Ranking" msgstr "Ranking"
#: elections/templates/elections/vote/rank.html:151 #: elections/templates/elections/vote/rank.html:155
#: elections/templates/elections/vote/select.html:24 #: elections/templates/elections/vote/select.html:24
msgid "Option(s) selectionnée(s)" msgid "Option(s) selectionnée(s)"
msgstr "Selected option(s)" msgstr "Selected option(s)"
#: elections/templates/elections/vote/rank.html:171 #: elections/templates/elections/vote/rank.html:175
#: elections/templates/elections/vote/rank.html:224 #: elections/templates/elections/vote/rank.html:228
msgid "Utiliser le formulaire classique" msgid "Utiliser le formulaire classique"
msgstr "Use the traditional form" msgstr "Use the traditional form"
#: elections/templates/elections/vote/rank.html:176 #: elections/templates/elections/vote/rank.html:180
msgid "Utiliser le cliquer-déposer" msgid "Utiliser le cliquer-déposer"
msgstr "Use Drag & Drop" msgstr "Use Drag & Drop"
#: elections/templates/elections/vote/rank.html:234 #: elections/templates/elections/vote/rank.html:238
#, python-format #, python-format
msgid "Rang %(i)s" msgid "Rang %(i)s"
msgstr "Rank %(i)s" msgstr "Rank %(i)s"
#: elections/templates/elections/vote/rank.html:245 #: elections/templates/elections/vote/rank.html:249
msgid "Ajouter un rang" msgid "Ajouter un rang"
msgstr "Add an rank" msgstr "Add an rank"
#: elections/utils.py:207 #: elections/utils.py:195
msgid "Vous devez sélectionnner une option." msgid "Vous devez sélectionnner une option."
msgstr "You must select an option." msgstr "You must select an option."
#: elections/utils.py:212 #: elections/utils.py:200
msgid "Vous ne pouvez pas sélectionner plus d'une option." msgid "Vous ne pouvez pas sélectionner plus d'une option."
msgstr "You cannot select more than one option." msgstr "You cannot select more than one option."
#: elections/utils.py:229 #: elections/utils.py:217
msgid "Le classement maximal est {}." msgid "Le classement maximal est {}."
msgstr "The maximum ranking is {}." msgstr "The maximum ranking is {}."
#: elections/utils.py:233 #: elections/utils.py:221
msgid "Le classement minimal est 1." msgid "Le classement minimal est 1."
msgstr "The minimum ranking is 1." msgstr "The minimum ranking is 1."
#: elections/utils.py:347 #: elections/utils.py:335
msgid "" msgid ""
"Format invalide. Vérifiez que le fichier est bien formé (i.e. chaque ligne " "Format invalide. Vérifiez que le fichier est bien formé (i.e. chaque ligne "
"de la forme 'login,nom,email')." "de la forme 'login,nom,email')."
@ -570,83 +598,132 @@ msgstr ""
"Invalid format. Check that the file is properly formed (i.e. each line of " "Invalid format. Check that the file is properly formed (i.e. each line of "
"the form 'login,name,e-mail')." "the form 'login,name,e-mail')."
#: elections/utils.py:361 #: elections/utils.py:349
msgid "La ligne {} n'a pas le bon nombre d'éléments." msgid "La ligne {} n'a pas le bon nombre d'éléments."
msgstr "The line {} has the wrong number of elements." msgstr "The line {} has the wrong number of elements."
#: elections/utils.py:366 #: elections/utils.py:354
msgid "Valeur manquante dans la ligne {} : 'login'." msgid "Valeur manquante dans la ligne {} : 'login'."
msgstr "Missing value in line {}: 'login'." msgstr "Missing value in line {}: 'login'."
#: elections/utils.py:371 #: elections/utils.py:359
msgid "Doublon dans les logins : lignes {} et {}." msgid "Doublon dans les logins : lignes {} et {}."
msgstr "Duplicate logins: lines {} and {}." msgstr "Duplicate logins: lines {} and {}."
#: elections/utils.py:379 #: elections/utils.py:367
msgid "Valeur manquante dans la ligne {} : 'nom'." msgid "Valeur manquante dans la ligne {} : 'nom'."
msgstr "Missing value in line {}: 'name'." msgstr "Missing value in line {}: 'name'."
#: elections/utils.py:385 #: elections/utils.py:373
msgid "Adresse mail invalide à la ligne {} : '{}'." msgid "Adresse mail invalide à la ligne {} : '{}'."
msgstr "Invalid e-mail address in line {}: '{}'." msgstr "Invalid e-mail address in line {}: '{}'."
#: elections/views.py:73 #: elections/views.py:58
msgid "Élection créée avec succès !" msgid "Élection créée avec succès !"
msgstr "Election successfully created!" msgstr "Election successfully created!"
#: elections/views.py:130 #: elections/views.py:99
msgid "Élection visible !"
msgstr "Election now visible!"
#: elections/views.py:127
msgid "Liste de votant·e·s importée avec succès !" msgid "Liste de votant·e·s importée avec succès !"
msgstr "Voters list successfully imported!" msgstr "Voters list successfully imported!"
#: elections/views.py:164 #: elections/views.py:161
msgid "Mail d'annonce envoyé avec succès !" msgid "Mail d'annonce envoyé avec succès !"
msgstr "Announcement e-mail sent successfully!" msgstr "Announcement e-mail sent successfully!"
#: elections/views.py:196 #: elections/views.py:193
msgid "Élection modifiée avec succès !" msgid "Élection modifiée avec succès !"
msgstr "Election successfully modified!" msgstr "Election successfully modified!"
#: elections/views.py:279 #: elections/views.py:276
msgid "Élection dépouillée avec succès !" msgid "Élection dépouillée avec succès !"
msgstr "Election successfully counted!" msgstr "Election successfully counted!"
#: elections/views.py:305 #: elections/views.py:302
msgid "Élection publiée avec succès !" msgid "Élection publiée avec succès !"
msgstr "Election successfully published!" msgstr "Election successfully published!"
#: elections/views.py:306 #: elections/views.py:303
msgid "Élection dépubliée avec succès !" msgid "Élection dépubliée avec succès !"
msgstr "Election successfully de-published!" msgstr "Election successfully de-published!"
#: elections/views.py:318 #: elections/views.py:330
msgid "Élection archivée avec succès !" msgid "Élection archivée avec succès !"
msgstr "Election successfully archived!" msgstr "Election successfully archived!"
#: elections/views.py:350 #: elections/views.py:362
msgid "Question modifiée avec succès !" msgid "Question modifiée avec succès !"
msgstr "Question successfully modified!" msgstr "Question successfully modified!"
#: elections/views.py:362 #: elections/views.py:374
msgid "Question supprimée !" msgid "Question supprimée !"
msgstr "Question deleted!" msgstr "Question deleted!"
#: elections/views.py:400 #: elections/views.py:412
msgid "Option modifiée avec succès !" msgid "Option modifiée avec succès !"
msgstr "Option successfully modified!" msgstr "Option successfully modified!"
#: elections/views.py:412 #: elections/views.py:424
msgid "Option supprimée !" msgid "Option supprimée !"
msgstr "Option deleted!" msgstr "Option deleted!"
#: elections/views.py:566 #: elections/views.py:578
msgid "Votre choix a bien été enregistré !" msgid "Votre choix a bien été enregistré !"
msgstr "Your choice has been recorded!" msgstr "Your choice has been recorded!"
#: kadenios/settings/common.py:138 #: faqs/models.py:12
msgid "titre"
msgstr "title"
#: faqs/models.py:17
msgid "contenu"
msgstr "content"
#: faqs/models.py:22
msgid "mise à jour"
msgstr "updated"
#: faqs/models.py:24
msgid "ancre"
msgstr "anchor"
#: faqs/templates/faqs/faq.html:16
#, python-format
msgid "Mis à jour le %(maj)s"
msgstr "Updated on %(maj)s"
#: faqs/templates/faqs/faq_create.html:13
msgid "Nouvelle FAQ"
msgstr "New FAQ"
#: faqs/templates/faqs/faq_edit.html:13
msgid "Modification de la FAQ"
msgstr "Editing an FAQ"
#: faqs/templates/faqs/faq_list.html:10
msgid "Liste des FAQ"
msgstr "List of FAQs"
#: faqs/templates/faqs/faq_list.html:21
msgid "Créer une FAQ"
msgstr "Create a FAQ"
#: faqs/views.py:18
msgid "Faq créée avec succès !"
msgstr "FAQ successfully created!"
#: faqs/views.py:34
msgid "Faq modifiée avec succès !"
msgstr "FAQ successfully modified!"
#: kadenios/settings/common.py:140
msgid "Français" msgid "Français"
msgstr "French" msgstr "French"
#: kadenios/settings/common.py:139 #: kadenios/settings/common.py:141
msgid "Anglais" msgid "Anglais"
msgstr "English" msgstr "English"
@ -698,20 +775,43 @@ msgstr "Password reset"
msgid "Envoyer un mail" msgid "Envoyer un mail"
msgstr "Send an e-mail" msgstr "Send an e-mail"
#: shared/templates/base.html:124 #: shared/templates/authens/pwd_reset_email.txt:2
#, python-format
msgid ""
"Quelqu'un (probablement vous) a demandé la réinitialisation du mot de passe "
"associé à cette addresse sur %(site_name)s."
msgstr ""
#: shared/templates/authens/pwd_reset_email.txt:4
msgid ""
"S'il s'agit bien de vous, vous pouvez vous rendre à l'adresse suivante pour "
"en choisir un nouveau : "
msgstr ""
#: shared/templates/authens/pwd_reset_email.txt:8
#, python-format
msgid "Pour information, votre nom d'utilisateur est le suivant : %(username)s"
msgstr ""
#: shared/templates/authens/pwd_reset_email.txt:10
#, python-format
msgid "L'équipe %(site_name)s"
msgstr ""
#: shared/templates/base.html:122
msgid "Élections" msgid "Élections"
msgstr "Elections" msgstr "Elections"
#: shared/templates/base.html:136 #: shared/templates/base.html:143
#, python-format #, python-format
msgid "Connecté·e en tant que %(name)s par %(connection)s" msgid "Connecté·e en tant que %(name)s par %(connection)s"
msgstr "Logged in as %(name)s via %(connection)s" msgstr "Logged in as %(name)s via %(connection)s"
#: shared/templates/base.html:152 #: shared/templates/base.html:159
msgid "Se connecter" msgid "Se connecter"
msgstr "Log in" msgstr "Log in"
#: shared/templates/base.html:235 #: shared/templates/base.html:242
msgid "" msgid ""
"Développé par <a class=\"tag is-light is-danger\" href=\"https://www.eleves." "Développé par <a class=\"tag is-light is-danger\" href=\"https://www.eleves."
"ens.fr/kde\">KDEns</a>. En cas de pépin, contacter <span class=\"tag is-info " "ens.fr/kde\">KDEns</a>. En cas de pépin, contacter <span class=\"tag is-info "

View file

@ -112,16 +112,24 @@
<nav class="level has-background-primary"> <nav class="level has-background-primary">
<div class="level-left px-4"> <div class="level-left px-4">
<div class="level-item"> <div class="level-item">
<a href="{% url "kadenios" %}"> <a href="{% url 'kadenios' %}">
<h1 class="has-text-primary-light is-size-1 is-family-secondary">Kadenios</h1> <h1 class="has-text-primary-light is-size-1 is-family-secondary">Kadenios</h1>
</a> </a>
</div> </div>
<div class="level-item px-4"> <div class="level-item pl-4">
<a href="{% url "election.list" %}"> <a href="{% url 'election.list' %}">
<h3 class="has-text-primary-light has-text-weight-semibold is-size-3">{% trans "Élections" %}</h3> <h3 class="has-text-primary-light has-text-weight-semibold is-size-3">{% trans "Élections" %}</h3>
</a> </a>
</div> </div>
{% comment %}
<div class="level-item pl-4">
<a href="{% url 'faq.list' %}">
<h3 class="has-text-primary-light has-text-weight-semibold is-size-3">{% trans "FAQ" %}</h3>
</a>
</div>
{% endcomment %}
</div> </div>
<div class="level-right px-5"> <div class="level-right px-5">