How to render templates dynamically for a static user choice - django

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>

Related

Switching Django languages with flags and urls

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.

How do you translate the slug value of a page?

I'm trying to implement a language switcher, for which I'm using the Django recommended form:
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
{% get_current_language as LANGUAGE_CODE %}
<input name="next" type="hidden" value="{{ redirect_to }}">
<input name="language" type="hidden" value="{% if LANGUAGE_CODE == 'en' %}es{% else %}en{% endif %}">
</form>
My urls.py is set up like so:
urlpatterns = [
# Wagtail urls
re_path(r'^cms/', include(wagtailadmin_urls)),
re_path(r'^documents/', include(wagtaildocs_urls)),
# Django urls
path('admin/', admin.site.urls),
path('i18n/', include('django.conf.urls.i18n')),
]
urlpatterns += i18n_patterns(
path(r'', include(wagtail_urls))
)
When I click to change my language, I am correctly forwarded to /en/slug or es/slug, depending on the language I have selected. However the actual slug value is not being translated. Since I have Spanish slugs for the Spanish pages, I am getting a 404 when I switch languages, because I am directed to the English slug value paired with the Spanish locale prefix (es).
I also tried using the slugurl_trans template tag, but that didn't seem to work (maybe because I'm not explicitly defining any URLs in my i18n_patterns call?).
Any guidance on this would be really helpful, as I've spent way too many hours on this!
It has been long but I'm going to post an answer anyway, the best way to get rid of the different slugs problem is by using django signals like this
#receiver(pre_save)
def set_translated_slug_on_new_instance(sender, instance, **kwargs):
if isinstance(instance, Page):
instance.slug_es = instance.slug_en

Django translate refers to wrong URL

I am using Django (version 2.1.3) in one of my project and currently struggle with a weird bug. I use the build in internationalization module and included a language toggler in my main menu which is loaded on every page
{% get_current_language as LANGUAGE_CODE %}
<form id="form" action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path|strip_lang }}" />
<input id="form_lang" name="language" type="hidden" value="{{ LANGUAGE_CODE }}"/>
</form>
<ul role="menu" class="dropdown-menu"id="lang-dropdown">
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<li>
<a href="#" onClick='(function(){
document.getElementById("form_lang").value = "{{ language.code }}";
document.getElementById("form").submit(); return false;})();return false;'>
{{ language.name_local }} ({{ language.code }})</a>
</li>
{% endfor %}
</ul>
I created a special tag "strip_lang" to strip the language identifier from the current URL.
#register.filter
#stringfilter
def strip_lang(value):
"""Removes all values of arg from the given string"""
lang = getattr(settings, "LANGUAGES", None)
url = value.split('/')
if url[1] in [l[0] for l in lang]:
return urllib.parse.unquote('/' + '/'.join(value.split('/')[2:]))
else:
return urllib.parse.unquote(value)
This all works well. However, for one of my apps, I always get rerouted to a different app.
ie if I am at path
/en/app1/mypage1
and toggle the language i suddenly end up at
/fr/app2/mypage1
*****EDIT*****
Referals for app2 work correctly. When entering a URL manually for app1 the pages load correctly.
My url.py in the main project looks like this
urlpatterns = [
path('admin/', admin.site.urls),
path('i18n/', include('django.conf.urls.i18n')),
]
urlpatterns += i18n_patterns(
path('app1/', include('app1.urls')),
path('app2/', include('app2.urls')),
path('app3/', include('app3.urls')),
url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),
url(r'^login/$', auth_views.LoginView.as_view(), {'template_name': 'login.html'}, name='login'),
url(r'^logout/$', auth_views.LogoutView.as_view(), {'template_name': 'logged_out.html'}, name='logout'),
url(r'^oauth/', include('social_django.urls', namespace='social')),
prefix_default_language=False)
ans urls.py of my apps look like this
urlpatterns = [
path('', views.index, name='index'),
path('surveys/', views.nrgt_surveys, name='nrgt_surveys'),
path('surveys/<str:survey_name>/', views.survey, name='survey'),
path('surveys/<str:survey_name>/<query_name>', views.survey_query, name='survey_query'),
path('landscapes/', views.landscapes, name='landscapes'),
path('landscapes/<str:landscape_name>/', views.landscape, name='landscape'),
path('landscapes/<str:landscape_name>/<query_name>', views.landscape_query, name='landscape_query'),
]
I do not specify the app name anywhere in my code. When I track my network requests I can also see that the correct URL is submitted in the POST request. Why does my url get modified?

set_lanuguage is not changing the language of the enitre webpage and miss the redirections by views

My form with language selection buttons and an update button. Customer update form is implemented through django forms and views however language selections are directly implemented in html file using below code:
{% 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{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>
1:image of webpage rendered form
Whenever I select any language same page with default english is rendered again.
I have placed the relevant context processors and locale middleware where it should be in settings file.
My root urlConf is given below:
urlpatterns = [
url(r'^', include('custupdate.urls')),
url(r'^i18n/', include('django.conf.urls.i18n')),
]
urlpatterns += i18n_patterns(
url(r'^', include('custupdate.urls')),
My application url conf is given:
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^personBasic', views.person_detail, name='person_detail'),
url(r'^licenseeBasic', views.licensee_detail, name='licensee_detail'),
url(r'^address', views.address, name='address'),
url(r'^contact', views.contact, name='contact'),
url(r'^email', views.email, name='email'),
]
My each url e.g personBasic is hooked to its relevant view and view is hooked with relevant form.
Now when I enter following url in address bar and hit enter
http://mycompany.com/custupdate
Because of above url configurations it goes to index view which redirects to following url
http://mycompany.com/custupdate/personBasic
and image 1 is shown in browser.
So selecting any language renders the same page again without change of language.
When I do inspect element in the browser for any language button when its pressed I get following url requested
http://mycompany.com/custupdate/i18n/setlang/
instead of
http://mycompany.com/custupdate/personBasic/i18n/setlang/
Question is when the language buttons are pressed shouldn't the whole url in address bar be rendered as translated version. Whatever is after custupdate is skipped somehow and i18n/setlang is appended after custupdate where i'm expecting it to be like this
/custupdate/personBasic/i18n/setlang/
or
/custupdate/contact/i18n/setlang/
or
/custupdate/email/i18n/setlang/
Change your root URLconf to this:
urlpatterns = [
url(r'^i18n/', include('django.conf.urls.i18n')),
]
urlpatterns += i18n_patterns(
url(r'^', include('custupdate.urls')),
)
Also, inside your form, remove the hidden input named next, completely. You have not defined a redirect_to variable.
Also, make sure that you have set middlewares in the correct order.

django - set_language view giving me a "Page not found" error

Hi there
I've been following the docs on internationalization for django (using mezzanine on django 1.2.5) closely and everything is fine, except when i use a form like the one in the docs to switch language code
like this
<form action="/i18n/setlang/" method="post">
<input name="next" type="hidden" value="/whatever/" />
<select name="language">
{% for lang in LANGUAGES %}
<option value="{{ lang.0 }}">{{ lang.1 }}</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>
with my urlconf looking like this
urlpatterns += patterns("",
("^admin/", include(admin.site.urls)),
("^", include("mezzanine.urls")),
(r'^i18n/', include('django.conf.urls.i18n')),
)
when i switch language and hit "go", i get a
Page Not Found (404)
Request Method: POST
Request URL: http://127.0.0.1:8000/i18n/setlang/
No Page matches the given query.
i added the i18n urls and the locale middleware alright.I tried it in a fresh project as well without luck.
Any clues?
Mezzanine's urlpatterns include a "catch all" for pages, so anything underneath it will never be found. To get your patterns working you simply need to swap the last two patterns in your urls.py to look like:
urlpatterns += patterns("",
("^admin/", include(admin.site.urls)),
(r'^i18n/', include('django.conf.urls.i18n')),
("^", include("mezzanine.urls")),
)