Changeset - 4005eddcc559
[Not reviewed]
i18n
0 4 1
Dennis Fink - 3 years ago 2022-01-16 21:46:21
dennis.fink@c3l.lu
Add Flask-Babel

This allows us to to i18n an l10n of the membership form.
5 files changed with 81 insertions and 4 deletions:
0 comments (0 inline, 0 general)
babel.cfg
Show inline comments
 
new file 100644
 
[python: **.py]
 
[jinja2: **/templates/**.html]
 
extensions=jinja2.ext.autoescape,jinja2.ext.with_
c3l_membership/__init__.py
Show inline comments
 
import base64
 
import json
 
import os.path
 
import secrets
 

	
 
from flask import Flask
 
from flask import Flask, g, redirect, request, url_for
 
from flask_babel import Babel
 
from flask_qrcode import QRcode
 

	
 
config_file = os.path.abspath("/etc/membership.json")
 

	
 
qrcode = QRcode()
 
babel = Babel()
 

	
 

	
 
def create_app():
 

	
 
    app = Flask(__name__)
 

	
 
    try:
 
        app.config.from_file(config_file, load=json.load)
 
    except FileNotFoundError:
 
        pass
 

	
 
    qrcode.init_app(app)
 
    babel.init_app(app)
 

	
 
    _default_secret_key = base64.b64encode(secrets.token_bytes()).decode("utf-8")
 
    app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY", _default_secret_key)
 
    app.config["LANGUAGES"] = ["en", "de", "fr", "lb"]
 

	
 
    app.config.setdefault("SUPPORTING_FEE", 40)
 
    app.config.setdefault("REGULAR_FEE", 120)
 

	
 
    app.config.setdefault("DIGICASH_ENABLED", True)
 
    app.config.setdefault("BITCOIN_ENABLED", True)
 
    app.config.setdefault("ETHEREUM_ENABLED", True)
 
    app.config.setdefault("MONERO_ENABLED", True)
 
    app.config.setdefault("ZCASH_ENABLED", True)
 

	
 
    app.config.setdefault(
 
        "BITCOIN_CONVERSION_SCRIPT", "/usr/local/share/btc/BTC_Membership.pl"
 
    )
 
    app.config.setdefault(
 
        "ETHEREUM_CONVERSION_SCRIPT", "/usr/local/share/eth/ETH_Membership.pl"
 
    )
 
    app.config.setdefault(
 
        "MONERO_CONVERSION_SCRIPT", "/usr/local/share/xmr/XMR_Membership.pl"
 
    )
 
    app.config.setdefault(
 
        "ZCASH_CONVERSION_SCRIPT", "/usr/local/share/zcash/ZCASH_Membership.pl"
 
    )
 

	
 
    @babel.localeselector
 
    def get_locale():
 
        if not g.get("lang_code", None):
 
            g.lang_code = request.accept_languages.best_match(app.config["LANGUAGES"])
 
        return g.lang_code
 

	
 
    from .views import root_page
 

	
 
    app.register_blueprint(root_page)
 

	
 
    @app.route("/")
 
    def home():
 
        g.lang_code = request.accept_languages.best_match(app.config["LANGUAGES"])
 
        return redirect(url_for("root.index"))
 

	
 
    return app
 

	
 

	
 
app = create_app()
c3l_membership/views.py
Show inline comments
 
import re
 
import subprocess
 
from datetime import date
 

	
 
from flask import Blueprint, current_app, render_template, request
 
from flask import Blueprint, current_app, g, render_template, request
 
from flask_weasyprint import HTML, render_pdf
 

	
 
from .forms import MembershipForm
 

	
 
root_page = Blueprint("root", __name__)
 
root_page = Blueprint("root", __name__, url_prefix="/<lang_code>")
 

	
 
xml_template = "<member><numm>{name}</numm><gebuertsdag>{birthday:%d.%m.%Y}</gebuertsdag><address>{address}</address><nick>{username}</nick><email>{email}</email><status>{status}</status><stemmrecht>{voting}</stemmrecht></member>"
 

	
 

	
 
@root_page.url_defaults
 
def add_lang_code(endpoint, values):
 
    values.setdefault("lang_code", g.lang_code)
 

	
 

	
 
@root_page.url_value_preprocessor
 
def pull_lang_code(endpoint, values):
 
    g.lang_code = values.pop("lang_code")
 

	
 

	
 
@root_page.route("/", methods=("GET", "POST"))
 
def index():
 
    form = MembershipForm()
 

	
 
    choices = [("cash", "by cash"), ("wire transfer", "by wire transfer")]
 

	
 
    for k, v in (
 
        ("DIGICASH_ENABLED", ("digicash", "by DigiCash")),
 
        ("BITCOIN_ENABLED", ("bitcoin", "by bitcoin")),
 
        ("ETHEREUM_ENABLED", ("ethereum", "by ethereum")),
 
        ("MONERO_ENABLED", ("monero", "by monero")),
 
        ("ZCASH_ENABLED", ("zcash", "by zcash")),
poetry.lock
Show inline comments
 
[[package]]
 
name = "babel"
 
version = "2.9.1"
 
description = "Internationalization utilities"
 
category = "main"
 
optional = false
 
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 

	
 
[package.dependencies]
 
pytz = ">=2015.7"
 

	
 
[[package]]
 
name = "black"
 
version = "21.12b0"
 
description = "The uncompromising code formatter."
 
category = "dev"
 
optional = false
 
python-versions = ">=3.6.2"
 

	
 
[package.dependencies]
 
click = ">=7.1.2"
 
mypy-extensions = ">=0.4.3"
 
pathspec = ">=0.9.0,<1"
 
@@ -163,24 +174,41 @@ python-versions = ">=3.6"
 

	
 
[package.dependencies]
 
click = ">=7.1.2"
 
itsdangerous = ">=2.0"
 
Jinja2 = ">=3.0"
 
Werkzeug = ">=2.0"
 

	
 
[package.extras]
 
async = ["asgiref (>=3.2)"]
 
dotenv = ["python-dotenv"]
 

	
 
[[package]]
 
name = "flask-babel"
 
version = "2.0.0"
 
description = "Adds i18n/l10n support to Flask applications"
 
category = "main"
 
optional = false
 
python-versions = "*"
 

	
 
[package.dependencies]
 
Babel = ">=2.3"
 
Flask = "*"
 
Jinja2 = ">=2.5"
 
pytz = "*"
 

	
 
[package.extras]
 
dev = ["pytest", "pytest-mock", "bumpversion", "ghp-import", "sphinx", "pallets-sphinx-themes"]
 

	
 
[[package]]
 
name = "flask-qrcode"
 
version = "3.0.0"
 
description = "A concise Flask extension to render QR codes on Jinja2 templates using python-qrcode"
 
category = "main"
 
optional = false
 
python-versions = "*"
 

	
 
[package.dependencies]
 
Flask = "*"
 
pillow = "*"
 
qrcode = "*"
 

	
 
@@ -365,24 +393,32 @@ python-versions = ">=2.7, !=3.0.*, !=3.1
 
name = "pyphen"
 
version = "0.12.0"
 
description = "Pure Python module to hyphenate text"
 
category = "main"
 
optional = false
 
python-versions = ">=3.7"
 

	
 
[package.extras]
 
doc = ["sphinx", "sphinx-rtd-theme"]
 
test = ["pytest", "pytest-cov", "pytest-flake8", "pytest-isort", "coverage"]
 

	
 
[[package]]
 
name = "pytz"
 
version = "2021.3"
 
description = "World timezone definitions, modern and historical"
 
category = "main"
 
optional = false
 
python-versions = "*"
 

	
 
[[package]]
 
name = "qrcode"
 
version = "7.3.1"
 
description = "QR Code image generator"
 
category = "main"
 
optional = false
 
python-versions = ">=3.6"
 

	
 
[package.dependencies]
 
colorama = {version = "*", markers = "platform_system == \"Windows\""}
 

	
 
[package.extras]
 
all = ["zest.releaser", "tox", "pytest", "pytest", "pytest-cov", "pillow"]
 
@@ -499,27 +535,31 @@ version = "3.6.0"
 
description = "Backport of pathlib-compatible object wrapper for zip files"
 
category = "main"
 
optional = false
 
python-versions = ">=3.6"
 

	
 
[package.extras]
 
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
 
testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
 

	
 
[metadata]
 
lock-version = "1.1"
 
python-versions = ">=3.7.0,<4"
 
content-hash = "71f2f5db862ef41b627c0a05e0c0b4ceaf7aa1316f8cd13232df304a470dacf4"
 
content-hash = "e6337b7e5ae01abe852dbd202497fef50c09546e0a0f98f26b3ee81beb262237"
 

	
 
[metadata.files]
 
babel = [
 
    {file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"},
 
    {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"},
 
]
 
black = [
 
    {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"},
 
    {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"},
 
]
 
cairocffi = [
 
    {file = "cairocffi-1.3.0.tar.gz", hash = "sha256:108a3a7cb09e203bdd8501d9baad91d786d204561bd71e9364e8b34897c47b91"},
 
]
 
cairosvg = [
 
    {file = "CairoSVG-2.5.2-py3-none-any.whl", hash = "sha256:98c276b7e4f0caf01e5c7176765c104ffa1aa1461d63b2053b04ab663cf7052b"},
 
    {file = "CairoSVG-2.5.2.tar.gz", hash = "sha256:b0b9929cf5dba005178d746a8036fcf0025550f498ca54db61873322384783bc"},
 
]
 
cffi = [
 
@@ -596,24 +636,28 @@ djhtml = [
 
dnspython = [
 
    {file = "dnspython-2.1.0-py3-none-any.whl", hash = "sha256:95d12f6ef0317118d2a1a6fc49aac65ffec7eb8087474158f42f26a639135216"},
 
    {file = "dnspython-2.1.0.zip", hash = "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4"},
 
]
 
email-validator = [
 
    {file = "email_validator-1.1.3-py2.py3-none-any.whl", hash = "sha256:5675c8ceb7106a37e40e2698a57c056756bf3f272cfa8682a4f87ebd95d8440b"},
 
    {file = "email_validator-1.1.3.tar.gz", hash = "sha256:aa237a65f6f4da067119b7df3f13e89c25c051327b2b5b66dc075f33d62480d7"},
 
]
 
flask = [
 
    {file = "Flask-2.0.2-py3-none-any.whl", hash = "sha256:cb90f62f1d8e4dc4621f52106613488b5ba826b2e1e10a33eac92f723093ab6a"},
 
    {file = "Flask-2.0.2.tar.gz", hash = "sha256:7b2fb8e934ddd50731893bdcdb00fc8c0315916f9fcd50d22c7cc1a95ab634e2"},
 
]
 
flask-babel = [
 
    {file = "Flask-Babel-2.0.0.tar.gz", hash = "sha256:f9faf45cdb2e1a32ea2ec14403587d4295108f35017a7821a2b1acb8cfd9257d"},
 
    {file = "Flask_Babel-2.0.0-py3-none-any.whl", hash = "sha256:e6820a052a8d344e178cdd36dd4bb8aea09b4bda3d5f9fa9f008df2c7f2f5468"},
 
]
 
flask-qrcode = [
 
    {file = "Flask-QRcode-3.0.0.tar.gz", hash = "sha256:96a49da1396a600e79cc4b119610a2e61cb1433f9449994eabf36bbe1478b96b"},
 
]
 
flask-weasyprint = [
 
    {file = "Flask-WeasyPrint-0.6.tar.gz", hash = "sha256:ceb48d15dca49d6f32be60a19fb6d6a43f0668978ac8af4240292b85630652b1"},
 
    {file = "Flask_WeasyPrint-0.6-py2.py3-none-any.whl", hash = "sha256:688424cd47e1b06915feeb295c4a03df667222865676c3029ed52a6be5622caf"},
 
]
 
flask-wtf = [
 
    {file = "Flask-WTF-1.0.0.tar.gz", hash = "sha256:872fbb17b5888bfc734edbdcf45bc08fb365ca39f69d25dc752465a455517b28"},
 
    {file = "Flask_WTF-1.0.0-py3-none-any.whl", hash = "sha256:01feccfc395405cea48a3f36c23f0d766e2cc6fd2a5a065ad50ad3e5827ec797"},
 
]
 
html5lib = [
 
@@ -787,24 +831,28 @@ pillow = [
 
platformdirs = [
 
    {file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"},
 
    {file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"},
 
]
 
pycparser = [
 
    {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
 
    {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
 
]
 
pyphen = [
 
    {file = "pyphen-0.12.0-py3-none-any.whl", hash = "sha256:459020cd320eb200c0c5ba46b98b2278fd34c5546f520fdcd2ce5f8d733eb994"},
 
    {file = "pyphen-0.12.0.tar.gz", hash = "sha256:b7d3dfc24b6f2178cdb2b1757ace0bd5d222de3e62c28d22ac578c5f22a13e9b"},
 
]
 
pytz = [
 
    {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"},
 
    {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"},
 
]
 
qrcode = [
 
    {file = "qrcode-7.3.1.tar.gz", hash = "sha256:375a6ff240ca9bd41adc070428b5dfc1dcfbb0f2507f1ac848f6cded38956578"},
 
]
 
six = [
 
    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
 
    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
 
]
 
tinycss2 = [
 
    {file = "tinycss2-1.1.1-py3-none-any.whl", hash = "sha256:fe794ceaadfe3cf3e686b22155d0da5780dd0e273471a51846d0a02bc204fec8"},
 
    {file = "tinycss2-1.1.1.tar.gz", hash = "sha256:b2e44dd8883c360c35dd0d1b5aad0b610e5156c2cb3b33434634e539ead9d8bf"},
 
]
 
tomli = [
pyproject.toml
Show inline comments
 
@@ -7,22 +7,23 @@ license = "GPL-3.0-or-later"
 
include = ["c3l_membership/static/*", "c3l_membership/template/*"]
 

	
 
[tool.poetry.dependencies]
 
python = ">=3.7.0,<4"
 
Flask = "^2.0.2"
 
Flask-QRcode = "^3.0.0"
 
Flask-WeasyPrint = "^0.6"
 
Flask-WTF = "^1.0.0"
 
email-validator = "^1.1.3"
 
WTForms="^3.0.1"
 
WeasyPrint="52.5"
 
djhtml = "^1.4.11"
 
Flask-Babel = "^2.0.0"
 

	
 
[tool.poetry.dev-dependencies]
 
black = "^21.12b0"
 
mypy = "^0.930"
 
isort = "^5.10.1"
 

	
 

	
 
[build-system]
 
requires = ["poetry-core>=1.0.0"]
 
build-backend = "poetry.core.masonry.api"
0 comments (0 inline, 0 general)