Permalink
Browse files

Merge pull request #1414 from digi604/new_i18n

Removes Multilingual Middleware and updates the i18n configuration of the cms. CMS_LANGUAGES has been completely overhauled and all the old i18n settings removed.
  • Loading branch information...
2 parents 987d7de + 237609f commit 4b968ce1ff5715f5011bd6d622a84be453977f46 @digi604 committed Oct 3, 2012
Showing with 1,623 additions and 1,231 deletions.
  1. +3 −3 .travis.yml
  2. +1 −0 AUTHORS
  3. +10 −0 CHANGELOG.txt
  4. +4 −9 cms/admin/forms.py
  5. +7 −17 cms/admin/pageadmin.py
  6. +3 −2 cms/api.py
  7. +2 −1 cms/app_base.py
  8. +1 −1 cms/apphook_pool.py
  9. +69 −55 cms/appresolver.py
  10. +1 −1 cms/cms_toolbar.py
  11. +7 −6 cms/conf/__init__.py
  12. +32 −21 cms/conf/global_settings.py
  13. +130 −19 cms/conf/patch.py
  14. +18 −3 cms/exceptions.py
  15. +3 −3 cms/menu.py
  16. +0 −149 cms/middleware/multilingual.py
  17. +15 −2 cms/middleware/page.py
  18. +0 −41 cms/models/__init__.py
  19. +2 −2 cms/models/pagemodel.py
  20. +3 −2 cms/models/pluginmodel.py
  21. +1 −1 cms/models/titlemodels.py
  22. +1 −1 cms/plugin_rendering.py
  23. +1 −1 cms/plugins/inherit/cms_plugins.py
  24. +2 −2 cms/plugins/inherit/models.py
  25. +11 −2 cms/plugins/utils.py
  26. +4 −4 cms/templatetags/cms_admin.py
  27. +66 −28 cms/test_utils/cli.py
  28. +10 −1 cms/test_utils/project/nonroot_urls.py
  29. +13 −1 cms/test_utils/project/sampleapp/cms_app.py
  30. BIN cms/test_utils/project/sampleapp/media/sampleapp/img/gift.jpg
  31. +9 −0 cms/test_utils/project/sampleapp/ns_urls.py
  32. +2 −0 cms/test_utils/project/sampleapp/templates/sampleapp/app.html
  33. +1 −1 cms/test_utils/project/sampleapp/templates/sampleapp/category_view.html
  34. +8 −4 cms/test_utils/project/sampleapp/templates/sampleapp/home.html
  35. +2 −1 cms/test_utils/project/sampleapp/urls.py
  36. +5 −0 cms/test_utils/project/sampleapp/views.py
  37. +7 −0 cms/test_utils/project/second_urls_for_apphook_tests.py
  38. +18 −6 cms/test_utils/project/urls.py
  39. +8 −0 cms/test_utils/project/urls_for_apphook_tests.py
  40. +3 −1 cms/test_utils/testcases.py
  41. +0 −1 cms/tests/__init__.py
  42. +232 −69 cms/tests/apphooks.py
  43. +25 −17 cms/tests/menu.py
  44. +1 −1 cms/tests/menu_page_viewperm.py
  45. +6 −6 cms/tests/menu_page_viewperm_staff.py
  46. +17 −2 cms/tests/menu_utils.py
  47. +0 −132 cms/tests/middleware.py
  48. +115 −59 cms/tests/multilingual.py
  49. +1 −1 cms/tests/nested_plugins.py
  50. +10 −22 cms/tests/nonroot.py
  51. +19 −17 cms/tests/page.py
  52. +16 −6 cms/tests/permmod.py
  53. +0 −45 cms/tests/rendering.py
  54. +5 −3 cms/tests/reversion_tests.py
  55. +4 −4 cms/tests/site.py
  56. +14 −12 cms/tests/templatetags.py
  57. +1 −1 cms/tests/toolbar.py
  58. +13 −23 cms/tests/views.py
  59. +1 −2 cms/urls.py
  60. +4 −5 cms/utils/__init__.py
  61. +2 −7 cms/utils/admin.py
  62. +124 −24 cms/utils/i18n.py
  63. +10 −8 cms/utils/page.py
  64. +14 −5 cms/utils/page_resolver.py
  65. +63 −38 cms/views.py
  66. +33 −92 docs/advanced/i18n.rst
  67. +8 −78 docs/concepts/multiple_languages.rst
  68. +69 −25 docs/extending_cms/app_integration.rst
  69. +89 −54 docs/getting_started/configuration.rst
  70. +2 −0 docs/getting_started/installation.rst
  71. +6 −4 docs/getting_started/tutorial.rst
  72. +1 −0 docs/index.rst
  73. +152 −0 docs/upgrade/2.4.rst
  74. +1 −7 menus/base.py
  75. +5 −2 menus/templates/menu/language_chooser.html
  76. +14 −0 menus/templatetags/i18n_compat.py
  77. +16 −37 menus/templatetags/menu_tags.py
  78. +22 −9 menus/utils.py
  79. +19 −19 runtestserver.py
  80. +3 −1 test_requirements/django-1.3.txt
  81. +2 −1 test_requirements/django-1.4.txt
  82. +1 −1 test_requirements/requirements_base.txt
View
@@ -4,10 +4,10 @@ python:
- "2.6"
- "2.7"
env:
- - DJANGO="django>=1.3,<1.4"
- - DJANGO="django>=1.4,<1.5"
+ - DJANGO=test_requirements/django-1.3.txt
+ - DJANGO=test_requirements/django-1.4.txt
install:
- - pip install -q $DJANGO django-mptt==0.5.1 django-reversion==1.6 django-classy-tags==0.3.4.1 django-sekizai==0.6.1 html5lib==0.95 jinja2==2.6 PIL==1.1.7 pygments==1.5 south==0.7.5 sphinx==1.1.3 argparse
+ - pip install -q -r $DJANGO --use-mirrors
script:
python runtests.py
notifications:
View
@@ -92,6 +92,7 @@ Contributors (in alphabetical order):
* Ian Lewis
* indexofire
* Ionel Cristian Maries
+* Iván Raskovsky
* Ivan Vershigora
* izi
* Jameel Al-Aziz
View
@@ -110,6 +110,16 @@
- fixed an incompatibility with Python 2.5
+==== 2.4.0 ===-
+
+- CMS_LANGUAGE setting has changed
+- CMS_HIDE_UNTRANSLATED setting removed
+- CMS_LANGUAGE_FALLBACK setting removed
+- CMS_LANGUAGE_CONF setting removed
+- CMS_SITE_LANGUAGES setting removed
+- CMS_FRONTEND_LANGUAGES setting removed
+- MultilingualMiddleware has been removed
+
View
@@ -3,6 +3,7 @@
from cms.forms.widgets import UserSelectAdminWidget
from cms.models import (Page, PagePermission, PageUser, ACCESS_PAGE,
PageUserGroup)
+from cms.utils.i18n import get_language_tuple, get_language_list
from cms.utils.mail import mail_page_user_change
from cms.utils.page import is_valid_page_slug
from cms.utils.page_resolver import get_page_from_path, is_valid_url
@@ -60,7 +61,7 @@ class PageAddForm(forms.ModelForm):
help_text=_('The default title'))
slug = forms.CharField(label=_("Slug"), widget=forms.TextInput(),
help_text=_('The part of the title that is used in the URL'))
- language = forms.ChoiceField(label=_("Language"), choices=settings.CMS_LANGUAGES,
+ language = forms.ChoiceField(label=_("Language"), choices=get_language_tuple(),
help_text=_('The current language of the content fields.'))
class Meta:
@@ -74,13 +75,7 @@ def __init__(self, *args, **kwargs):
if not self.fields['site'].initial:
self.fields['site'].initial = Site.objects.get_current().pk
site_id = self.fields['site'].initial
- languages = []
- language_mappings = dict(settings.LANGUAGES)
- if site_id in settings.CMS_SITE_LANGUAGES:
- for lang in settings.CMS_SITE_LANGUAGES[site_id]:
- languages.append((lang, language_mappings.get(lang, lang)))
- else:
- languages = settings.CMS_LANGUAGES
+ languages = get_language_tuple(site_id)
self.fields['language'].choices = languages
if not self.fields['language'].initial:
self.fields['language'].initial = get_language()
@@ -139,7 +134,7 @@ def clean_slug(self):
def clean_language(self):
language = self.cleaned_data['language']
- if not language in dict(settings.CMS_LANGUAGES).keys():
+ if not language in get_language_list():
raise ValidationError("Given language does not match language settings.")
return language
View
@@ -17,6 +17,7 @@
from cms.utils import (copy_plugins, helpers, moderator, permissions, plugins,
get_template_from_request, get_language_from_request,
placeholder as placeholder_utils, admin as admin_utils, cms_static_url)
+from cms.utils.i18n import get_language_dict, get_language_list, get_language_tuple, get_language_object
from cms.utils.page_resolver import is_valid_url
from cms.utils.admin import jsonify_request
from cms.utils.permissions import has_plugin_permission
@@ -441,13 +442,13 @@ def get_form(self, request, obj=None, **kwargs):
installed_plugins = plugin_pool.get_all_plugins(placeholder_name, obj)
plugin_list = CMSPlugin.objects.filter(language=language, placeholder=placeholder, parent=None).order_by('position')
other_plugins = CMSPlugin.objects.filter(placeholder=placeholder, parent=None).exclude(language=language)
- dict_cms_languages = dict(settings.CMS_LANGUAGES)
+ dict_cms_languages = get_language_dict()
for plugin in other_plugins:
if (not plugin.language in copy_languages) and (plugin.language in dict_cms_languages):
copy_languages[plugin.language] = dict_cms_languages[plugin.language]
language = get_language_from_request(request, obj)
- if copy_languages and len(settings.CMS_LANGUAGES) > 1:
+ if copy_languages and len(get_language_list()) > 1:
show_copy = True
widget = PluginEditor(attrs={
'installed': installed_plugins,
@@ -566,14 +567,7 @@ def _get_site_languages(self, obj):
site_id = None
if obj:
site_id = obj.site_id
- languages = []
- if site_id and site_id in settings.CMS_SITE_LANGUAGES:
- for lang in settings.CMS_SITE_LANGUAGES[site_id]:
- lang_label = dict(settings.CMS_LANGUAGES).get(lang, dict(settings.LANGUAGES).get(lang, lang))
- languages.append((lang, lang_label))
- else:
- languages = settings.CMS_LANGUAGES
- return languages
+ return get_language_tuple(site_id)
def update_language_tab_context(self, request, obj, context=None):
if not context:
@@ -676,11 +670,7 @@ def changelist_view(self, request, extra_context=None):
site_id = int(site_id)
# languages
- languages = []
- if site_id and site_id in settings.CMS_SITE_LANGUAGES:
- languages = settings.CMS_SITE_LANGUAGES[site_id]
- else:
- languages = [lang[0] for lang in settings.CMS_LANGUAGES]
+ languages = get_language_list(site_id)
# parse the cookie that saves which page trees have
# been opened already and extracts the page ID
@@ -986,7 +976,7 @@ def delete_translation(self, request, object_id, extra_context=None):
raise PermissionDenied
message = _('Title and plugins with language %(language)s was deleted') % {
- 'language': [name for code, name in settings.CMS_LANGUAGES if code == language][0]
+ 'language': get_language_object(language)['name']
}
self.log_change(request, titleobj, message)
self.message_user(request, message)
@@ -1189,7 +1179,7 @@ def copy_plugins(self, request):
if not page.has_change_permission(request):
return HttpResponseForbidden(ugettext("You do not have permission to change this page"))
- if not language or not language in [ lang[0] for lang in settings.CMS_LANGUAGES ]:
+ if not language or not language in get_language_list():
return HttpResponseBadRequest(ugettext("Language must be set to a supported language!"))
if language == copy_from:
return HttpResponseBadRequest(ugettext("Language must be different than the copied language!"))
View
@@ -7,6 +7,7 @@
calling these methods!
"""
import datetime
+from cms.utils.i18n import get_language_list
from django.conf import settings
from django.contrib.auth.models import User
@@ -125,7 +126,7 @@ def create_page(title, template, language, menu_title=None, slug=None,
assert template in [tpl[0] for tpl in settings.CMS_TEMPLATES]
# validate language:
- assert language in [lang[0] for lang in settings.CMS_LANGUAGES]
+ assert language in get_language_list()
# set default slug:
if not slug:
@@ -220,7 +221,7 @@ def create_title(language, title, page, menu_title=None, slug=None,
See docs/extending_cms/api_reference.rst for more info
"""
# validate language:
- assert language in [lang[0] for lang in settings.CMS_LANGUAGES]
+ assert language in get_language_list()
# validate page
assert isinstance(page, Page)
View
@@ -2,4 +2,5 @@
class CMSApp(object):
name = None
urls = None
- menus = []
+ menus = []
+ app_name = None
View
@@ -43,7 +43,7 @@ def register(self, app):
"but the 'menus' attribute is empty, did you make a typo?")
name = app.__name__
if name in self.apps.keys():
- raise AppAlreadyRegistered, "[%s] an cms app with this name is already registered" % name
+ raise AppAlreadyRegistered, "[%s] a cms app with this name is already registered" % name
self.apps[name] = app
def get_apphooks(self):
View
@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
+from __future__ import with_statement
from cms.apphook_pool import apphook_pool
+from cms.utils.i18n import force_language, get_language_list
from cms.utils.moderator import get_page_queryset
from django.conf import settings
@@ -10,6 +12,7 @@
RegexURLPattern
from django.db.models import Q
from django.utils.importlib import import_module
+from django.utils.translation import get_language
APP_RESOLVERS = []
@@ -18,8 +21,8 @@ def clear_app_resolvers():
APP_RESOLVERS = []
def applications_page_check(request, current_page=None, path=None):
- """Tries to find if given path was resolved over application.
- Applications have higher priority than other cms pages.
+ """Tries to find if given path was resolved over application.
+ Applications have higher priority than other cms pages.
"""
if current_page:
return current_page
@@ -28,6 +31,9 @@ def applications_page_check(request, current_page=None, path=None):
# This removes the non-CMS part of the URL.
path = request.path.replace(reverse('pages-root'), '', 1)
# check if application resolver can resolve this
+ for lang in get_language_list():
+ if path.startswith(lang + "/"):
+ path = path[len(lang + "/"):]
for resolver in APP_RESOLVERS:
try:
page_id = resolver.resolve_page_id(path)
@@ -46,30 +52,44 @@ def applications_page_check(request, current_page=None, path=None):
class AppRegexURLResolver(RegexURLResolver):
page_id = None
- url_patterns = None
-
+ url_patterns_dict = {}
+
+ @property
+ def url_patterns(self):
+ language = get_language()
+ if language in self.url_patterns_dict:
+ return self.url_patterns_dict[language]
+ else:
+ return []
+
def resolve_page_id(self, path):
"""Resolves requested path similar way how resolve does, but instead
- of return callback,.. returns page_id to which was application
+ of return callback,.. returns page_id to which was application
assigned.
"""
tried = []
match = self.regex.search(path)
if match:
new_path = path[match.end():]
for pattern in self.url_patterns:
- try:
- sub_match = pattern.resolve(new_path)
- except Resolver404, e:
- if 'tried' in e.args[0]:
- tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']])
- elif 'path' in e.args[0]:
- tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['path']])
+ if isinstance(pattern, AppRegexURLResolver):
+ try:
+ return pattern.resolve_page_id(new_path)
+ except Resolver404:
+ pass
else:
- if sub_match:
- return pattern.page_id
- tried.append(pattern.regex.pattern)
- raise Resolver404, {'tried': tried, 'path': new_path}
+ try:
+ sub_match = pattern.resolve(new_path)
+ except Resolver404, e:
+ if 'tried' in e.args[0]:
+ tried.extend([[pattern] + t for t in e.args[0]['tried']])
+ elif 'path' in e.args[0]:
+ tried.extend([[pattern] + t for t in e.args[0]['path']])
+ else:
+ if sub_match:
+ return pattern.page_id
+ tried.append(pattern.regex.pattern)
+ raise Resolver404, {'tried': tried, 'path': new_path}
def recurse_patterns(path, pattern_list, page_id):
@@ -117,7 +137,7 @@ def get_app_urls(urls):
yield getattr(mod, 'urlpatterns')
else:
yield urlconf
-
+
def get_patterns_for_title(path, title):
"""
@@ -138,12 +158,12 @@ def get_patterns_for_title(path, title):
def get_app_patterns():
"""
Get a list of patterns for all hooked apps.
-
+
How this works:
-
+
By looking through all titles with an app hook (application_urls) we find all
urlconf modules we have to hook into titles.
-
+
If we use the ML URL Middleware, we namespace those patterns with the title
language.
@@ -156,54 +176,48 @@ def get_app_patterns():
except Site.DoesNotExist:
current_site = None
included = []
-
+
# we don't have a request here so get_page_queryset() can't be used,
- # so, if CMS_MODERATOR, use, public() queryset, otherwise
- # use draft(). This can be done, because url patterns are used just
+ # so, if CMS_MODERATOR, use, public() queryset, otherwise
+ # use draft(). This can be done, because url patterns are used just
# in frontend
is_draft = not settings.CMS_MODERATOR
title_qs = Title.objects.filter(page__publisher_is_draft=is_draft, page__site=current_site)
-
- if 'cms.middleware.multilingual.MultilingualURLMiddleware' in settings.MIDDLEWARE_CLASSES:
- use_namespaces = True
- hooked_applications = {}
- else:
- use_namespaces = False
- hooked_applications = []
-
+
+ hooked_applications = {}
+
# Loop over all titles with an application hooked to them
for title in title_qs.exclude(application_urls=None).exclude(application_urls='').select_related():
path = title.path
- if use_namespaces:
- mixid = "%s:%s:%s" % (path + "/", title.application_urls, title.language)
- else:
- mixid = "%s:%s" % (path + "/", title.application_urls)
- if mixid in included:
+ mix_id = "%s:%s:%s" % (path + "/", title.application_urls, title.language)
+ if mix_id in included:
# don't add the same thing twice
- continue
+ continue
if not settings.APPEND_SLASH:
path += '/'
- if use_namespaces:
- if title.language not in hooked_applications:
- hooked_applications[title.language] = []
- hooked_applications[title.language] += get_patterns_for_title(path, title)
+ if title.page_id not in hooked_applications:
+ hooked_applications[title.page_id] = {}
+ app = apphook_pool.get_apphook(title.application_urls)
+ if app.app_name:
+ inst_ns = title.page.reverse_id if title.page.reverse_id else app.app_name
+ app_ns = app.app_name, inst_ns
else:
- hooked_applications += get_patterns_for_title(path, title)
- included.append(mixid)
+ app_ns = None, None
+ with force_language(title.language):
+ hooked_applications[title.page_id][title.language] = (app_ns, get_patterns_for_title(path, title))
+ included.append(mix_id)
# Build the app patterns to be included in the cms urlconfs
app_patterns = []
- if use_namespaces:
- for ns, currentpatterns in hooked_applications.items():
- extra_patterns = patterns('', *currentpatterns)
- resolver = AppRegexURLResolver(r'', 'app_resolver', namespace=ns)
- resolver.url_patterns = extra_patterns
- app_patterns.append(resolver)
- APP_RESOLVERS.append(resolver)
- else:
- extra_patterns = patterns('', *hooked_applications)
- resolver = AppRegexURLResolver(r'', 'app_resolver')
- resolver.url_patterns = extra_patterns
+ for page_id in hooked_applications.keys():
+ resolver = None
+ for lang in hooked_applications[page_id].keys():
+ (app_ns, inst_ns), current_patterns = hooked_applications[page_id][lang]
+ if not resolver:
+ resolver = AppRegexURLResolver(r'', 'app_resolver', app_name=app_ns, namespace=inst_ns)
+ resolver.page_id = page_id
+ extra_patterns = patterns('', *current_patterns)
+ resolver.url_patterns_dict[lang] = extra_patterns
app_patterns.append(resolver)
APP_RESOLVERS.append(resolver)
- return app_patterns
+ return app_patterns
Oops, something went wrong.

0 comments on commit 4b968ce

Please sign in to comment.