Changes between Version 4 and Version 5 of Dev/i18n


Ignore:
Timestamp:
07/28/11 12:19:54 (3 years ago)
Author:
pferreir
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Dev/i18n

    v4 v5  
    55== Writing i18n-aware code == 
    66 
     7=== The basics === 
     8 
     9The basic tool in code i18n is `_()`. In indico, this function is available by default ('''no need to import!''') everywhere. So, the code: 
     10 
     11{{{ 
     12#!python 
     13print _('Fetch the cow') 
     14}}} 
     15 
     16would be displayed as: 
     17 
     18{{{ 
     19Fetchez la vache 
     20}}} 
     21 
     22considering that we had a [wikipedia:Franglais Franglais] dictonary loaded. A dictionary is just a map that associates an "original string" with a "translated string". Every language will have its own dictionary, that is application dependent and had to be loaded beforehand (we will see more below).  
     23 
     24Anyone who has done (web) interface programming before can immediately see some tricky use cases that would not work. For example: 
     25 
     26{{{ 
     27print _('Fetch %d cows' % number) 
     28}}} 
     29 
     30would imply that we have an infinite dictionary. Of course the fix is easy: 
     31 
     32{{{ 
     33print _('Fetch %d cows') % number 
     34}}} 
     35 
     36And both Babel and `msgfmt` can handle format strings, and even warn you whenever the translation does not include the correct characters, etc. 
     37 
     38=== Plurals === 
     39 
     40However, this is not enough. Suppose that 'number = 1'. How do we handle that? We could add an `if` expression and a single translation for "Fetch 1 cow". However, there is an easier/cleaner way: 
     41 
     42{{{ 
     43from indico.util.i18n import ungettext # unicode ngettext 
     44 
     45print ungettext("Fetch %s cow", "Fetch %s cows", number) % number 
     46 
     47}}} 
     48 
     49You might be asking why we do not simply do: 
     50 
     51{{{ 
     52print "%s %s %s" % (_("Fetch"), number, ungettext("cow", "cows", number))  
     53}}} 
     54 
     55The answer is: we should '''never''' make any assumptions about the order of word in a sentence. If in English it is generally true that the verb comes before the object, for other languages that may not be right. That's why it's better to spend some more characters and translate the whole sentence - like this, translators won't see themselves limited by the assumptions you've done in your code. 
     56 
     57=== Dates/Times === 
     58 
     59=== Others === 
     60 
     61=== Common mistakes === 
    762It's very hard to write/maintain an application that is 100% internationalized, since this requires a great deal of coordination not only with the translators, but between developers as well. Not only people usually forget to properly internationalize strings, but also when they remember to do so they choose to do it at the wrong place. Here are some examples of some good/bad practices. 
    863 
     
    2782Why is this wrong? Class attributes are initialized only once, '''at module load time'''. So, since modules are normally only loaded once '''per process''', a French user that is using this app will ''theoretically'' (see paragraph below) get the same translation as a Japanese one. The '''right way''' to do so would be delaying translation till the template is rendered: we could have a dictionary of "English" strings and then just call `_()` from the piece of template (or other i18n-safe code) that calls `getUserType`. 
    2883 
    29 Fortunately our current i18n code supports Lazy translation (meaning that it replaces the result string with a proxy object that will only execute the translation when it is asked for its string value), and the situation above would not be problematic. However, it '''not at all good practice''' and should be '''avoided'''. 
     84Fortunately our current i18n code supports (thanks to Babel) "lazy translation" (meaning that it replaces the result string with a proxy object that will only execute the translation when it is asked for its string value), and the situation above would not be problematic. However, it '''not at all good practice''' and should be '''avoided'''. 
    3085 
    3186Another classic mistake is: 
     
    4499 
    45100This one should be easier to spot, if you consider that `Persistent` objects are stored in the database. By translating `position`, we get it in the language that was in use at the time of object creation. The right way to do it is, once again, to translate "as late as possible". 
     101 
     102 
     103== Managing dictionaries ==