Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django i18n default language without path prefixes

I have an existing multi-lingual Django app that I'm porting to Django 1.4. I18n support is currently based on some ugly hacks, I'd like to make it use Django's built-in i18n modules.

One constraint is that I don't want to change the urls that are already in place. This site has been active for a while and there are external links to it that I dont' want to break or redirect. The urls scheme works like this: English content is at the root of the site, while other languages use prefixes in the domain name:

English urls:

/
/articles/
/suggestions/

Spanish urls:

/es/
/es/articulos/
/es/sugerencias/

I've got the translated pages working with Django 1.4's i18n modules, but it really, really, really wants to put all the English urls under /en/. I've tried a few different hacks, including defining non-internationalized urls for the English version:

def build(callback):
  return callback('',
    url(_(r'^$'), home.index, name="home"),
    url(_(r'^articles/$'), content.article_list, name='article_list'),
    url(_(r'^suggestions/$'), suggestions.suggestions, name='suggestions'),
  )

urlpatterns = build(patterns)
urlpatterns += build(i18n_patterns)

This makes the urls resolve properly, but the {% url %} tag to do reverse resolution doesn't work.

What's the best way to accomplish non-prefixed English-language urls?

like image 506
Colin Putney Avatar asked Nov 29 '12 23:11

Colin Putney


2 Answers

I used solid-i18n-url to solve similar problem: https://github.com/st4lk/django-solid-i18n-urls

Nice description how it works located here: http://www.lexev.org/en/2013/multilanguage-site-django-without-redirects/

like image 167
Dmytriy Voloshyn Avatar answered Nov 06 '22 03:11

Dmytriy Voloshyn


UPDATE: Read answer bellow, Django 1.10 supports it natively

I faced this problem and solved this way:

  • Created an alternative i18n_patterns that do not prefix the site main language (defined in settings.LANGUAGE_CODE).

  • Created an alternative middleware that only uses the URL prefixes language to activate the current language.

I didn't see any side-effect using this technique.

The code:

# coding: utf-8
"""
Cauê Thenório - cauelt(at)gmail.com

This snippet makes Django do not create URL languages prefix (i.e. /en/)
for the default language (settings.LANGUAGE_CODE).

It also provides a middleware that activates the language based only on the URL.
This middleware ignores user session data, cookie and 'Accept-Language' HTTP header.

Your urls will be like:

In your default language (english in example):

    /contact
    /news
    /articles

In another languages (portuguese in example):

    /pt/contato
    /pt/noticias
    /pt/artigos

To use it, use the 'simple_i18n_patterns' instead the 'i18n_patterns'
in your urls.py:

    from this_sinppet import simple_i18n_patterns as i18n_patterns

And use the 'SimpleLocaleMiddleware' instead the Django's 'LocaleMiddleware'
in your settings.py:

    MIDDLEWARE_CLASSES = (
    ...
        'this_snippet.SimpleLocaleMiddleware'
    ...
    )

Works on Django >=1.4
"""

import re

from django.conf import settings
from django.conf.urls import patterns
from django.core.urlresolvers import LocaleRegexURLResolver
from django.middleware.locale import LocaleMiddleware
from django.utils.translation import get_language, get_language_from_path
from django.utils import translation


class SimpleLocaleMiddleware(LocaleMiddleware):

    def process_request(self, request):

        if self.is_language_prefix_patterns_used():
            lang_code = (get_language_from_path(request.path_info) or
                         settings.LANGUAGE_CODE)

            translation.activate(lang_code)
            request.LANGUAGE_CODE = translation.get_language()


class NoPrefixLocaleRegexURLResolver(LocaleRegexURLResolver):

    @property
    def regex(self):
        language_code = get_language()

        if language_code not in self._regex_dict:
            regex_compiled = (re.compile('', re.UNICODE)
                              if language_code == settings.LANGUAGE_CODE
                              else re.compile('^%s/' % language_code, re.UNICODE))

            self._regex_dict[language_code] = regex_compiled
        return self._regex_dict[language_code]


def simple_i18n_patterns(prefix, *args):
    """
    Adds the language code prefix to every URL pattern within this
    function, when the language not is the main language.
    This may only be used in the root URLconf, not in an included URLconf.

    """
    pattern_list = patterns(prefix, *args)
    if not settings.USE_I18N:
        return pattern_list
    return [NoPrefixLocaleRegexURLResolver(pattern_list)]

The code above is available on: https://gist.github.com/cauethenorio/4948177

like image 43
Cauê Thenório Avatar answered Nov 06 '22 03:11

Cauê Thenório