diff --git a/django/contrib/syndication/views.py b/django/contrib/syndication/views.py index a8b98c84ae..68ffb0bfe0 100644 --- a/django/contrib/syndication/views.py +++ b/django/contrib/syndication/views.py @@ -1,6 +1,5 @@ from calendar import timegm -from django.conf import settings from django.contrib.sites.shortcuts import get_current_site from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist from django.http import Http404, HttpResponse @@ -10,6 +9,7 @@ from django.utils.encoding import iri_to_uri from django.utils.html import escape from django.utils.http import http_date from django.utils.timezone import get_default_timezone, is_naive, make_aware +from django.utils.translation import get_language def add_domain(domain, url, secure=False): @@ -30,6 +30,7 @@ class Feed: feed_type = feedgenerator.DefaultFeed title_template = None description_template = None + language = None def __call__(self, request, *args, **kwargs): try: @@ -134,7 +135,7 @@ class Feed: subtitle=self._get_dynamic_attr('subtitle', obj), link=link, description=self._get_dynamic_attr('description', obj), - language=settings.LANGUAGE_CODE, + language=self.language or get_language(), feed_url=add_domain( current_site.domain, self._get_dynamic_attr('feed_url', obj) or request.path, diff --git a/docs/ref/contrib/syndication.txt b/docs/ref/contrib/syndication.txt index d79db5a94a..aedf942a4d 100644 --- a/docs/ref/contrib/syndication.txt +++ b/docs/ref/contrib/syndication.txt @@ -307,8 +307,14 @@ Language -------- Feeds created by the syndication framework automatically include the -appropriate ```` tag (RSS 2.0) or ``xml:lang`` attribute (Atom). This -comes directly from your :setting:`LANGUAGE_CODE` setting. +appropriate ```` tag (RSS 2.0) or ``xml:lang`` attribute (Atom). By +default, this is :func:`django.utils.translation.get_language()`. You can change it +by setting the ``language`` class attribute. + +.. versionchanged:: 3.0 + + The ``language`` class attribute was added. In older versions, the behavior + is the same as ``language = settings.LANGUAGE_CODE``. URLs ---- @@ -406,6 +412,10 @@ This example illustrates all possible attributes and methods for a title_template = None description_template = None + # LANGUAGE -- Optional. This should be a string specifying a language + # code. Defaults to django.utils.translation.get_language(). + language = 'de' + # TITLE -- One of the following three is required. The framework # looks for them in this order. diff --git a/docs/releases/3.0.txt b/docs/releases/3.0.txt index 9bf4ce2205..1c222cfe7a 100644 --- a/docs/releases/3.0.txt +++ b/docs/releases/3.0.txt @@ -116,7 +116,10 @@ Minor features :mod:`django.contrib.syndication` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* ... +* Added the ``language`` class attribute to the + :class:`django.contrib.syndication.views.Feed` to customize a feed language. + The default value is :func:`~django.utils.translation.get_language()` instead + of setting:`LANGUAGE_CODE`. Cache ~~~~~ diff --git a/tests/syndication_tests/feeds.py b/tests/syndication_tests/feeds.py index 0805258138..4e9b1170b1 100644 --- a/tests/syndication_tests/feeds.py +++ b/tests/syndication_tests/feeds.py @@ -136,6 +136,10 @@ class TemplateContextFeed(TestRss2Feed): return context +class TestLanguageFeed(TestRss2Feed): + language = 'de' + + class NaiveDatesFeed(TestAtomFeed): """ A feed with naive (non-timezone-aware) dates. diff --git a/tests/syndication_tests/tests.py b/tests/syndication_tests/tests.py index 043533d943..dab7ebab33 100644 --- a/tests/syndication_tests/tests.py +++ b/tests/syndication_tests/tests.py @@ -82,6 +82,7 @@ class SyndicationFeedTest(FeedTestCase): self.assertEqual(len(feed_elem), 1) feed = feed_elem[0] self.assertEqual(feed.getAttribute('version'), '2.0') + self.assertEqual(feed.getElementsByTagName('language')[0].firstChild.nodeValue, 'en') # Making sure there's only one `channel` element w/in the # `rss` element. @@ -363,6 +364,11 @@ class SyndicationFeedTest(FeedTestCase): summary = entry.getElementsByTagName('summary')[0] self.assertEqual(summary.getAttribute('type'), 'html') + def test_feed_generator_language_attribute(self): + response = self.client.get('/syndication/language/') + feed = minidom.parseString(response.content).firstChild + self.assertEqual(feed.firstChild.getElementsByTagName('language')[0].firstChild.nodeValue, 'de') + def test_title_escaping(self): """ Titles are escaped correctly in RSS feeds. diff --git a/tests/syndication_tests/urls.py b/tests/syndication_tests/urls.py index d23c33e21b..bff7bd0c8d 100644 --- a/tests/syndication_tests/urls.py +++ b/tests/syndication_tests/urls.py @@ -15,6 +15,7 @@ urlpatterns = [ path('syndication/atom/', feeds.TestAtomFeed()), path('syndication/latest/', feeds.TestLatestFeed()), path('syndication/custom/', feeds.TestCustomFeed()), + path('syndication/language/', feeds.TestLanguageFeed()), path('syndication/naive-dates/', feeds.NaiveDatesFeed()), path('syndication/aware-dates/', feeds.TZAwareDatesFeed()), path('syndication/feedurl/', feeds.TestFeedUrlFeed()),