From c288ba14fd475a03ef148769ffb4146669a34de9 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 20 Apr 2019 13:57:39 +0200 Subject: fixing #5063, also adding i18n, with help by Torsten --- Makefile | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- config.mk | 7 ++++++ i18nfix.py | 34 +++++++++++++++++++++++++++ index.html.j2 | 35 +++++++++++++++++++++++----- locale/babel.map | 12 ++++++++++ static/web-common | 2 +- template.py | 60 ++++++++++++++++++++++++++--------------------- 7 files changed, 184 insertions(+), 36 deletions(-) create mode 100644 config.mk create mode 100644 i18nfix.py create mode 100644 locale/babel.map diff --git a/Makefile b/Makefile index 72460df..e6f461f 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,67 @@ -.PHONY: all -all: - ./template.py +# This file is in the public domain. + +# Hardly anyone seems to read README files anymore, so keep this note here: +# Don't remove the variables for python etc. They exist +# because one system sticks with PEPs, and others opt +# for installing every version side-by-side, +# Same goes for babel. + +include config.mk + +# All: build HTML pages in all languages and compile the +# TypeScript logic in web-common. +all: locale template +# cd web-common && $(TSC) + +# Extract translateable strings from jinja2 templates. +locale/messages.pot: *.j2 # common/*.j2 common/*.j2.inc + env PYTHONPATH="." $(BABEL) extract -F locale/babel.map -o locale/messages.pot . + +# Update translation (.po) files with new strings. +locale-update: locale/messages.pot + msgmerge -U -m --previous locale/en/LC_MESSAGES/messages.po locale/messages.pot + + if grep -nA1 '#-#-#-#-#' locale/*/LC_MESSAGES/messages.po; then echo -e "\nERROR: Conflicts encountered in PO files.\n"; exit 1; fi + +# Compile translation files for use. +locale-compile: + $(BABEL) compile -d locale -l en --use-fuzzy + +# Process everything related to gettext translations. +locale: locale-update locale-compile + +# Run the jinja2 templating engine to expand templates to HTML +# incorporating translations. +template: locale-compile + $(PYTHON) ./template.py + +run: all + @[ "$(BROWSER)" ] || ( echo "You need to export the environment variable 'BROWSER' to run this."; exit 1 ) + $(RUN_BROWSER) http://0.0.0.0:8000 & + # cd rendered && $(PYTHON) -m http.server + $(PYTHON) -m http.server + +clean: + rm -rf __pycache__ + rm -rf en/ de/ fr/ it/ es/ ru/ + rm -rf rendered/ + +submodules/init: + git submodule update --init --recursive + +submodules/update: + git submodule update --recursive --remote + +.SILENT: show-help + +show-help: + printf "all:\t\t\tBuild the website\n" + printf "locale/messages.pot:\tExtract translateable strings from jinja2 templates.\n" + printf "locale-update:\t\tUpdate translation files with new strings.\n" + printf "locale-compile:\t\tCompile translation files for use.\n" + printf "locale:\t\t\tProcess everything related to gettext translations.\n" + printf "template:\t\texpand jinja2 templates to html.\n" + printf "run:\t\t\tspawn python webserver and open the current directory.\n" + printf "clean:\t\t\tclean.\n" + printf "submodules/init:\tinit git submodules\n" + printf "submodules/update:\tupdate git submodules\n" diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..6d0dae0 --- /dev/null +++ b/config.mk @@ -0,0 +1,7 @@ +# config.mk Makefile fragment to set custom variables. + +TSC=tsc +PYTHON=python3 +BABEL=pybabel + +RUN_BROWSER=$(BROWSER) diff --git a/i18nfix.py b/i18nfix.py new file mode 100644 index 0000000..9e4b26b --- /dev/null +++ b/i18nfix.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +# This file is in the public domain. + +""" +Extract translations from a Jinja2 template, stripping leading newlines. + +@author Florian Dold +""" + +import jinja2.ext +import re + +def normalize(message): + if isinstance(message, str): + message = message.strip() + # collapse whitespaces (including newlines) into one space. + message = re.sub("\s+", " ", message) + return message + + +def babel_extract(fileobj, keywords, comment_tags, options): + res = jinja2.ext.babel_extract(fileobj, keywords, comment_tags, options) + for lineno, funcname, message, comments in res: + message = normalize(message) + yield lineno, funcname, message, comments + +def wrap_gettext(f): + """ + Call gettext with whitespace normalized. + """ + def wrapper(message): + message = normalize(message) + return f(message) + return wrapper diff --git a/index.html.j2 b/index.html.j2 index 0dcdead..6945479 100644 --- a/index.html.j2 +++ b/index.html.j2 @@ -2,7 +2,7 @@ - Taler Demo - Auditor + {{ _("Taler Demo - Auditor") }} @@ -50,19 +50,42 @@
-

Taler Demo

-

Auditor

-

This is an auditor for the currency "{{ currency }}".

+

{{ _("Taler Demo") }}

+

{{ _("Auditor") }}

+

+ {{ _("This is an auditor for the %(curr)s currency.", curr=currency) }} +

-

You can learn more about Taler on our main website.

+

+ {% trans %} + You can learn more about Taler on our main website. + {% endtrans %} +

- +

{{ _("%(curr)s Auditor", curr=currency) }}

+

+ {{ _("This is the Web site of the auditor for the %(curr)s currency.",curr=currency) }} + {% trans %} + In the GNU Taler system, an auditor is responsible for verifying + that an exchange operates correctly. If you trust us to do a good + job auditing, please click here: + {% endtrans %} +

+
+ +
+

+ {% trans %} + This will tell your wallet that you are willing to trust exchanges that + we audit to handle the TESTKUDOS currency properly. + {% endtrans %} +

diff --git a/locale/babel.map b/locale/babel.map new file mode 100644 index 0000000..72b6f99 --- /dev/null +++ b/locale/babel.map @@ -0,0 +1,12 @@ +[extractors] +jinja2 = i18nfix:babel_extract + +[jinja2: **.j2] +encoding = utf-8 +lstrip_blocks = True +trim_blocks = True + +[jinja2: **.j2.inc] +encoding = utf-8 +lstrip_blocks = True +ltrim_blocks = True diff --git a/static/web-common b/static/web-common index d7e0135..68cb09c 160000 --- a/static/web-common +++ b/static/web-common @@ -1 +1 @@ -Subproject commit d7e013594d15388b1a7342a44a0e9c8d4ecca82d +Subproject commit 68cb09ce78e261dbcddc69b174b8766f96794971 diff --git a/template.py b/template.py index bd67d3f..c8153cc 100755 --- a/template.py +++ b/template.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # This file is in the public domain. # -# This script runs the jinga2 templating engine on an input template-file +# This script runs the jinja2 templating engine on an input template-file # using the specified locale for gettext translations, and outputs # the resulting (HTML) ouptut-file. # @@ -12,19 +12,19 @@ import os.path import sys import re import gettext +import subprocess import jinja2 import glob import codecs import os -import os.path -import subprocess +sys.path.append(os.getcwd()) +import i18nfix env = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(__file__)), - extensions=["jinja2.ext.i18n"], - lstrip_blocks=True, - trim_blocks=True, - - undefined=jinja2.StrictUndefined, + extensions=["jinja2.ext.i18n"], + lstrip_blocks=True, + trim_blocks=True, + undefined=jinja2.StrictUndefined, autoescape=False) default_ctx = {} @@ -38,6 +38,8 @@ auditor_priv_file = os.path.expanduser("~/.local/share/taler/auditor/offline-key default_ctx["auditor_pub"] = subprocess.check_output(["gnunet-ecc", "-p", auditor_priv_file]).decode("utf-8").strip() +langs_full = {"en": "English" } + for in_file in glob.glob("*.j2"): name, ext = re.match(r"(.*)\.([^.]+)$", in_file.rstrip(".j2")).groups() tmpl = env.get_template(in_file) @@ -51,34 +53,40 @@ for in_file in glob.glob("*.j2"): def url_localized(filename): return "../" + locale + "/" + filename + def svg_localized(filename): + lf = filename + "." + locale + ".svg" + if "en" == locale or not os.path.isfile (lf): + return "../" + filename + ".svg" + else: + return "../" + lf + def url(x): # TODO: look at the app root environment variable # TODO: check if file exists return "../" + x - for l in ("en", "de", "it", "es"): - locale = os.path.basename(l) + for l in glob.glob("locale/*/"): + locale = os.path.basename(l[:-1]) - if os.path.isdir(os.path.join("./locale/", locale)): - tr = gettext.translation("messages", - localedir="locale", - languages=[locale]) + tr = gettext.translation("messages", + localedir="locale", + languages=[locale]) - env.install_gettext_translations(tr, newstyle=True) - else: - print("warning: locale {} not found".format(locale)) - - ctx = dict( - lang=locale, - url=url, - self_localized=self_localized, - url_localized=url_localized, - filename=name + "." + ext) - ctx.update(default_ctx) + tr.gettext = i18nfix.wrap_gettext(tr.gettext) + + env.install_gettext_translations(tr, newstyle=True) + ctx = dict(lang=locale, + lang_full=langs_full[locale], + url=url, + self_localized=self_localized, + url_localized=url_localized, + svg_localized=svg_localized, + filename=name + "." + ext) + ctx.update(default_ctx) content = tmpl.render(**ctx) + out_name = "./" + locale + "/" + in_file.rstrip(".j2") os.makedirs("./" + locale, exist_ok=True) - with codecs.open(out_name, "w", "utf-8") as f: f.write(content) -- cgit v1.2.3