3
0
Files
python-capport/src/capport/api/lang.py

84 lines
2.3 KiB
Python

from __future__ import annotations
import os.path
import re
import typing
import quart
from .app import app
_VALID_LANGUAGE_NAMES = re.compile(r'^[-a-z0-9_]+$')
def parse_accept_language(value: str) -> typing.List[str]:
value = value.strip()
if not value or value == '*':
return []
tuples = []
for entry in value.split(','):
attrs = entry.split(';')
name = attrs.pop(0).strip().lower()
q = 1.0
for attr in attrs:
if not '=' in attr: continue
key, value = attr.split('=', maxsplit=1)
if key.strip().lower() == 'q':
try:
q = float(value.strip())
except ValueError:
q = 0.0
if q >= 0.0:
tuples.append((q, name))
tuples.sort()
have = set()
result = []
for (_q, name) in tuples:
if name in have: continue
if name == '*': break
have.add(name)
if _VALID_LANGUAGE_NAMES.match(name):
result.append(name)
short_name = name.split('-', maxsplit=1)[0].split('_', maxsplit=1)[0]
if not short_name or short_name in have: continue
have.add(short_name)
result.append(short_name)
return result
@app.before_request
def detect_language():
g = quart.g
r = quart.request
s = quart.session
if 'setlang' in r.args:
lang = r.args.get('setlang').strip().lower()
if lang and _VALID_LANGUAGE_NAMES.match(lang):
if s.get('lang') != lang:
s['lang'] = lang
g.langs = [lang]
return
else:
# reset language
s.pop('lang', None)
lang = s.get('lang')
if lang:
lang = lang.strip().lower()
if lang and _VALID_LANGUAGE_NAMES.match(lang):
g.langs = [lang]
return
acc_lang = ','.join(r.headers.get_all('Accept-Language'))
g.langs = parse_accept_language(acc_lang)
async def render_i18n_template(template, /, **kwargs) -> str:
langs: typing.List[str] = quart.g.langs
if not langs:
return await quart.render_template(template, **kwargs)
names = [
os.path.join('i18n', lang, template)
for lang in langs
]
names.append(template)
return await quart.render_template(names, **kwargs)