I need to render a language selector as an unordered list in Django such as:
<ul>
...
<li><a href="???">EN</a></li>
<li><a href="???">FR</a></li>
<ul>
I'm using Django i18n/set_language
without i18n_pattern
and it works very well if I use the form below, given in the documentation:
{% load i18n %}
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>
I'd like to continue using i18n/set_language
, but with the <li>
structure, without the form <select>
and the submit button.
Is it possible? How could I do this?
As that link explains, the built-in set_language view is expecting a POST, which you can't do from a link (except by using Javascript).
But the next section, Explicitly setting the active language, gives you all the details you need to write your own view that can take the parameter from the URL. So:
def set_language_from_url(request, user_language):
translation.activate(user_language)
request.session[translation.LANGUAGE_SESSION_KEY] = user_language
return redirect(' ...somewhere... ')
and give it a URL:
url(r'/set_language/(?P<user_language>\w+)/$', set_language_from_url, name="set_language_from_url")
Now you can do:
<li><a href="{% url "set_language_from_url" user_language="en" %}">EN</a></li>
<li><a href="{% url "set_language_from_url" user_language="fr" %}">FR</a></li>
etc.
I really didn't like the idea of having to do 2 clicks (one for selecting the language and another click to "Go" to submit it), so I found a work-around. It is still a form, but it works like a list:
As explained here, one can use buttons instead of links:
<form action="{% url 'set_language' %}" method="post"> {% csrf_token %} <input name="next" type="hidden" value="{{ request.get_full_path|slice:'3:' }}" /> <ul class="nav navbar-nav navbar-right language menu"> {% get_current_language as LANGUAGE_CODE %} {% get_available_languages as LANGUAGES %} {% get_language_info_list for LANGUAGES as languages %} {% for language in languages %} <li> <button type="submit" name="language" value="{{ language.code }}" class="{% if language.code == LANGUAGE_CODE %}selected{% endif %}"> {{ language.name_local }} </button> </li> {% endfor %} </ul> </form>
Then, as per Bootstrap Dropdown docs:
Historically dropdown menu contents had to be links, but that’s no longer the case with v4. Now you can optionally use elements in your dropdowns instead of just s.
Merge both and tune it a bit with css to make it look like a list, and this is how it looks like for me:
.language-btn{
background-color: #c9f0dd;
border: 1px solid #c9f0dd;
border-radius: 2px;
color: #0C4B33;
font-size: 10px;
margin-right: 5px;
}
.navbar-right{
margin-right: 20px;
}
.dropdown-menu{
min-width: inherit;
}
.fake-btn{
background-color: transparent;
border: none;
color: rgb(150,150,150);
height: 12px;
font-size: 11px;
}
.no-margins{
margin: 0;
padding: 0;
}
.selected{
color: #0C4B33;
}
<div class="btn-group nav navbar-nav navbar-right language menu">
<button class="btn btn-secondary btn-sm dropdown-toggle language-btn" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{% get_language_info for LANGUAGE_CODE as lang %}
{{ lang.name_local }} ({{ lang.code }})
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenu2">
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path|slice:'3:' }}" />
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<ul class="no-margins">
<button type="submit"
name="language"
value="{{ language.code }}"
class="{% if language.code == LANGUAGE_CODE %}selected{% endif %} dropdown-item fake-btn">
{{ language.name_local }} ({{ language.code }})
</button>
</ul>
{% endfor %}
</form>
</div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With