Switching Django languages with flags and urls - django

I am currently having a language switcher in Django based on flags, but where the URL for all languages are the same.
I would now like to change the language switcher so that selecting a flag also redirects the user to a URL prefix (like /en, /es, /fr, etc.) so I easily can send the page in different default languages to different users. Linking to the URL prefix works fine, but how do I easiest redirect the users there when they select flags in the code below?
<div class="navbar-btns ml-3">
<div class="navbar-btns-inner">
<div id="language-switcher" class="navbar-btn collapsed">
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="/" />
<select name="language" onchange="this.form.submit()">
{% for language in request|get_language_info_list_ex %}
<option value="{{ language.code }}" {% if language.is_current %} selected="selected"{% endif %}>
<span class="flag">{{ language.flag }}</span>
{# {{ language.code }} #}
</option>
{% endfor %}
</select>
</form>
</div>
</div>
</div>

On my page I use a simple view and some regex to redirect the users back to the page they was on.
Here is my view
from django.conf import settings
from django.http import HttpResponseRedirect
from yourapp.utils.translation import get_locale_url
def set_language(request, language_code=None):
url = request.META.get('HTTP_REFERER', settings.BASE_URL)
url = get_locale_url(url, language_code)
return HttpResponseRedirect(url)
and my utils.translation.py
import re
from django.conf import settings
from django.utils.translation import get_language
def get_locale_url(url, language_code):
pattern = r'^(?:/)|^#$|(?:(?:https?://)?(?:yoursubdomain\.)?domain\.com/?(?:(?:sma|en)?/?)?)'
if settings.USE_I18N:
if any(language_code in language for language in settings.LANGUAGES):
if re.match(pattern, url, flags=re.I):
split_url = re.split(pattern, url, flags=re.I)
if language_code == "nb":
url = settings.BASE_URL + "/" + split_url[len(split_url)-1]
else:
url = settings.BASE_URL + "/" + language_code + "/" + split_url[len(split_url)-1]
return url
Change yoursubdomain (usually www) and yourdomain to work with your own site. You also neeed to add the language codes you have activated to your regex pattern. I use sma and en so I've written (sma|en).
It ain't the prettiest solution, but it works.

Related

How to prevent redirect_to_login from targeting LOGIN_REDIRECT_URL

So in general when a user logs in, my app redirects him to dashboard-overview:
# settings.py
# Login and Logout target routes
LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'dashboard-overview'
LOGOUT_REDIRECT_URL = '/'
However for a specific case I want the user to be redirected to 'calculator-page' using a helper function which doesn't work as the user is again redirected to the value of LOGIN_REDIRECT_URL.
# views.py
def render_calculator(request, slug):
"""
Renders the calculator page
"""
# Check for the user being authenticated
if not request.user.is_authenticated:
return redirect_to_login('calculator-page')
# routes to http://127.0.0.1:8000/login/?next=calculator-page which looks fine,
# but then it fails after login to re-route as specified and sends to
# 'dashboard-overview' again
else:
club_obj = Offer.objects.get(club__slug=slug)
# Create Context
context = {
'club_obj': club_obj,
}
return render(request, 'core/calculator.html', context)
# urls.py
from django.urls import path, include
from django.contrib.auth import views
from applications.user import views as user_views
urlpatterns = [
# Login View
path('login/', views.LoginView.as_view(template_name='user/login.html'), name="login"),
path('logout/', views.LogoutView.as_view(), name="logout"),
# Sign Up
path('signup/', user_views.signup, name='signup'),
]
# template user/login.html
{% extends 'user/user_frame.html' %}
{% load static %}
<!-- Styles -->
{% block styles %}
<link href="{% static 'css/user_frame.css' %}" rel="stylesheet" type="text/css">
{% endblock styles %}
{% block form %}
<div class="logo-container"><img src="{% static 'images/logo_negative_text.svg' %}" class="logo-image"></div>
<div class="form-container">
<!-- form headline -->
<h1 class="form-headline">Login to your Farena Account</h1>
<!-- form -->
<form class="form" method="post" action=".">
{% csrf_token %}
<div class="error-wrapper">
<div class="errors">{{ form.non_field_errors }}</div>
</div>
<div class="email-wrapper field-wrapper">
<div class="tag name-tag">{{ form.username.label }}*</div>
<div class="input">{{ form.username }}</div>
</div>
<div class="password-wrapper field-wrapper">
<div class="tag">{{ form.password.label }}*</div>
<div class="input">{{ form.password }}</div>
<div class="forgot-password">Forgot Password?</div>
</div>
<!-- submit button -->
<button class="login-button" type="submit">Log In</button>
</form>
</div>
<div class="account-info">No account yet? Sign Up!</div>
{% endblock form %}
The issue is with your template for the login view - you're missing the next form field that tells Django where to redirect the user after they have logged in. See the documentation for sample template code for this view.
Specifically, you need to add this inside your form:
<input type="hidden" name="next" value="{{ next }}">
That's missing right now which means Django will always just default to LOGIN_REDIRECT_URL.

How to render templates dynamically for a static user choice

I don't know how to put this question as a title. But my question is I have 2 templates for each view in my django project templates folder. One template for english language and another for spanish language. My templates structure is
Project
|
app
|
templates
|
app
|
home_en.html
home_es.html
about_en.html
about_es.html
I need to render the templates according to the user choice of language. I have the project now fully in english running. As a start I only have the templates converted to spanish and ready to render. I am sorry this is a vague question but some directions to this problem would help.
My main urls are
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^en/', include('app.urls')),
url(r'^es/', include('app.urls')),
]
my app urlpatterns are
urlpatterns = [
url(r'^about$', views.about, name='about'),
url(r'.*', views.home, name='home'), ]
I also tried checking the request url with /en/ or /es/ and then render according to it in each views like below.
def home(request):
if request.path == '/en/':
return render(request, 'app/home_en.html', {'title':'HOME'})
else:
return render(request, 'app/home_es.html', {'title':'HOME'})
def about(request):
if request.path == '/en/about':
return render(request, 'app/about_en.html', {'title':'ABOUT'})
else:
return render(request, 'app/about_es.html', {'title':'ABOUT'})
This works fine when I explicitly give url request as /en/ or /es/. How could i set it on the url based on the users selection of language ?
If I explicitly make request to http://127.0.0.1/es/about, my about page is shown in spanish but when I switch to home from there, it goes back to English home page. I want the url to stay as /es/ as the start even if I change the url. Now it changes to english since it is upper level in pattern
A very simple solution is to use a single pattern with a named group:
url(r'^(?P<language>en|es)/', include('app.urls'))
Your views must then accept the language parameter:
def home(request, language):
# language is either "es" or "en".
return render(request, 'app/home_{}.html'.format(language), {'title': 'HOME'})
You may also consider Django's localization and avoid duplicating the views.
Please read Django translation docs. here: https://docs.djangoproject.com/en/1.10/topics/i18n/translation/#module-django.conf.urls.i18n
See the part: Language prefix in URL patterns
in your urls.py:
from django.conf.urls.i18n import i18n_patterns
urlpatterns += i18n_patterns (
url(r'^about$', views.about, name='about'),
url(r'.*', views.home, name='home'),
)
This will automatically prefix you urls with language codes.
in the views.py you can get language code fomr request.LANGUAGE_CODE like this: from request.LANGUAGE_CODE == 'en'
To choose language put in your html templates:
{% load i18n %}
<form action="{% url 'set_language' %}" method="POST">{% csrf_token %}
<select name="language" id="language">
<option value="en">en</option>
<option value="ru">ru</option>
<option value="az">az</option>
</select>
<button type="submit">send</button>
</form>
or
{% 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>

Unable to set language after using "i18n_pattern" to show language prefix in URL

As suggested, I'm wanting to show a language prefix in the URL and allow a visitor to my site to change the language using a form in the template. I've been using the sections on URL prefix and set_language redirect view from the "Translation" page of the Django docs as a guide so far. My code is largely copied from this source.
The Problem
Without using "i18n_pattern" (having both "url" calls in "pattern") in my URLconf, I manage to select language on the index.html page and have Django redirect me to the same page with the new language I have chosen. However, of course, the language URL prefix isn't shown.
When I use "i18n_pattern", the language prefix appears in the URL but seems to break the ability to change languages from the index.html form. For example, if I'm set on English and I change from "English (en)" to "Türkçe (tr)" in the form, the page essentially does a refresh without changing to Turkish (English is still shown). I can however change the language by changing my URL language prefix from "/en/" to "/tr/".
pages/templates/pages/index.html:
{% load i18n %}
<html>
<head>
...
</head>
<body>
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language">
{% 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>
...
</body>
</html>
[project_name]/urls.py:
from django.conf.urls import patterns, include, url
from django.conf.urls.i18n import i18n_patterns
urlpatterns = patterns('',
url(r'^i18n/', include('django.conf.urls.i18n')),
)
urlpatterns += i18n_patterns('',
url(r'', include('pages.urls', namespace='pages')),
)
Note: The templates I'm using are located in the app called "pages".
Any help on getting these to work together would be appreciated! I have so far been unable to find anything on stackoverflow relating to this issue. If any more information is needed, please ask!
This StackOverflow question contains further details and some possible answers to the problem. None of the solutions are really appealing; nor should really be required. Unfortunately, this seems to be a problem with Django where both desired "features" can't work together "out-of-the-box" with the desired effect. In my case, since my site is a single page site, I can get away with setting the context variable with "redirect_to" = '/' (in the view) to negate the problem.

How to use django.views.i18n.set_language() function?

I read a tutorial in Django site but I don't understand how to use the set_language() function. For example, I have a demo follow as:
index.html
{% trans "Hello World." %}
<form action="/i18n/setlang/" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="/next/page/" />
<select name="language">
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}">{{ language.name_local }} ({{ language.code}})</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>
urls.py
urlpatterns = patterns('',
(r'^i18n/', include('django.conf.urls.i18n')),
)
views.py
What need I write to display the languages, which were chosen from user in this file?
Thanks,
Thinh
With the code you are using, you don't need to write your own views. The form will make a POST request to /i18n/setlang/, with the language code and (optional) the redirect-to (next) page as parameters.
The django view does the following (from the django documentation)
Django looks for a next parameter in the POST data.
- If that doesn't exist, or is empty, Django tries the URL in the Referrer header.
- If that's empty -- say, if a user's browser suppresses that header -- then the user will be - redirected to / (the site root) as a fallback.
So in essence, the user will be redirected after submitting the form, and the django view will set the language for that user according to what was submitted.
Hope this helps,
Hoff

How to explicitly set django_language in django session

How to explicitly set django_language in Django session?
Thanks a lot...
If you want your users to be able to specify language, make sure that LocaleMiddleware is enabled:
MIDDLEWARE_CLASSES = (
...
'django.middleware.locale.LocaleMiddleware',
...
)
Then Django will look for the user's language preference in that order (see get_language_from_request in trans_real.py):
in request.path_info, if i18n_patterns are used
request.session[settings.LANGUAGE_SESSION_KEY] (DEPRECATED in Django 3.0, removed in Django 4.0)
request.COOKIES[settings.LANGUAGE_COOKIE_NAME]
every language in request.META['HTTP_ACCEPT_LANGUAGE'], until accepted one is found
settings.LANGUAGE_CODE.
As of Django 4.0
The most straightforward way to set language explicitly in Django session is to activate and set the cookie, see the docs:
from django.conf import settings
from django.http import HttpResponse
from django.utils import translation
user_language = 'fr' # example
translation.activate(user_language)
# persist using the cookie
response = HttpResponse(...)
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, user_language)
Before Django 4.0
The most straightforward way to set language explicitly in Django session is to rewrite request.session[settings.LANGUAGE_SESSION_KEY]:
def someview (request):
...
request.session[settings.LANGUAGE_SESSION_KEY] = 'en'
...
And if you will use a version >= Django 1.8. Here it is how we could use that:
from django.utils.translation import LANGUAGE_SESSION_KEY
def someview (request):
...
request.session[LANGUAGE_SESSION_KEY] = 'en'
Consider using django.views.i18n.set_language(). Activate this view by adding the following line to your URLconf:
# This example makes the view available at /i18n/setlang/
url(r'^i18n/', include('django.conf.urls.i18n')),
As a convenience, Django comes with a view,
django.views.i18n.set_language(), that sets a user’s language
preference and redirects to a given URL or, by default, back to the
previous page.
The view expects to be called via the POST method, with a language
parameter set in request. If session support is enabled, the view
saves the language choice in the user’s session. Otherwise, it saves
the language choice in a cookie that is by default named
django_language. (The name can be changed through the
LANGUAGE_COOKIE_NAME setting.)
I think the best way is to follow Django documentation:
in your urls.py file:
urlpatterns = [
# other libraries
path('i18n/', include('django.conf.urls.i18n')),
]
and in your template file (ex: "/core.html") just call de standard "set_language" view. I'll go for a boostrap switcher:
{% load i18n %}
<ul class="navbar-nav">
<li class="dropdown nav-item">
<a href="#" class="dropdown-toggle nav-link" data-toggle="dropdown">
<i class="nc-icon nc-planet"></i>
</a>
<ul class="dropdown-menu">
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for lang in languages %}
<button type="submit"
name="language"
value="{{ lang.code }}"
class="dropdown-item">
{{ lang.name_local }}
</button>
{% endfor %}
</form>
</ul>
</li>
</ul>