diff --git a/genshi/filters/i18n.py b/genshi/filters/i18n.py
--- a/genshi/filters/i18n.py
+++ b/genshi/filters/i18n.py
@@ -17,7 +17,7 @@
 """
 
 from compiler import ast
-from gettext import gettext
+from gettext import NullTranslations
 import re
 
 from genshi.core import Attrs, Namespace, QName, START, END, TEXT, START_NS, \
@@ -35,7 +35,7 @@
     """Can extract and translate localizable strings from markup streams and
     templates.
     
-    For example, assume the followng template:
+    For example, assume the following template:
     
     >>> from genshi.template import MarkupTemplate
     >>> 
@@ -91,7 +91,7 @@
     INCLUDE_ATTRS = frozenset(['abbr', 'alt', 'label', 'prompt', 'standby',
                                'summary', 'title'])
 
-    def __init__(self, translate=gettext, ignore_tags=IGNORE_TAGS,
+    def __init__(self, translator=NullTranslations(), ignore_tags=IGNORE_TAGS,
                  include_attrs=INCLUDE_ATTRS, extract_text=True):
         """Initialize the translator.
         
@@ -103,7 +103,7 @@
                              extracted, or only text in explicit ``gettext``
                              function calls
         """
-        self.translate = translate
+        self.translator = translator
         self.ignore_tags = ignore_tags
         self.include_attrs = include_attrs
         self.extract_text = extract_text
@@ -126,7 +126,12 @@
         """
         ignore_tags = self.ignore_tags
         include_attrs = self.include_attrs
-        translate = self.translate
+        try:
+            # Unicode aware version first
+            gettext = self.translator.ugettext
+        except AttributeError:
+            gettext = self.translator.gettext
+
         if not self.extract_text:
             search_text = False
         skip = 0
@@ -160,7 +165,7 @@
                     newval = value
                     if search_text and isinstance(value, basestring):
                         if name in include_attrs:
-                            newval = self.translate(value)
+                            newval = gettext(value)
                     else:
                         newval = list(self(_ensure(value), ctxt,
                             search_text=False)
@@ -177,8 +182,6 @@
                     continue
                 elif i18n_msg in attrs:
                     params = attrs.get(i18n_msg)
-                    if params and type(params) is list: # event tuple
-                        params = params[0][1]
                     msgbuf = MessageBuffer(params)
                     attrs -= i18n_msg
 
@@ -188,7 +191,7 @@
                 if not msgbuf:
                     text = data.strip()
                     if text:
-                        data = data.replace(text, unicode(translate(text)))
+                        data = data.replace(text, unicode(gettext(text)))
                     yield kind, data, pos
                 else:
                     msgbuf.append(kind, data, pos)
@@ -199,7 +202,7 @@
             elif not skip and msgbuf and kind is END:
                 msgbuf.append(kind, data, pos)
                 if not msgbuf.depth:
-                    for event in msgbuf.translate(translate(msgbuf.format())):
+                    for event in msgbuf.translate(gettext(msgbuf.format())):
                         yield event
                     msgbuf = None
                     yield kind, data, pos
@@ -271,6 +274,7 @@
         skip = 0
         i18n_msg = I18N_NAMESPACE['msg']
         i18n_comment = I18N_NAMESPACE['comment']
+        i18n_choose = I18N_NAMESPACE['choose']
         xml_lang = XML_NAMESPACE['lang']
 
         for kind, data, pos in stream:
@@ -305,8 +309,9 @@
                     msgbuf.append(kind, data, pos)
                 elif i18n_msg in attrs:
                     params = attrs.get(i18n_msg)
-                    if params and type(params) is list: # event tuple
-                        params = params[0][1]
+                    msgbuf = MessageBuffer(params, pos[1])
+                elif i18n_choose in attrs:
+                    params = attrs.get(i18n_choose)
                     msgbuf = MessageBuffer(params, pos[1])
                 if i18n_comment in attrs and msgbuf:
                     msgbuf.comments.append(attrs.get(i18n_comment))
@@ -322,7 +327,12 @@
             elif not skip and msgbuf and kind is END:
                 msgbuf.append(kind, data, pos)
                 if not msgbuf.depth:
-                    yield msgbuf.lineno, None, msgbuf.format(), msgbuf.comments
+                    if msgbuf.singular or msgbuf.plural:
+                         yield msgbuf.lineno, 'ngettext', msgbuf.format(), \
+                                                                msgbuf.comments
+                    else:
+                        yield msgbuf.lineno, None, msgbuf.format(), \
+                                                                msgbuf.comments
                     msgbuf = None
 
             elif kind is EXPR or kind is EXEC:
@@ -340,7 +350,7 @@
                 for lineno, funcname, text, comments in messages:
                     yield lineno, funcname, text, comments
 
-
+    
 class MessageBuffer(object):
     """Helper class for managing internationalized mixed content.
     
@@ -355,15 +365,36 @@
         :param lineno: the line number on which the first stream event
                        belonging to the message was found
         """
-        self.params = [name.strip() for name in params.split(',')]
+        if isinstance(params, (list, tuple)):
+            self.params = []
+            for entry in params:
+                if entry[0] == 'TEXT':
+                    for param in entry[1].split(','):
+                        if param:
+                            self.params.append(param.strip())
+                elif entry[0] == 'EXPR':
+                    self.choose_numeral = entry[1]
+        else:
+            self.params = params
+        self.singular_params = self.params[:]
+        self.plural_params = self.params[:]
         self.lineno = lineno
         self.string = []
+        self.singular = []
+        self.plural = []
         self.events = {}
         self.values = {}
+        self.singular_values = {}
+        self.plural_values = {}
         self.depth = 1
         self.order = 1
+        self.choose_order = 1
         self.stack = [0]
         self.comments = []
+        self.i18n_choose_singular = I18N_NAMESPACE['singular']
+        self.i18n_choose_plural = I18N_NAMESPACE['plural']
+        self.choose_singular = False
+        self.choose_plural = False
 
     def append(self, kind, data, pos):
         """Append a stream event to the buffer.
@@ -373,31 +404,72 @@
         :param pos: the position of the event in the source
         """
         if kind is TEXT:
-            self.string.append(data)
+            if self.choose_singular:
+                self.singular.append(data)
+            if self.choose_plural:
+                self.plural.append(data)
+            else:
+                self.string.append(data)
             self.events.setdefault(self.stack[-1], []).append(None)
         elif kind is EXPR:
-            param = self.params.pop(0)
-            self.string.append('%%(%s)s' % param)
+            if self.choose_singular:
+                param = self.singular_params.pop(0)
+                self.singular.append('%%(%s)s' % param)
+                self.singular_values[param] = (kind, data, pos)         
+            elif self.choose_plural:
+                param = self.plural_params.pop(0)
+                self.plural.append('%%(%s)s' % param)
+                self.plural_values[param] = (kind, data, pos)
+            else:
+                param = self.params.pop(0)
+                self.string.append('%%(%s)s' % param)
+                self.values[param] = (kind, data, pos)
             self.events.setdefault(self.stack[-1], []).append(None)
-            self.values[param] = (kind, data, pos)
         else:
             if kind is START:
-                self.string.append(u'[%d:' % self.order)
+                if self.choose_singular:
+                    self.ordered_singular = True
+                    self.singular.append(u'[%d:' % self.choose_order)
+                elif self.choose_plural:
+                    self.ordered_plural = True
+                    self.plural.append(u'[%d:' % self.choose_order)
+                    self.choose_order += 1
+                elif self.i18n_choose_singular in data[1]:
+                    self.choose_singular = True
+                    self.choose_plural = False
+                elif self.i18n_choose_plural in data[1]:
+                    self.choose_plural = True
+                    self.choose_singular = False
+                else:
+                    self.string.append(u'[%d:' % self.order)
+                    self.order += 1
                 self.events.setdefault(self.order, []).append((kind, data, pos))
                 self.stack.append(self.order)
                 self.depth += 1
-                self.order += 1
             elif kind is END:
                 self.depth -= 1
                 if self.depth:
+                    if self.choose_singular:
+                        self.choose_singular = False
+                        if self.choose_order > 1:
+                            self.singular.append(u']')
+                            self.ordered_singular = False
+                    elif self.choose_plural:
+                        self.choose_plural = False
+                        if self.choose_order > 1:
+                            self.plural.append(u']')
+                    else:                        
+                        self.string.append(u']')
                     self.events[self.stack[-1]].append((kind, data, pos))
-                    self.string.append(u']')
                     self.stack.pop()
 
     def format(self):
         """Return a message identifier representing the content in the
         buffer.
         """
+        if self.singular or self.plural:
+            return (u''.join(self.singular).strip(),
+                    u''.join(self.plural).strip())
         return u''.join(self.string).strip()
 
     def translate(self, string, regex=re.compile(r'%\((\w+)\)s')):
