Locale from django app not change - python

I newbie into Django, and I need make a I18N system. I have this url.py:
from django.contrib import admin
from django.urls import path, include
from . import views
urlpatterns = [
path('', views.index, name='home'),
path(r'^i18n/', include('django.conf.urls.i18n')),
]
And I made this html to change the language:
{% load i18n %}
<form action="/i18n/setlang/" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{request.path}}" />
<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>
But when I click in "Go" button, the server response is: Page not found (404), The current path, i18n/setlang/, didn't match any of these. I stay using python 3.6 and Django 2.0.4.
And I no have idea how can I solve it.

The problem was here:
path(r'^i18n/', include('django.conf.urls.i18n')),
I cut off r'^':
path('i18n/', include('django.conf.urls.i18n')),
and works!

Related

Django translation redirect back to the current page

How to redirect back to the current page.
In my site I'm implementing two language which is 'en' and 'fa'
right now It's working but doesn't redirect to current page like docs.djangoproject.com we have instead it redirect me to home 'localhost:8000/fa/' or /en
here is the code:
for template hearders.py
<li class="dropdown default-dropdown">
<form action="{% url 'selectlanguage' %}" 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="{% trans 'Go' %}">
</form>
</li>
code for urls.py is:
path('selectlanguage', views.selectlanguage, name='selectlanguage'),
and for views.py is:
def selectlanguage(request):
if request.method == 'POST': # check post
cur_language = translation.get_language()
lasturl= request.META.get('HTTP_REFERER')
lang = request.POST['language']
translation.activate(lang)
request.session[translation.LANGUAGE_SESSION_KEY]=lang
#return HttpResponse(lang)
return HttpResponseRedirect(lang)
did you wrap the urls in the i18n_patterns?
from django.conf.urls.i18n import i18n_patterns
urlpatterns += i18n_patterns(
path('about/', about_views.main, name='about'),
path('news/', include(news_patterns, namespace='news')),
)

Django Internationalization - Language not change

I have already searched on many post but none could solve my problem.
My settings.py :
from os import path
PROJECT_ROOT = path.abspath(path.dirname(__file__))
LOCALE_PATHS = (path.join(PROJECT_ROOT, '/conf/locale/'),)
TIME_ZONE = 'UTC'
LANGUAGE_CODE = 'fr-fr'
USE_I18N = True
USE_L10N = True
gettext = lambda x: x
LANGUAGES = (
('fr', gettext('French')),
('en', gettext('English')),
)
TEMPLATE_CONTEXT_PROCESSOR = (
"django.core.context_processors.i18n",
)
MIDDLEWARE_CLASSES = (
"django.middleware.locale.LocaleMiddleware",
)
urls.py :
from django.conf.urls import *
urlpatterns = patterns ('',
...
url(r'^i18n/', include('django.conf.urls.i18n')),
)
template.html (reduced version) :
<div id="header">
...
{% include 'i18n.html' %}
</div>
i18n.html :
{% load i18n %}
{% trans "Une ligne de test" %}
<form action="/i18n/setlang/" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path|slice:'3:' }} />
<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 know this code has already appeared in many other posts but none solutions helped me.
My problem is that when i submit the form, the page reloads but the dropdown return on "French".
Furthermore, when i try an obsolete translation in /locale/fr/LC_MESSAGES/django.po for "Une ligne de test", i don't have the translate so I believe it doesn't access but I don't know why
Someone would have something to offer me please ?
| UPDATE |
When I run python manage.py runserver the translation don't work but I have in the terminal "POST /i18n/setlang/ HTTP/1.1" 302 0 so I think that this calls for the function set_language() but I really don't understand why the language don't change and why an obsolete translation doesn't display with the initial language.
And when I try LANGUAGE_CODE = "en", the dropdown take the value English but all the page stay in French.
For the information, I use Django 1.4.11 but I don't think that's my problem.
| UPDATE |
I tried too with this template, with only one choice to try change the language but the result is always the same.
<form action="/i18n/setlang/" method="post">
{% csrf_token %}
<input type="hidden" name="language" value="en" />
<input type="hidden" name="next" value "{{ request.get_full_path|slice:'3:' }}" />
<input type="submit" value="English" />
</form>
What does it missing ?

Django1.8 'app' is not a registered namespace

My error:
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'app:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter}}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>
I want to know why it's wrong here.
This is the official website of the document is written
This detail.html:
<h1>{{ question.question_text }}</h1>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'app:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }} </label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>
Now I know the problems is in detail.html, my main urls and my app called myapp URLCONF and views.py
views.py:
def vote(request, question_id):
p = get_object_or_404(Question, pk=question_id)
try:
selected_choice = p.choice_set.get(pk=request.POST['choice'])
except (KeyError, Choice.DoesNotExist):
# Redisplay the question voting form.
return render(request, 'polls/detail.html', {
'question': p,
'error_message': "You didn't select a choice.",
})
else:
selected_choice.votes += 1
selected_choice.save()
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('polls:results', args=(p.id,)))
My urls.py:
urlpatterns = [
url(r'^$',views.Index,name='index'),
url(r'^(?P<question_id>\d+)/$',views.detail,name='detail'),
url(r'^(?P<question_id>\d+)/results/$', views.results, name='results'),
url(r'^(?P<question_id>\d+)/vote/$', views.vote, name='vote'),
url(r'^admin/', admin.site.urls),
]
Namespacing is used when you include another url config inside your root urls.py. The example in the tutorial works because they have include('polls.urls') in tutorial 1, and then in tutorial 3 they have set app_name = 'polls' in polls/urls.py and changed the url tag to {% 'polls:vote' question.id %}.
In your case, all your url patterns are in the root config, so you should remove the namespace from your url tag.
{% url 'vote' question.id %}
My Project picture
I added a new urls.py
this code,mydjango/urls.py
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
url(r'^app/', include('app.urls')),
url(r'^admin/', admin.site.urls),
]
app/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]

How can I change Django admin language?

I have a django 1.6 site with i18n working. I can change the frontend language with a select box in the top of the template, but I don't know if there is a django app or trick to change the admin language, because it seems to store somewhere in session variable, and it keeps the first language I have used in the frontend.
In your settings.py just add 'django.middleware.locale.LocaleMiddleware' to your MIDDLEWARE_CLASSES setting, making sure it appears after 'django.contrib.sessions.middleware.SessionMiddleware'.
You can create /en/admin, /fr/admin/ and so on using i18n_patterns:
urlpatterns += i18n_patterns(
url(r'^admin/', include(admin.site.urls)),
)
(For Django <= 1.7, you must specify a prefix, use i18n_patterns('', ... ))
Here is a slightly modified version of a code snippet from the Django docs for admin/base.html that adds a language selection dropdown:
{% extends "admin/base.html" %}
{% load i18n %}
{% block userlinks %}
{{ block.super }}
/ <form action="{% url 'set_language' %}" method="post" style="display:inline">{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}">
<select name="language" onchange="this.form.submit()">
{% 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>
</form>
{% endblock %}
For this to work you also need to add the following to your urlpatterns:
path('i18n/', include('django.conf.urls.i18n')),

Issue trying to change language from Django template

I need to include two buttons or links to allow users change language between English and Spanish. I've read the docs and tried this:
<form action="/i18n/setlang/" method="post">{% csrf_token %}
<input name="language" type="hidden" value="es" />
<input type="submit" value="ES" />
</form>
However, every time I click the button, the page is reloaded but the language doesn't change at all. Am I missing something?
Note: I haven't set next, as I just want to reload the current page in the desired language.
If I use the default form provided by the docs the result is the same: the page reloads but language isn't changed:
<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>
UPDATE:
After further testing, I've noticed that there is a problem using both i18n_patterns and patterns in the urls.py. Currently I have a file that looks like:
urlpatterns = i18n_patterns('',
url(r'^contents/', include('contents.urls')),
url(r'^events/', include('events.urls')),
# ...
)
urlpatterns += patterns('',
url(r'^i18n/', include('django.conf.urls.i18n')),
)
And this doesn't seem to work. However, if I remove the i18n_patterns and change it to patterns then it seems to work:
urlpatterns = patterns('',
url(r'^contents/', include('contents.urls')),
url(r'^events/', include('events.urls')),
# ...
)
urlpatterns += patterns('',
url(r'^i18n/', include('django.conf.urls.i18n')),
)
The docs say that you don't have to include it inside i18n_patterns, so I think this should work, but it doesn't! It doesn't matter if you include django.conf.urls.i18n before or after i18n_patterns it always does the same.
After more testing and thanks to the related question linked by #AronYsidoro I've finally found the issue and a very simple solution that actually solves this.
First, let me explain the problem: When working with i18_patterns in your urls.py to prepend the language code, if you call the URL set_language to change the language without specifying next, it defaults to the current one, but with the prepended old language code! So, the language gets back to the original! And, if you explicitly specify next, you must be sure to do not include the language code at the begining.
If you use {{ request.path }} or {{ request.get_full_path }} to specify the next as the current page this won't work as it returns the language code too.
So, how do we remove this undesired language code to reload the current page with the language changed when using i18n_patterns? Easy, we just have to slice the 3 first chars (the slash and the two chars language code)!
Here you have two examples. The first one in form of a select (with the languages as choices) and the other one in form of a button (per language).
I really hope this helps someone else. You can just copy and paste the code and it should work. However, if using the "button form", you just have to set the language to your desired!
Change language from list:
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path|slice:'3:' }}" />
<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="Change" />
</form>
Change language as button:
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ request.get_full_path|slice:'3:' }}" />
<input name="language" type="hidden" value="es" />
<input type="submit" value="ES" />
</form>
A sum-up of possible options:
Change the user's session language with a select
There is an excellent extensive description with example on Django docs.
Change the user's session language with buttons
There is no need to repeat a form for each button as #Caumons suggested, instead you can simply include as many buttons in the form as the languages.
<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>
You can certainly style up the buttons to look like links or whatever.
Change the language displayed with links
If it is not required that the default user session language is changed, then simple links can be used to change the content:
<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>
<a href="/{{ language.code }}{{ request.get_full_path|slice:'3:' }}"
class="{% if language.code == LANGUAGE_CODE %}selected{% endif %}"
lang="{{ language.code }}">
{{ language.name_local }}
</a>
</li>
{% endfor %}
</ul>
SEO
I am not entirely sure that the content is seo friendly if a form is used to change the session language, as Django recommends. Therefore it is possible that the link <a> markup is added as hidden below the <button> element.
If in your current system you have only 2 languages then simply use like below:
{% ifequal LANGUAGE_CODE "en" %}
Spanish
{% else %}
English
{% endifequal %}
No need of a form, url and submit etc. It worked for me.
Besides adding form that was suggested here:
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
{{ request.get_full_path_info|slice:'3:'}}
<input name="next" type="hidden" value="{{ languageless_url }}" />
<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.code }}
</button>
</li>
{% endfor %}
</ul>
</form>
I would suggest adding a context processor (app.context_processors.py):
def language_processor(request):
"""
This is needed for language picker to work
"""
return {
'languageless_url':
'/' + '/'.join(request.get_full_path().split('/')[2:])
}
This allows to leave the logic out of template.
Also don't forget to add your processor in template settings:
'context_processors': [
'app.context_processors.language_processor',
If you only need two languages, ex. English and French and you've defined this in your settings.py and you have set the default language and you have configured urls.py in your main app correctly. Then, just use this in your template (or partial, topbar etc.) btn-kinito "btn-header are just styling classes you can manipulate that with css or JS.
The loop or iteration inside is just looping through the LANGUAGES[] list, which you've defined in settings.py, then it creates a button. with the character "|" and a space to make it look cute since we have just two langs.
The {% url 'set_language' %} is Django's redirect view called set_language it redirects to URL. This is why in your main apps's urls.py you need to put path('i18n/', include('django.conf.urls.i18n')), In this case. So after the button is created for each language in the list you will be able to be redirected to that url.
<div class="btn-header">
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<button type="submit" name="language" value="{{ language.code }}"
class="btn-kinito">
{{ language.code }}
</button>|
{% endfor %}
</form>
</div>
For urls.py I think it could look like this:
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.conf.urls.i18n import i18n_patterns
# I don't want my admin translated
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns += i18n_patterns (
path('i18n/', include('django.conf.urls.i18n')),
path('', include('pages.urls')),
path('cats', include('cats.urls')),
path('dogs', include('dogs.urls')),
prefix_default_language=False,
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
The prefix_default_language=False, this is optional and it removes the default language prefix from the url, which makes sense if you just got two or three languages. Although I did run into problems with this in the past, where the prefix_default_language=False, did not work.
How to fix the problem with prefix_default_language=False, NOT working, or not removing the default language prefix from urls
In my settings.py I changed:
LANGUAGE_CODE = 'en-us' to LANGUAGE_CODE = 'en'
(seems to have solved it)
I know it's not a solid solution but I needed a switch button (not a dropdown list since I want to toggle between two languages)
So I came up with this:
{% get_language_info_list for LANGUAGES as languages %}
{% if LANGUAGE_CODE == languages.0.code %}
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<div class="lang-btn">
<input name="next" type="hidden" value="{{ redirect_to }}" />
<input name="language" type="hidden" value="{{ languages.1.code }}" />
<button type="submit"><img width="30" src="{% static 'united-kingdom.png' %}" alt=""></button>
</div>
</form>
{% else %}
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<div class="lang-btn">
<input name="next" type="hidden" value="{{ redirect_to }}" />
<input name="language" type="hidden" value="{{ languages.0.code }}" />
<button type="submit"><img width="30" src="{% static 'turkey.png' %}" alt=""></button>
</div>
</form>
{% endif %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
<div class="btn-header">
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
{% for language in languages %}
{% if language.code != LANGUAGE_CODE %}
<button type="submit" name="language" value="{{ language.code }}">{{ language.name }}</button>
{% endif %}
{% endfor %}
</form>
</div>
if you have two languages. It will only show you the one that's off.
https://www.loom.com/share/9319c0e9204f417a8eec897965ce3a96
Django 3.02
<div class="uk-flex">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
<div class="languages">
<p>{% trans "Language" %}:</p>
<ul class="languages">
{% for language in languages %}
<li>
<a href="/{{ language.code }}/{{ request.get_full_path |slice:'4:'}}" {% if language.code == LANGUAGE_CODE %} class="selected"{% endif %}>
{{ language.name_local }}
</a>
</li>
{% endfor %}
</ul>
</div>
</div>
Seems lot of people have spend a lot of time (like myself) finding a proper solution that works for all cases. "Trick" is to set next = '' if you want to reload existing page in different language. Citing from the django doc:
After setting the language choice, Django looks for a next parameter in the POST or GET data. If that is found and Django considers it to be a safe URL (i.e. it doesn’t point to a different host and uses a safe scheme), a redirect to that URL will be performed. Otherwise, Django may fall back to redirecting the user to the URL from the Referer header
Finally I wanted to have a function that I can call for any language changes triggered by links, buttons, dropdown menus or whatever. I ended up with this little js function:
django_language_set(language_code){
url = "{% url 'set_language' %}";
data = {
language: language_code,
next: '',
csrfmiddlewaretoken: '{{ csrf_token }}'
};
this.form_post(url, data)
}
form_post(path, params, method='post') {
/* simulates a post submit, call like:
form_post('/home', {language: 'de', next: ''})"
*/
const form = document.createElement('form');
form.method = method;
form.action = path;
for (const key in params) {
if (params.hasOwnProperty(key)) {
const hiddenField = document.createElement('input');
hiddenField.type = 'hidden';
hiddenField.name = key;
hiddenField.value = params[key];
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
}
Call the function, e.g.
<a #click="django_language_set('fr')">French</a>

Categories