gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-taler-merchant-demos] 18/18: merge torsten-redesign branch, imple


From: gnunet
Subject: [taler-taler-merchant-demos] 18/18: merge torsten-redesign branch, implement i18n support
Date: Sat, 10 Oct 2020 22:55:52 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository taler-merchant-demos.

commit 2e665813a44988bfd906c0fab773f82652047841
Merge: ad45c1d 58af977
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sat Oct 10 22:55:31 2020 +0200

    merge torsten-redesign branch, implement i18n support

 .gitignore                                         |   3 +-
 Makefile                                           |  41 +++++-
 README.md                                          |  33 ++++-
 setup.py                                           |   1 +
 talermerchantdemos/.gitignore                      |   6 +
 talermerchantdemos/.vscode/launch.json             |  15 +++
 talermerchantdemos/blog/articles/scrap1_11.html    |   1 -
 talermerchantdemos/blog/blog.py                    | 139 ++++++++++++++++-----
 talermerchantdemos/blog/content.py                 |  13 +-
 .../blog/templates/article_frame.html              |  13 --
 .../blog/templates/article_frame.html.j2           |  15 +++
 .../blog/templates/article_refunded.html           |  10 --
 .../blog/templates/article_refunded.html.j2        |  16 +++
 talermerchantdemos/blog/templates/base.html        |  79 ------------
 talermerchantdemos/blog/templates/base.html.j2     | 119 ++++++++++++++++++
 .../blog/templates/confirm_refund.html             |  19 ---
 .../blog/templates/confirm_refund.html.j2          |  22 ++++
 talermerchantdemos/blog/templates/error.html       |  22 ----
 talermerchantdemos/blog/templates/error.html.j2    |  24 ++++
 talermerchantdemos/blog/templates/index.html       |  40 ------
 talermerchantdemos/blog/templates/show_refund.html |  28 -----
 talermerchantdemos/static/__init__.py              |   1 +
 talermerchantdemos/static/{demo.css => demo.scss}  |  27 ++--
 talermerchantdemos/static/navbar.css               |  75 +++++++++++
 talermerchantdemos/static/navbar.css.map           |   1 +
 talermerchantdemos/static/navbar.scss              | 103 +++++++++++++++
 talermerchantdemos/static/{pure.css => pure.scss}  |   2 +-
 .../{taler-fallback.css => taler-fallback.scss}    |   0
 28 files changed, 606 insertions(+), 262 deletions(-)

diff --cc .gitignore
index bee8a64,8e95770..92ed544
--- a/.gitignore
+++ b/.gitignore
@@@ -1,1 -1,3 +1,2 @@@
- __pycache__
+ talermerchantdemos/static/*.css
 -
+ talermerchantdemos/static/navbar.css.map
diff --cc Makefile
index d40e2f4,eefac0d..0cea1c3
--- a/Makefile
+++ b/Makefile
@@@ -38,3 -38,27 +38,42 @@@ dist
  .PHONY: pretty
  pretty:
        yapf -r -i talerblog/
+ 
++# i18n
++extract:
++#     Note: Flask-BabelEx expects 'translations/' for the dirname,
++#       even though GNU gettext typically uses 'locale/'
++      mkdir -p translations/
++      pybabel extract -F babel.cfg -o translations/messages.pot .
++#     Add new language as follows:
++#     pybabel init -i locale/messages.pot -d locale/ -l de
++
++compile:
++      pybabel compile -d translations/
++
++update: extract
++      pybabel update -i translations/messages.pot -d translations/
++
+ # SASS/SCSS
+ 
+ sass-setup:
+       @echo "This is the initial sass-installation/setup script."
+       @echo "This setup must run as root, on a machine that has NPM 
installed!"
+       @echo "If your password is requested (for escalation), please enter it."
+       sudo npm install -g sass
+ 
+ scss-setup: sass-setup
+ 
+ sass-build:
+       @echo "Warning: If Sass/Scss is not installed, please run \`make 
sass-setup\` first!"
+       @echo "This script will only convert files inside /static"
+       sass talermerchantdemos/static:talermerchantdemos/static
+ 
+ scss-build: sass-build
+ 
+ sass-autobuild:
+       @echo "Warning: If Sass/Scss is not installed, please run \`make 
sass-setup\` first!"
+       @echo "This script will automatically build sass/scss files in the 
static directory!"
+       sass --watch talermerchantdemos/static:talermerchantdemos/static
+ 
+ scss-autobuild: sass-autobuild
diff --cc README.md
index 953ec69,d221946..c9f3e7f
--- a/README.md
+++ b/README.md
@@@ -6,9 -10,9 +10,9 @@@ Step 1: `cd` into the directory:<br/
  > ```$ cd taler-merchant-demos```
  
  <br/>
--Step 2: Ensure Python3.5 or above is installed using a command like:<br/>
++Step 2: Ensure Python 3.5 or above and Flask with the Babel extension are 
installed using a command like:<br/>
  
--> ```$ sudo apt install python3.8 -y```
++> ```$ sudo apt install python3.8 python3-flask-babel -y```
  
  <br/>
  Step 3: Ensure Python3 Pip is installed:<br/>
@@@ -16,7 -20,7 +20,7 @@@
  > ```$ sudo apt install python3-pip -y```
  
  <br/>
--Step 4: configure it using:<br/>
++Step 4: configure this package using:<br/>
  
  > ```$ ./configure --destination=local```
  
@@@ -27,14 -31,24 +31,28 @@@ Step 5: Install UWSGI<br
  
  <br/>
  Step 6: Install LXML
- *NOTE: DO NOT INSTALL USING PIP2 (on my system, that is what the pip command 
uses) - INSTALL IT USING PIP3*
+ *NOTE: DO NOT INSTALL USING PIP2 (on my system, that is what the pip command 
uses) - INSTALL IT USING PIP3*<br>
  
  > ```$ pip3 install lxml```
+ 
+ <br/>
+ 
+ Step 7: Install NPM<br>
+ 
+ > ```$ sudo apt install npm; sudo npm install -g npm node```
+ 
  <br>
  
+ Step 8: Install scss<br>
+ > ```$ make sass-install```
+ 
++This will the NPM implementation of sass. If you have a Ruby
++tool called 'sass' installed, this build will NOT work.
++
++
  ## Quick Install for the dependencies
  Here's one command to automatically install all dependencies at once:
- > ```$ sudo apt install python3.8 python3-pip -y; pip3 install lxml uwsgi; 
./configure --destination=local```
+ > ```$ sudo apt install python3.8 python3-pip npm -y; pip3 install lxml 
uwsgi; ./configure --destination=local; sudo npm install -g npm node;make 
sass-install```
  
  ## Configuring the demo
  *This is just how I did it, and not the main method of doing it*
@@@ -72,40 -84,11 +90,45 @@@ Step 3: Configure the config
  To apply changes, use
  > ```$ make install```
  
+ <br>
+ 
+ To apply ***SCSS*** changes, use
+ > ```$ make scss-build```
+ 
  ## Running the program
  To start the server, use the following command:<br>
 -> ```$ taler-merchant-demos --serve-http blog```
 +> ```$ taler-merchant-demos blog```
 +
 +## More configuration options.
 +This makes the blog speak UWSGI over TCP:
 +> ```
 +> [frontends]
 +> backend_apikey = "ApiKey Sandbox"
 +> backend = https://backend.test.taler.net/
 +>
 +> [taler]
 +> currency = TESTKUDOS
 +>
 +> [blog]
 +> serve = uwsgi
 +> uwsgi_serve = tcp
 +> uwsgi_port = XZY
 +
 +> ```
 +<br>
 +
 +This makes the blog speak UWSGI over unix domain socket:
 +> ```
 +> [frontends]
 +> backend_apikey = "ApiKey Sandbox"
 +> backend = https://backend.test.taler.net/
 +>
 +> [taler]
 +> currency = TESTKUDOS
 +>
 +> [blog]
 +> serve = uwsgi
 +> uwsgi_serve = unix
 +> uwsgi_unixpath = "/tmp/blog.uwsgi"
 +> uwsgi_unixpath_mode = XZY
 +> ```
diff --cc setup.py
index deeba73,deeba73..af37dc7
--- a/setup.py
+++ b/setup.py
@@@ -20,6 -20,6 +20,7 @@@ setup(name='talermerchantdemos'
                "static/*.svg",
                # Blog files
                "blog/templates/*.html",
++              "blog/templates/*.j2",
                "blog/articles/*",
                "blog/data/*",
                # Donation files
diff --cc talermerchantdemos/blog/blog.py
index d6cd3fc,865605b..c8315e5
--- a/talermerchantdemos/blog/blog.py
+++ b/talermerchantdemos/blog/blog.py
@@@ -1,6 -1,6 +1,6 @@@
  ##
--# This file is part of GNU taler.
--# Copyright (C) 2014-2017 INRIA
++# This file is part of GNU Taler.
++# Copyright (C) 2014-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
@@@ -24,6 -24,6 +24,11 @@@ import tracebac
  import uuid
  import base64
  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 time
  import sys
  from urllib.parse import urljoin, urlencode, urlparse
@@@ -85,6 -54,6 +90,34 @@@ ARTICLE_AMOUNT = CURRENCY + ":0.5
  BACKEND_URL = urljoin(BACKEND_BASE_URL, "instances/blog/")
  
  app.config.from_object(__name__)
++babel = Babel(app)
++
++print("Using translations from:")
++print(list(babel.translation_directories))
++translations = [str(translation) for translation in babel.list_translations()]
++translations.append('en')
++print("Operating with the following translations available:")
++print(translations)
++
++
++##
++# Helper function used inside Jinja2 logic to create a links
++# to the current page but in a different language. Used to
++# implement the "Language" menu.
++#
++def self_localized(lang):
++    """
++    Return URL for the current page in another locale.
++    """
++    path = request.path
++    # path must have the form "/$LANG/$STUFF"
++    parts = path.split('/', 2)
++    if (2 >= len(parts)):
++        # Totally unexpected path format, do not localize
++        return path
++    return "/" + lang + "/" + parts[2]
++
++app.jinja_env.globals.update(self_localized=self_localized)
  
  
  ##
@@@ -107,7 -76,7 +140,7 @@@ 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", **params)
      flask.abort(flask.make_response(t, abort_status_code))
  
  
@@@ -120,7 -89,7 +153,7 @@@
  @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"), 
stack=traceback.format_exc()
      )
  
  
@@@ -130,8 -99,19 +163,29 @@@
  # @return response object of the index page.
  @app.route("/")
  def index():
 -    supported = ['en', 'de' ]
+     default = 'en'
 -    target = flask.request.accept_languages.best_match(supported, default)
++    target = flask.request.accept_languages.best_match(translations, default)
+     return flask.redirect("/" + target + "/", code=302)
+ 
++@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"
++
+ ##
+ # Serve the main index page for a particular language.
+ #
+ # @return response object of the index page.
+ @app.route("/<lang>/")
+ def start(lang):
      return flask.render_template(
-         "templates/index.html", merchant_currency=CURRENCY, 
articles=ARTICLES.values()
 -        "templates/index.html", lang=lang, merchant_currency=CURRENCY, 
articles=ARTICLES.values()
++        "templates/index.html.j2", lang=lang, merchant_currency=CURRENCY, 
articles=ARTICLES.values()
      )
  
  
@@@ -144,16 -124,11 +198,16 @@@ def confirm_refund(lang, order_id)
      order_status = pay_status.get("order_status")
      if order_status != "paid":
          err_abort(
-             400, message="can't refund unpaid article",
+             400, message="Cannot refund unpaid article",
          )
      article_name = pay_status["contract_terms"]["extra"]["article_name"]
 +
 +    if not refundable(pay_status):
 +        return flask.render_template(
-             "templates/error.html", message="Item not refundable (anymore)"
++            "templates/error.html.j2", message=gettext("Article is not 
anymore refundable")
 +        )
      return flask.render_template(
--        "templates/confirm_refund.html", article_name=article_name, 
order_id=order_id
++        "templates/confirm_refund.html.j2", article_name=article_name, 
order_id=order_id
      )
  
  
@@@ -219,34 -188,31 +272,53 @@@ def render_article(article_name, data, 
          err_abort(404, message=m)
      # the order_id is needed for refunds
      return flask.render_template(
--        "templates/article_frame.html",
++        "templates/article_frame.html.j2",
          article_file=get_article_file(article_info),
          article_name=article_name,
          order_id=order_id,
 +        refundable=refundable
      )
  
 +##
 +# Setup a fresh order with the backend.
 +#
 +# @param article_name which article the order is for
 +# @param lang which language to use
 +#
 +def post_order(article_name,lang):
 +    order = dict(
 +        amount=ARTICLE_AMOUNT,
 +        extra=dict(article_name=article_name,lang=lang),
 +        fulfillment_url=flask.request.base_url,
 +        summary="Essay: " + article_name.replace("_", " "),
 +        # 10 minutes time for a refund
 +        wire_transfer_deadline=dict(t_ms=1000 * int(time.time() + 15 * 30)),
 +    )
 +    order_resp = backend_post(
 +        BACKEND_URL,
 +        "private/orders",
 +        dict(order=order, refund_delay=dict(d_ms=1000 * 120)))
 +    return order_resp
 +
+ ##
+ # Setup a fresh order with the backend.
+ #
+ # @param article_name which article the order is for
+ # @param lang which language to use
+ #
+ def post_order(article_name,lang):
+     order = dict(
+         amount=ARTICLE_AMOUNT,
+         extra=dict(article_name=article_name,lang=lang),
+         fulfillment_url=flask.request.base_url,
+         summary="Essay: " + article_name.replace("_", " "),
+         # 10 minutes time for a refund
+         refund_deadline=dict(t_ms=1000 * int(time.time() + 10 * 30)),
+         wire_transfer_deadline=dict(t_ms=1000 * int(time.time() + 15 * 30)),
+     )
+     order_resp = backend_post(BACKEND_URL, "private/orders", 
dict(order=order))
+     return order_resp
+ 
  
  ##
  # Trigger a article purchase.  The logic follows the main steps:
@@@ -308,39 -274,30 +379,49 @@@ def article(article_name, lang=None, da
  
      if order_status == "paid":
          refunded = pay_status["refunded"]
 -         if refunded:
 +        if refunded:
-             return flask.render_template(
-                 "templates/article_refunded.html",
+              return flask.render_template(
 -                "templates/article_refunded.html",
++                "templates/article_refunded.html.j2",
                  article_name=article_name,
                  order_id=order_id,
              )
-         return render_article(article_name, data, order_id, 
refundable(pay_status))
 -        else:
 -            response = render_article(article_name, data, order_id)
 -            response.set_cookie("order_id", order_id, 
path=urllib.parse.quote(f"/essay/{article_name}"))
 -            response.set_cookie("order_id", order_id, 
path=urllib.parse.quote(f"/{lang}/essay/{article_name}"))
 -            return response
 -    else:
 -        # Check if the customer came on this page via the
 -        # re-purchase detection mechanism
 -        ai = pay_status.get("already_paid_order_id")
 -        au = pay_status.get("already_paid_fulfillment_url")
 -        if ai is not None and au is not None:
 -            response = flask.redirect(au)
 -            response.set_cookie("order_id", ai, 
path=urllib.parse.quote(f"/essay/{article_name}"))
 -            return response
++        response = render_article(article_name, data, order_id, 
refundable(pay_status))
++        response.set_cookie(
++            "order_id", order_id, 
path=urllib.parse.quote(f"/essay/{article_name}")
++        )
++        response.set_cookie(
++            "order_id", order_id, 
path=urllib.parse.quote(f"/{lang}/essay/{article_name}")
++        )
++        return response
 +
 +    # Check if the customer came on this page via the
 +    # re-purchase detection mechanism
 +    ai = pay_status.get("already_paid_order_id")
 +    au = pay_status.get("already_paid_fulfillment_url")
 +    if ai is not None and au is not None:
 +        response = flask.redirect(au)
 +        response.set_cookie(
 +            "order_id", ai, path=urllib.parse.quote(f"/essay/{article_name}")
 +        )
 +        return response
  
      # Redirect the browser to a page where the wallet can
      # run the payment protocol.
      response = flask.redirect(pay_status["order_status_url"])
 -    response.set_cookie("order_id", order_id, 
path=urllib.parse.quote(f"/essay/{article_name}"))
 -    response.set_cookie("order_id", order_id, 
path=urllib.parse.quote(f"/{lang}/essay/{article_name}"))
 +    response.set_cookie(
 +        "order_id", order_id, 
path=urllib.parse.quote(f"/essay/{article_name}")
 +    )
++    response.set_cookie(
++        "order_id", order_id, 
path=urllib.parse.quote(f"/{lang}/essay/{article_name}")
++    )
      return response
 +
 +@app.errorhandler(500)
 +def handler(e):
 +    return flask.render_template(
-         "templates/error.html", message="Internal server error")
++        "templates/error.html.j2", message=gettext("Internal server error"))
 +
 +@app.errorhandler(404)
 +def handler(e):
 +    return flask.render_template(
-         "templates/error.html", message="Page not found")
++        "templates/error.html.j2", message=gettext("Page not found"))
diff --cc talermerchantdemos/blog/templates/article_frame.html
index a5050d3,8c2b6d4..0000000
deleted file mode 100644,100644
--- a/talermerchantdemos/blog/templates/article_frame.html
+++ /dev/null
@@@ -1,13 -1,11 +1,0 @@@
--{% extends "templates/base.html" %}
--{% block main %}
--{% include "articles/" + article_file %}
--
- {% if refundable %}
--<hr>
--<p>
-   You don't like this article?  <a href="{{ url_for('confirm_refund', 
order_id=order_id) }}">Get a refund</a> within
-   the first hour after buying it.
 -  You did not like this article?
 -  <a href="{{ url_for('confirm_refund', lang='en', order_id=order_id) }}">Get 
a refund</a>
 -  within the first hour after buying it.
--</p>
- {% endif %}
- 
--{% endblock main %}
diff --cc talermerchantdemos/blog/templates/article_frame.html.j2
index 0000000,0000000..a878e95
new file mode 100644
--- /dev/null
+++ b/talermerchantdemos/blog/templates/article_frame.html.j2
@@@ -1,0 -1,0 +1,15 @@@
++{% extends "templates/base.html.j2" %}
++{% block main %}
++{% include "articles/" + article_file %}
++
++{% if refundable %}
++<hr>
++<p>
++  {{
++    gettext("You did not like this article?") +
++    gettext("You can <a href="{url}">request a refund</a> within the first 
hour after buying it.").format(url=url_for('confirm_refund', lang='en', 
order_id=order_id)
++  }}
++</p>
++{% endif %}
++
++{% endblock main %}
diff --cc talermerchantdemos/blog/templates/article_refunded.html
index 95c4a6b,95c4a6b..0000000
deleted file mode 100644,100644
--- a/talermerchantdemos/blog/templates/article_refunded.html
+++ /dev/null
@@@ -1,10 -1,10 +1,0 @@@
--{% extends "templates/base.html" %}
--{% block main %}
--
--<h2>Refunded</h2>
--
--<p>Your payment (order ID <tt>{{ order_id }}<tt>) for the article "{{ 
article_name }}" has been refunded.</p>
--
--<p>You won't be able to view it until you pay for it again.</p>
--
--{% endblock main %}
diff --cc talermerchantdemos/blog/templates/article_refunded.html.j2
index 0000000,0000000..34e0a0b
new file mode 100644
--- /dev/null
+++ b/talermerchantdemos/blog/templates/article_refunded.html.j2
@@@ -1,0 -1,0 +1,16 @@@
++{% extends "templates/base.html.j2" %}
++{% block main %}
++
++<h2>{{ gettext("Refunded") }}</h2>
++
++<p>
++{{
++  gettext("Your payment (order ID <tt>{order}<tt>) for the article 
"{article}" has been refunded.").format(order=order_id,article=article_name)
++}}
++</p>
++
++<p>
++{{ gettext("You won't be able to view it until you pay for it again.") }}
++</p>
++
++{% endblock main %}
diff --cc talermerchantdemos/blog/templates/base.html.j2
index 0000000,824cf9d..58ce857
mode 000000,100644..100644
--- a/talermerchantdemos/blog/templates/base.html.j2
+++ b/talermerchantdemos/blog/templates/base.html.j2
@@@ -1,0 -1,120 +1,119 @@@
+ <!DOCTYPE html>
 -<!-- 
++<!--
+   This file is part of GNU TALER.
 -  Copyright (C) 2014, 2015, 2016 INRIA
++  Copyright (C) 2014, 2015, 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
+   Foundation; either version 2.1, or (at your option) any later version.
+ 
+   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
FOR
+   A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
details.
+ 
+   You should have received a copy of the GNU Lesser General Public License 
along with
+   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ -->
+ 
+ <html>
+ <head>
+   <meta charset="UTF-8">
+   <meta name="viewport" content="width=device-width, initial-scale=1.0">
+   {% block meta %}{% endblock %}
 -  <title>Taler Essay Shop Demo</title>
++  <title>{{ gettext("Taler Essay Shop Demo") }}</title>
+   <link rel="stylesheet" type="text/css" href="{{ url_for('static', 
filename='pure.css') }}" />
+   <link rel="stylesheet" type="text/css" href="{{ url_for('static', 
filename='demo.css') }}" />
+   <link rel="stylesheet" type="text/css" href="{{ url_for('static', 
filename='navbar.css') }}" />
+   <style>
+     .warn {
+       background-color: #aa393977;
+       padding: 1em;
+     }
+     @keyframes hoveranim {
+       from {left:0;}
+       to {left:1vw;}
+     }
+     @keyframes hoveranimrevert {
+       from {left:1vw;}
+       to {left:0;}
+     }
+     .notice {
+       border-radius: 1em;
+       background: #0333;
+       border-left: 0.3em solid #033;
+       padding-left: 1em;
+       padding-top: 0.5em;
+       padding-bottom: 0.5em;
+       margin-top: 2em;
+       margin-bottom: 2em;
+     }
+     .notice {
+       position: relative;
+       left: 0;
+       animation-name: hoveranimrevert;
+       animation-duration: 1s;
+     }
+     .notice:hover {
+       left: 1vw;
+       animation-name: hoveranim;
+       animation-duration: 1s;
+     }
+     #main a:link, #main a:visited, #main a:hover, #main a:active {
+         color: black;
+     }
+   </style>
 -  
++
+   {% block styles %}{% endblock %}
+   {% block scripts %}{% endblock %}
+ </head>
+ 
+ <body>
+   <header class="demobar" style="display: flex; flex-direction: column;">
+     <h1><span class="tt adorn-brackets">Taler Demo</span></h1>
+     <h1><span class="it"><a href="{{ env('TALER_ENV_URL_MERCHANT_BLOG') 
}}">Shop</a></span></h1>
 -    <p>On this page you can buy articles using an imaginary currency (for 
now).
 -       The articles are chapters from Richard Stallman's book &quot;Free 
Software, Free Society&quot;,
 -       which is also
 -      <a 
href="http://shop.fsf.org/product/free-software-free-society-2/";>published by 
the FSF</a>
 -      and available gratis at <a href="http://www.gnu.org/";>gnu.org</a>.
++    <p>{{
++      gettext("On this page you can buy articles using an imaginary 
currency.") + "<br>" +
++      gettext("The articles are chapters from Richard Stallman's book 
&quot;Free Software, Free Society&quot;.") + "<br>" +
++      gettext('The book is <a href="{shop}">published by the FSF</a> and 
available gratis at <a 
href="{gnu}">gnu.org</a>.').format(shop="https://shop.fsf.org/product/free-software-free-society-2";,
 gnu="https://www.gnu.org";)
++      }}
+     </p>
+   </header>
+   <div style="display:flex; flex-direction: column;" class="navcontainer">
+     <nav class="demolist">
 -      <a href="{{ env('TALER_ENV_URL_INTRO', '#') }}">Introduction</a>
 -      <a href="{{ env('TALER_ENV_URL_BANK', '#') }}">Bank</a>
 -      <a href="{{ env('TALER_ENV_URL_MERCHANT_BLOG', '#') }}" 
class="active">Essay Shop</a>
 -      <a href="{{ env('TALER_ENV_URL_MERCHANT_DONATIONS', '#') 
}}">Donations</a>
 -      <a href="{{ env('TALER_ENV_URL_MERCHANT_SURVEY', '#') 
}}">Tipping/Survey</a>
 -      <a href="{{ env('TALER_ENV_URL_BACKOFFICE', '#') }}">Back-office</a>
++      <a href="{{ env('TALER_ENV_URL_INTRO', '#') 
}}">{{gettext("Introduction")}}</a>
++      <a href="{{ env('TALER_ENV_URL_BANK', '#') }}">{{gettext("Bank")}}</a>
++      <a href="{{ env('TALER_ENV_URL_MERCHANT_BLOG', '#') }}" 
class="active">{{gettext("Essay Shop")}}</a>
++      <a href="{{ env('TALER_ENV_URL_MERCHANT_DONATIONS', '#') 
}}">{{gettext("Donations")}}</a>
++      <a href="{{ env('TALER_ENV_URL_MERCHANT_SURVEY', '#') 
}}">{{gettext("Tipping/Survey")}}</a>
++      <!-- a href="{{ env('TALER_ENV_URL_BACKOFFICE', '#') 
}}">{{gettext("Back-office")}}</a -->
+       <span class="right">
 -        Language
++        {{ gettext("English [en]") }}
+         <!-- <input type="checkbox"> -->
+         <div class="nav">
+           <br>
+           <!--<hr style="width: 100%;">-->
 -          <a href="{{ '#LANG_EN_LANGEND' }}" class="navbtn">EN</a><br>
 -          <a href="{{ '#LANG_DE_LANGEND' }}" class="navbtn">DE</a><br>
 -          <a href="{{ '#LANG_FR_LANGEND' }}" class="navbtn">FR</a><br>
 -          <a href="{{ '#LANG_IT_LANGEND' }}" class="navbtn">IT</a><br>
 -          <a href="{{ '#LANG_JP_LANGEND' }}" class="navbtn">JP</a>
 -          <!-- lang strings structured as such to make replacing them with 
code using an ide's replace function easy -->
++          {% if lang != 'en' %}
++          <a href="{{ self_localized('en') }}" class="navbtn">English 
[en]</a><br>
++          {% endif %}
++          {% if lang != 'de' %}
++          <a href="{{ self_localized('de') }}" class="navbtn">Deutsch 
[de]</a><br>
++          {% endif %}
+         </div>
+       </span>
+     </nav>
+   </div>
+   <!-- <input type="checkbox" class="r"><label>test</label> -->
+ 
+   <section id="main" class="content">
+     {% block main %}
+       This is the main content of the page.
+     {% endblock %}
+     <hr />
+     <div>
 -      <p>You can learn more about Taler on our main <a 
href="https://taler.net";>website</a>.</p>
++      <p>{{ gettext('You can learn more about Taler on our main <a 
href="{site}">website</a>.').format(site="https://taler.net/";) }}</p>
+       <div style="flex-grow:1"></div>
+       <p>Copyright &copy; 2014&mdash;2020 Taler Systems SA</p>
+     </div>
+   </section>
+ </body>
+ </html>
 -
diff --cc talermerchantdemos/blog/templates/confirm_refund.html
index 10aaa74,c4773d3..0000000
deleted file mode 100644,100644
--- a/talermerchantdemos/blog/templates/confirm_refund.html
+++ /dev/null
@@@ -1,19 -1,19 +1,0 @@@
--{% extends "templates/base.html" %}
--{% block main %}
--  <h1>Refund Article?</h1>
--
--  <p>
-     Do you want to get a refund for the article <em>{{ article_name }}</em>?  
After you've requested a refund,
 -    Do you want to get a refund for the article <em>{{ article_name }}</em>?  
After you have requested a refund,
--    you won't be able to read the article anymore.
--  </p>
--
--  <p>
-       You will only be able to receive the refund on the same wallet that 
you've used to pay
 -      You will only be able to receive the refund on the same wallet that you 
have used to pay
--      for this article originally.
--  </p>
--
--  <form action="{{ url_for('refund', order_id=order_id) }}" method="POST">
--    <input type="text" name="article_name" value={{ article_name}} hidden>
--    <input type="submit" value="Request refund">
--  </form>
--{% endblock main %}
diff --cc talermerchantdemos/blog/templates/confirm_refund.html.j2
index 0000000,0000000..09f3730
new file mode 100644
--- /dev/null
+++ b/talermerchantdemos/blog/templates/confirm_refund.html.j2
@@@ -1,0 -1,0 +1,22 @@@
++{% extends "templates/base.html.j2" %}
++{% block main %}
++  <h1>{{ gettext("Confirm refund request for article"))</h1>
++
++  <p>
++    {{
++       gettext("Do you want to get a refund for the article 
<em>{name}</em>?").format(name=article_name) +
++       gettext("After you have requested a refund, you won't be able to read 
the article anymore.")
++    }}
++  </p>
++
++  <p>
++    {{
++      gettext ("You will only be able to receive the refund on the same 
wallet that you have used to pay for this article originally.")
++    }}
++  </p>
++
++  <form action="{{ url_for('refund', order_id=order_id) }}" method="POST">
++    <input type="text" name="article_name" value={{ article_name}} hidden>
++    <input type="submit" value="Request refund">
++  </form>
++{% endblock main %}
diff --cc talermerchantdemos/blog/templates/error.html
index 0d4bd02,0d4bd02..0000000
deleted file mode 100644,100644
--- a/talermerchantdemos/blog/templates/error.html
+++ /dev/null
@@@ -1,22 -1,22 +1,0 @@@
--{% extends "templates/base.html" %}
--{% block main %}
--  <h1>An Error Occurred</h1>
--
--  <p>{{ message }}</p>
--
--  {% if status_code %}
--  <p>The backend returned status code {{ status_code }}.</p>
--  {% endif %}
--
--  {% if json %}
--  <p>Backend Response:</p>
--  <pre>{{ json }}</pre>
--  {% endif %}
--
--  {% if stack %}
--  <p>Stack trace:</p>
--  <pre>
--    {{ stack }}
--  </pre>
--  {% endif %}
--{% endblock main %}
diff --cc talermerchantdemos/blog/templates/error.html.j2
index 0000000,0000000..ffc2e1f
new file mode 100644
--- /dev/null
+++ b/talermerchantdemos/blog/templates/error.html.j2
@@@ -1,0 -1,0 +1,24 @@@
++{% extends "templates/base.html.j2" %}
++{% block main %}
++  <h1>{{ gettext("Error encountered") }}</h1>
++
++  <p>{{ message }}</p>
++
++  {% if status_code %}
++  <p>
++    {{ gettext ("The backend returned status code 
{code}.").format(code=status_code) }}.
++  </p>
++  {% endif %}
++
++  {% if json %}
++  <p>{{gettext("Backend response:")}}</p>
++  <pre>{{ json }}</pre>
++  {% endif %}
++
++  {% if stack %}
++  <p>{{gettext("Stack trace:")}}</p>
++  <pre>
++    {{ stack }}
++  </pre>
++  {% endif %}
++{% endblock main %}
diff --cc talermerchantdemos/blog/templates/index.html
index 0159779,e139bd2..0000000
deleted file mode 100644,100644
--- a/talermerchantdemos/blog/templates/index.html
+++ /dev/null
@@@ -1,40 -1,41 +1,0 @@@
--{% extends "templates/base.html" %}
--{% block main %}
--    <h1>Essay Shop: Free Software, Free Society</h1>
--    <div style="font-size: smaller;">
--      <p>This is the second edition of <cite>Free Software, Free Society: 
Selected Essays of Richard M. Stallman.</cite><br>
--      Free Software Foundation<br>
--      51 Franklin Street, Fifth Floor<br>
--      Boston, MA 02110-1335
--      <br>
--      Copyright &copy; 2002, 2010 Free Software Foundation, Inc.
--      </p>
--
--      <p>Verbatim copying and distribution of this entire book are permitted
--      worldwide, without royalty, in any medium, provided this notice is
--      preserved. Permission is granted to copy and distribute translations
--      of this book from the original English into another language provided
--      the translation has been approved by the Free Software Foundation and
--      the copyright notice and this permission notice are preserved on all
--      copies.
--      </p>
--      <p>ISBN 978-0-9831592-0-9</p>
--    </div>
--
--    <h2>Chapters</h2>
--    <div>
--      Click on an individual chapter to to purchase it.  You can
-       get free, virtual money to buy articles on this page at the <a href="{{ 
env('TALER_ENV_URL_BANK', '#') }}">bank</a>.
 -      get free, virtual money to buy articles on this page at the
 -      <a href="{{ env('TALER_ENV_URL_BANK', '#') }}">bank</a>.
--    </div>
--
--    <div>
--      {% for article in articles %}
--      <div class="notice">
-       <h3><a href="{{ url_for('article', article_name=article.slug) 
}}">{{article.title}}</a></h3>
-       <p>{{ article.teaser|safe }} <a href="{{ url_for('article', 
article_name=article.slug) }}">(Pay to read more...)</a></p>
 -      <h3><a href="{{ url_for('article', lang=article.lang, 
article_name=article.slug) }}" class="articleTitle">{{article.title}}</a></h3>
 -      <p>{{ article.teaser|safe }} <a href="{{ url_for('article', 
lang=article.lang, article_name=article.slug) }}">(Pay to read more...)</a></p>
--      </div>
--      {% else %}
--      <em>(No articles available)</em>
--      {% endfor %}
--    </div>
--{% endblock main %}
diff --cc talermerchantdemos/blog/templates/show_refund.html
index 913b6a5,913b6a5..0000000
deleted file mode 100644,100644
--- a/talermerchantdemos/blog/templates/show_refund.html
+++ /dev/null
@@@ -1,28 -1,28 +1,0 @@@
--{% extends "templates/base.html" %}
--
--{% block main %}
--
--<h1>Refund</h1>
--
--<div class="taler-installed-hide">
--  <p>
--  Looks like your browser doesn't support GNU Taler payments.  You can try
--  installing a <a href="https://taler.net/en/wallet.html";>wallet browser 
extension</a>.
--  </p>
--</div>
--
--<div>
--
--  <p>
--  You can use this QR code to get a refund with your mobile wallet:
--  </p>
--
--  {{ qrcode_svg | safe }}
--
--  <p>
--  Click <a href="{{ taler_refund_uri }}">this link</a> to open your system's 
Taler wallet if it exists.
--  </p>
--
--</div>
--
--{% endblock main %}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]