Edgewall Software

Changes between Version 98 and Version 99 of GenshiTutorial


Ignore:
Timestamp:
Oct 31, 2007, 6:51:53 AM (16 years ago)
Author:
palgarvio
Comment:

Add the I18n Support to Geddit.

Legend:

Unmodified
Added
Removed
Modified
  • GenshiTutorial

    v98 v99  
    14741474
    14751475
     1476=== Internationalize The Application (I18N) ===
     1477To internationalize our application we'll use [http://babel.edgewall.org Babel].
     1478{{{
     1479easy_install Babel
     1480}}}
     1481
     1482To get the basic info on how to work with message catalog using Babel [http://babel.edgewall.org/wiki/Documentation/0.9/messages.html read this], I'll just follow you through the basic procedures.
     1483
     1484First 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:
     1485{{{
     1486# Extraction from Python source files
     1487
     1488[python: **.py]
     1489
     1490# Extraction from Genshi HTML and text templates
     1491
     1492[genshi: **/templates/**.html
     1493}}}
     1494The 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.
     1495
     1496Now let's extract some messages to be translated:
     1497{{{
     1498pybabel extract -o geddit/locale/geddit.pot -F ./mapping.cfg geddit
     1499}}}
     1500
     1501The output should be similar to:
     1502{{{
     1503extracting messages from geddit/__init__.py
     1504extracting messages from geddit/controller.py
     1505extracting messages from geddit/form.py
     1506extracting messages from geddit/model.py
     1507extracting messages from geddit/translator.py
     1508extracting messages from geddit/lib/__init__.py
     1509extracting messages from geddit/lib/ajax.py
     1510extracting messages from geddit/lib/template.py
     1511extracting messages from geddit/templates/_comment.html
     1512extracting messages from geddit/templates/_form.html
     1513extracting messages from geddit/templates/comment.html
     1514extracting messages from geddit/templates/index.html
     1515extracting messages from geddit/templates/info.html
     1516extracting messages from geddit/templates/layout.html
     1517extracting messages from geddit/templates/submit.html
     1518writing PO template file to geddit/locale/geddit.pot
     1519}}}
     1520
     1521Now let's create the English catalog which normally isn't translated:
     1522{{{
     1523pybabel init -D geddit -i geddit/locale/geddit.pot -d geddit/locale/ -l en
     1524}}}
     1525
     1526And, since I'm Portuguese, we'll create a Portuguese catalog to serve as an example:
     1527{{{
     1528pybabel init -D geddit -i geddit/locale/geddit.pot -d geddit/locale/ -l pt_PT
     1529}}}
     1530On this step you can create a catalog in your mother language if not english so that you can see Geddit translated.
     1531
     1532Edit the contents of the resulting `geddit.po` for the locale you created, translate it, save and exit.
     1533
     1534Next step will involve compiling these catalogs so that they can be used by python's gettext module:
     1535{{{
     1536pybabel compile -D geddit -d geddit/locale/ -f --statistics
     1537}}}
     1538
     1539Now, our Geddit application needs to use and know how to use these translated catalogs.
     1540
     1541Let's modify `geddit/controller.py` with(this is a diff):
     1542{{{
     1543#!diff
     1544Index: geddit/controller.py
     1545===================================================================
     1546--- geddit/controller.py        (revision 766)
     1547+++ geddit/controller.py        (working copy)
     1548@@ -92,8 +92,40 @@
     1549             links = sorted(self.data.values(), key=operator.attrgetter('time'))
     1550             return template.render(links=links)
     1551
     1552+    @cherrypy.expose
     1553+    def set_lang(self, language):
     1554+       import gettext
     1555+       import formencode
     1556+       import __builtin__
     1557+       locale_dir = os.path.join(os.path.dirname(__file__), 'locale')
     1558+       domain = 'geddit'
     1559+       codeset= 'utf-8'
     1560+
     1561+       gettext.bindtextdomain(domain, locale_dir)
     1562+       gettext.textdomain(domain)
     1563+
     1564+       try:
     1565+            translator = gettext.translation(domain,
     1566+                                         locale_dir,
     1567+                                         languages=[language],
     1568+                                         codeset=codeset)
     1569+       except IOError, error:
     1570+            language=['en']
     1571+            translator = gettext.translation(domain,
     1572+                                         locale_dir,
     1573+                                         languages=language,
     1574+                                         codeset=codeset)
     1575+       formencode.api.set_stdtranslation(languages=[language])
     1576+       __builtin__._ = translator.ugettext
     1577+       raise cherrypy.HTTPRedirect('/')
     1578+
     1579+
     1580
     1581 def main(filename):
     1582+    import __builtin__
     1583+    from gettext import NullTranslations
     1584+
     1585+    __builtin__._ = NullTranslations().ugettext
     1586     # load data from the pickle file, or initialize it to an empty list
     1587     if os.path.exists(filename):
     1588         fileobj = open(filename, 'rb')
     1589}}}
     1590
     1591Our `geddit/lib/template.py` with(also diff):
     1592{{{
     1593!#diff
     1594Index: geddit/lib/template.py
     1595===================================================================
     1596--- geddit/lib/template.py      (revision 766)
     1597+++ geddit/lib/template.py      (working copy)
     1598@@ -4,6 +4,7 @@
     1599 from genshi.core import Stream
     1600 from genshi.output import encode, get_serializer
     1601 from genshi.template import Context, TemplateLoader
     1602+from genshi.filters import Translator
     1603
     1604 from geddit.lib import ajax
     1605
     1606@@ -42,6 +43,7 @@
     1607         template = loader.load(args[0])
     1608     else:
     1609         template = cherrypy.thread_data.template
     1610+    template.filters.insert(0, Translator(_))
     1611     ctxt = Context(url=cherrypy.url)
     1612     ctxt.push(kwargs)
     1613     return template.generate(ctxt)
     1614}}}
     1615
     1616And finaly our `geddit/templates/layout.html` with(also diff):
     1617{{{
     1618#!diff
     1619Index: geddit/templates/layout.html
     1620===================================================================
     1621--- geddit/templates/layout.html        (revision 766)
     1622+++ geddit/templates/layout.html        (working copy)
     1623@@ -19,6 +19,16 @@
     1624         <a href="/"><img src="${url('/media/logo.gif')}" width="201" height="79" alt="geddit?" /></a>
     1625       </div>
     1626       <div id="content">
     1627+        <form method="post" id="lang_choose" name="lang_choose" action="${url('/set_lang')}">
     1628+        <label for="language">Language:</label>
     1629+        <select id="language" name="language" onChange="$('#lang_choose').submit()">
     1630+          <option value="en">English</option>
     1631+          <option value="pt_PT">Portuguese</option>
     1632+        </select>
     1633+        </form>
     1634+        <noscript>
     1635+          <input type="submit" name="submit" value="Update"/>
     1636+        </noscript>
     1637         ${select('*|text()')}
     1638       </div>
     1639       <div id="footer">
     1640}}}
     1641
     1642This will allow the user to select the language.
     1643
     1644And that wraps it up!
     1645
    14761646== Summary ==
    14771647
     
    14851655
    14861656 * [wiki:GenshiTutorial/Authentication Add authentication], preferably based on [http://openid.net/ OpenID] ([http://openidenabled.com/python-openid/ Python libraries for OpenID] are available.)
    1487  * [wiki:GenshiTutorial/Internationalization Internationalize the application], using Genshi's builtin [wiki:Documentation/i18n.html I18n support] and [http://babel.edgewall.org/ Babel].
     1657 * [wiki:GenshiTutorial/Internationalization Internationalize the application], using Genshi's builtin [wiki:Documentation/i18n.html I18n support] and [http://babel.edgewall.org/ Babel]. '''DONE'''
    14881658 * [wiki:GenshiTutorial/CsrfProtection Add protection against cross-site request forgery (CSRF) attacks], using the [wiki:Documentation/filters.html#transformer Transformer] filter to inject form tokens in HTML forms.
    14891659 * [wiki:GenshiTutorial/Voting Add voting on links]. See the [http://developer.yahoo.com/ypatterns/pattern.php?pattern=votetopromote Vote to Promote] pattern in Yahoo's “Design Pattern Library” for some inspiration.