From 9636ecd076f4334ded2541d2151aaa9a23aae814 Mon Sep 17 00:00:00 2001 From: Florian Festi Date: Sun, 21 Apr 2019 10:57:50 +0200 Subject: [PATCH] boxesserver: Mark strings translatable and translate generator strings --- scripts/boxesserver | 104 +++++++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 45 deletions(-) diff --git a/scripts/boxesserver b/scripts/boxesserver index 4d677c5..ce1fd36 100755 --- a/scripts/boxesserver +++ b/scripts/boxesserver @@ -25,6 +25,7 @@ import codecs import mimetypes import re import markdown +import gettext # Python 2 vs Python 3 compat try: @@ -90,6 +91,9 @@ class ThrowingArgumentParser(argparse.ArgumentParser): boxes.ArgumentParser = ThrowingArgumentParser # Evil hack class BServer: + + lang_re = re.compile(r"([a-z]{2,3}(-[-a-zA-Z0-9]*)?)\s*(;\s*q=(\d\.?\d*))?") + def __init__(self): self.boxes = {b.__name__ : b() for b in boxes.generators.getAllBoxGenerators().values() if b.webinterface} self.boxes['TrayLayout2'] = boxes.generators.traylayout.TrayLayout2(self, webargs=True) @@ -102,7 +106,22 @@ class BServer: self.staticdir = os.path.join(os.path.dirname(__file__), '../static/') - def arg2html(self, a, prefix, defaults={}): + def getLanguage(self, accept_language): + languages = accept_language.split(",") + langs = [] + for l in languages: + m = self.lang_re.match(l.strip()) + if m: + langs.append((float(m.group(4) or 1.0), m.group(1))) + langs.sort(reverse=True) + langs = [l[1].replace("-", "_") for l in langs] + try: + return gettext.translation('boxes.py', localedir='locale', + languages=langs) + except OSError: + return gettext.translation('boxes.py', languages=langs, fallback=True) + + def arg2html(self, a, prefix, defaults={}, _=lambda s:s): name = a.option_strings[0].replace("-", "") if isinstance(a, argparse._HelpAction): return "" @@ -113,7 +132,7 @@ class BServer: default = defaults.get(name, None) row = """%s%%s%s\n""" % \ - (viewname, a.help or "") + (_(viewname), "" if not a.help else _(a.help)) if (isinstance(a, argparse._StoreAction) and hasattr(a.type, "html")): input = a.type.html(name, default or a.default) @@ -125,7 +144,7 @@ class BServer: options = "\n".join( ("""""" % (e, ' selected="selected"' if e == (default or a.default) else "", - e) for e in a.choices)) + _(e)) for e in a.choices)) input = """\n""" % (name, options) else: input = """""" % \ @@ -154,11 +173,11 @@ class BServer: """ - def args2html(self, name, box, action="", defaults={}): + def args2html(self, name, box, action="", defaults={}, _=lambda s:s): result = [""" - Boxes - """, name, """ + """ + _("Boxes - %s") % _(name), """ @@ -179,7 +198,7 @@ class BServer:

""", name, """

-

""", box.__doc__ or "", """

+

""", _(box.__doc__) if box.__doc__ else "", """

""" % (action)] groupid = 0 @@ -193,11 +212,11 @@ class BServer: for a in group._group_actions: if a.dest in ("input", "output"): continue - result.append(self.arg2html(a, prefix, defaults)) + result.append(self.arg2html(a, prefix, defaults, _)) result.append("") groupid += 1 result.append(""" -

+

@@ -212,29 +231,20 @@ class BServer:
""") if box.description: - result.append(markdown.markdown(box.description)) + result.append(markdown.markdown(_(box.description))) result.append(""" - - - - +""" + self.footer(_) + """ """ ) return (s.encode("utf-8") for s in result) - def menu(self): + def menu(self, _): result = [""" - Boxes.py + """ + _("Boxes.py") + """ @@ -254,13 +264,13 @@ class BServer:
-

Boxes.py

+

""" + _("Boxes.py") + """

-Create boxes and more with a laser cutter! +""" + _("Create boxes and more with a laser cutter!") + """

- - Boxes.py is an Open Source box generator written in Python. It features both finished parametrized generators as well as a Python API for writing your own. It features finger and (flat) dovetail joints, flex cuts, holes and slots for screws, hinges, gears, pulleys and much more. +""" + _(""" + Boxes.py is an Open Source box generator written in Python. It features both finished parametrized generators as well as a Python API for writing your own. It features finger and (flat) dovetail joints, flex cuts, holes and slots for screws, hinges, gears, pulleys and much more.""") + """

@@ -274,7 +284,7 @@ Create boxes and more with a laser cutter!
""" ] for nr, group in enumerate(self.groups): - result.append('''

%s

\n
\n''' % (nr, nr, group.title, nr)) + result.append('''

%s

\n
\n''' % (nr, nr, _(group.title), nr)) result.append("""
@@ -285,9 +295,9 @@ Create boxes and more with a laser cutter! continue docs = "" if box.__doc__: - docs = " - " + box.__doc__ + docs = " - " + _(box.__doc__) result.append("""
  • %s%s
  • \n""" % ( - group.name, name, group.name, name, name, docs)) + group.name, name, group.name, name, _(name), docs)) result.append("\n
    \n") result.append("""
    @@ -296,32 +306,34 @@ Create boxes and more with a laser cutter!

    -
    - - - +
    """ + self.footer(_) + """ """) return (s.encode("utf-8") for s in result) - def errorMessage(self, name, e): + def footer(self, _): + return """ + +""" + + def errorMessage(self, name, e, _): return [ b""" - Error generating""", name.encode(), + <title>""", _("Error generating %s") % _(name).encode(), b""" -

    An error occurred!

    """, +

    """ + _("An error occurred!") + "

    ", u"".join(u"

    %s

    " % cgi.escape(s) for s in type(u"")(e).split(u"\n")).encode('utf-8'), b""" @@ -377,10 +389,12 @@ b""" d = parse_qs(environ['QUERY_STRING']) name = environ["PATH_INFO"][1:] + _ = self.getLanguage(environ.get("HTTP_ACCEPT_LANGUAGE", "")).gettext + box = self.boxes.get(name, None) if not box: start_response(status, headers) - return self.menu() + return self.menu(_=_) args = [unquote_plus(arg) for arg in environ['QUERY_STRING'].split("&")] @@ -393,20 +407,20 @@ b""" k, v = kv defaults[k] = cgi.escape(v, True) start_response(status, headers) - return self.args2html(name, box, "./" + name, defaults=defaults) + return self.args2html(name, box, "./" + name, defaults=defaults, _=_) else: args = ["--"+ arg for arg in args if arg != "render=1"] try: box.parseArgs(args) except (ArgumentParserError) as e: start_response(status, headers) - return self.errorMessage(name, e) + return self.errorMessage(name, e, _) if name == "TrayLayout": start_response(status, headers) box.fillDefault(box.x, box.y) self.boxes["TrayLayout2"].argparser.set_defaults(layout=str(box)) return self.args2html( - name, self.boxes["TrayLayout2"], action="TrayLayout2") + name, self.boxes["TrayLayout2"], action="TrayLayout2", _=_) if name == "TrayLayout2": try: box.parse(box.layout.split("\n"))