Mark
Mark

Reputation: 19969

When using i18n_patterns, how to reverse url without language code

I am using i18n_patterns but I want to use reverse to create a link to the page without language in the url (such that the user will be redirected based on cookies and headers and such).

I have tried

from django.utils.translation import activate, deactivate, get_language
current_lang = get_language()
deactivate()
url = reverse(things)
activate(current_lang)

That works for getting other language versions using activate(target_lang), but if I deactivate I just get urls for the default language (/en/account/ but I want /account/).

I already thought getting alternate language versions is overly complicated, but this I cannot manage at all. Any hints? (Without manually stripping LANGUAGE_CODE from the url)

UPDATE: I also tried

from django.core.urlresolvers import get_resolver
get_resolver(None).reverse(*args, **kwargs)

but get NoReverseMatch

Upvotes: 4

Views: 3849

Answers (3)

Chris
Chris

Reputation: 6382

Another route that is vanilla Django, but affects your URLs, Django provides the ability to omit the language prefix for your default language. Then reverse will work as you wish.

If in urls.py you turn off the language prefix for your default language, using the prefix_default_language parameter of the i18n_patterns method:

i18n_patterns(path(), path(), ..., prefix_default_language=False)

Then, when the default language is activated, the URL without the prefix is returned by reverse:

>>> activate(settings.LANGUAGE_CODE)  # or activate("en")
>>> reverse("news:index")
'/news/'

>>> activate("nl")
>>> reverse("news:index")
'/nl/news/'

Upvotes: 0

Gosti
Gosti

Reputation: 41

I also spent time to find a nice solution and here is mine.

Next to main urls file ('my_project/urls.py'), create the file 'my_project/urls_without_lang.py' with the content below.

Then, you can use reverse('viewname', urlconf='my_project.urls_without_lang')

Django=<1.11

from copy import copy

from django.urls.resolvers import LocaleRegexURLResolver

from .urls import urlpatterns as urlpatterns_i18n

"""
Purpose of this file is to be able to reverse URL patterns without language prefix.
This is usefull to build URL meant to be communicated "outside" of the domain without any language duty.

To use it with 'reverse' method (from django.shortcuts module), simply give the additional parameter:
    `urlconf='my_project.urls_without_lang'`
Example: `reverse('viewname', urlconf='my_project.urls_without_lang')`
"""

urlpatterns = copy(urlpatterns_i18n)
for el in urlpatterns_i18n:
    if isinstance(el, LocaleRegexURLResolver):
        urlpatterns.remove(el)
        urlpatterns += el.url_patterns

Django>1.11

from copy import copy

from django.urls import URLResolver

from .urls import urlpatterns as urlpatterns_i18n

urlpatterns = copy(urlpatterns_i18n)
for el in urlpatterns_i18n:
    if isinstance(el, URLResolver) and isinstance(el.urlconf_name, list):
        urlpatterns.remove(el)
        urlpatterns += el.url_patterns

Hope that will help some of you.

Upvotes: 0

mbrochh
mbrochh

Reputation: 1011

I think the easiest way is to let Django resolve the URL with the language prefix and then just remove the language prefix.

You can write the following function:

import re
from django.core.urlresolvers import reverse

def reverse_no_i18n(viewname, *args, **kwargs):
    result = reverse(viewname, *args, **kwargs)
    m = re.match(r'(/[^/]*)(/.*$)', result)
    return m.groups()[1]

Now, anywhere in your code you can do something like this:

from myproject.utils import reverse_no_i18n

def my_view(request):
    return HttpResponseRedirect(reverse_no_i18n('my_view_name'))

You might also want to create a custom {% url %} templatetag which calls your custom function.

Upvotes: 3

Related Questions