4

After solving this problem here, there's another one: if you use the translation url system here https://docs.djangoproject.com/en/1.8/topics/i18n/translation/ you will see you add patterns like urlpatterns += i18n_patterns(...).

The problem is that the base url without the language is not taken in account ie:

  • resolve('/fr/produits/') works,
  • but resolve('/produits/') doesnt work and raises 404.

How to solve this?

Here are my urls:

urlpatterns = [
    url(r'^debug/?$', p_views.debug, name='debug'),
    url(r'^i18n/', include('django.conf.urls.i18n')),
    url(r'^login/(\w*)', p_views.login, name='login'),
    url(r'^admin/', include(admin_site.urls)),
    url(r'^public/(?P<path>.*)$',
        'django.views.static.serve',
        {'document_root': settings.MEDIA_ROOT},
        name='url_public'
        ),
]
urlpatterns += i18n_patterns(
    url(_(r'^produits/detail/(?P<slug>[a-zA-Z0-9-_]+)/$'),
        p_views.ProduitDetailView.as_view(), name='produits_detail'),
    url(_(r'^produits/'),
        p_views.IndexView.as_view(), name='produits_index'),
)

And here's the very simple URL-tester I've made (which corresponds to the /debug view):

def debug(req):

    def test(url):
        try:
            return u'<pre>{0} {1}</pre>'.format(url, resolve(url))
        except Resolver404:
            return u'<pre>{0} {1}</pre>'.format(url, 'None')

    response = HttpResponse()
    response.write(test('produits'))
    response.write(test('produits/'))
    response.write(test('/produits'))
    response.write(test('/produits/'))
    response.write(test('/fr/produits'))
    response.write(test('/fr/produits/'))
    response.write(test('/en/products/'))
    response.write(test('/sv/produkter/'))
    return response

Here's the http://localhost:8000/debug page:

produits None
produits/ None
/produits None
/produits/ None
/fr/produits None
/fr/produits/ ResolverMatch(func=produits.views.IndexView, args=(), kwargs={}, url_name=produits_index, app_name=None, namespaces=[])
/en/products/ None
/sv/produkter/ None

The three lastest lines should all return ResolverMatch(...) because they are all valid URLs.

Community
  • 1
  • 1
Olivier Pons
  • 15,363
  • 26
  • 117
  • 213
  • Related: [Django i18n default language without path prefixes](http://stackoverflow.com/q/13636604/1324033) – Sayse Sep 23 '15 at 12:15
  • @Sayse Thank you, but I've already read it and it doesn't solve my problem. I want to do kinddof "reverse translation" to go from `/sv/produkter/` to `/fr/produits/` (to see it's a valid URL) – Olivier Pons Sep 23 '15 at 12:20
  • Yeah thats why I didn't mark it as a duplicate. I didn't manage to find an exact resolution and haven't the time to help im afraid – Sayse Sep 23 '15 at 12:22
  • I've updated my question to show more details. – Olivier Pons Sep 23 '15 at 12:25

1 Answers1

5

Django's url resolvers only work on current language. So you will need to switch language before attempting to solve an url in a specific language, using translation.activate.

For resolving the url, that means you must know the language beforehand, switch to it and only then resolve (basically what the localemiddleware will do for you).

For reversing the url, that means you should probably reverse the url using its name. You'll get back the url in current language. I cannot test right now, but it should work like this:

from django.utils import translation
translation.activate('fr')
reverse('produits_index')    # /fr/produits/
translation.activate('en')
reverse('produits_index')    # /en/products/

If you did manage to get a ResolverMatch object, you have the url name as an attribute on it, conveniently named url_name.

I hope it helps, I am a bit unclear as to what you are trying to do. Feel free to comment/edit your question and I'll try to update this answer.


Update by Olivier Pons


Here's the working solution:

here's my working solution, which is close to spectras, but works the way I wanted:

# (!) resolve() use current language
#     -> try to guess language then activate BEFORE resolve()
lg_curr = translation.get_language()
lg_url = get_language_from_path(url) or lg_curr
translation.activate(lg_url)
try:
    resolve(url)
    req.session['url_back'] = url  # no error -> ok, remember this
except Resolver404:
    pass
translation.activate(lg_curr)

...and then later on, after successful registration/login, if there's a req.session['url_back'] then I remove it from session and make a redirect on it.

Olivier Pons
  • 15,363
  • 26
  • 117
  • 213
spectras
  • 13,105
  • 2
  • 31
  • 53