Welcome to django-localeurl¶
Warning
django-localeurl is currently un-maintained (so pull requests will not be reviewed or merged), and its approach has been obsoleted by the introduction of locale-aware URL patterns in Django itself. If you are nonetheless interested in taking over maintenance of django-localeurl, please file an issue to volunteer. Thank you!
The localeurl Django application allows you to specify the language of a page in the URL.
Suppose you have a Django website in multiple languages. Using
localeurl, without modifying your URLconfs, you can have URLs like
this: http://www.example.com/nl/company/profile
. Any URLs without
a language prefix will be redirected to add the prefix for the default
language (or, optionally, the language preferred in the user’s browser
settings).
Some reasons for using localeurl:
- Search engines will index all languages.
- Every page should have a unique URL. If you feel that different languages means different pages, then each language should get its own unique URL.
- If you don’t set the language via the URL, setting the language for the website should be done using a POST request (because it influences subsequent page views, see Django ticket #3651). You might prefer a simple link for changing the language, and localeurl allows this.
You can install localeurl with pip:
pip install django-localeurl
or install the in-development version:
pip install django-localeurl==dev
The localeurl code is licensed under the MIT License. See the
LICENSE.txt
file in the distribution.
Documentation¶
Installation¶
This section describes how to install the localeurl application in your Django project.
Setup¶
Setup consists of installing the middleware and adding 'localeurl'
to the installed applications list.
Add
'localeurl.middleware.LocaleURLMiddleware'
tosettings.MIDDLEWARE_CLASSES
. It must come before'django.middleware.common.CommonMiddleware'
orsettings.APPEND_SLASH
will not work. Make sure Django’s built-inLocaleMiddleware
is not in yourMIDDLEWARE_CLASSES
setting;LocaleURLMiddleware
replaces it and the two will not work together. It must also come afterdjango.contrib.sessions.middleware.SessionMiddleware
if you plan using the session fallback (seeLOCALEURL_USE_SESSION
below).Add
'localeurl'
tosettings.INSTALLED_APPS
. Because the application needs to replace the standardurlresolvers.reverse
function, it is important to place it at the top of the list:INSTALLED_APPS = ( 'localeurl', ... )
If you want to use the view, include the localeurl URLconf module in your project:
urlpatterns = patterns('', ... (r'^localeurl/', include('localeurl.urls')), ... )
Make sure
settings.LANGUAGE_CODE
or its root language is insettings.LANGUAGES
. For example, ifLANGUAGE_CODE == 'en-us'
thenLANGUAGES
must contain either'en-us'
or'en'
. If you have not changed either option you do not have to do anything.
Configuration¶
The application can be configured by editing the project’s settings.py
file.
LOCALE_INDEPENDENT_PATHS
A tuple of regular expressions matching paths that will not be redirected to add the language prefix. For example, a site with a language selection splash page would add
'^/$'
as a locale independent path match.Example:
LOCALE_INDEPENDENT_PATHS = ( r'^/$', r'^/games/', r'^/ajax/', )
LOCALE_INDEPENDENT_MEDIA_URL
(default:True
)- Whether paths starting with
settings.MEDIA_URL
(if it is a path, i.e. not a full URL) are considered to be locale-independent. LOCALE_INDEPENDENT_STATIC_URL
(default:True
)- Whether paths starting with
settings.STATIC_URL
(if it is a path, i.e. not a full URL) are considered to be locale-independent. PREFIX_DEFAULT_LOCALE
(default:True
)- Whether to add the prefix for the default language
(
settings.LANGUAGE_CODE
). For example, ifLANGUAGE_CODE == 'en'
then the path/about/
will be passed to the URL resolver unchanged and/en/about/
will be redirected to/about/
. LOCALEURL_USE_ACCEPT_LANGUAGE
(default:False
)- Whether to check the
Accept-Language
header from the browser as an intermediate fallback in case no locale is specified in the URL. (The default behavior, preserved for backwards compatibility, is to fallback directly tosettings.LANGUAGE_CODE
).
LOCALEURL_USE_SESSION
(default: False
)
Whether to check for a user-selected locale in the Django session as a fallback in case no locale is specified in the URL. If
True
, thechange_locale
view will save the chosen locale to the user’s session under thedjango_language
session key. When used and available, the session locale takes precedence over theAccept-Language
header fallback (seeLOCALEURL_USE_ACCEPT_LANGUAGE
above).A localized URL still takes precedence over a locale in the user’s session. Following a localized link such as one generated using the
chlocale
filter won’t switch the session’sdjango_language
; only thechange_locale
view will.To use this feature, sessions must be in use, and
django.contrib.sessions.middleware.SessionMiddleware
must come beforelocaleurl.middleware.LocaleURLMiddleware
insettings.MIDDLEWARE_CLASSES
.
LOCALE_REDIRECT_PERMANENT
(default:True
)- Whether to use a permanent redirect (301 status code) or temporary
redirect (302) when redirecting users from the no-locale version of a URL
to the default locale (or the locale specified in their Accept-Language
header if
LOCALEURL_USE_ACCEPT_LANGUAGE
is True). If Accept-Language is not used, these redirects will never change (as long as the default locale never changes), so 301 (the default) is a fine choice. If you use Accept-Language you may want to consider switching this toFalse
, as the redirect will then be dependent on the user’s Accept-Language header.
Usage¶
The localeurl application provides a middleware class that sets
request.LANGUAGE_CODE
based on a prefix on the URL path. It stripping off
this language prefix from request.path_info
so that the URLconf modules do
not need to change. Existing applications should work transparently with
localeurl if they follow the usual Django convention of using url
tags in
templates and (and the urlresolvers.reverse
function in Python code) to
generate internal links.
Paths without locale prefix are redirected to the default locale, either from
request.LANGUAGE_CODE
(set by a previous language discovery middleware such
as django.middleware.locale.LocaleMiddleware
) or from
settings.LANGUAGE_CODE
. So a request for /about/
would be redirected to
/fr/about/
if French is the default language. (This behavior can be changed
using settings.PREFIX_DEFAULT_LOCALE
.) Determination of the default locale
can also take into account the Accept-Language
browser header (see
settings.LOCALEURL_USE_ACCEPT_LANGUAGE
), or a previously user-selected
locale (see settings.LOCALEURL_USE_SESSION
, and the change_locale
view
below).
Templates¶
The application adds one template tag and two filters. Add the following at the top of a template to enable them:
{% load localeurl_tags %}
The locale_url
tag¶
The localeurl application replaces the urlresolvers.reverse
function to
return locale-specific URLs, so existing templates should not need to be
changed. To manipulate the language on rendered URLs you can use the
locale_url
tag. This tag behaves exactly like the standard url
tag,
except you specify a language.
Note
In Django 1.3 and later, using the locale_url
tag from
localeurl_tags
will result in a deprecation warning about changed url
tag syntax. To avoid this warning, {% load locale_url from
localeurl_future %}
in your template after you {% load localeurl_tags
%}
. This also requires that you adopt the new url tag syntax.
Example¶
You can refer to a specific URL in a specified language like this:
<a href="{% locale_url "de" articles.views.display id=article.id %}">Show article in German</a>
If you are using Django 1.3+ and you loaded locale_url
from the
localeurl_future
library, you’d need quotes around the view name:
<a href="{% locale_url "de" "articles.views.display" id=article.id %}">Show article in German</a>
The chlocale
filter¶
To add or change the locale prefix of a path use chlocale
. It takes one
argument: the new locale. If the path is locale-independent any prefix on the
path will be stripped. This is also the case if
settings.PREFIX_DEFAULT_LOCALE == False
and the locale argument is the
default locale.
Examples¶
To change the language of a URL to Dutch:
Please click <a href="{{ help_url|chlocale:"nl" }}">here</a> for Dutch help.
This filter can be used to allow users to go to a different language version of the same page. If you have this in your settings file:
_ = lambda s: s
LANGUAGES = (
('en', _(u'English')),
('nl', _(u'Nederlands')),
('de', _(u'Deutsch')),
('fr', _(u'Français')),
)
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.request',
'django.core.context_processors.i18n',
...
)
... then you can add a language selection menu in templates like this:
{% for lang in LANGUAGES %}
{% ifequal lang.0 LANGUAGE_CODE %}
<li class="selected">{{ lang.1 }}</li>
{% else %}
<li><a href="{{ request.path|chlocale:lang.0 }}">{{ lang.1 }}</a></li>
{% endifequal %}
{% endfor %}
Views¶
The application supplies a view to change the locale.
The change_locale
view¶
Instead of the language selection menu shown in the chlocale
example above,
you can use the localeurl_change_locale
view to switch to a different
language. It is designed to mimic the Django set_language
redirect view.
When settings.LOCALEURL_USE_SESSION
is set to True
(default is
False
), It also records the user-selected locale to the current Django
session. The last selected locale will then be used as the default locale when
redirecting from paths missing a locale prefix.
Example¶
This form shows a drop-down box to change the page language:
{% load i18n %}
<form id="locale_switcher" method="POST" action="{% url localeurl_change_locale %}">
<select name="locale" onchange="$('#locale_switcher').submit()">
{% for lang in LANGUAGES %}
<option value="{{ lang.0 }}" {% ifequal lang.0 LANGUAGE_CODE %}selected="selected"{% endifequal %}>{{ lang.1 }}</option>
{% endfor %}
</select>
<noscript>
<input type="submit" value="Set" />
</noscript>
</form>
Sitemaps¶
Localeurl supplies a LocaleurlSitemap
class for more convenient
creation of sitemaps that include URLs in all available languages,
based on this snippet.
To use, just inherit your sitemap classes from
localeurl.sitemaps.LocaleurlSitemap
instead of
django.contrib.sitemaps.Sitemap
, and instantiate one for each
language in your sitemaps dictionary.
Example¶
The following show how might create a multilingual sitemap:
from localeurl.sitemaps import LocaleurlSitemap
# example Sitemap
class AdvertisementsSitemap(LocaleurlSitemap):
def items(self):
return Advertisement.active_objects.all()
# create each section in all languages
sitemaps = {
'advertisements-sk': sitemaps.AdvertisementsSitemap('sk'),
'advertisements-cs': sitemaps.AdvertisementsSitemap('cs'),
}
# add sitemap into urls
urlpatterns = patterns('',
url(r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}),
)
History¶
Changelog¶
Tip: (unreleased)
- Release 2.0.2: (2015-01-26)
- (Re-)Add import of models in middleware, to ensure monkeypatch of
reverse
happens soon enough. Fixes #5, again. - Fix detection of locales with >2 letter codes. Fixes #38.
- (Re-)Add import of models in middleware, to ensure monkeypatch of
- Release 2.0.1: (2013-09-19)
- Change canonical documentation links from http://pythonhosted.org/django-localeurl/ to http://django-localeurl.readthedocs.org
- Release 2.0: (2013-09-19)
- BACKWARDS-INCOMPATIBLE: Drop support for Django 1.0 - 1.2; Python 2.4 and 2.5.
- Deprecate
localeurl_future
tag library, always use new url tag syntax. - Try importing
patterns, url
first fromdjango.conf.urls
; usedjango.conf.urls.defaults
only as Django 1.3 fallback. Fixes #36. - Don’t try to parse referrer if not present. Fixes #33. Thanks Simon Luijk.
- Add support for a session-stored locale fallback. Thanks Sylvain Fourmanoit for report and draft patch, and Alex Marandon for adding tests. Fixes #23.
- Make language-code matching case-insensitive, per RFC. Thanks torgeilo for the report. Fixes #32.
- Fix issue with non-ASCII characters in URLs. Thanks Chris Adams.
- Release 1.5: (2011-08-24)
- Added
LOCALE_REDIRECT_PERMANENT
setting; defaults to True, if set toFalse
302 redirects are used rather than 301. Thanks oyvindeh. LOCALE_INDEPENDENT_PATHS
can now be plain string regular expressions, they don’t have to be compiled regex objects. Fixes #9.- Added import of
localeurl.models
tolocaleurl.middleware
, to ensure thatreverse
is monkeypatched before any requests are served. Fixes #5. Thanks Antti Kaihola for the report, Andrey Shipilov and jefurii for fix confirmation. - Added iri_to_uri encoding of non-ASCII redirect URLs. Fixes #13.
- Sorted language codes longest-first to avoid matching e.g. ‘pt’ before ‘pt-br’. Fixes #15. Thanks Roman Barczyński for report and draft patch.
- Added
LOCALE_INDEPENDENT_STATIC_URL
setting to mirrorLOCALE_INDEPENDENT_MEDIA_URL
. This setting defaults to True, so if you want URLs under STATIC_URL to be locale-dependent, you will need to set it to False. - Fixed middleware redirection when there is a script prefix. Fixes #10. Thanks iro for report and draft patch.
- Added
localeurl_future
template tag library to providelocale_url
tag that wraps the new Djangourl
tag to allow using the new syntax and avoid deprecation warnings under Django 1.3. Fixes #17. Thanks Fabian Büchler for the report. - Accounted for reverse() receiving kwargs=None. Fixes #18. Thanks Alexander Clausen for report and tests, Joel Ryan for draft patch.
- Prevented change_locale view from stripping query params from
next
. Fixes #7. Thanks Sverre Johansen.
- Added
- Release 1.4: (2010-03-19)
- Moved localeurl settings from localeurl/__init__.py to localeurl/settings.py.
- Added
LocaleurlSitemap
for easier creation of multilingual sitemaps. - Added
LOCALEURL_USE_ACCEPT_LANGUAGE
setting to check HTTP Accept-Language header before resorting tosettings.LANGUAGE_CODE
when locale is not specified in URL. - Switched to 301 permanent redirects for no-locale URL redirect.
- Moved to BitBucket for source code hosting.
- Added the
change_locale
view, contributed by Panos Laganakos.
- Release 1.3: (2009-04-06)
- Changed chlocale tag to strip prefix of locale-independent paths.
- Moved the monkey-patching of urlresolvers.reverse to models.py.
- Removed
REDIRECT_LOCALE_INDEPENDENT_PATHS
settings option; this is now the default.
- Release 1.2: (2009-01-19):
- Moved the documentation into the source tree. (Based on a blog post by Andi Albrecht.)
- Released version 1.2.
- Release 1.1: (2008-11-20):
- Added the
PREFIX_DEFAULT_LOCALE
settings option contributed by Jonas Christian. - Added
REDIRECT_LOCALE_INDEPENDENT_PATHS
settings option.
- Added the
- Release 1.0: (2008-09-10):
- Added Django 1.0 or higher as a prerequisite.
- Moved to Google Code.
Credits¶
localeurl was developed by Joost Cassee based on the work by Atli Þorbjörnsson. Contributions by Jonas Christian. Includes code from the django-localize project by Artiom Diomin. Currently maintained by Carl Meyer.
It was partly taken from and partly inspired by discussions on the django-users and django-multilingual mailinglists:
- Atli Þorbjörnsson: Locale from URL Middleware
- Panos Laganakos: creating a multilingual middleware
- Piotr Majewski: multilingual middleware NEW FEATURE!
See also this blog post on internationalisation by Yann Malet that references Atli’s code.
- The announcement of localeurl on these lists can be found here: