Can't get internationalization to work with Django 1.5 - django

I am trying to make a website available in different languages. I am following some tutorial I found on GitHub (https://github.com/mjp/django-multi-language).
views.py
#! -*- coding: utf-8 -*-
from django.shortcuts import render
from django.utils.translation import ugettext as _
# ──────────────────────────────────────────────────────────────────────────────
def index(request):
# Rendering the page
context = { 'foobar':_('Hello !') }
response = render(request, 'home/index.html', context)
request.session['django_language'] = 'fr'
return response
index.html
{% load i18n %}
<p>{{ foobar }}</p>
settings.py
# Project path for further access
PROJECT_PATH = path.realpath(path.dirname(__file__))
# Locale paths
LOCALE_PATHS = ( # Next to the settings.py
PROJECT_PATH+'/locale/', # the time I find a better way to
) # avoid hard coded absolute path
Localization is quite straightforward, but my page keeps saying Hello ! instead of Bonjour !.
Edit
- documentation/
- locale/ <-- I want it here
- sources/
- application1/
- application2/
- projectname/
- settings.py
- ...
- locale/ <-- Currently here
- toolbox/

Setting request.session['django_langauge'] is not helpfull in this case. The LocaleMiddleware which I assume you have installed will parse that before the request gets to the view function. You should directly use the translation functions to change language for this.
from django.utils.translation import activate
def index(request):
activate('fr')
....
return response

Related

Django translation.activate doesn't work when redirect

I have a two-language Django website and when I want to change the language, it doesn't work.
Here is the links in the template to change the language:
EN
FA
As you can see, I send the language that I want and the current path as parameters for the view.
This is the urls.py:
from .views import change_language
urlpatterns = [
path('change_lang', change_language, name='change_lang'),
]
And this is the views.py:
from django.utils.translation import activate
def home(request):
# My commands
# activate('fa')
context = {
# Some key and values
}
return render(request, 'home.html', context)
def change_language(request):
activate(request.GET.get('lang'))
return redirect(request.GET.get('next'))
And I've added these two line in the settings.py as well:
LANGUAGES = [
('fa', 'Persian'),
('en', 'English'),
]
And I found that activate(request.GET.get('lang')) doesn't work.
But when I uncomment the activate('fa') in the home view, It does work. But this command doesn't work in the change_language method.
I've found that it is because of the redirect method. I replace the redirect with render and then the activate works!
How can I do activate a language and then redirect?
Thanks for your help.

Separate domain for separate apps on django

I'd like to separate some apps on my website, and move some on differents domains.
But I'd like to avoid rewriting the urls in all the templates.
Is there an easy way to do this ?
The idea was to rewrite the reverse function (and thus, all the url dispatching thing).
Then, you have the first website called 'foo.com' and the second named 'bar.com'
This works for more sites than just two
app/urls.py
#!/usr/bin/python
# coding: utf-8
from django.conf.urls import include, url
from foo import urls as foo_urls
from bar import urls as bar_urls
url_patterns = [
url(r'^foo/',
include(foo_urls),
namespace='foo'),
url(r'^bar/',
include(bar_urls),
namespace='bar'),
]
app/__init__.py
#!/usr/bin/python
# coding: utf-8
"""
Just to simplify the multi website thing. Everything is served from one instance
"""
from __future__ import absolute_import
from django.core import urlresolvers
from django.http import Http404
from .settings LANGUAGES
old_reverse = urlresolvers.reverse
def remove_prefix(s, prefix):
return s[len(prefix):] if s.startswith(prefix) else s
def new_reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None):
""" Return an url with the domain if the page is situated on another domain
Note that this works for urls templatetags and for
django.core.urlresolvers.reverse, that are used a lot in get_absolute_url()
methods.
"""
old_reverse_url = old_reverse(viewname, urlconf, args, kwargs, current_app)
splitted_url = old_reverse_url.split('/')
if splitted_url[1] in [L[0] for L in LANGUAGES]:
(trash, lang, app, *path) = splitted_url
else:
(trash, app, *path) = splitted_url
lang = ''
if app == 'admin' or current_app == 'admin':
# fix a case where sometime the reverse has or has not a trailing /
old_reverse_url = remove_prefix(old_reverse_url, '/')
# fix a case where sometime the reverse has a double admin at the
# begining
old_reverse_url = old_reverse_url.replace('adminadmin', 'admin')
return '/%s' % old_reverse_url
path = '/'.join(path)
if lang == '':
return '//%s.com/%s' % (app, path)
else:
return '//%s.com/%s/%s' % (app, lang, path)
urlresolvers.reverse = new_reverse
templates examples
<a href="{% url 'foo:index' %}*>foo index</a>

django i18n_patterns hide default lang_code from url

I'm using the i18n_patterns to add a prefix of current lang_code to my url.
urlpatterns += i18n_patterns('',
url(r'^', include('blaszczakphoto2.gallery.urls')),
)
It allowes me to get urls like /en/about-us/ , /pl/about-us/ etc..
My default language is pl
LANGUAGE_CODE = 'pl'
I want url like /about-us/ for clients viewing my site in polish lenguage. Is there any way to hide lang_code prefix from url for default lang_code?
Django >=1.10 can handle this natively. There is a new prefix_default_language argument in i18n_patterns function.
Setting prefix_default_language to False removes the prefix from
the default language (LANGUAGE_CODE). This can be useful when adding
translations to existing site so that the current URLs won’t change.
Source: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#language-prefix-in-url-patterns
Example:
# Main urls.py:
urlpatterns = i18n_patterns(
url(r'^', include('my_app.urls', namespace='my_app')),
prefix_default_language=False
)
# my_app.urls.py:
url(r'^contact-us/$', ...),
# settings:
LANGUAGE_CODE = 'en' # Default language without prefix
LANGUAGES = (
('en', _('English')),
('cs', _('Czech')),
)
The response of example.com/contact-us/ will be in English and example.com/cs/contact-us/ in Czech.
Here is a very simple package: django-solid-i18n-urls
After setup, urls without language prefix will always use default language, that is specified in settings.LANGUAGE_CODE. Redirects will not occur.
If url will have language prefix, then this language will be used.
Also answered here: https://stackoverflow.com/a/16580467/821594.
I faced this problem and solved this way:
Created an alternative i18n_patterns that do not prefix the site main language (defined in settings.LANGUAGE_CODE).
Created an alternative middleware that only uses the URL prefixes language to activate the current language.
I didn't see any side-effect using this technique.
The code:
# coding: utf-8
"""
Cauê Thenório - cauelt(at)gmail.com
This snippet makes Django do not create URL languages prefix (i.e. /en/)
for the default language (settings.LANGUAGE_CODE).
It also provides a middleware that activates the language based only on the URL.
This middleware ignores user session data, cookie and 'Accept-Language' HTTP header.
Your urls will be like:
In your default language (english in example):
/contact
/news
/articles
In another languages (portuguese in example):
/pt/contato
/pt/noticias
/pt/artigos
To use it, use the 'simple_i18n_patterns' instead the 'i18n_patterns'
in your urls.py:
from this_sinppet import simple_i18n_patterns as i18n_patterns
And use the 'SimpleLocaleMiddleware' instead the Django's 'LocaleMiddleware'
in your settings.py:
MIDDLEWARE_CLASSES = (
...
'this_snippet.SimpleLocaleMiddleware'
...
)
Works on Django >=1.4
"""
import re
from django.conf import settings
from django.conf.urls import patterns
from django.core.urlresolvers import LocaleRegexURLResolver
from django.middleware.locale import LocaleMiddleware
from django.utils.translation import get_language, get_language_from_path
from django.utils import translation
class SimpleLocaleMiddleware(LocaleMiddleware):
def process_request(self, request):
if self.is_language_prefix_patterns_used():
lang_code = (get_language_from_path(request.path_info) or
settings.LANGUAGE_CODE)
translation.activate(lang_code)
request.LANGUAGE_CODE = translation.get_language()
class NoPrefixLocaleRegexURLResolver(LocaleRegexURLResolver):
#property
def regex(self):
language_code = get_language()
if language_code not in self._regex_dict:
regex_compiled = (re.compile('', re.UNICODE)
if language_code == settings.LANGUAGE_CODE
else re.compile('^%s/' % language_code, re.UNICODE))
self._regex_dict[language_code] = regex_compiled
return self._regex_dict[language_code]
def simple_i18n_patterns(prefix, *args):
"""
Adds the language code prefix to every URL pattern within this
function, when the language not is the main language.
This may only be used in the root URLconf, not in an included URLconf.
"""
pattern_list = patterns(prefix, *args)
if not settings.USE_I18N:
return pattern_list
return [NoPrefixLocaleRegexURLResolver(pattern_list)]
The code above is available on:
https://gist.github.com/cauethenorio/4948177
You might want to check yawd-translations which does exactly that. If you don't care about the extra functionality (manage languages from db), you can have a look at the urls.translation_patterns method and the middleware.TranslationMiddleware to see how it can be done.
This is my solution:
Create django middleware: django_app/lib/middleware/locale.py
from django.utils import translation
class SwitchLanguageMiddleware(object):
def process_request(self, request):
lang = request.GET.get('lang', '')
if lang:
translation.activate(lang)
request.LANGUAGE_CODE = translation.get_language()
def process_response(self, request, response):
request.session['django_language'] = translation.get_language()
if 'Content-Language' not in response:
response['Content-Language'] = translation.get_language()
translation.deactivate()
return response
It's read the get parameter of request and if it has lang attribute, then switching language. Ex.: /about-us/?lang=pl
Include this middleware to settings.py:
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.common.CommonMiddleware',
'django_app.libs.middleware.locale.SwitchLanguageMiddleware',
)

action="/i18n/setlang/" does not redirect to any page

I have followed the django documentation[1] to implement i18n on a "hello word" kind of google app engine website.
unfortunately, after reading dozens of html pages, django and appengine documentation I can't figure out what is happening:
changing the language code into the django_settings.py do change the language of the page and update a dropdown with the current language (i.e. LANGUAGE_CODE = 'fr' or 'es' or 'en')
change the dropdown and clicking on "change language" do lead to a "error 404" and the URL shows http:///i18n/setlang/
where can I find a list of django middlewares that app engine use by default? this might help me to digg deeper.
technical requirements (we don't plan to upgrade before i18n works :-) :
python 2.5.4
google app engine 1.6.2
Django 1.2
[1] [https://docs.djangoproject.com/en/1.2/topics/i18n/]
[2] [cssjanus.googlecode.com] a piece of code that do exactly what I want to do. but I miss a small trick
index.html contains this
<form action="/i18n/setlang/" method="post">
<input name="next" type="hidden" value="/MainPage">
<select name="language">
{% for lang in LANGUAGES %} <option value="{{ lang.0 }}"
{% ifequal LANGUAGE_CODE lang.0 %}
selected="selected"
{% endifequal %}>{{ lang.1 }}</option>
{% endfor %}
</select>
<input type="submit" value="{% trans "Change Language" %}">
</form>
app.yaml:
application: i18n
version: 1
runtime: python
api_version: 1
handlers:
- url: .*
script: helloworld.py`
django_seetings.py
import os
DEBUG = True
TEMPLATE_DEBUG = DEBUG
LANGUAGE_CODE = 'fr'
USE_I18N = True
gettext = lambda s: s
LANGUAGES = (
('en', gettext('English')),
('fr', gettext('French')),
('es', gettext('Spanish')),
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
)
SESSION_ENGINE = 'gae_sessions'
helloworld.py (I don't use urls.py)
# coding=UTF-8
# Standard Python imports.
import os
import sys
import logging
import __builtin__
# Google App Hosting imports.
from google.appengine.dist import use_library
use_library('django', '1.2')
# Enable info logging by the app (this is separate from appserver's
# logging).
logging.getLogger().setLevel(logging.INFO)
# Must set this env var *before* importing any part of Django.
os.environ['DJANGO_SETTINGS_MODULE'] = 'django_settings'
from google.appengine.ext.webapp import util
# Import the part of Django that we use here.
from google.appengine.ext import webapp
from views import MainPage
from django.conf.urls.defaults import include
def main():
# Create a Django application for WSGI
application = webapp.WSGIApplication([('/', MainPage),
(r'^i18n/', include('django.conf.urls.i18n')),
], debug=True)
# Run the WSGI CGI handler with that application.
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
views.py
'''
Created on Apr 24, 2012
#author:xxxx
'''
import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from django.utils.translation import ugettext #ok
from django import http
from django.http import HttpResponseRedirect
import django_settings
from django.utils.translation import check_for_language
#from django.shortcuts import render_to_response
#def MainPage(request):
class MainPage(webapp.RequestHandler):
def get(self):
template_values = {
'helloworld': ugettext("helloworld!"),
'title': ugettext("home page"),
}
path = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(path, template_values))
#return render_to_response('index.html', template_values)
helloworld.py
# coding=UTF-8
# Standard Python imports.
import os
import sys
import logging
import __builtin__
# Google App Hosting imports.
from google.appengine.dist import use_library
use_library('django', '1.2')
# Enable info logging by the app (this is separate from appserver's
# logging).
logging.getLogger().setLevel(logging.INFO)
# Must set this env var *before* importing any part of Django.
os.environ['DJANGO_SETTINGS_MODULE'] = 'django_settings'
from google.appengine.ext.webapp import util
# Import the part of Django that we use here.
from google.appengine.ext import webapp
from views import MainPage
from django.conf.urls.defaults import include
def main():
# Create a Django application for WSGI
application = webapp.WSGIApplication([('/', MainPage),
(r'^i18n/', include('django.conf.urls.i18n')),
], debug=True)
# Run the WSGI CGI handler with that application.
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
It seems that you are confusing django routing with webapp's one. I don't think you can use statement like include('django.conf.urls.i18n') in the initialization process of webapp.WSGIApplication.
Additionally, as greg says, I also recommend using Python2.7 runtime, because it is much easier for you to use django(Believe me, it's super easy) with the new runtime.
Updated: added a procedure for running django-1.3 with Python2.7 runtime
Here is a rough procedure to make django work with python2.7 runtime.
Create a project
$ env PYTHONPATH=/somewhere/google_appengine/lib/django_1_3 \
python /somewhere/google_appengine/lib/django_1_3/django/bin/django-admin.py\
startproject my_django_project
$ cd my_django_project
You can use settings.py for your django settings file by configuring
an env_variables in your app.yaml.
Create an app.yaml
application: tmatsuo-hr
version: 1
runtime: python27
api_version: 1
threadsafe: true
env_variables:
DJANGO_SETTINGS_MODULE: 'settings'
handlers:
- url: /.*
script: main.app
libraries:
- name: django
version: 1.3
Create your django app
$ env PYTHONPATH=/somewhere/google_appengine/lib/django_1_3 \
python manage.py startapp myapp
Create your main.py
import django.core.handlers.wsgi
app = django.core.handlers.wsgi.WSGIHandler()
Configure your settings.py
ROOT_URLCONF = 'urls'
Add 'myapp' to your INSTALLED_APPS
Configure urls.py
url(r'^$', 'myapp.views.index', name='index'),
Create your views at myapp/views.py
# Create your views here.
from django.http import HttpResponse
def index(request):
return HttpResponse('Hello World!')
Done. You should be able to configure this project in the same way as usual django applications.
However, you can not use Django's model because it needs SQL backends. If you'd like to do so, go check django-nonrel, or consider using django with CloudSQL.

Using static images with sorl-thumbnail

I am trying to serve the thumbnail of a file that resides in my STATIC_ROOT folder. It doesn't really matter if it ends up in MEDIA_URL/cache, but sorl-thumbnail will not load the image from the static folder.
current code:
{% thumbnail "images/store/no_image.png" "125x125" as thumb %}
hack that works
{% thumbnail "http://localhost/my_project/static/images/store/no_image.png" "125x125" as thumb %}
I don't like the hack because
A) It is not dry (my project is actually served from a sub-directory of /
B) It is using http to grab a file that is only 3 directories away, seems pointlessly inefficient
I worked around this by passing through a file to the template context from my view.
Here is an example util function I called from my views:
def get_placeholder_image():
from django.core.files.images import ImageFile
from django.core.files.storage import get_storage_class
storage_class = get_storage_class(settings.STATICFILES_STORAGE)
storage = storage_class()
placeholder = storage.open(settings.PLACEHOLDER_IMAGE_PATH)
image = ImageFile(placeholder)
image.storage = storage
return image
You could probably do something similar as a custom template tag.
Template filter works. But I am not sure, whether there is each time reading from storage. If so, it is unreasonably...
from django.template import Library
from django.core.files.images import ImageFile
from django.core.files.storage import get_storage_class
register = Library()
#register.filter
def static_image(path):
"""
{% thumbnail "/img/default_avatar.png"|static_image "50x50" as img %}
<img src="{{ MEDIA_URL }}{{img}}"/>
{% endthumbnail %}
"""
storage_class = get_storage_class(settings.STATICFILES_STORAGE)
storage = storage_class()
image = ImageFile(storage.open(path))
image.storage = storage
return image
Assuming you are using Django 1.3 you should take a look at the docs about Managing static files
If you setup everything correctly, you can include your images like this:
<img src="{{ STATIC_URL }}images/store/no_image.png" />
I ended up hijacking the fact that it can get from a URL, and wrote my own tag that overrides the _render method on the ThumbnailNode:
from django.template import Library
from django.contrib.sites.models import Site
from django.contrib.sites.models import get_current_site
from sorl.thumbnail.templatetags.thumbnail import ThumbnailNode as SorlNode
from sorl.thumbnail.conf import settings
from sorl.thumbnail.images import DummyImageFile
from sorl.thumbnail import default
register = Library()
class ThumbnailNode(SorlNode):
"""allows to add site url prefix"""
def _render(self, context):
file_ = self.file_.resolve(context)
if isinstance(file_, basestring):
site = get_current_site(context['request'])
file_ = "http://" + site.domain + file_
geometry = self.geometry.resolve(context)
options = {}
for key, expr in self.options:
noresolve = {u'True': True, u'False': False, u'None': None}
value = noresolve.get(unicode(expr), expr.resolve(context))
if key == 'options':
options.update(value)
else:
options[key] = value
if settings.THUMBNAIL_DUMMY:
thumbnail = DummyImageFile(geometry)
elif file_:
thumbnail = default.backend.get_thumbnail(
file_, geometry, **options
)
else:
return self.nodelist_empty.render(context)
context.push()
context[self.as_var] = thumbnail
output = self.nodelist_file.render(context)
context.pop()
return output
#register.tag
def thumbnail(parser, token):
return ThumbnailNode(parser, token)
Then from the template:
{% with path=STATIC_URL|add:"/path/to/static/image.png" %}
{% thumbnail path "50x50" as thumb %}
<img src="{{ thumb.url }}" />
...
Not the neatest solution... :-/
The default value of setting sorl THUMBNAIL_STORAGE is the same settings.DEFAULT_FILE_STORAGE.
You must create storage that uses STATIC_ROOT, for example you can use 'django.core.files.storage.FileSystemStorage' and instantiate with location=settings.STATIC_ROOT and base_url=settings.STATIC_URL
Only THUMBNAIL_STORAGE set in settings for a 'MyCustomFileStorage' did not work. So I had to do to DEFAULT_FILE_STORAGE and it worked.
Define in settings.py:
DEFAULT_FILE_STORAGE = 'utils.storage.StaticFilesStorage'
utils/storage.py:
import os
from datetime import datetime
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.core.exceptions import ImproperlyConfigured
def check_settings():
"""
Checks if the MEDIA_(ROOT|URL) and STATIC_(ROOT|URL)
settings have the same value.
"""
if settings.MEDIA_URL == settings.STATIC_URL:
raise ImproperlyConfigured("The MEDIA_URL and STATIC_URL "
"settings must have different values")
if (settings.MEDIA_ROOT == settings.STATIC_ROOT):
raise ImproperlyConfigured("The MEDIA_ROOT and STATIC_ROOT "
"settings must have different values")
class TimeAwareFileSystemStorage(FileSystemStorage):
def accessed_time(self, name):
return datetime.fromtimestamp(os.path.getatime(self.path(name)))
def created_time(self, name):
return datetime.fromtimestamp(os.path.getctime(self.path(name)))
def modified_time(self, name):
return datetime.fromtimestamp(os.path.getmtime(self.path(name)))
class StaticFilesStorage(TimeAwareFileSystemStorage):
"""
Standard file system storage for static files.
The defaults for ``location`` and ``base_url`` are
``STATIC_ROOT`` and ``STATIC_URL``.
"""
def __init__(self, location=None, base_url=None, *args, **kwargs):
if location is None:
location = settings.STATIC_ROOT
if base_url is None:
base_url = settings.STATIC_URL
if not location:
raise ImproperlyConfigured("You're using the staticfiles app "
"without having set the STATIC_ROOT setting. Set it to "
"the absolute path of the directory that holds static files.")
# check for None since we might use a root URL (``/``)
if base_url is None:
raise ImproperlyConfigured("You're using the staticfiles app "
"without having set the STATIC_URL setting. Set it to "
"URL that handles the files served from STATIC_ROOT.")
if settings.DEBUG:
check_settings()
super(StaticFilesStorage, self).__init__(location, base_url, *args, **kwargs)
Reference:
https://github.com/mneuhaus/heinzel/blob/master/staticfiles/storage.py
https://docs.djangoproject.com/en/dev/ref/settings/#default-file-storage