94 lines
2.8 KiB
Python
94 lines
2.8 KiB
Python
from os import path
|
|
|
|
from jinja2 import Environment
|
|
from jinja2 import PackageLoader
|
|
from werkzeug.exceptions import HTTPException
|
|
from werkzeug.exceptions import NotFound
|
|
from werkzeug.routing import RequestRedirect
|
|
from werkzeug.wrappers import Request as BaseRequest
|
|
from werkzeug.wrappers import Response as BaseResponse
|
|
|
|
from .urls import map
|
|
|
|
TEMPLATES = path.join(path.dirname(__file__), "templates")
|
|
views = {}
|
|
|
|
|
|
def expose(name):
|
|
"""Register the function as view."""
|
|
|
|
def wrapped(f):
|
|
views[name] = f
|
|
return f
|
|
|
|
return wrapped
|
|
|
|
|
|
class Request(BaseRequest):
|
|
def __init__(self, environ, urls):
|
|
super().__init__(environ)
|
|
self.urls = urls
|
|
self.matched_url = None
|
|
|
|
def url_for(self, endpoint, **args):
|
|
if "lang_code" not in args:
|
|
args["lang_code"] = self.language
|
|
if endpoint == "this":
|
|
endpoint = self.matched_url[0]
|
|
tmp = self.matched_url[1].copy()
|
|
tmp.update(args)
|
|
args = tmp
|
|
return self.urls.build(endpoint, args)
|
|
|
|
|
|
class Response(BaseResponse):
|
|
pass
|
|
|
|
|
|
class TemplateResponse(Response):
|
|
jinja_env = Environment(loader=PackageLoader("i18nurls"), autoescape=True)
|
|
|
|
def __init__(self, template_name, **values):
|
|
self.template_name = template_name
|
|
self.template_values = values
|
|
Response.__init__(self, mimetype="text/html")
|
|
|
|
def __call__(self, environ, start_response):
|
|
req = environ["werkzeug.request"]
|
|
values = self.template_values.copy()
|
|
values["req"] = req
|
|
self.data = self.render_template(self.template_name, values)
|
|
return super().__call__(environ, start_response)
|
|
|
|
def render_template(self, name, values):
|
|
template = self.jinja_env.get_template(name)
|
|
return template.render(values)
|
|
|
|
|
|
class Application:
|
|
def __init__(self):
|
|
from i18nurls import views
|
|
|
|
self.not_found = views.page_not_found
|
|
|
|
def __call__(self, environ, start_response):
|
|
urls = map.bind_to_environ(environ)
|
|
req = Request(environ, urls)
|
|
try:
|
|
endpoint, args = urls.match(req.path)
|
|
req.matched_url = (endpoint, args)
|
|
if endpoint == "#language_select":
|
|
lng = req.accept_languages.best
|
|
lng = lng.split("-")[0].lower() if lng else "en"
|
|
index_url = urls.build("index", {"lang_code": lng})
|
|
resp = Response(f"Moved to {index_url}", status=302)
|
|
resp.headers["Location"] = index_url
|
|
else:
|
|
req.language = args.pop("lang_code", None)
|
|
resp = views[endpoint](req, **args)
|
|
except NotFound:
|
|
resp = self.not_found(req)
|
|
except (RequestRedirect, HTTPException) as e:
|
|
resp = e
|
|
return resp(environ, start_response)
|