diff --git a/.gitignore b/.gitignore index 5b87262..d426daf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ -.venv/ +*.mo *.pyc +.venv/ config.json diff --git a/README.md b/README.md index e17a58d..8f78445 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,26 @@ Licenced under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/). See [LICENCE](LICENCE) file for full licence text. +## Development + +All instructions assume you have the requirements already installed. + +## Adding translations + +Replace `` with your intended language. + +1. run `pybabel init -i messages.pot -d translations -l ` +2. edit `translations//LC_MESSAGES/messages.po` +3. For testing, run `pybabel compile -d translations` + +If you changed the translation strings, make sure to run `pybabel extract -F babel.cfg -o messages.pot .` and +`pybabel update -i messages.pot -d translations` first. + ## Setting it up +After deploying the repository, change to `ldap_frontend` directory, then +run `pybabel compile -d translations`. + ### config.json ```json { diff --git a/ldap_frontend/__init__.py b/ldap_frontend/__init__.py index f92cc63..8bfffeb 100644 --- a/ldap_frontend/__init__.py +++ b/ldap_frontend/__init__.py @@ -2,7 +2,8 @@ from json import load from os import environ from flask import Flask, flash, redirect, request, session, url_for -from flask_wtf.csrf import CSRFProtect, CSRFError +from flask_babel import Babel, gettext +from flask_wtf.csrf import CSRFError, CSRFProtect from ldap3 import ALL_ATTRIBUTES, MODIFY_ADD, MODIFY_DELETE from ldap3.core.exceptions import LDAPException from ldap3.utils.dn import escape_rdn @@ -19,16 +20,25 @@ from .helpers.ldap import ( app = Flask(__name__) app.secret_key = environ.get("FLASK_SECRET_KEY", default="test") +app.config["LANGUAGES"] = {"en": "English", "de": "Deutsch"} + +babel = Babel(app) csrf = CSRFProtect(app) with open(environ["APP_CONFIG"]) as f: APP_CONFIG = load(f) +@babel.localeselector +def get_locale(): + return request.accept_languages.best_match(app.config["LANGUAGES"].keys()) + @app.errorhandler(CSRFError) def handle_csrf_error(e): - flash("CRSF validation error. For your own safety, you have been logged out.") + flash( + gettext("CRSF validation error. For your own safety, you have been logged out.") + ) session["is_logged_in"] = False session["username"] = "" @@ -39,7 +49,7 @@ def handle_csrf_error(e): @app.route("/") def slash(): - if session.get('is_logged_in'): + if session.get("is_logged_in"): return redirect(url_for("selfservice")) return redirect(url_for("login")) @@ -57,11 +67,11 @@ def login(): session["username"] = escape_rdn(request.form["username"]) session["password"] = request.form["password"] - flash("logged in") + flash(gettext("logged in")) return redirect(url_for("selfservice")) else: - flash("username or password is wrong") + flash(gettext("username or password is wrong")) return template(None, "login.html") @@ -72,7 +82,7 @@ def logout(): session["username"] = "" session["password"] = "" - flash("logged out") + flash(gettext("you have been logged out")) return redirect(url_for("login")) @@ -96,7 +106,7 @@ def selfservice(ldap): "mail": request.form["mail"], }, ) - flash("data updated") + flash(gettext("user data was updated")) except LDAPException as e: app.logger.error( "Updating {} failed: {}\n{}".format( @@ -113,15 +123,15 @@ def selfservice(ldap): request.form["current"], ): validated = False - flash("current password does not match") + flash(gettext("current password does not match the one stored")) if request.form["new"] != request.form["repeat"]: validated = False - flash("new passwords do not match") + flash(gettext("new passwords do not match")) if len(request.form["new"]) < 12: validated = False - flash("new password must be atleast 12 characters") + flash(gettext("new password must be atleast 12 characters long")) if validated: try: @@ -131,7 +141,7 @@ def selfservice(ldap): request.form["new"], ) session["password"] = request.form["new"] - flash("password changed") + flash(gettext("your password was changed")) except LDAPException as e: app.logger.error( "Updating {} failed: {}".format( @@ -184,7 +194,13 @@ def group_edit(ldap, ou): ] }, ) - flash(f"{request.form['remove']} was removed from {ou}") + flash( + gettext( + "%(user)s was removed from %(ou)s", + user=request.form["remove"], + ou=ou, + ) + ) elif request.form.get("add"): ldap.modify( APP_CONFIG["template"]["group_dn"].format(ou), @@ -199,7 +215,11 @@ def group_edit(ldap, ou): ] }, ) - flash(f"{request.form['add']} was added to {ou}") + flash( + gettext( + "%(user)s was added to %(ou)s", user=request.form["remove"], ou=ou + ) + ) return redirect(url_for("group_edit", ou=ou)) diff --git a/ldap_frontend/babel.cfg b/ldap_frontend/babel.cfg new file mode 100644 index 0000000..f0234b3 --- /dev/null +++ b/ldap_frontend/babel.cfg @@ -0,0 +1,3 @@ +[python: **.py] +[jinja2: **/templates/**.html] +extensions=jinja2.ext.autoescape,jinja2.ext.with_ diff --git a/ldap_frontend/messages.pot b/ldap_frontend/messages.pot new file mode 100644 index 0000000..1afe15e --- /dev/null +++ b/ldap_frontend/messages.pot @@ -0,0 +1,199 @@ +# Translations template for PROJECT. +# Copyright (C) 2021 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2021. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2021-12-23 09:11+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.9.1\n" + +#: __init__.py:40 +msgid "CRSF validation error. For your own safety, you have been logged out." +msgstr "" + +#: __init__.py:69 +msgid "logged in" +msgstr "" + +#: __init__.py:73 +msgid "username or password is wrong" +msgstr "" + +#: __init__.py:84 +msgid "you have been logged out" +msgstr "" + +#: __init__.py:108 +msgid "user data was updated" +msgstr "" + +#: __init__.py:125 +msgid "current password does not match the one stored" +msgstr "" + +#: __init__.py:129 +msgid "new passwords do not match" +msgstr "" + +#: __init__.py:133 +msgid "new password must be atleast 12 characters long" +msgstr "" + +#: __init__.py:143 +msgid "your password was changed" +msgstr "" + +#: __init__.py:196 +#, python-format +msgid "%(user)s was removed from %(ou)s" +msgstr "" + +#: __init__.py:211 +#, python-format +msgid "%(user)s was added to %(ou)s" +msgstr "" + +#: templates/login.html:2 templates/login.html:7 templates/login.html:19 +msgid "Login" +msgstr "" + +#: templates/login.html:10 +msgid "Username" +msgstr "" + +#: templates/login.html:15 +msgid "Password" +msgstr "" + +#: templates/layout/default.html:23 templates/selfservice.html:2 +msgid "self service" +msgstr "" + +#: templates/selfservice.html:7 +msgid "Edit User Data" +msgstr "" + +#: templates/groups/members.html:7 templates/selfservice.html:10 +msgid "uid" +msgstr "" + +#: templates/selfservice.html:13 +msgid "Contact an administrator if you want to change this." +msgstr "" + +#: templates/selfservice.html:18 +msgid "name" +msgstr "" + +#: templates/selfservice.html:21 +msgid "This field gets adjusted automatically based on the fields below." +msgstr "" + +#: templates/selfservice.html:26 +msgid "surname" +msgstr "" + +#: templates/selfservice.html:33 +msgid "given name" +msgstr "" + +#: templates/selfservice.html:40 +msgid "e-mail address" +msgstr "" + +#: templates/selfservice.html:46 +msgid "Update" +msgstr "" + +#: templates/selfservice.html:53 templates/selfservice.html:77 +msgid "change password" +msgstr "" + +#: templates/selfservice.html:56 +msgid "current password" +msgstr "" + +#: templates/selfservice.html:63 +msgid "new password" +msgstr "" + +#: templates/selfservice.html:66 +msgid "Your new password must be atleast 12 characters long." +msgstr "" + +#: templates/selfservice.html:71 +msgid "repeat new password" +msgstr "" + +#: templates/groups/list.html:2 +msgid "group list" +msgstr "" + +#: templates/groups/list.html:7 +msgid "group name" +msgstr "" + +#: templates/groups/list.html:8 +msgid "group description" +msgstr "" + +#: templates/groups/list.html:9 +msgid "member?" +msgstr "" + +#: templates/groups/list.html:10 +msgid "member count" +msgstr "" + +#: templates/groups/members.html:2 +#, python-format +msgid "group %(ou)s" +msgstr "" + +#: templates/groups/members.html:8 +msgid "cn" +msgstr "" + +#: templates/groups/members.html:9 +msgid "remove member" +msgstr "" + +#: templates/groups/members.html:21 +msgid "remove" +msgstr "" + +#: templates/groups/members.html:31 templates/groups/members.html:45 +msgid "add user to group" +msgstr "" + +#: templates/groups/members.html:37 +msgid "select user" +msgstr "" + +#: templates/layout/default.html:26 +msgid "groups" +msgstr "" + +#: templates/layout/default.html:30 +msgid "Other Sites" +msgstr "" + +#: templates/layout/default.html:39 +#, python-format +msgid "Signed in as %(uid)s" +msgstr "" + +#: templates/layout/default.html:39 +msgid "logout" +msgstr "" + diff --git a/ldap_frontend/templates/groups/list.html b/ldap_frontend/templates/groups/list.html index 4a7c37a..ceff05b 100644 --- a/ldap_frontend/templates/groups/list.html +++ b/ldap_frontend/templates/groups/list.html @@ -1,13 +1,13 @@ {% extends "layout/default.html" %} -{% block title %}groups{% endblock %} +{% block title %}{% trans %}group list{% endtrans %}{% endblock %} {% block content %} - - - - + + + + diff --git a/ldap_frontend/templates/groups/members.html b/ldap_frontend/templates/groups/members.html index 44b92b5..e9c589a 100644 --- a/ldap_frontend/templates/groups/members.html +++ b/ldap_frontend/templates/groups/members.html @@ -1,12 +1,12 @@ {% extends "layout/default.html" %} -{% block title %}group {{ ou }}{% endblock %} +{% block title %}{% trans ou=ou %}group {{ ou }}{% endtrans %}{% endblock %} {% block content %}
group namegroup descriptionmember?member count{% trans %}group name{% endtrans %}{% trans %}group description{% endtrans %}{% trans %}member?{% endtrans %}{% trans %}member count{% endtrans %}
- - - + + + @@ -18,7 +18,7 @@ - + @@ -28,13 +28,13 @@
- add user to group + {% trans %}add user to group{% endtrans %}

+
{% endblock %} diff --git a/ldap_frontend/templates/layout/default.html b/ldap_frontend/templates/layout/default.html index 9b2b3e8..61934c1 100644 --- a/ldap_frontend/templates/layout/default.html +++ b/ldap_frontend/templates/layout/default.html @@ -20,16 +20,14 @@ diff --git a/ldap_frontend/templates/login.html b/ldap_frontend/templates/login.html index e8eadaa..85fb0bb 100644 --- a/ldap_frontend/templates/login.html +++ b/ldap_frontend/templates/login.html @@ -1,21 +1,22 @@ {% extends "layout/default.html" %} +{% block title %}{% trans %}Login{% endtrans %}{% endblock %} {% block content %}
- Login + {% trans %}Login{% endtrans %}
- +
- +
- +
{% endblock %} diff --git a/ldap_frontend/templates/selfservice.html b/ldap_frontend/templates/selfservice.html index 9126d3e..c7d243a 100644 --- a/ldap_frontend/templates/selfservice.html +++ b/ldap_frontend/templates/selfservice.html @@ -1,79 +1,80 @@ {% extends "layout/default.html" %} -{% block title %}self service{% endblock %} +{% block title %}{% trans %}self service{% endtrans %}{% endblock %} {% block content %}
- user data + {% trans %}Edit User Data{% endtrans %}
- +
-
contact an administrator if you want to change this
+
{% trans %}Contact an administrator if you want to change this.{% endtrans %}
- +
-
gets adjusted automatically
+
{% trans %}This field gets adjusted automatically based on the fields below.{% endtrans %}
- +
- +
- +
-
+
- password + {% trans %}change password{% endtrans %}
- +
- +
- + +
{% trans %}Your new password must be atleast 12 characters long.{% endtrans %}
- +
-
+
{% endblock %} diff --git a/ldap_frontend/translations/de/LC_MESSAGES/messages.po b/ldap_frontend/translations/de/LC_MESSAGES/messages.po new file mode 100644 index 0000000..946bcaa --- /dev/null +++ b/ldap_frontend/translations/de/LC_MESSAGES/messages.po @@ -0,0 +1,200 @@ +# German translations for qzwi-ldap-frontend. +# Copyright (C) 2021 Franziska Kunsmann +# +msgid "" +msgstr "" +"Project-Id-Version: qzwi-ldap-frontend\n" +"Report-Msgid-Bugs-To: qzwi@kunsmann.eu\n" +"POT-Creation-Date: 2021-12-23 09:11+0100\n" +"PO-Revision-Date: 2021-12-23 08:41+0100\n" +"Last-Translator: Franziska Kunsmann \n" +"Language: de\n" +"Language-Team: de \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.9.1\n" + +#: __init__.py:40 +msgid "CRSF validation error. For your own safety, you have been logged out." +msgstr "" +"Formularvalidierung fehlgeschlagen. Zu deiner Sicherheit wurdest du " +"abgemeldet." + +#: __init__.py:69 +msgid "logged in" +msgstr "Erfolgreich angemeldet" + +#: __init__.py:73 +msgid "username or password is wrong" +msgstr "Der eingegebene Benutzername existiert nicht oder das Passwort ist falsch." + +#: __init__.py:84 +msgid "you have been logged out" +msgstr "Du wurdest abgemeldet." + +#: __init__.py:108 +msgid "user data was updated" +msgstr "Die Benutzerdaten wurden geändert." + +#: __init__.py:125 +msgid "current password does not match the one stored" +msgstr "Das eingegebene Passwort stimmt nicht mit dem bisherigen überein." + +#: __init__.py:129 +msgid "new passwords do not match" +msgstr "Das neue Passwort stimmt nicht mit der Wiederholung überein." + +#: __init__.py:133 +msgid "new password must be atleast 12 characters long" +msgstr "Dein neues Passwort muss mindestens 12 Zeichen lang sein." + +#: __init__.py:143 +msgid "your password was changed" +msgstr "Dein Passwort wurde geändert." + +#: __init__.py:196 +#, python-format +msgid "%(user)s was removed from %(ou)s" +msgstr "%(user)s wurde aus %(ou)s entfernt." + +#: __init__.py:211 +#, python-format +msgid "%(user)s was added to %(ou)s" +msgstr "%(user)s wurde zu %(ou)s hinzugefügt." + +#: templates/login.html:2 templates/login.html:7 templates/login.html:19 +msgid "Login" +msgstr "Anmelden" + +#: templates/login.html:10 +msgid "Username" +msgstr "Benutzername" + +#: templates/login.html:15 +msgid "Password" +msgstr "Passwort" + +#: templates/layout/default.html:23 templates/selfservice.html:2 +msgid "self service" +msgstr "Daten ändern" + +#: templates/selfservice.html:7 +msgid "Edit User Data" +msgstr "Benutzer*innen-Daten ändern" + +#: templates/groups/members.html:7 templates/selfservice.html:10 +msgid "uid" +msgstr "Login-Name" + +#: templates/selfservice.html:13 +msgid "Contact an administrator if you want to change this." +msgstr "Kontaktiere einen Administrator, wenn du diesen Wert ändern möchtest." + +#: templates/selfservice.html:18 +msgid "name" +msgstr "Name" + +#: templates/selfservice.html:21 +msgid "This field gets adjusted automatically based on the fields below." +msgstr "Dieser Wert wird automatisch basierend auf den Feldern darunter geändert." + +#: templates/selfservice.html:26 +msgid "surname" +msgstr "Nachname" + +#: templates/selfservice.html:33 +msgid "given name" +msgstr "Vorname" + +#: templates/selfservice.html:40 +msgid "e-mail address" +msgstr "E-Mail-Adresse" + +#: templates/selfservice.html:46 +msgid "Update" +msgstr "Daten ändern" + +#: templates/selfservice.html:53 templates/selfservice.html:77 +msgid "change password" +msgstr "Passwort ändern" + +#: templates/selfservice.html:56 +msgid "current password" +msgstr "Aktuelles Passwort" + +#: templates/selfservice.html:63 +msgid "new password" +msgstr "Neues Passwort" + +#: templates/selfservice.html:66 +msgid "Your new password must be atleast 12 characters long." +msgstr "Dein neues Passwort muss mindestens 12 Zeichen lang sein." + +#: templates/selfservice.html:71 +msgid "repeat new password" +msgstr "Neues Passwort (Wiederholung)" + +#: templates/groups/list.html:2 +msgid "group list" +msgstr "Gruppen-Übersicht" + +#: templates/groups/list.html:7 +msgid "group name" +msgstr "Gruppen-Name" + +#: templates/groups/list.html:8 +msgid "group description" +msgstr "Gruppen-Beschreibung" + +#: templates/groups/list.html:9 +msgid "member?" +msgstr "Mitglied?" + +#: templates/groups/list.html:10 +msgid "member count" +msgstr "Anzahl der Mitglieder" + +#: templates/groups/members.html:2 +#, python-format +msgid "group %(ou)s" +msgstr "Gruppe %(ou)s" + +#: templates/groups/members.html:8 +msgid "cn" +msgstr "Name" + +#: templates/groups/members.html:9 +msgid "remove member" +msgstr "Mitglied entfernen" + +#: templates/groups/members.html:21 +msgid "remove" +msgstr "Entfernen" + +#: templates/groups/members.html:31 templates/groups/members.html:45 +msgid "add user to group" +msgstr "Mitglied zur Gruppe hinzufügen" + +#: templates/groups/members.html:37 +msgid "select user" +msgstr "Benutzer auswählen" + +#: templates/layout/default.html:26 +msgid "groups" +msgstr "Gruppen" + +#: templates/layout/default.html:30 +msgid "Other Sites" +msgstr "Links" + +#: templates/layout/default.html:39 +#, python-format +msgid "Signed in as %(uid)s" +msgstr "Angemeldet als %(uid)s\n" + +#: templates/layout/default.html:39 +msgid "logout" +msgstr "Abmelden" + diff --git a/requirements.txt b/requirements.txt index ef0be59..6691931 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,7 @@ +Babel==2.9.1 click==8.0.3 Flask==2.0.2 +Flask-Babel==2.0.0 Flask-WTF==1.0.0 gunicorn==20.1.0 itsdangerous==2.0.1 @@ -7,5 +9,6 @@ Jinja2==3.0.3 ldap3==2.9.1 MarkupSafe==2.0.1 pyasn1==0.4.8 +pytz==2021.3 Werkzeug==2.0.2 WTForms==3.0.0
uidcnremove{% trans %}uid{% endtrans %}{% trans %}cn{% endtrans %}{% trans %}remove member{% endtrans %}