Repository: django-cms/django-cms

Issue:
CMS_FRONTEND_LANGUAGES does not work as advertised in docs
CMS_FRONTEND_LANGUAGES only limits what's displayed in the language switcher. The other languages are still publicly accessible. http://docs.django-cms.org/en/2.3.1/getting_started/configuration.html#cms-frontend-languages

I think it would me handy to have a setting that disables certain languages from being accessible, while still being able to edit pages in those languages.



Discussion:

Resolving patch:
diff --git a/cms/middleware/multilingual.py b/cms/middleware/multilingual.py
--- a/cms/middleware/multilingual.py
+++ b/cms/middleware/multilingual.py
@@ -1,4 +1,5 @@
 # -*- coding: utf-8 -*-
+from cms.test_utils.util.context_managers import SettingsOverride
 from cms.utils.i18n import get_default_language
 from django.conf import settings
 from django.core.urlresolvers import reverse
@@ -8,8 +9,6 @@
 import urllib
 import urlparse
 
-SUPPORTED = dict(settings.CMS_LANGUAGES)
-
 HAS_LANG_PREFIX_RE = re.compile(r"^/(%s)/.*" % "|".join([re.escape(lang[0]) for lang in settings.CMS_LANGUAGES]))
 
 
@@ -76,32 +75,30 @@ def patch_response(content, pages_root, language):
 
 class MultilingualURLMiddleware(object):
     def get_language_from_request(self, request):
-        changed = False
         prefix = has_lang_prefix(request.path_info)
+        lang = None
         if prefix:
             request.path = "/" + "/".join(request.path.split("/")[2:])
             request.path_info = "/" + "/".join(request.path_info.split("/")[2:])
             t = prefix
-            if t in SUPPORTED:
+            if t in settings.CMS_FRONTEND_LANGUAGES:
                 lang = t
-                if (hasattr(request, "session") and
-                    request.session.get("django_language", None) != lang):
-                    request.session["django_language"] = lang
-                changed = True
-        else:
-            lang = translation.get_language_from_request(request)
-        if not changed:
-            if hasattr(request, "session"):
-                lang = request.session.get("django_language", None)
-                if lang in SUPPORTED and lang is not None:
-                    return lang
-            elif "django_language" in request.COOKIES.keys():
-                lang = request.COOKIES.get("django_language", None)
-                if lang in SUPPORTED and lang is not None:
-                    return lang
-            if not lang:
+        if not lang:
+            languages = []
+            for frontend_lang in settings.CMS_FRONTEND_LANGUAGES:
+                languages.append((frontend_lang,frontend_lang))
+            with SettingsOverride(LANGUAGES=languages):
                 lang = translation.get_language_from_request(request)
-        lang = get_default_language(lang)
+        if not lang:
+            lang = get_default_language()
+        old_lang = None
+        if hasattr(request, "session") and request.session.get("django_language", None):
+            old_lang = request.session["django_language"]
+        if not old_lang and hasattr(request, "COOKIES") and request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME, None):
+            old_lang = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME)
+        if old_lang != lang:
+            if hasattr(request, 'session'):
+                request.session['django_language'] = lang
         return lang
 
     def process_request(self, request):
@@ -114,7 +111,8 @@ def process_response(self, request, response):
         local_middleware = LocaleMiddleware()
         response = local_middleware.process_response(request, response)
         path = unicode(request.path)
-
+        if not hasattr(request, 'session') and request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME) != language:
+            response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language)
         # note: pages_root is assumed to end in '/'.
         #       testing this and throwing an exception otherwise, would probably be a good idea
 


Test patch:
diff --git a/cms/test_utils/cli.py b/cms/test_utils/cli.py
--- a/cms/test_utils/cli.py
+++ b/cms/test_utils/cli.py
@@ -110,6 +110,11 @@ def configure(**extra):
             ('pt-BR', gettext("Brazil")),
             ('nl', gettext("Dutch")),
         ),
+        CMS_FRONTEND_LANGUAGES = (
+            'fr',
+            'de',
+            'nl',
+        ),
         CMS_LANGUAGE_CONF = {
             'de':['fr', 'en'],
             'en':['fr', 'de'],
diff --git a/cms/tests/menu.py b/cms/tests/menu.py
--- a/cms/tests/menu.py
+++ b/cms/tests/menu.py
@@ -267,7 +267,7 @@ def test_language_chooser(self):
         context = self.get_context(path=self.get_page(3).get_absolute_url())
         tpl = Template("{% load menu_tags %}{% language_chooser %}")
         tpl.render(context) 
-        self.assertEqual(len(context['languages']), len(settings.CMS_SITE_LANGUAGES[settings.SITE_ID]))
+        self.assertEqual(len(context['languages']), 2)
         # try a different template and some different args
         tpl = Template("{% load menu_tags %}{% language_chooser 'menu/test_language_chooser.html' %}")
         tpl.render(context) 
diff --git a/cms/tests/middleware.py b/cms/tests/middleware.py
--- a/cms/tests/middleware.py
+++ b/cms/tests/middleware.py
@@ -14,22 +14,24 @@ def test_multilingual_middleware_get_lang_from_request(self):
         
         middle = MultilingualURLMiddleware()
         
-        KLINGON = 'x-klingon'
+        FRENCH = 'fr'
         ELVISH = 'x-elvish'
         
-        with SettingsOverride(CMS_LANGUAGES=((KLINGON, 'Klingon'),)):
+        with SettingsOverride(CMS_LANGUAGES=((FRENCH, 'French'),("it", "Italian")), CMS_FRONTEND_LANGUAGES=(FRENCH,)):
             request = AttributeObject(
                 session={},
-                path_info='/en/whatever',
-                path='/en/whatever'
+                path_info='/it/whatever',
+                path='/it/whatever',
+                COOKIES={},
+                META={},
             )
             result = middle.get_language_from_request(request)
-            self.assertEqual(result, 'en')
+            self.assertEqual(result, 'en')#falls back to default
             
             
             request = AttributeObject(
                 session={
-                    'django_language': KLINGON,
+                    'django_language': FRENCH,
                 },
                 path_info='whatever',
                 path='whatever',
@@ -37,19 +39,19 @@ def test_multilingual_middleware_get_lang_from_request(self):
                 META={},
             )
             result = middle.get_language_from_request(request)
-            self.assertEqual(result, KLINGON) # the session's language. Nerd.
+            self.assertEqual(result, FRENCH) # the session's language.
             
             
             request = AttributeObject(
                 path_info='whatever',
                 path='whatever',
                 COOKIES={
-                    'django_language': KLINGON,
+                    'django_language': FRENCH,
                 },
                 META={},
             )
             result = middle.get_language_from_request(request)
-            self.assertEqual(result, KLINGON) # the cookies language.
+            self.assertEqual(result, FRENCH) # the cookies language.
             
             # Now the following should revert to the default language (en)
             request.COOKIES['django_language'] = ELVISH
@@ -60,18 +62,18 @@ def test_multilingual_middleware_get_lang_from_request(self):
     def test_multilingual_middleware_ignores_static_url(self):
 
         middle = MultilingualURLMiddleware()
-        KLINGON = 'x-klingon'
+        FRENCH = 'x-FRENCH'
         
-        with SettingsOverride(CMS_LANGUAGES=((KLINGON, 'Klingon'),)):
+        with SettingsOverride(CMS_LANGUAGES=((FRENCH, 'FRENCH'),)):
             request = AttributeObject(
                 session={},
                 path_info='whatever',
                 path='whatever',
                 COOKIES={
-                    'django_language': KLINGON,
+                    'django_language': FRENCH,
                 },
                 META = {},
-                LANGUAGE_CODE = KLINGON
+                LANGUAGE_CODE = FRENCH
             )
             html = """<ul>
                 <li><a href="/some-page/">some page</a></li>
@@ -89,8 +91,8 @@ def test_multilingual_middleware_ignores_static_url(self):
             response = middle.process_response(request,HttpResponse(html))
             
             # These paths shall be prefixed
-            self.assertTrue('href="/%s/some-page/' %KLINGON in response.content)
-            self.assertTrue('href="/%s%simages/some-other-file.jpg' %(KLINGON, '/some-path/') in response.content)
+            self.assertTrue('href="/%s/some-page/' %FRENCH in response.content)
+            self.assertTrue('href="/%s%simages/some-other-file.jpg' %(FRENCH, '/some-path/') in response.content)
 
             # These shall not
             self.assertTrue('href="%simages/some-media-file.jpg' %settings.MEDIA_URL in response.content)