forked from Github-Mirrors/canaille
LDAP 'preferredLanguage' attribute support
This commit is contained in:
parent
2a018510d8
commit
bb0daf34d7
20 changed files with 343 additions and 192 deletions
|
@ -25,6 +25,7 @@ Added
|
|||
|
||||
- Python 3.11 support. :pr:`61`
|
||||
- apparmor slapd configuration instructions in CONTRIBUTING.rst :pr:`66`
|
||||
- ``preferredLanguage`` attribute support. :pr:`75`
|
||||
|
||||
Changed
|
||||
*******
|
||||
|
|
|
@ -12,6 +12,7 @@ from flask_themer import FileSystemThemeLoader
|
|||
from flask_themer import render_template
|
||||
from flask_themer import Themer
|
||||
|
||||
from .i18n import available_language_codes
|
||||
from .ldap_backend.backend import init_backend
|
||||
from .oidc.oauth import setup_oauth
|
||||
|
||||
|
@ -100,25 +101,34 @@ def setup_jinja(app):
|
|||
app.jinja_env.filters["timestamp"] = timestamp
|
||||
|
||||
|
||||
def setup_babel(app):
|
||||
def setup_i18n(app):
|
||||
babel = Babel(app)
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
g.available_language_codes = available_language_codes(babel)
|
||||
|
||||
@babel.localeselector
|
||||
def get_locale():
|
||||
user = getattr(g, "user", None)
|
||||
if user is not None:
|
||||
return user.locale
|
||||
from .flaskutils import current_user
|
||||
|
||||
user = current_user()
|
||||
available_language_codes = getattr(g, "available_language_codes", [])
|
||||
if user is not None and user.preferredLanguage in available_language_codes:
|
||||
return user.preferredLanguage
|
||||
|
||||
if app.config.get("LANGUAGE"):
|
||||
return app.config.get("LANGUAGE")
|
||||
|
||||
return request.accept_languages.best_match(["fr_FR", "en_US"])
|
||||
return request.accept_languages.best_match(available_language_codes)
|
||||
|
||||
@babel.timezoneselector
|
||||
def get_timezone():
|
||||
user = getattr(g, "user", None)
|
||||
from .flaskutils import current_user
|
||||
|
||||
user = current_user()
|
||||
if user is not None:
|
||||
return user.timezone
|
||||
return user.Timezone
|
||||
|
||||
|
||||
def setup_themer(app):
|
||||
|
@ -165,7 +175,7 @@ def create_app(config=None, validate=True):
|
|||
setup_oauth(app)
|
||||
setup_blueprints(app)
|
||||
setup_jinja(app)
|
||||
setup_babel(app)
|
||||
setup_i18n(app)
|
||||
setup_themer(app)
|
||||
|
||||
@app.before_request
|
||||
|
|
|
@ -496,6 +496,12 @@ def profile_edit(editor, username):
|
|||
) and request.form["action"] == "edit":
|
||||
flash(_("Profile updated successfuly."), "success")
|
||||
|
||||
if (
|
||||
"preferredLanguage" in request.form
|
||||
and form["preferredLanguage"].data == "auto"
|
||||
):
|
||||
user.preferredLanguage = None
|
||||
|
||||
user.save()
|
||||
return redirect(url_for("account.profile_edition", username=username))
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
|
|||
[ACL.DEFAULT]
|
||||
PERMISSIONS = ["edit_self", "use_oidc"]
|
||||
READ = ["uid", "groups"]
|
||||
WRITE = ["givenName", "sn", "userPassword", "telephoneNumber", "jpegPhoto", "mail", "labeledURI"]
|
||||
WRITE = ["givenName", "sn", "userPassword", "telephoneNumber", "jpegPhoto", "mail", "labeledURI", "preferredLanguage"]
|
||||
|
||||
[ACL.ADMIN]
|
||||
FILTER = "memberof=cn=moderators,ou=groups,dc=mydomain,dc=tld"
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import wtforms.form
|
||||
from flask import current_app
|
||||
from flask import g
|
||||
from flask_babel import lazy_gettext as _
|
||||
from flask_wtf import FlaskForm
|
||||
from flask_wtf.file import FileAllowed
|
||||
from flask_wtf.file import FileField
|
||||
|
||||
from .i18n import available_language_codes
|
||||
from .i18n import native_language_name_from_code
|
||||
from .models import Group
|
||||
from .models import User
|
||||
|
||||
|
@ -89,6 +92,13 @@ class PasswordResetForm(FlaskForm):
|
|||
)
|
||||
|
||||
|
||||
def available_language_choices():
|
||||
return [("auto", _("Automatic"))] + [
|
||||
(lang_code, native_language_name_from_code(lang_code))
|
||||
for lang_code in g.available_language_codes
|
||||
]
|
||||
|
||||
|
||||
PROFILE_FORM_FIELDS = dict(
|
||||
uid=wtforms.StringField(
|
||||
_("Username"),
|
||||
|
@ -164,6 +174,10 @@ PROFILE_FORM_FIELDS = dict(
|
|||
"placeholder": _("https://mywebsite.tld"),
|
||||
},
|
||||
),
|
||||
preferredLanguage=wtforms.SelectField(
|
||||
_("Preferred language"),
|
||||
choices=available_language_choices,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
|
22
canaille/i18n.py
Normal file
22
canaille/i18n.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
import gettext
|
||||
|
||||
import pycountry
|
||||
|
||||
DEFAULT_LANGUAGE_CODE = "en"
|
||||
|
||||
|
||||
def native_language_name_from_code(code):
|
||||
language = pycountry.languages.get(alpha_2=code[:2])
|
||||
if code == DEFAULT_LANGUAGE_CODE:
|
||||
return language.name
|
||||
|
||||
translation = gettext.translation(
|
||||
"iso639-3", pycountry.LOCALES_DIR, languages=[code]
|
||||
)
|
||||
return translation.gettext(language.name)
|
||||
|
||||
|
||||
def available_language_codes(babel):
|
||||
return [str(translation) for translation in babel.list_translations()] + [
|
||||
DEFAULT_LANGUAGE_CODE
|
||||
]
|
|
@ -52,7 +52,7 @@ def cached_oauth_authorization_server():
|
|||
"code id_token",
|
||||
"token id_token",
|
||||
],
|
||||
"ui_locales_supported": ["en-US", "fr-FR"],
|
||||
"ui_locales_supported": g.available_language_codes,
|
||||
"code_challenge_methods_supported": ["plain", "S256"],
|
||||
}
|
||||
|
||||
|
|
|
@ -43,10 +43,14 @@ display=true
|
|||
|
||||
{% if field.type not in ("SelectField", "SelectMultipleField") %}
|
||||
{{ field(**kwargs) }}
|
||||
{% elif field.render_kw and "readonly" in field.render_kw %}
|
||||
{% elif field.type == "SelectMultipleField" and field.render_kw and "readonly" in field.render_kw %}
|
||||
{{ field(class_="ui fluid dropdown multiple read-only", **kwargs) }}
|
||||
{% else %}
|
||||
{% elif field.type == "SelectMultipleField" %}
|
||||
{{ field(class_="ui fluid dropdown multiple", **kwargs) }}
|
||||
{% elif field.type == "SelectField" and field.render_kw and "readonly" in field.render_kw %}
|
||||
{{ field(class_="ui fluid dropdown read-only", **kwargs) }}
|
||||
{% elif field.type == "SelectField" %}
|
||||
{{ field(class_="ui fluid dropdown", **kwargs) }}
|
||||
{% endif %}
|
||||
|
||||
{% if suffix_text %}
|
||||
|
|
|
@ -143,6 +143,11 @@
|
|||
{% block labeled_uri_field scoped %}{{ render_field(form.labeledURI) }}{% endblock %}
|
||||
{% endif %}
|
||||
|
||||
{% if "preferredLanguage" in form %}
|
||||
{% block preferred_language_field scoped %}{{ render_field(form.preferredLanguage) }}{% endblock %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
<h4 class="ui dividing header">{% trans %}Account information{% endtrans %}</h4>
|
||||
|
||||
{% if "uid" in form %}
|
||||
|
|
|
@ -3,25 +3,25 @@
|
|||
# This file is distributed under the same license as the PROJECT project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
|
||||
# Camille <camille@yaal.coop>, 2021-2022.
|
||||
# Éloi Rivard <eloi@yaal.fr>, 2020-2022.
|
||||
# Éloi Rivard <eloi.rivard@nubla.fr>, 2020-2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: contact@yaal.fr\n"
|
||||
"POT-Creation-Date: 2022-07-07 14:27+0200\n"
|
||||
"PO-Revision-Date: 2022-07-07 14:28+0200\n"
|
||||
"Last-Translator: Éloi Rivard <eloi@yaal.fr>\n"
|
||||
"Language: fr_FR\n"
|
||||
"Language-Team: French - France <equipe@yaal.fr>\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
"POT-Creation-Date: 2022-11-20 19:32+0100\n"
|
||||
"PO-Revision-Date: 2022-11-20 19:32+0100\n"
|
||||
"Last-Translator: Éloi Rivard <eloi.rivard@nubla.fr>\n"
|
||||
"Language: fr\n"
|
||||
"Language-Team: French <traduc@traduc.org>\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.10.1\n"
|
||||
"X-Generator: Gtranslator 40.0\n"
|
||||
"Generated-By: Babel 2.11.0\n"
|
||||
"X-Generator: Gtranslator 42.0\n"
|
||||
|
||||
#: canaille/account.py:93 canaille/account.py:118 canaille/oidc/oauth.py:88
|
||||
#: canaille/account.py:93 canaille/account.py:118 canaille/oidc/endpoints.py:92
|
||||
msgid "Login failed, please check your information"
|
||||
msgstr "La connexion a échoué, veuillez vérifier vos informations."
|
||||
|
||||
|
@ -71,7 +71,7 @@ msgstr "Votre compte a déjà été créé."
|
|||
msgid "You are already logged in, you cannot create an account."
|
||||
msgstr "Vous êtes déjà connectés, vous ne pouvez pas créer de compte."
|
||||
|
||||
#: canaille/account.py:316 canaille/forms.py:185 canaille/forms.py:233
|
||||
#: canaille/account.py:316 canaille/forms.py:199 canaille/forms.py:247
|
||||
#: canaille/templates/groups.html:11 canaille/templates/userlist.html:17
|
||||
#: canaille/themes/default/base.html:61
|
||||
msgid "Groups"
|
||||
|
@ -113,16 +113,16 @@ msgstr "L'édition du profil a échoué."
|
|||
msgid "Profile updated successfuly."
|
||||
msgstr "Le profil a été mis à jour avec succès."
|
||||
|
||||
#: canaille/account.py:520
|
||||
#: canaille/account.py:527
|
||||
#, python-format
|
||||
msgid "The user %(user)s has been sucessfuly deleted"
|
||||
msgstr "L'utilisateur %(user)s a bien été supprimé"
|
||||
|
||||
#: canaille/account.py:550
|
||||
#: canaille/account.py:557
|
||||
msgid "Could not send the password reset link."
|
||||
msgstr "Impossible d'envoyer le lien de réinitialisation."
|
||||
|
||||
#: canaille/account.py:554
|
||||
#: canaille/account.py:561
|
||||
msgid ""
|
||||
"A password reset link has been sent at your email address. You should "
|
||||
"receive it within 10 minutes."
|
||||
|
@ -130,7 +130,7 @@ msgstr ""
|
|||
"Un lien de ré-initialisation de votre mot de passe vous a été envoyé par "
|
||||
"mail. Vous devriez le recevoir d'ici une dizaine de minutes."
|
||||
|
||||
#: canaille/account.py:565
|
||||
#: canaille/account.py:572
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The user '%(user)s' does not have permissions to update their password. We "
|
||||
|
@ -139,17 +139,17 @@ msgstr ""
|
|||
"L'utilisateur '%(user)s' n'a pas la permission d'éditer son mot de passe. "
|
||||
"Nous ne pouvons pas lui envoyer un email de réinitialisation."
|
||||
|
||||
#: canaille/account.py:580
|
||||
#: canaille/account.py:587
|
||||
msgid "We encountered an issue while we sent the password recovery email."
|
||||
msgstr ""
|
||||
"Nous avons rencontré un problème lors de l'envoi de l'email de "
|
||||
"réinitialisation de mot de passe."
|
||||
|
||||
#: canaille/account.py:599
|
||||
#: canaille/account.py:606
|
||||
msgid "The password reset link that brought you here was invalid."
|
||||
msgstr "Le lien de réinitialisation qui vous a amené ici est invalide."
|
||||
|
||||
#: canaille/account.py:608
|
||||
#: canaille/account.py:615
|
||||
msgid "Your password has been updated successfuly"
|
||||
msgstr "Votre mot de passe a correctement été mis à jour."
|
||||
|
||||
|
@ -157,8 +157,8 @@ msgstr "Votre mot de passe a correctement été mis à jour."
|
|||
msgid "Email"
|
||||
msgstr "Courriel"
|
||||
|
||||
#: canaille/admin.py:29 canaille/forms.py:47 canaille/forms.py:71
|
||||
#: canaille/forms.py:123 canaille/forms.py:227
|
||||
#: canaille/admin.py:29 canaille/forms.py:50 canaille/forms.py:74
|
||||
#: canaille/forms.py:133 canaille/forms.py:241
|
||||
msgid "jane@doe.com"
|
||||
msgstr "camille@dupont.fr"
|
||||
|
||||
|
@ -182,7 +182,7 @@ msgstr "Invitation sur {website_name}"
|
|||
msgid "John Doe"
|
||||
msgstr "Camille Dupont"
|
||||
|
||||
#: canaille/apputils.py:44 canaille/forms.py:95 canaille/forms.py:215
|
||||
#: canaille/apputils.py:44 canaille/forms.py:105 canaille/forms.py:229
|
||||
msgid "jdoe"
|
||||
msgstr "cdupont"
|
||||
|
||||
|
@ -198,129 +198,137 @@ msgstr " ou "
|
|||
msgid "No SMTP server has been configured"
|
||||
msgstr "Aucun serveur SMTP n'a été configuré"
|
||||
|
||||
#: canaille/forms.py:15
|
||||
#: canaille/forms.py:18
|
||||
msgid "The login '{login}' already exists"
|
||||
msgstr "L'identifiant '{login}' existe déjà"
|
||||
|
||||
#: canaille/forms.py:22
|
||||
#: canaille/forms.py:25
|
||||
msgid "The email '{email}' already exists"
|
||||
msgstr "L'email '{email}' existe déjà"
|
||||
|
||||
#: canaille/forms.py:29
|
||||
#: canaille/forms.py:32
|
||||
msgid "The group '{group}' already exists"
|
||||
msgstr "Le group '{group}' existe déjà"
|
||||
|
||||
#: canaille/forms.py:38
|
||||
#: canaille/forms.py:41
|
||||
msgid "The login '{login}' does not exist"
|
||||
msgstr "L'identifiant '{login}' n'existe pas"
|
||||
|
||||
#: canaille/forms.py:44 canaille/forms.py:68 canaille/templates/userlist.html:8
|
||||
#: canaille/forms.py:47 canaille/forms.py:71 canaille/templates/userlist.html:8
|
||||
msgid "Login"
|
||||
msgstr "Identifiant"
|
||||
|
||||
#: canaille/forms.py:57 canaille/forms.py:80 canaille/forms.py:144
|
||||
#: canaille/forms.py:60 canaille/forms.py:83 canaille/forms.py:154
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: canaille/forms.py:83 canaille/forms.py:148
|
||||
#: canaille/forms.py:86 canaille/forms.py:158
|
||||
msgid "Password confirmation"
|
||||
msgstr "Confirmation du mot de passe"
|
||||
|
||||
#: canaille/forms.py:86 canaille/forms.py:151
|
||||
#: canaille/forms.py:89 canaille/forms.py:161
|
||||
msgid "Password and confirmation do not match."
|
||||
msgstr "Le mot de passe et sa confirmation ne correspondent pas."
|
||||
|
||||
#: canaille/forms.py:94 canaille/forms.py:214
|
||||
#: canaille/forms.py:96
|
||||
msgid "Automatic"
|
||||
msgstr "Automatique"
|
||||
|
||||
#: canaille/forms.py:104 canaille/forms.py:228
|
||||
msgid "Username"
|
||||
msgstr "Identifiant"
|
||||
|
||||
#: canaille/forms.py:98 canaille/forms.py:200 canaille/oidc/clients.py:36
|
||||
#: canaille/forms.py:108 canaille/forms.py:214 canaille/oidc/clients.py:36
|
||||
#: canaille/templates/groups.html:17
|
||||
#: canaille/templates/oidc/admin/client_list.html:23
|
||||
#: canaille/templates/userlist.html:11
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: canaille/forms.py:100
|
||||
#: canaille/forms.py:110
|
||||
msgid "Given name"
|
||||
msgstr "Prénom"
|
||||
|
||||
#: canaille/forms.py:102
|
||||
#: canaille/forms.py:112
|
||||
msgid "John"
|
||||
msgstr "Martin"
|
||||
|
||||
#: canaille/forms.py:108
|
||||
#: canaille/forms.py:118
|
||||
msgid "Family Name"
|
||||
msgstr "Nom de famille"
|
||||
|
||||
#: canaille/forms.py:111
|
||||
#: canaille/forms.py:121
|
||||
msgid "Doe"
|
||||
msgstr "Dupont"
|
||||
|
||||
#: canaille/forms.py:117 canaille/forms.py:220
|
||||
#: canaille/forms.py:127 canaille/forms.py:234
|
||||
msgid "Email address"
|
||||
msgstr "Courriel"
|
||||
|
||||
#: canaille/forms.py:119
|
||||
#: canaille/forms.py:129
|
||||
msgid ""
|
||||
"This email will be used as a recovery address to reset the password if needed"
|
||||
msgstr ""
|
||||
"Cette adresse servira d'adresse e-mail de récupération pour recevoir un e-"
|
||||
"mail de réinitialisation de mot de passe en cas de besoin"
|
||||
|
||||
#: canaille/forms.py:129
|
||||
#: canaille/forms.py:139
|
||||
msgid "Phone number"
|
||||
msgstr "Numéro de téléphone"
|
||||
|
||||
#: canaille/forms.py:129
|
||||
#: canaille/forms.py:139
|
||||
msgid "555-000-555"
|
||||
msgstr "06 01 02 03 04"
|
||||
|
||||
#: canaille/forms.py:132
|
||||
#: canaille/forms.py:142
|
||||
msgid "Address"
|
||||
msgstr "Adresse"
|
||||
|
||||
#: canaille/forms.py:134
|
||||
#: canaille/forms.py:144
|
||||
msgid "132, Foobar Street, Gotham City 12401"
|
||||
msgstr "132, rue du Lorem Ipsum - 99000 Gotham City"
|
||||
|
||||
#: canaille/forms.py:138
|
||||
#: canaille/forms.py:148
|
||||
msgid "Photo"
|
||||
msgstr "Photo"
|
||||
|
||||
#: canaille/forms.py:142 canaille/templates/profile.html:95
|
||||
#: canaille/forms.py:152 canaille/templates/profile.html:95
|
||||
msgid "Delete the photo"
|
||||
msgstr "Supprimer la photo"
|
||||
|
||||
#: canaille/forms.py:156
|
||||
#: canaille/forms.py:166
|
||||
msgid "Number"
|
||||
msgstr "Numéro"
|
||||
|
||||
#: canaille/forms.py:158
|
||||
#: canaille/forms.py:168
|
||||
msgid "1234"
|
||||
msgstr "1234"
|
||||
|
||||
#: canaille/forms.py:162
|
||||
#: canaille/forms.py:172
|
||||
msgid "Website"
|
||||
msgstr "Site internet"
|
||||
|
||||
#: canaille/forms.py:164
|
||||
#: canaille/forms.py:174
|
||||
msgid "https://mywebsite.tld"
|
||||
msgstr "https://mon-site-internet.fr"
|
||||
|
||||
#: canaille/forms.py:187
|
||||
#: canaille/forms.py:178
|
||||
msgid "Preferred language"
|
||||
msgstr "Langage favori"
|
||||
|
||||
#: canaille/forms.py:201
|
||||
msgid "users, admins ..."
|
||||
msgstr "utilisateurs, administrateurs ..."
|
||||
|
||||
#: canaille/forms.py:203
|
||||
#: canaille/forms.py:217
|
||||
msgid "group"
|
||||
msgstr "groupe"
|
||||
|
||||
#: canaille/forms.py:207 canaille/templates/groups.html:18
|
||||
#: canaille/forms.py:221 canaille/templates/groups.html:18
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
|
||||
#: canaille/forms.py:218
|
||||
#: canaille/forms.py:232
|
||||
msgid "Username editable by the invitee"
|
||||
msgstr "L'identifiant sera éditable par la personne invitée"
|
||||
|
||||
|
@ -333,11 +341,11 @@ msgstr "La création du groupe a échoué."
|
|||
msgid "The group %(group)s has been sucessfully created"
|
||||
msgstr "Le groupe %(group)s a bien été créé"
|
||||
|
||||
#: canaille/groups.py:92
|
||||
#: canaille/groups.py:93
|
||||
msgid "Group edition failed."
|
||||
msgstr "L'édition du groupe a échoué."
|
||||
|
||||
#: canaille/groups.py:101
|
||||
#: canaille/groups.py:102
|
||||
#, python-format
|
||||
msgid "The group %(group)s has been sucessfully deleted"
|
||||
msgstr "Le groupe %(group)s a bien été supprimé"
|
||||
|
@ -431,11 +439,11 @@ msgstr "Le client n'a pas été ajouté. Veuillez vérifier vos informations."
|
|||
msgid "The client has been created."
|
||||
msgstr "Le client a été créé."
|
||||
|
||||
#: canaille/oidc/clients.py:233
|
||||
#: canaille/oidc/clients.py:234
|
||||
msgid "The client has not been edited. Please check your information."
|
||||
msgstr "Le client n'a pas été édité. Veuillez vérifier vos informations."
|
||||
|
||||
#: canaille/oidc/clients.py:260
|
||||
#: canaille/oidc/clients.py:263
|
||||
msgid "The client has been edited."
|
||||
msgstr "Le client a été édité."
|
||||
|
||||
|
@ -451,39 +459,39 @@ msgstr "Impossible de supprimer cet accès."
|
|||
msgid "The access has been revoked"
|
||||
msgstr "L'accès a été révoqué."
|
||||
|
||||
#: canaille/oidc/oauth.py:43
|
||||
#: canaille/oidc/endpoints.py:45
|
||||
msgid "Personnal information about yourself, such as your name or your gender."
|
||||
msgstr "Vos informations personnelles, comme votre nom ou votre genre."
|
||||
|
||||
#: canaille/oidc/oauth.py:45
|
||||
#: canaille/oidc/endpoints.py:47
|
||||
msgid "Your email address."
|
||||
msgstr "Votre adresse email."
|
||||
|
||||
#: canaille/oidc/oauth.py:46
|
||||
#: canaille/oidc/endpoints.py:48
|
||||
msgid "Your postal address."
|
||||
msgstr "Votre adresse postale."
|
||||
|
||||
#: canaille/oidc/oauth.py:47
|
||||
#: canaille/oidc/endpoints.py:49
|
||||
msgid "Your phone number."
|
||||
msgstr "Votre numéro de téléphone."
|
||||
|
||||
#: canaille/oidc/oauth.py:48
|
||||
#: canaille/oidc/endpoints.py:50
|
||||
msgid "Groups you are belonging to"
|
||||
msgstr "Les groupes auxquels vous appartenez"
|
||||
|
||||
#: canaille/oidc/oauth.py:136
|
||||
#: canaille/oidc/endpoints.py:140
|
||||
msgid "You have been successfully logged out."
|
||||
msgstr "Vous avez été déconnecté·e."
|
||||
|
||||
#: canaille/oidc/oauth.py:317
|
||||
#: canaille/oidc/endpoints.py:338
|
||||
msgid "You have been disconnected"
|
||||
msgstr "Vous avez été déconnecté·e."
|
||||
|
||||
#: canaille/oidc/oauth.py:325
|
||||
#: canaille/oidc/endpoints.py:346
|
||||
msgid "An error happened during the logout"
|
||||
msgstr "Une erreur est survenue lors de la déconnexion"
|
||||
|
||||
#: canaille/oidc/oauth.py:337
|
||||
#: canaille/oidc/endpoints.py:358
|
||||
msgid "You have not been disconnected"
|
||||
msgstr "Vous n'avez pas été déconnecté"
|
||||
|
||||
|
@ -581,14 +589,14 @@ msgstr "Page de connexion"
|
|||
msgid "Send the initialization email"
|
||||
msgstr "Envoyer le courriel d'initialisation"
|
||||
|
||||
#: canaille/templates/fomanticui.html:64
|
||||
#: canaille/templates/fomanticui.html:68
|
||||
#: canaille/templates/oidc/admin/client_edit.html:35
|
||||
#: canaille/templates/oidc/admin/client_edit.html:44
|
||||
#: canaille/templates/oidc/admin/client_edit.html:53
|
||||
msgid "This field is not editable"
|
||||
msgstr "Ce champ n'est pas modifiable"
|
||||
|
||||
#: canaille/templates/fomanticui.html:68
|
||||
#: canaille/templates/fomanticui.html:72
|
||||
msgid "This field is required"
|
||||
msgstr "Ce champ est requis"
|
||||
|
||||
|
@ -615,7 +623,6 @@ msgstr ""
|
|||
" "
|
||||
|
||||
#: canaille/templates/forgotten-password.html:38
|
||||
#: canaille/templates/profile.html:191 canaille/templates/profile.html:219
|
||||
msgid "Send again"
|
||||
msgstr "Envoyer à nouveau"
|
||||
|
||||
|
@ -682,7 +689,7 @@ msgstr "Supprimer le groupe"
|
|||
msgid "Create group"
|
||||
msgstr "Créer le groupe"
|
||||
|
||||
#: canaille/templates/group.html:82 canaille/templates/profile.html:259
|
||||
#: canaille/templates/group.html:82 canaille/templates/profile.html:254
|
||||
msgid "Submit"
|
||||
msgstr "Valider"
|
||||
|
||||
|
@ -873,23 +880,23 @@ msgstr "Informations personnelles"
|
|||
msgid "Click to upload a photo"
|
||||
msgstr "Cliquez pour mettre en ligne une photo"
|
||||
|
||||
#: canaille/templates/profile.html:146
|
||||
#: canaille/templates/profile.html:151
|
||||
msgid "Account information"
|
||||
msgstr "Informations sur le compte"
|
||||
|
||||
#: canaille/templates/profile.html:171
|
||||
#: canaille/templates/profile.html:176
|
||||
msgid "User password is not mandatory"
|
||||
msgstr "Le mot de passe utilisateur n'est pas requis à la création"
|
||||
|
||||
#: canaille/templates/profile.html:174
|
||||
#: canaille/templates/profile.html:179
|
||||
msgid "The user password can be set:"
|
||||
msgstr "Il pourra être renseigné :"
|
||||
|
||||
#: canaille/templates/profile.html:176
|
||||
#: canaille/templates/profile.html:181
|
||||
msgid "by filling this form;"
|
||||
msgstr "en remplissant ce formulaire ;"
|
||||
|
||||
#: canaille/templates/profile.html:177
|
||||
#: canaille/templates/profile.html:182
|
||||
msgid ""
|
||||
"by sending the user a password initialization mail, after the account "
|
||||
"creation;"
|
||||
|
@ -897,7 +904,7 @@ msgstr ""
|
|||
"en envoyant un lien d'initialisation de mot de passe, par mail à "
|
||||
"l'utilisateur, après la création de son compte;"
|
||||
|
||||
#: canaille/templates/profile.html:178 canaille/templates/profile.html:207
|
||||
#: canaille/templates/profile.html:183 canaille/templates/profile.html:206
|
||||
msgid ""
|
||||
"or simply waiting for the user to sign-in a first time, and then receive a "
|
||||
"password initialization mail."
|
||||
|
@ -905,7 +912,7 @@ msgstr ""
|
|||
"ou simplement en attendant la première connexion de l'utilisateur, afin "
|
||||
"qu'il reçoive un lien d'initialisation de mot de passe par email."
|
||||
|
||||
#: canaille/templates/profile.html:181 canaille/templates/profile.html:210
|
||||
#: canaille/templates/profile.html:186 canaille/templates/profile.html:209
|
||||
msgid "The user will not be able to authenticate unless the password is set"
|
||||
msgstr ""
|
||||
"L'utilisateur ne pourra pas se connecter tant que son mot de passe n'est pas "
|
||||
|
@ -915,36 +922,36 @@ msgstr ""
|
|||
msgid "Send email"
|
||||
msgstr "Envoyer l'email"
|
||||
|
||||
#: canaille/templates/profile.html:200
|
||||
#: canaille/templates/profile.html:199
|
||||
msgid "This user does not have a password yet"
|
||||
msgstr "L'utilisateur n'a pas encore de mot de passe"
|
||||
|
||||
#: canaille/templates/profile.html:203
|
||||
#: canaille/templates/profile.html:202
|
||||
msgid "You can solve this by:"
|
||||
msgstr "Vous pouvez régler ceci en :"
|
||||
|
||||
#: canaille/templates/profile.html:205
|
||||
#: canaille/templates/profile.html:204
|
||||
msgid "setting a password using this form;"
|
||||
msgstr "renseignant un mot de passe via ce formulaire ;"
|
||||
|
||||
#: canaille/templates/profile.html:206
|
||||
#: canaille/templates/profile.html:205
|
||||
msgid ""
|
||||
"sending the user a password initialization mail, by clicking this button;"
|
||||
msgstr ""
|
||||
"envoyant un lien d'initialisation de mot de passe, par mail à l'utilisateur, "
|
||||
"en cliquant sur ce bouton;"
|
||||
|
||||
#: canaille/templates/profile.html:221
|
||||
#: canaille/templates/profile.html:217
|
||||
msgid "Send mail"
|
||||
msgstr "Envoyer l'email"
|
||||
|
||||
#: canaille/templates/mail/admin.html:56 canaille/templates/profile.html:225
|
||||
#: canaille/templates/mail/admin.html:56 canaille/templates/profile.html:220
|
||||
#: canaille/templates/reset-password.html:11
|
||||
#: canaille/templates/reset-password.html:16
|
||||
msgid "Password reset"
|
||||
msgstr "Réinitialisation du mot de passe"
|
||||
|
||||
#: canaille/templates/profile.html:227
|
||||
#: canaille/templates/profile.html:222
|
||||
msgid ""
|
||||
"If the user has forgotten his password, you can send him a password reset "
|
||||
"email by clicking this button."
|
||||
|
@ -952,19 +959,19 @@ msgstr ""
|
|||
"Si l'utilisateur a oublié son mot de passe, vous pouvez lui envoyer un email "
|
||||
"contenant un lien de réinitilisation en cliquant sur ce bouton."
|
||||
|
||||
#: canaille/templates/profile.html:239
|
||||
#: canaille/templates/profile.html:234
|
||||
msgid "Delete the user"
|
||||
msgstr "Supprimer l'utilisateur"
|
||||
|
||||
#: canaille/templates/profile.html:241
|
||||
#: canaille/templates/profile.html:236
|
||||
msgid "Delete my account"
|
||||
msgstr "Supprimer mon compte"
|
||||
|
||||
#: canaille/templates/profile.html:248
|
||||
#: canaille/templates/profile.html:243
|
||||
msgid "Impersonate"
|
||||
msgstr "Prendre l'identité"
|
||||
|
||||
#: canaille/templates/profile.html:254 canaille/templates/users.html:20
|
||||
#: canaille/templates/profile.html:249 canaille/templates/users.html:20
|
||||
msgid "Invite a user"
|
||||
msgstr "Inviter un utilisateur"
|
||||
|
||||
|
@ -1162,14 +1169,14 @@ msgstr "Secret"
|
|||
msgid "Issued at"
|
||||
msgstr "Créé le"
|
||||
|
||||
#: canaille/templates/oidc/admin/client_edit.html:72
|
||||
msgid "Edit"
|
||||
msgstr "Éditer"
|
||||
|
||||
#: canaille/templates/oidc/admin/client_edit.html:75
|
||||
#: canaille/templates/oidc/admin/client_edit.html:74
|
||||
msgid "Delete the client"
|
||||
msgstr "Supprimer le client"
|
||||
|
||||
#: canaille/templates/oidc/admin/client_edit.html:77
|
||||
msgid "Edit"
|
||||
msgstr "Éditer"
|
||||
|
||||
#: canaille/templates/oidc/admin/client_list.html:17
|
||||
msgid "Add client"
|
||||
msgstr "Ajouter un client"
|
||||
|
|
|
@ -8,16 +8,16 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2022-07-07 14:27+0200\n"
|
||||
"POT-Creation-Date: 2022-11-20 19:32+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.10.1\n"
|
||||
"Generated-By: Babel 2.11.0\n"
|
||||
|
||||
#: canaille/account.py:93 canaille/account.py:118 canaille/oidc/oauth.py:88
|
||||
#: canaille/account.py:93 canaille/account.py:118 canaille/oidc/endpoints.py:92
|
||||
msgid "Login failed, please check your information"
|
||||
msgstr ""
|
||||
|
||||
|
@ -65,7 +65,7 @@ msgstr ""
|
|||
msgid "You are already logged in, you cannot create an account."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:316 canaille/forms.py:185 canaille/forms.py:233
|
||||
#: canaille/account.py:316 canaille/forms.py:199 canaille/forms.py:247
|
||||
#: canaille/templates/groups.html:11 canaille/templates/userlist.html:17
|
||||
#: canaille/themes/default/base.html:61
|
||||
msgid "Groups"
|
||||
|
@ -103,37 +103,37 @@ msgstr ""
|
|||
msgid "Profile updated successfuly."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:520
|
||||
#: canaille/account.py:527
|
||||
#, python-format
|
||||
msgid "The user %(user)s has been sucessfuly deleted"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:550
|
||||
#: canaille/account.py:557
|
||||
msgid "Could not send the password reset link."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:554
|
||||
#: canaille/account.py:561
|
||||
msgid ""
|
||||
"A password reset link has been sent at your email address. You should "
|
||||
"receive it within 10 minutes."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:565
|
||||
#: canaille/account.py:572
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The user '%(user)s' does not have permissions to update their password. "
|
||||
"We cannot send a password reset email."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:580
|
||||
#: canaille/account.py:587
|
||||
msgid "We encountered an issue while we sent the password recovery email."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:599
|
||||
#: canaille/account.py:606
|
||||
msgid "The password reset link that brought you here was invalid."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/account.py:608
|
||||
#: canaille/account.py:615
|
||||
msgid "Your password has been updated successfuly"
|
||||
msgstr ""
|
||||
|
||||
|
@ -141,8 +141,8 @@ msgstr ""
|
|||
msgid "Email"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/admin.py:29 canaille/forms.py:47 canaille/forms.py:71
|
||||
#: canaille/forms.py:123 canaille/forms.py:227
|
||||
#: canaille/admin.py:29 canaille/forms.py:50 canaille/forms.py:74
|
||||
#: canaille/forms.py:133 canaille/forms.py:241
|
||||
msgid "jane@doe.com"
|
||||
msgstr ""
|
||||
|
||||
|
@ -166,7 +166,7 @@ msgstr ""
|
|||
msgid "John Doe"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/apputils.py:44 canaille/forms.py:95 canaille/forms.py:215
|
||||
#: canaille/apputils.py:44 canaille/forms.py:105 canaille/forms.py:229
|
||||
msgid "jdoe"
|
||||
msgstr ""
|
||||
|
||||
|
@ -182,128 +182,136 @@ msgstr ""
|
|||
msgid "No SMTP server has been configured"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:15
|
||||
#: canaille/forms.py:18
|
||||
msgid "The login '{login}' already exists"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:22
|
||||
#: canaille/forms.py:25
|
||||
msgid "The email '{email}' already exists"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:29
|
||||
#: canaille/forms.py:32
|
||||
msgid "The group '{group}' already exists"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:38
|
||||
#: canaille/forms.py:41
|
||||
msgid "The login '{login}' does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:44 canaille/forms.py:68 canaille/templates/userlist.html:8
|
||||
#: canaille/forms.py:47 canaille/forms.py:71 canaille/templates/userlist.html:8
|
||||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:57 canaille/forms.py:80 canaille/forms.py:144
|
||||
#: canaille/forms.py:60 canaille/forms.py:83 canaille/forms.py:154
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:83 canaille/forms.py:148
|
||||
#: canaille/forms.py:86 canaille/forms.py:158
|
||||
msgid "Password confirmation"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:86 canaille/forms.py:151
|
||||
#: canaille/forms.py:89 canaille/forms.py:161
|
||||
msgid "Password and confirmation do not match."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:94 canaille/forms.py:214
|
||||
#: canaille/forms.py:96
|
||||
msgid "Automatic"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:104 canaille/forms.py:228
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:98 canaille/forms.py:200 canaille/oidc/clients.py:36
|
||||
#: canaille/forms.py:108 canaille/forms.py:214 canaille/oidc/clients.py:36
|
||||
#: canaille/templates/groups.html:17
|
||||
#: canaille/templates/oidc/admin/client_list.html:23
|
||||
#: canaille/templates/userlist.html:11
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:100
|
||||
#: canaille/forms.py:110
|
||||
msgid "Given name"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:102
|
||||
#: canaille/forms.py:112
|
||||
msgid "John"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:108
|
||||
#: canaille/forms.py:118
|
||||
msgid "Family Name"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:111
|
||||
#: canaille/forms.py:121
|
||||
msgid "Doe"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:117 canaille/forms.py:220
|
||||
#: canaille/forms.py:127 canaille/forms.py:234
|
||||
msgid "Email address"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:119
|
||||
#: canaille/forms.py:129
|
||||
msgid ""
|
||||
"This email will be used as a recovery address to reset the password if "
|
||||
"needed"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:129
|
||||
#: canaille/forms.py:139
|
||||
msgid "Phone number"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:129
|
||||
#: canaille/forms.py:139
|
||||
msgid "555-000-555"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:132
|
||||
#: canaille/forms.py:142
|
||||
msgid "Address"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:134
|
||||
#: canaille/forms.py:144
|
||||
msgid "132, Foobar Street, Gotham City 12401"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:138
|
||||
#: canaille/forms.py:148
|
||||
msgid "Photo"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:142 canaille/templates/profile.html:95
|
||||
#: canaille/forms.py:152 canaille/templates/profile.html:95
|
||||
msgid "Delete the photo"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:156
|
||||
#: canaille/forms.py:166
|
||||
msgid "Number"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:158
|
||||
#: canaille/forms.py:168
|
||||
msgid "1234"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:162
|
||||
#: canaille/forms.py:172
|
||||
msgid "Website"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:164
|
||||
#: canaille/forms.py:174
|
||||
msgid "https://mywebsite.tld"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:187
|
||||
#: canaille/forms.py:178
|
||||
msgid "Preferred language"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:201
|
||||
msgid "users, admins ..."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:203
|
||||
#: canaille/forms.py:217
|
||||
msgid "group"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:207 canaille/templates/groups.html:18
|
||||
#: canaille/forms.py:221 canaille/templates/groups.html:18
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/forms.py:218
|
||||
#: canaille/forms.py:232
|
||||
msgid "Username editable by the invitee"
|
||||
msgstr ""
|
||||
|
||||
|
@ -316,11 +324,11 @@ msgstr ""
|
|||
msgid "The group %(group)s has been sucessfully created"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/groups.py:92
|
||||
#: canaille/groups.py:93
|
||||
msgid "Group edition failed."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/groups.py:101
|
||||
#: canaille/groups.py:102
|
||||
#, python-format
|
||||
msgid "The group %(group)s has been sucessfully deleted"
|
||||
msgstr ""
|
||||
|
@ -413,11 +421,11 @@ msgstr ""
|
|||
msgid "The client has been created."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/clients.py:233
|
||||
#: canaille/oidc/clients.py:234
|
||||
msgid "The client has not been edited. Please check your information."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/clients.py:260
|
||||
#: canaille/oidc/clients.py:263
|
||||
msgid "The client has been edited."
|
||||
msgstr ""
|
||||
|
||||
|
@ -433,39 +441,39 @@ msgstr ""
|
|||
msgid "The access has been revoked"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/oauth.py:43
|
||||
#: canaille/oidc/endpoints.py:45
|
||||
msgid "Personnal information about yourself, such as your name or your gender."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/oauth.py:45
|
||||
#: canaille/oidc/endpoints.py:47
|
||||
msgid "Your email address."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/oauth.py:46
|
||||
#: canaille/oidc/endpoints.py:48
|
||||
msgid "Your postal address."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/oauth.py:47
|
||||
#: canaille/oidc/endpoints.py:49
|
||||
msgid "Your phone number."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/oauth.py:48
|
||||
#: canaille/oidc/endpoints.py:50
|
||||
msgid "Groups you are belonging to"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/oauth.py:136
|
||||
#: canaille/oidc/endpoints.py:140
|
||||
msgid "You have been successfully logged out."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/oauth.py:317
|
||||
#: canaille/oidc/endpoints.py:338
|
||||
msgid "You have been disconnected"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/oauth.py:325
|
||||
#: canaille/oidc/endpoints.py:346
|
||||
msgid "An error happened during the logout"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/oidc/oauth.py:337
|
||||
#: canaille/oidc/endpoints.py:358
|
||||
msgid "You have not been disconnected"
|
||||
msgstr ""
|
||||
|
||||
|
@ -553,14 +561,14 @@ msgstr ""
|
|||
msgid "Send the initialization email"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/fomanticui.html:64
|
||||
#: canaille/templates/fomanticui.html:68
|
||||
#: canaille/templates/oidc/admin/client_edit.html:35
|
||||
#: canaille/templates/oidc/admin/client_edit.html:44
|
||||
#: canaille/templates/oidc/admin/client_edit.html:53
|
||||
msgid "This field is not editable"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/fomanticui.html:68
|
||||
#: canaille/templates/fomanticui.html:72
|
||||
msgid "This field is required"
|
||||
msgstr ""
|
||||
|
||||
|
@ -581,7 +589,6 @@ msgid ""
|
|||
msgstr ""
|
||||
|
||||
#: canaille/templates/forgotten-password.html:38
|
||||
#: canaille/templates/profile.html:191 canaille/templates/profile.html:219
|
||||
msgid "Send again"
|
||||
msgstr ""
|
||||
|
||||
|
@ -643,7 +650,7 @@ msgstr ""
|
|||
msgid "Create group"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/group.html:82 canaille/templates/profile.html:259
|
||||
#: canaille/templates/group.html:82 canaille/templates/profile.html:254
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
|
@ -821,35 +828,35 @@ msgstr ""
|
|||
msgid "Click to upload a photo"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:146
|
||||
#: canaille/templates/profile.html:151
|
||||
msgid "Account information"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:171
|
||||
#: canaille/templates/profile.html:176
|
||||
msgid "User password is not mandatory"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:174
|
||||
#: canaille/templates/profile.html:179
|
||||
msgid "The user password can be set:"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:176
|
||||
#: canaille/templates/profile.html:181
|
||||
msgid "by filling this form;"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:177
|
||||
#: canaille/templates/profile.html:182
|
||||
msgid ""
|
||||
"by sending the user a password initialization mail, after the account "
|
||||
"creation;"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:178 canaille/templates/profile.html:207
|
||||
#: canaille/templates/profile.html:183 canaille/templates/profile.html:206
|
||||
msgid ""
|
||||
"or simply waiting for the user to sign-in a first time, and then receive "
|
||||
"a password initialization mail."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:181 canaille/templates/profile.html:210
|
||||
#: canaille/templates/profile.html:186 canaille/templates/profile.html:209
|
||||
msgid "The user will not be able to authenticate unless the password is set"
|
||||
msgstr ""
|
||||
|
||||
|
@ -857,51 +864,51 @@ msgstr ""
|
|||
msgid "Send email"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:200
|
||||
#: canaille/templates/profile.html:199
|
||||
msgid "This user does not have a password yet"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:203
|
||||
#: canaille/templates/profile.html:202
|
||||
msgid "You can solve this by:"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:205
|
||||
#: canaille/templates/profile.html:204
|
||||
msgid "setting a password using this form;"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:206
|
||||
#: canaille/templates/profile.html:205
|
||||
msgid "sending the user a password initialization mail, by clicking this button;"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:221
|
||||
#: canaille/templates/profile.html:217
|
||||
msgid "Send mail"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/mail/admin.html:56 canaille/templates/profile.html:225
|
||||
#: canaille/templates/mail/admin.html:56 canaille/templates/profile.html:220
|
||||
#: canaille/templates/reset-password.html:11
|
||||
#: canaille/templates/reset-password.html:16
|
||||
msgid "Password reset"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:227
|
||||
#: canaille/templates/profile.html:222
|
||||
msgid ""
|
||||
"If the user has forgotten his password, you can send him a password reset"
|
||||
" email by clicking this button."
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:239
|
||||
#: canaille/templates/profile.html:234
|
||||
msgid "Delete the user"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:241
|
||||
#: canaille/templates/profile.html:236
|
||||
msgid "Delete my account"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:248
|
||||
#: canaille/templates/profile.html:243
|
||||
msgid "Impersonate"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/profile.html:254 canaille/templates/users.html:20
|
||||
#: canaille/templates/profile.html:249 canaille/templates/users.html:20
|
||||
msgid "Invite a user"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1072,12 +1079,12 @@ msgstr ""
|
|||
msgid "Issued at"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/oidc/admin/client_edit.html:72
|
||||
msgid "Edit"
|
||||
#: canaille/templates/oidc/admin/client_edit.html:74
|
||||
msgid "Delete the client"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/oidc/admin/client_edit.html:75
|
||||
msgid "Delete the client"
|
||||
#: canaille/templates/oidc/admin/client_edit.html:77
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
#: canaille/templates/oidc/admin/client_list.html:17
|
||||
|
|
|
@ -132,7 +132,7 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
|
|||
[ACL.DEFAULT]
|
||||
PERMISSIONS = ["use_oidc"]
|
||||
READ = ["uid", "groups"]
|
||||
WRITE = ["jpegPhoto", "givenName", "sn", "userPassword", "telephoneNumber", "mail", "labeledURI"]
|
||||
WRITE = ["jpegPhoto", "givenName", "sn", "userPassword", "telephoneNumber", "mail", "labeledURI", "preferredLanguage"]
|
||||
|
||||
[ACL.ADMIN]
|
||||
FILTER = "memberof=cn=admins,ou=groups,dc=mydomain,dc=tld"
|
||||
|
|
|
@ -132,7 +132,7 @@ GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"
|
|||
[ACL.DEFAULT]
|
||||
PERMISSIONS = ["edit_self", "use_oidc"]
|
||||
READ = ["uid", "groups"]
|
||||
WRITE = ["jpegPhoto", "givenName", "sn", "userPassword", "telephoneNumber", "mail", "labeledURI", "postalAddress"]
|
||||
WRITE = ["jpegPhoto", "givenName", "sn", "userPassword", "telephoneNumber", "mail", "labeledURI", "postalAddress", "preferredLanguage"]
|
||||
|
||||
[ACL.ADMIN]
|
||||
FILTER = "memberof=cn=admins,ou=groups,dc=mydomain,dc=tld"
|
||||
|
|
27
poetry.lock
generated
27
poetry.lock
generated
|
@ -562,6 +562,17 @@ python-versions = "*"
|
|||
[package.dependencies]
|
||||
pyasn1 = ">=0.4.6,<0.5.0"
|
||||
|
||||
[[package]]
|
||||
name = "pycountry"
|
||||
version = "22.3.5"
|
||||
description = "ISO country, subdivision, language, currency and script definitions and their translations"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6, <4"
|
||||
|
||||
[package.dependencies]
|
||||
setuptools = "*"
|
||||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "2.21"
|
||||
|
@ -785,7 +796,7 @@ tornado = ["tornado (>=5)"]
|
|||
name = "setuptools"
|
||||
version = "65.5.1"
|
||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||
category = "dev"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
|
@ -1132,7 +1143,7 @@ sentry = ["sentry-sdk"]
|
|||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = ">=3.7, <4"
|
||||
content-hash = "ca4930693ac75ee10a32eb6eb7880b3f9a152fbbcaafe2e928e27f8334513146"
|
||||
content-hash = "f2c09fc960f35844fe14b819721ea49c5722c59d2c30946892a698db920917bb"
|
||||
|
||||
[metadata.files]
|
||||
aiosmtpd = [
|
||||
|
@ -1566,6 +1577,9 @@ pyasn1-modules = [
|
|||
{file = "pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"},
|
||||
{file = "pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"},
|
||||
]
|
||||
pycountry = [
|
||||
{file = "pycountry-22.3.5.tar.gz", hash = "sha256:b2163a246c585894d808f18783e19137cb70a0c18fb36748dc01fc6f109c1646"},
|
||||
]
|
||||
pycparser = [
|
||||
{file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
|
||||
{file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
|
||||
|
@ -1583,8 +1597,6 @@ pyquery = [
|
|||
{file = "pyquery-1.4.3.tar.gz", hash = "sha256:a388eefb6bc4a55350de0316fbd97cda999ae669b6743ae5b99102ba54f5aa72"},
|
||||
]
|
||||
pyreadline = [
|
||||
{file = "pyreadline-2.1.win-amd64.exe", hash = "sha256:9ce5fa65b8992dfa373bddc5b6e0864ead8f291c94fbfec05fbd5c836162e67b"},
|
||||
{file = "pyreadline-2.1.win32.exe", hash = "sha256:65540c21bfe14405a3a77e4c085ecfce88724743a4ead47c66b84defcf82c32e"},
|
||||
{file = "pyreadline-2.1.zip", hash = "sha256:4530592fc2e85b25b1a9f79664433da09237c1a270e4d78ea5aa3a2c7229e2d1"},
|
||||
]
|
||||
pyrepl = [
|
||||
|
@ -1629,6 +1641,13 @@ pyyaml = [
|
|||
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
|
||||
{file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
|
||||
{file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
|
||||
{file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
|
||||
{file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
|
||||
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
|
||||
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
|
||||
{file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
|
||||
{file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
|
||||
{file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
|
||||
{file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
|
||||
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
|
||||
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
|
||||
|
|
|
@ -52,6 +52,7 @@ wtforms = "<4"
|
|||
"sphinx" = {version = "*", optional=true}
|
||||
"sphinx-rtd-theme" = {version = "*", optional=true}
|
||||
"sphinx-issues" = {version = "*", optional=true}
|
||||
pycountry = "^22.3.5"
|
||||
|
||||
[tool.poetry.extras]
|
||||
sentry = ["sentry-sdk"]
|
||||
|
|
|
@ -171,6 +171,7 @@ def configuration(slapd_server, smtpd, keypair_path):
|
|||
"telephoneNumber",
|
||||
"postalAddress",
|
||||
"employeeNumber",
|
||||
"preferredLanguage",
|
||||
],
|
||||
},
|
||||
"ADMIN": {
|
||||
|
|
|
@ -39,6 +39,7 @@ def test_generate_user_standard_claims_with_default_config(
|
|||
testclient, slapd_connection, user
|
||||
):
|
||||
User.ldap_object_classes(slapd_connection)
|
||||
user.preferredLanguage = ["fr"]
|
||||
|
||||
data = generate_user_claims(user, STANDARD_CLAIMS, DEFAULT_JWT_MAPPING_CONFIG)
|
||||
|
||||
|
@ -47,6 +48,7 @@ def test_generate_user_standard_claims_with_default_config(
|
|||
"family_name": "Doe",
|
||||
"email": "john@doe.com",
|
||||
"sub": "user",
|
||||
"locale": "fr",
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
from flask import g
|
||||
|
||||
|
||||
def test_oauth_authorization_server(testclient):
|
||||
res = testclient.get("/.well-known/oauth-authorization-server", status=200).json
|
||||
assert "https://auth.mydomain.tld" == res["issuer"]
|
||||
assert res["ui_locales_supported"] == g.available_language_codes
|
||||
|
||||
|
||||
def test_openid_configuration(testclient):
|
||||
res = testclient.get("/.well-known/openid-configuration", status=200).json
|
||||
assert "https://auth.mydomain.tld" == res["issuer"]
|
||||
assert res["ui_locales_supported"] == g.available_language_codes
|
||||
|
|
45
tests/test_i18n.py
Normal file
45
tests/test_i18n.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
from canaille.models import User
|
||||
|
||||
|
||||
def test_preferred_language(testclient, logged_user):
|
||||
assert logged_user.preferredLanguage is None
|
||||
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
assert res.form["preferredLanguage"].value == "auto"
|
||||
assert "My profile" in res.text
|
||||
assert "Mon profil" not in res.text
|
||||
|
||||
res.form["preferredLanguage"] = "fr"
|
||||
res = res.form.submit(name="action", value="edit").follow()
|
||||
logged_user = User.get(dn=logged_user.dn)
|
||||
assert logged_user.preferredLanguage == "fr"
|
||||
assert res.form["preferredLanguage"].value == "fr"
|
||||
assert "My profile" not in res.text
|
||||
assert "Mon profil" in res.text
|
||||
|
||||
res.form["preferredLanguage"] = "en"
|
||||
res = res.form.submit(name="action", value="edit").follow()
|
||||
logged_user = User.get(dn=logged_user.dn)
|
||||
assert logged_user.preferredLanguage == "en"
|
||||
assert res.form["preferredLanguage"].value == "en"
|
||||
assert "My profile" in res.text
|
||||
assert "Mon profil" not in res.text
|
||||
|
||||
res.form["preferredLanguage"] = "auto"
|
||||
res = res.form.submit(name="action", value="edit").follow()
|
||||
logged_user = User.get(dn=logged_user.dn)
|
||||
assert logged_user.preferredLanguage is None
|
||||
assert res.form["preferredLanguage"].value == "auto"
|
||||
assert "My profile" in res.text
|
||||
assert "Mon profil" not in res.text
|
||||
|
||||
|
||||
def test_language_config(testclient, logged_user):
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
assert "My profile" in res.text
|
||||
assert "Mon profil" not in res.text
|
||||
|
||||
testclient.app.config["LANGUAGE"] = "fr"
|
||||
res = testclient.get("/profile/user", status=200)
|
||||
assert "My profile" not in res.text
|
||||
assert "Mon profil" in res.text
|
|
@ -50,6 +50,7 @@ def test_edition(
|
|||
"cn=foo,ou=groups,dc=mydomain,dc=tld",
|
||||
"cn=bar,ou=groups,dc=mydomain,dc=tld",
|
||||
]
|
||||
res.form["preferredLanguage"] = "fr"
|
||||
res.form["jpegPhoto"] = Upload("logo.jpg", jpeg_photo)
|
||||
res = res.form.submit(name="action", value="edit").follow()
|
||||
assert "Profile updated successfuly." in res, str(res)
|
||||
|
@ -63,6 +64,7 @@ def test_edition(
|
|||
assert ["email@mydomain.tld"] == logged_user.mail
|
||||
assert ["555-666-777"] == logged_user.telephoneNumber
|
||||
assert ["postal_address"] == logged_user.postalAddress
|
||||
assert "fr" == logged_user.preferredLanguage
|
||||
assert "666" == logged_user.employeeNumber
|
||||
assert [jpeg_photo] == logged_user.jpegPhoto
|
||||
|
||||
|
|
Loading…
Reference in a new issue