django-localeurl-1.5/0000775000175000017500000000000011625261240014104 5ustar carljmcarljmdjango-localeurl-1.5/setup.cfg0000644000175000017500000000026411625261240015725 0ustar carljmcarljm[build_sphinx] all_files = 1 build-dir = docs/.build/ source-dir = docs/ [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 [upload_sphinx] upload-dir = docs/.build/html django-localeurl-1.5/django_localeurl.egg-info/0000775000175000017500000000000011625261240021102 5ustar carljmcarljmdjango-localeurl-1.5/django_localeurl.egg-info/SOURCES.txt0000644000175000017500000000133011625261240022761 0ustar carljmcarljmHGREV LICENSE.txt MANIFEST.in README.txt metadata.py runtests.py setup.cfg setup.py django_localeurl.egg-info/PKG-INFO django_localeurl.egg-info/SOURCES.txt django_localeurl.egg-info/dependency_links.txt django_localeurl.egg-info/top_level.txt docs/history.rst docs/index.rst docs/setup.rst docs/usage.rst localeurl/__init__.py localeurl/middleware.py localeurl/models.py localeurl/settings.py localeurl/sitemaps.py localeurl/urls.py localeurl/utils.py localeurl/views.py localeurl/templatetags/__init__.py localeurl/templatetags/localeurl_future.py localeurl/templatetags/localeurl_tags.py localeurl/tests/__init__.py localeurl/tests/models.py localeurl/tests/test_urls.py localeurl/tests/test_utils.py localeurl/tests/tests.pydjango-localeurl-1.5/django_localeurl.egg-info/top_level.txt0000644000175000017500000000001211625261236023630 0ustar carljmcarljmlocaleurl django-localeurl-1.5/django_localeurl.egg-info/dependency_links.txt0000644000175000017500000000000111625261236025153 0ustar carljmcarljm django-localeurl-1.5/django_localeurl.egg-info/PKG-INFO0000644000175000017500000000532011625261236022202 0ustar carljmcarljmMetadata-Version: 1.0 Name: django-localeurl Version: 1.5 Summary: A Django application that allow you to specify the language of a page in the URL. Home-page: http://packages.python.org/django-localeurl/ Author: Carl Meyer Author-email: carl@oddbird.net License: MIT License Description: Welcome to django-localeurl =========================== 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. .. _Django: http://www.djangoproject.com/ .. _`Django ticket #3651`: http://code.djangoproject.com/ticket/3651 You can install localeurl with pip_:: pip install django-localeurl or install the `in-development version`_:: pip install django-localeurl==dev .. _pip: http://pip.openplans.org .. _`in-development version`: http://bitbucket.org/carljm/django-localeurl/get/tip.gz#egg=django-localeurl-dev .. comment: See the `full documentation`_. .. _`full documentation`: http://packages.python.org/django-localeurl/ Keywords: django i18n Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Framework :: Django Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Application Frameworks Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Localization django-localeurl-1.5/README.txt0000644000175000017500000000051511475212726015611 0ustar carljmcarljmThis Django application allows the language be set in the URL. Copyright (C) 2008-2010 Joost Cassee and contributors This program is licensed under the MIT License (see LICENSE.txt) See the docs/ directory for documentation, or http://pypi.python.org/pypi/django-localeurl for released versions. -- Joost Cassee joost@cassee.net django-localeurl-1.5/MANIFEST.in0000644000175000017500000000006411475212726015650 0ustar carljmcarljminclude HGREV include *.txt *.py include docs/*.rst django-localeurl-1.5/metadata.py0000644000175000017500000000130011625260513016230 0ustar carljmcarljmimport subprocess import os.path try: # don't get confused if our sdist is unzipped in a subdir of some # other hg repo if os.path.isdir('.hg'): p = subprocess.Popen(['hg', 'parents', r'--template={rev}\n'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) if not p.returncode: fh = open('HGREV', 'w') fh.write(p.communicate()[0].splitlines()[0]) fh.close() except (OSError, IndexError): pass try: hgrev = open('HGREV').read() except IOError: hgrev = '' name = 'localeurl' authors = 'Joost Cassee, Artiom Diomin and Carl Meyer' copyright_years = '2008-2010' version = '1.5' release = version django-localeurl-1.5/setup.py0000755000175000017500000000304011475212726015624 0ustar carljmcarljm#!/usr/bin/env python # # Copyright (c) 2008 Joost Cassee # Licensed under the terms of the MIT License (see LICENSE.txt) from setuptools import setup import metadata app_name = metadata.name version = metadata.version long_description = open('docs/index.rst').read().split('split here', 1)[0] + """ See the `full documentation`_. .. _`full documentation`: http://packages.python.org/django-localeurl/ """ setup( name = "django-%s" % app_name, version = version, packages = [app_name, '%s.templatetags' % app_name, '%s.tests' % app_name], author = "Joost Cassee", author_email = "joost@cassee.net", maintainer = "Carl Meyer", maintainer_email = "carl@oddbird.net", description = "A Django application that allow you to specify the" \ " language of a page in the URL.", long_description = long_description, license = "MIT License", keywords = "django i18n", classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Framework :: Django', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Application Frameworks', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Localization', ], url = "http://packages.python.org/django-%s/" % app_name, test_suite = 'runtests.runtests', ) django-localeurl-1.5/localeurl/0000775000175000017500000000000011625261240016066 5ustar carljmcarljmdjango-localeurl-1.5/localeurl/utils.py0000644000175000017500000000552411552676407017622 0ustar carljmcarljmfrom django.conf import settings from django.core import urlresolvers from localeurl import settings as localeurl_settings def is_locale_independent(path): """ Returns whether the path is locale-independent. """ if (localeurl_settings.LOCALE_INDEPENDENT_MEDIA_URL and settings.MEDIA_URL and path.startswith(settings.MEDIA_URL)): return True if (localeurl_settings.LOCALE_INDEPENDENT_STATIC_URL and getattr(settings, "STATIC_URL", None) and path.startswith(settings.STATIC_URL)): return True for regex in localeurl_settings.LOCALE_INDEPENDENT_PATHS: if regex.search(path): return True return False def strip_path(path): """ Separates the locale prefix from the rest of the path. If the path does not begin with a locale it is returned without change. """ check = localeurl_settings.PATH_RE.match(path) if check: path_info = check.group('path') or '/' if path_info.startswith('/'): return check.group('locale'), path_info return '', path def supported_language(locale): """ Returns the supported language (from settings.LANGUAGES) for the locale. """ if locale in localeurl_settings.SUPPORTED_LOCALES: return locale elif locale[:2] in localeurl_settings.SUPPORTED_LOCALES: return locale[:2] else: return None def is_default_locale(locale): """ Returns whether the locale is the default locale. """ return locale == supported_language(settings.LANGUAGE_CODE) def locale_path(path, locale=''): """ Generate the localeurl-enabled path from a path without locale prefix. If the locale is empty settings.LANGUAGE_CODE is used. """ locale = supported_language(locale) if not locale: locale = supported_language(settings.LANGUAGE_CODE) if is_locale_independent(path): return path elif is_default_locale(locale) and not localeurl_settings.PREFIX_DEFAULT_LOCALE: return path else: return ''.join([u'/', locale, path]) def locale_url(path, locale=''): """ Generate the localeurl-enabled URL from a path without locale prefix. If the locale is empty settings.LANGUAGE_CODE is used. """ path = locale_path(path, locale) return add_script_prefix(path) def strip_script_prefix(url): """ Strips the SCRIPT_PREFIX from the URL. Because this function is meant for use in templates, it assumes the URL starts with the prefix. """ assert url.startswith(urlresolvers.get_script_prefix()), \ "URL must start with SCRIPT_PREFIX: %s" % url pos = len(urlresolvers.get_script_prefix()) - 1 return url[:pos], url[pos:] def add_script_prefix(path): """ Prepends the SCRIPT_PREFIX to a path. """ return ''.join([urlresolvers.get_script_prefix(), path[1:]]) django-localeurl-1.5/localeurl/templatetags/0000775000175000017500000000000011625261240020560 5ustar carljmcarljmdjango-localeurl-1.5/localeurl/templatetags/localeurl_future.py0000644000175000017500000000061111552117634024510 0ustar carljmcarljmfrom django import template from django.templatetags.future import url from django.utils.functional import wraps from localeurl_tags import locale_url register = template.Library() def locale_url_wrapper(parser, token): return locale_url(parser, token, django_url_tag=url) locale_url_wrapper = wraps(locale_url)(locale_url_wrapper) register.tag('locale_url', locale_url_wrapper) django-localeurl-1.5/localeurl/templatetags/__init__.py0000644000175000017500000000000011475212726022665 0ustar carljmcarljmdjango-localeurl-1.5/localeurl/templatetags/localeurl_tags.py0000644000175000017500000000474311552207421024140 0ustar carljmcarljmfrom django import template from django.template import Node, Token, TemplateSyntaxError from django.template import resolve_variable, defaulttags from django.template.defaultfilters import stringfilter from django.utils.functional import wraps from localeurl import utils register = template.Library() def chlocale(url, locale): """ Changes the URL's locale prefix if the path is not locale-independent. Otherwise removes locale prefix. """ _, path = utils.strip_script_prefix(url) _, path = utils.strip_path(path) return utils.locale_url(path, locale) chlocale = stringfilter(chlocale) register.filter('chlocale', chlocale) def rmlocale(url): """Removes the locale prefix from the URL.""" script_prefix, path = utils.strip_script_prefix(url) _, path = utils.strip_path(path) return ''.join([script_prefix, path]) rmlocale = stringfilter(rmlocale) register.filter('rmlocale', rmlocale) def locale_url(parser, token, django_url_tag): """ Renders the url for the view with another locale prefix. The syntax is like the 'url' tag, only with a locale before the view. Examples: {% locale_url "de" cal.views.day day %} {% locale_url "nl" cal.views.home %} {% locale_url "en-gb" cal.views.month month as month_url %} """ bits = token.split_contents() if len(bits) < 3: raise TemplateSyntaxError("'%s' takes at least two arguments:" " the locale and a view" % bits[0]) urltoken = Token(token.token_type, bits[0] + ' ' + ' '.join(bits[2:])) urlnode = django_url_tag(parser, urltoken) return LocaleURLNode(bits[1], urlnode) class LocaleURLNode(Node): def __init__(self, locale, urlnode): self.locale = locale self.urlnode = urlnode def render(self, context): locale = resolve_variable(self.locale, context) if utils.supported_language(locale) is None: raise ValueError("locale not in settings.LANGUAGES: %s" % locale) path = self.urlnode.render(context) if self.urlnode.asvar: self.urlnode.render(context) context[self.urlnode.asvar] = chlocale(context[self.urlnode.asvar], locale) return '' else: return chlocale(path, locale) def locale_url_wrapper(parser, token): return locale_url(parser, token, django_url_tag=defaulttags.url) locale_url_wrapper = wraps(locale_url)(locale_url_wrapper) register.tag('locale_url', locale_url_wrapper) django-localeurl-1.5/localeurl/tests/0000775000175000017500000000000011625261240017230 5ustar carljmcarljmdjango-localeurl-1.5/localeurl/tests/test_utils.py0000644000175000017500000000753111552123745022013 0ustar carljmcarljm""" Test utilities. """ from django.conf import settings as django_settings from django.core.handlers.wsgi import WSGIRequest from django import template from django.test import Client from django.utils import encoding NO_SETTING = object() class TestSettingsManager(object): """ A class which can modify some Django settings temporarily for a test and then revert them to their original values later. Based on the work by 'carljm': http://www.djangosnippets.org/snippets/1011/ """ def __init__(self, settings=django_settings): self._settings = settings self._original_settings = {} def set(self, **kwargs): self.set_from_dict(kwargs) def set_from_dict(self, settings): for k,v in settings.iteritems(): self._original_settings.setdefault(k, getattr(self._settings, k, NO_SETTING)) setattr(self._settings, k, v) def revert(self): for k,v in self._original_settings.iteritems(): if v == NO_SETTING: try: delattr(self._settings, k) except AttributeError: # Django < r11825 delattr(self._settings._wrapped, k) else: setattr(self._settings, k, v) self._original_settings = {} class RequestFactory(Client): """ Class that lets you create mock Request objects for use in testing. Usage: rf = RequestFactory() get_request = rf.get('/hello/') post_request = rf.post('/submit/', {'foo': 'bar'}) This class re-uses the django.test.client.Client interface, docs here: http://www.djangoproject.com/documentation/testing/#the-test-client Once you have a request object you can pass it to any view function, just as if that view had been hooked up using a URLconf. Based on the work by Simon Willison: http://www.djangosnippets.org/snippets/963/ """ def request(self, **request): """ Similar to parent class, but returns the request object as soon as it has created it. """ environ = { 'HTTP_COOKIE': self.cookies, 'PATH_INFO': '/', 'QUERY_STRING': '', 'REQUEST_METHOD': 'GET', 'SCRIPT_NAME': '', 'SERVER_NAME': 'testserver', 'SERVER_PORT': 80, 'SERVER_PROTOCOL': 'HTTP/1.1', } environ.update(self.defaults) environ.update(request) return WSGIRequest(environ) class TestTemplate(template.Template): """ TestTemplate behaves just like django.template.Template, but you can give it a list of template.Libraries to load before parsing the template. This is equivalent to adding a bunch of {% load %} tags to the beginning of your template string, but you can use custom tag libraries which do not belong to Django applications' templatetags packages. Based on the work by Alexander Khodyrev: http://www.djangosnippets.org/snippets/1641/ """ def __init__(self, template_string, name='', libraries=[]): try: template_string = encoding.smart_unicode(template_string) except UnicodeDecodeError: raise template.TemplateEncodingError( "template content must be unicode or UTF-8 string") origin = template.StringOrigin(template_string) self.nodelist = self.my_compile_string(template_string, origin, libraries) self.name = name def my_compile_string(self, template_string, origin, libraries=[]): "Compiles template_string into NodeList ready for rendering" lexer = template.Lexer(template_string, origin) parser = template.Parser(lexer.tokenize()) for lib in libraries: parser.add_library(lib) return parser.parse() django-localeurl-1.5/localeurl/tests/test_urls.py0000644000175000017500000000042211475212727021633 0ustar carljmcarljm""" URLconf for testing. """ from django.conf.urls.defaults import * urlpatterns = patterns('localeurl.tests.test_urls', url(r'^dummy/$', 'dummy', name='dummy0'), url(r'^dummy/(?P.+)$', 'dummy', name='dummy1'), ) def dummy(request, test='test'): pass django-localeurl-1.5/localeurl/tests/__init__.py0000664000175000017500000000000011552161602021327 0ustar carljmcarljmdjango-localeurl-1.5/localeurl/tests/tests.py0000664000175000017500000003534611607632406020765 0ustar carljmcarljm# -*- coding: utf-8 -*- """ Tests for the localeurl application. """ import re from django import template from django.core import urlresolvers from django.test import TestCase from django.utils import translation from localeurl import middleware, settings as localeurl_settings, utils from localeurl.models import reverse from localeurl.sitemaps import LocaleurlSitemap from localeurl.templatetags import localeurl_tags from localeurl.tests import test_utils def settings_fixture(mgr): mgr.set( USE_I18N = True, LANGUAGES = ( ('en', 'English'), ('nl-nl', 'Dutch'), ('nl-be', 'Flemish'), ('fr', 'French'), ('pt', 'Portuguese'), ('pt-br', 'Brazilian Portuguese'), ), LANGUAGE_CODE = 'en-gb', LOCALE_INDEPENDENT_PATHS = ( re.compile('^/$'), '^/test/independent/', ), LOCALE_INDEPENDENT_MEDIA_URL = True, MEDIA_URL = '/media/', LOCALE_INDEPENDENT_STATIC_URL = True, STATIC_URL = '/static/', TEMPLATE_CONTEXT_PROCESSORS = ( 'django.core.context_processors.i18n', ), ) class LocaleurlTestCase(TestCase): urls = 'localeurl.tests.test_urls' def setUp(self): self.settings_manager = test_utils.TestSettingsManager() settings_fixture(self.settings_manager) translation.activate("en") reload(localeurl_settings) reload(urlresolvers) def tearDown(self): self.settings_manager.revert() reload(localeurl_settings) reload(urlresolvers) class UtilsTestCase(LocaleurlTestCase): def test_is_locale_independent(self): self.assertFalse(utils.is_locale_independent('/fr/about')) self.assertFalse(utils.is_locale_independent('/about')) self.assertTrue(utils.is_locale_independent('/media/img/logo.png')) self.assertTrue(utils.is_locale_independent('/static/img/logo.png')) self.assertTrue(utils.is_locale_independent('/')) self.assertTrue(utils.is_locale_independent( '/test/independent/bla/bla')) def test_strip_path(self): self.assertEqual(('', '/'), utils.strip_path('/')) self.assertEqual(('', '/about/'), utils.strip_path('/about/')) self.assertEqual(('', '/about/localeurl/'), utils.strip_path('/about/localeurl/')) self.assertEqual(('fr', '/about/localeurl/'), utils.strip_path('/fr/about/localeurl/')) self.assertEqual(('nl-be', '/about/localeurl/'), utils.strip_path('/nl-be/about/localeurl/')) self.assertEqual(('', '/de/about/localeurl/'), utils.strip_path('/de/about/localeurl/')) def test_strip_path_takes_longer_code_first(self): # Refs issue #15. self.assertEqual(('pt-br', '/about/localeurl/'), utils.strip_path('/pt-br/about/localeurl/')) def test_supported_language(self): self.assertEqual('fr', utils.supported_language('fr')) self.assertEqual('nl-be', utils.supported_language('nl-be')) self.assertEqual('en', utils.supported_language('en-gb')) self.assertEqual(None, utils.supported_language('de')) def test_is_default_locale(self): self.assertTrue(utils.is_default_locale('en')) self.assertFalse(utils.is_default_locale('en-gb')) self.assertFalse(utils.is_default_locale('fr')) self.assertFalse(utils.is_default_locale('de')) def test_locale_path(self): self.assertEqual('/en/about/localeurl/', utils.locale_path('/about/localeurl/')) self.assertEqual('/en/about/localeurl/', utils.locale_path('/about/localeurl/', 'de')) self.assertEqual('/en/about/localeurl/', utils.locale_path('/about/localeurl/', 'en')) self.assertEqual('/en/about/localeurl/', utils.locale_path('/about/localeurl/', 'en-us')) self.assertEqual('/nl-nl/about/localeurl/', utils.locale_path('/about/localeurl/', 'nl-nl')) self.assertEqual('/test/independent/bla/bla', utils.locale_path('/test/independent/bla/bla', 'en')) def test_locale_url(self): previous_script_prefix = urlresolvers.get_script_prefix() urlresolvers.set_script_prefix("/blah/") self.assertEqual('/blah/en/about/localeurl/', utils.locale_url('/about/localeurl/')) self.assertEqual('/blah/en/about/localeurl/', utils.locale_url('/about/localeurl/', 'de')) self.assertEqual('/blah/en/about/localeurl/', utils.locale_url('/about/localeurl/', 'en')) self.assertEqual('/blah/en/about/localeurl/', utils.locale_url('/about/localeurl/', 'en-us')) self.assertEqual('/blah/nl-nl/about/localeurl/', utils.locale_url('/about/localeurl/', 'nl-nl')) self.assertEqual('/blah/test/independent/bla/bla', utils.locale_url('/test/independent/bla/bla', 'en')) urlresolvers.set_script_prefix(previous_script_prefix) class MiddlewareTestCase(LocaleurlTestCase): def setUp(self): super(MiddlewareTestCase, self).setUp() self.request_factory = test_utils.RequestFactory() self.middleware = middleware.LocaleURLMiddleware() def test_with_locale(self): r1 = self.request_factory.get('/fr/test/') r2 = self.middleware.process_request(r1) self.assertEqual(None, r2) self.assertEqual('fr', r1.LANGUAGE_CODE) self.assertEqual('/test/', r1.path_info) def test_with_sublocale(self): r1 = self.request_factory.get('/nl-nl/test/bla/bla/') r2 = self.middleware.process_request(r1) self.assertEqual(None, r2) self.assertEqual('nl-nl', r1.LANGUAGE_CODE) self.assertEqual('/test/bla/bla/', r1.path_info) def test_locale_independent_url(self): r1 = self.request_factory.get('/test/independent/bla/bla/') r2 = self.middleware.process_request(r1) self.assertEqual(None, r2) self.assertEqual('en-gb', r1.LANGUAGE_CODE) self.assertEqual('/test/independent/bla/bla/', r1.path_info) def test_locale_specified_on_independent_url_with_query_string(self): r1 = self.request_factory.get('/nl-be/test/independent/?foo=bar') r2 = self.middleware.process_request(r1) self.assertEqual(301, r2.status_code) self.assertEqual('/test/independent/?foo=bar', r2['Location']) def test_redirect_with_script_prefix(self): previous_script_prefix = urlresolvers.get_script_prefix() urlresolvers.set_script_prefix('/prefix/') r1 = self.request_factory.get('/nl-be/test/independent/') r2 = self.middleware.process_request(r1) self.assertEqual(301, r2.status_code) self.assertEqual('/prefix/test/independent/', r2['Location']) # no infinite redirects r3 = self.request_factory.get('/test/independent/') r4 = self.middleware.process_request(r3) self.assertEqual(None, r4) urlresolvers.set_script_prefix(previous_script_prefix) def test_redirect_statuscode_302(self): self.settings_manager.set(LOCALE_REDIRECT_PERMANENT=False) reload(localeurl_settings) r1 = self.request_factory.get('/nl-be/test/independent/?foo=bar') r2 = self.middleware.process_request(r1) self.assertEqual(302, r2.status_code) def test_redirect_statuscode_default(self): r1 = self.request_factory.get('/nl-be/test/independent/?foo=bar') r2 = self.middleware.process_request(r1) self.assertEqual(301, r2.status_code) def test_check_accept_lang(self): self.settings_manager.set(LOCALEURL_USE_ACCEPT_LANGUAGE=True) reload(localeurl_settings) r1 = self.request_factory.get('/test/', HTTP_ACCEPT_LANGUAGE='fr, de;q=0.8') r2 = self.middleware.process_request(r1) self.assertEqual(301, r2.status_code) self.assertEqual('/fr/test/', r2['Location']) class DefaultPrefixMiddlewareTestCase(MiddlewareTestCase): def setUp(self): super(DefaultPrefixMiddlewareTestCase, self).setUp() def test_no_locale(self): r1 = self.request_factory.get('/test/') r2 = self.middleware.process_request(r1) self.assertEqual(301, r2.status_code) self.assertEqual('/en/test/', r2['Location']) def test_non_ascii(self): r1 = self.request_factory.get('/plaît/') r2 = self.middleware.process_request(r1) self.assertEqual(301, r2.status_code) self.assertEqual('/en/pla%C3%AEt/', r2['Location']) def test_with_query_string(self): r1 = self.request_factory.get('/test/?somevar=someval') r2 = self.middleware.process_request(r1) self.assertEqual(301, r2.status_code) self.assertEqual('/en/test/?somevar=someval', r2['Location']) class NoDefaultPrefixMiddlewareTestCase(MiddlewareTestCase): def setUp(self): super(NoDefaultPrefixMiddlewareTestCase, self).setUp() self.settings_manager.set(PREFIX_DEFAULT_LOCALE=False) reload(localeurl_settings) def test_default_locale(self): r1 = self.request_factory.get('/test/foo/') r2 = self.middleware.process_request(r1) self.assertEqual(None, r2) self.assertEqual('en-gb', r1.LANGUAGE_CODE) self.assertEqual('/test/foo/', r1.path_info) def test_default_locale_specified(self): r1 = self.request_factory.get('/en/test/foo/') r2 = self.middleware.process_request(r1) self.assertEqual(301, r2.status_code) self.assertEqual('/test/foo/', r2['Location']) def test_alternate_locale(self): r1 = self.request_factory.get('/fr/test/foo/') r2 = self.middleware.process_request(r1) self.assertEqual(None, r2) self.assertEqual('fr', r1.LANGUAGE_CODE) self.assertEqual('/test/foo/', r1.path_info) class TagsTestCase(LocaleurlTestCase): def render_template(self, text): t = test_utils.TestTemplate(text, libraries=[localeurl_tags.register]) c = template.Context() return t.render(c) def test_locale_url_tag(self): self.assertRaises(ValueError, self.render_template, '{% locale_url "nl" dummy0 %}') self.assertEqual('/en/dummy/', self.render_template( '{% locale_url "en-us" dummy0 %}')) self.assertEqual('/fr/dummy/4', self.render_template( '{% locale_url "fr" dummy1 test=4 %}')) self.assertEqual('/en/dummy/4', self.render_template( '{% locale_url "en" dummy1 test=4 as testvar %}{{ testvar }}')) def test_chlocale_filter(self): self.assertEqual('/fr/dummy/', self.render_template( '{{ "/dummy/"|chlocale:"fr" }}')) self.assertEqual('/en/dummy/', self.render_template( '{{"/fr/dummy/"|chlocale:"en-gb"}}')) def test_rmlocale_filter(self): self.assertEqual('/dummy/', self.render_template( '{{ "/dummy/"|rmlocale }}')) self.assertEqual('/dummy/', self.render_template( '{{ "/nl-be/dummy/"|rmlocale }}')) self.assertEqual('/dummy/', self.render_template( '{{ "/en/dummy/"|rmlocale }}')) def test_locale_url_tag_no_default_prefix(self): self.settings_manager.set(PREFIX_DEFAULT_LOCALE=False) reload(localeurl_settings) self.assertEqual('/dummy/', self.render_template( '{% locale_url "en-us" dummy0 %}')) self.assertEqual('/fr/dummy/', self.render_template( '{% locale_url "fr" dummy0 %}')) def test_chlocale_filter_no_default_prefix(self): self.settings_manager.set(PREFIX_DEFAULT_LOCALE=False) reload(localeurl_settings) self.assertEqual('/dummy/', self.render_template( '{{ "/nl-nl/dummy/"|chlocale:"en-gb" }}')) self.assertEqual('/fr/dummy/', self.render_template( '{{"/nl-nl/dummy/"|chlocale:"fr"}}')) try: from localeurl.templatetags import localeurl_future except ImportError: localeurl_future = None # @@@ use proper test skipping once Django 1.2 is minimum version if localeurl_future is not None: class FutureTagsTestCase(LocaleurlTestCase): def render_template(self, text): t = test_utils.TestTemplate(text, libraries=[localeurl_future.register]) c = template.Context() return t.render(c) def test_locale_url_tag(self): self.assertRaises(ValueError, self.render_template, '{% locale_url "nl" "dummy0" %}') self.assertEqual('/en/dummy/', self.render_template( '{% locale_url "en-us" "dummy0" %}')) self.assertEqual('/fr/dummy/4', self.render_template( '{% locale_url "fr" "dummy1" test=4 %}')) self.assertEqual('/en/dummy/4', self.render_template( '{% locale_url "en" "dummy1" test=4 as testvar %}{{ testvar }}')) def test_locale_url_tag_no_default_prefix(self): self.settings_manager.set(PREFIX_DEFAULT_LOCALE=False) reload(localeurl_settings) self.assertEqual('/dummy/', self.render_template( '{% locale_url "en-us" "dummy0" %}')) self.assertEqual('/fr/dummy/', self.render_template( '{% locale_url "fr" "dummy0" %}')) class DummyModel(object): def __init__(self, num): self.num = num def get_absolute_url(self): return '/dummy/%s/' % self.num class DummySitemap(LocaleurlSitemap): def items(self): return [DummyModel(i) for i in range(3)] class SitemapTestCase(LocaleurlTestCase): def setUp(self): super(SitemapTestCase, self).setUp() class DummySite(object): domain = 'www.example.com' from django.contrib.sites.models import Site self._orig_get_current = Site.objects.get_current Site.objects.get_current = lambda: DummySite() def test_localeurl_sitemap(self): sitemap = DummySitemap('fr') self.assertEqual(sitemap.get_urls()[0]['location'], 'http://www.example.com/fr/dummy/0/') def tearDown(self): super(SitemapTestCase, self).tearDown() from django.contrib.sites.models import Site Site.objects.get_current = self._orig_get_current class ReverseTestCase(LocaleurlTestCase): def test_args_kwargs_none(self): url = reverse("dummy0", args=None, kwargs=None) self.assertEqual(url, "/en/dummy/") def test_args_none(self): url = reverse("dummy1", args=None, kwargs=dict(test="test")) self.assertEqual(url, "/en/dummy/test") def test_kwargs_none(self): url = reverse("dummy1", args=["test"], kwargs=None) self.assertEqual(url, "/en/dummy/test") django-localeurl-1.5/localeurl/tests/models.py0000664000175000017500000000000011552162057021060 0ustar carljmcarljmdjango-localeurl-1.5/localeurl/settings.py0000664000175000017500000000157211607632201020304 0ustar carljmcarljmimport re from django.conf import settings SUPPORTED_LOCALES = dict(settings.LANGUAGES) # Issue #15. Sort locale codes to avoid matching e.g. 'pt' before 'pt-br' LOCALES_RE = '|'.join( sorted(SUPPORTED_LOCALES.keys(), key=lambda i: len(i), reverse=True)) PATH_RE = re.compile(r'^/(?P%s)(?P.*)$' % LOCALES_RE) LOCALE_INDEPENDENT_PATHS = [re.compile(p) for p in getattr(settings, 'LOCALE_INDEPENDENT_PATHS', [])] LOCALE_INDEPENDENT_MEDIA_URL = getattr(settings, 'LOCALE_INDEPENDENT_MEDIA_URL', True) LOCALE_INDEPENDENT_STATIC_URL = getattr(settings, 'LOCALE_INDEPENDENT_STATIC_URL', True) PREFIX_DEFAULT_LOCALE = getattr(settings, 'PREFIX_DEFAULT_LOCALE', True) USE_ACCEPT_LANGUAGE = getattr(settings, 'LOCALEURL_USE_ACCEPT_LANGUAGE', False) LOCALE_REDIRECT_PERMANENT = getattr(settings, 'LOCALE_REDIRECT_PERMANENT', True) django-localeurl-1.5/localeurl/__init__.py0000644000175000017500000000000011475212727020174 0ustar carljmcarljmdjango-localeurl-1.5/localeurl/sitemaps.py0000664000175000017500000000065411552207447020302 0ustar carljmcarljmfrom django.contrib.sitemaps import Sitemap from localeurl.templatetags.localeurl_tags import chlocale class LocaleurlSitemap(Sitemap): """ From a `snippet by tomas`_. .. _`snippet by tomas`: http://www.djangosnippets.org/snippets/1620/ """ def __init__(self, language): self.language = language def location(self, obj): return chlocale(obj.get_absolute_url(), self.language) django-localeurl-1.5/localeurl/views.py0000644000175000017500000000142311475212726017603 0ustar carljmcarljmfrom urlparse import urlsplit from django import http from django.utils.translation import check_for_language from localeurl import utils def change_locale(request): """ Redirect to a given url while changing the locale in the path The url and the locale code need to be specified in the request parameters. """ next = request.REQUEST.get('next', None) if not next: next = urlsplit(request.META.get('HTTP_REFERER', None))[2] if not next: next = '/' _, path = utils.strip_path(next) if request.method == 'POST': locale = request.POST.get('locale', None) if locale and check_for_language(locale): path = utils.locale_path(path, locale) response = http.HttpResponseRedirect(path) return response django-localeurl-1.5/localeurl/urls.py0000644000175000017500000000026211475212726017433 0ustar carljmcarljmfrom django.conf.urls.defaults import * from localeurl.views import change_locale urlpatterns = patterns('', url(r'^change/', change_locale, name='localeurl_change_locale'), ) django-localeurl-1.5/localeurl/middleware.py0000664000175000017500000000657411607632271020577 0ustar carljmcarljmfrom django.conf import settings import django.core.exceptions from django.http import HttpResponsePermanentRedirect, HttpResponseRedirect from django.utils import translation from django.utils.encoding import iri_to_uri from django.utils.translation.trans_real import parse_accept_lang_header from localeurl import settings as localeurl_settings # Importing models ensures that reverse() is patched soon enough. Refs #5. from localeurl import utils # Make sure the default language is in the list of supported languages assert utils.supported_language(settings.LANGUAGE_CODE) is not None, \ "Please ensure that settings.LANGUAGE_CODE is in settings.LANGUAGES." class LocaleURLMiddleware(object): """ Middleware that sets the language based on the request path prefix and strips that prefix from the path. It will also automatically redirect any path without a prefix, unless PREFIX_DEFAULT_LOCALE is set to True. Exceptions are paths beginning with MEDIA_URL and/or STATIC_URL (if settings.LOCALE_INDEPENDENT_MEDIA_URL and/or settings.LOCALE_INDEPENDENT_STATIC_URL are set) or matching any regular expression from LOCALE_INDEPENDENT_PATHS from the project settings. For example, the path '/en/admin/' will set request.LANGUAGE_CODE to 'en' and request.path to '/admin/'. Alternatively, the language is set by the first component of the domain name. For example, a request on 'fr.example.com' would set the language to French. If you use this middleware the django.core.urlresolvers.reverse function is be patched to return paths with locale prefix (see models.py). """ def __init__(self): if not settings.USE_I18N: raise django.core.exceptions.MiddlewareNotUsed() def process_request(self, request): locale, path = utils.strip_path(request.path_info) if localeurl_settings.USE_ACCEPT_LANGUAGE and not locale: accept_langs = filter(lambda x: x, [utils.supported_language(lang[0]) for lang in parse_accept_lang_header( request.META.get('HTTP_ACCEPT_LANGUAGE', ''))]) if accept_langs: locale = accept_langs[0] locale_path = utils.locale_path(path, locale) if locale_path != request.path_info: if request.META.get("QUERY_STRING", ""): locale_path = "%s?%s" % (locale_path, request.META['QUERY_STRING']) locale_url = utils.add_script_prefix(locale_path) redirect_class = HttpResponsePermanentRedirect if not localeurl_settings.LOCALE_REDIRECT_PERMANENT: redirect_class = HttpResponseRedirect # @@@ iri_to_uri for Django 1.0; 1.1+ do it in HttpResp...Redirect return redirect_class(iri_to_uri(locale_url)) request.path_info = path if not locale: try: locale = request.LANGUAGE_CODE except AttributeError: locale = settings.LANGUAGE_CODE translation.activate(locale) request.LANGUAGE_CODE = translation.get_language() def process_response(self, request, response): if 'Content-Language' not in response: response['Content-Language'] = translation.get_language() translation.deactivate() return response django-localeurl-1.5/localeurl/models.py0000664000175000017500000000142311552114271017723 0ustar carljmcarljmfrom django.conf import settings from django.core import urlresolvers from django.utils import translation from localeurl import utils def reverse(*args, **kwargs): reverse_kwargs = kwargs.get('kwargs') or {} locale = utils.supported_language(reverse_kwargs.pop( 'locale', translation.get_language())) url = django_reverse(*args, **kwargs) _, path = utils.strip_script_prefix(url) return utils.locale_url(path, locale) django_reverse = None def patch_reverse(): """ Monkey-patches the urlresolvers.reverse function. Will not patch twice. """ global django_reverse if urlresolvers.reverse is not reverse: django_reverse = urlresolvers.reverse urlresolvers.reverse = reverse if settings.USE_I18N: patch_reverse() django-localeurl-1.5/runtests.py0000755000175000017500000000263211625260104016347 0ustar carljmcarljm#!/usr/bin/env python from os.path import dirname, abspath import sys from django.conf import settings if not settings.configured: from django import VERSION settings_dict = dict( INSTALLED_APPS=( 'localeurl', 'localeurl.tests', 'django.contrib.sites', # for sitemap test ), ROOT_URLCONF='localeurl.tests.test_urls', SITE_ID=1, ) if VERSION >= (1, 2): settings_dict["DATABASES"] = { "default": { "ENGINE": "django.db.backends.sqlite3" }} else: settings_dict["DATABASE_ENGINE"] = "sqlite3" settings.configure(**settings_dict) def runtests(*test_args): if not test_args: test_args = ['tests'] parent = dirname(abspath(__file__)) sys.path.insert(0, parent) try: from django.test.simple import DjangoTestSuiteRunner def run_tests(test_args, verbosity, interactive): runner = DjangoTestSuiteRunner( verbosity=verbosity, interactive=interactive, failfast=False) return runner.run_tests(test_args) except ImportError: # for Django versions that don't have DjangoTestSuiteRunner from django.test.simple import run_tests failures = run_tests( test_args, verbosity=1, interactive=True) sys.exit(failures) if __name__ == '__main__': runtests(*sys.argv[1:]) django-localeurl-1.5/LICENSE.txt0000644000175000017500000000206611570477525015747 0ustar carljmcarljmCopyright (c) 2008-2011 Joost Cassee and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. django-localeurl-1.5/docs/0000775000175000017500000000000011625261240015034 5ustar carljmcarljmdjango-localeurl-1.5/docs/setup.rst0000644000175000017500000000714611607634433016744 0ustar carljmcarljm============ Installation ============ This section describes how to install the localeurl application in your Django project. Prerequisites ------------- The localeurl application requires Django_ 1.0 or higher. .. _Django: http://www.djangoproject.com/download/ Setup ----- Setup consists of installing the middleware and adding ``'localeurl'`` to the installed applications list. #. Add ``'localeurl.middleware.LocaleURLMiddleware'`` to ``settings.MIDDLEWARE_CLASSES``. It must come *before* ``'django.middleware.common.CommonMiddleware'`` or ``settings.APPEND_SLASH`` will not work. Make sure Django's built-in ``LocaleMiddleware`` is **not** in your ``MIDDLEWARE_CLASSES`` setting; ``LocaleURLMiddleware`` replaces it and the two will not work together. #. Add ``'localeurl'`` to ``settings.INSTALLED_APPS``. Because the application needs to replace the standard ``urlresolvers.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 in ``settings.LANGUAGES``. For example, if ``LANGUAGE_CODE == 'en-us'`` then ``LANGUAGES`` must contain either ``'en-us'`` or ``'en'``. If you have not changed either option you do not have to do anything. .. _configuration: 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, if ``LANGUAGE_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 to ``settings.LANGUAGE_CODE``). ``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 to ``False``, as the redirect will then be dependent on the user's Accept-Language header. django-localeurl-1.5/docs/usage.rst0000644000175000017500000001364311552131665016705 0ustar carljmcarljm===== 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``.) 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`_. .. _new url tag syntax: http://docs.djangoproject.com/en/1.3/releases/1.3/#changes-to-url-and-ssi Example ------- You can refer to a specific URL in a specified language like this:: Show article in German 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:: Show article in German 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 here 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 %}
  • {{ lang.1 }}
  • {% else %}
  • {{ lang.1 }}
  • {% endifequal %} {% endfor %} The ``rmlocale`` filter ~~~~~~~~~~~~~~~~~~~~~~~ You can use the ``rmlocale`` filter to remove the locale prefix from a path. It takes no arguments. Example ------- To remove the language prefix for a URL: The language-independent URL for this page is {{ request.path|rmlocale }}. 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`_. .. _`redirect view`: http://docs.djangoproject.com/en/dev/topics/i18n/#the-set-language-redirect-view Example ------- This form shows a drop-down box to change the page language:: {% load i18n %}
    Sitemaps ======== Localeurl supplies a ``LocaleurlSitemap`` class for more convenient creation of sitemaps that include URLs in all available languages, based on `this snippet`_. .. _`this snippet`: http://www.djangosnippets.org/snippets/1620/ 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}), ) django-localeurl-1.5/docs/history.rst0000664000175000017500000001166211625261004017273 0ustar carljmcarljm======= History ======= Changelog --------- Release 1.5: (2011-08-24) * Added ``LOCALE_REDIRECT_PERMANENT`` setting; defaults to True, if set to ``False`` 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`` to ``localeurl.middleware``, to ensure that ``reverse`` 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 mirror ``LOCALE_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 provide ``locale_url`` tag that wraps the new Django ``url`` 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. 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 to ``settings.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. Release 1.0: (2008-09-10): * Added Django 1.0 or higher as a prerequisite. * Moved to Google Code. .. _`BitBucket`: http://www.bitbucket.org/carljm/django-localeurl/ .. _`a blog post`: http://andialbrecht.blogspot.com/2008/10/google-code-sphinx-theme.html 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: * `Announcement on django-users`_ * `Announcement on django-multilingual`_ .. _`Carl Meyer`: http://www.oddbird.net/ .. _`Joost Cassee`: http://joost.cassee.net/ .. _`django-localize`: http://github.com/kron4eg/django-localize/tree/master .. _`Artiom Diomin`: http://jabber.linux.md/ .. _django-users: http://groups.google.com/group/django-users .. _django-multilingual: http://code.google.com/p/django-multilingual/ .. _`Locale from URL Middleware`: http://groups.google.com/group/django-users/browse_thread/thread/7c5508174340191a/8cb2eb93168ef282 .. _`creating a multilingual middleware`: http://groups.google.com/group/django-multilingual/browse_thread/thread/b05fc30232069e1d/3e2e3ef2830cc36a .. _`multilingual middleware NEW FEATURE!`: http://groups.google.com/group/django-multilingual/browse_thread/thread/6801ea196d2aa2a9/1c8c854c474cb420 .. _`this blog post on internationalisation`: http://yml-blog.blogspot.com/2007/12/django-internationalisation.html .. _`Announcement on django-users`: http://groups.google.com/group/django-users/browse_thread/thread/413e46ab3517831 .. _`Announcement on django-multilingual`: http://groups.google.com/group/django-multilingual/browse_thread/thread/bb56598b289bd488 django-localeurl-1.5/docs/index.rst0000644000175000017500000000330511475212726016704 0ustar carljmcarljmWelcome to django-localeurl =========================== 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. .. _Django: http://www.djangoproject.com/ .. _`Django ticket #3651`: http://code.djangoproject.com/ticket/3651 You can install localeurl with pip_:: pip install django-localeurl or install the `in-development version`_:: pip install django-localeurl==dev .. _pip: http://pip.openplans.org .. _`in-development version`: http://bitbucket.org/carljm/django-localeurl/get/tip.gz#egg=django-localeurl-dev .. comment: split here The localeurl code is licensed under the `MIT License`_. See the ``LICENSE.txt`` file in the distribution. .. _`MIT License`: http://www.opensource.org/licenses/mit-license.php Documentation ------------- .. toctree:: :maxdepth: 2 setup usage history django-localeurl-1.5/HGREV0000644000175000017500000000000311625261236014676 0ustar carljmcarljm103django-localeurl-1.5/PKG-INFO0000664000175000017500000000532011625261240015201 0ustar carljmcarljmMetadata-Version: 1.0 Name: django-localeurl Version: 1.5 Summary: A Django application that allow you to specify the language of a page in the URL. Home-page: http://packages.python.org/django-localeurl/ Author: Carl Meyer Author-email: carl@oddbird.net License: MIT License Description: Welcome to django-localeurl =========================== 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. .. _Django: http://www.djangoproject.com/ .. _`Django ticket #3651`: http://code.djangoproject.com/ticket/3651 You can install localeurl with pip_:: pip install django-localeurl or install the `in-development version`_:: pip install django-localeurl==dev .. _pip: http://pip.openplans.org .. _`in-development version`: http://bitbucket.org/carljm/django-localeurl/get/tip.gz#egg=django-localeurl-dev .. comment: See the `full documentation`_. .. _`full documentation`: http://packages.python.org/django-localeurl/ Keywords: django i18n Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Framework :: Django Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Application Frameworks Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Localization