1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Fixed #33662 -- Allowed Sitemap to customize languages for each item.

This commit is contained in:
Roxane 2022-10-21 17:36:44 +02:00 committed by Mariusz Felisiak
parent ab7a85ac29
commit 289e9a75af
5 changed files with 122 additions and 5 deletions

View File

@ -92,6 +92,10 @@ class Sitemap:
return attr(item) return attr(item)
return attr return attr
def get_languages_for_item(self, item):
"""Languages for which this item is displayed."""
return self._languages()
def _languages(self): def _languages(self):
if self.languages is not None: if self.languages is not None:
return self.languages return self.languages
@ -103,8 +107,8 @@ class Sitemap:
# This is necessary to paginate with all languages already considered. # This is necessary to paginate with all languages already considered.
items = [ items = [
(item, lang_code) (item, lang_code)
for lang_code in self._languages()
for item in self.items() for item in self.items()
for lang_code in self.get_languages_for_item(item)
] ]
return items return items
return self.items() return self.items()
@ -201,7 +205,8 @@ class Sitemap:
} }
if self.i18n and self.alternates: if self.i18n and self.alternates:
for lang_code in self._languages(): item_languages = self.get_languages_for_item(item[0])
for lang_code in item_languages:
loc = f"{protocol}://{domain}{self._location(item, lang_code)}" loc = f"{protocol}://{domain}{self._location(item, lang_code)}"
url_info["alternates"].append( url_info["alternates"].append(
{ {
@ -209,7 +214,7 @@ class Sitemap:
"lang_code": lang_code, "lang_code": lang_code,
} }
) )
if self.x_default: if self.x_default and settings.LANGUAGE_CODE in item_languages:
lang_code = settings.LANGUAGE_CODE lang_code = settings.LANGUAGE_CODE
loc = f"{protocol}://{domain}{self._location(item, lang_code)}" loc = f"{protocol}://{domain}{self._location(item, lang_code)}"
loc = loc.replace(f"/{lang_code}/", "/", 1) loc = loc.replace(f"/{lang_code}/", "/", 1)

View File

@ -311,6 +311,15 @@ Note:
The latest ``lastmod`` returned by calling the method with all The latest ``lastmod`` returned by calling the method with all
items returned by :meth:`Sitemap.items`. items returned by :meth:`Sitemap.items`.
.. method:: Sitemap.get_languages_for_item(item, lang_code)
.. versionadded:: 4.2
**Optional.** A method that returns the sequence of language codes for
which the item is displayed. By default
:meth:`~Sitemap.get_languages_for_item` returns
:attr:`~Sitemap.languages`.
Shortcuts Shortcuts
========= =========

View File

@ -145,7 +145,8 @@ Minor features
:mod:`django.contrib.sitemaps` :mod:`django.contrib.sitemaps`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ... * The new :meth:`.Sitemap.get_languages_for_item` method allows customizing the
list of languages for which the item is displayed.
:mod:`django.contrib.sites` :mod:`django.contrib.sites`
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -10,7 +10,7 @@ from django.utils.deprecation import RemovedInDjango50Warning
from django.utils.formats import localize from django.utils.formats import localize
from .base import SitemapTestsBase from .base import SitemapTestsBase
from .models import TestModel from .models import I18nTestModel, TestModel
class HTTPSitemapTests(SitemapTestsBase): class HTTPSitemapTests(SitemapTestsBase):
@ -440,6 +440,72 @@ class HTTPSitemapTests(SitemapTestsBase):
) )
self.assertXMLEqual(response.content.decode(), expected_content) self.assertXMLEqual(response.content.decode(), expected_content)
@override_settings(LANGUAGES=(("en", "English"), ("pt", "Portuguese")))
def test_language_for_item_i18n_sitemap(self):
"""
A i18n sitemap index in which item can be chosen to be displayed for a
lang or not.
"""
only_pt = I18nTestModel.objects.create(name="Only for PT")
response = self.client.get("/item-by-lang/i18n.xml")
url, pk, only_pt_pk = self.base_url, self.i18n_model.pk, only_pt.pk
expected_urls = (
f"<url><loc>{url}/en/i18n/testmodel/{pk}/</loc>"
f"<changefreq>never</changefreq><priority>0.5</priority></url>"
f"<url><loc>{url}/pt/i18n/testmodel/{pk}/</loc>"
f"<changefreq>never</changefreq><priority>0.5</priority></url>"
f"<url><loc>{url}/pt/i18n/testmodel/{only_pt_pk}/</loc>"
f"<changefreq>never</changefreq><priority>0.5</priority></url>"
)
expected_content = (
f'<?xml version="1.0" encoding="UTF-8"?>\n'
f'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" '
f'xmlns:xhtml="http://www.w3.org/1999/xhtml">\n'
f"{expected_urls}\n"
f"</urlset>"
)
self.assertXMLEqual(response.content.decode(), expected_content)
@override_settings(LANGUAGES=(("en", "English"), ("pt", "Portuguese")))
def test_alternate_language_for_item_i18n_sitemap(self):
"""
A i18n sitemap index in which item can be chosen to be displayed for a
lang or not.
"""
only_pt = I18nTestModel.objects.create(name="Only for PT")
response = self.client.get("/item-by-lang-alternates/i18n.xml")
url, pk, only_pt_pk = self.base_url, self.i18n_model.pk, only_pt.pk
expected_urls = (
f"<url><loc>{url}/en/i18n/testmodel/{pk}/</loc>"
f"<changefreq>never</changefreq><priority>0.5</priority>"
f'<xhtml:link rel="alternate" '
f'hreflang="en" href="{url}/en/i18n/testmodel/{pk}/"/>'
f'<xhtml:link rel="alternate" '
f'hreflang="pt" href="{url}/pt/i18n/testmodel/{pk}/"/>'
f'<xhtml:link rel="alternate" '
f'hreflang="x-default" href="{url}/i18n/testmodel/{pk}/"/></url>'
f"<url><loc>{url}/pt/i18n/testmodel/{pk}/</loc>"
f"<changefreq>never</changefreq><priority>0.5</priority>"
f'<xhtml:link rel="alternate" '
f'hreflang="en" href="{url}/en/i18n/testmodel/{pk}/"/>'
f'<xhtml:link rel="alternate" '
f'hreflang="pt" href="{url}/pt/i18n/testmodel/{pk}/"/>'
f'<xhtml:link rel="alternate" '
f'hreflang="x-default" href="{url}/i18n/testmodel/{pk}/"/></url>'
f"<url><loc>{url}/pt/i18n/testmodel/{only_pt_pk}/</loc>"
f"<changefreq>never</changefreq><priority>0.5</priority>"
f'<xhtml:link rel="alternate" '
f'hreflang="pt" href="{url}/pt/i18n/testmodel/{only_pt_pk}/"/></url>'
)
expected_content = (
f'<?xml version="1.0" encoding="UTF-8"?>\n'
f'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" '
f'xmlns:xhtml="http://www.w3.org/1999/xhtml">\n'
f"{expected_urls}\n"
f"</urlset>"
)
self.assertXMLEqual(response.content.decode(), expected_content)
def test_sitemap_without_entries(self): def test_sitemap_without_entries(self):
response = self.client.get("/sitemap-without-entries/sitemap.xml") response = self.client.get("/sitemap-without-entries/sitemap.xml")
expected_content = ( expected_content = (

View File

@ -48,6 +48,22 @@ class XDefaultI18nSitemap(AlternatesI18nSitemap):
x_default = True x_default = True
class ItemByLangSitemap(SimpleI18nSitemap):
def get_languages_for_item(self, item):
if item.name == "Only for PT":
return ["pt"]
return super().get_languages_for_item(item)
class ItemByLangAlternatesSitemap(AlternatesI18nSitemap):
x_default = True
def get_languages_for_item(self, item):
if item.name == "Only for PT":
return ["pt"]
return super().get_languages_for_item(item)
class EmptySitemap(Sitemap): class EmptySitemap(Sitemap):
changefreq = "never" changefreq = "never"
priority = 0.5 priority = 0.5
@ -168,6 +184,14 @@ xdefault_i18n_sitemaps = {
"i18n-xdefault": XDefaultI18nSitemap, "i18n-xdefault": XDefaultI18nSitemap,
} }
item_by_lang_i18n_sitemaps = {
"i18n-item-by-lang": ItemByLangSitemap,
}
item_by_lang_alternates_i18n_sitemaps = {
"i18n-item-by-lang-alternates": ItemByLangAlternatesSitemap,
}
simple_sitemaps_not_callable = { simple_sitemaps_not_callable = {
"simple": SimpleSitemap(), "simple": SimpleSitemap(),
} }
@ -358,6 +382,18 @@ urlpatterns = [
{"sitemaps": sitemaps_lastmod_ascending}, {"sitemaps": sitemaps_lastmod_ascending},
name="django.contrib.sitemaps.views.sitemap", name="django.contrib.sitemaps.views.sitemap",
), ),
path(
"item-by-lang/i18n.xml",
views.sitemap,
{"sitemaps": item_by_lang_i18n_sitemaps},
name="django.contrib.sitemaps.views.sitemap",
),
path(
"item-by-lang-alternates/i18n.xml",
views.sitemap,
{"sitemaps": item_by_lang_alternates_i18n_sitemaps},
name="django.contrib.sitemaps.views.sitemap",
),
path( path(
"lastmod-sitemaps/descending.xml", "lastmod-sitemaps/descending.xml",
views.sitemap, views.sitemap,