From aa06ddd3cf1de03922fc4e45e46ef3476a69e3f8 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 11 Oct 2020 16:15:15 +0200 Subject: add i18n and new menu structure to donations page --- talermerchantdemos/donations/donations.py | 115 +++++++++++++++++---- talermerchantdemos/donations/templates/base.html | 55 ---------- .../donations/templates/base.html.j2 | 115 +++++++++++++++++++++ .../donations/templates/checkout.html | 59 ----------- .../donations/templates/checkout.html.j2 | 46 +++++++++ talermerchantdemos/donations/templates/error.html | 22 ---- .../donations/templates/error.html.j2 | 24 +++++ .../donations/templates/fulfillment.html | 11 -- .../donations/templates/fulfillment.html.j2 | 22 ++++ talermerchantdemos/donations/templates/index.html | 42 -------- .../donations/templates/index.html.j2 | 44 ++++++++ .../templates/provider-not-supported.html | 6 -- .../templates/provider-not-supported.html.j2 | 6 ++ talermerchantdemos/survey/survey.py | 11 -- 14 files changed, 352 insertions(+), 226 deletions(-) delete mode 100644 talermerchantdemos/donations/templates/base.html create mode 100644 talermerchantdemos/donations/templates/base.html.j2 delete mode 100644 talermerchantdemos/donations/templates/checkout.html create mode 100644 talermerchantdemos/donations/templates/checkout.html.j2 delete mode 100644 talermerchantdemos/donations/templates/error.html create mode 100644 talermerchantdemos/donations/templates/error.html.j2 delete mode 100644 talermerchantdemos/donations/templates/fulfillment.html create mode 100644 talermerchantdemos/donations/templates/fulfillment.html.j2 delete mode 100644 talermerchantdemos/donations/templates/index.html create mode 100644 talermerchantdemos/donations/templates/index.html.j2 delete mode 100644 talermerchantdemos/donations/templates/provider-not-supported.html create mode 100644 talermerchantdemos/donations/templates/provider-not-supported.html.j2 (limited to 'talermerchantdemos') diff --git a/talermerchantdemos/donations/donations.py b/talermerchantdemos/donations/donations.py index 3f021f9..19fc235 100644 --- a/talermerchantdemos/donations/donations.py +++ b/talermerchantdemos/donations/donations.py @@ -1,6 +1,6 @@ ## # This file is part of GNU TALER. -# Copyright (C) 2014-2016 INRIA +# Copyright (C) 2014-2016, 2020 Taler Systems SA # # TALER is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software @@ -20,13 +20,18 @@ import base64 import logging import flask +from flask import request +from flask_babel import Babel +from flask_babel import refresh +from flask_babel import force_locale +from flask_babel import gettext import os import time import traceback import urllib from taler.util.talerconfig import TalerConfig, ConfigurationError from urllib.parse import urljoin -from ..httpcommon import backend_post, backend_get, fallback_404 +from ..httpcommon import backend_post, backend_get, fallback_404, self_localized import sys if not sys.version_info.major == 3 and sys.version_info.minor >= 6: @@ -52,6 +57,28 @@ except ConfigurationError as ce: exit(1) app.config.from_object(__name__) +babel = Babel(app) + + +LOGGER.info("Using translations from:" + ':'.join(list(babel.translation_directories))) +translations = [str(translation) for translation in babel.list_translations()] +if not 'en' in translations: + translations.append('en') +LOGGER.info("Operating with the following translations available: " + ' '.join(translations)) + +app.jinja_env.globals.update(self_localized=self_localized) + + +@babel.localeselector +def get_locale(): + parts = request.path.split('/', 2) + if (2 >= len(parts)): + # Totally unexpected path format, do not localize + return "en" + lang = parts[1] + if lang in translations: + return lang + return "en" ## @@ -73,7 +100,10 @@ def utility_processor(): # @param abort_status_code status code to return along the response. # @param params _kw_ arguments to passed verbatim to the templating engine. def err_abort(abort_status_code, **params): - t = flask.render_template("templates/error.html", **params) + t = flask.render_template( + "templates/error.html.j2", + lang=get_locale(), + **params) flask.abort(flask.make_response(t, abort_status_code)) @@ -110,7 +140,7 @@ def backend_instanced_post(instance, endpoint, json): def expect_parameter(name): val = flask.request.args.get(name) if not val: - return err_abort(400, message="parameter '{}' required".format(name)) + return err_abort(400, message=gettext("parameter '{}' required").format(name)) return val @@ -123,17 +153,47 @@ def expect_parameter(name): @app.errorhandler(Exception) def internal_error(e): return flask.render_template( - "templates/error.html", message="Internal error", stack=traceback.format_exc() + "templates/error.html.j2", + message=gettext("Internal error"), + lang=get_locale(), + stack=traceback.format_exc() ) +## +# Serve the /favicon.ico requests. +# +# @return the favicon.ico file. +@app.route("/favicon.ico") +def favicon(): + LOGGER.info("will look into: " + os.path.join(app.root_path, 'static')) + return flask.send_from_directory( + os.path.join(app.root_path, 'static'), + "favicon.ico", + mimetype="image/vnd.microsoft.ico" + ) ## -# Serve the main index page. +# Serve the main index page, redirecting to // # # @return response object of the index page. @app.route("/") def index(): - return flask.render_template("templates/index.html", merchant_currency=CURRENCY) + default = 'en' + target = flask.request.accept_languages.best_match(translations, default) + return flask.redirect("/" + target + "/", code=302) + + +## +# Serve the main index page. +# +# @return response object of the index page. +@app.route("//") +def start(lang): + return flask.render_template( + "templates/index.html.j2", + lang=lang, + merchant_currency=CURRENCY + ) ## @@ -151,16 +211,17 @@ def javascript_licensing(): # and finally confirm the donation. # # @return response object for the /checkout page. -@app.route("/checkout", methods=["GET"]) -def checkout(): +@app.route("//checkout", methods=["GET"]) +def checkout(lang): amount = expect_parameter("donation_amount") donation_receiver = expect_parameter("donation_receiver") donation_donor = expect_parameter("donation_donor") return flask.render_template( - "templates/checkout.html", + "templates/checkout.html.j2", donation_amount=amount, donation_receiver=donation_receiver, donation_donor=donation_donor, + lang=lang, merchant_currency=CURRENCY, ) @@ -170,9 +231,12 @@ def checkout(): # of further processing the payment method they chose. # # @return response object about the mentioned impossibility. -@app.route("/provider-not-supported") +@app.route("//provider-not-supported") def provider_not_supported(): - return flask.render_template("templates/provider-not-supported.html") + return flask.render_template( + "templates/provider-not-supported.html.j2", + lang=lang + ) ## @@ -182,17 +246,19 @@ def provider_not_supported(): # @return response object that will redirect the browser to # the fulfillment URL, where all the pay-logic will # happen. -@app.route("/donate") -def donate(): +@app.route("//donate") +def donate(lang): donation_receiver = expect_parameter("donation_receiver") donation_amount = expect_parameter("donation_amount") donation_donor = expect_parameter("donation_donor") payment_system = expect_parameter("payment_system") if payment_system != "taler": - return flask.redirect(flask.url_for("provider_not_supported")) + return flask.redirect(flask.url_for("provider_not_supported", + lang=lang)) fulfillment_url = flask.url_for( "fulfillment", timestamp=str(time.time()), + lang=lang, receiver=donation_receiver, _external=True, ) @@ -200,7 +266,9 @@ def donate(): order = dict( amount=donation_amount, extra=dict( - donor=donation_donor, receiver=donation_receiver, amount=donation_amount + donor=donation_donor, + receiver=donation_receiver, + amount=donation_amount ), fulfillment_url=fulfillment_url, summary="Donation to {}".format(donation_receiver), @@ -211,7 +279,10 @@ def donate(): ) order_id = order_resp["order_id"] return flask.redirect( - flask.url_for("fulfillment", receiver=donation_receiver, order_id=order_id) + flask.url_for("fulfillment", + receiver=donation_receiver, + lang=lang, + order_id=order_id) ) @@ -223,8 +294,8 @@ def donate(): # @return after the wallet sent the payment, the final HTML "congrats" # page is returned; otherwise, the browser will be redirected # to a page that accepts the payment. -@app.route("/donation/") -def fulfillment(receiver): +@app.route("//donation/") +def fulfillment(lang,receiver): order_id = expect_parameter("order_id") pay_params = dict(order_id=order_id) pay_status = backend_instanced_get( @@ -239,6 +310,7 @@ def fulfillment(receiver): donation_amount=extra["amount"], donation_donor=extra["donor"], order_id=order_id, + lang=lang, currency=CURRENCY, ) return flask.redirect(pay_status["order_status_url"]) @@ -246,4 +318,7 @@ def fulfillment(receiver): @app.errorhandler(404) def handler(e): return flask.render_template( - "templates/error.html", message="Page not found") + "templates/error.html.j2", + lang=get_locale(), + message=gettext("Page not found") + ) diff --git a/talermerchantdemos/donations/templates/base.html b/talermerchantdemos/donations/templates/base.html deleted file mode 100644 index 7456dca..0000000 --- a/talermerchantdemos/donations/templates/base.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - Taler Donation Demo - - - - {% block styles %}{% endblock %} - {% block scripts %}{% endblock %} - - - -
-

Taler Demo

-

Donations

-

This is the donation page, you can make donations (with an imaginary currency for now) to free software projects.

- -

You can learn more about Taler on our main website.

-
- -
- {% block main %} - This is the main content of the page. - {% endblock %} -
- -
- - diff --git a/talermerchantdemos/donations/templates/base.html.j2 b/talermerchantdemos/donations/templates/base.html.j2 new file mode 100644 index 0000000..b67658b --- /dev/null +++ b/talermerchantdemos/donations/templates/base.html.j2 @@ -0,0 +1,115 @@ + + + + + + {{ gettext("Taler Donation Demo") }} + + + + + + {% block styles %}{% endblock %} + {% block scripts %}{% endblock %} + + + +
+

{{ gettext("Taler Demo") }}

+

{{gettext("Donations")}}

+

{{ + gettext ("This is the donation page.") + "
" + + gettext ("Using this page you can make donations (in an imaginary currency) to Free Software projects.") + }} +

+
+ + + +
+ {% block main %} + This is the main content of the page. + {% endblock %} +
+
+

{{ gettext('You can learn more about Taler on our main website.').format(site="https://taler.net/") }}

+
+

Copyright © 2014—2020 Taler Systems SA

+
+
+ + diff --git a/talermerchantdemos/donations/templates/checkout.html b/talermerchantdemos/donations/templates/checkout.html deleted file mode 100644 index 5c3e116..0000000 --- a/talermerchantdemos/donations/templates/checkout.html +++ /dev/null @@ -1,59 +0,0 @@ -{% extends "templates/base.html" %} - -{% block main %} -
-

Select your payment method

- -

- This is an example for a "checkout" page of a Web shop. - On the previous page, you have created the shopping cart - and decided which product to buy (i.e. which project to - donate KUDOS to). Now in this page, you are asked to - select a payment option. As Taler is not yet universally - used, we expect merchants will offer various payment options. -

-

- The page also demonstrates how to only enable (or show) the Taler - option if Taler is actually supported by the browser. For example, - if you disable the Taler extension now, the Taler payment option - will be disabled in the page. Naturally, you could also trivially - hide the Taler option entirely by changing the visibility instead. -

-

- Note that you MUST select Taler here for the demo to continue, - as the other payment options are just placeholders and not - really working in the demonstration. Also, it is of course - possible to ask the user to make this choice already on the - previous page (with the shopping cart), we just separated the - two steps to keep each step as simple as possible. -

- -
-

- - - - - -
-
- -
- -{% endblock main %} diff --git a/talermerchantdemos/donations/templates/checkout.html.j2 b/talermerchantdemos/donations/templates/checkout.html.j2 new file mode 100644 index 0000000..5251fdf --- /dev/null +++ b/talermerchantdemos/donations/templates/checkout.html.j2 @@ -0,0 +1,46 @@ +{% extends "templates/base.html.j2" %} + +{% block main %} +
+

{{ gettext("Select your payment method") }}

+ +

+ {{ + gettext('This is an example for a "checkout" page of a Web shop. On the previous page, you have created the shopping cart and decided which product to buy (i.e. which project to donate KUDOS to). Now in this page, you are asked to select a payment option. As Taler is not yet universally used, we expect merchants will offer various payment options.') + }} +

+

+ {{ + gettext('Note that you MUST select Taler here for the demo to continue, as the other payment options are just placeholders and not really working in the demonstration. Also, it is of course possible to ask the user to make this choice already on the previous page (with the shopping cart), we just separated the two steps to keep each step as simple as possible.') + }} +

+ +
+

+ + + + + +
+
+ +
+ +{% endblock main %} diff --git a/talermerchantdemos/donations/templates/error.html b/talermerchantdemos/donations/templates/error.html deleted file mode 100644 index 0d4bd02..0000000 --- a/talermerchantdemos/donations/templates/error.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "templates/base.html" %} -{% block main %} -

An Error Occurred

- -

{{ message }}

- - {% if status_code %} -

The backend returned status code {{ status_code }}.

- {% endif %} - - {% if json %} -

Backend Response:

-
{{ json }}
- {% endif %} - - {% if stack %} -

Stack trace:

-
-    {{ stack }}
-  
- {% endif %} -{% endblock main %} diff --git a/talermerchantdemos/donations/templates/error.html.j2 b/talermerchantdemos/donations/templates/error.html.j2 new file mode 100644 index 0000000..ffc2e1f --- /dev/null +++ b/talermerchantdemos/donations/templates/error.html.j2 @@ -0,0 +1,24 @@ +{% extends "templates/base.html.j2" %} +{% block main %} +

{{ gettext("Error encountered") }}

+ +

{{ message }}

+ + {% if status_code %} +

+ {{ gettext ("The backend returned status code {code}.").format(code=status_code) }}. +

+ {% endif %} + + {% if json %} +

{{gettext("Backend response:")}}

+
{{ json }}
+ {% endif %} + + {% if stack %} +

{{gettext("Stack trace:")}}

+
+    {{ stack }}
+  
+ {% endif %} +{% endblock main %} diff --git a/talermerchantdemos/donations/templates/fulfillment.html b/talermerchantdemos/donations/templates/fulfillment.html deleted file mode 100644 index 17d8cd8..0000000 --- a/talermerchantdemos/donations/templates/fulfillment.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "templates/base.html" %} - -{% block main %} -

Donation Receipt

-

Thank you, {{ donation_donor }}, for donating {{ donation_amount }} to {{ donation_receiver }}.

- -

Please keep the order identifier {{ order_id }} as a receipt for your donation. You can show other people that you donated -by sharing this link with them.

- -

You can always make another donation

-{% endblock main %} diff --git a/talermerchantdemos/donations/templates/fulfillment.html.j2 b/talermerchantdemos/donations/templates/fulfillment.html.j2 new file mode 100644 index 0000000..df9f30b --- /dev/null +++ b/talermerchantdemos/donations/templates/fulfillment.html.j2 @@ -0,0 +1,22 @@ +{% extends "templates/base.html.j2" %} + +{% block main %} +

{{ gettext("Donation Receipt") }}

+

+ {{ + gettext("Thank you, {donor}, for donating {amount} to {receiver}.").format(donor=donation_donor,amount=donation_amount,receiver=donation_receiver) + }} +

+

+ {{ + gettext("Please keep the order identifier {id} as a receipt for your donation.").format(id=order_id) + + gettext('You can show other people that you donated by sharing this link with them.').format(link=request.url) + }} +

+ +

+ {{ + gettext('You can always make another donation.').format(link=url_for('index')) + }} +

+{% endblock main %} diff --git a/talermerchantdemos/donations/templates/index.html b/talermerchantdemos/donations/templates/index.html deleted file mode 100644 index cbb3c35..0000000 --- a/talermerchantdemos/donations/templates/index.html +++ /dev/null @@ -1,42 +0,0 @@ -{% extends "templates/base.html" %} - -{% block main %} -

Welcome to the Taler Donation "Shop" Demo

- -

This toy donations website shows the user experience for donations with Taler. -You are paying with an imaginary currency ({{ merchant_currency }}). -

- -
-

Please select a project, the amount (*) of {{ merchant_currency }} you - wish to donate, and enter the name that will appear on your receipt:

- -
-
- - - - -
-
-

- (*) To make it a bit more fun, the 5 {{ merchant_currency }} option is - deliberately implemented with a fault: the merchant will try to make you - donate 6 {{ merchant_currency }} instead of the 5 {{ merchant_currency }} you - got to see. But do not worry, you will be given the opportunity to review - the final offer from the merchant in a window secured by the Taler - extension. That way, you can spot the error before committing to an - incorrect contract. -

-
- -{% endblock %} diff --git a/talermerchantdemos/donations/templates/index.html.j2 b/talermerchantdemos/donations/templates/index.html.j2 new file mode 100644 index 0000000..91122f3 --- /dev/null +++ b/talermerchantdemos/donations/templates/index.html.j2 @@ -0,0 +1,44 @@ +{% extends "templates/base.html.j2" %} + +{% block main %} +

{{ gettext("Taler donation demonstrator") }}

+ +

+{{ + gettext("This donations website shows the user experience for donations with Taler.") + "
" + + gettext("You can make donations in an toy currency ({currency})").format(currency=merchant_currency) +}} +

+ +
+

+ {{ + gettext("Please select a project, the amount (*) of {currency} you wish to donate, and enter the name that will appear on your receipt:").format(currency=merchant_currency) + }} +

+ +
+
+ + + + +
+
+

+ {{ + gettext("(*) To make it a bit more fun, the 5 {currency} option is deliberately implemented with a fault: the merchant will try to make you donate 6 {currency} instead of the 5 {currency} shown in the form. But do not worry, you will be given the opportunity to review the final offer from the merchant in a window secured by the Taler extension. That way, you can spot the error before committing to an incorrect contract or amount.").format(currency=merchant_currency) + }} +

+
+ +{% endblock %} diff --git a/talermerchantdemos/donations/templates/provider-not-supported.html b/talermerchantdemos/donations/templates/provider-not-supported.html deleted file mode 100644 index 88f2000..0000000 --- a/talermerchantdemos/donations/templates/provider-not-supported.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "templates/base.html" %} - -{% block main %} -

Payment Provider Not Supported

-

Unfortunately the selected payment provider is not supported in this demo. Please go back and select "Taler".

-{% endblock main %} diff --git a/talermerchantdemos/donations/templates/provider-not-supported.html.j2 b/talermerchantdemos/donations/templates/provider-not-supported.html.j2 new file mode 100644 index 0000000..88f2000 --- /dev/null +++ b/talermerchantdemos/donations/templates/provider-not-supported.html.j2 @@ -0,0 +1,6 @@ +{% extends "templates/base.html" %} + +{% block main %} +

Payment Provider Not Supported

+

Unfortunately the selected payment provider is not supported in this demo. Please go back and select "Taler".

+{% endblock main %} diff --git a/talermerchantdemos/survey/survey.py b/talermerchantdemos/survey/survey.py index 38065f1..871b417 100644 --- a/talermerchantdemos/survey/survey.py +++ b/talermerchantdemos/survey/survey.py @@ -125,17 +125,6 @@ def favicon(): mimetype="image/vnd.microsoft.ico" ) -## -# Return a error response to the client. -# -# @param abort_status_code status code to return along the response. -# @param params _kw_ arguments to passed verbatim to the templating engine. -def err_abort(abort_status_code, **params): - t = flask.render_template( - "templates/error.html.j2", - lang=get_locale(), - **params) - flask.abort(flask.make_response(t, abort_status_code)) ## # Tell the backend to 'authorize' a tip; this means that -- cgit v1.2.3