diff --git a/genshi/filters/i18n.py b/genshi/filters/i18n.py
--- a/genshi/filters/i18n.py
+++ b/genshi/filters/i18n.py
@@ -22,7 +22,7 @@
 
 from genshi.core import Attrs, Namespace, QName, START, END, TEXT, START_NS, \
                         END_NS, XML_NAMESPACE, _ensure
-from genshi.template.base import Template, EXPR, SUB
+from genshi.template.base import Template, Context, EXPR, SUB, INCLUDE
 from genshi.template.markup import MarkupTemplate, EXEC
 
 __all__ = ['Translator', 'extract']
@@ -107,6 +107,7 @@
         self.ignore_tags = ignore_tags
         self.include_attrs = include_attrs
         self.extract_text = extract_text
+        self.i18n_domains = []
 
     def __call__(self, stream, ctxt=None, search_text=True, msgbuf=None):
         """Translate any localizable strings in the given stream.
@@ -128,14 +129,27 @@
         include_attrs = self.include_attrs
         ugettext = self.translator.ugettext
         ungettext = self.translator.ungettext
+        try:
+            dugettext = self.translator.dugettext
+            dungettext = self.translator.dungettext
+        except AttributeError:
+            # No domain support, show a warning???
+            dugettext = lambda d, s: ugettext(s)
+            dungettext = lambda d, s, p, n: ungettext(s, p, n)
 
         if not self.extract_text:
             search_text = False
         skip = 0
         i18n_msg = I18N_NAMESPACE['msg']
         i18n_choose = I18N_NAMESPACE['choose']
+        i18n_domain = I18N_NAMESPACE['domain']
         ns_prefixes = []
         xml_lang = XML_NAMESPACE['lang']
+        
+        if not ctxt:
+            ctxt = Context()
+                    
+        i18n_domains = ctxt.get('i18n_domains', [])
 
         for kind, data, pos in stream:
 
@@ -151,23 +165,32 @@
             # handle different events that can be localized
             if kind is START:
                 tag, attrs = data
+
+                if i18n_domain in attrs:
+                    i18n_domains.append((tag, attrs.get(i18n_domain).strip()))
+                    attrs -= i18n_domain
+                    
                 if tag in self.ignore_tags or \
                         isinstance(attrs.get(xml_lang), basestring):
                     skip += 1
                     yield kind, data, pos
                     continue
-
+                    
                 new_attrs = []
                 changed = False
                 for name, value in attrs:
                     newval = value
                     if search_text and isinstance(value, basestring):
                         if name in include_attrs:
-                            newval = ugettext(value)
+                            if i18n_domains:
+                                newval = dugettext(i18n_domains[-1][1], value)
+                            else:
+                                newval = ugettext(value)
                     else:
+                        # Update context with current domains
+                        ctxt['i18n_domains'] = i18n_domains
                         newval = list(self(_ensure(value), ctxt,
-                            search_text=False)
-                        )
+                                           search_text=False))
                     if newval != value:
                         value = newval
                         changed = True
@@ -185,7 +208,7 @@
                 elif i18n_choose in attrs:
                     params = attrs.get(i18n_choose)
                     msgbuf = MessageBuffer(params)
-                    attrs -= i18n_choose                    
+                    attrs -= i18n_choose
 
                 yield kind, (tag, attrs), pos
 
@@ -193,7 +216,11 @@
                 if not msgbuf:
                     text = data.strip()
                     if text:
-                        data = data.replace(text, unicode(ugettext(text)))
+                        if i18n_domains:
+                            data = data.replace(text,
+                                unicode(dugettext(i18n_domains[-1][1], text)))
+                        else:
+                            data = data.replace(text, unicode(ugettext(text)))
                     yield kind, data, pos
                 else:
                     msgbuf.append(kind, data, pos)
@@ -206,17 +233,28 @@
                 if not msgbuf.depth:
                     if msgbuf.singular or msgbuf.plural:
                         singular, plural, expr = msgbuf.format()
-                        events = ungettext(singular, plural,
-                                           expr.evaluate(ctxt))
+                        if i18n_domains:
+                            events = dungettext(i18n_domains[-1][1],
+                                                singular, plural,
+                                                expr.evaluate(ctxt))
+                        else:
+                            events = ungettext(singular, plural,
+                                               expr.evaluate(ctxt))
                     else:
-                        events = ugettext(msgbuf.format())
+                        if i18n_domains:
+                            events = dugettext(i18n_domains[-1][1],
+                                               msgbuf.format())
+                        else:
+                            events = ugettext(msgbuf.format())
                     for event in msgbuf.translate(events):
                         yield event
                     msgbuf = None
                     yield kind, data, pos
-
+                    
             elif kind is SUB:
                 subkind, substream = data
+                # Update context with current domains
+                ctxt['i18n_domains'] = i18n_domains
                 new_substream = list(self(substream, ctxt, msgbuf=msgbuf))
                 yield kind, (subkind, new_substream), pos
 
@@ -225,9 +263,13 @@
 
             elif kind is END_NS and data in ns_prefixes:
                 ns_prefixes.remove(data)
-
             else:
                 yield kind, data, pos
+                
+            if kind is END and i18n_domains and i18n_domains[-1][1] == data:
+                i18n_domains.pop()
+                # Update context with current domains
+                ctxt['i18n_domains'] = i18n_domains
 
     GETTEXT_FUNCTIONS = ('_', 'gettext', 'ngettext', 'dgettext', 'dngettext',
                          'ugettext', 'ungettext')
diff --git a/genshi/template/base.py b/genshi/template/base.py
--- a/genshi/template/base.py
+++ b/genshi/template/base.py
@@ -560,6 +560,7 @@
         template files.
         """
         from genshi.template.loader import TemplateNotFound
+        from genshi.filters.i18n import Translator
 
         for event in stream:
             if event[0] is INCLUDE:

