File: translations.py

package info (click to toggle)
python-django-feincms 1.6.2-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 2,716 kB
  • sloc: python: 6,585; makefile: 85; sh: 18
file content (212 lines) | stat: -rw-r--r-- 9,052 bytes parent folder | download
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&amp;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')

# ------------------------------------------------------------------------
# ------------------------------------------------------------------------