3

我有一台带有烧瓶应用程序实例的服务器,并且有几个域通过 DNS 映射到该服务器。

我的网站必须通过主机和前缀支持多种语言:

mysite.com - english
mysite.com/fr - franch
mysite.ru - russian
mysite.ru/by - belarusian
localhost or other unknown host without language prefix - default language (english)

我通过双重路由注册/endpoint/<lang>/endpoint重新加载url_for功能实现了它,它可以工作,但现在我必须为abort功能实现自定义错误页面:

mysite.com/wrong-url-there - mysite.com/404.html (english)
mysite.com/fr/wrong-url-there - mysite.com/fr/404.html (franch)
mysite.ru/wrong-url-there - mysite.ru/404.html (russian)
mysite.ru/by/wrong-url-there - mysite.ru/by/404.html (belorusian)

而且我没有看到解决方案。我认为我的实施很糟糕,我必须改进它。我想我必须为每个站点语言根创建一个应用程序实例,并为其预定义语言或使用蓝图,但我还没有找到适合我的解决方案。

有人可以给我建议如何用flask或wsgi或nginx解决这个url多语言支持吗?

4

4 回答 4

4

It's in the official doc: http://flask.pocoo.org/docs/patterns/urlprocessors/ (This is basically the same answer as Matthew Scragg's).

于 2013-04-12T10:27:12.430 回答
3

几个月前我做过类似的事情。我对其进行了一些修改并推送到了 github。如果您无法使模板语言中立,您可以执行 codegeek 建议的操作。使用这种方法,您可以减少所需的模板文件。

https://github.com/scragg0x/Flask-Localisation-Example

我的网站.py

from flask import Flask, Blueprint, g, redirect, request

app = Flask(__name__)

mod = Blueprint('mysite', __name__, url_prefix='/<lang_code>')

sites = {
    'mysite.com': 'en',
    'myothersite.com': 'fr'
}

@app.url_defaults
def add_language_code(endpoint, values):
    values.setdefault('lang_code', g.lang_code)

@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
    url = request.url.split('/', 3)
    g.lang_code = sites[url[2]]

@mod.url_defaults
def add_language_code(endpoint, values):
    values.setdefault('lang_code', g.lang_code)

@mod.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code')

@app.route('/')
@mod.route('/')
def index():
    # Use g.lang_code to pull localized data for template
    return 'lang = %s' % g.lang_code

app.register_blueprint(mod)

测试.py

import os
import unittest
import re
import requests
import urllib2
import json
from mysite import app

class MySiteTestCase(unittest.TestCase):

    def setUp(self):
        app.config['TESTING'] = True
        app.config['SERVER_NAME'] = 'mysite.com'
        self.domain = 'http://mysite.com/'
        self.app = app.test_client()

    def tearDown(self):
        pass

    def test_en_index(self):
        rv = self.app.get('/en/', self.domain)
        self.assertEqual(rv.data, 'lang = en')
        print self.domain, rv.data

    def test_fr_index(self):
        rv = self.app.get('/fr/', self.domain)
        self.assertEqual(rv.data, 'lang = fr')
        print self.domain, rv.data

    def test_default(self):
        rv = self.app.get('/', self.domain)
        self.assertEqual(rv.data, 'lang = en')
        print self.domain, rv.data

class MyOtherSiteTestCase(unittest.TestCase):

    def setUp(self):
        app.config['TESTING'] = True
        app.config['SERVER_NAME'] = 'myothersite.com'
        self.domain = 'http://myothersite.com/'
        self.app = app.test_client()

    def tearDown(self):
        pass

    def test_en_index(self):
        rv = self.app.get('/en/', self.domain)
        self.assertEqual(rv.data, 'lang = en')
        print self.domain, rv.data

    def test_fr_index(self):
        rv = self.app.get('/fr/', self.domain)
        self.assertEqual(rv.data, 'lang = fr')
        print self.domain, rv.data

    def test_default(self):
        rv = self.app.get('/', self.domain)
        self.assertEqual(rv.data, 'lang = fr')
        print self.domain, rv.data

if __name__ == '__main__':
    unittest.main()
于 2013-02-07T04:57:43.387 回答
2

免责声明:此代码未经测试。我只是给你一个关于如何处理这个问题的大致想法。

我建议您将蓝图与Flask-Babel 之类的扩展结合使用。例如,您可以执行以下操作:

views.py

mysitebp = Blueprint('mysitebp',__name__)

然后在您的应用程序包(通常__init__.py)中,您可以执行以下操作:

__init__.py

from mysite.views import mysitebp
app = Flask(__name__)
app.register_blueprint(mysitebp,url_prefix='/en/',template_folder='en')
app.register_blueprint(mysitebp,url_prefix='/fr',template_folder='fr')

..等等

您的目录结构可能如下所示:

mysite/
__init__.py
views.py
templates/
    base.html
    404.html
    en/
        en.html
    fr/
        french.html

Flask-Babel 会帮你翻译 404.html 等。

于 2013-02-04T14:49:52.193 回答
0

我自己的解决方案:

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('/<any(%s):_lang>/' % languages)
def home():
    return render_template('home.html')


@app.route('/other/')
@app.route('/<any(%s):_lang>/other/' % languages)
def other():
    return render_template('other.html')

我不在那里使用蓝图,因为我也使用flask-login并且我无法为每个蓝图设置多个使用不同语言的登录页面。例如,如果页面需要登录,flask 将我重定向到登录页面,我必须更新此页面的语言。mysite.com/login如果没有多次重定向,登录页面也不能是 asmysite.com/fr/login等。

UPD:我不能request.view_args用于检测语言或重定向,因为在这种情况下,我无法将错误页面的语言检测为mysite.com/fr/wrong-page-there(无法检测endpointview_args)。为了避免这个问题,我可以使用 hask: add url rule as/<lang_code>/<path:path>并在此处引发 404 错误。

于 2013-02-19T13:36:44.107 回答