I have one server with flask application instance and have several domain which mapped to this server by DNS.
My site must support several languages by host and pref
My own solution:
from flask import Flask, g, render_template, redirect, request
app = Flask(__name__)
default_language = 'en'
language_urls = {
'en': 'mysite.com',
'fr': 'mysite.com/fr',
'ru': 'mysite.ru',
'by': 'mysite.ru/by',
}
languages = ','.join(language_urls.keys())
def get_language_by_request(request_host, request_path):
'''
Looking bad, but work.
I cab't use request.view_args there,
because this can't detect language for 404 pages
like mysite.com/fr/unknown-page
'''
request_host_path = request_host + request_path
request_paths = request_host_path.split('/', 2)
if (len(request_paths) > 1 and request_paths[1] in language_urls.keys()):
request_language_prefix = request_paths[1]
return request_language_prefix
for language, url in language_urls.items():
host_prefix = url.split('/')
if len(host_prefix) == 1:
host, = host_prefix
if request_host == host:
return language
return default_language
def get_language_url_parameter_value(language, request_host):
host_prefix = language_urls[language]
if host_prefix == request_host:
return None
return language
def get_redirection_url_by_request(request_host, request_path, request_url):
'''
Looking bad, but work.
I cab't use request.view_args there,
because this can't detect language for 404 pages
like mysite.com/fr/unknown-page
'''
request_host_path = request_host + request_path
request_paths = request_host_path.split('/', 2)
request_language_prefix = None
if (len(request_paths) > 1 and request_paths[1] in language_urls.keys()):
request_language_prefix = request_paths[1]
hosts = []
for language, url in language_urls.items():
host_prefix = url.split('/')
if len(host_prefix) == 1:
host, = host_prefix
language_prefix = None
else:
host, language_prefix = host_prefix
if request_host == host and request_language_prefix == language_prefix:
return None
hosts.append(host)
if request_host not in hosts:
return None
if request_language_prefix:
request_host_prefix = request_host + '/' + request_language_prefix
host_prefix = language_urls[request_language_prefix]
return request_url.replace(request_host_prefix, host_prefix)
return None
@app.url_defaults
def set_language_in_url(endpoint, values):
if '_lang' not in values and hasattr(g, 'language_url_value'):
values['_lang'] = g.language_url_value
@app.url_value_preprocessor
def get_language_from_url(endpoint, values):
g.language = get_language_by_request(request.host, request.path)
g.language_url_value = get_language_url_parameter_value(g.language, request.host)
if values and '_lang' in values:
del values['_lang']
@app.before_request
def check_language_redirection():
redirection_url = get_redirection_url_by_request(request.host, request.path, request.url)
return redirect(redirection_url) if redirection_url else None
@app.route('/')
@app.route('//' % languages)
def home():
return render_template('home.html')
@app.route('/other/')
@app.route('//other/' % languages)
def other():
return render_template('other.html')
I don't use blueprints there because I also use flask-login and I can't set several login pages with different languages for each blueprint. For example if page required login, flask redirect me to login page and I must update language for this page. Also login pages can't be as mysite.com/login, mysite.com/fr/login and etc without several redirections.
UPD: I can't use request.view_args for detect language or redirection, because on this case I can't detect language for error pages as mysite.com/fr/wrong-page-there (can't detect endpoint and view_args). To avoid this problem I can use hask: add url rule as / and raise 404 error there.