Change languages on-the-fly with django
This is more a reminder than a proper post, but let’s see how do we do this. I’ve been weeks wondering how the heck I could change the language on the fly in a website with the django i18n system, and the worst is that IT’S DOCUMENTED, but it’s sparse across the documentation and the source code docs (hey guys, you could write down all the documentation from time to time).
Let’s start:
To have the translation system working you need to add this middleware to your settings:
1 | django.middleware.locale.LocaleMiddleware |
After that, on your urls.py file you need to include the i18n view:
1 | (r'^i18n/', include('django.conf.urls.i18n')), |
That view only accepts POST requests, so if for any reason you need a GET, you will better be prepared, because you have to modify a core view, or create your own one. Ok, that view will put the url “i18n/setlang” to our service. Let’s go to the interesting part, the HTML code:
1 2 3 4 5 6 7 8 9 | <form action="/i18n/setlang/" method="post">{% csrf_token %} <input name="next" type="hidden" value="/" /> <select name="language"> {% for lang in LANGUAGES %} <option value="{{ lang.0 }}">{{ lang.1 }}</option> {% endfor %} </select> <input type="submit" value="Go" /> </form> |
This code will make a dropdown list with ALL the languages supported by django (and there are quite a few) so if you want to restrict the languages you must set up the LANGUAGES variable in your settings.py with something like this:
1 2 3 4 5 | LANGUAGES = ( ('es', 'Spanish'), ('en', 'English'), ('gl', 'Galician'), ) |
Be warned, this language list is NOT translated, that means that wherever you are, that list will be always in english. To translate it you must make use of gettext directly. Do not attempt to use the translation utils from django, that will cause a circular import.
UPDATE:
Aleck gave us another way of doing the i18n selector, using links instead of a dropdown (which is very useful :) In this use case, we use list items for selecting from English and Dutch languages. This HTML code assumes you have this code in your settings.py:
1 2 3 4 | LANGUAGES = ( ('en', 'English'), ('nl', 'Dutch'), ) |
HTML code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <li> <form name="setLangEnglish" action="/i18n/setlang/" method="POST">{% csrf_token %} <input name="next" type="hidden" value="/" /> <input type="hidden" name="language" value="en" /> <a href="#" onclick="document.setLangEnglish.submit();return false;">English</a> </form> </li> <li> <form name="setLangDutch" action="/i18n/setlang/" method="POST">{% csrf_token %} <input name="next" type="hidden" value="/" /> <input type="hidden" name="language" value="nl" /> <a href="#" onclick="document.setLangDutch.submit();return false;">Dutch</a> </form> </li> |
Thank you very much Aleck!
UPDATE 2:
These days I’m updating the CSS of e-cidadania to Bootstrap 2.0 so I thought it could be a nice moment to change the language selector for something more stylish. Here is the code to use a list selector with bootstrap 2.0:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <ul class="nav pull-right"> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">{% trans "Language" %}<b class="caret"></b></a> <ul class="dropdown-menu"> {% for lang in LANGUAGES %} <li> <form name="setLang{{ lang.1}}" action="/i18n/setlang/" method="POST">{% csrf_token %} <input name="next" type="hidden" value="/" /> <input type="hidden" name="language" value="{{ lang.0 }}" /> <a href="#" onclick="document.setLang{{ lang.1 }}.submit();return false;">{{ lang.1 }}</a> </form> </li> {% endfor %} </ul> </li> </ul> |