Genshi Tutorial: Adding Internationalization
To internationalize our application we'll use Babel.
easy_install Babel
To get the basic info on how to work with message catalog using Babel read this, I'll just follow you through the basic procedures.
First we'll create a locale directory under geddit which will hold the message catalogs. Next, we'll create a mapping file which will tell Babel how to handle the several type of files. Create a mappings.cfg on the directory above the geddit one and add inside:
# Extraction from Python source files [python: **.py] # Extraction from Genshi HTML and text templates [genshi: **/templates/**.html]
The above will tell Babel that .py files should be handled by the python extractor and that the .html files should be handled by the Genshi extractor.
Now let's extract some messages to be translated:
pybabel extract -o geddit/locale/geddit.pot -F ./mappings.cfg geddit
The output should be similar to:
extracting messages from geddit/__init__.py extracting messages from geddit/controller.py extracting messages from geddit/form.py extracting messages from geddit/model.py extracting messages from geddit/translator.py extracting messages from geddit/lib/__init__.py extracting messages from geddit/lib/ajax.py extracting messages from geddit/lib/template.py extracting messages from geddit/templates/_comment.html extracting messages from geddit/templates/_form.html extracting messages from geddit/templates/comment.html extracting messages from geddit/templates/index.html extracting messages from geddit/templates/info.html extracting messages from geddit/templates/layout.html extracting messages from geddit/templates/submit.html writing PO template file to geddit/locale/geddit.pot
Now let's create the English catalog which normally isn't translated:
pybabel init -D geddit -i geddit/locale/geddit.pot -d geddit/locale/ -l en
And, since I'm Portuguese, we'll create a Portuguese catalog to serve as an example:
pybabel init -D geddit -i geddit/locale/geddit.pot -d geddit/locale/ -l pt_PT
On this step you can create a catalog in your mother language if not english so that you can see Geddit translated.
Edit the contents of the resulting geddit.po for the locale you created, translate it, save and exit.
Next step will involve compiling these catalogs so that they can be used by python's gettext module:
pybabel compile -D geddit -d geddit/locale/ -f --statistics
Now, our Geddit application needs to use and know how to use these translated catalogs.
Let's modify geddit/controller.py with(this is a diff):
-
geddit/controller.py
92 92 links = sorted(self.data.values(), key=operator.attrgetter('time')) 93 93 return template.render(links=links) 94 94 95 @cherrypy.expose 96 def set_lang(self, language): 97 import gettext 98 import formencode 99 import __builtin__ 100 locale_dir = os.path.join(os.path.dirname(__file__), 'locale') 101 domain = 'geddit' 102 codeset= 'utf-8' 103 104 gettext.bindtextdomain(domain, locale_dir) 105 gettext.textdomain(domain) 106 107 try: 108 translator = gettext.translation(domain, 109 locale_dir, 110 languages=[language], 111 codeset=codeset) 112 except IOError, error: 113 language=['en'] 114 translator = gettext.translation(domain, 115 locale_dir, 116 languages=language, 117 codeset=codeset) 118 formencode.api.set_stdtranslation(languages=[language]) 119 __builtin__._ = translator.ugettext 120 raise cherrypy.HTTPRedirect('/') 121 122 95 123 96 124 def main(filename): 125 import __builtin__ 126 from gettext import NullTranslations 127 128 __builtin__._ = NullTranslations().ugettext 97 129 # load data from the pickle file, or initialize it to an empty list 98 130 if os.path.exists(filename): 99 131 fileobj = open(filename, 'rb')
Our geddit/lib/template.py with(also diff):
-
geddit/lib/template.py
4 4 from genshi.core import Stream 5 5 from genshi.output import encode, get_serializer 6 6 from genshi.template import Context, TemplateLoader 7 from genshi.filters import Translator 7 8 8 9 from geddit.lib import ajax 9 10 … … 42 43 template = loader.load(args[0]) 43 44 else: 44 45 template = cherrypy.thread_data.template 46 template.filters.insert(0, Translator(_)) 45 47 ctxt = Context(url=cherrypy.url) 46 48 ctxt.push(kwargs) 47 49 return template.generate(ctxt)
WARNING: there's an error in the above code, please see #238.
And finaly our geddit/templates/layout.html with(also diff):
-
geddit/templates/layout.html
19 19 <a href="/"><img src="${url('/media/logo.gif')}" width="201" height="79" alt="geddit?" /></a> 20 20 </div> 21 21 <div id="content"> 22 <form method="post" id="lang_choose" name="lang_choose" action="${url('/set_lang')}"> 23 <label for="language">Language:</label> 24 <select id="language" name="language" onChange="$('#lang_choose').submit()"> 25 <option value="en">English</option> 26 <option value="pt_PT">Portuguese</option> 27 </select> 28 </form> 29 <noscript> 30 <input type="submit" name="submit" value="Update"/> 31 </noscript> 22 32 ${select('*|text()')} 23 33 </div> 24 34 <div id="footer">
This will allow the user to select the language.
And that wraps it up!
Attachments (1)
-
tutorial07.png
(21.0 KB) -
added by cmlenz 17 years ago.
Move screenshot over, too
Download all attachments as: .zip