1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
# ------------------------------------------------------------------------
# coding=utf-8
# ------------------------------------------------------------------------
"""
This extension adds a language field to every page. When calling setup_request,
the page's language is activated.
Pages in secondary languages can be said to be a translation of a page in the
primary language (the first language in settings.LANGUAGES), thereby enabling
deeplinks between translated pages.
It is recommended to activate :class:`django.middleware.locale.LocaleMiddleware`
so that the correct language will be activated per user or session even for
non-FeinCMS managed views such as Django's administration tool.
"""
# ------------------------------------------------------------------------
import logging
from django.conf import settings as django_settings
from django.db import models
from django.http import HttpResponseRedirect
from django.utils import translation
from django.utils.translation import ugettext_lazy as _
from feincms import settings
from feincms.translations import is_primary_language
from feincms._internal import monkeypatch_method, monkeypatch_property
# ------------------------------------------------------------------------
logger = logging.getLogger(__name__)
# ------------------------------------------------------------------------
def user_has_language_set(request):
"""
Determine whether the user has explicitely set a language earlier on.
This is taken later on as an indication that we should not mess with the
site's language settings, after all, the user's decision is what counts.
"""
if hasattr(request, 'session') and request.session.get('django_language') is not None:
return True
if django_settings.LANGUAGE_COOKIE_NAME in request.COOKIES:
return True
return False
# ------------------------------------------------------------------------
def translation_set_language(request, select_language):
"""
Set and activate a language, if that language is available.
"""
if translation.check_for_language(select_language):
fallback = False
else:
# The page is in a language that Django has no messages for.
# We display anyhow, but fall back to primary language for
# other messages and other applications. It is *highly* recommended to
# create a new django.po for the language instead of
# using this behaviour.
select_language = django_settings.LANGUAGES[0][0]
fallback = True
translation.activate(select_language)
request.LANGUAGE_CODE = translation.get_language()
if hasattr(request, 'session'):
# User has a session, then set this language there
if select_language != request.session.get('django_language'):
request.session['django_language'] = select_language
elif request.method == 'GET' and not fallback:
# No session is active. We need to set a cookie for the language
# so that it persists when the user changes his location to somewhere
# not under the control of the CMS.
# Only do this when request method is GET (mainly, do not abort
# POST requests)
response = HttpResponseRedirect(request.get_full_path())
response.set_cookie(django_settings.LANGUAGE_COOKIE_NAME, select_language)
return response
# ------------------------------------------------------------------------
def translations_request_processor_explicit(page, request):
# If this page is just a redirect, don't do any language specific setup
if page.redirect_to:
return
# Until further notice, the user might be wanting to switch to the
# page's language...
desired_language = page.language
# ...except if the user explicitely wants to switch language
if 'set_language' in request.GET:
desired_language = request.GET['set_language']
# ...or the user already has explicitely set a language, bail out and
# don't change it for him behind her back
elif user_has_language_set(request):
return
return translation_set_language(request, desired_language)
# ------------------------------------------------------------------------
def translations_request_processor_standard(page, request):
# If this page is just a redirect, don't do any language specific setup
if page.redirect_to:
return
if page.language == translation.get_language():
return
return translation_set_language(request, page.language)
# ------------------------------------------------------------------------
def get_current_language_code(request):
language_code = getattr(request, 'LANGUAGE_CODE', None)
if language_code is None:
logger.warning("Could not access request.LANGUAGE_CODE. Is 'django.middleware.locale.LocaleMiddleware' in MIDDLEWARE_CLASSES?")
return language_code
# ------------------------------------------------------------------------
def register(cls, admin_cls):
cls.add_to_class('language', models.CharField(_('language'), max_length=10,
choices=django_settings.LANGUAGES, default=django_settings.LANGUAGES[0][0]))
cls.add_to_class('translation_of', models.ForeignKey('self',
blank=True, null=True, verbose_name=_('translation of'),
related_name='translations',
limit_choices_to={'language': django_settings.LANGUAGES[0][0]},
help_text=_('Leave this empty for entries in the primary language.')
))
if hasattr(cls, 'register_request_processor'):
if settings.FEINCMS_TRANSLATION_POLICY == "EXPLICIT":
cls.register_request_processor(translations_request_processor_explicit,
key='translations')
else: # STANDARD
cls.register_request_processor(translations_request_processor_standard,
key='translations')
if hasattr(cls, 'get_redirect_to_target'):
@monkeypatch_method(cls)
def get_redirect_to_target(self, request):
"""
Find an acceptable redirect target. If this is a local link, then try
to find the page this redirect references and translate it according
to the user's language. This way, one can easily implement a localized
"/"-url to welcome page redirection.
"""
target = self.redirect_to
if target and target.find('//') == -1: # Not an offsite link http://bla/blubb
try:
page = cls.objects.page_for_path(target)
page = page.get_translation(get_current_language_code(request))
target = page.get_absolute_url()
except cls.DoesNotExist:
pass
return target
@monkeypatch_method(cls)
def available_translations(self):
if not self.id: # New, unsaved pages have no translations
return []
if is_primary_language(self.language):
return self.translations.all()
elif self.translation_of:
return [self.translation_of] + list(self.translation_of.translations.exclude(
language=self.language))
else:
return []
@monkeypatch_method(cls)
def get_original_translation(self, *args, **kwargs):
if is_primary_language(self.language):
return self
return self.translation_of
@monkeypatch_property(cls)
def original_translation(self):
return self.get_original_translation()
@monkeypatch_method(cls)
def get_translation(self, language):
return self.original_translation.translations.get(language=language)
def available_translations_admin(self, page):
translations = dict((p.language, p.id) for p in page.available_translations())
links = []
for key, title in django_settings.LANGUAGES:
if key == page.language:
continue
if key in translations:
links.append(u'<a href="%s/" title="%s">%s</a>' % (
translations[key], _('Edit translation'), key.upper()))
else:
links.append(u'<a style="color:#baa" href="add/?translation_of=%s&language=%s" title="%s">%s</a>' % (
page.id, key, _('Create translation'), key.upper()))
return u' | '.join(links)
available_translations_admin.allow_tags = True
available_translations_admin.short_description = _('translations')
admin_cls.available_translations_admin = available_translations_admin
if hasattr(admin_cls, 'add_extension_options'):
admin_cls.add_extension_options('language', 'translation_of')
admin_cls.list_display.extend(['language', 'available_translations_admin'])
admin_cls.list_filter.extend(['language'])
admin_cls.raw_id_fields.append('translation_of')
# ------------------------------------------------------------------------
# ------------------------------------------------------------------------
|