Python flask web application with multilanguages support by host and prefix

后端 未结 4 1697
隐瞒了意图╮
隐瞒了意图╮ 2020-12-18 11:24

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

4条回答
  •  旧巷少年郎
    2020-12-18 11:38

    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.

提交回复
热议问题