如何从webapp2的cookie /标题/会话中确定语言?
问题内容:
我想利用webapp2的新功能进行本地化,该功能还具有针对时间和货币的特定于语言环境的格式。
Django有一个很好的函数,称为get_language_from_request,在我完全迁移到webapp2之前,我已经使用了它,现在我使用的是来自webapp2的i18n,我可以在用gettext编写的本地化之间切换,并编译到名为messages.mo的文件中,我的应用程序可以阅读和显示。然后,我确定并优先考虑了以下几种获取用户语言的方法:1.
HTTP GET例如。hl = pt-br代表巴西葡萄牙语。2. HTTP
SESSION变量,我叫i18n_language。3.应该设置并获取Cookie,但我不知道该怎么做。4.我可以得到的HTTP标头,在这里我也不知道。我正在寻找djnango如何get_language_from_request
使用我以前使用的便捷方式完成操作,现在我不再导入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有多少功能,如果没有.mo本地化版本,我是否需要回退,因为pt-br等语言应回退到pt
pt-br和其他方言类似。
实际设置我可以使用的语言
i18n.get_i18n().set_locale(language)
我要求您提供帮助,以优先考虑获取用户语言的各种方式,并且我也想知道您的想法如何继续实施。还是您认为我可以只使用会话变量来完成操作,而不能对“完整”的解决方案那么周全,因为我无论如何都主要针对地理使用来修复语言,因为现在我唯一实际使用的翻译是巴西葡萄牙语和英语,但我想要它也准备好切换到西班牙语和俄语以及其他语言,因此,我希望能够切换到用户语言并将其至少保存到webapp2会话中,并且知道您对使用cookie和标头获取用户的想法语言。
我以前从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
是否可以针对每个请求执行此操作?我想我也应该将标题设置为语言self.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函数中使用会话,可能是因为尚未创建会话对象。因此,我在BaseHandler渲染函数中放置了用于从会话中获取语言的代码,它似乎可以正常工作。考虑标题或cookie值也很不错。
问题答案:
这是我的工作-
我有一个基本请求处理程序,所有请求处理程序都继承自该请求处理程序,然后在这里有一个包含可用语言的常量,并且我重写了init方法来为每个请求设置语言:
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”,但由于我在应用程序中启用的语言列表是固定的(语言环境更改网址很难在页脚中编码),我不太担心。
高温超导