diff -Nur a/itota-trac-subtickets-plugin-cb202be/setup.cfg b/itota-trac-subtickets-plugin-cb202be/setup.cfg
--- a/itota-trac-subtickets-plugin-cb202be/setup.cfg	2010-04-11 18:10:44.000000000 +0200
+++ b/itota-trac-subtickets-plugin-cb202be/setup.cfg	2010-05-04 01:26:30.000000000 +0200
@@ -1,3 +1,24 @@
 [egg_info]
 tag_build = .dev
 tag_date = True
+
+[extract_messages]
+add_comments = TRANSLATOR:
+msgid_bugs_address = hoff.st@web.de
+output_file = tracsubtickets/locale/messages.pot
+keywords = _ ngettext:1,2 N_ tag_
+width = 72
+
+[init_catalog]
+input_file = tracsubtickets/locale/messages.pot
+output_dir = tracsubtickets/locale
+domain = tracsubtickets
+
+[compile_catalog]
+directory = tracsubtickets/locale
+domain = tracsubtickets
+
+[update_catalog]
+input_file = tracsubtickets/locale/messages.pot
+output_dir = tracsubtickets/locale
+domain = tracsubtickets
diff -Nur a/itota-trac-subtickets-plugin-cb202be/setup.py b/itota-trac-subtickets-plugin-cb202be/setup.py
--- a/itota-trac-subtickets-plugin-cb202be/setup.py	2010-04-11 18:10:44.000000000 +0200
+++ b/itota-trac-subtickets-plugin-cb202be/setup.py	2010-05-09 22:44:51.000000000 +0200
@@ -1,6 +1,7 @@
 #!/usr/bin/python
 #
 # Copyright (c) 2010, Takashi Ito
+# i18n and German translation by Steffen Hoffmann
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,20 +32,30 @@
 
 setup(
     name = 'TracSubTicketsPlugin',
-    version = '0.1.0',
+    version = '0.1.1',
     keywords = 'trac plugin ticket subticket',
     author = 'Takashi Ito',
     author_email = 'TakashiC.Ito@gmail.com',
     url = 'http://github.com/itota/trac-subtickets-plugin',
     description = 'Trac Sub-Tickets Plugin',
+    long_description = """
+    This plugin for Trac 0.12 provides Sub-Tickets functionality.
+
+    The association is done by adding parent tickets number to a custom field.
+    Checks ensure i.e. resolving of sub-tickets before closing the parent.
+    Babel is required to display localized texts.
+    Currently only translation for de_DE is provided.
+    """
     license = 'BSD',
 
-    install_requires = ['Trac'],
+    install_requires = ['Trac >= 0.12dev'],
 
     packages = find_packages(exclude=['*.tests*']),
     package_data = {
         'tracsubtickets': [
             'htdocs/css/*.css',
+            'locale/*.*',
+            'locale/*/LC_MESSAGES/*.*',
         ],
     },
     entry_points = {
@@ -57,4 +68,3 @@
         ],
     },
 )
-
diff -Nur a/itota-trac-subtickets-plugin-cb202be/tracsubtickets/api.py b/itota-trac-subtickets-plugin-cb202be/tracsubtickets/api.py
--- a/itota-trac-subtickets-plugin-cb202be/tracsubtickets/api.py	2010-04-11 18:10:44.000000000 +0200
+++ b/itota-trac-subtickets-plugin-cb202be/tracsubtickets/api.py	2010-05-04 00:12:04.000000000 +0200
@@ -29,17 +29,27 @@
 
 import re
 
+import pkg_resources
+
 from trac.core import *
 from trac.env import IEnvironmentSetupParticipant
 from trac.db import DatabaseManager
 from trac.ticket.model import Ticket
 from trac.ticket.api import ITicketChangeListener, ITicketManipulator
 
+from trac.util.translation import domain_functions
+
+
 import db_default
 
 
 NUMBERS_RE = re.compile(r'\d+', re.U)
 
+# i18n support for plugins, available since Trac r7705
+# use _, tag_ and N_ as usual, e.g. _("this is a message text")
+_, tag_, N_, add_domain = domain_functions('tracsubtickets', 
+    '_', 'tag_', 'N_', 'add_domain')
+
 
 class SubTicketsSystem(Component):
 
@@ -47,6 +57,13 @@
                ITicketChangeListener,
                ITicketManipulator)
 
+    def __init__(self):
+        self._version = None
+        self.ui = None
+        # bind the 'traccsubtickets' catalog to the locale directory
+        locale_dir = pkg_resources.resource_filename(__name__, 'locale')
+        add_domain(self.env.path, locale_dir)
+
     # IEnvironmentSetupParticipant methods
     def environment_created(self):
         self.found_db_version = 0
@@ -159,13 +176,13 @@
             myid = str(ticket.id)
             for id in _ids:
                 if id == myid:
-                    yield 'parents', 'A ticket cannot be a parent to itself'
+                    yield 'parents', _('A ticket cannot be a parent to itself')
                 else:
                     # check if the id exists
                     cursor.execute("SELECT id FROM ticket WHERE id=%s", (id, ))
                     row = cursor.fetchone()
                     if row is None:
-                        yield 'parents', 'Ticket #%s does not exist' % id
+                        yield 'parents', _('Ticket #%s does not exist') % id
                 ids.append(id)
 
             # circularity check function
@@ -176,7 +193,7 @@
                 for x in [int(x[0]) for x in cursor]:
                     if x in all_parents:
                         error = ' > '.join(['#%s' % n for n in all_parents + [x]])
-                        errors.append(('parents', 'Circularity error: %s' % error))
+                        errors.append(('parents', _('Circularity error: %s') % error))
                     else:
                         errors += _check_parents(x, all_parents)
                 return errors
@@ -185,7 +202,7 @@
                 # check parent ticket state
                 parent = Ticket(self.env, x)
                 if parent and parent['status'] == 'closed':
-                    yield 'parents', 'Parent ticket #%s is closed' % x
+                    yield 'parents', _('Parent ticket #%s is closed') % x
                 else:
                     # check circularity
                     all_parents = ticket.id and [ticket.id] or []
@@ -196,5 +213,5 @@
 
         except Exception, e:
             self.log.error(e)
-            yield 'parents', 'Not a valid list of ticket IDs'
+            yield 'parents', _('Not a valid list of ticket IDs')
 
diff -Nur a/itota-trac-subtickets-plugin-cb202be/tracsubtickets/locale/de_DE/LC_MESSAGES/tracsubtickets.po b/itota-trac-subtickets-plugin-cb202be/tracsubtickets/locale/de_DE/LC_MESSAGES/tracsubtickets.po
--- a/itota-trac-subtickets-plugin-cb202be/tracsubtickets/locale/de_DE/LC_MESSAGES/tracsubtickets.po	1970-01-01 01:00:00.000000000 +0100
+++ b/itota-trac-subtickets-plugin-cb202be/tracsubtickets/locale/de_DE/LC_MESSAGES/tracsubtickets.po	2010-05-09 22:49:45.000000000 +0200
@@ -0,0 +1,61 @@
+# translation of tracsubtickets.po to German
+# German (Germany) translations for TracSubTicketsPlugin.
+# Copyright (C) 2010
+# This file is distributed under the same license as the
+# TracSubTicketsPlugin project.
+#
+# Steffen Hoffmann <hoff.st@web.de>, 2010.
+msgid ""
+msgstr ""
+"Project-Id-Version: TracSubTicketsPlugin 0.1.x\n"
+"Report-Msgid-Bugs-To: hoff.st@web.de\n"
+"POT-Creation-Date: 2010-05-04 01:38+0200\n"
+"PO-Revision-Date: 2010-05-04 01:48+0200\n"
+"Last-Translator: Steffen Hoffmann <hoff.st@web.de>\n"
+"Language-Team: German de_DE <trac-dev@googlegroups.com>\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 1.0dev-r482\n"
+
+#: tracsubtickets/api.py:179
+msgid "A ticket cannot be a parent to itself"
+msgstr "Ein Ticket kann nicht sein eigener Vorläufer sein"
+
+#: tracsubtickets/api.py:185
+#, python-format
+msgid "Ticket #%s does not exist"
+msgstr "Ticket #%s ist nicht vorhanden"
+
+#: tracsubtickets/api.py:196
+#, python-format
+msgid "Circularity error: %s"
+msgstr "Zirkelbezug: %s"
+
+#: tracsubtickets/api.py:205 tracsubtickets/web_ui.py:129
+#, python-format
+msgid "Parent ticket #%s is closed"
+msgstr "Das Vorgänger-Ticket #%s ist geschossen"
+
+#: tracsubtickets/api.py:216
+msgid "Not a valid list of ticket IDs"
+msgstr "Keine gültige Liste von Ticket-IDs"
+
+#: tracsubtickets/web_ui.py:123
+#, python-format
+msgid "Child ticket #%s has not been closed yet"
+msgstr "Folge-Ticket #%s wurde bisher noch nicht geschlossen"
+
+#: tracsubtickets/web_ui.py:141
+msgid "add"
+msgstr "hinzufügen"
+
+#: tracsubtickets/web_ui.py:143
+msgid "Create new child ticket"
+msgstr "Neues Folge-Ticket erstellen"
+
+#: tracsubtickets/web_ui.py:147
+msgid "Subtickets "
+msgstr "Folge-Tickets "
+
diff -Nur a/itota-trac-subtickets-plugin-cb202be/tracsubtickets/locale/messages.pot b/itota-trac-subtickets-plugin-cb202be/tracsubtickets/locale/messages.pot
--- a/itota-trac-subtickets-plugin-cb202be/tracsubtickets/locale/messages.pot	1970-01-01 01:00:00.000000000 +0100
+++ b/itota-trac-subtickets-plugin-cb202be/tracsubtickets/locale/messages.pot	2010-05-09 22:51:39.000000000 +0200
@@ -0,0 +1,60 @@
+# Translations template for TracSubTicketsPlugin.
+# Copyright (C) 2010 ORGANIZATION
+# This file is distributed under the same license as the
+# TracSubTicketsPlugin project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: TracSubTicketsPlugin 0.1.x\n"
+"Report-Msgid-Bugs-To: hoff.st@web.de\n"
+"POT-Creation-Date: 2010-05-04 01:38+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <trac-dev@googlegroups.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 1.0dev-r482\n"
+
+#: tracsubtickets/api.py:179
+msgid "A ticket cannot be a parent to itself"
+msgstr ""
+
+#: tracsubtickets/api.py:185
+#, python-format
+msgid "Ticket #%s does not exist"
+msgstr ""
+
+#: tracsubtickets/api.py:196
+#, python-format
+msgid "Circularity error: %s"
+msgstr ""
+
+#: tracsubtickets/api.py:205 tracsubtickets/web_ui.py:129
+#, python-format
+msgid "Parent ticket #%s is closed"
+msgstr ""
+
+#: tracsubtickets/api.py:216
+msgid "Not a valid list of ticket IDs"
+msgstr ""
+
+#: tracsubtickets/web_ui.py:123
+#, python-format
+msgid "Child ticket #%s has not been closed yet"
+msgstr ""
+
+#: tracsubtickets/web_ui.py:141
+msgid "add"
+msgstr ""
+
+#: tracsubtickets/web_ui.py:143
+msgid "Create new child ticket"
+msgstr ""
+
+#: tracsubtickets/web_ui.py:147
+msgid "Subtickets "
+msgstr ""
+
diff -Nur a/itota-trac-subtickets-plugin-cb202be/tracsubtickets/web_ui.py b/itota-trac-subtickets-plugin-cb202be/tracsubtickets/web_ui.py
--- a/itota-trac-subtickets-plugin-cb202be/tracsubtickets/web_ui.py	2010-04-11 18:10:44.000000000 +0200
+++ b/itota-trac-subtickets-plugin-cb202be/tracsubtickets/web_ui.py	2010-05-04 01:38:52.000000000 +0200
@@ -35,7 +35,7 @@
 from genshi.builder import tag
 from genshi.filters import Transformer
 
-from api import NUMBERS_RE
+from api import NUMBERS_RE, _
 
 
 class SubTicketsModule(Component):
@@ -120,13 +120,13 @@
 
             for parent, child in cursor:
                 if Ticket(self.env, child)['status'] != 'closed':
-                    yield None, 'Child ticket #%s has not been closed yet' % child
+                    yield None, _('Child ticket #%s has not been closed yet') % child
 
         elif action == 'reopen':
             ids = set(NUMBERS_RE.findall(ticket['parents'] or ''))
             for id in ids:
                 if Ticket(self.env, id)['status'] == 'closed':
-                    yield None, 'Parent ticket #%s is closed' % id
+                    yield None, _('Parent ticket #%s is closed') % id
 
     # ITemplateStreamFilter method
     def filter_stream(self, req, method, filename, stream, data):
@@ -138,11 +138,13 @@
                 # title
                 div = tag.div(class_='description')
                 if ticket['status'] != 'closed':
-                    link = tag.a('add', href=req.href.newticket(parents=ticket.id))
+                    link = tag.a(_('add'),
+                        href=req.href.newticket(parents=ticket.id),
+                        title=_('Create new child ticket'))
                     link = tag.span('(', link, ')', class_='addsubticket')
                 else:
                     link = None
-                div.append(tag.h3('Subtickets ', link))
+                div.append(tag.h3(_('Subtickets '), link))

             if 'subtickets' in data:
                 # table 

