diff --git a/i18n/de-DE.json b/i18n/de-DE.json
new file mode 100644
index 0000000..619566d
--- /dev/null
+++ b/i18n/de-DE.json
@@ -0,0 +1,50 @@
+{
+ "html_language": "de",
+ "browser_language": "de-DE",
+ "ok": "ok",
+ "cancel": "abbrechen",
+ "dashboard": "dashboard",
+ "username": "benutzername",
+ "password": "passwort",
+ "login": "login",
+ "logout": "abmelden",
+ "comments": "kommentare",
+ "unpublished": "unveröffentlicht",
+ "published": "veröffentlicht",
+ "spam": "spam",
+ "edit": "editieren",
+ "manage": "verwalten",
+ "export": "export",
+ "delete": "löschen",
+ "new": "neu",
+ "project": "projekt",
+ "new_project": "neues projekt",
+ "statistics": "statistiken",
+ "address": "adresse",
+ "status": "status",
+ "manage_mail": "Mail Addressen verwalten",
+ "manage_comments": "Kommentare verwalten",
+ "manage_comments_delete_comment": "Diesen Kommentar löschen",
+ "manage_comments_delete_and_block": "Diesen Kommentar löschen und EMail Adresse blocken.",
+ "manage_comments_allow_comment": "Diesen Kommentar erlauben, aber Email Adresse nicht freischalten.",
+ "manage_comments_allow_and_approve": "Diesen Kommentar erlauben und Email Adresse freischalten.",
+ "manage_spam": "Spam verwalten",
+ "select_article": "Artikel auswählen",
+ "hooray_no_spam": "Hurra, kein Spam!",
+ "spam_score": "Spamerkennung",
+ "tooltip_spam_score": "Je höher der Spam Wert ist, desto höher die Chance, dass es sich um Spam handelt.",
+ "stats_label_regular_comments": "reguläre Kommentare",
+ "stats_label_unpublished_comments": "unveröffentlichte Kommentare",
+ "stats_last_7_days": "Aktivität der letzten 7 Tage",
+ "stats_total_percentage": "Verhältnis von Kommentaren zu Spam",
+ "select_project_to_manage": "Projekte:",
+ "tooltip_create_new_project": "Neues Projekt erzeugen",
+ "tooltip_delete_project": "Projekt und dazugehörige Daten löschen",
+ "tooltip_edit_project": "Einstellungen und Daten des Projekts ändern",
+ "tooltip_export_all_comments": "Alle Kommentare nach Hugo exportieren.
Wird normalerweise nicht benötigt.",
+ "tooltip_manage_this_project": "Dieses Projekt verwalten",
+ "placeholder_search_mail": "Mail Adressen durchsuchen",
+ "tooltip_email_blocked": "Email ist momentan gesperrt. Zum entsperren klicken.",
+ "tooltip_email_allowed": "Email darf momentan ohne Bestätigung posten. Zum Sperren klicken.",
+ "tooltip_delete_email": "Eintrag löschen. Email unterliegt wieder den normalen Regeln."
+}
diff --git a/i18n/en-US.json b/i18n/en-US.json
new file mode 100644
index 0000000..bceb0fe
--- /dev/null
+++ b/i18n/en-US.json
@@ -0,0 +1,49 @@
+{
+ "html_language": "en",
+ "browser_language": "en-US",
+ "ok": "ok",
+ "cancel": "cancel",
+ "dashboard": "dashboard",
+ "username": "username",
+ "password": "password",
+ "login": "login",
+ "logout": "logout",
+ "comments": "comments",
+ "unpublished": "unpublished",
+ "published": "published",
+ "spam": "spam",
+ "edit": "edit",
+ "manage": "manage",
+ "export": "export",
+ "delete": "delete",
+ "new": "new",
+ "project": "project",
+ "new_project": "new project",
+ "statistics": "statistics",
+ "address": "address",
+ "status": "status",
+ "manage_mail": "manage mail addresses",
+ "stats_label_regular_comments": "regular comments",
+ "stats_label_unpublished_comments": "unpublished comments",
+ "stats_last_7_days": "Activity last 7 days",
+ "stats_total_percentage": "Total comment - spam ratio",
+ "manage_comments": "manage comments",
+ "manage_comments_delete_comment": "Delete this comment",
+ "manage_comments_delete_and_block": "Delete this comment and block mail address",
+ "manage_comments_allow_comment": "Approve this comment, don't approve mail",
+ "manage_comments_allow_and_approve": "Approve this comment and approve mail",
+ "select_article": "Select article",
+ "select_project_to_manage": "Projects",
+ "hooray_no_spam": "Hooray, no Spam!",
+ "spam_score": "score",
+ "tooltip_spam_score": "The higher the spam score is, the more likely it is spam",
+ "tooltip_create_new_project": "Create a new project",
+ "tooltip_delete_project": "Delete the project and all of its content",
+ "tooltip_edit_project": "Edit the name of the project and it's properties",
+ "tooltip_export_all_comments": "Export all comments to Hugo.
This is normally not needed.",
+ "tooltip_manage_this_project": "Manage this project",
+ "placeholder_search_mail": "Search mail",
+ "tooltip_email_blocked": "Email is currently blocked. Click to unblock.",
+ "tooltip_email_allowed": "Email is currently excempt from spam detection. Click to block.",
+ "tooltip_delete_email": "Delete entry, Email has to follow the regular rules."
+}
diff --git a/labertasche/__init__.py b/labertasche/__init__.py
index 64d0aeb..af6d693 100644
--- a/labertasche/__init__.py
+++ b/labertasche/__init__.py
@@ -13,7 +13,8 @@ from labertasche import (
blueprints,
helper,
mail,
- settings
+ settings,
+ language
)
_all_ = [
@@ -22,5 +23,6 @@ _all_ = [
blueprints,
helper,
mail,
- settings
+ settings,
+ language
]
diff --git a/labertasche/language/__init__.py b/labertasche/language/__init__.py
new file mode 100644
index 0000000..379c629
--- /dev/null
+++ b/labertasche/language/__init__.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# /**********************************************************************************
+# * _author : Domeniko Gentner
+# * _mail : code@tuxstash.de
+# * _repo : https://git.tuxstash.de/gothseidank/labertasche
+# * _license : This project is under MIT License
+# *********************************************************************************/
+from flask import Request
+from pathlib import Path
+from json import load
+
+
+class Language:
+
+ def __init__(self, request: Request):
+ # Define data
+ self.i18n = dict()
+ self.languages = list()
+
+ # Directory where translations live
+ i18n_dir = Path('./i18n').absolute()
+
+ # Looks for translations
+ for filename in i18n_dir.glob("*.json"):
+ if filename.is_file():
+ self.languages.append(filename.stem)
+
+ # Check the browser language in the headers
+ self.browser_language = request.accept_languages.best_match(self.languages, default="en-US")
+
+ # Try to Load language accepted by browser
+ try:
+ file = i18n_dir / self.browser_language
+ with file.with_suffix(".json").absolute().open('r', encoding='utf-8') as fp:
+ foreign = load(fp)
+ except FileNotFoundError:
+ pass
+
+ # Always load english
+ file = i18n_dir / "en-US"
+ with file.with_suffix(".json").absolute().open('r', encoding='utf-8') as fp:
+ self.i18n = load(fp)
+
+ # Merge dicts, so missing keys are replaced with English
+ self.i18n.update(**foreign)
+
diff --git a/server.py b/server.py
index de90ce4..4bcf344 100644
--- a/server.py
+++ b/server.py
@@ -9,11 +9,12 @@
# noinspection PyProtectedMember
from sqlalchemy.engine import Engine
from logging import getLogger, ERROR as LOGGING_ERROR
-from flask import Flask, redirect, url_for
+from flask import Flask, redirect, url_for, request
from flask_cors import CORS
from sqlalchemy import event, inspect
from labertasche.settings import Settings, Secret
from labertasche.database import labertasche_db
+from labertasche.language import Language
from labertasche.blueprints import bp_comments, bp_login, bp_dashboard, bp_jsconnector, bp_dbupgrades
from labertasche.helper import User
from flask_login import LoginManager
@@ -36,15 +37,13 @@ laberflask.config.update(dict(
SECRET_KEY=secret.key,
TEMPLATES_AUTO_RELOAD=settings.debug,
SQLALCHEMY_DATABASE_URI=settings.database_uri,
- SQLALCHEMY_TRACK_MODIFICATIONS=False
+ SQLALCHEMY_TRACK_MODIFICATIONS=False,
+ JSON_AS_ASCII=False
))
# Mark secret for deletion
del secret
-# CORS
-cors = CORS(laberflask)
-
# Import blueprints
laberflask.register_blueprint(bp_comments)
laberflask.register_blueprint(bp_dashboard)
@@ -70,6 +69,10 @@ with laberflask.app_context():
labertasche_db.create_all()
+# CORS
+cors = CORS(laberflask)
+
+
# There is only one user
@loginmgr.user_loader
def user_loader(user_id):
@@ -92,3 +95,10 @@ def set_sqlite_pragma(dbapi_connection, connection_record):
cursor = dbapi_connection.cursor()
cursor.execute("PRAGMA journal_mode=WAL;")
cursor.close()
+
+
+# Inject i18n dictionaries into all templates
+@laberflask.context_processor
+def inject_language():
+ lang = Language(request)
+ return {"i18n": lang.i18n}
diff --git a/templates/base.html b/templates/base.html
index 303804a..63e9f68 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -1,5 +1,5 @@
-
+
Labertasche Login
+Labertasche {{ i18n['login'] | capitalize }}