Python 如何从webapp2中的cookies/headers/session确定语言?
我想利用webapp2的本地化新功能,该功能还具有特定于语言环境的时间和货币格式 Django有一个很好的函数,名为get_language_from_request,我在完全迁移到webapp2之前使用了它,现在我使用webapp2中的i18n,我可以在使用gettext编写的本地化和编译到我的应用程序可以读取和显示的名为messages.mo的文件之间切换。然后,我确定了以下获得用户语言的方法并确定了其优先级: 1.HTTP GET eg.hl=pt br表示巴西葡萄牙语 2.HTTP会话变量我称之为i18n_语言 3.我应该做饼干,但我不知道怎么做 4.我可以得到HTTP头,在这里我也不清楚,我正在看djnango是如何通过一个方便的Python 如何从webapp2中的cookies/headers/session确定语言?,python,django,google-app-engine,internationalization,webapp2,Python,Django,Google App Engine,Internationalization,Webapp2,我想利用webapp2的本地化新功能,该功能还具有特定于语言环境的时间和货币格式 Django有一个很好的函数,名为get_language_from_request,我在完全迁移到webapp2之前使用了它,现在我使用webapp2中的i18n,我可以在使用gettext编写的本地化和编译到我的应用程序可以读取和显示的名为messages.mo的文件之间切换。然后,我确定了以下获得用户语言的方法并确定了其优先级: 1.HTTP GET eg.hl=pt br表示巴西葡萄牙语 2.HTTP会话变
get\u language\u from\u request
实现的,我以前使用过这个get\u language\u,现在我已经停止导入django,我仍然希望我现在基于webapp2的代码具有这个功能
def get_language_from_request(self, request):
"""
Analyzes the request to find what language the user wants the system to
show. If the user requests a sublanguage where we have a main language, we send
out the main language.
"""
if self.request.get('hl'):
self.session['i18n_language'] = self.request.get('hl')
return self.request.get('hl')
if self.session:
lang_code = self.session.get('i18n_language', None)
if lang_code:
logging.info('language found in session')
return lang_code
lang_code = Cookies(self).get(LANGUAGE_COOKIE_NAME)
if lang_code:
logging.info('language found in cookies')
return lang_code
accept = os.environ.get('HTTP_ACCEPT_LANGUAGE', '')
for accept_lang, unused in self.parse_accept_lang_header(accept):
logging.info('accept_lang:'+accept_lang)
lang_code = accept_lang
return lang_code
我看到django代码是可用的,但我不知道webapp2中的i18n有多大作用。例如,如果pt br没有.mo本地化,其他方言也没有类似的本地化,我是否需要考虑pt br等语言的回退
实际上设置了我可以使用的语言
i18n.get_i18n().set_locale(语言)
我请求您帮助确定获得用户语言的不同方法的优先级,我也想知道您对如何继续实施的想法。或者你认为我可以只使用session变量,而不需要对“完整”的解决方案进行彻底的修改,因为我基本上都是根据地理位置来修改语言的,我现在唯一实际使用的翻译是巴西葡萄牙语和英语,但我希望它能很好地转换为西班牙语、俄语和其他语言,因此,我希望能够切换到用户语言,并至少将其保存到webapp2会话,并了解您对使用cookie和header来获取用户语言的看法
我以前使用的源代码是来自django的si,看起来像这样,我不能再使用它了,因为它被锁定在django.mo文件中,并且特定于django
def get_language_from_request(request):
"""
Analyzes the request to find what language the user wants the system to
show. Only languages listed in settings.LANGUAGES are taken into account.
If the user requests a sublanguage where we have a main language, we send
out the main language.
"""
global _accepted
from django.conf import settings
globalpath = os.path.join(os.path.dirname(sys.modules[settings.__module__].__file__), 'locale')
supported = dict(settings.LANGUAGES)
if hasattr(request, 'session'):
lang_code = request.session.get('django_language', None)
if lang_code in supported and lang_code is not None and check_for_language(lang_code):
return lang_code
lang_code = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME)
if lang_code and lang_code not in supported:
lang_code = lang_code.split('-')[0] # e.g. if fr-ca is not supported fallback to fr
if lang_code and lang_code in supported and check_for_language(lang_code):
return lang_code
accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
for accept_lang, unused in parse_accept_lang_header(accept):
if accept_lang == '*':
break
# We have a very restricted form for our language files (no encoding
# specifier, since they all must be UTF-8 and only one possible
# language each time. So we avoid the overhead of gettext.find() and
# work out the MO file manually.
# 'normalized' is the root name of the locale in POSIX format (which is
# the format used for the directories holding the MO files).
normalized = locale.locale_alias.get(to_locale(accept_lang, True))
if not normalized:
continue
# Remove the default encoding from locale_alias.
normalized = normalized.split('.')[0]
if normalized in _accepted:
# We've seen this locale before and have an MO file for it, so no
# need to check again.
return _accepted[normalized]
for lang, dirname in ((accept_lang, normalized),
(accept_lang.split('-')[0], normalized.split('_')[0])):
if lang.lower() not in supported:
continue
langfile = os.path.join(globalpath, dirname, 'LC_MESSAGES',
'django.mo')
if os.path.exists(langfile):
_accepted[normalized] = lang
return lang
return settings.LANGUAGE_CODE
对每个请求都这样做可以吗?我想我还应该将标题设置为languageself.response.headers['Content-language']=language
根据我的期望,如果我选择使用http头,我可以直接从django获取一些函数,但我不明白它是做什么的,所以也许你可以从django为我解释一下这段代码:
def parse_accept_lang_header(lang_string):
"""
Parses the lang_string, which is the body of an HTTP Accept-Language
header, and returns a list of (lang, q-value), ordered by 'q' values.
Any format errors in lang_string results in an empty list being returned.
"""
result = []
pieces = accept_language_re.split(lang_string)
if pieces[-1]:
return []
for i in range(0, len(pieces) - 1, 3):
first, lang, priority = pieces[i : i + 3]
if first:
return []
priority = priority and float(priority) or 1.0
result.append((lang, priority))
result.sort(lambda x, y: -cmp(x[1], y[1]))
return result
多谢各位
更新
我发现我无法在请求处理程序的initialize函数中使用会话,可能是因为会话对象尚未创建。因此,我将用于从会话I获取语言的代码放在BaseHandler呈现函数中,它似乎可以工作。考虑头部或Cookie值也很好。 我要做的是-我有一个基本的请求处理程序,我的所有请求处理程序都从中继承,然后在这里我有一个常量,其中包含可用的语言,我需要设置每个请求的语言:
import webapp2
from webapp2_extras import i18n
AVAILABLE_LOCALES = ['en_GB', 'es_ES']
class BaseHandler(webapp2.RequestHandler):
def __init__(self, request, response):
""" Override the initialiser in order to set the language.
"""
self.initialize(request, response)
# first, try and set locale from cookie
locale = request.cookies.get('locale')
if locale in AVAILABLE_LOCALES:
i18n.get_i18n().set_locale(locale)
else:
# if that failed, try and set locale from accept language header
header = request.headers.get('Accept-Language', '') # e.g. en-gb,en;q=0.8,es-es;q=0.5,eu;q=0.3
locales = [locale.split(';')[0] for locale in header.split(',')]
for locale in locales:
if locale in AVAILABLE_LOCALES:
i18n.get_i18n().set_locale(locale)
break
else:
# if still no locale set, use the first available one
i18n.get_i18n().set_locale(AVAILABLE_LOCALES[0])
首先,我检查cookie,然后检查头部,如果找不到有效的语言,最后默认为第一种可用语言
要设置cookie,我有一个单独的控制器,看起来像这样:
import base
class Index(base.BaseHandler):
""" Set the language cookie (if locale is valid), then redirect back to referrer
"""
def get(self, locale):
if locale in self.available_locales:
self.response.set_cookie('locale', locale, max_age = 15724800) # 26 weeks' worth of seconds
# redirect to referrer or root
url = self.request.headers.get('Referer', '/')
self.redirect(url)
因此,像www.example.com/locale/en_GB这样的URL会将区域设置更改为en_GB,设置cookie并返回给推荐人(这样做的优点是可以在任何页面上切换语言,并使其保持在同一页面上)
此方法不考虑页眉中区域设置的部分匹配,例如“en”而不是“en_GB”,但鉴于我在应用程序中启用的语言列表是固定的(并且区域设置更改URL硬编码在页脚中),我并不太担心
HTH完全基于fishwebby的答案,经过一些改进和一些设计更改,以下是我的工作:
"""
Use this handler instead of webapp2.RequestHandler to support localization.
Fill the AVAILABLE_LOCALES tuple with the acceptable locales.
"""
__author__ = 'Cristian Perez <http://cpr.name>'
import webapp2
from webapp2_extras import i18n
AVAILABLE_LOCALES = ('en_US', 'es_ES', 'en', 'es')
class LocalizedHandler(webapp2.RequestHandler):
def set_locale_from_param(self):
locale = self.request.get('locale')
if locale in AVAILABLE_LOCALES:
i18n.get_i18n().set_locale(locale)
# Save locale to cookie for future use
self.save_locale_to_cookie(locale)
return True
return False
def set_locale_from_cookie(self):
locale = self.request.cookies.get('locale')
if locale in AVAILABLE_LOCALES:
i18n.get_i18n().set_locale(locale)
return True
return False
def set_locale_from_header(self):
locale_header = self.request.headers.get('Accept-Language') # e.g. 'es,en-US;q=0.8,en;q=0.6'
if locale_header:
locale_header = locale_header.replace(' ', '')
# Extract all locales and their preference (q)
locales = [] # e.g. [('es', 1.0), ('en-US', 0.8), ('en', 0.6)]
for locale_str in locale_header.split(','):
locale_parts = locale_str.split(';q=')
locale = locale_parts[0]
if len(locale_parts) > 1:
locale_q = float(locale_parts[1])
else:
locale_q = 1.0
locales.append((locale, locale_q))
# Sort locales according to preference
locales.sort(key=lambda locale_tuple: locale_tuple[1], reverse=True)
# Find first exact match
for locale in locales:
for available_locale in AVAILABLE_LOCALES:
if locale[0].replace('-', '_').lower() == available_locale.lower():
i18n.get_i18n().set_locale(available_locale)
return True
# Find first language match (prefix e.g. 'en' for 'en-GB')
for locale in locales:
for available_locale in AVAILABLE_LOCALES:
if locale[0].split('-')[0].lower() == available_locale.lower():
i18n.get_i18n().set_locale(available_locale)
return True
# There was no match
return False
def set_locale_default(self):
i18n.get_i18n().set_locale(AVAILABLE_LOCALES[0])
def save_locale_to_cookie(self, locale):
self.response.set_cookie('locale', locale)
def __init__(self, request, response):
"""
Override __init__ in order to set the locale
Based on: http://stackoverflow.com/a/8522855/423171
"""
# Must call self.initialze when overriding __init__
# http://webapp-improved.appspot.com/guide/handlers.html#overriding-init
self.initialize(request, response)
# First, try to set locale from GET parameter (will save it to cookie)
if not self.set_locale_from_param():
# Second, try to set locale from cookie
if not self.set_locale_from_cookie():
# Third, try to set locale from Accept-Language header
if not self.set_locale_from_header():
# Fourth, set locale to first available option
self.set_locale_default()
“”“
使用此处理程序而不是webapp2.RequestHandler来支持本地化。
用可接受的语言环境填充可用的语言环境元组。
"""
__作者:克里斯蒂安·佩雷斯
导入webapp2
从webapp2_附加导入i18n
可用语言环境=('en_-US','es_-es','en','es')
类LocalizedHandler(webapp2.RequestHandler):
def set_locale_from_param(self):
locale=self.request.get('locale')
如果语言环境在可用的语言环境中:
i18n.get_i18n().set_locale(locale)
#将区域设置保存到cookie以备将来使用
self.save_locale_to_cookie(locale)
返回真值
返回错误
def set_locale_from_cookie(self):
locale=self.request.cookies.get('locale')
如果语言环境在可用的语言环境中:
i18n.get_i18n().set_locale(locale)
返回真值
返回错误
def set_locale_来自_标题(自身):
locale_header=self.request.headers.get('Accept-Language')#例如es,en-US;q=0.8,en;q=0.6'
如果区域设置为U头:
locale\u header=locale\u header.replace(“”,“”)
#提取所有区域设置及其首选项(q)
地区=[]例如[('es',1.0),('en-US',0.8),('en',0.6)]
对于locale_标头中的locale_str.split(','):
locale\u parts=locale\u str.split(“;q=”)
语言环境=语言环境\u部分[0]
如果len(区域设置和部件)>1:
locale\u q=float(locale\u部分[1])
其他:
语言环境_q=1.0
append((locale,locale_q))
#根据首选项对区域设置进行排序
排序(key=lambda locale\u tuple:locale\u tuple[1],reverse=True)
#找到第一个完全匹配的
对于区域设置中的区域设置:
对于可用语言环境中的可用语言环境:
如果区域设置为[0]。请替换('-','.'').lower()==availab