Skip to main content

Implementing Multilingual Sitemaps

To generate sitemaps for internationalized content in this project, you use the i18n attribute on the Sitemap class. This allows you to automatically generate URLs for all active languages and include SEO-friendly hreflang tags.

Basic Multilingual Sitemap

To enable multi-language URL generation, set i18n = True in your Sitemap subclass. This causes the sitemap to generate a separate entry for every language defined in your LANGUAGES setting for each item returned by items().

from django.contrib.sitemaps import Sitemap
from .models import I18nTestModel

class SimpleI18nSitemap(Sitemap):
changefreq = "never"
priority = 0.5
i18n = True

def items(self):
# Returns a queryset of items to be translated
return I18nTestModel.objects.order_by("pk").all()

When i18n is enabled, the sitemap internally expands your items into (item, lang_code) tuples. Methods like location(), priority(), and lastmod() are then called for each tuple, with the appropriate language activated during the call to location().

For better SEO, you can include <xhtml:link rel="alternate" hreflang="..."> tags in your sitemap by setting alternates = True.

class AlternatesI18nSitemap(Sitemap):
i18n = True
alternates = True

def items(self):
return I18nTestModel.objects.all()

This will include links to all other language versions of the page within each <url> entry in the XML output.

Configuring the Default Language (x-default)

To specify a default version for users whose language isn't explicitly listed, use the x_default attribute. This requires alternates to be enabled.

class XDefaultI18nSitemap(Sitemap):
i18n = True
alternates = True
x_default = True

def items(self):
return I18nTestModel.objects.all()

The x-default URL is generated by taking the URL for the language specified in settings.LANGUAGE_CODE and removing the language prefix (e.g., /en/my-page/ becomes /my-page/).

Restricting Languages

If you only want to generate sitemap entries for a subset of your project's supported languages, use the languages attribute.

class LimitedI18nSitemap(Sitemap):
i18n = True
alternates = True
# Only generate entries for English and Spanish
languages = ["en", "es"]

def items(self):
return I18nTestModel.objects.all()

Per-Item Language Control

For more granular control, such as when certain content is only available in specific languages, override the get_languages_for_item method.

class ItemByLangSitemap(Sitemap):
i18n = True

def items(self):
return I18nTestModel.objects.all()

def get_languages_for_item(self, item):
# Only allow Portuguese for specific items
if item.name == "Only for PT":
return ["pt"]
# Fallback to all supported languages for others
return super().get_languages_for_item(item)

Requirements and Configuration

For multilingual sitemaps to function correctly, ensure the following are configured in your project:

  1. Settings: USE_I18N must be set to True in your settings.py.
  2. URL Patterns: Your model's absolute URLs must be defined within i18n_patterns in your urls.py so that they receive the correct language prefixes.
# urls.py example
from django.conf.urls.i18n import i18n_patterns
from django.urls import path
from .views import testmodelview

urlpatterns = i18n_patterns(
path("testmodel/<int:id>/", testmodelview, name="i18n_testmodel"),
)

Troubleshooting

  • Entry Count: When i18n=True, the total number of entries in your sitemap will be number of items * number of languages. If you have a large number of items and languages, you may hit the limit (default 50,000) much faster, triggering pagination.
  • Missing Prefixes: If your URLs in the sitemap do not have language prefixes (e.g., /en/), verify that your get_absolute_url() implementation uses reverse() and that the corresponding paths are wrapped in i18n_patterns.
  • x-default Logic: The x_default logic specifically looks for the settings.LANGUAGE_CODE prefix in the generated URL to strip it. If your default language does not use a prefix in the URL, x-default may not behave as expected.