#
# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
__docformat__ = 'restructuredtext'
from persistent import Persistent
from zope.container.contained import Contained
from zope.i18n.interfaces import INegotiator as IZopeNegotiator
from zope.i18n.locales import locales
from zope.interface import Interface, implementer
from zope.schema.fieldproperty import FieldProperty
from zope.traversing.interfaces import ITraversable
from pyams_i18n.interfaces import INegotiator, LANGUAGE_CACHE_KEY
from pyams_skin.layer import IPyAMSUserLayer
from pyams_utils.adapter import ContextRequestAdapter, adapter_config
from pyams_utils.i18n import get_browser_language
from pyams_utils.registry import get_global_registry, query_utility, utility_config
[docs]@implementer(INegotiator)
class Negotiator(Persistent, Contained):
"""Language negotiator utility"""
policy = FieldProperty(INegotiator['policy'])
server_language = FieldProperty(INegotiator['server_language'])
offered_languages = FieldProperty(INegotiator['offered_languages'])
cache_enabled = FieldProperty(INegotiator['cache_enabled'])
[docs] def get_language(self, request):
"""See :intf:`INegotiator`"""
# lang parameter, if defined, is of higher priority
if 'lang' in request.params:
return request.params['lang']
policies = self.policy.split(' --> ')
for policy in policies:
# check server policy
if policy == 'server':
if self.server_language:
return self.server_language
# check session policy
elif policy == 'session':
if self.cache_enabled:
try:
cached = request.annotations[LANGUAGE_CACHE_KEY]
return cached
except AttributeError:
return self.server_language
except KeyError:
session = request.session
lang = session.get('language')
if lang is not None:
request.annotations[LANGUAGE_CACHE_KEY] = lang
return lang
else:
session = request.session
lang = session.get('language')
if lang is not None:
return lang
# check browser policy
elif policy == 'browser':
lang = get_browser_language(request)
if lang is not None:
return lang
return None
[docs] def clear_cache(self, request):
"""Clear cached language value"""
try:
del request.annotations[LANGUAGE_CACHE_KEY]
except KeyError:
pass
[docs]@adapter_config(name='lang', context=(Interface, IPyAMSUserLayer), provides=ITraversable)
class LangNamespaceTraverser(ContextRequestAdapter):
"""++lang++ namespace traverser
This traverser is mainly used for backward compatibility with previous Zope 3 websites.
"""
[docs] def traverse(self, name, furtherpath=None):
if name != '*':
self.request.GET['lang'] = name
return self.context
[docs]def locale_negotiator(request):
"""Negotiate language based on server, browser, request and user settings
Locale is extracted from request's "lang" parameter, from browser settings or from
negotiator utility
"""
negotiator = query_utility(INegotiator)
if negotiator is not None:
locale_name = negotiator.get_language(request)
else:
locale_name = get_browser_language(request)
if not locale_name:
registry = get_global_registry()
locale_name = registry.settings.get('pyramid.default_locale_name', 'en')
if '-' in locale_name:
# remove 'sub-locale' to prevent Babel and Zope exceptions for unknown locales
locale_name = locale_name.split('-')[0]
return locale_name
[docs]def get_locale(request):
"""Get zope.i18n "locale" attribute"""
return locales.getLocale(request.locale_name)
[docs]@utility_config(provides=IZopeNegotiator)
class ZopeNegotiator(object):
"""Zope language negotiator"""
[docs] def getLanguage(self, langs, env):
return locale_negotiator(env)