Flask支持多语言站点
Flask的多语言国际化可以使用Flask-Babel插件,在此不再细述,但对于所谓的多语言站点(即形如example.com/zh/uri、example.com/en/uri或者zh.example.com、en.example.com)文档上却未作细述
有一个 Flask URL Processors 需要对所有的uri都额外增加一个lang_code的前缀,路由数较少时没什么问题,但路由数较多时太过麻烦
实现example.com/en/uri可以有多种方式,除了使用Flask URL Processors中介绍的外,还可以
使用nginx重定向uri
这应该是各种方式里最简单的一种
1location ~ ^/en/ { 2 rewrite ^/en/(.*)$ /$1 last; 3} 4location = /en { 5 rewrite ^/(.*)$ /index last; 6}
使用uri获取对应非302响应
即增加一个url为/en/<path:uri>的路由,在此路由func中,根据<path:uri>信息获取已注册路由的view_function,不使用重定向,而是直接调用view_function返回实际响应
1# https://stackoverflow.com/questions/38488134/get-the-flask-view-function-that-matches-a-url 2def get_view_function(url, method='GET'): 3 adapter = current_app.url_map.bind('localhost') 4 try: 5 match = adapter.match(url, method=method) 6 except RequestRedirect as e: 7 # recursively match redirects 8 return get_view_function(e.new_url, method) 9 except (MethodNotAllowed, NotFound): 10 # no match 11 return None 12 13 try: 14 # return the view function and arguments 15 return current_app.view_functions[match[0]], match[1] 16 except KeyError: 17 # no view is associated with the endpoint 18 return None
提高查找对应view-function的性能,增加缓存到内存中
1FUNCTION = dict() 2 3def view_function_cache(func): 4 @wraps(func) 5 def _view_function(url, method='GET'): 6 # 避免故意访问 7 if len(FUNCTION) > 100: 8 for k, v in FUNCTION.items(): 9 if v is None: 10 FUNCTION.pop(k) 11 12 key = method + url 13 key = str(hashlib.md5(key.encode("UTF-8")).hexdigest()) 14 if key in FUNCTION: 15 return FUNCTION[key] 16 FUNCTION[key] = func(url, method) 17 return FUNCTION[key] 18 19 return _view_function
这样就可以定义/en/<uri>实际的view_function
1def redirect_en(uri): 2 view_function = get_view_function( 3 "/" + uri, 4 request.method, 5 ) 6 if view_function is None: 7 abort(404) 8 # 注:因为我使用Flask-Babel是根据accept_language来区别不同语言 9 request.environ["HTTP_ACCEPT_LANGUAGE"] = "en-US,en;q=0.5" 10 return view_function[0](**view_function[1])
使用url_map复制并alias路由
原理同Flask URL Processors ,为所有的路由都额外增加/en前缀,并在before_request中匹配到以/en开头的请求就修改对应accept_language信息
1@app.before_request 2def before_request(): 3 if request.path.startswith("/en/"): 4 request.environ["HTTP_ACCEPT_LANGUAGE"] = "en-US,en;q=0.5" 5 6url_map = list(app.url_map.iter_rules()) 7for rule in url_map: 8 app.add_url_rule("/en" + rule.rule, rule.endpoint, alias=True)
咦,感觉这种方式更简单一些,但最好还是能够对一些特殊的路由比如: static, admin, subdomain等进行特殊处理
