Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How could I use Django i18n/setlang without form select and submit button?

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?

like image 878
msampaio Avatar asked Aug 28 '16 21:08

msampaio


2 Answers

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.

like image 104
Daniel Roseman Avatar answered Nov 03 '22 01:11

Daniel Roseman


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 dropdown menu screenshot

css

.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;
}

html

<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>
like image 26
J0ANMM Avatar answered Nov 03 '22 00:11

J0ANMM