How to translate validations from AUTH_PASSWORD_VALIDATORS in UserCreationForm - django

I have a multiple language app (Django 1.11) with a form to create new users. In this form, the error messages when the user send invalid input must come in Portuguese (pt-BR) or English (en-US) based on the selected language. The custom validations and some of the automatic Django messages for validations are well translated, but not the following: "The password is too similar to the username."; "This password is too short. It must contain at least 8 characters." and "This password is too common.". Actually, they are shown in Portuguese, since the LANGUAGE_CODE from settings.py is 'pt-BR'.
I was able to translate some of the automatic messages such "A user with that username already exists." with django.utils.translation.activate as in the following code.
from django.utils.translation import activate
activate(curr_lang)
But this wasn't enough to translate the validations from settings.AUTH_PASSWORD_VALIDATORS. I manually changed the LANGUAGE_CODE from 'pt-BR' to 'en-US' and was able to see the messages only in English. What is the best strategy to translate these messages? As far as I researched, setting LANGUAGE_CODE is not a option, since the results I find suggest the use of django.utils.translation.activate. Thanks in advance

After several tries, I think the solution was:
Add "django.middleware.locale.LocaleMiddleware" to MIDDLEWARE at settings.py (be careful with the order as explained at the documentation)
MIDDLEWARE = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
...
Add the LANGUAGES const also at settings.py after LANGUAGE_CODE, which has to contain the default language
LANGUAGE_CODE = 'pt-BR'
LANGUAGES = [
('pt-BR', 'Portuguese'),
('en-US', 'English'),
]
Use Django's default set_language method - on urls.py, add the following line:
urlpatterns = [
....
url(r'^i18n/', include('django.conf.urls.i18n')),
And, on the html file with the selection of language,
{% load i18n %}
{% load staticfiles %}
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language" id="curr_lang" class="select2-single" onchange="this.form.submit()">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
<option value="pt-BR" title="Português" {% if LANGUAGE_CODE == 'pt-br' %}selected{% endif %}>{% static 'img/flags/br.png' %}</option>
<option value="en-US" title="English" {% if LANGUAGE_CODE == 'en-us' %}selected{% endif %}>{% static 'img/flags/us.png' %}</option>
</select>
</form>
On context_processor.py, define a function (I'm calling global_env) to be run at the end of every view. On settings.py, add 'your-application-name-here.context_processor.global_env' such as
TEMPLATES = [
...
'OPTIONS': {
'context_processors': [
'your-application-name-here.context_processor.global_env',
...
And, on context_processor.py, the function must have
def global_env(request):
from django.utils.translation import activate
curr_lang = request.session[LANGUAGE_SESSION_KEY]
activate(curr_lang)
# More code to render dictionary to views for non-default messages on page
....
I think these steps complete the translation of default form validation messages from Django without the need of custom validators.

Related

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

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.

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>

Django translations always rendering in english

After looking at the trying all of the recommendations I could find on this subject, my translations still do not work whatsoever.
/settings.py file
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'
LOCALE_PATHS = (
'/Users/samb/Projects/transtest/locale'
)
# Custom Languages
ugettext = lambda s: s
LANGUAGES = (
('de', ugettext('German')),
('en', ugettext('English')),
('fr', ugettext('French')),
('fr-CA', ugettext('French Canadian')),
)
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale.
USE_L10N = True
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# Uncomment the next line for simple clickjacking protection:
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
view.py
from django.shortcuts import render_to_response
from django.template import RequestContext
def trans(request):
return render_to_response('index.html', context_instance=RequestContext(request))
my template file (index.html)
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
<html>
<head>
<title>translations</title>
</head>
<body>
{% for l in LANGUAGES %}
{{ l }}<br />
{% endfor %}
{{ LANGUAGE_CODE }}<br />
{% trans "Welcome to my site" %}
</body>
</html>
po file (that has been compiled)
located at /Users/samb/Projects/transtest/locale/fr/LC_MESSAGES
#: transtest/templates/index.html:13
msgid "Welcome to my site"
msgstr "Please work"
I can never get the 'Welcome to my site' to work. The LANGUAGES and LANGUAGE_CODE variables in my template are all working (unless I 'Accept_language: fr_CA').
After reading all the other posts on this subject and still having the same problem, I feel like I must have a silly mistake, or am missing a vital step entirely. Any thoughts?
Update: This is how I am testing the translation:
telnet localhost 8000
Connected to localhost.
Escape character is '^]'.
GET /
Accept_language: fr
<html>
<head>
<title>Translations</title>
</head>
<body>
('de', u'Allemand')<br />
('en', u'Anglais')<br />
('fr', u'Fran\xe7ais')<br />
('fr-CA', u'French Canadian')<br />
fr<br />
Welcome to my site
</body>
</html>
Connection closed by foreign host.
I noticed that the languages are getting translated, but the 'Welcome to my site' is not.
The docs say here that LocaleMiddleware ...
... should come after SessionMiddleware, because LocaleMiddleware makes
use of session data. And it should come before CommonMiddleware
because CommonMiddleware needs an activated language in order to
resolve the requested URL.
Maybe it will help when you take account of this in your definition of the MIDDLEWARE_CLASSES.

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>