Веб-приложение с флагом Python с поддержкой нескольких языков хостом и префиксом

У меня есть один экземпляр с флеш-приложением и имеет несколько доменов, которые отображаются на этом сервере 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</lang> и перезагрузил функцию 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)

И я не вижу решения для этого. Я считаю, что моя реализация плохая, и я должен ее улучшить. Я думаю, что я должен создать один экземпляр приложения для каждого корня языка сайта с предопределенным языком для него или использовать план, но пока не нашел решения для меня.

Кто-нибудь может дать мне совет, как разрешить эту поддержку мультиязыков с флягой или wsgi или nginx?

4 ответа

Мое собственное решение:

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')
</any(%s):_lang></any(%s):_lang>

Я не использую чертежи там, потому что я также использую flask-login, и я не могу установить несколько страниц входа с разными языками для каждого проекта. Например, если для входа требуется страница, флажок перенаправляет меня на страницу входа, и я должен обновить язык для этой страницы. Также страницы входа не могут быть как mysite.com/login, mysite.com/fr/login и т.д. Без нескольких перенаправлений.

UPD: Я не могу использовать request.view_args для определения языка или перенаправления, потому что в этом случае я не могу определить язык для страниц ошибок как mysite.com/fr/wrong-page-there (не могу обнаружить endpoint и view_args). Чтобы избежать этой проблемы, я могу использовать hask: добавить правило url как /<lang_code>/</lang_code> и вызвать там ошибку 404.


Это в официальном документе: http://flask.pocoo.org/docs/patterns/urlprocessors/ (Это в основном тот же ответ, что и у Мэтью Скрагга).


Отказ от ответственности: этот код не проверен. Я просто даю вам представление о том, как подойти к этому.

Я предлагаю вам использовать чертежи в сочетании с расширением, например Flask-Babel. Например, вы можете сделать что-то вроде:

views.py

mysitebp = *********('mysitebp',__name__)

Затем в вашем пакете приложений (обычно __init__.py) вы можете сделать:

__init__.py

from mysite.views import mysitebp
app = Flask(__name__)
app.******************(mysitebp,url_prefix='/en/',template_folder='en')
app.******************(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 и т.д.


Я работал над чем-то похожим несколько месяцев назад. Я немного изменил его и нажал на github. Вы можете сделать то, что предложили codegeek, если вы не можете сделать свой шаблонный язык нейтральным. С помощью этого метода вы можете сократить необходимые файлы шаблонов.

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

mysite.py

from flask import Flask, *********, g, redirect, request
app = Flask(__name__)
mod = *********('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.******************(mod)
</lang_code>

tests.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()

licensed under cc by-sa 3.0 with attribution.