Commit bddb88d9 authored by tleb's avatar tleb

Comment UV API and fix little bugs

parent dbe44a9c
Pipeline #2109 passed with stage
in 31 minutes and 57 seconds
......@@ -77,3 +77,4 @@ from .user import *
from .club import *
from .group import *
from .launderette import *
from .uv import *
......@@ -24,15 +24,9 @@
from rest_framework.response import Response
from rest_framework.decorators import api_view, renderer_classes
from rest_framework.renderers import StaticHTMLRenderer, JSONRenderer
from rest_framework.views import APIView
from django.core.exceptions import PermissionDenied
from rest_framework import serializers
import urllib.request
import json
from rest_framework.renderers import StaticHTMLRenderer
from core.templatetags.renderer import markdown
from pedagogy.views import CanCreateUVFunctionMixin
@api_view(["POST"])
......@@ -46,94 +40,3 @@ def RenderMarkdown(request):
except:
data = "Error"
return Response(data)
@api_view(["GET"])
@renderer_classes((JSONRenderer,))
def uv_endpoint(request):
if not request.user.is_authenticated or not CanCreateUVFunctionMixin.can_create_uv(
request.user
):
raise PermissionDenied
lang = "fr"
params = request.query_params
if "year" not in params or "code" not in params:
raise serializers.ValidationError("Missing query parameter")
uvs_url = "https://extranet1.utbm.fr/gpedago/api/guide/uvs/{lang}/{year}"
response = urllib.request.urlopen(uvs_url.format(lang=lang, year=params["year"]))
uvs = json.loads(response.read().decode("utf-8"))
try:
found = next(uv for uv in uvs if uv["code"] == params["code"])
except StopIteration:
# shouldn't be 404, rather something like 204
return Response(status=404)
uv_url = "https://extranet1.utbm.fr/gpedago/api/guide/uv/{lang}/{year}/{code}/{formation}"
response = urllib.request.urlopen(
uv_url.format(
lang=lang,
year=params["year"],
code=params["code"],
formation=found["codeFormation"],
)
)
uv = json.loads(response.read().decode("utf-8"))
res = {}
res["credit_type"] = found["codeCategorie"]
semesters = {
(True, True): "AUTUMN_AND_SPRING",
(True, False): "AUTOMN",
(False, True): "SPRING",
}
res["semester"] = semesters.get(
(found["ouvertAutomne"], found["ouvertPrintemps"]), "CLOSED"
)
langs = {"es": "SP", "en": "EN", "de": "DE"}
res["language"] = langs.get(uv["codeLangue"], "FR")
if uv["departement"] == "Pôle Humanités":
res["department"] = "HUMA"
else:
departments = {
"AL": "IMSI",
"AE": "EE",
"GI": "GI",
"GC": "EE",
"GM": "MC",
"TC": "TC",
"GP": "IMSI",
"ED": "EDIM",
"AI": "GI",
"AM": "MC",
}
res["department"] = departments.get(uv["codeFormation"], "NA")
res["credits"] = uv["creditsEcts"]
activities = ("CM", "TD", "TP", "THE", "TE")
for activity in activities:
res["hours_{}".format(activity)] = 0
for activity in uv["activites"]:
if activity["code"] in activities:
res["hours_{}".format(activity["code"])] += activity["nbh"] // 60
res["manager"] = uv["automne"]["responsable"]
res["title"] = uv["libelle"]
res["objectives"] = uv["objectifs"]
res["program"] = uv["programme"]
res["skills"] = uv["acquisitionCompetences"]
res["key_concepts"] = uv["acquisitionNotions"]
return Response(res)
from rest_framework.response import Response
from rest_framework.decorators import api_view, renderer_classes
from rest_framework.renderers import JSONRenderer
from django.core.exceptions import PermissionDenied
from rest_framework import serializers
import urllib.request
import json
from pedagogy.views import CanCreateUVFunctionMixin
@api_view(["GET"])
@renderer_classes((JSONRenderer,))
def uv_endpoint(request):
# is authenticated and has the right to create an UV
if not request.user.is_authenticated or not CanCreateUVFunctionMixin.can_create_uv(
request.user
):
raise PermissionDenied
params = request.query_params
if "year" not in params or "code" not in params:
raise serializers.ValidationError("Missing query parameter")
short_uv, full_uv = find_uv("fr", params["year"], params["code"])
if short_uv is None or full_uv is None:
return Response(status=204)
return Response(make_clean_uv(short_uv, full_uv))
def find_uv(lang, year, code):
"""
Uses the UTBM API to find a UV.
short_uv is the UV entry in the UV list. It is returned as it contains
information which are not in full_uv.
full_uv is the detailed representation of an UV.
"""
# query the UV list
uvs_url = "https://extranet1.utbm.fr/gpedago/api/guide/uvs/{lang}/{year}"
response = urllib.request.urlopen(uvs_url.format(lang=lang, year=year))
uvs = json.loads(response.read().decode("utf-8"))
try:
# find the first UV which matches the code
short_uv = next(uv for uv in uvs if uv["code"] == code)
except StopIteration:
return (None, None)
# get detailed information about the UV
uv_url = "https://extranet1.utbm.fr/gpedago/api/guide/uv/{lang}/{year}/{code}/{formation}"
response = urllib.request.urlopen(
uv_url.format(
lang=lang, year=year, code=code, formation=short_uv["codeFormation"]
)
)
full_uv = json.loads(response.read().decode("utf-8"))
return (short_uv, full_uv)
def make_clean_uv(short_uv, full_uv):
"""
Cleans the data up so that it corresponds to our data representation.
"""
res = {}
res["credit_type"] = short_uv["codeCategorie"]
# probably wrong on a few UVs as we pick the first UV we find but
# availability depends on the formation
semesters = {
(True, True): "AUTUMN_AND_SPRING",
(True, False): "AUTUMN",
(False, True): "SPRING",
}
res["semester"] = semesters.get(
(short_uv["ouvertAutomne"], short_uv["ouvertPrintemps"]), "CLOSED"
)
langs = {"es": "SP", "en": "EN", "de": "DE"}
res["language"] = langs.get(full_uv["codeLangue"], "FR")
if full_uv["departement"] == "Pôle Humanités":
res["department"] = "HUMA"
else:
departments = {
"AL": "IMSI",
"AE": "EE",
"GI": "GI",
"GC": "EE",
"GM": "MC",
"TC": "TC",
"GP": "IMSI",
"ED": "EDIM",
"AI": "GI",
"AM": "MC",
}
res["department"] = departments.get(full_uv["codeFormation"], "NA")
res["credits"] = full_uv["creditsEcts"]
activities = ("CM", "TD", "TP", "THE", "TE")
for activity in activities:
res["hours_{}".format(activity)] = 0
for activity in full_uv["activites"]:
if activity["code"] in activities:
res["hours_{}".format(activity["code"])] += activity["nbh"] // 60
# wrong if the manager changes depending on the semester
res["manager"] = full_uv["automne"]["responsable"]
res["title"] = full_uv["libelle"]
res["objectives"] = full_uv["objectifs"]
res["program"] = full_uv["programme"]
res["skills"] = full_uv["acquisitionCompetences"]
res["key_concepts"] = full_uv["acquisitionNotions"]
return res
......@@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-10-13 17:21+0200\n"
"POT-Creation-Date: 2019-10-18 18:04+0200\n"
"PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Skia <skia@libskia.so>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n"
......@@ -88,12 +88,12 @@ msgstr "Compte club"
msgid "%(club_account)s on %(bank_account)s"
msgstr "%(club_account)s sur %(bank_account)s"
#: accounting/models.py:214 club/models.py:281 counter/models.py:616
#: accounting/models.py:214 club/models.py:281 counter/models.py:632
#: election/models.py:18 launderette/models.py:194
msgid "start date"
msgstr "date de début"
#: accounting/models.py:215 club/models.py:282 counter/models.py:617
#: accounting/models.py:215 club/models.py:282 counter/models.py:633
#: election/models.py:19
msgid "end date"
msgstr "date de fin"
......@@ -129,13 +129,13 @@ msgstr "classeur"
#: accounting/models.py:290 core/models.py:825 core/models.py:1363
#: core/models.py:1411 core/models.py:1440 counter/models.py:364
#: counter/models.py:457 counter/models.py:646 eboutic/models.py:46
#: counter/models.py:457 counter/models.py:662 eboutic/models.py:46
#: eboutic/models.py:93 forum/models.py:311 forum/models.py:408
#: stock/models.py:104
msgid "date"
msgstr "date"
#: accounting/models.py:291 counter/models.py:123 counter/models.py:647
#: accounting/models.py:291 counter/models.py:123 counter/models.py:663
#: pedagogy/models.py:219 stock/models.py:107
msgid "comment"
msgstr "commentaire"
......@@ -654,7 +654,7 @@ msgid "Target"
msgstr "Cible"
#: accounting/templates/accounting/journal_details.jinja:38
#: core/views/forms.py:112
#: core/views/forms.py:94
msgid "Code"
msgstr "Code"
......@@ -1046,7 +1046,7 @@ msgstr "Vous ne pouvez pas faire de boucles dans les clubs"
msgid "A club with that unix_name already exists"
msgstr "Un club avec ce nom UNIX existe déjà."
#: club/models.py:267 counter/models.py:607 counter/models.py:637
#: club/models.py:267 counter/models.py:623 counter/models.py:653
#: eboutic/models.py:42 eboutic/models.py:89 election/models.py:192
#: launderette/models.py:145 launderette/models.py:213 sas/models.py:244
#: trombi/models.py:213
......@@ -1155,7 +1155,7 @@ msgid "There are no members in this club."
msgstr "Il n'y a pas de membres dans ce club."
#: club/templates/club/club_members.jinja:78
#: core/templates/core/file_detail.jinja:19 core/views/forms.py:355
#: core/templates/core/file_detail.jinja:19 core/views/forms.py:337
#: launderette/views.py:226 trombi/templates/trombi/detail.jinja:19
msgid "Add"
msgstr "Ajouter"
......@@ -1363,7 +1363,7 @@ msgstr "Anciens membres"
msgid "History"
msgstr "Historique"
#: club/views.py:115 core/templates/core/base.jinja:119 core/views/user.py:219
#: club/views.py:115 core/templates/core/base.jinja:118 core/views/user.py:219
#: sas/templates/sas/picture.jinja:95 trombi/views.py:61
msgid "Tools"
msgstr "Outils"
......@@ -1651,7 +1651,7 @@ msgid "Calls to moderate"
msgstr "Appels à modérer"
#: com/templates/com/news_admin_list.jinja:242
#: core/templates/core/base.jinja:171
#: core/templates/core/base.jinja:170
msgid "Events"
msgstr "Événements"
......@@ -1930,23 +1930,23 @@ msgstr "Jusqu'à"
msgid "Automoderation"
msgstr "Automodération"
#: com/views.py:227 com/views.py:231 com/views.py:241
#: com/views.py:227 com/views.py:231 com/views.py:245
msgid "This field is required."
msgstr "Ce champ est obligatoire."
#: com/views.py:237
#: com/views.py:241
msgid "You crazy? You can not finish an event before starting it."
msgstr "T'es fou? Un événement ne peut pas finir avant même de commencer."
#: com/views.py:466
#: com/views.py:470
msgid "Delete and save to regenerate"
msgstr "Supprimer et sauver pour regénérer"
#: com/views.py:481
#: com/views.py:485
msgid "Weekmail of the "
msgstr "Weekmail du "
#: com/views.py:591
#: com/views.py:595
msgid ""
"You must be a board member of the selected club to post in the Weekmail."
msgstr ""
......@@ -2372,24 +2372,24 @@ msgstr "500, Erreur Serveur"
msgid "Welcome!"
msgstr "Bienvenue !"
#: core/templates/core/base.jinja:49
#: core/templates/core/base.jinja:48
msgid "Username"
msgstr "Nom d'utilisateur"
#: core/templates/core/base.jinja:51
#: core/templates/core/base.jinja:50
msgid "Password"
msgstr "Mot de passe"
#: core/templates/core/base.jinja:53 core/templates/core/login.jinja:4
#: core/templates/core/base.jinja:52 core/templates/core/login.jinja:4
#: core/templates/core/password_reset_complete.jinja:5
msgid "Login"
msgstr "Connexion"
#: core/templates/core/base.jinja:55 core/templates/core/register.jinja:18
#: core/templates/core/base.jinja:54 core/templates/core/register.jinja:18
msgid "Register"
msgstr "S'enregister"
#: core/templates/core/base.jinja:81 core/templates/core/base.jinja:82
#: core/templates/core/base.jinja:80 core/templates/core/base.jinja:81
#: forum/templates/forum/macros.jinja:171
#: forum/templates/forum/macros.jinja:175
#: matmat/templates/matmat/search_form.jinja:37
......@@ -2399,64 +2399,64 @@ msgstr "S'enregister"
msgid "Search"
msgstr "Recherche"
#: core/templates/core/base.jinja:108
#: core/templates/core/base.jinja:107
msgid "View more"
msgstr "Voir plus"
#: core/templates/core/base.jinja:112
#: core/templates/core/base.jinja:111
#: forum/templates/forum/last_unread.jinja:17
msgid "Mark all as read"
msgstr "Marquer tout commme lu"
#: core/templates/core/base.jinja:122
#: core/templates/core/base.jinja:121
msgid "Logout"
msgstr "Déconnexion"
#: core/templates/core/base.jinja:155
#: core/templates/core/base.jinja:154
msgid "Main"
msgstr "Accueil"
#: core/templates/core/base.jinja:157
#: core/templates/core/base.jinja:156
msgid "Associations & Clubs"
msgstr "Associations & Clubs"
#: core/templates/core/base.jinja:161
#: core/templates/core/base.jinja:160
msgid "AE"
msgstr "L'AE"
#: core/templates/core/base.jinja:162
#: core/templates/core/base.jinja:161
msgid "AE's clubs"
msgstr "Les clubs de L'AE"
#: core/templates/core/base.jinja:163
#: core/templates/core/base.jinja:162
msgid "BdF"
msgstr "Le BdF"
#: core/templates/core/base.jinja:164
#: core/templates/core/base.jinja:163
msgid "BDS"
msgstr "Le BDS"
#: core/templates/core/base.jinja:165
#: core/templates/core/base.jinja:164
msgid "CETU"
msgstr "Le CETU"
#: core/templates/core/base.jinja:166
#: core/templates/core/base.jinja:165
msgid "Doceo"
msgstr "Doceo"
#: core/templates/core/base.jinja:167
#: core/templates/core/base.jinja:166
msgid "Positions"
msgstr "Postes à pourvoir"
#: core/templates/core/base.jinja:175
#: core/templates/core/base.jinja:174
msgid "Calendar"
msgstr "Calendrier"
#: core/templates/core/base.jinja:176
#: core/templates/core/base.jinja:175
msgid "Big event"
msgstr "Grandes Activités"
#: core/templates/core/base.jinja:179
#: core/templates/core/base.jinja:178
#: forum/templates/forum/favorite_topics.jinja:14
#: forum/templates/forum/last_unread.jinja:14
#: forum/templates/forum/macros.jinja:90 forum/templates/forum/main.jinja:6
......@@ -2465,11 +2465,11 @@ msgstr "Grandes Activités"
msgid "Forum"
msgstr "Forum"
#: core/templates/core/base.jinja:180
#: core/templates/core/base.jinja:179
msgid "Gallery"
msgstr "Photos"
#: core/templates/core/base.jinja:181 counter/models.py:223
#: core/templates/core/base.jinja:180 counter/models.py:223
#: counter/templates/counter/counter_list.jinja:11
#: eboutic/templates/eboutic/eboutic_main.jinja:4
#: eboutic/templates/eboutic/eboutic_main.jinja:24
......@@ -2479,75 +2479,75 @@ msgstr "Photos"
msgid "Eboutic"
msgstr "Eboutic"
#: core/templates/core/base.jinja:183
#: core/templates/core/base.jinja:182
msgid "Services"
msgstr "Services"
#: core/templates/core/base.jinja:187
#: core/templates/core/base.jinja:186
msgid "Matmatronch"
msgstr "Matmatronch"
#: core/templates/core/base.jinja:188 launderette/models.py:47
#: core/templates/core/base.jinja:187 launderette/models.py:47
#: launderette/templates/launderette/launderette_book.jinja:5
#: launderette/templates/launderette/launderette_book_choose.jinja:4
#: launderette/templates/launderette/launderette_main.jinja:4
msgid "Launderette"
msgstr "Laverie"
#: core/templates/core/base.jinja:189 core/templates/core/file.jinja:20
#: core/templates/core/base.jinja:188 core/templates/core/file.jinja:20
#: core/views/files.py:84
msgid "Files"
msgstr "Fichiers"
#: core/templates/core/base.jinja:190 core/templates/core/user_tools.jinja:108
#: core/templates/core/base.jinja:189 core/templates/core/user_tools.jinja:108
msgid "Pedagogy"
msgstr "Pédagogie"
#: core/templates/core/base.jinja:194
#: core/templates/core/base.jinja:193
msgid "My Benefits"
msgstr "Mes Avantages"
#: core/templates/core/base.jinja:198
#: core/templates/core/base.jinja:197
msgid "Sponsors"
msgstr "Partenaires"
#: core/templates/core/base.jinja:199
#: core/templates/core/base.jinja:198
msgid "Subscriber benefits"
msgstr "Les avantages cotisants"
#: core/templates/core/base.jinja:203
#: core/templates/core/base.jinja:202
msgid "Help"
msgstr "Aide"
#: core/templates/core/base.jinja:207
#: core/templates/core/base.jinja:206
msgid "FAQ"
msgstr "FAQ"
#: core/templates/core/base.jinja:208 core/templates/core/base.jinja:250
#: core/templates/core/base.jinja:207 core/templates/core/base.jinja:249
msgid "Contacts"
msgstr "Contacts"
#: core/templates/core/base.jinja:209
#: core/templates/core/base.jinja:208
msgid "Wiki"
msgstr "Wiki"
#: core/templates/core/base.jinja:251
#: core/templates/core/base.jinja:250
msgid "Legal notices"
msgstr "Mentions légales"
#: core/templates/core/base.jinja:252
#: core/templates/core/base.jinja:251
msgid "Intellectual property"
msgstr "Propriété intellectuelle"
#: core/templates/core/base.jinja:253
#: core/templates/core/base.jinja:252
msgid "Help & Documentation"
msgstr "Aide & Documentation"
#: core/templates/core/base.jinja:254
#: core/templates/core/base.jinja:253
msgid "R&D"
msgstr "R&D"
#: core/templates/core/base.jinja:256
#: core/templates/core/base.jinja:255
msgid "Site made by good people"
msgstr "Site réalisé par des gens bons"
......@@ -2688,6 +2688,7 @@ msgstr "Éditer le groupe"
#: core/templates/core/group_edit.jinja:9
#: core/templates/core/user_edit.jinja:37
#: core/templates/core/user_group.jinja:8
#: pedagogy/templates/pedagogy/uv_create.jinja:36
msgid "Update"
msgstr "Mettre à jour"
......@@ -3520,7 +3521,7 @@ msgstr "Ajouter un nouveau dossier"
msgid "Error creating folder %(folder_name)s: %(msg)s"
msgstr "Erreur de création du dossier %(folder_name)s : %(msg)s"
#: core/views/files.py:121 core/views/forms.py:323 core/views/forms.py:330
#: core/views/files.py:121 core/views/forms.py:305 core/views/forms.py:312
#: sas/views.py:94
#, python-format
msgid "Error uploading file %(file_name)s: %(msg)s"
......@@ -3530,91 +3531,91 @@ msgstr "Erreur d'envoi du fichier %(file_name)s : %(msg)s"
msgid "Apply rights recursively"
msgstr "Appliquer les droits récursivement"
#: core/views/forms.py:105
#: core/views/forms.py:87
msgid "Heading"
msgstr "Titre"
#: core/views/forms.py:106
#: core/views/forms.py:88
msgid "Italic"
msgstr "Italique"
#: core/views/forms.py:107
#: core/views/forms.py:89
msgid "Bold"
msgstr "Gras"
#: core/views/forms.py:108
#: core/views/forms.py:90
msgid "Strikethrough"
msgstr "Barré"
#: core/views/forms.py:109
#: core/views/forms.py:91
msgid "Underline"
msgstr "Souligné"
#: core/views/forms.py:110
#: core/views/forms.py:92
msgid "Superscript"
msgstr "Exposant"
#: core/views/forms.py:111
#: core/views/forms.py:93
msgid "Subscript"
msgstr "Indice"
#: core/views/forms.py:113
#: core/views/forms.py:95
msgid "Quote"
msgstr "Citation"
#: core/views/forms.py:114
#: core/views/forms.py:96
msgid "Unordered list"
msgstr "Liste non ordonnée"
#: core/views/forms.py:115
#: core/views/forms.py:97
msgid "Ordered list"
msgstr "Liste ordonnée"
#: core/views/forms.py:116
#: core/views/forms.py:98
msgid "Insert image"
msgstr "Insérer image"
#: core/views/forms.py:117
#: core/views/forms.py:99
msgid "Insert link"
msgstr "Insérer lien"
#: core/views/forms.py:118
#: core/views/forms.py:100
msgid "Insert table"
msgstr "Insérer tableau"
#: core/views/forms.py:119
#: core/views/forms.py:101
msgid "Clean block"
msgstr "Nettoyer bloc"
#: core/views/forms.py:120
#: core/views/forms.py:102
msgid "Toggle preview"
msgstr "Activer la prévisualisation"
#: core/views/forms.py:121
#: core/views/forms.py:103
msgid "Toggle side by side"
msgstr "Activer la vue côte à côte"
#: core/views/forms.py:122
#: core/views/forms.py:104
msgid "Toggle fullscreen"
msgstr "Activer le plein écran"
#: core/views/forms.py:123
#: core/views/forms.py:105
msgid "Markdown guide"
msgstr "Guide markdown"
#: core/views/forms.py:139 core/views/forms.py:147
#: core/views/forms.py:121 core/views/forms.py:129
msgid "Choose file"
msgstr "Choisir un fichier"
#: core/views/forms.py:163 core/views/forms.py:171
#: core/views/forms.py:145 core/views/forms.py:153
msgid "Choose user"
msgstr "Choisir un utilisateur"
#: core/views/forms.py:203
#: core/views/forms.py:185
msgid "Username, email, or account number"
msgstr "Nom d'utilisateur, email, ou numéro de compte AE"
#: core/views/forms.py:269
#: core/views/forms.py:251
msgid ""
"Profile: you need to be visible on the picture, in order to be recognized (e."
"g. by the barmen)"
......@@ -3622,36 +3623,36 @@ msgstr ""
"Photo de profil: vous devez être visible sur la photo afin d'être reconnu "
"(par exemple par les barmen)"
#: core/views/forms.py:271
#: core/views/forms.py:253
msgid "Avatar: used on the forum"
msgstr "Avatar : utilisé sur le forum"
#: core/views/forms.py:272
#: core/views/forms.py:254
msgid "Scrub: let other know how your scrub looks like!"
msgstr "Blouse : montrez aux autres à quoi ressemble votre blouse !"
#: core/views/forms.py:334
#: core/views/forms.py:316
msgid "Bad image format, only jpeg, png, and gif are accepted"
msgstr "Mauvais format d'image, seuls les jpeg, png, et gif sont acceptés"
#: core/views/forms.py:354
#: core/views/forms.py:336
msgid "Godfather"
msgstr "Parrain"
#: core/views/forms.py:354
#: core/views/forms.py:336
msgid "Godchild"
msgstr "Fillot"
#: core/views/forms.py:358 counter/views.py:154 trombi/views.py:156
#: core/views/forms.py:340 counter/views.py:154 trombi/views.py:156
msgid "Select user"
msgstr "Choisir un utilisateur"
#: core/views/forms.py:371 core/views/forms.py:389 election/models.py:24
#: core/views/forms.py:353 core/views/forms.py:371 election/models.py:24
#: election/views.py:154
msgid "edit groups"
msgstr "groupe d'édition"
#: core/views/forms.py:374 core/views/forms.py:392 election/models.py:31
#: core/views/forms.py:356 core/views/forms.py:374 election/models.py:31
#: election/views.py:157
msgid "view groups"
msgstr "groupe de vue"
......@@ -3742,7 +3743,7 @@ msgstr "groupe d'achat"
msgid "archived"
msgstr "archivé"
#: counter/models.py:185 counter/models.py:738
#: counter/models.py:185 counter/models.py:754
msgid "product"
msgstr "produit"
......@@ -3770,7 +3771,7 @@ msgstr "vendeurs"
msgid "token"
msgstr "jeton"
#: counter/models.py:237 counter/models.py:613 counter/models.py:643
#: counter/models.py:237 counter/models.py:629 counter/models.py:659
#: launderette/models.py:41 stock/models.py:43
msgid "counter"
msgstr "comptoir"
......@@ -3791,7 +3792,7 @@ msgstr "rechargement"