Merge branch 'thubrecht/traduction' into 'master'

Thubrecht/traduction

Closes #2

See merge request klub-dev-ens/kadenios!4
This commit is contained in:
Tom Hubrecht 2021-04-15 16:12:31 +00:00
commit 9d316a3044
15 changed files with 945 additions and 81 deletions

View file

@ -1,3 +1,5 @@
from translated_fields import language_code_formfield_callback
from django import forms
from django.forms.models import inlineformset_factory
from django.utils import timezone
@ -8,6 +10,8 @@ from .utils import check_csv
class ElectionForm(forms.ModelForm):
formfield_callback = language_code_formfield_callback
def clean(self):
cleaned_data = super().clean()
if cleaned_data["start_date"] < timezone.now():
@ -23,16 +27,18 @@ class ElectionForm(forms.ModelForm):
class Meta:
model = Election
fields = [
"name",
"description",
"vote_restrictions",
"restricted",
*Election.name.fields,
"start_date",
"end_date",
*Election.description.fields,
"restricted",
*Election.vote_restrictions.fields,
]
widgets = {
"description": forms.Textarea(attrs={"rows": 4}),
"vote_restrictions": forms.Textarea(attrs={"rows": 4}),
"description_en": forms.Textarea(attrs={"rows": 4}),
"description_fr": forms.Textarea(attrs={"rows": 4}),
"vote_restrictions_en": forms.Textarea(attrs={"rows": 4}),
"vote_restrictions_fr": forms.Textarea(attrs={"rows": 4}),
}
@ -59,17 +65,21 @@ class VoterMailForm(forms.Form):
class QuestionForm(forms.ModelForm):
formfield_callback = language_code_formfield_callback
class Meta:
model = Question
fields = ["text", "type"]
widgets = {"text": forms.TextInput}
fields = [*Question.text.fields, "type"]
widgets = {"text_fr": forms.TextInput, "text_en": forms.TextInput}
class OptionForm(forms.ModelForm):
formfield_callback = language_code_formfield_callback
class Meta:
model = Option
fields = ["text"]
widgets = {"text": forms.TextInput}
fields = [*Option.text.fields]
widgets = {"text_fr": forms.TextInput, "text_en": forms.TextInput}
class DeleteVoteForm(forms.Form):

View file

@ -0,0 +1,63 @@
# Generated by Django 3.2 on 2021-04-15 08:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("elections", "0021_election_vote_restrictions"),
]
operations = [
migrations.RenameField(
model_name="election",
old_name="description",
new_name="description_fr",
),
migrations.RenameField(
model_name="election",
old_name="name",
new_name="name_fr",
),
migrations.RenameField(
model_name="election",
old_name="vote_restrictions",
new_name="vote_restrictions_fr",
),
migrations.RenameField(
model_name="option",
old_name="text",
new_name="text_fr",
),
migrations.RenameField(
model_name="question",
old_name="text",
new_name="text_fr",
),
migrations.AddField(
model_name="election",
name="description_en",
field=models.TextField(blank=True, verbose_name="description"),
),
migrations.AddField(
model_name="election",
name="name_en",
field=models.CharField(blank=True, max_length=255, verbose_name="nom"),
),
migrations.AddField(
model_name="election",
name="vote_restrictions_en",
field=models.TextField(blank=True, verbose_name="conditions de vote"),
),
migrations.AddField(
model_name="option",
name="text_en",
field=models.TextField(blank=True, verbose_name="texte"),
),
migrations.AddField(
model_name="question",
name="text_en",
field=models.TextField(blank=True, verbose_name="question"),
),
]

View file

@ -1,3 +1,5 @@
from translated_fields import TranslatedFieldWithFallback
from django.conf import settings
from django.contrib.auth.models import AbstractUser
from django.db import models, transaction
@ -25,14 +27,18 @@ from .utils import (
class Election(models.Model):
name = models.CharField(_("nom"), max_length=255)
name = TranslatedFieldWithFallback(models.CharField(_("nom"), max_length=255))
short_name = models.SlugField(_("nom bref"), unique=True)
description = models.TextField(_("description"), blank=True)
description = TranslatedFieldWithFallback(
models.TextField(_("description"), blank=True)
)
start_date = models.DateTimeField(_("date et heure de début"))
end_date = models.DateTimeField(_("date et heure de fin"))
vote_restrictions = models.TextField(_("conditions de vote"), blank=True)
vote_restrictions = TranslatedFieldWithFallback(
models.TextField(_("conditions de vote"), blank=True)
)
restricted = models.BooleanField(
_("restreint le vote à une liste de personnes"), default=True
@ -69,7 +75,7 @@ class Question(models.Model):
election = models.ForeignKey(
Election, related_name="questions", on_delete=models.CASCADE
)
text = models.TextField(_("question"), blank=False)
text = TranslatedFieldWithFallback(models.TextField(_("question"), blank=False))
type = models.CharField(
_("type de question"),
choices=QUESTION_TYPES,
@ -125,7 +131,7 @@ class Option(models.Model):
question = models.ForeignKey(
Question, related_name="options", on_delete=models.CASCADE
)
text = models.TextField(_("texte"), blank=False)
text = TranslatedFieldWithFallback(models.TextField(_("texte"), blank=False))
winner = models.BooleanField(_("option gagnante"), default=False)
voters = models.ManyToManyField(

View file

@ -2,6 +2,24 @@
{% load i18n %}
{% block extra_head %}
<script>
document.addEventListener('DOMContentLoaded', () => {
var $modalButtons = document.querySelectorAll('.modal-button') || [];
$modalButtons.forEach(function($el) {
$el.addEventListener('click', function() {
var $target = document.getElementById($el.dataset.target);
$target_form = $target.querySelector("form");
$target_form.action = $el.dataset.post_url;
});
});
});
</script>
{% endblock %}
{% block content %}
<div class="level is-block-tablet is-block-desktop is-flex-fullhd">
@ -217,55 +235,38 @@
{# Rajout d'une option #}
{% if election.start_date > current_time %}
<form action="{% url 'election.add-option' q.pk %}" method="post">
<div class="panel-block field has-addons">
{% csrf_token %}
<div class="control has-icons-left is-expanded">
<input class="input is-success" type="text" name="text" id="id_text" placeholder="{% trans "Rajouter une option" %}">
<span class="icon is-left">
<div class="panel-block">
<button class="button modal-button is-primary is-outlined is-fullwidth" data-post_url="{% url 'election.add-option' q.pk %}" data-target="modal-add_option">
<span class="icon">
<i class="fas fa-plus"></i>
</span>
<span>{% trans "Rajouter une option" %}</span>
</button>
</div>
<div class="control">
<button class="button is-success">{% trans "Valider" %}</button>
</div>
</div>
</form>
{% endif %}
</div>
{% endfor %}
{# Rajout d'une question #}
{% if election.start_date > current_time %}
{# Rajout d'une option #}
{% trans "Rajouter une option" as modal_title %}
{% include "forms/modal-form.html" with modal_id="add_option" form=o_form %}
{# Rajout d'une question #}
{% trans "Rajouter une question" as modal_title %}
{% include "forms/modal-form.html" with modal_id="add_question" form=q_form %}
<div class="columns is-centered" id="q_add">
<div class="column is-two-thirds">
<form action="{% url 'election.add-question' election.pk %}" method="post">
{% csrf_token %}
<div class="field has-addons">
<div class="control has-icons-left is-expanded">
<input class="input is-primary" type="text" name="text" id="id_text" placeholder="{% trans "Rajouter une question" %}">
<span class="icon is-left">
<button class="button modal-button is-primary is-outlined is-fullwidth" data-post_url="{% url 'election.add-question' election.pk %}" data-target="modal-add_question">
<span class="icon">
<i class="fas fa-question"></i>
</span>
</div>
<div class="control">
<span class="select is-primary">
<select name="type" id="id_type">
{% for val, choice in question_types %}
<option value="{{ val }}">{{ choice }}</option>
{% endfor %}
</select>
</span>
</div>
<div class="control">
<button class="button is-primary is-outlined">{% trans "Valider" %}</button>
</div>
</div>
</form>
<span>{% trans "Rajouter une question" %}</span>
</button>
</div>
</div>
{% endif %}

View file

@ -90,8 +90,16 @@ class ElectionAdminView(CreatorOnlyMixin, DetailView):
return reverse("election.view", args=[self.object.pk])
def get_context_data(self, **kwargs):
from django.utils.translation import get_language
print(get_language())
kwargs.update(
{"current_time": timezone.now(), "question_types": QUESTION_TYPES}
{
"current_time": timezone.now(),
"question_types": QUESTION_TYPES,
"o_form": OptionForm,
"q_form": QuestionForm,
}
)
return super().get_context_data(**kwargs)

View file

@ -6,6 +6,7 @@ import os
import sys
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _
# #############################################################################
# Secrets
@ -59,6 +60,7 @@ INSTALLED_APPS = [
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
@ -132,6 +134,13 @@ USE_I18N = True
USE_L10N = True
USE_TZ = True
LANGUAGES = [
("fr", _("Français")),
("en", _("Anglais")),
]
LOCALE_PATHS = [os.path.join(BASE_DIR, "shared", "locale")]
# #############################################################################
# Paramètres des fichiers statiques
# #############################################################################

View file

@ -10,6 +10,7 @@ urlpatterns = [
path("elections/", include("elections.urls")),
path("auth/", include("shared.auth.urls")),
path("authens/", include("authens.urls")),
path("i18n/", include("django.conf.urls.i18n")),
]
if "debug_toolbar" in settings.INSTALLED_APPS:

View file

@ -1,4 +1,5 @@
django==3.2.*
django-translated-fields==0.11.1
authens>=0.1b2
numpy
networkx

Binary file not shown.

View file

@ -0,0 +1,697 @@
# Kadenios translations.
# Copyright (C) 2021 Klub Dev ENS
# This file is distributed under the same license as the kadenios package.
# Klub Dev ENS <klub-dev@ens.fr>, 2021.
#
msgid ""
msgstr ""
"Project-Id-Version: 0.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-04-15 16:56+0200\n"
"PO-Revision-Date: 2021-04-15 16:57+0200\n"
"Last-Translator: Test Translator <test@translator>\n"
"Language-Team: \n"
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.4.1\n"
#: elections/forms.py:29
msgid "Impossible de faire débuter l'élection dans le passé"
msgstr "Impossible to start the election in the past"
#: elections/forms.py:33
msgid "Impossible de terminer l'élection avant de la commencer"
msgstr "Impossible to end the election before it starts"
#: elections/forms.py:56
msgid "Sélectionnez un fichier .csv"
msgstr "Select a .csv file"
#: elections/forms.py:66
msgid "Extension de fichier invalide, il faut un fichier au format CSV."
msgstr "Invalid file extension, a CSV file is required."
#: elections/forms.py:100
msgid "Supprimer le vote de {} ({}) ?"
msgstr "Delete the vote of {} ({}) ?"
#: elections/forms.py:105 elections/templates/elections/election_admin.html:168
#: elections/templates/elections/election_admin.html:195
#: elections/templates/elections/election_voters.html:57
msgid "Supprimer"
msgstr "Delete"
#: elections/forms.py:105
msgid "Non"
msgstr "No"
#: elections/forms.py:105
msgid "Oui"
msgstr "Yes"
#: elections/models.py:31
msgid "nom"
msgstr "name"
#: elections/models.py:32
msgid "nom bref"
msgstr "short name"
#: elections/models.py:34
msgid "description"
msgstr "description"
#: elections/models.py:37
msgid "date et heure de début"
msgstr "start date and time"
#: elections/models.py:38
msgid "date et heure de fin"
msgstr "end date and time"
#: elections/models.py:41
msgid "conditions de vote"
msgstr "voting requirements"
#: elections/models.py:45
msgid "restreint le vote à une liste de personnes"
msgstr "restricts the vote to a list of people"
#: elections/models.py:49
msgid "mail avec les identifiants envoyé"
msgstr "mail with credentials sent"
#: elections/models.py:66
msgid "résultats publics"
msgstr "results published"
#: elections/models.py:67
msgid "dépouillée"
msgstr "counted"
#: elections/models.py:69
msgid "archivée"
msgstr "archived"
#: elections/models.py:79
msgid "question"
msgstr "question"
#: elections/models.py:81
msgid "type de question"
msgstr "type of question"
#: elections/models.py:88
msgid "nombre maximal de votes reçus"
msgstr "maximal number of votes received"
#: elections/models.py:135
msgid "texte"
msgstr "text"
#: elections/models.py:137
msgid "option gagnante"
msgstr "winning option"
#: elections/models.py:145
msgid "nombre de votes reçus"
msgstr "number of votes received"
#: elections/models.py:164
msgid "rang de l'option"
msgstr "option's ranking"
#: elections/models.py:180
msgid "votes supplémentaires"
msgstr "extra votes"
#: elections/models.py:196
msgid "Nom et Prénom"
msgstr "Name and surname"
#: elections/models.py:218 elections/tests/test_models.py:57
msgid "identifiants spécifiques"
msgstr "dedicated credentials"
#: elections/models.py:222
msgid "Peut administrer des élections"
msgstr "Can manage elections"
#: elections/staticdefs.py:26 elections/tests/test_models.py:56
msgid "mot de passe"
msgstr "password"
#: elections/staticdefs.py:27 elections/tests/test_models.py:55
msgid "CAS"
msgstr "CAS"
#: elections/staticdefs.py:31
msgid "Assentiment"
msgstr "Assent"
#: elections/staticdefs.py:32
msgid "Uninominal"
msgstr "Uninominal"
#: elections/staticdefs.py:33
msgid "Condorcet"
msgstr "Condorcet"
#: elections/staticdefs.py:44
msgid ""
"Le mode de scrutin pour cette question est un vote par assentiment. Vous "
"pouvez donc sélectionner autant d'options que vous souhaitez. Vous pouvez "
"également ne sélectionner aucune option."
msgstr ""
"The voting method for this question is a assent vote. You can therefore "
"select as many options as you wish. You can also select no options at all."
#: elections/staticdefs.py:49
msgid ""
"Le mode de scrutin pour cette question est un vote uninominal. Vous ne "
"pouvez donc sélectionner qu'une seule option."
msgstr ""
"The voting method for this question is a uninominal vote. You can therefore "
"only select one option."
#: elections/staticdefs.py:53
#, python-brace-format
msgid ""
"Le mode de scrutin pour cette question est un vote de type condorcet. Vous "
"devez classer les options <b>entre 1 et {nb_options}</b>, l'option classée 1 "
"étant votre préférée. <b>Vous pouvez donner le même classement à plusieurs "
"options</b>, si vous laissez vide le classement d'une option, elle sera "
"classée dernière automatiquement."
msgstr ""
"The voting method for this question is a condorcet vote. You must rank the "
"options <b>between 1 and {nb_options}</b>, with the option ranked 1 being "
"your favourite. <b>You can give the same ranking to more than one option</"
"b>, if you leave an option's ranking blank, it will be ranked last "
"automatically."
#: elections/templates/elections/delete_vote.html:7
msgid "Supprimer un vote"
msgstr "Delete a vote"
#: elections/templates/elections/delete_vote.html:23
#: elections/templates/elections/election_create.html:41
#: elections/templates/elections/election_update.html:47
#: elections/templates/elections/option_update.html:29
#: elections/templates/elections/question_update.html:29
#: elections/templates/elections/vote.html:125
#: shared/templates/auth/election_login.html:25
#: shared/templates/authens/pwd_login.html:25
#: shared/templates/authens/pwd_reset_confirm.html:25
#: shared/templates/forms/modal-form.html:23
msgid "Enregistrer"
msgstr "Save"
#: elections/templates/elections/delete_vote.html:32
#: elections/templates/elections/election_update.html:55
#: elections/templates/elections/election_voters.html:19
#: elections/templates/elections/mail_voters.html:43
#: elections/templates/elections/option_update.html:37
#: elections/templates/elections/question_update.html:37
#: elections/templates/elections/upload_voters.html:46
#: elections/templates/elections/vote.html:134
#: shared/templates/auth/election_login.html:34
#: shared/templates/authens/pwd_login.html:34
#: shared/templates/authens/pwd_reset.html:34
msgid "Retour"
msgstr "Back"
#: elections/templates/elections/election.html:20
msgid "Votant·e·s"
msgstr "Voters"
#: elections/templates/elections/election.html:29
msgid "Élection terminée"
msgstr "Election completed"
#: elections/templates/elections/election.html:31
msgid "Élection en cours"
msgstr "Election in progress"
#: elections/templates/elections/election.html:40
#: elections/templates/elections/election_list.html:72
msgid "Administrer"
msgstr "Manage"
#: elections/templates/elections/election.html:67
#, python-format
msgid "Créé par %(creator)s"
msgstr "Created by %(creator)s"
#: elections/templates/elections/election.html:80
msgid "Votre vote a bien été enregistré."
msgstr "Your vote has been recorded."
#: elections/templates/elections/election.html:107
msgid "Voter"
msgstr "Vote"
#: elections/templates/elections/election.html:118
msgid ""
"Pour voter lors de cette élection, vous devez vous connecter à l'aide des "
"identifiants reçus par mail."
msgstr ""
"To vote in this election, you must log in using the login credentials you "
"received by e-mail."
#: elections/templates/elections/election.html:120
#: elections/templates/elections/election_voters.html:44
msgid ""
"Pour voter lors de cette élection, vous devez vous connecter à l'aide du CAS "
"élève, d'autres restrictions peuvent s'appliquer et votre vote pourra être "
"supprimé si vous n'avez pas le droit de vote."
msgstr ""
"To vote in this election you must log in using the student CAS, other "
"restrictions may apply and your vote may be deleted if you are not eligible "
"to vote."
#: elections/templates/elections/election.html:136
msgid "Connexion par identifiants"
msgstr "Login with credentials"
#: elections/templates/elections/election.html:147
#: shared/templates/authens/login_switch.html:20
msgid "Connexion via CAS"
msgstr "Login via CAS"
#: elections/templates/elections/election.html:175
msgid "A voté"
msgstr "Voted"
#: elections/templates/elections/election_admin.html:41
msgid "Actions"
msgstr "Actions"
#: elections/templates/elections/election_admin.html:54
#: elections/templates/elections/election_admin.html:177
#: elections/templates/elections/election_admin.html:200
msgid "Modifier"
msgstr "Edit"
#: elections/templates/elections/election_admin.html:63
#: elections/templates/elections/upload_voters.html:25
msgid "Gestion de la liste de votant·e·s"
msgstr "Management of the voters' list"
#: elections/templates/elections/election_admin.html:75
#: elections/templates/elections/election_voters.html:27
msgid "Liste des votant·e·s"
msgstr "Voters' list"
#: elections/templates/elections/election_admin.html:83
msgid "Dépouiller"
msgstr "Count"
#: elections/templates/elections/election_admin.html:94
msgid "Publier"
msgstr "Publish"
#: elections/templates/elections/election_admin.html:96
msgid "Dépublier"
msgstr "De-publish"
#: elections/templates/elections/election_admin.html:106
msgid "Archiver"
msgstr "Archive"
#: elections/templates/elections/election_admin.html:243
#: elections/templates/elections/election_admin.html:254
msgid "Rajouter une option"
msgstr "Add an option"
#: elections/templates/elections/election_admin.html:258
#: elections/templates/elections/election_admin.html:268
msgid "Rajouter une question"
msgstr "Add a question"
#: elections/templates/elections/election_create.html:31
msgid "Création d'une élection"
msgstr "Creating an election"
#: elections/templates/elections/election_list.html:10
msgid "Liste des élections"
msgstr "List of elections"
#: elections/templates/elections/election_list.html:21
msgid "Créer une élection"
msgstr "Create an election"
#: elections/templates/elections/election_list.html:54
msgid "Élection dépouillée"
msgstr "Election counted"
#: elections/templates/elections/election_list.html:60
msgid "Élection publiée"
msgstr "Published election"
#: elections/templates/elections/election_list.html:66
msgid "Élection archivée"
msgstr "Archived election"
#: elections/templates/elections/election_update.html:31
msgid "Modification d'une élection"
msgstr "Editing an election"
#: elections/templates/elections/election_voters.html:42
msgid ""
"Seules les personnes présentes sur cette liste peuvent voter, vous avez dû "
"recevoir un mail avec vos identifiants de connexion."
msgstr ""
"Only people on this list can vote, you should have received an e-mail with "
"your login credentials."
#: elections/templates/elections/election_voters.html:54
#: elections/templates/elections/upload_voters.html:105
msgid "Nom"
msgstr "Name"
#: elections/templates/elections/election_voters.html:55
msgid "Vote enregistré"
msgstr "Recorded vote"
#: elections/templates/elections/election_voters.html:89
#, python-format
msgid "Supprimer le vote de %(v_name)s"
msgstr "Delete the vote of %(v_name)s"
#: elections/templates/elections/mail_voters.html:7
msgid "Composition du mail aux votant·e·s"
msgstr "Composition of the e-mail to voters"
#: elections/templates/elections/mail_voters.html:12
msgid ""
"Assurez-vous que la liste des votant·e·s est complète, en effet, une fois le "
"mail envoyé, il ne sera plus possible de la modifier."
msgstr ""
"Make sure that the list of voters is complete, as once the e-mail is sent, "
"it will not be possible to change it."
#: elections/templates/elections/mail_voters.html:17
#, python-brace-format
msgid ""
"Rajoutez le message à envoyer aux électeurs entre 'Dear {full_name}' et "
"l'url de l'élection."
msgstr ""
"Add the message to be sent to voters between 'Dear {full_name}' and the "
"election url."
#: elections/templates/elections/mail_voters.html:34
msgid "Envoyer"
msgstr "Send"
#: elections/templates/elections/option_update.html:13
msgid "Modification d'une option"
msgstr "Editing an option"
#: elections/templates/elections/question_update.html:13
msgid "Modification d'une question"
msgstr "Editing a question"
#: elections/templates/elections/results/rank.html:39
#, python-format
msgid ""
"L'option %(winner)s est préférée à l'option %(loser)s par %(cell)s voix."
msgstr ""
"The %(winner)s option is preferred to the %(loser)s option by %(cell)s votes."
#: elections/templates/elections/results/rank.html:51
msgid ""
"La matrice des résultats montre les points d'avance, l'option gagnante est "
"affichée sur la colonne et la perdante sur la ligne. "
msgstr ""
"The results matrix shows the lead points, with the winning option displayed "
"in the column and the losing option in the row. "
#: elections/templates/elections/results/select.html:4
msgid "L'option majoritaire et gagnante est colorée en vert."
msgstr "The dominant and winning option is coloured green."
#: elections/templates/elections/upload_voters.html:36
msgid "Envoyer le mail d'annonce"
msgstr "Send the announcement e-mail"
#: elections/templates/elections/upload_voters.html:57
msgid ""
"Importez un fichier au format CSV, avec sur la première colonne le login, "
"sur la deuxième, le nom et prénom et enfin l'adresse email sur la troisième. "
"Soit :<br><br><pre>Login_1,Prénom/Nom_1,mail_1@machin.test<br>Login_2,Prénom/"
"Nom_2,mail_2@bidule.test<br>...</pre>"
msgstr ""
"Import a file in CSV format, with the login in the first column, the first "
"and last name in the second and the e-mail address in the third. So:"
"<br><br><pre>Login_1,Firstname/Lastname_1,mail_1@thing.test<br>Login_2,"
"Firstname/Lastname_2,mail_2@thingy.test<br>...</pre>"
#: elections/templates/elections/upload_voters.html:83
msgid "Importer"
msgstr "Import"
#: elections/templates/elections/upload_voters.html:96
msgid "Liste des votant·e·s pour cette élection"
msgstr "List of voters for this election"
#: elections/templates/elections/upload_voters.html:104
msgid "Login"
msgstr "Login"
#: elections/templates/elections/upload_voters.html:106
msgid "Email"
msgstr "E-mail"
#: elections/templates/elections/vote.html:25
#: elections/templates/elections/vote.html:76
msgid "Option(s) selectionnée(s)"
msgstr "Selected option(s)"
#: elections/templates/elections/vote.html:75
msgid "Classement"
msgstr "Ranking"
#: elections/templates/elections/vote.html:101
msgid "Vote pour la question :"
msgstr "Vote for the question:"
#: elections/templates/elections/vote.html:142
msgid "Confirmation du vote"
msgstr "Confirmation of the vote"
#: elections/templates/elections/vote.html:154
msgid "Confirmer"
msgstr "Confirm"
#: elections/templates/elections/vote.html:161
#: shared/templates/forms/modal-form.html:30
msgid "Annuler"
msgstr "Cancel"
#: elections/utils.py:206
msgid "Vous devez sélectionnner une option."
msgstr "You must select an option."
#: elections/utils.py:211
msgid "Vous ne pouvez pas sélectionner plus d'une option."
msgstr "You cannot select more than one option."
#: elections/utils.py:228
msgid "Le classement maximal est {}."
msgstr "The maximum ranking is {}."
#: elections/utils.py:232
msgid "Le classement minimal est 1."
msgstr "The minimum ranking is 1."
#: elections/utils.py:289
msgid ""
"Format invalide. Vérifiez que le fichier est bien formé (i.e. chaque ligne "
"de la forme 'login,nom,email')."
msgstr ""
"Invalid format. Check that the file is properly formed (i.e. each line of "
"the form 'login,name,e-mail')."
#: elections/utils.py:303
msgid "La ligne {} n'a pas le bon nombre d'éléments."
msgstr "The line {} has the wrong number of elements."
#: elections/utils.py:308
msgid "Valeur manquante dans la ligne {} : 'login'."
msgstr "Missing value in line {}: 'login'."
#: elections/utils.py:313
msgid "Doublon dans les logins : lignes {} et {}."
msgstr "Duplicate logins: lines {} and {}."
#: elections/utils.py:321
msgid "Valeur manquante dans la ligne {} : 'nom'."
msgstr "Missing value in line {}: 'name'."
#: elections/utils.py:327
msgid "Adresse mail invalide à la ligne {} : '{}'."
msgstr "Invalid e-mail address in line {}: '{}'."
#: elections/views.py:69
msgid "Élection créée avec succès !"
msgstr "Election successfully created!"
#: elections/views.py:113
msgid "Liste de votant·e·s importée avec succès !"
msgstr "Voters list successfully imported!"
#: elections/views.py:147
msgid "Mail d'annonce envoyé avec succès !"
msgstr "Announcement e-mail sent successfully!"
#: elections/views.py:179
msgid "Élection modifiée avec succès !"
msgstr "Election successfully modified!"
#: elections/views.py:249
msgid "Élection dépouillée avec succès !"
msgstr "Election successfully counted!"
#: elections/views.py:275
msgid "Élection publiée avec succès !"
msgstr "Election successfully published!"
#: elections/views.py:276
msgid "Élection dépubliée avec succès !"
msgstr "Election successfully de-published!"
#: elections/views.py:288
msgid "Élection archivée avec succès !"
msgstr "Election successfully archived!"
#: elections/views.py:320
msgid "Question modifiée avec succès !"
msgstr "Question successfully modified!"
#: elections/views.py:332
msgid "Question supprimée !"
msgstr "Question deleted!"
#: elections/views.py:370
msgid "Option modifiée avec succès !"
msgstr "Option successfully modified!"
#: elections/views.py:382
msgid "Option supprimée !"
msgstr "Option deleted!"
#: elections/views.py:522
msgid "Votre choix a bien été enregistré !"
msgstr "Your choice has been recorded!"
#: kadenios/settings/common.py:138
msgid "Français"
msgstr "French"
#: kadenios/settings/common.py:139
msgid "Anglais"
msgstr "English"
#: shared/auth/forms.py:13
msgid "Identifiant"
msgstr "Username"
#: shared/auth/forms.py:15
msgid "Mot de passe"
msgstr "Password"
#: shared/auth/forms.py:50
msgid ""
"Aucun·e électeur·ice avec cet identifiant et mot de passe n'existe pour "
"cette élection. Vérifiez que les informations rentrées sont correctes, les "
"champs sont sensibles à la casse."
msgstr ""
"No voter with this username and password exists for this election. Check "
"that the information entered is correct, the fields are case sensitive."
#: shared/templates/auth/election_login.html:9
#: shared/templates/authens/login_switch.html:33
#: shared/templates/authens/pwd_login.html:9
msgid "Connexion par mot de passe"
msgstr "Password login"
#: shared/templates/authens/login_switch.html:9
msgid "Choisissez la méthode de connexion"
msgstr "Choose the connection method"
#: shared/templates/authens/pwd_login.html:42
msgid "Mot de passe oublié :"
msgstr "Forgotten password:"
#: shared/templates/authens/pwd_login.html:48
msgid "Réinitialiser mon mot de passe."
msgstr "Reset my password."
#: shared/templates/authens/pwd_reset.html:9
#: shared/templates/authens/pwd_reset_confirm.html:9
msgid "Réinitialisation du mot de passe"
msgstr "Password reset"
#: shared/templates/authens/pwd_reset.html:25
msgid "Envoyer un mail"
msgstr "Send an e-mail"
#: shared/templates/base.html:113
msgid "Élections"
msgstr "Elections"
#: shared/templates/base.html:125
#, python-format
msgid "Connecté·e en tant que %(name)s par %(connection)s"
msgstr "Logged in as %(name)s via %(connection)s"
#: shared/templates/base.html:141
msgid "Se connecter"
msgstr "Log in"
#: shared/templates/base.html:224
msgid ""
"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 "
"is-light\">klub-dev [at] ens [dot] fr</span>."
msgstr ""
"Developed by <a class=\"tag is-light is-danger\" href=\"https://www.eleves."
"ens.fr/kde\">KDEns</a>. In case of glitches, contact <span class=\"tag is-"
"info is-light\">klub-dev [at] ens [dot] fr</span>."
#: shared/templates/forms/file.html:17
msgid "Choisissez un fichier..."
msgstr "Choose a file..."
#: shared/templates/forms/file.html:21
msgid "Aucun fichier sélectionné"
msgstr "No file selected"
#: shared/templates/kadenios.html:7
msgid "Bienvenue sur Kadenios"
msgstr "Welcome to Kadenios"
#: shared/templates/kadenios.html:10
msgid "La plateforme Kadenios permet de créer des élections."
msgstr "The Kadenios platform provides a way to create elections."
#: shared/templates/registration/logged_out.html:9
msgid "Déconnexion réussie"
msgstr "Successfully logged out"
#: shared/templates/registration/logged_out.html:22
msgid "Se reconnecter"
msgstr "Log back in"
#: shared/templates/registration/logged_out.html:31
msgid "Accueil"
msgstr "Home"
#~ msgid " [{}] :"
#~ msgstr " [{}]:"
#~ msgid "Valider"
#~ msgstr "Confirm"

View file

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icon-css-gb" viewBox="0 0 640 480">
<path fill="#012169" d="M0 0h640v480H0z"/>
<path fill="#FFF" d="M75 0l244 181L562 0h78v62L400 241l240 178v61h-80L320 301 81 480H0v-60l239-178L0 64V0h75z"/>
<path fill="#C8102E" d="M424 281l216 159v40L369 281h55zm-184 20l6 35L54 480H0l240-179zM640 0v3L391 191l2-44L590 0h50zM0 0l239 176h-60L0 42V0z"/>
<path fill="#FFF" d="M241 0v480h160V0H241zM0 160v160h640V160H0z"/>
<path fill="#C8102E" d="M0 193v96h640v-96H0zM273 0v480h96V0h-96z"/>
</svg>

After

Width:  |  Height:  |  Size: 538 B

View file

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icon-css-fr" viewBox="0 0 640 480">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="#fff" d="M0 0h640v480H0z"/>
<path fill="#00267f" d="M0 0h213.3v480H0z"/>
<path fill="#f31830" d="M426.7 0H640v480H426.7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 292 B

View file

@ -82,6 +82,16 @@
}
});
// Language selection
var $langs = document.querySelectorAll('.dropdown-item.lang-selector') || [];
$langs.forEach($lang => {
$lang.addEventListener('click', () => {
document.getElementById('lang-input').value = $lang.dataset.lang;
document.getElementById('lang-form').submit();
});
});
});
</script>
@ -105,28 +115,31 @@
</div>
</div>
{% block auth %}
<div class="level-right px-5">
{% block auth %}
<div class="level-item">
{% if user.is_authenticated %}
<div class="level is-mobile">
<div class="level-item mr-5">
<div class="level-item">
<div class="tag">
{% blocktrans with name=user.get_username connection=user.connection_method %}Connecté·e en tant que {{ name }} par {{ connection }}{% endblocktrans %}
</div>
</div>
<div class="level-item ml-3 py-4">
<a class="icon is-size-1 has-text-white" href="{% url 'authens:logout' %}?next={% if view.get_next_url %}{{ view.get_next_url }}{% else %}/{% endif %}">
<div class="level-item">
<a class="button is-primary" href="{% url 'authens:logout' %}?next={% if view.get_next_url %}{{ view.get_next_url }}{% else %}/{% endif %}">
<span class="icon is-size-1">
<i class="fas fa-sign-out-alt"></i>
</span>
</a>
</div>
</div>
{% else %}
<div class="level-item py-2">
<a class="tag has-text-primary is-size-5" href="{% url 'authens:login' %}?next={{ request.path }}">
<span>{% trans "Se connecter" %}</span>
<span class="icon">
<a class="button" href="{% url 'authens:login' %}?next={{ request.path }}">
<span class="is-size-5">{% trans "Se connecter" %}</span>
<span class="icon is-size-4">
<i class="fas fa-sign-in-alt"></i>
</span>
</a>
@ -134,6 +147,49 @@
{% endif %}
</div>
{% endblock %}
{# Choix de la langue #}
<div class="level-item">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as langs %}
<form action="{% url "set_language" %}" method="POST" id="lang-form">
{% csrf_token %}
<input type="hidden" name="language" id="lang-input">
</form>
<div class="dropdown is-hoverable is-right">
<div class="dropdown-trigger">
<a class="button is-primary is-large" aria-haspopup="true" aria-controls="dropdown-menu">
<span class="icon is-size-2">
<i class="fas fa-language"></i>
</span>
</a>
</div>
<div class="dropdown-menu">
<div class="dropdown-content">
{% for lang in langs %}
{% with lang_svg="images/"|add:lang.code|add:".svg" %}
<a class="dropdown-item lang-selector" data-lang="{{ lang.code }}">
<span class="icon-text">
<span class="icon">
<img src="{% static lang_svg %}">
</span>
<span class="ml-1">{{ lang.name_translated }}</span>
</span>
{% endwith %}
</a>
{% if not forloop.last %}
<hr class="dropdown-divider">
{% endif %}
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</nav>
{% block layout %}
<div class="main-content">

View file

@ -25,7 +25,7 @@
<a class="button is-primary button-close">
<span class="icon">
<i class="fas fa-undo-alt"></i>
<i class="fas fa-times"></i>
</span>
<span>{% trans "Annuler" %}</span>
</a>

View file

@ -4,11 +4,9 @@
{% block content %}
{% blocktrans %}
<h1 class="title">Bienvenue sur Kadenios</h1>
<h1 class="title">{% trans "Bienvenue sur Kadenios" %}</h1>
<hr>
La plateforme Kadenios permet de créer des élections.
{% endblocktrans %}
{% trans "La plateforme Kadenios permet de créer des élections." %}
{% endblock %}