Locale/Internationalization in django - python

I realize there is a utility django.utils.translation that will translate "Hello" in "Hola" somehow but I wanted more control over the exact translations.
Right now my django project is achieving multilingual support with a View.py wrapper for render with some logic to determine the user's preferred locale or falling back to a default locale.
My templates are currently in this type of structure:
templates/en_US/index.html
templates/es_MX/index.html
with some logic that will let it fall back to templates/en_US/index.html if, say, templates/pt_PT/index.html doesn't exist.
I want to create a custom tag/function (https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/) in my template layer that can translate a token to a string so I can move away from maintaining a set of template files for each locale. For example:
<h2> {% t 'index.welcome' %} </h2>
in en-US it would become:
<h2> Welcome </h2>
in es-MX it would become:
<h2> Hola </h2>
So I thought I could to this like this:
from django import template
register = template.Library()
#register.simple_tag
def t(token):
# determine locale and look up the token and get its value
# in the appropriate locale file (with some fall-back logic)
But I don't have access to the request object in a registered tag so I can't determine what I need to find the locale.

All of this functionality, and more, is already provided by Django's Internationalization framework, as documented here: https://docs.djangoproject.com/en/1.8/topics/i18n/translation/
Translations in templates, specifically, are done by way of the trans template tag, such as {% trans 'Welcome' %}.
(As mentioned in my comment above)

Related

Finding the source of Django login page message

I have created a working Django application. I am using django-allauth for implementing social-account authentication.
Now, suppose I am logged-in inside my application using an e-mail id whose user does not have a staff access and, if I open admin login page directly, the admin login page is displayed as follows:
My question is: how can I stop Django from displaying the message "Successfully signed in as ... "? Where is the source of this message present?
The Successfully signed in message is a message from django-allauth. It uses the messages framework.
I suggest that you add the template code to display messages to your base template. That way, the message will be displayed immediately after you have logged in, rather than when you go directly to the admin login (which does include the template code to display messages).
The text you are referring to (You are authenticated as ...) can be found in this template:
python3.6/site-packages/django/contrib/admin/templates/admin/login.html
You can override this template to remove the messsage. For example, look into this question for how to override djangos default templates.
To override this you need to inherit the template by {% extends "admin/login.html" %}
Then you need to override the block with the name.
{% blocktrans trimmed %} You are authenticated as {{ username }}, but are not authorized to access this page. Would you like to login to a different account? {% endblocktrans %}
Now you can customize this particular line and then point your function to load your custom html file instead of the standard admin ones or you can directly edit the login.html in your django package(Not a good idea). To know where it is fetching from you can do the following...
$python
>>>import sys
>>>sys.path = sys.path[1:]
>>>import django
>>>print(django.__path__)
And then go into contrib\admin\templates\admin and edit the login.html manually.

Allowing language change through a query string parameter ?lang=<code> in django with i18n

In django I want to allow a query string of the form ?...&lang=&... to set the current url. Ideally the lang= would be removed from the query string, and the session language key set to the new language.
The eventual resulting url would be the url the browser lands on. This should happen for every url on the site, in addition to the other language selection methods that i18n makes available (so I guess this would be a middleware).
I rather dislike the POST to view approach that appears to be the standard for django-i18n.
Does anything like this exist already?
Django Middleware language change query string ?hl=langcode
https://gist.github.com/teury/5d2213181ed0abe06c316c19431f355e
import django
from django.utils import translation
from django.shortcuts import redirect, reverse
def is_django_greater_than_1_10():
main_version = django.VERSION[0]
if main_version > 1:
return True
sub_version = django.VERSION[1]
if main_version == 1 and sub_version >= 10:
return True
return False
if is_django_greater_than_1_10():
from django.utils.deprecation import MiddlewareMixin
superclass = MiddlewareMixin
else:
superclass = object
class LanguageMiddleware(superclass):
def process_response(self, request, response):
if request.resolver_match.view_name is "home":
lang_url = request.GET.get('hl')
if not lang_url:
return response
current_language = translation.get_language()
if lang_url == current_language:
return response
translation.activate(lang_url)
request.session[translation.LANGUAGE_SESSION_KEY] = lang_url
return redirect(reverse('home') + '?hl=' + lang_url)
else:
return response
I have implemented this system in a single "home" url
change the language according to the key value
Traslate by Google.
Idioma nativo = Español
After reading the Django documentations, and realising that the Django devs appear to also be in the business of enforcing their own coding standards (and here I am thinking specifically at this comment in the source code:
Since this view changes how the user will see the rest of the site, it must
only be accessed as a POST request. If called as a GET request, it will
redirect to the page in the request (the 'next' parameter) without changing
any state.
) I decided to go with the solution outlined in this post, which I am pasting below (almost) verbatim (hence the non semantic table layout):
<div id="languages">
<table >
<tr>
{% get_available_languages as languages %}
{% for key, item in languages %}
<td>
<form action="/i18n/setlang/" method="post">
{% csrf_token %}
<input type="hidden" name="language" value="{{key}}"/>
<input id="lang_select_{{key}}" type = "image" src="/media/img/{{ key }}.gif" alt="{{ item }}"/>
</form>
</td>
{% endfor %}
</tr>
</table>
</div>
I also came up with my own JS solution which is a little more flexible and vastly more complicated, so it's not really worth it (though it gives links: but since they need an onClick attribute, or moral equivalent, they are useless for SEO purposes).
Of course yanking the code and removing the dumbass GET limitation is also an option - though a higher maintainence one.
P.S: Those who find my comment above adversarial (and also, no doubt, my quest misguided) should consider how the stance that requires POST to switch language flies in the face of SE traversal, while forcing jumps through this kind of hoops to honor the established design convention of allowing the user to switch language by clicking on flag icons.

Changing css styles from view in Django

Sorry in advance if there is an obvious answer to this, I'm still learning the ropes with Django.
I'm creating a website which has 6 pre determined subjects (not stored in DB)
english, civics, literature, language, history, bible
each subject is going to be associated with a unique color.
I've got a template for a subject.html page and a view that loads from the url appname/subject/subjectname
what I need to do is apply particular css to style the page according to the subject accessed. for example if the user goes to appname/subject/english I want the page to be "themed" to english.
I hope I've made myself clear, also I would like to know if there is a way I can add actual css code to the stylesheet and not have to change attributes one by one from the back-end.
thanks very much!
In templates you can use conditionals for add css, like this:
<div class="{% if subject=='civics' %}civic-class{% endif %}"></div>
For this, subject value should come from view.
Now, for themed page, you could use the extends tag. Let's supose:
def your_view(request):
subject # Here you get the url subject, 'how' is up to you
if subject == 'english'
template_base = '/some/html/tenplate.html'
elif subject == 'civis':
template_base = '/some/other/template.html'
... # then you return 'template_base' variable to template
Then in template:
{% extends template_base %} # at the top
Hope this helps, is the same logic if you use Class-Based views.
Django's views are not responsible for the presentation, it's the template (and css etc of course)'s reponsability. Now assuming you have the same view serving different subjects, the view obviously need to know which is the current subject (I assume from a captured part of the url passed as argument to the view), so it can easily pass this information to the template, which in turn can use it to add a subject-specific class to the body tag. Then you only have to write your css accordingly.
As an example:
# urls.py
patterns = urlpatterns('',
#...
url(r'whatever/(P?<subject>[a-z-]+>)/$', 'myviews.index', ...),
)
# myviews.py
def index(request, subject):
# do whatever
context = {
# whatever else
'subject':subject
}
return render(request, "whatever/index.html", context)
# whatever/index.html
<html>
# headers etc
<body class="something {{ subject }} etc">
# whatever here
</body>
</html>
You can do this is many ways.
In general you need to return some variable from your view to the html and depending on this variable select a style sheet, if your variable name will match you style sheet's name you can do "{{variable}}.css", if not you can use JQuery.

"Read More" for Django WYSIWYG editor

I am using django-summernote editor for creating posts with text and images which are saved in a character field as HTML tags.
I want to add a read-more functionality where a limited sized preview is shown for all the posts. An idea could be to truncate the character field, but it may lead to truncation of HTML image tags if they happen to be positioned between the boundary.
How to get around this?
Django has two template filters you can use to make sure your HTML doesn't get malformed: truncatechars_html and truncatewords_html
Template filters are just functions, so you can import them anywhere you need in your Python code and assign the result to a variable you can use elsewhere, etc.
Example:
from django.template.defaultfilters import truncatechars_html
html = """<p>Look, I’m some HTML. You can truncate me
with Django template filters</p>"""
truncated_value = truncatechars_html(html, 30)
I'm late to this party but this post came up in search results. I just got a working solution to this myself with a custom template filter. This allows you to drop in the break on a case by case basis like WordPress. Here is what I did (with help from this post and the Django docs):
Sample post submitted in a textfield:
<p>Here is some sample text</p>
<!--more-->
<img src="cool_photo.jpg" />
in templatetags/read_more.py
from django import template
from django.template.defaultfilters import stringfilter
register = template.Library()
#register.filter(name='read_more')
#stringfilter
def read_more(value):
pattern = "<!--more-->"
return value.split(pattern, 1)[0]
in the template that's rendering the truncated version:
{% load read_more %}
{{ object.body|read_more|safe }}
Since the split pattern is an html comment there's no need to cut it from the main post body template:
{{ object.body|safe }}

How to enable {% trans %} tag for jinja templates?

I try to enable the trans tag and I've made a test template i18n.html:
{% trans %}For sale{% endtrans %}--{{message}}--{{decimal_format}}
Here is my python code according to the manpages:
from webapp2_extras import i18n as multilingua
import jinja2
from webapp2_extras.i18n import lazy_gettext as gettext
from webapp2_extras.i18n import lazy_gettext as _
from jinja2 import Environment, FileSystemLoader
jinja_environment = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
extensions=['jinja2.ext.i18n'])
# The code below seems wrong since it is django but it was the only way I could make the page load
jinja_environment.install_gettext_translations(django.utils.translation)
class HelloWorldHandler(webapp2.RequestHandler):
def get(self):
# Set the requested locale.
locale = self.request.GET.get('locale', 'pt')
multilingua.get_i18n().set_locale(locale)
message = multilingua.gettext('For sale')
#django.utils.translation.activate('pt')
template = jinja_environment.get_template('templates/i18n.html')
decimal_format = multilingua.I18n(self.request).format_decimal(1000)
self.response.out.write(template.render(message=message, decimal_format=decimal_format))
I could not make it work without django and therefore I ask how to lose the django translation and staying with webapp2.i18n + jinja instead.
There was also a discussion in a thread where I'm not the only one saying that documentation is somewhat incomplete or hard to find. Could you please answer or comment which is the recommended way of making the trans tag work and why I must include jinja_environment.install_gettext_translations(django.utils.translation)
?
When I try to remove my use of django I also lose the functions of webapp2.i18n. My locale files are both in locale/... and conf/locale.. since the first is the default for webapp2 and the second is the default for django translations, so I could really use some guidelines for best practice here to get rid of the django dependecies and use webapp2 and jinja for rendering my localizations.
If to any help, I did receive an error message when trying to remove django:
self.response.out.write(template.render(message=message, decimal_format=decimal_format))
File "/media/Lexar/montao/montaoproject/jinja2/environment.py", line 894, in render
return self.environment.handle_exception(exc_info, True)
File "/media/Lexar/montao/montaoproject/templates/i18n.html", line 2, in top-level template code
{{ _('For sale') }}--{{message}}--{{decimal_format}}
UndefinedError: 'gettext' is undefined
Thank you
Take a look at Jinja2's i18n Extension documentation. Calling install_gettext_translations basically sets the object through which Jinja2 will call gettext, ngettext, etc, in order to translate strings when it encounters a {% trans %} tag.
Since those functions are defined on webapp2.i18n (see here), jinja2 will successfully call those functions to retrieve translations, dependent upon your call to set_locale inside of the request. I don't have the code in front of me, but I'd guess that gettext and company defined in webapp2.i18n are merely proxies to call webapp.i18.get_i18n().gettext, which is the magic that makes all of this work.
Here is a working example for Django+jinja2:
from jinja2 import PackageLoader, Environment
from django.utils import translation
...
jinja_environment = Environment(loader=PackageLoader('website', 'templates'),
extensions=['jinja2.ext.i18n'])
jinja_environment.install_gettext_translations(translation)
template = jinja_environment.get_template('test.jinja.html')
page_next_app_table = template.render()
...
In test.jinja.html:
<html>
<b> {{ _( "Traslate This" ) }}:</b>
</html>

Categories

Resources