Django: How to get language code in template? - django

Is there's some global variable for gettin' language code in django template or atleast passing it through view?
something like: {{ LANG }} should produce "en" for example..
I really not comfortable when people using request.LANGUAGE_CODE.
Detailed explanation would be appreciated =)

It's an old topic. But some might find it useful.
{% load i18n %}
...
{% get_current_language as LANGUAGE_CODE %}
Django reference and example.

If it didn't already exist, you would need to write a template context processor. Here's how you'd do that.
Put this somewhere:
def lang_context_processor(request):
return {'LANG': request.LANGUAGE_CODE}
And then, add a reference to it the TEMPLATE_CONTEXT_PROCESSORS setting. Something like this:
from django.conf import global_settings
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
'myproject.myapp.templatecontext.lang_context_processor',
)
(I recommend adding to the global setting because it means you don't break things accidentally when a new context processor is added to the defaults.)
However, it does exist, as the inbuilt template context processor django.template.context_processors.i18n. You can access it as LANGUAGE_CODE.
Purely for interest, here's the definition of that function:
def i18n(request):
from django.utils import translation
return {
'LANGUAGES': settings.LANGUAGES,
'LANGUAGE_CODE': translation.get_language(),
'LANGUAGE_BIDI': translation.get_language_bidi(),
}
Make sure that you're using a RequestContext for your template rendering, not a plain Context, or it won't work.

Tested with Django==1.11.2.
Enable I18N and employ i18n template context processor.
# setings.py
USE_I18N = True
# ...
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
# ...
'django.template.context_processors.i18n',
# ...
],
},
},
]
And then it's simple in the template.
# template.html
{% load i18n %}
{{ LANGUAGE_CODE }}
But use render(), not render_to_response(), in your view function so the LANGUAGE_CODE variable is accessible in the template:
render_to_response()
This function preceded the introduction of render() and works
similarly except that it doesn’t make the request available in the
response. It’s not recommended and is likely to be deprecated in the
future.

Related

Django & Jinja2 templates using {{ url() }}

I am trying to figure out how to pass my user_id within my html using jinja's {{ url() }}, using urls that don't need any id like /dashboard/ work fine but I need to pass an id to this- example: /user/3 . I have tried the following with no success:
{{ url('detail') }}
{{ url('detail', user_id=User.id) }}
{{ url('detail', User.id) }}
Here's part of my views and html:
views.py
urlpatterns = [
path('dashboard/', dashboard, name='dashboard'),
path('user/<int:user_id>/', detail, name='detail'),
]
dashboard.html
{% for User in all_users %}
{{ url('detail') }}
{% endfor %}
Any help on this would be appreciated, thanks
I found a solution:
{% for User in all_users %}
{{ url('detail', args=[User.id] )}}
{% endfor %}
This also works:
{% url 'detail' user.id %}
Then, in views.py, your corresponding function should receive user_id as an argument (internally user.id becomes user_id).
Django now has official backend support for Jinja2 - I'm guessing you were using django-jinja which provides an implementation of the url function but it's fairly straightforward to integrate Django and Jinja now without adding any additional dependencies (besides Jinja2).
First, configure your TEMPLATES in your settings file and add a dictionary entry with the jinja2 backend:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'APP_DIRS': True,
'OPTIONS': {
'extensions': [<custom extensions if any>]
'environment': 'yourapp.jinja2.environment',
...
},
},
...
]
The key part of this is the environment setting. The examples suggest creating a jinja2.py file in your app directory and defining an environment function there that you'll set to a function that returns a Jinja2 Environment, e.g.,
# example yourapp/jinja2.py
from django.conf import settings
from django.urls import reverse
from django.templatetags.static import static
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update({
'static': static,
'url': reverse,
'settings': settings,
...
})
return env
Here we are binding Python functions (and Django things) to be made available in our Jinja2 environment, so now static in a jinja template can be called static(...) and invoke the Django static function defined in django.templatetags.static, and url is bound to the Django reverse function so url('detail', args=[user.id]) should work. If you prefer a signature like {{ url('detail', pk=123) }} without generating an invalid arguments error you can define your own function:
def jinja_url(viewname, *args, **kwargs):
return reverse(viewname, args=args, kwargs=kwargs)
and bind 'url': jinja_url in your TEMPLATES settings instead.
It's also important to note that Django looks for your jinja templates in a jinja2 directory under your app dir, not the templates directory.

Switch language in jinja template

I'm migrating a multi lingual Django application from Django's template engine to Jinja2. In the templates I currently switch the active language on a per object basis using Django's language template tag i.e.:
{% load i18n %}
<h1>{% trans 'Page title' %}</h1>
<ul>
{% for obj in object_list %}
{% language obj.language_code %}
<li>{% trans 'view' %}: {{ obj.title }}
{% endlanguage %}
{% endfor %}
</ul>
We also use i18n_patterns so the urls of each object are language specific as well.
I'm stuck on how to convert this to Jinja. I cannot use Django's i18n template tags and cannot find something equivalent for Jinja.
I was also looking at Babel to help with extracting messages from the templates. So a solution that works with Babel as well as with Django would be preferred.
It turns out it's fairly simple to do this by writing a custom jinja2 extension (I've based this on the example in the jinja2 docs):
from django.utils import translation
from jinja2.ext import Extension, nodes
class LanguageExtension(Extension):
tags = {'language'}
def parse(self, parser):
lineno = next(parser.stream).lineno
# Parse the language code argument
args = [parser.parse_expression()]
# Parse everything between the start and end tag:
body = parser.parse_statements(['name:endlanguage'], drop_needle=True)
# Call the _switch_language method with the given language code and body
return nodes.CallBlock(self.call_method('_switch_language', args), [], [], body).set_lineno(lineno)
def _switch_language(self, language_code, caller):
with translation.override(language_code):
# Temporarily override the active language and render the body
output = caller()
return output
# Add jinja2's i18n extension
env.add_extension('jinja2.ext.i18n')
# Install Django's translation module as the gettext provider
env.install_gettext_translations(translation, newstyle=True)
# Add the language extension to the jinja2 environment
environment.add_extension(LanguageExtension)
With this extension in place switching the active translation language is pretty much exactly like how you'd do it in Django:
{% language 'en' %}{{ _('Hello World'){% endlanguage %}
The only caveat is that when using Django as a gettext provider and Babel as a message extractor it's important to tell Babel to set the message domain to django when running init/update/compile_catalog.
I have this code snippet to switch between languages in jinja2.
def change_lang(request, lang=None, *args, **kwargs):
"""
Get active page's url by a specified language, it activates
Usage: {{ change_lang(request, 'en') }}
"""
path = request.path
url_parts = resolve(path)
url = path
cur_language = get_language()
try:
activate(lang)
url = reverse(url_parts.view_name, kwargs=url_parts.kwargs)
finally:
activate(cur_language)
return "%s" % url
in settings.py
TEMPLATES = [
{
"BACKEND": "django_jinja.backend.Jinja2",
'DIRS': [
os.path.join(BASE_DIR, 'templates/jinja'),
],
"OPTIONS": {
# Match the template names ending in .html but not the ones in the admin folder.
"match_extension": ".html",
"match_regex": r"^(?!admin/).*",
"newstyle_gettext": True,
"extensions": [
"jinja2.ext.do",
"jinja2.ext.loopcontrols",
"jinja2.ext.with_",
"jinja2.ext.i18n",
"jinja2.ext.autoescape",
"django_jinja.builtins.extensions.CsrfExtension",
"django_jinja.builtins.extensions.CacheExtension",
"django_jinja.builtins.extensions.TimezoneExtension",
"django_jinja.builtins.extensions.UrlsExtension",
"django_jinja.builtins.extensions.StaticFilesExtension",
"django_jinja.builtins.extensions.DjangoFiltersExtension",
],
'globals': {
'change_lang': 'drug.utils.change_lang'
},
"bytecode_cache": {
"name": "default",
"backend": "django_jinja.cache.BytecodeCache",
"enabled": False,
},
"autoescape": True,
"auto_reload": DEBUG,
"translation_engine": "django.utils.translation",
"context_processors": [
"dashboard.context_processors.auth",
# "django.template.context_processors.debug",
"django.template.context_processors.i18n",
# "django.template.context_processors.media",
# "django.template.context_processors.static",
# "django.template.context_processors.tz",
"django.contrib.messages.context_processors.messages",
]
}
},
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
]
},
},]
and then you can use this in anywhere in your templates {{ _('Hello World') }}

How can I access environment variables directly in a Django template?

I'm looking to do something like this non-working code in my Django template:
{% if os.environ.DJANGO_SETTINGS_MODULE == "settings.staging" %}
Is something like this possible? My workaround is creating a context processor to make the variable available across all templates, but wanted to know if there is a more direct way to achieve the same result.
Use context_processor, do as below and you should be able to access os.environ['DJANGO_SETTINGS_MODULE'] as SETTING_TYPE in templates. Example you can use {% if SETTING_TYPE == "settings.staging" %}
project/context_processors.py
import os
def export_vars(request):
data = {}
data['SETTING_TYPE'] = os.environ['DJANGO_SETTINGS_MODULE']
return data
project/settings.py (your actual settings file)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
...
'project.context_processors.export_vars',
...
]
}
}
]
Extending on #vinay kumar's comment, you can create a custom template filter in the following way:
application/template_tags_folder/template_tags_file.py
from django.template.defaulttags import register
import os
#register.filter
def env(key):
return os.environ.get(key, None)
And then in your template you can access it this way:
template.html
{% if 'DJANGO_SETTINGS_MODULE'|env == 'app_name.staging_settings' %}
Finally I leave a django docs reference and a stackoverflow reference for creating custom template tags and filters in django.

Django messages framework with built-in Jinja2 backend

How can I use the Django messages framework with Jinja2 and the built-in Jinja2 backend in Django 1.8?
I tried doing it as before, but then remembered that the Jinja2 backend doesn't have the context processors of Django Templating Language. Is it possible via the request as with session.
I have been using Django only for a few months, so even if the answer is obvious, please let me know.
To expand a bit on the answer above, here's the step-by-step breakdown.
First, enable a custom Environment for jinja2, as described here
In settings.py, point the environment option for jinja2 to some function
`TEMPLATES = [
{
"BACKEND": "django_jinja.backend.Jinja2",
"APP_DIRS": True,
"OPTIONS": {
"match_extension": ".jinja",
"environment": "myapp.jinjaconfig.environment",
}
},
...]`
Now you write that function to add messages to the environment. Create myapp/jinjaconfig.py (or whatever name you choose, to match what you added to settings.py):
from jinja2 import Environment
from django.contrib import messages
def environment(**options):
env = Environment(**options)
env.globals.update({
'get_messages': messages.get_messages,
})
return env
At this point you have get_messages available in your template. You can use it like this:
{% for message in get_messages(request) %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
Note that you have to pass in the request as an argument there
In the end I decided to go with the Jinja2 environment. I added a global callable to the environment like 'messages': messages.get_messages, which will let me access it like a context processor, but with messages(request) instead of the object 'messages' in DTL.
For beginners like me who doesn't know much about Jinja2, I added this callable to the jinja2.py file, which we create for enabling Jinja2 backend, just below the callable for url. You also have to import messages module from django.contrib in this file. Now, you can access the messages store from the Jinja2 template by accessing it using messages(request).
There's a ticket 24694 about adding support for OPTIONS['context_processors'] to the Jinja2 template backend.
One of the suggestions from the discussion (it's quite long!) is to use django-jinja.
Use the django_jinja package.
In your settings.py file, you will be able to add a context_processor like the example below and it works without doing anything else:
# Just an example
TEMPLATES = [
{
"BACKEND": "django_jinja.backend.Jinja2",
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.contrib.messages.context_processors.messages",
],
}
},
Doing this will merge the messages context into the template context.

Django: sorl-thumbnail and easy-thumbnail in same project

I'm working on and project that uses two separate modular Django apps. However, one app requires easy-thumbnails and the other requires sorl-thumbnails. Unfortunately, the two thumbnail libraries make use of the template tag syntax {% load thumbnail %}, so they clash and break when a template using them tries to render.
Are there any approaches to solve this type of clash? (For example, a template option does to the effect of {% load thumbnail as easy_thumbnail %}). Am I going to have to fork one of the apps and replace one of the thumbnail libraries with another? If so, which should I choose to go with?
Thank you for considering my question,
Joe
In Django 1.9, you can use the libraries option of DjangoTemplates to include a tag library under a specified name. In the example below, the thumbnail library from sorl.thumbnail is included under the name sorl_thumbnail.
Note: the templatetag itself is not changed within the template... ie. remains thumbnail
Usage:
settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "foo", "templates")],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'libraries': {
'sorl_thumbnail': 'sorl.thumbnail.templatetags.thumbnail',
},
},
},
]
your_template.html
{% load sorl_thumbnail %}
{% thumbnail mymodel.image "640x480" crop="center" as im %}
<img src="{{ im.url }}" width="{{im.width}}" height="{{im.height}}"/>
{% endthumbnail %}
Sure, just write your own stub easy_thumbnail wrapper...
Create a thumbnailtags package in one of your django apps...
...making sure it's got an empty __init__.py
In thumbnailtags/easy_thumbnail.py do something like:
from django.template import Library
from easy_thumbnails.templatetags import thumbnail
register = Library()
def easy_thumbnail(parser, token):
return thumbnail(parser, token)
register.tag(easy_thumbnail)
Use {% load easy_thumbnail %}
Note:
You might also be able to do 'import thumbnail as easy_thumbnail, and skip the def easy_thumbnail bit, tho I've not tried that.
This blog link shows how to handle this.
https://timmyomahony.com/blog/using-sorl-thumbnail-and-easy-thumbnails-same-template/
(previously
http://timmyomahony.com/blog/2012/10/22/using-sorl-thumbnail-and-easy-thumbnails-same-template/)
UPDATE 2015
I had to do the following modifications to Tom Christie's answer in order to get this to work:
create a templatetags package in one of you local apps. It is important to name it templatetags. See django docs for template tags.
... make sure it has an __init__.py, empty or not.
In templatetags/easy_thumbnail.py do this:
from django.template import Library
from easy_thumbnails.templatetags import thumbnail
register = Library()
def easy_thumbnail(parser, token):
return thumbnail.thumbnail(parser, token) # the important bit
register.tag(easy_thumbnail)
Use {% load easy_thumbnail %} or - load easy_thumbnail with pyjade