Rgfvfk Iff
Rgfvfk Iff

Reputation: 1609

Django url change language code

I am trying to change the language of the website when users click a button in Django.

I have a base project and the urls are:

urlpatterns += i18n_patterns(
    # Ecommerce is the app where I want to change the language
    url(r'^', include("ecommerce.urls")),
)

The url inside Ecommerce.urls is:

urlpatterns = [
    url(r'^testing/$', views.test, name='url_testing'),
    ... other urls
]

When I visit the url above, I first go to: http://localhost/en/testing/.

I want to set a link <a href="{% url 'url_testing' %}">Change Language</a> so that when users click it, it will change language to http://localhost/zh-hans/testing/. How do I do this in my template?

EDIT

I can now change the language using the following code but the problem is that it only works once:

<form id="languageForm" action="/i18n/setlang/" method="post">
    {% csrf_token %}
    <input name="next" type="hidden" value="{% url 'url_testing' %}" /> 
    <input id="newLanguageInput" type="hidden" name="language"/>
</form>

And my links are:

<li><a onclick="changeLanguage('zh-hans')">简体</a></li>
<li><a onclick="changeLanguage('zh-hant')">繁體</a></li>

The function changeLanguage is defined like:

function changeLanguage(newLanguage) {
    $('input[name="newLanguageInput"]').val(newLanguage);
    $('#languageForm').submit();
}

The code works when I first click any of the 2 links, and I will be redirected to the url http://localhost/zh-hans/testing/ or http://localhost/zh-hant/testing/. The problem is after I change the language once, it no longer changes. Is there something wrong with my submit?

Upvotes: 5

Views: 11415

Answers (4)

Dos
Dos

Reputation: 2507

I would add some improvements to the previous answers:

  1. Translate the url before the redirection
  2. Ensure to read the "next" param when present
  3. Disable the set_language redirect view

About points 1 and 2, here an improved implementation of the ActivateLanguageView, directly inspired by the django.views.i18n.set_language official Django function (that unfortunately is a POST)

from django.conf import settings
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import translate_url
from django.utils.translation import check_for_language
from django.views.generic import View


class ActivateLanguageView(View):

    def get(self, request, language_code, **kwargs):
        next_url = self.request.GET.get("next", self.request.META.get('HTTP_REFERER', '/'))
        response = HttpResponseRedirect(next_url) if next_url else HttpResponse(status=404)
        if check_for_language(language_code):
            if next_url:
                next_trans = translate_url(next_url, language_code)
                if next_trans != next_url:
                    response = HttpResponseRedirect(next_trans)
            response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language_code)
        return response

About point 3, the @Boris Đurkan and @jlandercy's answers about the url and template files are valid, but I'd explicitly remove the following if included in your urls:

urlpatterns = [
    # ...
    # path('i18n/', include('django.conf.urls.i18n')),  # REMOVE ME!
]

Here more details about the set_language redirect view from the official Django docs.

Upvotes: 1

jlandercy
jlandercy

Reputation: 10992

New snippets compatible with new API (Boostrap 5 and Django >= 4.0) updated from the excellent @Boris Đurkan answer.

Django has dropped the translation.LANGUAGE_SESSION_KEY support. So basically we need to make this setup using the session cookie.

class ActivateLanguageView(View):

    def get(self, request, lang, **kwargs):
        url = request.META.get('HTTP_REFERER', '/')
        translation.activate(lang)
        response = HttpResponseRedirect(url)
        response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang)
        return response

Boostrap has changed its jQuery binding for dropdown:

<li class="nav-item dropdown">
  {% get_current_language as LANGUAGE_CODE %}
  <a class="nav-link dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">
    <strong>{{ LANGUAGE_CODE }}</strong>
  </a>
  <div class="dropdown-menu dropdown-menu-right">

    {% get_available_languages as languages %}
    {% for lang_code, lang_name in languages %}

    <a href="{% url 'activate_language' lang_code %}" class="dropdown-item">
      {% if lang_code == LANGUAGE_CODE %}
        <i class="bi bi-check-circle"></i>&nbsp;&nbsp;
      {% else %}
        <i class="bi bi-circle"></i>&nbsp;&nbsp;
      {% endif %}
      {{ lang_name }} ({{ lang_code }})
    </a>

    {% endfor %}
  </div>
</li>

Other parts of code remains basically the same.

Upvotes: 3

Boris Đurkan
Boris Đurkan

Reputation: 601

You can change the language of the website when users click a link (no url translation, no post) like this:

navigation.html (with bootstrap4 and font awesome)

<li class="nav-item dropdown">
  {% get_current_language as LANGUAGE_CODE %}
  <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown">{{ LANGUAGE_CODE }}</a>
  <div class="dropdown-menu dropdown-menu-right">

    {% get_available_languages as languages %}
    {% for lang_code, lang_name in languages %}

    <a href="{% url 'main:activate_language' lang_code %}" class="dropdown-item">
      {% if lang_code == LANGUAGE_CODE %}
        <i class="fas fa-check-circle"></i>&nbsp;&nbsp;
      {% else %}
        <i class="far fa-circle"></i>&nbsp;&nbsp;
      {% endif %}
      {{ lang_name }} ({{ lang_code }})
    </a>

    {% endfor %}
  </div>
</li>

views.py

from django.shortcuts import redirect
from django.utils import translation
from django.views.generic.base import View

class ActivateLanguageView(View):
    language_code = ''
    redirect_to   = ''

    def get(self, request, *args, **kwargs):
        self.redirect_to   = request.META.get('HTTP_REFERER')
        self.language_code = kwargs.get('language_code')
        translation.activate(self.language_code)
        request.session[translation.LANGUAGE_SESSION_KEY] = self.language_code
        return redirect(self.redirect_to)

urls.py

from django.urls import path
from .views import ActivateLanguageView

app_name = 'main'
urlpatterns = [
    path('language/activate/<language_code>/', ActivateLanguageView.as_view(), name='activate_language'),
]

It's work for me.

Upvotes: 6

nik_m
nik_m

Reputation: 12086

Actually it's not going to be a simple <a> link but a <form>.

Have a read on how to set_language redirect view. This form will be responsible for changing languages. It's easy as a pie.

Make sure you have set some LANGUAGES first.

Upvotes: 4

Related Questions