Tuesday, December 22, 2009
New localization system already in trunk
Friday, April 24, 2009
GSoC: Implementation of additional i18n features on Django
Here you have my proposal for Google Summer of Code 2009. It was approved previous week, and I'll be working on it during this summer.
The problem
While Django provides an amazing system to translate texts, and displays localized dates in some parts of the admin; it has many data that could be internationalized, not it's not yet.
The information that developers should be able to localize/translate is mainly:
-
All dates and related information (times, calendars...)
-
All numbers (mainly decimal ones)
-
Texts (and any data in general) saved on the database
More information on these issues can be found in the following blog post and this ticket:
http://vaig.be/2008/07/django-i18n-status.html
http://code.djangoproject.com/ticket/7980
Proposal
The proposed solution for improving Django i18n includes several different tasks. Those tasks are:
-
Import locale data from CLDR
-
Apply i18n to Django dates and times
-
Apply i18n to Django numbers
-
Allow translating content on the database
- Fix already reported bug about i18n
Next are the details for every task. Note that all those specifications are subject to change, according to discussions with the mentor of the project, Django core developers team, and the main Django community.
Importing locale data
The main repository of locale data is the Common Locale Data Repository (CLDR) by the Unicode Consortium http://cldr.unicode.org/. It provides a set of XML files with information such as date, time and number formatting for most languages.
The idea of this task would be to create a python script (probably as a django-admin command), that will extract all necessary data from those XML files and put it into configuration files on the Django structure. This information will be used by Django to internationalize data on applications.
The idea of this script is to be used just by Django developers. It would mainly be a one-time execution script, and then it would be executed just when new locales are added (are some are changed).
All information gathered from CLDR files could be saved on django/conf/locale/{ language code }/formats/django.po
Specific settings imported from CLDR could be (with English localized example):
-
SHORT_DATETIME_FORMAT (12-31-2000 11:59 p.m.)
-
LONG_DATETIME_FORMAT (December 31th 2000, 11:59 p.m.)
-
SHORT_DATE_FORMAT (12-31-2000)
-
LONG_DATE_FORMAT (December 31th 2000)
-
FIRST_DAY_OF_WEEK (0 meaning Sunday)
-
TIME_FORMAT (11:59 p.m.)
-
YEAR_MONTH_FORMAT (December of 2000)
-
MONTH_DAY_FORMAT (December 31th)
-
DECIMAL_NUMBER FORMAT (1,000,000.123)
There are some locale based parameters that already exist on Django, on translation files (LC_MESSAGES) and could be deprecated on future releases of Django (when breaking backward compatibility). Those are:
-
DATETIME_FORMAT
-
DATE_FORMAT
-
TIME_FORMAT
-
YEAR_MONTH_FORMAT
-
MONTH_DAY_FORMAT
For keeping the system flexible, existing default values on settings will be kept. Probably it would be worth to add new ones for the new customizable formats.
Dates, times and calendar i18n
All dates and times displayed using Django should use the format defined for the current session locale. This is already implemented for some dates, like the ones displayed in admin's lists. Also a filter for formatting dates already exists in templates, which, together with the formats in the translation files, can do the job. But the good way to do that would be displaying the date by default on the session locale.
All Django forms (including admin forms) should accept the short date/datetime format of the current locale. Now it's possible to define the accepted formats using parameters of the widget, and this can be kept, but at least support for entering data formatted in current locale should be added. ISO and/or English locale can be kept as well. Existing data on input fields should be displayed in current locale too.
As Django 1.0 series is maintaining backward compatibility, those changes have to be implemented being compatible with existing behavior by default.
The calendar on admin's date/datetime field should also be displayed according to user session locale.
So basically those are the main tasks required for internationalizing Django dates:
-
Format all python date/datetimes objects using locale settings when converted to string to be displayed. Basically it means models.DateField and models.DateTimeField values on model instances.
-
Change input widgets to display data and to allow entering data on the format of the current locale.
-
Display admin calendar starting weeks on the day defined for current locale.
With those changes next tickets would be fixed:
-
#1061 About first day on calendars
-
#5526 About accepting non-English formats on input widgets
-
#6231 About the output format of the SelectDateWidget
-
#6449 About default format of displayed dates
-
#6483 About supporting European dates on javascript routines
-
#7509 About supporting different formats on SplitDateTimeWidget
-
#7656 About inheriting i18n features of AdminDateWidget
Number i18n
Right now, Django doesn't provide anything for localizing numbers on applications. All numeric values within Django applications are formatted using American formats. Users from many countries are not used to dealing with the American format, and a simple shop using Django can create confusion among users who, for example, expect the comma to be the decimal separator, and they find the point on prices.
As for the previous section, changes must be applied keeping backward compatibility.
So Django should display, and use by default the language of the current locale to format numbers. Basically that means:
-
Format numbers on templates using current session locale
-
Display and allow entering data using session locale on input widgets
With those changes next ticket should be fixed:
-
#3940 About comma as decimal separator
Translating dynamic content
Django has an amazing system for translating texts to any language. The only problem of this system is that it can just be used for static content (defined on source files, including templates), and not for dynamic content, created by users after deploying the web site. This can be useful for many different situations like an application that has a product catalog where product names and descriptions have to be translated, or a news website, where news can be translated to any language.
There are some external applications, widely used, that allow to do that on Django, but all of them have many different problems, like complex and tricky syntax for developers, ugly interface for users, bad design, bad scalability... Main applications are:
-
django-multilingual
-
transdb
-
django-transmeta
-
django-multilingual-model
A comparison of the two first applications, and some ideas for a better solution, can be found on a presentation at
http://docs.google.com/Presentation?docid=dfbzs3ks_7f2z85hvr&hl=en
Basically, a good solution to allow Django developers to translate their models should include:
-
An easy way to specify translatable fields on models (or outside the models)
-
An easy way to allow translating content using the admin or custom forms
-
Displaying translated fields in session language by default (allowing to get the value for a specific value)
-
A scalable way to save translations on the database
To achieve those targets a lot of analysis is required, so, just some ideas are detailed here.
For the model syntax there are many different options, some of them can be checked on this blog post, and this poll:
http://vaig.be/2009/03/django-multilingual-syntax-poll.html
http://doodle.com/aicvayf8ss2mxm2h
The most popular one is (using an example):
class MyModel(model.Model):
my_field = CharField()
my_i18n_field = CharField()
class Meta:
translate = ('my_i18n_field',)
A way to translate models (and whole applications) without modifying its code would be great, in order to translate applications that already exist.
For the database backend there are also different options, including:
- To create a field on the model for every translation
- To create a related model
There is just one generic ticket on Django that would be fixed:
-
#6460 About multilingual content on database
May be it's not possible having a generic solution that fits most of the user-cases, and in that case could be worth making some modifications on Django to make it easier creating external applications that can do this job.
Fix i18n bugs
There are many bugs already accepted on Django trac, that would be fixed on this Summer of Code. A better review will be done, but some of them could be:
- #3907: LocaleMiddleware allows languages not supported by Django
- #5494: Javascript catalog doesn't check project level locales
- #7050: make-messages should ignore applications with custom localization
Timeline
The estimated time line for this project, detailed in a weekly basis is:
-
Week 01: Analysis and working environment setup
-
Week 02: Import CLDR
-
Week 03: Import CLDR
-
Week 04: I18n of dates and numbers
-
Week 05: I18n of dates and numbers
-
Week 06: I18n of dates and numbers
-
Week 07: Translation of dynamic content
-
Week 08: Translation of dynamic content
-
Week 09: Translation of dynamic content
-
Week 10: Translation of dynamic content
-
Week 11: Fix i18n bugs
-
Week 12: Fix i18n bugs
My dedication to the project will be full time, around 40 hours per week. A total of 480 hours are estimated for the whole project.
About me
My name is Marc Garcia, I'm from Barcelona, Europe, and I'm 29 years old.
I am studying computer science at Universitat Oberta de Catalunya, an Internet-based university from Barcelona. Currently I'm not working but I have almost 8 years of programming experience (with different technologies, mainly Python, PHP and VB).
I started using Django in 2006, and at this time I developed and participated on the development of many websites, as well as many reusable applications for Django.
As examples of reusable Django applications note:
-
django-stdimage: Saves ImageField files with standard names, allowing to delete them, and creating automatic thumbnails.
-
Transdb: Allows translating database content
-
django-transmeta: Also allows translating database content (different approach)
-
django-cart: Simple cart object to easily add/update/remove products to user session
As examples of websites, note next ones:
-
http://elisa.fluendo.com (main developer)
-
http://www.andalucia.org (developer of some parts, mainly the shop and the registration system)
-
http://www.muchomasqueunregalo.com (developer of the Django part of the web site, including the shopping system and product detail pages).
-
http://www.accopensys.com (only developer)
-
http://www.showroom.es (only developer)
-
http://www.tierratenis.com (only developer)
-
http://www.latelierdelraval.com (only developer)
-
http://www.restaurantalpunt.com (only developer)
I'm also one of the two official translators of Django to Castilian Spanish and Catalan. In addition, I was interviewed about localization on Django on This Week in Django 20 (on 2008-04-27). I maintain a blog with many Django related posts at http://vaig.be.
Wednesday, March 25, 2009
django-cart released!
So what I've not any complain for satchmo, the fact is that is not the ideal solution for some cases as some small shops with few options.
With that said, this post is to announce the release of a new project that could help some people to do simple web shops in a very simple way. This project is django-cart.
While django-cart already existed, it was an unfinished (and unmaintained) project by Eric Woundenberg, to whom I'm very thankful for letting reuse it's project, and avoid confusion.
So, what's django-cart. Django Cart is basically a django application that provides a Cart class, with add/remove/update and get methods to be used for storing products. The products model isn't included in the application, so you can define your products with the fields you need. Then you just need something like...
product_to_add = MyProductModel.objects.get(id=whatever)
cart = Cart(request)
cart.add(product_to_add, product_to_add.price)
and your product will be saved on the database, on a session based cart. Getting the content of the cart is as easy as itering the cart instance.
And basically that's it. More information is available on the project page. Just note that the current version of the application is unstable, and hasn't been tested enough, so feel free to use it, but consider that you'll have to test it by yourself and report/fix some bugs.
I hope all you like it!
Wednesday, March 11, 2009
Getting client OS in Django
So, while most time just some Javascript is used to customize user experience based on its operating system, few times it'll also be useful to do it in the server side.
For those cases, here you've a simple context processor that will make available a template variable named "platform" which content can be "Linux", "Mac" or "Windows".
import re
def user_agent(request):
'''
Context processor for Django that provides operating system
information base on HTTP user agent.
A user agent looks like (line break added):
"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) \
Gecko/2009020409 Iceweasel/3.0.6 (Debian-3.0.6-1)"
'''
print 'user_agent'
# Mozilla/5.0
regex = '(?P<application_name>\w+)/(?P<application_version>[\d\.]+)'
regex += ' \('
# X11
regex += '(?P<compatibility_flag>\w+)'
regex += '; '
# U
regex += '(?P<version_token>[\w .]+)'
regex += '; '
# Linux i686
regex += '(?P<platform_token>[\w .]+)'
# anything else
regex += '; .*'
user_agent = request.META['HTTP_USER_AGENT']
result = re.match(regex, user_agent)
if result:
result_dict = result.groupdict()
full_platform = result_dict['platform_token']
platform_values = full_platform.split(' ')
if platform_values[0] in ('Windows', 'Linux', 'Mac'):
platform = platform_values[0]
elif platform_values[1] in ('Mac',):
# Mac is given as "PPC Mac" or "Intel Mac"
platform = platform_values[1]
else:
platform = None
else:
full_platform = None
platform = None
return {
'user-agent': user_agent,
'full_platform': full_platform,
'platform': platform,
}
To make it work just copy the code in a file
myproject/myapp/context_processors.py
add it to context processors in settings
TEMPLATE_CONTEXT_PROCESSORS = ('myproject.myapp.context_processors.user_agent', [...])and don't forget to add the RequestContext parameter if you are processing your template with render_to_response and want the variable available
from django.template import RequestContext
[...]
render_to_response('mytemplate.html', mycontext, RequestContext(request))
Then you'll be able to do something like that in your templates:
<p>You are a {{ platform }} user.</p>
Tuesday, March 10, 2009
django-multilingual syntax poll
While there are some intentional differences among some projects (for example django-modeltranslation is the only one that can translate models without editing them), it would be great to merge all (or most) existing projects, and join the efforts to get our best application (and hopefully it'll worth to be included in Django itself).
So, with the merge of those applications in mind, we're planning to create a branch on django-multilingual that will have the very best of each existing application, and any other cool idea.
So if you have good Python/Django skills, and want to add some open source work in your CV... ;) join us now!
Or if you are a potential user of this application, or you just think that your opinion is worth to be shared, please fill the MODEL SYNTAX POLL, or mail us with your ideas.
Here there are simple sample for each option on the poll:
class Translation
class MyModel(model.Model):
my_field = CharField()
class Translation(multilingual.Translation):
my_i18n_field = CharField()
custom fields
class MyModel(model.Model):
my_field = CharField()
my_i18n_field = TransCharField()
separate model
class MyModel(model.Model):
my_field = CharField()
my_i18n_field = CharField()
Class MyModelTranslation(TranslationOptions):
fields = ('my_i18n_field',)
translate attrs in Meta
class MyModel(model.Model):
my_field = CharField()
my_i18n_field = CharField()
class Meta:
translate = ('my_i18n_field',)
translate=True in field options
class MyModel(model.Model):
my_field = CharField()
my_i18n_field = CharField(translate=True)
Do you have a better idea?
Just leave a comment here,
or write a mail on this thread
Friday, March 6, 2009
Numeric IP field for Django
Basically, and IP address is just 4 bytes of data, but it's text representation can use between 7 and 15 bytes. That's not a big different when your model will have few rows, but it's a different when you'll have a huge set of IP addresses, and specially if you want to join tables by it.
The only inconvenient of storing the IPs as numbers is that are not human readable if you want to check them directly to database.
So, here you have my code that can be used as a replacement of IPAddressField:
import IPy
from django.db import models
from django import forms
from django.utils.translation import ugettext as _
def _ip_to_int(ip):
return IPy.IP(ip).ip
def _int_to_ip(numeric_ip):
return IPy.IP(numeric_ip).strNormal()
class IPFormField(forms.fields.Field):
def clean(self, value):
try:
_ip_to_int(value)
except ValueError:
raise forms.ValidationError, \
_('You must provide a valid IP address')
return super(IPFormField, self).clean(value)
class IPField(models.fields.PositiveIntegerField):
'''
IP field for django for storing IPs as integers on database
(Django's field IPAddressField stores them as text)
'''
__metaclass__ = models.SubfieldBase
def to_python(self, value):
if value:
if isinstance(value, long):
return _int_to_ip(value)
else:
return value
else:
return None
def get_db_prep_save(self, value):
try:
result = _ip_to_int(value)
except ValueError:
result = None
return result
def get_db_prep_value(self, value):
if value:
return _ip_to_int(value)
else:
return None
def get_db_prep_lookup(self, lookup_type, value):
return super(IPField, self).get_db_prep_lookup(
lookup_type,
_ip_to_int(value)
)
def formfield(self, **kwargs):
defaults = {'form_class': IPFormField}
defaults.update(kwargs)
return super(IPField, self).formfield(**defaults)
NOTE: This code requires IPy, a single file python library to work with IP addresses.
Wednesday, March 4, 2009
Easier field translation with django-transmeta
The basis of that simplicity is creating a field in the database table for every translation, so internally we'll have something like:
CREATE TABLE app_model (
[...]
myfield_en varchar,
myfield_ca varchar,
[...]
);
where "en" and "ca" are the languages in our application (English and Catalan in this case).
For the developer, translating a model is as simple as adding a metaclass to the model, and specify the fields to translate in its Meta class:
from transmeta import TransMeta
class MyModel(models.Model):
__metaclass__ = TransMeta
name = models.CharField(max_length=64)
description = models.TextField()
price = models.FloatField()
class Meta:
translate = ('name', 'description', )
Even with this project is still as tricky as transdb and multilingual, its main goal is being really really simple, for its design, for developers, and its code (that mainly it's about 120 lines of code). It also breaks some limitations of transdb (its most simple predecessor IMHO) like translating non-text fields.
I also want to mention that I just discovered a new project for translating model fields, named django-modeltranslation, that looks cool, but I don't like the (admin like) registering way to set translatable fields (too much complicated).
Thursday, February 19, 2009
Parsing unescaped urls in django
The answer is that can get unexpected results if you server works in Django (and probably in any python framework/application). That's because python's BaseHTTPServer.BaseHTTPRequestHandler handles urls according to standards, not from a human point of view.
Let's see with an example, consider the next request:
http://vaig.be/identify_myself?name=Marc Garcia&country=Cataloniaif you request it with a browser, it will escape the space in the url, so the server will get:
http://vaig.be/identify_myself?name=Marc%20Garcia&country=Cataloniabut what if the client uses, for example, python's urllib2.urlopen without escaping (using urllib.quote)? Of course it is a mistake, but you, as server side developer can't control your clients.
In that case the whole request that server receives is:
GET http://vaig.be/identify_myself?name=Marc Garcia&country=Catalonia HTTP/1.1and after being processed (splitted) by python's BaseHTTPServer.BaseHTTPRequestHandler, what we'll get from django is:
request.method == 'GET'
request.META['QUERY_STRING'] == 'name=Marc'
request.META['SERVER_PROTOCOL'] == 'Garcia&country=Catalonia HTTP/1.1'
so our request.GET dictionary will look like:
request.GET == {'name': 'Marc'}what is not the expected value (from a human point of view).
So, what we can do for avoiding this result is quite easy (and of course tricky), and is getting the GET values not from django request.GET dictionary but from the one returned by this function:
def _manual_GET(request):
if ' ' in request.META['SERVER_PROTOCOL']:
query_string = ' '.join(
[request.META['QUERY_STRING']] +
request.META['SERVER_PROTOCOL'].split(' ')[:-1]
)
args = query_string.split('&')
result = {}
for arg in args:
key, value = arg.split('=', 1)
result[key] = value
return result
else:
return request.GET
Wednesday, August 13, 2008
StdImage updated to trunk
Basically all major changes (except GeoDjango) affected it, such as change from newforms to forms, signal refactoring, and file storage refactoring. Now it's up to date.
Remind that django-stdimage is a Django application that provides a standardized image field(standard name including row id, standard size, and ability to create automatic thumbnails, also standarized of course).
Friday, August 1, 2008
Translating Django apps. Good practices
1. Setting up the environment
Doing some trivial changes to your project structure, can avoid you of translating many string (the ones that are already translated in Django, or in any external application).
For achieving it, my tip is to copy Django itself, and all external applications to your project path, not in a PYTHONPATH directory. It can also avoid compatibility problems, and version conflicts if you're working on several projects. Then your project root will contain something like:
__init__.py
settings.py
urls.py
django/
transdb/
myapp/Next step is patching Django (while it's not included in trunk) to omit the inclusion of already translated applications into your project. Here is the patch, and you can also see #7050 for further information, or know the status.
Then, when executing ./manage.py makemessages you'll find in your project catalogs, just strings that aren't previously translated.
2. Creating string
If you don't have a correct literal creation policy, then your translator will have extra work, problems, and your translation won't be as correct as it should.
The first thing to do is write literals thinking in reusability (as software reusability but for translations). I'll show it with some examples:
Using
{% trans 'product' %}
{% trans 'Product' %}
{% trans 'product:' %}
you'll create 3 different string in your translation. Using
{% trans 'product' %}
{{ _("product")|capfirst }}
{% trans 'product' %}:
will create just one.
Another thing to consider is that some times you consider that a word has just one meaning, or at least you don't think that could be translated using different words. But actually, when translating it to another language it can be converted to different words depending on the context. Let's use an example.
Play football
Play the guitarProbably for most native English speakers play doesn't have more than a subtle difference in two sentences, but if I translate it as follows:
_("play") -> jugarThen you'll find something like
Play football -> Jugar a futbol (what's correct)
Play the guitar -> Jugar con la guitarra (what means "To have fun with the guitar", probably without generating any sound)This will be avoided most times, because usually we don't translate word my word, but there are few cases where we do that, and you should consider doing something like that in that case (actually I never had to do it :)
_("play <!-- an instrument -->")
_("play <!-- a sport -->")Then when you translate into Spanish:
"play <!-- an instrument -->" -> "tocar"
"play <!-- a sport -->" -> "jugar"And I would also translate English into English:
"play <!-- an instrument -->" -> "play"
"play <!-- a sport -->" -> "play"There will be infinite cases that will generate issues when translating, and it'll be impossible to control everyone. I just wanted to give some tips focused to Django applications.
3. Translating
This article isn't intended to explain how to translate (I think that there is a degree at university for it ;) . But may be you should give some tips/explanations to your translators for better results.
The first thing you should explain them is how to work with some special cases in your strings. Here you have the two mos common examples that they will found:
"This is normal text, <big>and this one is bigger</big>"
"Hello %(name)s"Unless you explain them what it means, probably you'll find something like that in you translated string (using Spanish in the example):
"Este texto es normal, <grande>y éste es mayor</grande>"
"Hola %(nombre)s"Of course those translations doesn't generate the expected results, because the correct ones are:
"Este texto es normal, <big>y éste es mayor</big>"
"Hola %(name)s"Another thing that could be clarified, specially if your translator is involved in the Web site that is being translated (or at least knows the context where every string is used), is not to create translations more specific than the original texts.
For example, imagine that you've in your application a form for personal data, and one of the fields is called "name". Then you translate your application to Catalan, and your translator knows when translating "name", that is used as person name, and translate it as "nom propi" (first name). It will look nicer by now, while being incorrect for me, so later may be you'll add a form where you ask corporate information and you have a field "name" for the company name. You won't send the string "name" to the translator again, and your translation will be incorrect, so "nom propi" (first name) is not valid for the company name.
4. Choosing the main language
Sometimes it isn't so obvious the language your application is written in (I mean the language you use inside gettext strings, or trans/blocktrans tags).
If you're writing an application that will be used widely in the world, and it will be translated to many languages, probably you think that English should be the right language for it, but in some cases there are some questions to take care on.
- Will your company have an international team (specially of Django developers)? If you have workers from many countries, probably English will be good for letting all of them write/read from the code.
- Will your translation team/company use English as it source language? The .po files will show your main language as source for translating string. If you hire a German to French translator, isn't a good idea writing your strings in English, so your/their work will increase a lot, and the reliability of the process will decrease.
- Are your coders fluent in English? It's more complicated (more work) to change a string from a the main language than from a translation. So if your developers can't write correct English, writing literals in their mother tongue language will save time and work.
Unluckily some times you'll have conflicts in previous questions, and you'll have to choose the lesser evil.
Tuesday, July 29, 2008
DjangoCon is still alive?
The fact is that many people is waiting to know if he/she can get a ticket to start planning the trip to SF, ans specially to purchase flight tickets. In those two weeks since DjangoCon announcement, flight prices from Barcelona to SF have increased in a 30%. I don't think it's the only case.
My question is... It is so difficult to develop and run an application to register users, letting many djangonauts to save some money that could be given to the DSF? :) Are you coding it in PHP? ;)
Seriously, if you need help, just ask for it, we are a community. But please, stop delaying ticket releasing, we have to get our tickets, make our plans, and we don't want to waste our money getting last time flight tickets. IMHO ticket realising should be priority #1.
Finally I want to comment something else here in my blog, that previously submitted to DjangoCon organization. Program isn't closed, and probably this is planned and will be added later, but don't you think that BoF sessions are a must in the DjangoCon? I think that we should take profit of being all togheter, to discuss freely any subject about Django, or any related topic.
Saturday, July 26, 2008
Django i18n status
Here you have what, from my point of view, is the status of django i18n. Comments will be very welcome, specially from people from countries with other i18n needs than mine (based on the idea that Django i18n is perfect for people in the US, here is the troubleshooting for my country, for sure more problems exists for people in for example China).
This list is part of the analysis that I'm doing to fix all those problems. If you want to participate in making Django also "The web framework for perfectionists outside the US", please contact me.
| Subject | Comments | ||
| Translation (static content) | Yes | Django has an amazing translation system, easy to use, and exceptionally automated. Also it has bidi support. Despite of this, some problems can be found when translating django or applications to other languages (masculine/femenine...). | |
| Translation (database content) | No | Django doesn't support model field translation, but it can be achieved using an external application such as TransDb, django-multilingual, django-utils translation service and i18ndynamic. As far as I know only TransDb and django-multilingual are working on Django's trunk. | |
| Calendar customization | No | Patching Django is required to change first day of week in admin calendar (first day of week is Monday according to ISO and in many countries (most Europe, most South America, and some parts of Asia). See ticket #1061 | |
| Date format (when displaying) | Yes | Dates displayed in admin are formatted according to current locale. Also custom dates can be easily formatted using date filter (f.e. {{ my_date|date:_("DATE_FORMAT") }} ). The problem here, is that few internationalized formats are defined inside django, so using django formats you can internationalize a date with format "December 31th, 2000", but not with format "12/31/2000". It can be achieved creating date formats in your catalog. | |
| Date format (on inputs) | No | Django allows specifying one or many input formats for a date form field (using the input_formats parameter of the form field).I think that there is no way to specify the format on the admin fields, specially because the format that generates the calendar is always the same. Anyway what it's expected is not to specify the format of a field, actually it is to get the format from the current locale. | |
| Number format (when displaying) | No | Django has just a filter (floatformat) to format numbers, where you can specify how many decimals you want. It's very difficult to customize your number format, to the format of the current locale, and even to a fixed format. | |
| Number format (on input) | No | Django has no way to specify if you want to enter a decimal number with comma separator (dot is always used). Of course it can't be done according to current locale. |
Monday, May 19, 2008
TransDb working on trunk!
This weekend we had a TransDb sprint, to try to improve our project, and contribute to fix this situation in any way.
The result: We fixed many issues on TransDb, now the project has a more conventional structure, and a setup script, and... TransDb is now working on trunk!
For achieving it we created a new branch called oldforms.
Try it now!
Saturday, May 17, 2008
StdImageField: Improved image field for Django
Features of StdImageField:
- Saved files have standardized names (using field name and object id)
- Images can be removed
- Automatically creates a thumbnail
- Automatically resizes both image and thumbnail (with optional crop to fit exactly specified size)
Here you've an example of usage:
from django.db import models
from stdimage import StdImageField
class MyClass(models.Model):
my_image = StdImageField(upload_to='path/to/img', blank=True, \
size=(640, 480), thumbnail_size=(100, 100, True))If a file called "uploaded_file.png" is uploaded for object id 34, then result will be:
- /path/to/img/my_image_34.png (with bigger possible size to fit in a 640x480 area)
- /path/to/img/my_image_34.thumbnail.png (with a exact size of 100x100, cropping if necessary)
Also it will appear a check-box for deleting when using admin.
Sunday, May 11, 2008
Searching on Django Snippets
I've followed many of the James work, and it's awesome; but I've a complaint on Django Snippets. It's the inefficient way to find anything there. The only ways that I've found is searching using a paginated list by author, language or tag (sorted alphabetically), where you can spend a huge amount of time if the tag you search starts by Z.
Of course that I can go to Google an search using site:www.djangosnippets.org, and it would work for all indexed snippets, but I think that at least this search box should be added on the site (until anybody writes the generic search engine for Django). It would also help adding result page numbers (with links) at the end of the paginated list.
Changing language on the admin
With standard Django the only way that exists (as far as I know), is leaving the admin, going to the website, change the language there, and come back to the admin. Not very fast.
Today, I've created a snippet that creates a drop down menu on the admin bar (just in the main page) to change the language.
Hope it helps.
Saturday, May 10, 2008
DSNP 0.9 released
For now, it'll be 0.9 because it works on Django newforms-admin branch, so 1.0 will be reached when newforms-admin will be merged into trunk.
Changeset for this version is next:
- Generated sqlite file has write permissions for all users by default
- Static files are served by Django http server on development environment (DEBUG==True)
- File admin.py created to specify admin options
- Media path has changed (now, all static files are under "media" directory) due to an issue
I hope you like it.
Friday, May 9, 2008
Unable to define my urls exactly my way (resignation statement)
What it is nice for me, opposite to Django default settings, is avoiding the media prefix on my media urls, so
http://localhost/media/admin/css/login.css would be http://localhost/admin/css/login.cssTrying to emulate old website structures (used widely in php sites).
That could be nice or not, but for sure it is complicated.
The first step was to setup apache for it, a little bit more complicated than the usual setup, but possible:
<LocationMatch "/((css|js|img|swf|pdf)/|favicon.ico)">
SetHandler None
</LocationMatch>
The main problem comes when using Django development http server (started by "python manage.py runserver"), and the admin. Of course you can do that, but what is not possible, is to define the same name for your admin media path, and for the admin itself.
For example:
http://localhost/admin and http://localhost/admin/css/login.css
The reason is the Django web server, processes all requests starting with the ADMIN_MEDIA_PREFIX setting with the AdminMediaHandler, what implies with that structure that all admin requests (even the ones that aren't static files) are processed by this handler, raising an error when the request isn't for a static file. The error is next.
Permission denied: ${PYTHON_PATH}/django/contrib/admin/media/
So this is my resignation statement to do what I wanted to do initially. Now, options are:
- Don't use the Django http server (use apache even for development)
- Keep the same structure but change the admin media directory (for example from "admin" to "admin-media"
- Use the "media" (or any other name) prefix
NOTE: Current version of my project DSNP is affected by this issue. I'll solve it asap.
Wednesday, May 7, 2008
New DSNP version
Project (and application) creation in Django are very openend and flexible, but sometimes is useful getting all the work done for you, specially:
- If you create many Django projects with the same structure.
- If you're new to Python, and want to see a "hello world!" application working in less than one minute.
- If you want to check your Django structure with somebody's else (me).
DSNP does exactly that, automates the process of creating projects and applications in Django. The resulting website is a simple project with a single application, ready for start creating models and templates. It's also customizable, to let everyone set their own preferences in the script, and adapt it to your desired structure.
Want to try it (in five simple steps)?
svn checkout http://dsnp.googlecode.com/svn/trunk/
python dsnp.py myproject
cd myproject
python manage.py runserver
Browse http://localhost:8000/
Easy right?
Tuesday, April 29, 2008
Django L10n
Here I'll post some of the ideas of the interview (and some that I missed), for serving as reference:
How to translate your application (quick guide):
- Mark every text in your application for translation:
- In models.py, views.py... convert 'my text in just one language' to _('my text to translate'). Don't forget to import _: from django.utils.translation import ugettext_lazy as _
- In templates, convert <p>Text in english</p> to <p>{% trans 'Text in many languages' %}</p> (also this can be done with blocktrans tag)
- Go to your project path and create a directory called locale (also you can do that just for an application)
- Execute ${PATH_TO_DJANGO}/bin/make-messages -l ${LANGUAGE_CODE} (where language code is en for english, es for spanish...)
- Edit ${PROJECT_PATH}/locale/${LANGUAGE_CODE}/LC_MESSAGES/django.po and set the msgstr variables with the translation of every msgid
- Run msgfmt django.po -o django.mo (I just realized after the interview that exists a django script complie-messages.py that does that for all .po files)
- And then you have your application translated. There are some settings in settings.py that need to be set for making it work (USE_I18N = True, set LANGUAGES and LANGUAGE_CODE, and specify the django.middleware.locale.LocaleMiddleware middleware)
- Then probably you'll want to have your select input with all available languages (or something like that). For it you'll have to add (r'^i18n/', include('django.conf.urls.i18n')) to your urls.py, and from your html send a POST request to /i18n/setlang with the parameter language set to desired language code
- For more stuff, and detailed information check: http://www.djangoproject.com/documentation/i18n/
Things that IMHO should be improved in Django for a better L10n expirience:
- Move localflavors outside trunk (to avoid unnecessary translation costs). Every localflavor should come with necessary translations.
- Create locale settings (besides translations), to set decimal symbol, date and time format, first day of week... and use it automatically for current locale/language.
- Create translatable CharFields and TextFields. For now django-multilingual and transdb can be used for it.
- Adding something to select the language in admin (when more than one is available).
- Haven't checked it too much, but it'll be good if urls could be translated as well.
Finally I want to thank for letting me participate in TWID to Michael Trier, who is a father, husband, software architect, entrepreneur, a great journalist, and a better person. And also to Malcolm Tredinnick, who recommended me to the show (not sure if I deserved the honour), and for his unpayable help and support on my Django work.