[Debian-l10n-commits] r1519 - in /translate-toolkit/branches/upstream/current: ./ tools/ translate/ translate/convert/ translate/doc/user/ translate/lang/ translate/misc/ translate/misc/typecheck/ translate/storage/ translate/storage/placeables/ translate/storage/xml_extract/ translate/tools/

nekral-guest at users.alioth.debian.org nekral-guest at users.alioth.debian.org
Mon Dec 29 14:57:19 UTC 2008


Author: nekral-guest
Date: Mon Dec 29 14:57:18 2008
New Revision: 1519

URL: http://svn.debian.org/wsvn/?sc=1&rev=1519
Log:
[svn-upgrade] Integrating new upstream version, translate-toolkit (1.2.1)

Added:
    translate-toolkit/branches/upstream/current/translate/convert/odf2xliff   (with props)
    translate-toolkit/branches/upstream/current/translate/convert/odf2xliff.py
    translate-toolkit/branches/upstream/current/translate/convert/xliff2odf   (with props)
    translate-toolkit/branches/upstream/current/translate/convert/xliff2odf.py
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-mozilla_l10n_scripts.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-odf2xliff.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-pretranslate.html
    translate-toolkit/branches/upstream/current/translate/lang/bn.py
    translate-toolkit/branches/upstream/current/translate/lang/kn.py
    translate-toolkit/branches/upstream/current/translate/lang/te.py
    translate-toolkit/branches/upstream/current/translate/misc/context.py
    translate-toolkit/branches/upstream/current/translate/misc/contextlib.py
    translate-toolkit/branches/upstream/current/translate/misc/file_discovery.py
    translate-toolkit/branches/upstream/current/translate/misc/rich.py
    translate-toolkit/branches/upstream/current/translate/misc/typecheck/
    translate-toolkit/branches/upstream/current/translate/misc/typecheck/__init__.py
    translate-toolkit/branches/upstream/current/translate/misc/typecheck/doctest_support.py
    translate-toolkit/branches/upstream/current/translate/misc/typecheck/mixins.py
    translate-toolkit/branches/upstream/current/translate/misc/typecheck/sets.py
    translate-toolkit/branches/upstream/current/translate/misc/typecheck/typeclasses.py
    translate-toolkit/branches/upstream/current/translate/storage/odf_io.py
    translate-toolkit/branches/upstream/current/translate/storage/odf_shared.py
    translate-toolkit/branches/upstream/current/translate/storage/placeables/
    translate-toolkit/branches/upstream/current/translate/storage/placeables/__init__.py
    translate-toolkit/branches/upstream/current/translate/storage/placeables/base.py
    translate-toolkit/branches/upstream/current/translate/storage/placeables/lisa.py
    translate-toolkit/branches/upstream/current/translate/storage/placeables/misc.py
    translate-toolkit/branches/upstream/current/translate/storage/placeables/test_lisa.py
    translate-toolkit/branches/upstream/current/translate/storage/xml_extract/
    translate-toolkit/branches/upstream/current/translate/storage/xml_extract/__init__.py
    translate-toolkit/branches/upstream/current/translate/storage/xml_extract/extract.py
    translate-toolkit/branches/upstream/current/translate/storage/xml_extract/generate.py
    translate-toolkit/branches/upstream/current/translate/storage/xml_extract/misc.py
    translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_misc.py
    translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_unit_tree.py
    translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_xpath_breadcrumb.py
    translate-toolkit/branches/upstream/current/translate/storage/xml_extract/unit_tree.py
    translate-toolkit/branches/upstream/current/translate/storage/xml_extract/xpath_breadcrumb.py
    translate-toolkit/branches/upstream/current/translate/storage/xml_name.py
    translate-toolkit/branches/upstream/current/translate/tools/pretranslate   (with props)
    translate-toolkit/branches/upstream/current/translate/tools/pretranslate.py
    translate-toolkit/branches/upstream/current/translate/tools/test_pretranslate.py
Removed:
    translate-toolkit/branches/upstream/current/tools/poen
Modified:
    translate-toolkit/branches/upstream/current/PKG-INFO
    translate-toolkit/branches/upstream/current/setup.py
    translate-toolkit/branches/upstream/current/translate/README
    translate-toolkit/branches/upstream/current/translate/__version__.py
    translate-toolkit/branches/upstream/current/translate/convert/po2html.py
    translate-toolkit/branches/upstream/current/translate/convert/prop2po.py
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-creating_mozilla_pot_files.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-developers.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-formats.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-html2po.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-important_changes.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-index.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-mo.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-moz-l10n-builder.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-moz2po.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-php2po.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-po2tmx.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-podebug.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-poen.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-posegment.html
    translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-poterminology.html
    translate-toolkit/branches/upstream/current/translate/storage/base.py
    translate-toolkit/branches/upstream/current/translate/storage/dtd.py
    translate-toolkit/branches/upstream/current/translate/storage/lisa.py
    translate-toolkit/branches/upstream/current/translate/storage/mo.py
    translate-toolkit/branches/upstream/current/translate/storage/statsdb.py
    translate-toolkit/branches/upstream/current/translate/storage/test_po.py
    translate-toolkit/branches/upstream/current/translate/storage/test_xliff.py
    translate-toolkit/branches/upstream/current/translate/storage/xliff.py
    translate-toolkit/branches/upstream/current/translate/tools/pocount.py
    translate-toolkit/branches/upstream/current/translate/tools/podebug.py
    translate-toolkit/branches/upstream/current/translate/tools/poterminology.py

Modified: translate-toolkit/branches/upstream/current/PKG-INFO
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/PKG-INFO?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/PKG-INFO (original)
+++ translate-toolkit/branches/upstream/current/PKG-INFO Mon Dec 29 14:57:18 2008
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: translate-toolkit
-Version: 1.2.0
+Version: 1.2.1
 Summary: The Translate Toolkit is a Python package that assists in localization of software.
 Home-page: http://translate.sourceforge.net/wiki/toolkit/index
 Author: Translate.org.za

Modified: translate-toolkit/branches/upstream/current/setup.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/setup.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/setup.py (original)
+++ translate-toolkit/branches/upstream/current/setup.py Mon Dec 29 14:57:18 2008
@@ -30,6 +30,7 @@
 initfiles = [(join(sitepackages,'translate'),[join('translate','__init__.py')])]
 
 subpackages = ["convert", "misc", "storage", join("storage", "versioncontrol"), 
+        join("storage", "placeables"), join("storage", "xml_extract"), join("misc", "typecheck"),
         "filters", "tools", "services", "search", join("search", "indexing"), "lang"]
 # TODO: elementtree doesn't work in sdist, fix this
 packages = ["translate"]
@@ -53,6 +54,7 @@
                   ('convert', 'po2tmx'),
                   ('convert', 'po2wordfast'),
                   ('convert', 'csv2tbx'),
+                  ('convert', 'odf2xliff'), ('convert', 'xliff2odf'),
                   ('filters', 'pofilter'),
                   ('tools', 'pocompile'),
                   ('tools', 'poconflicts'),
@@ -65,11 +67,12 @@
                   ('tools', 'poswap'),
                   ('tools', 'poclean'),
                   ('tools', 'poterminology'),
+                  ('tools', 'pretranslate'),          
                   ('services', 'lookupclient.py'),
                   ('services', 'lookupservice')]
 
 translatebashscripts = [apply(join, ('tools', ) + (script, )) for script in [
-                  'pomigrate2', 'poen', 'pocompendium', 
+                  'pomigrate2', 'pocompendium', 
                   'posplit', 'popuretext', 'poreencode', 'pocommentclean'
                   ]]
 

Modified: translate-toolkit/branches/upstream/current/translate/README
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/README?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/README (original)
+++ translate-toolkit/branches/upstream/current/translate/README Mon Dec 29 14:57:18 2008
@@ -76,8 +76,9 @@
 reporting it as a bug.
 
 The package lxml is needed for XML file processing. Version 1.3.4 and upwards 
-should work. Alpha versions of lxml 2.0.0 have been tested.
-http://codespeak.net/lxml/
+should work in most cases, although the odf2xliff and xliff2odf tools
+require at least version 2.0.0 to function correctly. 
+from http://codespeak.net/lxml/
 
 The package lxml has dependencies on libxml2 and libxslt. Please check the lxml
 site for the recommended versions of these libraries.
@@ -90,6 +91,11 @@
 use libgettextpo from the gettext-tools package (it might have a slightly 
 different name on your distribution). This can greatly speed up access to PO 
 files, but has not yet been tested as extensively. Feedback is most welcome.
+
+When the environment variable PYTHONTYPECHECK is defined, the toolkit will
+enable dynamic type checking for certain functions in the toolkit (mostly
+those belonging the ODF-XLIFF code). This adds quite a bit of overhead and
+is only of use to programmers.
 
 Psyco can help to speed up several of the programs in the toolkit. It is
 optional, but highly recommended.
@@ -205,6 +211,8 @@
 csv2tbx  - Create TBX (TermBase eXchange) files from Comma Separated Value (CSV) files
 ini2po   - convert .ini files to to PO
 ical2po  - Convert iCalendar files (*.ics) to PO
+odf2xliff - Extract translatable strings from an ODF file into an XLIFF file
+xliff2odf - Combine an XLIFF file with an ODF template to generate a translated ODF file
 
 * Tools (Quality Assurance)
 pofilter - run any of the 40+ checks on your PO files

Modified: translate-toolkit/branches/upstream/current/translate/__version__.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/__version__.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/__version__.py (original)
+++ translate-toolkit/branches/upstream/current/translate/__version__.py Mon Dec 29 14:57:18 2008
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 """this file contains the version of translate"""
-ver = "1.2.0"
+ver = "1.2.1"
 build = 12001

Added: translate-toolkit/branches/upstream/current/translate/convert/odf2xliff
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/convert/odf2xliff?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/convert/odf2xliff (added)
+++ translate-toolkit/branches/upstream/current/translate/convert/odf2xliff Mon Dec 29 14:57:18 2008
@@ -1,0 +1,35 @@
+#!/usr/bin/env python
+#
+# Copyright 2004 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+"""Extracts localizable strings from OpenDocument files to XLIFF files
+
+Files supported include: 
+- .odt (Wordprocessor documents)
+- .ods (Spreadsheets)
+- .odp (Presentations)
+- .sxw (old OpenOffice.org 1.0 Wordprocessor documents)
+"""
+
+from translate.convert import odf2xliff
+
+if __name__ == '__main__':
+  odf2xliff.main()
+

Propchange: translate-toolkit/branches/upstream/current/translate/convert/odf2xliff
------------------------------------------------------------------------------
    svn:executable = *

Added: translate-toolkit/branches/upstream/current/translate/convert/odf2xliff.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/convert/odf2xliff.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/convert/odf2xliff.py (added)
+++ translate-toolkit/branches/upstream/current/translate/convert/odf2xliff.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,116 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2004-2006 Zuza Software Foundation
+#
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+"""convert OpenDocument (ODF) files to XLIFF localization files
+
+see: http://translate.sourceforge.net/wiki/toolkit/odf2xliff for examples and
+usage instructions.
+"""
+
+# Import from ttk
+from translate.storage import factory
+
+from translate.misc.contextlib import contextmanager, nested
+from translate.misc.context import with_
+from translate.storage import odf_io
+
+def convertodf(inputfile, outputfile, templates, engine):
+    """reads in stdin using fromfileclass, converts using convertorclass,
+       writes to stdout
+    """
+
+    # Temporary hack.
+    # inputfile is a Zip file, and needs to be
+    # read and written as a binary file under Windows, but
+    # they isn't initially in binary mode (under Windows);
+    # thus, we have to reopen it as such.
+    inputfile = open(inputfile.name, 'rb')
+
+    def translate_toolkit_implementation(store):
+        import cStringIO
+        import zipfile
+
+        from translate.storage.xml_extract import extract
+        from translate.storage import odf_shared
+
+        contents = odf_io.open_odf(inputfile)
+        for data in contents.values():
+            parse_state = extract.ParseState(odf_shared.no_translate_content_elements, 
+                                             odf_shared.inline_elements)
+            extract.build_store(cStringIO.StringIO(data), store, parse_state)
+    
+    def itools_implementation(store):
+        from itools.handlers import get_handler
+        from itools.gettext.po import encode_source
+        import itools.odf
+
+        filename = getattr(inputfile, 'name', 'unkown')
+        handler = get_handler(filename)
+
+        try:
+            get_units = handler.get_units
+        except AttributeError:
+            message = 'error: the file "%s" could not be processed'
+            raise AttributeError, message % filename
+
+        # Make the XLIFF file
+        for source, context, line in get_units():
+            source = encode_source(source)
+            unit = store.UnitClass(source)
+            store.addunit(unit)
+
+    @contextmanager
+    def store_context():
+        store = factory.getobject(outputfile)
+        yield store
+        store.save()
+
+    def with_block(store):
+        if engine == "toolkit":
+            translate_toolkit_implementation(store)
+        else:
+            itools_implementation(store)
+    
+    with_(store_context(), with_block)
+    return True
+
+
+def main(argv=None):
+    def add_options(parser):
+        parser.add_option("", "--engine", dest="engine", default="toolkit",
+                          type="choice", choices=["toolkit", "itools"],
+                          help="""Choose whether itools (--engine=itools) or the translate toolkit (--engine=toolkit)
+                          should be used as the engine to convert an ODF file to an XLIFF file.""")
+        parser.passthrough = ['engine']
+        return parser
+    
+    from translate.convert import convert
+    formats = {"sxw": ("xlf", convertodf),
+               "odt": ("xlf", convertodf),
+               "ods": ("xlf", convertodf),
+               "odp": ("xlf", convertodf)}
+    parser = convert.ConvertOptionParser(formats, description=__doc__)
+    add_options(parser)
+    parser.run(argv)
+
+if __name__ == '__main__':
+    main()

Modified: translate-toolkit/branches/upstream/current/translate/convert/po2html.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/convert/po2html.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/convert/po2html.py (original)
+++ translate-toolkit/branches/upstream/current/translate/convert/po2html.py Mon Dec 29 14:57:18 2008
@@ -39,8 +39,9 @@
 
 class po2html:
     """po2html can take a po file and generate html. best to give it a template file otherwise will just concat msgstrs"""
-    def __init__(self, wrap=None):
+    def __init__(self, wrap=None, usetidy=None):
         self.wrap = wrap
+        self.tidy = tidy and usetidy
 
     def wrapmessage(self, message):
         """rewraps text as required"""
@@ -83,14 +84,14 @@
                 #   see test_po2html.py in line 67
                 htmlresult = htmlresult.replace(msgid, msgstr, 1)
         htmlresult = htmlresult.encode('utf-8')
-        if tidy:
+        if self.tidy:
             htmlresult = str(tidy.parseString(htmlresult))
         return htmlresult
 
-def converthtml(inputfile, outputfile, templatefile, wrap=None, includefuzzy=False):
+def converthtml(inputfile, outputfile, templatefile, wrap=None, includefuzzy=False, usetidy=True):
     """reads in stdin using fromfileclass, converts using convertorclass, writes to stdout"""
     inputstore = po.pofile(inputfile)
-    convertor = po2html(wrap=wrap)
+    convertor = po2html(wrap=wrap, usetidy=usetidy)
     if templatefile is None:
         outputstring = convertor.convertstore(inputstore, includefuzzy)
     else:
@@ -111,6 +112,10 @@
         parser.add_option("-w", "--wrap", dest="wrap", default=None, type="int",
                 help="set number of columns to wrap html at", metavar="WRAP")
         parser.passthrough.append("wrap")
+    if tidy is not None:
+        parser.add_option("", "--notidy", dest="usetidy", default=True,
+                help="disables the use of HTML tidy", action="store_false")
+        parser.passthrough.append("usetidy")
     parser.add_fuzzy_option()
     parser.run(argv)
 

Modified: translate-toolkit/branches/upstream/current/translate/convert/prop2po.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/convert/prop2po.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/convert/prop2po.py (original)
+++ translate-toolkit/branches/upstream/current/translate/convert/prop2po.py Mon Dec 29 14:57:18 2008
@@ -88,6 +88,8 @@
                 translatedprop = translatedpropfile.locationindex[origprop.name]
                 # Need to check that this comment is not a copy of the developer comments
                 translatedpo = self.convertunit(translatedprop, "translator")
+                if translatedpo is "discard":
+                    continue
             else:
                 translatedpo = None
             # if we have a valid po unit, get the translation and add it...

Added: translate-toolkit/branches/upstream/current/translate/convert/xliff2odf
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/convert/xliff2odf?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/convert/xliff2odf (added)
+++ translate-toolkit/branches/upstream/current/translate/convert/xliff2odf Mon Dec 29 14:57:18 2008
@@ -1,0 +1,37 @@
+#!/usr/bin/env python
+#
+# Copyright 2004 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+"""Takes an ODF template file and an XLIFF file containing translations of
+strings in the ODF template. It creates a new ODF file using the translations
+of the XLIFF file.
+
+Files supported include: 
+- .odt (Wordprocessor documents)
+- .ods (Spreadsheets)
+- .odp (Presentations)
+- .sxw (old OpenOffice.org 1.0 Wordprocessor documents)
+"""
+
+from translate.convert import xliff2odf
+
+if __name__ == '__main__':
+  xliff2odf.main()
+

Propchange: translate-toolkit/branches/upstream/current/translate/convert/xliff2odf
------------------------------------------------------------------------------
    svn:executable = *

Added: translate-toolkit/branches/upstream/current/translate/convert/xliff2odf.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/convert/xliff2odf.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/convert/xliff2odf.py (added)
+++ translate-toolkit/branches/upstream/current/translate/convert/xliff2odf.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,125 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2004-2006 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+"""convert OpenDocument (ODF) files to Gettext PO localization files
+
+see: http://translate.sourceforge.net/wiki/toolkit/odf2xliff for examples and
+usage instructions.
+"""
+
+import cStringIO
+import zipfile
+import re
+
+import lxml.etree as etree
+
+from translate.storage import factory
+from translate.storage.xml_extract import unit_tree
+from translate.storage.xml_extract import extract
+from translate.storage.xml_extract import generate
+from translate.storage import odf_shared, odf_io
+
+def first_child(unit_node):
+    return unit_node.children.values()[0]
+
+def translate_odf(template, input_file):
+    def load_dom_trees(template):
+        odf_data = odf_io.open_odf(template)
+        return dict((filename, etree.parse(cStringIO.StringIO(data))) for filename, data in odf_data.iteritems())
+    
+    def load_unit_tree(input_file, dom_trees):
+        store = factory.getobject(input_file)
+        tree = unit_tree.build_unit_tree(store)
+
+        def extract_unit_tree(filename, root_dom_element_name):
+            """Find the subtree in 'tree' which corresponds to the data in XML file 'filename'"""
+            def get_tree():
+                try:
+                    return tree.children['office:%s' % root_dom_element_name, 0]
+                except KeyError:
+                    return unit_tree.XPathTree()
+            return (filename, get_tree())
+
+        return dict([extract_unit_tree('content.xml', 'document-content'),
+                     extract_unit_tree('meta.xml',    'document-meta'),
+                     extract_unit_tree('styles.xml',  'document-styles')])
+
+    def translate_dom_trees(unit_trees, dom_trees):
+        make_parse_state = lambda: extract.ParseState(odf_shared.no_translate_content_elements, odf_shared.inline_elements)
+        for filename, dom_tree in dom_trees.iteritems():
+            file_unit_tree = unit_trees[filename]
+            generate.apply_translations(dom_tree.getroot(), file_unit_tree, generate.replace_dom_text(make_parse_state))
+        return dom_trees
+
+    dom_trees = load_dom_trees(template)
+    unit_trees = load_unit_tree(input_file, dom_trees)
+    return translate_dom_trees(unit_trees, dom_trees)
+
+def write_odf(template, output_file, dom_trees):
+
+    def write_content_to_odf(output_zip, dom_trees):
+        for filename, dom_tree in dom_trees.iteritems():
+            output_zip.writestr(filename, etree.tostring(dom_tree, encoding='UTF-8', xml_declaration=True))
+
+    output_zip = odf_io.copy_odf(template, output_file, dom_trees.keys())
+    write_content_to_odf(output_zip, dom_trees)
+
+def convertxliff(input_file, output_file, template):
+    """reads in stdin using fromfileclass, converts using convertorclass, writes to stdout"""
+
+    # Temporary hack.
+    # template and output_file are Zip files, and need to be
+    # read and written as binary files under Windows, but
+    # they aren't initially in binary mode (under Windows);
+    # thus, we have to reopen them as such.
+    template = open(template.name, 'rb')
+    output_file = open(output_file.name, 'wb')
+
+    dom_trees = translate_odf(template, input_file)
+    write_odf(template, output_file, dom_trees)
+    return True
+
+def main(argv=None):
+    from translate.convert import convert
+    formats = {"xlf": ("odt", convertxliff), # Text
+               "xlf": ("ods", convertxliff), # Spreadsheet
+               "xlf": ("odp", convertxliff), # Presentation
+               "xlf": ("odg", convertxliff), # Drawing
+               "xlf": ("odc", convertxliff), # Chart
+               "xlf": ("odf", convertxliff), # Formula
+               "xlf": ("odi", convertxliff), # Image
+               "xlf": ("odm", convertxliff), # Master Document
+               "xlf": ("ott", convertxliff), # Text template
+               "xlf": ("ots", convertxliff), # Spreadsheet template
+               "xlf": ("otp", convertxliff), # Presentation template
+               "xlf": ("otg", convertxliff), # Drawing template
+               "xlf": ("otc", convertxliff), # Chart template
+               "xlf": ("otf", convertxliff), # Formula template
+               "xlf": ("oti", convertxliff), # Image template
+               "xlf": ("oth", convertxliff), # Web page template
+              }
+
+    parser = convert.ConvertOptionParser(formats, usetemplates=True, description=__doc__)
+    parser.run(argv)
+
+if __name__ == '__main__':
+    main()

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-creating_mozilla_pot_files.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-creating_mozilla_pot_files.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-creating_mozilla_pot_files.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-creating_mozilla_pot_files.html Mon Dec 29 14:57:18 2008
@@ -22,63 +22,95 @@
 You can do this two ways:
 </p>
 <ol>
-<li class="level1"><div class="li"> Using Mozilla <acronym title="Concurrent Versions System">CVS</acronym></div>
+<li class="level1"><div class="li"> Using Mozilla source (from <acronym title="Concurrent Versions System">CVS</acronym> or Mercurial)</div>
 </li>
 <li class="level1"><div class="li"> Using an en-US <acronym title="Cross Platform Installer">XPI</acronym> file</div>
 </li>
 </ol>
 
 </div>
-<!-- SECTION "Creating Mozilla POT files" [1-119] -->
+<!-- SECTION "Creating Mozilla POT files" [1-147] -->
+<h2><a name="using_mercurial" id="using_mercurial">Using Mercurial</a></h2>
+<div class="level2">
+
+<p>
+
+Since Firefox 3.1 and Thunderbird 3.0, Mozilla has switched to using Mercurial for version control. See the Mozilla's <a href="https://developer.mozilla.org/En/L10n_on_Mercurial" class="urlextern" title="https://developer.mozilla.org/En/L10n_on_Mercurial">L10n on Mercurial</a> page for instructions on how to checkout and update your Mozilla sources and l10n files.
+</p>
+
+<p>
+You can use <a href="toolkit-mozilla_l10n_scripts.html#get_moz_enus.py" class="wikilink1" title="toolkit-mozilla_l10n_scripts.html">get_moz_enUS.py</a> to extract an en-US directory from the source tree:
+
+</p>
+<pre class="code">get_moz_enUS.py -s mozilla-central/ -d l10n/ -p browser</pre>
+
+<p>
+
+This will move the correct en-US files to <code>l10n/en-US</code>.  You can now create <acronym title="Gettext Portable Object Template">POT</acronym> files as follows:
+
+</p>
+<pre class="code">moz2po -P l10n/en-US l10n/pot</pre>
+
+<p>
+
+This will create the <acronym title="Gettext Portable Object Template">POT</acronym> files in <code>l10n/pot</code> using the American English files from <code>en-US</code>.  You now have a set of <acronym title="Gettext Portable Object Template">POT</acronym> files 
+that you can use for translation or updating your existing <acronym title="Gettext Portable Object">PO</acronym> files.
+</p>
+
+</div>
+<!-- SECTION "Using Mercurial" [148-973] -->
 <h2><a name="using_cvs" id="using_cvs">Using CVS</a></h2>
 <div class="level2">
 
 <p>
 
-Check out files from Mozilla <acronym title="Concurrent Versions System">CVS</acronym>.  If you don't want to checkout all files do:
+Firefox versions before 3.1 and Thunderbird versions before 3.0 still has its source in <acronym title="Concurrent Versions System">CVS</acronym>. Check out files from the Mozilla repository. If you don't want to checkout all files do:
 
 </p>
 <pre class="code">make -f client.mk l10n-checkout</pre>
 
 <p>
 
-The English files are in the mozilla/ module, while the translated files all reside in the l10n/ module.  They have different structure but not enough to kill you.
+The English files are in the <code>mozilla/</code> module, while the translated files all reside in the <code>l10n/</code> module.  They have different structure but not enough to kill you.
 </p>
 
 <p>
-Once you have checked out mozilla/ you will need to get the correct files for en-US.  To do this we will create en-US as a pseudo language.
+Once you have checked out <code>mozilla/</code> you will need to get the correct files for en-US.  To do this we will create en-US as a pseudo language.
 
 </p>
 <pre class="code">make -f tools/l10n/l10n.mk create-en-US</pre>
 
 <p>
 
-This will move the correct en-US files to l10n/en-US.  You can now create <acronym title="Gettext Portable Object Template">POT</acronym> files as follows:
+This will move the correct en-US files to <code>l10n/en-US</code>.  You can now create <acronym title="Gettext Portable Object Template">POT</acronym> files as follows:
 
 </p>
 <pre class="code">moz2po -P l10n/en-US l10n/pot</pre>
 
 <p>
 
-This will create the <acronym title="Gettext Portable Object Template">POT</acronym> files in l10n/pot using the American English files from en-US.  You now have a set of <acronym title="Gettext Portable Object Template">POT</acronym> files 
+This will create the <acronym title="Gettext Portable Object Template">POT</acronym> files in <code>l10n/pot</code> using the American English files from <code>en-US</code>.  You now have a set of <acronym title="Gettext Portable Object Template">POT</acronym> files 
 that you can use for translation or updating your existing <acronym title="Gettext Portable Object">PO</acronym> files.
 </p>
 
 </div>
-<!-- SECTION "Using CVS" [120-928] -->
+<!-- SECTION "Using CVS" [974-1910] -->
 <h2><a name="using_an_en-us_xpi_file" id="using_an_en-us_xpi_file">Using an en-US XPI file</a></h2>
 <div class="level2">
 
 <p>
 
 Download an <acronym title="Cross Platform Installer">XPI</acronym> file and run the following:
+
 </p>
-<pre class="code bash"><pre class="code bash">moz2po -P en-US.xpi pot</pre></pre>
+<pre class="code">moz2po -P en-US.xpi pot</pre>
+
 <p>
-You now have a set of <acronym title="Gettext Portable Object Template">POT</acronym> files in <em>pot</em>.
+
+You now have a set of <acronym title="Gettext Portable Object Template">POT</acronym> files in <code>pot</code>.
 
 </p>
 
 </div>
-<!-- SECTION "Using an en-US XPI file" [929-] --></body>
+<!-- SECTION "Using an en-US XPI file" [1911-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-developers.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-developers.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-developers.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-developers.html Mon Dec 29 14:57:18 2008
@@ -99,10 +99,16 @@
 </li>
 <li class="level1"><div class="li"> tools -- all <acronym title="Gettext Portable Object">PO</acronym> manipulation programs: <a href="toolkit-pocount.html" class="wikilink1" title="toolkit-pocount.html">pocount</a>, <a href="toolkit-pogrep.html" class="wikilink1" title="toolkit-pogrep.html">pogrep</a>, etc</div>
 </li>
-</ul>
-
-</div>
-<!-- SECTION "Source code map" [1592-2199] -->
+<li class="level1"><div class="li"> lang -- modules with data / tweaks for various languages</div>
+</li>
+<li class="level1"><div class="li"> search -- translation memory, terminology matching, and indexing / searching</div>
+</li>
+<li class="level1"><div class="li"> share -- data files</div>
+</li>
+</ul>
+
+</div>
+<!-- SECTION "Source code map" [1592-2364] -->
 <h2><a name="current_source_state" id="current_source_state">Current source state</a></h2>
 <div class="level2">
 
@@ -116,21 +122,12 @@
 		<td class="col0 leftalign"> Development            </td><td class="col1 leftalign"> trunk                           </td>
 	</tr>
 	<tr class="row1">
-		<td class="col0 leftalign"> Current stable branch  </td><td class="col1 leftalign"> trunk (we have not needed to branch     </td>
-	</tr>
-	<tr class="row2">
-		<td class="col0"> Previous stable branch </td><td class="col1 leftalign"> wordforge-0-10-branch           </td>
-	</tr>
-	<tr class="row3">
-		<td class="col0"> Previous stable branch </td><td class="col1 leftalign"> wordforge-0-9-branch            </td>
-	</tr>
-	<tr class="row4">
-		<td class="col0"> Previous stable branch </td><td class="col1 leftalign"> translate-toolkit-0-8-branch    </td>
+		<td class="col0 leftalign"> Current stable branch  </td><td class="col1 leftalign"> Pootle-toolkit-1.2     </td>
 	</tr>
 </table>
 
 </div>
-<!-- SECTION "Current source state" [2200-2605] -->
+<!-- SECTION "Current source state" [2365-2571] -->
 <h2><a name="setup" id="setup">Setup</a></h2>
 <div class="level2">
 
@@ -155,7 +152,7 @@
 </p>
 
 </div>
-<!-- SECTION "Setup" [2606-2911] -->
+<!-- SECTION "Setup" [2572-2877] -->
 <h2><a name="general_overview_of_the_programs" id="general_overview_of_the_programs">General overview of the programs</a></h2>
 <div class="level2">
 
@@ -177,7 +174,7 @@
 </p>
 
 </div>
-<!-- SECTION "General overview of the programs" [2912-3245] -->
+<!-- SECTION "General overview of the programs" [2878-3211] -->
 <h3><a name="command_line_options" id="command_line_options">Command line options</a></h3>
 <div class="level3">
 
@@ -187,7 +184,7 @@
 </p>
 
 </div>
-<!-- SECTION "Command line options" [3246-3749] -->
+<!-- SECTION "Command line options" [3212-3715] -->
 <h2><a name="converters" id="converters">Converters</a></h2>
 <div class="level2">
 
@@ -213,7 +210,7 @@
 </p>
 
 </div>
-<!-- SECTION "Converters" [3750-5031] -->
+<!-- SECTION "Converters" [3716-4997] -->
 <h2><a name="tools" id="tools">Tools</a></h2>
 <div class="level2">
 
@@ -227,7 +224,7 @@
 </p>
 
 </div>
-<!-- SECTION "Tools" [5032-5511] -->
+<!-- SECTION "Tools" [4998-5477] -->
 <h2><a name="checks" id="checks">Checks</a></h2>
 <div class="level2">
 
@@ -271,11 +268,11 @@
 
 <p>
 
-The <a href="http://translate.sourceforge.net/doc/api/public/translate.filters-module.html" class="urlextern" title="http://translate.sourceforge.net/doc/api/public/translate.filters-module.html">API documentation</a> is a good start if you want to add a new tests.  To add a new language have a look at a language you understand amongst those already implemented.
-</p>
-
-</div>
-<!-- SECTION "Checks" [5512-6961] -->
+The <a href="http://translate.sourceforge.net/doc/api/translate.filters-module.html" class="urlextern" title="http://translate.sourceforge.net/doc/api/translate.filters-module.html">API documentation</a> is a good start if you want to add a new tests.  To add a new language have a look at a language you understand amongst those already implemented.
+</p>
+
+</div>
+<!-- SECTION "Checks" [5478-6920] -->
 <h2><a name="storage" id="storage">Storage</a></h2>
 <div class="level2">
 
@@ -322,7 +319,7 @@
 </ul>
 
 </div>
-<!-- SECTION "Storage" [6962-8355] -->
+<!-- SECTION "Storage" [6921-8314] -->
 <h3><a name="base_classes" id="base_classes">Base Classes</a></h3>
 <div class="level3">
 
@@ -349,5 +346,5 @@
 </p>
 
 </div>
-<!-- SECTION "Base Classes" [8356-] --></body>
+<!-- SECTION "Base Classes" [8315-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-formats.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-formats.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-formats.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-formats.html Mon Dec 29 14:57:18 2008
@@ -132,15 +132,21 @@
 <ul>
 <li class="level1"><div class="li"> Wordfast: glossary</div>
 </li>
-<li class="level1"><div class="li"> <a href="ftp://ftp.apple.com/developer/Tool_Chest/Localization_Tools/AppleGlot/AppleGlot_3.2_UsersGuide.pdf" class="urlextern" title="ftp://ftp.apple.com/developer/Tool_Chest/Localization_Tools/AppleGlot/AppleGlot_3.2_UsersGuide.pdf">AppleGlot</a> </div>
-<ul>
+<li class="level1"><div class="li"> Apple:</div>
+<ul>
+<li class="level2"><div class="li"> <a href="ftp://ftp.apple.com/developer/Tool_Chest/Localization_Tools/AppleGlot/AppleGlot_3.2_UsersGuide.pdf" class="urlextern" title="ftp://ftp.apple.com/developer/Tool_Chest/Localization_Tools/AppleGlot/AppleGlot_3.2_UsersGuide.pdf">AppleGlot</a> </div>
+</li>
 <li class="level2"><div class="li"> MacOS .strings file localization - Bug <a href="http://bugs.locamotion.org/show_bug.cgi?id=371" class="interwiki iw_bug" title="http://bugs.locamotion.org/show_bug.cgi?id=371">371</a> relates to this.</div>
 </li>
 </ul>
 </li>
-<li class="level1"><div class="li"> Adobe FrameMaker's Maker Interchange Format - <a href="http://help.adobe.com/en_US/FrameMaker/8.0/mif_reference.pdf" class="urlextern" title="http://help.adobe.com/en_US/FrameMaker/8.0/mif_reference.pdf">MIF</a> (See also <a href="http://lino.sourceforge.net/src/100.html" class="urlextern" title="http://lino.sourceforge.net/src/100.html">python-gendoc</a>, and <a href="http://search.cpan.org/~rst/FrameMaker-MifTree-0.075/lib/FrameMaker/MifTree.pm" class="urlextern" title="http://search.cpan.org/~rst/FrameMaker-MifTree-0.075/lib/FrameMaker/MifTree.pm">Perl MIF module</a>)</div>
-</li>
-<li class="level1"><div class="li"> FrameMaker's <a href="http://www.adobe.com/support/downloads/detail.jsp?ftpID=137" class="urlextern" title="http://www.adobe.com/support/downloads/detail.jsp?ftpID=137">Maker Markup Language</a> (<acronym title="Mathematical Markup Language">MML</acronym>)</div>
+<li class="level1"><div class="li"> Adobe:</div>
+<ul>
+<li class="level2"><div class="li"> FrameMaker's Maker Interchange Format - <a href="http://help.adobe.com/en_US/FrameMaker/8.0/mif_reference.pdf" class="urlextern" title="http://help.adobe.com/en_US/FrameMaker/8.0/mif_reference.pdf">MIF</a> (See also <a href="http://lino.sourceforge.net/src/100.html" class="urlextern" title="http://lino.sourceforge.net/src/100.html">python-gendoc</a>, and <a href="http://search.cpan.org/~rst/FrameMaker-MifTree-0.075/lib/FrameMaker/MifTree.pm" class="urlextern" title="http://search.cpan.org/~rst/FrameMaker-MifTree-0.075/lib/FrameMaker/MifTree.pm">Perl MIF module</a>)</div>
+</li>
+<li class="level2"><div class="li"> FrameMaker's <a href="http://www.adobe.com/support/downloads/detail.jsp?ftpID=137" class="urlextern" title="http://www.adobe.com/support/downloads/detail.jsp?ftpID=137">Maker Markup Language</a> (<acronym title="Mathematical Markup Language">MML</acronym>)</div>
+</li>
+</ul>
 </li>
 <li class="level1"><div class="li"> Microsoft</div>
 <ul>
@@ -152,6 +158,8 @@
 </li>
 <li class="level2"><div class="li"> <a href="http://en.wikipedia.org/wiki/XML%20Paper%20Specification" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/XML%20Paper%20Specification">XML Paper Specification</a></div>
 </li>
+<li class="level2"><div class="li"> .NET Resource files (.resx) - Bug <a href="http://bugs.locamotion.org/show_bug.cgi?id=396" class="interwiki iw_bug" title="http://bugs.locamotion.org/show_bug.cgi?id=396">396</a></div>
+</li>
 </ul>
 </li>
 <li class="level1"><div class="li"> <acronym title="Extensible Markup Language">XML</acronym> related</div>
@@ -166,8 +174,6 @@
 </li>
 <li class="level1"><div class="li"> <a href="http://en.wikipedia.org/wiki/Darwin_Information_Typing_Architecture" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/Darwin_Information_Typing_Architecture">DITA</a></div>
 </li>
-<li class="level1"><div class="li"> .NET Resource files (.resx) - Bug <a href="http://bugs.locamotion.org/show_bug.cgi?id=396" class="interwiki iw_bug" title="http://bugs.locamotion.org/show_bug.cgi?id=396">396</a></div>
-</li>
 <li class="level1"><div class="li"> <a href="http://en.wikipedia.org/wiki/PDF" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/PDF">PDF</a> (<a href="http://www.adobe.com/devnet/pdf/pdf_reference.html" class="urlextern" title="http://www.adobe.com/devnet/pdf/pdf_reference.html">spec</a>)</div>
 </li>
 <li class="level1"><div class="li"> <a href="http://en.wikipedia.org/wiki/LaTeX" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/LaTeX">LaTeX</a> - see <a href="http://plastex.sourceforge.net/plastex/index.html" class="urlextern" title="http://plastex.sourceforge.net/plastex/index.html">plasTeX</a>, a Python framework for processing LaTeX documents</div>
@@ -186,12 +192,16 @@
 </li>
 <li class="level2"><div class="li"> <a href="http://en.wikipedia.org/wiki/SubRip" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/SubRip">SubRip</a> .srt</div>
 </li>
-</ul>
-</li>
-</ul>
-
-</div>
-<!-- SECTION "Unsupported formats" [1326-3721] -->
+<li class="level2"><div class="li"> <a href="http://home.gna.org/gaupol/" class="urlextern" title="http://home.gna.org/gaupol/">Gaupol</a> an PyGTK based subtitling tool looks like a good option to get format readers.</div>
+</li>
+</ul>
+</li>
+<li class="level1"><div class="li"> Tcl: .msg files.  <a href="http://www.google.com/codesearch?hl=en&q=show:XvsRBDCljVk:M2kzUbm70Ts:D5EHICz0aaQ&sa=N&ct=rd&cs_p=http://www.scilab.org/download/4.0/scilab-4.0-src.tar.gz&cs_f=scilab-4.0/tcl/scipadsources/msg_files/AddingTranslations.txt" class="urlextern" title="http://www.google.com/codesearch?hl=en&q=show:XvsRBDCljVk:M2kzUbm70Ts:D5EHICz0aaQ&sa=N&ct=rd&cs_p=http://www.scilab.org/download/4.0/scilab-4.0-src.tar.gz&cs_f=scilab-4.0/tcl/scipadsources/msg_files/AddingTranslations.txt">Good documentation</a></div>
+</li>
+</ul>
+
+</div>
+<!-- SECTION "Unsupported formats" [1326-4136] -->
 <h2><a name="unlikely_to_be_supported" id="unlikely_to_be_supported">Unlikely to be supported</a></h2>
 <div class="level2">
 
@@ -206,5 +216,5 @@
 </ul>
 
 </div>
-<!-- SECTION "Unlikely to be supported" [3722-] --></body>
+<!-- SECTION "Unlikely to be supported" [4137-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-html2po.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-html2po.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-html2po.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-html2po.html Mon Dec 29 14:57:18 2008
@@ -124,15 +124,18 @@
 		<td class="col0 leftalign"> -wWRAP, --wrap=WRAP  </td><td class="col1 leftalign"> set number of columns to wrap html at  </td>
 	</tr>
 	<tr class="row11">
+		<td class="col0 leftalign"> --notidy             </td><td class="col1"> don't use tidy to clean up <acronym title="HyperText Markup Language">HTML</acronym>, even if installed (new in version 1.2.1) </td>
+	</tr>
+	<tr class="row12">
 		<td class="col0 leftalign"> --fuzzy              </td><td class="col1 leftalign"> use translations marked fuzzy   </td>
 	</tr>
-	<tr class="row12">
+	<tr class="row13">
 		<td class="col0 leftalign"> --nofuzzy            </td><td class="col1 leftalign"> don't use translations marked fuzzy (default)   </td>
 	</tr>
 </table>
 
 </div>
-<!-- SECTION "Usage" [90-2309] -->
+<!-- SECTION "Usage" [90-2410] -->
 <h2><a name="examples" id="examples">Examples</a></h2>
 <div class="level2">
 <pre class="code">html2po -P site pot</pre>
@@ -150,7 +153,7 @@
 </p>
 
 </div>
-<!-- SECTION "Examples" [2310-2661] -->
+<!-- SECTION "Examples" [2411-2762] -->
 <h2><a name="bugs" id="bugs">Bugs</a></h2>
 <div class="level2">
 
@@ -175,5 +178,5 @@
 </p>
 
 </div>
-<!-- SECTION "Bugs" [2662-] --></body>
+<!-- SECTION "Bugs" [2763-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-important_changes.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-important_changes.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-important_changes.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-important_changes.html Mon Dec 29 14:57:18 2008
@@ -32,8 +32,17 @@
 This section describes the changes in the (unreleased) development files. It should reflect upcoming changes in the next version of the toolkit and latest <a href="http://translate.sourceforge.net/snapshots/" class="urlextern" title="http://translate.sourceforge.net/snapshots/">beta or rc release</a>.
 </p>
 
-</div>
-<!-- SECTION "trunk" [287-528] -->
+<p>
+(none yet)
+</p>
+
+</div>
+<!-- SECTION "trunk" [287-540] -->
+<h2><a name="section" id="section">1.2</a></h2>
+<div class="level2">
+
+</div>
+<!-- SECTION "1.2" [541-557] -->
 <h3><a name="new_formats" id="new_formats">New formats</a></h3>
 <div class="level3">
 
@@ -55,7 +64,7 @@
 </p>
 
 </div>
-<!-- SECTION "New formats" [529-892] -->
+<!-- SECTION "New formats" [558-921] -->
 <h3><a name="stats_database_change" id="stats_database_change">Stats database change</a></h3>
 <div class="level3">
 
@@ -64,7 +73,7 @@
 </p>
 
 </div>
-<!-- SECTION "Stats database change" [893-1248] -->
+<!-- SECTION "Stats database change" [922-1277] -->
 <h3><a name="valid_accelerators" id="valid_accelerators">Valid accelerators</a></h3>
 <div class="level3">
 
@@ -74,7 +83,7 @@
 </p>
 
 </div>
-<!-- SECTION "Valid accelerators" [1249-1759] -->
+<!-- SECTION "Valid accelerators" [1278-1788] -->
 <h2><a name="branches" id="branches">branches</a></h2>
 <div class="level2">
 
@@ -84,7 +93,7 @@
 </p>
 
 </div>
-<!-- SECTION "branches" [1760-1936] -->
+<!-- SECTION "branches" [1789-1965] -->
 <h3><a name="toolkit-c-po" id="toolkit-c-po">toolkit-C-po</a></h3>
 <div class="level3">
 
@@ -94,12 +103,12 @@
 </p>
 
 </div>
-<!-- SECTION "toolkit-C-po" [1937-2375] -->
-<h2><a name="section" id="section">1.1.1</a></h2>
-<div class="level2">
-
-</div>
-<!-- SECTION "1.1.1" [2376-2394] -->
+<!-- SECTION "toolkit-C-po" [1966-2404] -->
+<h2><a name="section1" id="section1">1.1.1</a></h2>
+<div class="level2">
+
+</div>
+<!-- SECTION "1.1.1" [2405-2423] -->
 <h3><a name="premature_termination_of_dtd_entities" id="premature_termination_of_dtd_entities">Premature termination of DTD entities</a></h3>
 <div class="level3">
 
@@ -113,12 +122,12 @@
 </p>
 
 </div>
-<!-- SECTION "Premature termination of DTD entities" [2395-2900] -->
-<h2><a name="section1" id="section1">1.1</a></h2>
-<div class="level2">
-
-</div>
-<!-- SECTION "1.1" [2901-2918] -->
+<!-- SECTION "Premature termination of DTD entities" [2424-2929] -->
+<h2><a name="section2" id="section2">1.1</a></h2>
+<div class="level2">
+
+</div>
+<!-- SECTION "1.1" [2930-2947] -->
 <h3><a name="oo2po_help_helpcontent2_escaping_fixed" id="oo2po_help_helpcontent2_escaping_fixed">oo2po Help (helpcontent2) escaping fixed</a></h3>
 <div class="level3">
 
@@ -152,7 +161,7 @@
 </p>
 
 </div>
-<!-- SECTION "oo2po Help (helpcontent2) escaping fixed" [2919-4168] -->
+<!-- SECTION "oo2po Help (helpcontent2) escaping fixed" [2948-4197] -->
 <h3><a name="prop2po_uses_developer_comments" id="prop2po_uses_developer_comments">prop2po uses developer comments</a></h3>
 <div class="level3">
 
@@ -166,7 +175,7 @@
 </p>
 
 </div>
-<!-- SECTION "prop2po uses developer comments" [4169-4826] -->
+<!-- SECTION "prop2po uses developer comments" [4198-4855] -->
 <h3><a name="moz2po_no_longer_uses_kde_comments" id="moz2po_no_longer_uses_kde_comments">moz2po no longer uses KDE comments</a></h3>
 <div class="level3">
 
@@ -184,7 +193,7 @@
 </p>
 
 </div>
-<!-- SECTION "moz2po no longer uses KDE comments" [4827-6012] -->
+<!-- SECTION "moz2po no longer uses KDE comments" [4856-6041] -->
 <h3><a name="read_and_write_mo_files" id="read_and_write_mo_files">Read and Write MO files</a></h3>
 <div class="level3">
 
@@ -198,7 +207,7 @@
 </p>
 
 </div>
-<!-- SECTION "Read and Write MO files" [6013-6361] -->
+<!-- SECTION "Read and Write MO files" [6042-6390] -->
 <h3><a name="read_qt_.qm_files" id="read_qt_.qm_files">Read Qt .qm files</a></h3>
 <div class="level3">
 
@@ -208,12 +217,12 @@
 </p>
 
 </div>
-<!-- SECTION "Read Qt .qm files" [6362-6526] -->
-<h2><a name="section2" id="section2">1.0.1</a></h2>
-<div class="level2">
-
-</div>
-<!-- SECTION "1.0.1" [6527-6545] -->
+<!-- SECTION "Read Qt .qm files" [6391-6555] -->
+<h2><a name="section3" id="section3">1.0.1</a></h2>
+<div class="level2">
+
+</div>
+<!-- SECTION "1.0.1" [6556-6574] -->
 <h3><a name="pot2po_will_create_new_empty_po_files_if_needed" id="pot2po_will_create_new_empty_po_files_if_needed">pot2po will create new empty PO files if needed</a></h3>
 <div class="level3">
 
@@ -223,12 +232,12 @@
 </p>
 
 </div>
-<!-- SECTION "pot2po will create new empty PO files if needed" [6546-7000] -->
-<h2><a name="section3" id="section3">1.0</a></h2>
-<div class="level2">
-
-</div>
-<!-- SECTION "1.0" [7001-7017] -->
+<!-- SECTION "pot2po will create new empty PO files if needed" [6575-7029] -->
+<h2><a name="section4" id="section4">1.0</a></h2>
+<div class="level2">
+
+</div>
+<!-- SECTION "1.0" [7030-7046] -->
 <h3><a name="improved_xliff_support" id="improved_xliff_support">Improved XLIFF support</a></h3>
 <div class="level3">
 
@@ -237,7 +246,7 @@
 </p>
 
 </div>
-<!-- SECTION "Improved XLIFF support" [7018-7218] -->
+<!-- SECTION "Improved XLIFF support" [7047-7247] -->
 <h3><a name="pretty_xml_output" id="pretty_xml_output">Pretty XML output</a></h3>
 <div class="level3">
 
@@ -246,7 +255,7 @@
 </p>
 
 </div>
-<!-- SECTION "Pretty XML output" [7219-7362] -->
+<!-- SECTION "Pretty XML output" [7248-7391] -->
 <h3><a name="fuzzy_matching_in_pot2po_is_optional" id="fuzzy_matching_in_pot2po_is_optional">Fuzzy matching in pot2po is optional</a></h3>
 <div class="level3">
 
@@ -255,7 +264,7 @@
 </p>
 
 </div>
-<!-- SECTION "Fuzzy matching in pot2po is optional" [7363-7679] -->
+<!-- SECTION "Fuzzy matching in pot2po is optional" [7392-7708] -->
 <h3><a name="old_matchlevenshtein.py_can_cause_name_clash" id="old_matchlevenshtein.py_can_cause_name_clash">Old match/Levenshtein.py* can cause name clash</a></h3>
 <div class="level3">
 
@@ -264,7 +273,7 @@
 </p>
 
 </div>
-<!-- SECTION "Old match/Levenshtein.py* can cause name clash" [7680-8207] -->
+<!-- SECTION "Old match/Levenshtein.py* can cause name clash" [7709-8236] -->
 <h3><a name="po_file_layout_now_follows_gettext_more_closely" id="po_file_layout_now_follows_gettext_more_closely">PO file layout now follows Gettext more closely</a></h3>
 <div class="level3">
 
@@ -310,7 +319,7 @@
 </p>
 
 </div>
-<!-- SECTION "PO file layout now follows Gettext more closely" [8208-9870] -->
+<!-- SECTION "PO file layout now follows Gettext more closely" [8237-9899] -->
 <h3><a name="language_awareness" id="language_awareness">Language awareness</a></h3>
 <div class="level3">
 
@@ -319,7 +328,7 @@
 </p>
 
 </div>
-<!-- SECTION "Language awareness" [9871-10414] -->
+<!-- SECTION "Language awareness" [9900-10443] -->
 <h3><a name="new_pofilter_testsnewlines_and_tabs" id="new_pofilter_testsnewlines_and_tabs">New pofilter tests: newlines and tabs</a></h3>
 <div class="level3">
 
@@ -329,7 +338,7 @@
 </p>
 
 </div>
-<!-- SECTION "New pofilter tests: newlines and tabs" [10415-10709] -->
+<!-- SECTION "New pofilter tests: newlines and tabs" [10444-10738] -->
 <h3><a name="merging_can_change_fuzzy_status" id="merging_can_change_fuzzy_status">Merging can change fuzzy status</a></h3>
 <div class="level3">
 
@@ -350,7 +359,7 @@
 </p>
 
 </div>
-<!-- SECTION "Merging can change fuzzy status" [10710-11073] -->
+<!-- SECTION "Merging can change fuzzy status" [10739-11102] -->
 <h3><a name="pofilter_will_make_mozilla_accelerators_a_serious_failure" id="pofilter_will_make_mozilla_accelerators_a_serious_failure">pofilter will make Mozilla accelerators a serious failure</a></h3>
 <div class="level3">
 
@@ -360,7 +369,7 @@
 </p>
 
 </div>
-<!-- SECTION "pofilter will make Mozilla accelerators a serious failure" [11074-11426] -->
+<!-- SECTION "pofilter will make Mozilla accelerators a serious failure" [11103-11455] -->
 <h3><a name="po2prop_can_output_mozilla_or_java_style_properties" id="po2prop_can_output_mozilla_or_java_style_properties">po2prop can output Mozilla or Java style properties</a></h3>
 <div class="level3">
 
@@ -392,7 +401,7 @@
 </p>
 
 </div>
-<!-- SECTION "po2prop can output Mozilla or Java style properties" [11427-12471] -->
+<!-- SECTION "po2prop can output Mozilla or Java style properties" [11456-12500] -->
 <h3><a name="support_for_compressed_files" id="support_for_compressed_files">Support for compressed files</a></h3>
 <div class="level3">
 
@@ -401,12 +410,12 @@
 </p>
 
 </div>
-<!-- SECTION "Support for compressed files" [12472-12893] -->
-<h2><a name="section4" id="section4">0.11</a></h2>
-<div class="level2">
-
-</div>
-<!-- SECTION "0.11" [12894-12911] -->
+<!-- SECTION "Support for compressed files" [12501-12922] -->
+<h2><a name="section5" id="section5">0.11</a></h2>
+<div class="level2">
+
+</div>
+<!-- SECTION "0.11" [12923-12940] -->
 <h3><a name="po2oo_defaults_to_not_check_for_errors" id="po2oo_defaults_to_not_check_for_errors">po2oo defaults to not check for errors</a></h3>
 <div class="level3">
 
@@ -416,7 +425,7 @@
 </p>
 
 </div>
-<!-- SECTION "po2oo defaults to not check for errors" [12912-13321] -->
+<!-- SECTION "po2oo defaults to not check for errors" [12941-13350] -->
 <h3><a name="pofilter_xmltags_produces_less_false_positives" id="pofilter_xmltags_produces_less_false_positives">pofilter xmltags produces less false positives</a></h3>
 <div class="level3">
 
@@ -432,12 +441,12 @@
 </ol>
 
 </div>
-<!-- SECTION "pofilter xmltags produces less false positives" [13322-13794] -->
-<h2><a name="section5" id="section5">0.10</a></h2>
-<div class="level2">
-
-</div>
-<!-- SECTION "0.10" [13795-13812] -->
+<!-- SECTION "pofilter xmltags produces less false positives" [13351-13823] -->
+<h2><a name="section6" id="section6">0.10</a></h2>
+<div class="level2">
+
+</div>
+<!-- SECTION "0.10" [13824-13841] -->
 <h3><a name="po_to_xliff_conversion" id="po_to_xliff_conversion">PO to XLIFF conversion</a></h3>
 <div class="level3">
 
@@ -447,7 +456,7 @@
 </p>
 
 </div>
-<!-- SECTION "PO to XLIFF conversion" [13813-14069] -->
+<!-- SECTION "PO to XLIFF conversion" [13842-14098] -->
 <h3><a name="pot2po_can_replace_msgmerge" id="pot2po_can_replace_msgmerge">pot2po can replace msgmerge</a></h3>
 <div class="level3">
 
@@ -466,7 +475,7 @@
 </p>
 
 </div>
-<!-- SECTION "pot2po can replace msgmerge" [14070-14912] -->
+<!-- SECTION "pot2po can replace msgmerge" [14099-14941] -->
 <h3><a name="properties_pretty_formatting" id="properties_pretty_formatting">.properties pretty formatting</a></h3>
 <div class="level3">
 
@@ -488,12 +497,12 @@
 </p>
 
 </div>
-<!-- SECTION ".properties pretty formatting" [14913-15587] -->
-<h2><a name="section6" id="section6">0.9</a></h2>
-<div class="level2">
-
-</div>
-<!-- SECTION "0.9" [15588-15605] -->
+<!-- SECTION ".properties pretty formatting" [14942-15616] -->
+<h2><a name="section7" id="section7">0.9</a></h2>
+<div class="level2">
+
+</div>
+<!-- SECTION "0.9" [15617-15634] -->
 <h3><a name="escaping_-_dtd_files_are_no_longer_escaped" id="escaping_-_dtd_files_are_no_longer_escaped">Escaping - DTD files are no longer escaped</a></h3>
 <div class="level3">
 
@@ -530,7 +539,7 @@
 <span class="re3"># Edit file <span class="kw1">in</span> new-check <span class="kw1">in</span> your PO editor</span>
 pomerge -t new -i new-check -o new-check</pre></pre>
 </div>
-<!-- SECTION "Escaping - DTD files are no longer escaped" [15606-16860] -->
+<!-- SECTION "Escaping - DTD files are no longer escaped" [15635-16889] -->
 <h3><a name="migration_to_base_class" id="migration_to_base_class">Migration to base class</a></h3>
 <div class="level3">
 
@@ -557,7 +566,7 @@
 </p>
 
 </div>
-<!-- SECTION "Migration to base class" [16861-17975] -->
+<!-- SECTION "Migration to base class" [16890-18004] -->
 <h3><a name="duplicate_merging_in_po_files_-_merge_now_the_default" id="duplicate_merging_in_po_files_-_merge_now_the_default">Duplicate Merging in PO files - merge now the default</a></h3>
 <div class="level3">
 
@@ -579,7 +588,7 @@
 </p>
 
 </div>
-<!-- SECTION "Duplicate Merging in PO files - merge now the default" [17976-18920] -->
+<!-- SECTION "Duplicate Merging in PO files - merge now the default" [18005-18949] -->
 <h3><a name="properties_files_no_longer_use_escaped_unicode" id="properties_files_no_longer_use_escaped_unicode">.properties files no longer use escaped Unicode</a></h3>
 <div class="level3">
 
@@ -591,10 +600,10 @@
 </p>
 
 </div>
-<!-- SECTION ".properties files no longer use escaped Unicode" [18921-19544] -->
-<h2><a name="section7" id="section7">0.8</a></h2>
-<div class="level2">
-
-</div>
-<!-- SECTION "0.8" [19545-] --></body>
+<!-- SECTION ".properties files no longer use escaped Unicode" [18950-19573] -->
+<h2><a name="section8" id="section8">0.8</a></h2>
+<div class="level2">
+
+</div>
+<!-- SECTION "0.8" [19574-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-index.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-index.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-index.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-index.html Mon Dec 29 14:57:18 2008
@@ -23,25 +23,25 @@
 </p>
 
 <p>
-The toolkit can convert between various different <a href="toolkit-formats.html" class="wikilink1" title="toolkit-formats.html">translation formats</a> (such as Gettext <acronym title="Gettext Portable Object">PO</acronym> formats, <acronym title="XML Localization Interchange File Format">XLIFF</acronym>, OpenOffice.org, and Mozilla formats). This makes it possible to stay in one format across all your localisation, thus allowing you
+The Toolkit can convert between various different <a href="toolkit-formats.html" class="wikilink1" title="toolkit-formats.html">translation formats</a> (such as Gettext <acronym title="Gettext Portable Object">PO</acronym> formats, <acronym title="XML Localization Interchange File Format">XLIFF</acronym>, OpenOffice.org, and Mozilla formats). This makes it possible to stay in one format across all your localisation, thus allowing you
 to master one translation editor instead of one per project.  Of course an added benefit is that now you cannot create broken OpenOffice.org or Mozilla translation files.
 </p>
 
 <p>
-To help improve the quality of your localisation the toolkit includes tools to help check, validate, merge and extract messages from your localizations.  And of course there are many other <a href="toolkit-features.html" class="wikilink1" title="toolkit-features.html">benefits</a>.
-</p>
-
-<p>
-The toolkit has a long <a href="toolkit-history.html" class="wikilink1" title="toolkit-history.html">history</a> and is part of our project to build standards based localisation tools for Free and Open Source Software.
-</p>
-
-<p>
-These documents are maintained in the wiki at <a href="http://translate.sourceforge.net/wiki/toolkit/index" class="urlextern" title="http://translate.sourceforge.net/wiki/toolkit/index">http://translate.sourceforge.net/wiki/toolkit/index</a>
+To help improve the quality of your localisation, the Toolkit includes tools to help check, validate, merge and extract messages from your localizations.  And of course there are many other <a href="toolkit-features.html" class="wikilink1" title="toolkit-features.html">benefits</a>.
+</p>
+
+<p>
+The Toolkit has a long <a href="toolkit-history.html" class="wikilink1" title="toolkit-history.html">history</a> and is part of our project to build standards based localisation tools for Free and Open Source Software. At this stage the Translate Toolkit <acronym title="Application Programming Interface">API</acronym> already forms the technological basis of the translation tools built by ourselves and several other projects. If you want to use the Toolkit to build translation tools, you might be interested in the <a href="http://translate.sourceforge.net/doc/api" class="urlextern" title="http://translate.sourceforge.net/doc/api">API documentation for the Translate Toolkit</a>.
+</p>
+
+<p>
+This documentation is maintained in the wiki at <a href="http://translate.sourceforge.net/wiki/toolkit/index" class="urlextern" title="http://translate.sourceforge.net/wiki/toolkit/index">http://translate.sourceforge.net/wiki/toolkit/index</a> .
 If you want the latest version or want to make changes, please consult the wiki.
 </p>
 
 </div>
-<!-- SECTION "The Translate Toolkit" [1-1237] -->
+<!-- SECTION "The Translate Toolkit" [1-1572] -->
 <h1><a name="quick_start" id="quick_start">Quick Start</a></h1>
 <div class="level1">
 <ul>
@@ -64,7 +64,7 @@
 </ul>
 
 </div>
-<!-- SECTION "Quick Start" [1238-1441] -->
+<!-- SECTION "Quick Start" [1573-1776] -->
 <h1><a name="use_cases" id="use_cases">Use Cases</a></h1>
 <div class="level1">
 <ul>
@@ -93,7 +93,7 @@
 </ul>
 
 </div>
-<!-- SECTION "Use Cases" [1442-2282] -->
+<!-- SECTION "Use Cases" [1777-2617] -->
 <h1><a name="converters" id="converters">Converters</a></h1>
 <div class="level1">
 
@@ -117,6 +117,8 @@
 </li>
 <li class="level1"><div class="li"> <a href="toolkit-ini2po.html" class="wikilink1" title="toolkit-ini2po.html">ini2po</a> - Windows INI file converter (v1.1.1)</div>
 </li>
+<li class="level1"><div class="li"> <a href="toolkit-odf2xliff.html" class="wikilink1" title="toolkit-odf2xliff.html">odf2xliff</a> - Convert OpenDocument (ODF) documents to <acronym title="XML Localization Interchange File Format">XLIFF</acronym> and vice-versa.</div>
+</li>
 <li class="level1"><div class="li"> <a href="toolkit-php2po.html" class="wikilink1" title="toolkit-php2po.html">php2po</a> - <acronym title="Hypertext Preprocessor">PHP</acronym> localisable string arrays converter.</div>
 </li>
 <li class="level1"><div class="li"> <a href="toolkit-po2wordfast.html" class="wikilink1" title="toolkit-po2wordfast.html">po2wordfast</a> - Wordfast Translation Memory converter</div>
@@ -148,7 +150,7 @@
 </ul>
 
 </div>
-<!-- SECTION "Converters" [2283-3738] -->
+<!-- SECTION "Converters" [2618-4155] -->
 <h1><a name="tools" id="tools">Tools</a></h1>
 <div class="level1">
 
@@ -158,7 +160,7 @@
 </p>
 
 </div>
-<!-- SECTION "Tools" [3739-3821] -->
+<!-- SECTION "Tools" [4156-4238] -->
 <h3><a name="quality_assurance" id="quality_assurance">Quality Assurance</a></h3>
 <div class="level3">
 
@@ -180,7 +182,7 @@
 </ul>
 
 </div>
-<!-- SECTION "Quality Assurance" [3822-4323] -->
+<!-- SECTION "Quality Assurance" [4239-4740] -->
 <h3><a name="other_tools" id="other_tools">Other tools</a></h3>
 <div class="level3">
 <ul>
@@ -203,7 +205,7 @@
 </ul>
 
 </div>
-<!-- SECTION "Other tools" [4324-5159] -->
+<!-- SECTION "Other tools" [4741-5576] -->
 <h1><a name="scripts" id="scripts">Scripts</a></h1>
 <div class="level1">
 
@@ -237,5 +239,5 @@
 </ul>
 
 </div>
-<!-- SECTION "Scripts" [5160-] --></body>
+<!-- SECTION "Scripts" [5577-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-mo.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-mo.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-mo.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-mo.html Mon Dec 29 14:57:18 2008
@@ -32,17 +32,11 @@
 The toolkit can create .mo files from <acronym title="Gettext Portable Object">PO</acronym> or <acronym title="XML Localization Interchange File Format">XLIFF</acronym> files, handling plurals and msgctxt.  It can also read .mo files, allowing counting, etc and also allowing the .mo files to act as a translation memory.
 </p>
 
-</div>
-<!-- SECTION "Conformance" [309-537] -->
-<h3><a name="no_hash_table" id="no_hash_table">No hash table</a></h3>
-<div class="level3">
-
 <p>
-
-The hash table is not implemented (the Gettext .mo file works fine without it).  This might result in slower performance although the Gettext manual raises doubts about the speed gain.  The hash is platform dependent.  Bug <a href="http://bugs.locamotion.org/show_bug.cgi?id=326" class="interwiki iw_bug" title="http://bugs.locamotion.org/show_bug.cgi?id=326">326</a> is tracking implementation of hashing.
+Since version 1.2 of the Translate Toolkit, the hash table is also generated (the Gettext .mo file works fine without it). Due to slight differences in the construction of the hashing, the generated files are not identical to those generated by msgfmt, but they should be functionally equivalent and 100% usable. Bug <a href="http://bugs.locamotion.org/show_bug.cgi?id=326" class="interwiki iw_bug" title="http://bugs.locamotion.org/show_bug.cgi?id=326">326</a> tracked the implementation of the hashing. The hash is platform dependent.
 
 </p>
 
 </div>
-<!-- SECTION "No hash table" [538-] --></body>
+<!-- SECTION "Conformance" [309-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-moz-l10n-builder.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-moz-l10n-builder.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-moz-l10n-builder.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-moz-l10n-builder.html Mon Dec 29 14:57:18 2008
@@ -26,8 +26,17 @@
 Please also check the page on <a href="http://developer.mozilla.org/en/docs/Creating_a_Language_Pack" class="urlextern" title="http://developer.mozilla.org/en/docs/Creating_a_Language_Pack">creating a language pack</a> on the Mozilla wiki, to stay abreast of the latest Mozilla way of doing things.
 </p>
 
+<p>
+<p><div class="noteclassic">This page is only applicable to Mozilla products with its source hosted in <acronym title="Concurrent Versions System">CVS</acronym>. This includes Firefox versions before 3.1 and Thunderbird versions before 3.0.
+</p>
+
+<p>
+For information about working with the new source trees in Mercurial, see the <a href="toolkit-mozilla_l10n_scripts.html" class="wikilink1" title="toolkit-mozilla_l10n_scripts.html">Mozilla l10n scripts</a> page.
+</div></p>
+</p>
+
 </div>
-<!-- SECTION "moz-l10n-builder" [1-420] -->
+<!-- SECTION "moz-l10n-builder" [1-703] -->
 <h2><a name="prerequisites" id="prerequisites">Prerequisites</a></h2>
 <div class="level2">
 <ul>
@@ -55,7 +64,23 @@
 </li>
 </ul>
 </li>
+<li class="level1"><div class="li"> Directory structure under the directory you want to run moz-l10n-builder in:</div>
+</li>
 </ul>
+<table class="inline">
+	<tr class="row0">
+		<td class="col0"> l10n/ </td><td class="col1"> Contains Mozilla l10n files for available/needed language(s) </td>
+	</tr>
+	<tr class="row1">
+		<td class="col0"> mozilla/ </td><td class="col1"> The Mozilla source tree </td>
+	</tr>
+	<tr class="row2">
+		<td class="col0"> po/ </td><td class="col1"> Contains your <acronym title="Gettext Portable Object">PO</acronym> files (output from moz2po) </td>
+	</tr>
+	<tr class="row3">
+		<td class="col0"> potpacks/ </td><td class="col1"> Where <acronym title="Gettext Portable Object Template">POT</acronym>-archives go </td>
+	</tr>
+</table>
 
 <p>
 
@@ -63,18 +88,18 @@
 </p>
 
 </div>
-<!-- SECTION "Prerequisites" [421-1622] -->
+<!-- SECTION "Prerequisites" [704-2191] -->
 <h2><a name="latest_version" id="latest_version">Latest Version</a></h2>
 <div class="level2">
 
 <p>
 
-moz-l10n-builer is not currently distributed as part of the toolkit.  You can get the <a href="http://translate.svn.sourceforge.net/viewvc/*checkout*/translate/src/trunk/tools/moz-l10n-builder" class="urlextern" title="http://translate.svn.sourceforge.net/viewvc/*checkout*/translate/src/trunk/tools/moz-l10n-builder">latest version from Subversion</a>
- and you will also need this <a href="http://translate.svn.sourceforge.net/viewvc/*checkout*/translate/src/trunk/tools/mozilla-l10n.patch" class="urlextern" title="http://translate.svn.sourceforge.net/viewvc/*checkout*/translate/src/trunk/tools/mozilla-l10n.patch">minor patch</a> to the mozilla source code.
+moz-l10n-builer is not currently distributed as part of the toolkit.  You can get the <a href="https://translate.svn.sourceforge.net/svnroot/translate/src/trunk/tools/mozilla/moz-l10n-builder" class="urlextern" title="https://translate.svn.sourceforge.net/svnroot/translate/src/trunk/tools/mozilla/moz-l10n-builder">latest version from Subversion</a>
+ and you will also need this <a href="http://translate.svn.sourceforge.net/viewvc/*checkout*/translate/src/trunk/tools/mozilla/mozilla-l10n.patch" class="urlextern" title="http://translate.svn.sourceforge.net/viewvc/*checkout*/translate/src/trunk/tools/mozilla/mozilla-l10n.patch">minor patch</a> to the mozilla source code.
 </p>
 
 </div>
-<!-- SECTION "Latest Version" [1623-2043] -->
+<!-- SECTION "Latest Version" [2192-2619] -->
 <h2><a name="usage" id="usage">Usage</a></h2>
 <div class="level2">
 <pre class="code">moz-l10n-builder [language-code|ALL]</pre>
@@ -96,7 +121,7 @@
 </p>
 
 </div>
-<!-- SECTION "Usage" [2044-2263] -->
+<!-- SECTION "Usage" [2620-2839] -->
 <h2><a name="operation" id="operation">Operation</a></h2>
 <div class="level2">
 
@@ -123,7 +148,7 @@
 </ul>
 
 </div>
-<!-- SECTION "Operation" [2264-2689] -->
+<!-- SECTION "Operation" [2840-3265] -->
 <h2><a name="bugs" id="bugs">Bugs</a></h2>
 <div class="level2">
 
@@ -134,5 +159,5 @@
 </p>
 
 </div>
-<!-- SECTION "Bugs" [2690-] --></body>
+<!-- SECTION "Bugs" [3266-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-moz2po.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-moz2po.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-moz2po.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-moz2po.html Mon Dec 29 14:57:18 2008
@@ -25,11 +25,16 @@
 </p>
 
 <p>
-Caution: The conversion to and from <acronym title="Cross Platform Installer">XPI</acronym> files is no longer actively supported, please work directly against Mozilla <acronym title="Concurrent Versions System">CVS</acronym> files.
-</p>
-
-</div>
-<!-- SECTION "moz2po and po2moz" [1-517] -->
+<p><div class="noteclassic">This page should only be used as a reference to the command-line options for moz2po and po2moz. For more about using the Translate Toolkit and <acronym title="Gettext Portable Object">PO</acronym> files for translating Mozilla products, please see the page on <a href="toolkit-mozilla_l10n_scripts.html" class="wikilink1" title="toolkit-mozilla_l10n_scripts.html">Mozilla l10n scripts</a>.
+</div></p>
+</p>
+
+<p>
+<strong>Caution</strong>: The conversion to and from <acronym title="Cross Platform Installer">XPI</acronym> files is no longer actively supported, please work directly against Mozilla <acronym title="Concurrent Versions System">CVS</acronym> files.
+</p>
+
+</div>
+<!-- SECTION "moz2po and po2moz" [1-770] -->
 <h2><a name="usage" id="usage">Usage</a></h2>
 <div class="level2">
 <pre class="code">moz2po [options] <xpi|dir> <po>
@@ -130,44 +135,51 @@
 </table>
 
 </div>
-<!-- SECTION "Usage" [518-3166] -->
+<!-- SECTION "Usage" [771-3419] -->
 <h2><a name="examples" id="examples">Examples</a></h2>
 <div class="level2">
 
 </div>
-<!-- SECTION "Examples" [3167-3188] -->
+<!-- SECTION "Examples" [3420-3441] -->
 <h3><a name="creating_pot_files" id="creating_pot_files">Creating POT files</a></h3>
 <div class="level3">
-<pre class="code">cd mozilla
-make -f tools/l10n/l10n.mk create-en-US
-cd ..
-moz2po -P l10n/en-US pot</pre>
-
-<p>
-
-First extract the correct en-US source files from Mozilla <acronym title="Concurrent Versions System">CVS</acronym>, found in the <em>mozilla</em> directory, placing them in <em>l10n/en-US</em>.  Then create a set of <acronym title="Gettext Portable Object Template">POT</acronym> (<em>-P</em>) files in <em>pot</em>.
+
+<p>
+
+See <a href="toolkit-creating_mozilla_pot_files.html" class="wikilink1" title="toolkit-creating_mozilla_pot_files.html">this page</a> for more information on creating Mozilla <acronym title="Gettext Portable Object Template">POT</acronym> files.
+</p>
+
+<p>
+After extracting the en-US l10n files, you can run the following command:
+
+</p>
+<pre class="code">moz2po -P l10n/en-US pot</pre>
+
+<p>
+
+This creates a set of <acronym title="Gettext Portable Object Template">POT</acronym> (<code>-P</code>) files in the <code>pot</code> directory from the Mozilla files in <code>l10n/en-US</code>.
 
 </p>
 <pre class="code">moz2po -P en-US.xpi pot</pre>
 
 <p>
 
-Creating set of <acronym title="Gettext Portable Object Template">POT</acronym> (<em>-P</em>) files from the American English <acronym title="Cross Platform Installer">XPI</acronym>, <em>en-US.xpi</em> and placing them in <em>pot</em> for use a <acronym title="Gettext Portable Object">PO</acronym> Templates.
-</p>
-
-<p>
-If you want to create a set of <acronym title="Gettext Portable Object Template">POT</acronym> files with another base language try:
+Creating set of <acronym title="Gettext Portable Object Template">POT</acronym> (<code>-P</code>) files from the American English <acronym title="Cross Platform Installer">XPI</acronym> (<code>en-US.xpi</code>) and placing them in <code>pot</code> for use as <acronym title="Gettext Portable Object">PO</acronym> Templates.
+</p>
+
+<p>
+If you want to create a set of <acronym title="Gettext Portable Object Template">POT</acronym> files with another base language try the following:
 
 </p>
 <pre class="code">moz2po -P fr-FR.xpi fr-pot</pre>
 
 <p>
 
-This will create a set of <acronym title="Gettext Portable Object Template">POT</acronym> files in <em>fr-pot</em> that have French as your source language.
-</p>
-
-</div>
-<!-- SECTION "Creating POT files" [3189-3853] -->
+This will create a set of <acronym title="Gettext Portable Object Template">POT</acronym> files in <code>fr-pot</code> that have French as your source language.
+</p>
+
+</div>
+<!-- SECTION "Creating POT files" [3442-4156] -->
 <h3><a name="creating_po_files_from_existing_non-po_translations" id="creating_po_files_from_existing_non-po_translations">Creating PO files from existing non-PO translations</a></h3>
 <div class="level3">
 
@@ -180,51 +192,36 @@
 
 <p>
 
-This will combine the untranslated template en-US files from <em>en-US</em> combine them with your existing translations in <em>af-ZA</em> and output <acronym title="Gettext Portable Object">PO</acronym> files to <em>af-ZA_pofiles</em>.
-</p>
-
-<p>
-The following is a more detailed recipe for Mozilla translation against <acronym title="Concurrent Versions System">CVS</acronym>:
-
-</p>
-<pre class="code">cd mozilla
-make -f tools/l10n/l10n.mk create-en-US
-cd ..
-moz2po -t l10n/en-US l10n/xh po/xh</pre>
-
-<p>
-
-This is against Mozilla <acronym title="Concurrent Versions System">CVS</acronym>.  First create your en-US reference files. Then using moz2po take the template en-US files in <em>l10n/en-US</em> and merge them with translations in <em>l10n/xh</em> placing the <acronym title="Gettext Portable Object">PO</acronym> files in <em>po/xh</em>.  The text from <em>en-US</em> will appear in the msgid and the text from <em>xh</em> will appear in the msgstr.  Run <a href="toolkit-pocount.html" class="wikilink1" title="toolkit-pocount.html">pocount</a> to determine how much work you need to to to bring your translations up to fully translated.
+This will combine the untranslated template en-US files from <code>en-US</code> combine them with your existing translations in <code>af-ZA</code> and output <acronym title="Gettext Portable Object">PO</acronym> files to <code>af-ZA_pofiles</code>.
 
 </p>
 <pre class="code">moz2po -t l10n/fr l10n/xh po/xh</pre>
 
 <p>
 
-For those who are not English fluent you can do the same with another languages.  In this case msgid will contain the French text from <em>l10n/fr</em>.  This is useful for translating where the translators other languages is not English but French, Spanish or Portuguese.  Please make sure that the source languages i.e. the msgid language is fully translated as against en-US.
-</p>
-
-</div>
-<!-- SECTION "Creating PO files from existing non-PO translations" [3854-5337] -->
+For those who are not English fluent you can do the same with another languages.  In this case <code>msgid</code> will contain the French text from <code>l10n/fr</code>.  This is useful for translating where the translators other languages is not English but French, Spanish or Portuguese.  Please make sure that the source languages i.e. the <code>msgid</code> language is fully translated as against en-US.
+</p>
+
+</div>
+<!-- SECTION "Creating PO files from existing non-PO translations" [4157-5036] -->
 <h3><a name="creating_an_xpi_or_cvs_ready_translations" id="creating_an_xpi_or_cvs_ready_translations">Creating an XPI or CVS ready translations</a></h3>
 <div class="level3">
 <pre class="code">po2moz -lzu-ZA -t en-US.xpi zu zu-ZA.xpi</pre>
 
 <p>
 
-Create a Zulu language (<em>-lzu-ZA</em>) <acronym title="Cross Platform Installer">XPI</acronym> called <em>zu-ZA.xpi</em> from translations found in <em>zu</em> using <em>en-US.xpi</em> as a template.  We use a template to ensure that our <acronym title="Document Type Definition">DTD</acronym> and .properties files appear exactly as those in en-US
+Create a Zulu language (<code>-lzu-ZA</code>) <acronym title="Cross Platform Installer">XPI</acronym> called <code>zu-ZA.xpi</code> from translations found in <code>zu</code> using <code>en-US.xpi</code> as a template.  We use a template to ensure that our <acronym title="Document Type Definition">DTD</acronym> and .properties files appear exactly as those in en-US
 
 </p>
 <pre class="code">po2moz -t l10n/en-US po/xh l10n/xh</pre>
 
 <p>
 
-Create Mozilla files using the templates files in <em>l10n/en-US</em> (see above for how to create them) with <acronym title="Gettext Portable Object">PO</acronym> translations in <em>po/xh</em> and ouput then
-to <em>l10n/xh</em>.  The files now in <em>l10n/xh</em> are ready for submission to Mozilla and can be used to build a language pack or translated version of Mozilla.
-</p>
-
-</div>
-<!-- SECTION "Creating an XPI or CVS ready translations" [5338-6010] -->
+Create Mozilla files using the templates files in <code>l10n/en-US</code> (see above for how to create them) with <acronym title="Gettext Portable Object">PO</acronym> translations in <code>po/xh</code> and ouput them to <code>l10n/xh</code>.  The files now in <code>l10n/xh</code> are ready for submission to Mozilla and can be used to build a language pack or translated version of Mozilla.
+</p>
+
+</div>
+<!-- SECTION "Creating an XPI or CVS ready translations" [5037-5709] -->
 <h2><a name="issues" id="issues">Issues</a></h2>
 <div class="level2">
 
@@ -238,13 +235,11 @@
 </p>
 
 <p>
-Bug <a href="http://bugs.locamotion.org/show_bug.cgi?id=129" class="interwiki iw_bug" title="http://bugs.locamotion.org/show_bug.cgi?id=129">129</a> tracks the outstanding features 
-which would allow complete localisation of Mozilla including; all help, start pages, rdf files, etc.
-It also tracks some bugs.
-</p>
-
-<p>
-Accesskeys don't yet work in .properties files and in several cases where the Mozilla dtd files don't follow the normal conventions, for example in security/manager/chrome/pippki/pref-ssl.dtd.po. You might also want to check the files mentioned in this bug <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=329444" class="interwiki iw_mozbug" title="https://bugzilla.mozilla.org/show_bug.cgi?id=329444">329444</a> where mistakes in the <acronym title="Document Type Definition">DTD</acronym>-definitions cause problems in the matching of accelerators with the text.
+Bug <a href="http://bugs.locamotion.org/show_bug.cgi?id=129" class="interwiki iw_bug" title="http://bugs.locamotion.org/show_bug.cgi?id=129">129</a> tracks the outstanding features which would allow complete localisation of Mozilla including; all help, start pages, rdf files, etc. It also tracks some bugs.
+</p>
+
+<p>
+Accesskeys don't yet work in .properties files and in several cases where the Mozilla .dtd files don't follow the normal conventions, for example in <code>security/manager/chrome/pippki/pref-ssl.dtd.po</code>. You might also want to check the files mentioned in this bug <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=329444" class="interwiki iw_mozbug" title="https://bugzilla.mozilla.org/show_bug.cgi?id=329444">329444</a> where mistakes in the <acronym title="Document Type Definition">DTD</acronym>-definitions cause problems in the matching of accelerators with the text.
 </p>
 
 <p>
@@ -263,13 +258,13 @@
 </p>
 
 <p>
-There are some constructed strings in the Mozilla code which we can't do much about. Take good care to read the localisation notes. For an example, see mail/chrome/messenger/downloadheaders.dtd.po. In that specific file, the localisation note from the <acronym title="Document Type Definition">DTD</acronym> file is lost, so take good care of those.
-</p>
-
-<p>
-The file extension of the original Mozilla file is required to tell the Toolkit how to do the conversion.  Therefore, a file like foo.dtd must be named foo.dtd.po in order to po2moz to recognise it as a <acronym title="Document Type Definition">DTD</acronym> file.
-</p>
-
-</div>
-<!-- SECTION "Issues" [6011-] --></body>
+There are some constructed strings in the Mozilla code which we can't do much about. Take good care to read the localisation notes. For an example, see <code>mail/chrome/messenger/downloadheaders.dtd.po</code>. In that specific file, the localisation note from the <acronym title="Document Type Definition">DTD</acronym> file is lost, so take good care of those.
+</p>
+
+<p>
+The file extension of the original Mozilla file is required to tell the Toolkit how to do the conversion.  Therefore, a file like foo.dtd must be named foo.dtd.po in order to <code>po2moz</code> to recognise it as a <acronym title="Document Type Definition">DTD</acronym> file.
+</p>
+
+</div>
+<!-- SECTION "Issues" [5710-] --></body>
 </html>

Added: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-mozilla_l10n_scripts.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-mozilla_l10n_scripts.html?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-mozilla_l10n_scripts.html (added)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-mozilla_l10n_scripts.html Mon Dec 29 14:57:18 2008
@@ -1,0 +1,274 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+  <title></title>
+  <link rel="stylesheet" media="screen" type="text/css" href="./style.css" />
+  <link rel="stylesheet" media="screen" type="text/css" href="./design.css" />
+  <link rel="stylesheet" media="print" type="text/css" href="./print.css" />
+
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+</head>
+<body>
+<a href=.>start</a></br>
+
+
+
+<h1><a name="mozilla_l10n_scripts" id="mozilla_l10n_scripts">Mozilla L10n Scripts</a></h1>
+<div class="level1">
+
+</div>
+<!-- SECTION "Mozilla L10n Scripts" [1-35] -->
+<h2><a name="introduction" id="introduction">Introduction</a></h2>
+<div class="level2">
+
+<p>
+This page describes the purpose and usage of scripts available in the Translate Toolkit specifically for making the translation of Mozilla products easier.
+</p>
+
+<p>
+Mozilla's move from <acronym title="Concurrent Versions System">CVS</acronym> to Mercurial made a lot of these scripts necessary. For more information about Mozilla l10n from <acronym title="Concurrent Versions System">CVS</acronym>, see the <a href="toolkit-moz-l10n-builder.html" class="wikilink1" title="toolkit-moz-l10n-builder.html">moz-l10n-builder</a> page.
+</p>
+
+<p>
+All of these scripts are available on Subversion from <a href="https://translate.svn.sourceforge.net/svnroot/translate/src/trunk/tools/mozilla/" class="urlextern" title="https://translate.svn.sourceforge.net/svnroot/translate/src/trunk/tools/mozilla/">here</a>.
+</p>
+
+</div>
+<!-- SECTION "Introduction" [36-526] -->
+<h2><a name="requirements" id="requirements">Requirements</a></h2>
+<div class="level2">
+<ul>
+<li class="level1"><div class="li"> The <a href="toolkit-index.html" class="wikilink1" title="toolkit-index.html">Translate Toolkit</a></div>
+</li>
+<li class="level1"><div class="li"> All scripts in the <code>tools/mozilla</code> directory (from the project sources) should be executable and in your <code>PATH</code>.</div>
+</li>
+</ul>
+
+</div>
+<!-- SECTION "Requirements" [527-718] -->
+<h2><a name="build_ff3.1_langs.sh" id="build_ff3.1_langs.sh">build_ff3.1_langs.sh</a></h2>
+<div class="level2">
+
+</div>
+<!-- SECTION "build_ff3.1_langs.sh" [719-751] -->
+<h3><a name="description" id="description">Description</a></h3>
+<div class="level3">
+
+<p>
+This is a simple bash script that embodies most of the Mozilla l10n process and does the following:
+</p>
+<ol>
+<li class="level1"><div class="li"> Update Mozilla sources</div>
+</li>
+<li class="level1"><div class="li"> Update language files from <a href="http://hg.mozilla.org/l10n-central" class="urlextern" title="http://hg.mozilla.org/l10n-central">Mozilla's L10n</a> Mercurial repository.</div>
+</li>
+<li class="level1"><div class="li"> Replace old l10n en-US files with a fresh copy from the updated source tree.</div>
+</li>
+<li class="level1"><div class="li"> <a href="toolkit-creating_mozilla_pot_files.html" class="wikilink1" title="toolkit-creating_mozilla_pot_files.html">Create new POT files</a> from the <a href="#get_moz_enus.py" title=":toolkit:mozilla_l10n_scripts.txt ↵" class="wikilink1">en-US</a> l10n files.</div>
+</li>
+<li class="level1"><div class="li"> Create archives of the <acronym title="Gettext Portable Object Template">POT</acronym> files.</div>
+</li>
+<li class="level1"><div class="li"> For each language:</div>
+<ol>
+<li class="level2"><div class="li"> Update existing <acronym title="Gettext Portable Object">PO</acronym> files if the checked out from a <acronym title="Concurrent Versions System">CVS</acronym>, Subversion or Mercurial repository.</div>
+</li>
+<li class="level2"><div class="li"> <a href="toolkit-migrating_translations.html" class="wikilink1" title="toolkit-migrating_translations.html">Migrate</a> <acronym title="Gettext Portable Object">PO</acronym> files to new <acronym title="Gettext Portable Object Template">POT</acronym> files.</div>
+</li>
+<li class="level2"><div class="li"> <a href="toolkit-po2moz.html" class="wikilink1" title="toolkit-po2moz.html">Create Mozilla l10n files</a> for the language based on the migrated <acronym title="Gettext Portable Object">PO</acronym> files.</div>
+</li>
+<li class="level2"><div class="li"> Create archives of the <acronym title="Gettext Portable Object">PO</acronym> files.</div>
+</li>
+<li class="level2"><div class="li"> <a href="#buildxpi.py" title=":toolkit:mozilla_l10n_scripts.txt ↵" class="wikilink1">Build langpack</a> for the language.</div>
+</li>
+</ol>
+</li>
+</ol>
+
+<p>
+
+This script is used on the l10n.mozilla.org server to create most (if not all) of the files available from <a href="http://l10n.mozilla.org/pootle/" class="urlextern" title="http://l10n.mozilla.org/pootle/">http://l10n.mozilla.org/pootle/</a>. It was originally written as a stable way to provide these files and as such making it as general as possible was not the biggest requirement. This is evident in the script's very narrow focus.
+</p>
+
+</div>
+<!-- SECTION "Description" [752-1942] -->
+<h3><a name="usage" id="usage">Usage</a></h3>
+<div class="level3">
+
+<p>
+This script takes no command-line parameters and is only configurable via the variables at the top and, failing that, custom hacking of the script.
+</p>
+
+<p>
+The variables are used in the following ways:
+</p>
+<table class="inline">
+	<tr class="row0">
+		<td class="col0"><code>BUILD_DIR</code></td><td class="col1"> The base build directory from where building is done. </td>
+	</tr>
+	<tr class="row1">
+		<td class="col0"><code>MOZCENTRAL_DIR</code></td><td class="col1"> The directory containing a checkout of the Mozilla source tree (from <a href="http://hg.mozilla.org/mozilla-central/" class="urlextern" title="http://hg.mozilla.org/mozilla-central/">http://hg.mozilla.org/mozilla-central/</a>). </td>
+	</tr>
+	<tr class="row2">
+		<td class="col0"><code>HG_LANGS</code></td><td class="col1"> A space-seperated list of language codes to build for. </td>
+	</tr>
+	<tr class="row3">
+		<td class="col0"><code>L10N_DIR</code></td><td class="col1"> The directory where Mozilla l10n files should be collected. </td>
+	</tr>
+	<tr class="row4">
+		<td class="col0"><code><acronym title="Gettext Portable Object">PO</acronym>_DIR</code></td><td class="col1"> The directory containing the externally-hosted or previously available source <acronym title="Gettext Portable Object">PO</acronym> files (ex. <acronym title="Gettext Portable Object">PO</acronym> files managed in another VCS repository). It contains a sub-directory for each language. </td>
+	</tr>
+	<tr class="row5">
+		<td class="col0"><code>POPACK_DIR</code></td><td class="col1"> The output directory for <acronym title="Gettext Portable Object">PO</acronym> archives. </td>
+	</tr>
+	<tr class="row6">
+		<td class="col0"><code>PORECOVER_DIR</code></td><td class="col1"> The directory to put recovered <acronym title="Gettext Portable Object">PO</acronym> files in. It contains a sub-directory for each language. </td>
+	</tr>
+	<tr class="row7">
+		<td class="col0"><code><acronym title="Gettext Portable Object Template">POT</acronym>_INCLUDES</code></td><td class="col1"> A space-seperated list of files to be included in <acronym title="Gettext Portable Object Template">POT</acronym> archives. </td>
+	</tr>
+	<tr class="row8">
+		<td class="col0"><code>POTPACK_DIR</code></td><td class="col1"> The output directory for <acronym title="Gettext Portable Object Template">POT</acronym> archives. </td>
+	</tr>
+	<tr class="row9">
+		<td class="col0"><code>POUPDATED_DIR</code></td><td class="col1"> The directory to use for updated <acronym title="Gettext Portable Object">PO</acronym> files. It contains a sub-directory for each language. </td>
+	</tr>
+	<tr class="row10">
+		<td class="col0"><code>LANGPACK_DIR</code></td><td class="col1"> The directory to put langpacks (XPIs) in. </td>
+	</tr>
+	<tr class="row11">
+		<td class="col0"><code>FF_VERSION</code></td><td class="col1"> The version of Firefox that is being built for. This is used in the file names of archives. </td>
+	</tr>
+</table>
+
+</div>
+<!-- SECTION "Usage" [1943-3308] -->
+<h2><a name="build_tb3_langs.sh" id="build_tb3_langs.sh">build_tb3_langs.sh</a></h2>
+<div class="level2">
+
+<p>
+This is the script that the <code>build_ff3.1_langs.sh</code> script above was actually adapted from. It is 90% similar with the obvious exception that it is aimed at building Thunderbird 3.0 packages in stead of Firefox 3.1.
+</p>
+
+</div>
+<!-- SECTION "build_tb3_langs.sh" [3309-3558] -->
+<h2><a name="buildxpi.py" id="buildxpi.py">buildxpi.py</a></h2>
+<div class="level2">
+
+</div>
+<!-- SECTION "buildxpi.py" [3559-3582] -->
+<h3><a name="description1" id="description1">Description</a></h3>
+<div class="level3">
+
+<p>
+Creats a <acronym title="Cross Platform Installer">XPI</acronym> language pack from Mozilla sources and translated l10n files. This script has only been tested with Firefox 3.1 beta sources.
+</p>
+
+<p>
+It is basically the scripted version of the process described on Mozilla's <a href="https://developer.mozilla.org/en/Creating_a_Language_Pack" class="urlextern" title="https://developer.mozilla.org/en/Creating_a_Language_Pack">"Creating a language pack"</a> page.
+</p>
+
+<p>
+This script is used by <code>build_ff3.1_langs.sh</code> to build language packs in its final step.
+</p>
+
+<p>
+<strong>Note:</strong> This script uses the <code>.mozconfig</code> file in your home directory. Any existing <code>.mozconfig</code> is renamed to <code>.mozconfig.bak</code> during operation and copied back afterwards.
+</p>
+
+</div>
+<!-- SECTION "Description" [3583-4189] -->
+<h3><a name="usage1" id="usage1">Usage</a></h3>
+<div class="level3">
+<pre class="code">buildxpi.py -L /path/to/l10n -s /path/to/mozilla-central -o /path/to/xpi_output af</pre>
+
+Options:<table class="inline">
+	<tr class="row0">
+		<td class="col0"><code>/path/to/l10n</code></td><td class="col1"> The path to the parent directory of the “af” directory containing the Afrikaans translated l10n files. </td>
+	</tr>
+	<tr class="row1">
+		<td class="col0"><code>/path/to/mozilla-central</code></td><td class="col1"> The path to the Firefox sources check out from <a href="http://hg.mozilla.org/mozilla-central" class="urlextern" title="http://hg.mozilla.org/mozilla-central">Mercurial</a>. Note that <code>--mozproduct</code> is not specified, because the default is <code>browser</code>. For Thunderbird (>=3.0) it should be <code>/path/to/<a href="http://hg.mozilla.org/comm-central" class="urlextern" title="http://hg.mozilla.org/comm-central">comm-central</a></code> and <code>--mozproduct mail</code> should be specified. </td>
+	</tr>
+	<tr class="row2">
+		<td class="col0"><code>/path/to/xpi_output</code></td><td class="col1"> The path to the output directory. </td>
+	</tr>
+	<tr class="row3">
+		<td class="col0"><code>af</code></td><td class="col1"> The language (Afrikaans in this case) to build a language pack for. </td>
+	</tr>
+</table>
+
+</div>
+<!-- SECTION "Usage" [4190-4931] -->
+<h2><a name="get_moz_enus.py" id="get_moz_enus.py">get_moz_enUS.py</a></h2>
+<div class="level2">
+
+</div>
+<!-- SECTION "get_moz_enUS.py" [4932-4959] -->
+<h3><a name="description2" id="description2">Description</a></h3>
+<div class="level3">
+
+<p>
+A simple script to collect the en-US l10n files from a Mozilla source tree (<code>'comm-central</code>' or <code>'mozilla-central</code>') by traversing the product's <code>l10n.ini</code> file.
+</p>
+
+</div>
+<!-- SECTION "Description" [4960-5150] -->
+<h3><a name="usage2" id="usage2">Usage</a></h3>
+<div class="level3">
+<pre class="code">get_moz_enUS.py [options]</pre>
+
+<p>
+
+Options:
+</p>
+<table class="inline">
+	<tr class="row0">
+		<td class="col0"><code>-h</code>, <code>--help</code></td><td class="col1"> Show this help message and exit. </td>
+	</tr>
+	<tr class="row1">
+		<td class="col0"><code>-s SRCDIR</code>, <code>--src=SRCDIR</code></td><td class="col1"> The directory containing the Mozilla l10n sources. (default: <code>mozilla</code>) </td>
+	</tr>
+	<tr class="row2">
+		<td class="col0"><code>-d DESTDIR</code>, <code>--dest=DESTDIR</code></td><td class="col1"> The destination directory to copy the en-US locale files to. (default: <code>l10n</code>) </td>
+	</tr>
+	<tr class="row3">
+		<td class="col0"><code>-pMOZPRODUCT</code>, <code>--mozproduct=MOZPRODUCT</code></td><td class="col1"> The Mozilla product name. (default: <code>browser</code>) </td>
+	</tr>
+	<tr class="row4">
+		<td class="col0"><code>--delete-dest</code></td><td class="col1"> Delete the destination directory (if it exists). </td>
+	</tr>
+	<tr class="row5">
+		<td class="col0"><code>-v, --verbose</code></td><td class="col1"> Be more noisy. </td>
+	</tr>
+</table>
+
+</div>
+<!-- SECTION "Usage" [5151-5700] -->
+<h2><a name="moz-l10n-builder" id="moz-l10n-builder">moz-l10n-builder</a></h2>
+<div class="level2">
+
+<p>
+This is the pre-Mercurial build script originally written by Dwayne Bailey. This is the script that all the others on this page replaces for post-<acronym title="Concurrent Versions System">CVS</acronym> Mozilla l10n.
+</p>
+
+<p>
+<strong>Note</strong>: This script is <strong>not</strong> applicable to the l10n process of any Mozilla products after the move to Mercurial.
+</p>
+
+<p>
+For more information about this script see its dedicated <a href="toolkit-moz-l10n-builder.html" class="wikilink1" title="toolkit-moz-l10n-builder.html">wiki page</a>.
+</p>
+
+</div>
+<!-- SECTION "moz-l10n-builder" [5701-6111] -->
+<h2><a name="moz_l10n_builder.py" id="moz_l10n_builder.py">moz_l10n_builder.py</a></h2>
+<div class="level2">
+
+<p>
+This script was intended to be a simple and direct port of the <code>moz-l10n-builder</code> script from above. It has pro's and cons in comparison to the original, but is very similar for the most part. So for more information about this script, see the original script's <a href="toolkit-moz-l10n-builder.html" class="wikilink1" title="toolkit-moz-l10n-builder.html">wiki page</a>.
+
+</p>
+
+</div>
+<!-- SECTION "moz_l10n_builder.py" [6112-] --></body>
+</html>

Added: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-odf2xliff.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-odf2xliff.html?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-odf2xliff.html (added)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-odf2xliff.html Mon Dec 29 14:57:18 2008
@@ -1,0 +1,153 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+  <title></title>
+  <link rel="stylesheet" media="screen" type="text/css" href="./style.css" />
+  <link rel="stylesheet" media="screen" type="text/css" href="./design.css" />
+  <link rel="stylesheet" media="print" type="text/css" href="./print.css" />
+
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+</head>
+<body>
+<a href=.>start</a></br>
+
+
+
+<h1><a name="odf2xliff_and_xliff2odf" id="odf2xliff_and_xliff2odf">odf2xliff and xliff2odf</a></h1>
+<div class="level1">
+
+<p>
+
+Convert OpenDocument (ODF) files to <acronym title="XML Localization Interchange File Format">XLIFF</acronym> localization files. Create translated ODF files by combining the original ODF files with <acronym title="XML Localization Interchange File Format">XLIFF</acronym> files containing translations of strings in the original document.
+</p>
+
+<p>
+<acronym title="XML Localization Interchange File Format">XLIFF</acronym> is the <acronym title="Extensible Markup Language">XML</acronym> Localization Interchange File Format 
+developed by <a href="http://lisa.org/" class="urlextern" title="http://lisa.org/">LISA</a> (The Localization Industry Standards Authority) to allow translation
+work to be standardised no matter what the source format and to allow the work to be freely moved from tool to
+tool.
+</p>
+
+</div>
+<!-- SECTION "odf2xliff and xliff2odf" [1-525] -->
+<h2><a name="usage" id="usage">Usage</a></h2>
+<div class="level2">
+<pre class="code">odf2xliff [options] <original_odf> <xliff>
+xliff2odf [options] -t <original_odf> <xliff> <translated_odf></pre>
+
+<p>
+
+Where:
+</p>
+<table class="inline">
+	<tr class="row0">
+		<td class="col0"> <original_odf> </td><td class="col1 leftalign"> is an ODF document whose strings have to be translated  </td>
+	</tr>
+	<tr class="row1">
+		<td class="col0 leftalign"> <xliff>        </td><td class="col1"> is an <acronym title="XML Localization Interchange File Format">XLIFF</acronym> file </td>
+	</tr>
+	<tr class="row2">
+		<td class="col0"> <translated_odf> </td><td class="col1"> is an ODF file to generate by replacing the strings in <original_odf> with the translated strings in <xliff> </td>
+	</tr>
+</table>
+
+<p>
+
+Options (odf2xliff):
+
+</p>
+<table class="inline">
+	<tr class="row0">
+		<td class="col0 leftalign"> --version            </td><td class="col1 leftalign"> show program's version number and exit  </td>
+	</tr>
+	<tr class="row1">
+		<td class="col0 leftalign"> -h, --help           </td><td class="col1 leftalign"> show this help message and exit  </td>
+	</tr>
+	<tr class="row2">
+		<td class="col0 leftalign"> --manpage            </td><td class="col1 leftalign"> output a manpage based on the help  </td>
+	</tr>
+	<tr class="row3">
+		<td class="col0 leftalign"> <a href="toolkit-progress_progress.html" class="wikilink1" title="toolkit-progress_progress.html">--progress=PROGRESS</a>  </td><td class="col1 leftalign"> show progress as: dots, none, bar, names, verbose  </td>
+	</tr>
+	<tr class="row4">
+		<td class="col0 leftalign"> <a href="toolkit-errorlevel_errorlevel.html" class="wikilink1" title="toolkit-errorlevel_errorlevel.html">--errorlevel=ERRORLEVEL</a>  </td><td class="col1 leftalign"> show errorlevel as: none, message, exception, traceback  </td>
+	</tr>
+	<tr class="row5">
+		<td class="col0 leftalign"> -i INPUT, --input=INPUT   </td><td class="col1 leftalign"> read from INPUT in ODF format  </td>
+	</tr>
+	<tr class="row6">
+		<td class="col0 leftalign"> -o OUTPUT, --output=OUTPUT     </td><td class="col1 leftalign"> write to OUTPUT in <acronym title="XML Localization Interchange File Format">XLIFF</acronym> format  </td>
+	</tr>
+	<tr class="row7">
+		<td class="col0 leftalign"> <a href="toolkit-psyco_mode.html" class="wikilink1" title="toolkit-psyco_mode.html">--psyco=MODE</a>         </td><td class="col1 leftalign"> use psyco to speed up the operation, modes: none, full, profile  </td>
+	</tr>
+</table>
+
+<p>
+
+Options (xliff2odf):
+
+</p>
+<table class="inline">
+	<tr class="row0">
+		<td class="col0 leftalign"> --version            </td><td class="col1 leftalign"> show program's version number and exit    </td>
+	</tr>
+	<tr class="row1">
+		<td class="col0 leftalign"> -h, --help           </td><td class="col1 leftalign"> show this help message and exit    </td>
+	</tr>
+	<tr class="row2">
+		<td class="col0 leftalign"> --manpage            </td><td class="col1 leftalign"> output a manpage based on the help    </td>
+	</tr>
+	<tr class="row3">
+		<td class="col0 leftalign"> <a href="toolkit-progress_progress.html" class="wikilink1" title="toolkit-progress_progress.html">--progress=PROGRESS</a>  </td><td class="col1 leftalign"> show progress as: dots, none, bar, names, verbose    </td>
+	</tr>
+	<tr class="row4">
+		<td class="col0 leftalign"> <a href="toolkit-errorlevel_errorlevel.html" class="wikilink1" title="toolkit-errorlevel_errorlevel.html">--errorlevel=ERRORLEVEL</a>    </td><td class="col1 leftalign"> show errorlevel as: none, message, exception, traceback    </td>
+	</tr>
+	<tr class="row5">
+		<td class="col0 leftalign"> -i INPUT, --input=INPUT     </td><td class="col1 leftalign"> read from INPUT in <acronym title="XML Localization Interchange File Format">XLIFF</acronym> formats    </td>
+	</tr>
+	<tr class="row6">
+		<td class="col0 leftalign"> -o OUTPUT, --output=OUTPUT  </td><td class="col1 leftalign"> write to OUTPUT in ODF format    </td>
+	</tr>
+	<tr class="row7">
+		<td class="col0 leftalign"> -t TEMPLATE, --template=TEMPLATE   </td><td class="col1 leftalign"> read from TEMPLATE in ODF format    </td>
+	</tr>
+	<tr class="row8">
+		<td class="col0 leftalign"> <a href="toolkit-psyco_mode.html" class="wikilink1" title="toolkit-psyco_mode.html">--psyco=MODE</a>         </td><td class="col1 leftalign"> use psyco to speed up the operation, modes: none, full, profile    </td>
+	</tr>
+</table>
+
+</div>
+<!-- SECTION "Usage" [526-2259] -->
+<h2><a name="examples" id="examples">Examples</a></h2>
+<div class="level2">
+<pre class="code">odf2xliff english.odt english_français.xlf</pre>
+
+<p>
+
+Create an <acronym title="XML Localization Interchange File Format">XLIFF</acronym> file from an ODT file (the source ODF file could also be any of the other ODF files, including ODS, ODG, etc.). 
+
+</p>
+<pre class="code">xliff2odf -t english.odt english_français.xlf français.odt</pre>
+
+<p>
+
+Using english.odt as the template document, and english_français.xlf as the file of translations, create a translated file français.odt.
+</p>
+
+</div>
+<!-- SECTION "Examples" [2260-2662] -->
+<h2><a name="bugs" id="bugs">Bugs</a></h2>
+<div class="level2">
+
+<p>
+
+This filter is not yet extensively used… expect bugs.  See <a href="toolkit-xliff.html" class="wikilink1" title="toolkit-xliff.html">xliff</a> to see how well our implementation conforms to the standard.
+
+</p>
+
+</div>
+<!-- SECTION "Bugs" [2663-] --></body>
+</html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-php2po.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-php2po.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-php2po.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-php2po.html Mon Dec 29 14:57:18 2008
@@ -135,11 +135,43 @@
 
 </div>
 <!-- SECTION "Usage" [111-2295] -->
+<h2><a name="formats_supported" id="formats_supported">Formats Supported</a></h2>
+<div class="level2">
+
+<p>
+
+<acronym title="Hypertext Preprocessor">PHP</acronym> files need to be organized into separate languages per file and in the following format:
+
+</p>
+<pre class="code">$variable = 'string';</pre>
+
+<p>
+
+If $variable is an array it should be declared with the square bracket syntax.  For example, <code>$lang['var']</code>.
+</p>
+
+</div>
+<!-- SECTION "Formats Supported" [2296-2557] -->
+<h3><a name="unsupported" id="unsupported">Unsupported</a></h3>
+<div class="level3">
+
+<p>
+
+The converter does not support arrays in the form:
+</p>
+<pre class="code php"><span class="re1">$variable</span> <span class="sy0">=</span> <a href="http://www.php.net/array"><span class="kw3">array</span></a><span class="br0">(</span>
+   name <span class="sy0">=></span> <span class="st0">'value'</span><span class="sy0">,</span>
+<span class="br0">)</span></pre>
+<p>
+Gettext notations is also not supported, use the Gettext tools for those files.
+</p>
+
+</div>
+<!-- SECTION "Unsupported" [2558-2774] -->
 <h2><a name="examples" id="examples">Examples</a></h2>
 <div class="level2">
 
 <p>
-
 This example looks at roundtrip of <acronym title="Hypertext Preprocessor">PHP</acronym> translations as well as recovery of existing translations.
 </p>
 
@@ -185,15 +217,16 @@
 </p>
 
 </div>
-<!-- SECTION "Examples" [2296-3639] -->
+<!-- SECTION "Examples" [2775-4117] -->
 <h2><a name="issues" id="issues">Issues</a></h2>
 <div class="level2">
-
-<p>
-
-None known
-</p>
-
-</div>
-<!-- SECTION "Issues" [3640-] --></body>
+<ul>
+<li class="level1"><div class="li"> Support localisation variables using <code>array</code> is missing</div>
+</li>
+<li class="level1"><div class="li"> Proper escaping of single vs double quotes is missing. See <a href="http://bugs.locamotion.org/show_bug.cgi?id=593" class="interwiki iw_bug" title="http://bugs.locamotion.org/show_bug.cgi?id=593">593</a></div>
+</li>
+</ul>
+
+</div>
+<!-- SECTION "Issues" [4118-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-po2tmx.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-po2tmx.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-po2tmx.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-po2tmx.html Mon Dec 29 14:57:18 2008
@@ -95,8 +95,13 @@
 
 </div>
 <!-- SECTION "Examples" [1201-1372] -->
-<h2><a name="bugs" id="bugs">Bugs</a></h2>
+<h2><a name="bugs_and_issues" id="bugs_and_issues">Bugs and issues</a></h2>
 <div class="level2">
+
+</div>
+<!-- SECTION "Bugs and issues" [1373-1401] -->
+<h3><a name="markup_stripping" id="markup_stripping">Markup stripping</a></h3>
+<div class="level3">
 
 <p>
 
@@ -108,12 +113,30 @@
 </p>
 
 </div>
-<!-- SECTION "Bugs" [1373-1554] -->
+<!-- SECTION "Markup stripping" [1402-1593] -->
+<h3><a name="tmx_and_po_in_omegat" id="tmx_and_po_in_omegat">TMX and PO in OmegaT</a></h3>
+<div class="level3">
+
+<p>
+
+In some tools, like OmegaT, <acronym title="Gettext Portable Object">PO</acronym> files are parsed without expanding escaped sequences, even though such tools use <acronym title="Translation Memory eXchange">TMX</acronym> for translation memory.  Keep this in mind when using po2tmx, because po2tmx converts \n and \t to newlines and tabs in the <acronym title="Translation Memory eXchange">TMX</acronym> file.  If such a <acronym title="Translation Memory eXchange">TMX</acronym> file is used while translating <acronym title="Gettext Portable Object">PO</acronym> files in OmegaT, matching will be less than 100%.
+</p>
+
+<p>
+In other tools, such as Swordfish, the <acronym title="Gettext Portable Object">PO</acronym> comment “no-wrap” is interpreted in the same way as the equivalent function in <acronym title="Extensible Markup Language">XML</acronym>, which may also lead to mismatches if TMXes from po2tmx are used.
+</p>
+
+<p>
+There is nothing wrong with po2tmx, but if used in conjunction with tools that handle <acronym title="Gettext Portable Object">PO</acronym> files differently, it may lead to less than perfect matching.
+</p>
+
+</div>
+<!-- SECTION "TMX and PO in OmegaT" [1594-2319] -->
 <h2><a name="tips" id="tips">Tips</a></h2>
 <div class="level2">
 
 </div>
-<!-- SECTION "Tips" [1555-1572] -->
+<!-- SECTION "Tips" [2320-2337] -->
 <h3><a name="tmx_with_only_unique_segments" id="tmx_with_only_unique_segments">TMX with only unique segments</a></h3>
 <div class="level3">
 
@@ -139,7 +162,7 @@
 </p>
 
 </div>
-<!-- SECTION "TMX with only unique segments" [1573-2154] -->
+<!-- SECTION "TMX with only unique segments" [2338-2919] -->
 <h2><a name="the_toolkit_s_tmx_versus_other_tools" id="the_toolkit_s_tmx_versus_other_tools">The Toolkit's TMX versus other tools</a></h2>
 <div class="level2">
 
@@ -150,5 +173,5 @@
 </p>
 
 </div>
-<!-- SECTION "The Toolkit's TMX versus other tools" [2155-] --></body>
+<!-- SECTION "The Toolkit's TMX versus other tools" [2920-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-podebug.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-podebug.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-podebug.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-podebug.html Mon Dec 29 14:57:18 2008
@@ -19,8 +19,11 @@
 
 <p>
 
-Marks <acronym title="Gettext Portable Object">PO</acronym> messages so that it is easy to reference and locate strings when your
-translated application is running.
+Insert <a href="http://en.wikipedia.org/wiki/pseudo-translation" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/pseudo-translation">pseudo-translations</a> (also called <a href="http://en.wikipedia.org/wiki/pseudolocalization" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/pseudolocalization">pseudolocalization</a>) or debug markers into target text in <acronym title="XML Localization Interchange File Format">XLIFF</acronym>, Gettex <acronym title="Gettext Portable Object">PO</acronym> and other localization files.
+</p>
+
+<p>
+The pseudo translation or debig markers make it easy to reference and locate strings when your translated application is running.
 </p>
 
 <p>
@@ -31,10 +34,14 @@
 </li>
 <li class="level1"><div class="li"> Debug translations: if you know in what file the message occurs then you can quickly find it and fix it.</div>
 </li>
+<li class="level1"><div class="li"> Check that everything is translatable: any English only text needs to be analysed so that it can be localised.</div>
+</li>
+<li class="level1"><div class="li"> Check for Unicode compliance: by inserting Unicode text outside of the Latin range it allows you to check that your program can handle non-Latin correctly.</div>
+</li>
 </ul>
 
 </div>
-<!-- SECTION "podebug" [1-370] -->
+<!-- SECTION "podebug" [1-839] -->
 <h2><a name="usage" id="usage">Usage</a></h2>
 <div class="level2">
 <pre class="code">podebug [options] [-f format] <in> <out></pre>
@@ -48,10 +55,10 @@
 		<td class="col0 leftalign"> -f     </td><td class="col1 leftalign"> is an optional format strings.  The default format is ”[%s]”  </td>
 	</tr>
 	<tr class="row1">
-		<td class="col0 leftalign"> <in>   </td><td class="col1 leftalign"> is an input directory or <acronym title="Gettext Portable Object">PO</acronym> file  </td>
+		<td class="col0 leftalign"> <in>   </td><td class="col1 leftalign"> is an input directory or localisation file file  </td>
 	</tr>
 	<tr class="row2">
-		<td class="col0 leftalign"> <out>  </td><td class="col1 leftalign"> is an output directory or <acronym title="Gettext Portable Object">PO</acronym> files, if missing output will be to standard out.   </td>
+		<td class="col0 leftalign"> <out>  </td><td class="col1 leftalign"> is an output directory or localisation file, if missing output will be to standard out.   </td>
 	</tr>
 </table>
 
@@ -106,7 +113,7 @@
 </table>
 
 </div>
-<!-- SECTION "Usage" [371-1802] -->
+<!-- SECTION "Usage" [840-2295] -->
 <h2><a name="formats" id="formats">Formats</a></h2>
 <div class="level2">
 
@@ -162,7 +169,7 @@
 </p>
 
 </div>
-<!-- SECTION "Formats" [1803-2780] -->
+<!-- SECTION "Formats" [2296-3273] -->
 <h2><a name="rewriting_style" id="rewriting_style">Rewriting (style)</a></h2>
 <div class="level2">
 
@@ -176,7 +183,7 @@
 </p>
 
 </div>
-<!-- SECTION "Rewriting (style)" [2781-3420] -->
+<!-- SECTION "Rewriting (style)" [3274-3913] -->
 <h2><a name="ignoring_messages" id="ignoring_messages">Ignoring messages</a></h2>
 <div class="level2">
 
@@ -194,7 +201,7 @@
 </p>
 
 </div>
-<!-- SECTION "Ignoring messages" [3421-3975] -->
+<!-- SECTION "Ignoring messages" [3914-4468] -->
 <h2><a name="hashing" id="hashing">Hashing</a></h2>
 <div class="level2">
 
@@ -207,7 +214,7 @@
 </p>
 
 </div>
-<!-- SECTION "Hashing" [3976-4466] -->
+<!-- SECTION "Hashing" [4469-4959] -->
 <h2><a name="bugs" id="bugs">Bugs</a></h2>
 <div class="level2">
 
@@ -218,5 +225,5 @@
 </p>
 
 </div>
-<!-- SECTION "Bugs" [4467-] --></body>
+<!-- SECTION "Bugs" [4960-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-poen.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-poen.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-poen.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-poen.html Mon Dec 29 14:57:18 2008
@@ -19,6 +19,21 @@
 
 <p>
 
+<p><div class="notewarning">
+poen has been removed from Translate Toolkit > 1.2.  Rather use <a href="toolkit-podebug.html" class="wikilink1" title="toolkit-podebug.html">podebug</a> as follows:
+
+</p>
+<pre class="code">
+podebug --rewrite=en -f "" pot/ po/
+</pre>
+
+<p>
+
+
+</div></p>
+</p>
+
+<p>
 Initialises a directory English <acronym title="Gettext Portable Object">PO</acronym> files by taking <acronym title="Gettext Portable Object Template">POT</acronym> files and copying the msgid to the msgstr.  
 </p>
 
@@ -27,7 +42,7 @@
 </p>
 
 </div>
-<!-- SECTION "poen" [1-295] -->
+<!-- SECTION "poen" [1-458] -->
 <h2><a name="prerequisites" id="prerequisites">Prerequisites</a></h2>
 <div class="level2">
 
@@ -37,7 +52,7 @@
 </p>
 
 </div>
-<!-- SECTION "Prerequisites" [296-338] -->
+<!-- SECTION "Prerequisites" [459-501] -->
 <h2><a name="usage" id="usage">Usage</a></h2>
 <div class="level2">
 <pre class="code">poen [options] <pot> <en></pre>
@@ -70,7 +85,7 @@
 </table>
 
 </div>
-<!-- SECTION "Usage" [339-698] -->
+<!-- SECTION "Usage" [502-861] -->
 <h2><a name="bugs" id="bugs">Bugs</a></h2>
 <div class="level2">
 
@@ -81,5 +96,5 @@
 </p>
 
 </div>
-<!-- SECTION "Bugs" [699-] --></body>
+<!-- SECTION "Bugs" [862-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-posegment.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-posegment.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-posegment.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-posegment.html Mon Dec 29 14:57:18 2008
@@ -26,8 +26,12 @@
 This is useful for the creation of a file that can be used as a Translation Memory (e.g. when using <a href="pootle-updatetm.html" class="wikilink1" title="pootle-updatetm.html">updatetm</a> to create translation memory for Pootle) as you should get better matching after you have exposed translated sentences that might occur elsewhere in your work.
 </p>
 
+<p>
+Posegment won't do very advanced sentence boundary detection and alignment, but has customisations for the punctuation rules of several languages (Amharic, Afrikaans, Arabic, Armenian, Chinese, Greek, Japanese, Khmer, Oriya, Persian). For the purpose of increasing your TM (as described below), it is already very useful. Give it a try and help us to improve it even more for your language.
+</p>
+
 </div>
-<!-- SECTION "posegment" [1-443] -->
+<!-- SECTION "posegment" [1-834] -->
 <h2><a name="usage" id="usage">Usage</a></h2>
 <div class="level2">
 <pre class="code">posegment [options] <input> <segmented></pre>
@@ -92,7 +96,7 @@
 </table>
 
 </div>
-<!-- SECTION "Usage" [444-1580] -->
+<!-- SECTION "Usage" [835-1971] -->
 <h2><a name="examples" id="examples">Examples</a></h2>
 <div class="level2">
 
@@ -120,7 +124,7 @@
 </p>
 
 </div>
-<!-- SECTION "Examples" [1581-2164] -->
+<!-- SECTION "Examples" [1972-2555] -->
 <h2><a name="issues" id="issues">Issues</a></h2>
 <div class="level2">
 <ul>
@@ -133,5 +137,5 @@
 </ul>
 
 </div>
-<!-- SECTION "Issues" [2165-] --></body>
+<!-- SECTION "Issues" [2556-] --></body>
 </html>

Modified: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-poterminology.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-poterminology.html?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-poterminology.html (original)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-poterminology.html Mon Dec 29 14:57:18 2008
@@ -37,10 +37,11 @@
 <p>
 <p><div class="noteclassic">New in v1.2
 </div></p>
-</p>
-
-</div>
-<!-- SECTION "poterminology" [1-759] -->
+
+</p>
+
+</div>
+<!-- SECTION "poterminology" [1-756] -->
 <h2><a name="usage" id="usage">Usage</a></h2>
 <div class="level2">
 <pre class="code">poterminology [options] <input> <terminology></pre>
@@ -94,7 +95,7 @@
 		<td class="col0 leftalign"> <a href="toolkit-psyco_mode.html" class="wikilink1" title="toolkit-psyco_mode.html">--psyco=MODE</a>         </td><td class="col1 leftalign"> use psyco to speed up the operation, modes: none, full, profile  </td>
 	</tr>
 	<tr class="row10">
-		<td class="col0 leftalign"> -S STOPFILE, --stopword-list=STOPFILE  </td><td class="col1"> read stopword (term exclusion) list from STOPFILE (default site-packages/translate/share/stoplist-en) </td>
+		<td class="col0 leftalign"> -S STOPFILE, --stopword-list=STOPFILE  </td><td class="col1 leftalign"> read stopword (term exclusion) list from STOPFILE (default site-packages/translate/share/stoplist-en)  </td>
 	</tr>
 	<tr class="row11">
 		<td class="col0 leftalign"> -F, --fold-titlecase  </td><td class="col1 leftalign"> fold “Title Case” to lowercase (default)  </td>
@@ -106,7 +107,7 @@
 		<td class="col0 leftalign"> -I, --ignore-case     </td><td class="col1 leftalign"> make all terms lowercase  </td>
 	</tr>
 	<tr class="row14">
-		<td class="col0"> --accelerator=ACCELERATORS </td><td class="col1 leftalign"> ignores the given accelerator characters when matching  </td>
+		<td class="col0"> --accelerator=ACCELERATORS </td><td class="col1 leftalign"> ignores the given accelerator characters when matching (accelerator characters probably require quoting)  </td>
 	</tr>
 	<tr class="row15">
 		<td class="col0 leftalign"> -t LENGTH, --term-words=LENGTH  </td><td class="col1 leftalign"> generate terms of up to LENGTH words (default 3)  </td>
@@ -121,7 +122,7 @@
 		<td class="col0 leftalign"> --substr-needed=MIN   </td><td class="col1 leftalign"> omit substring-only terms appearing in less than MIN different messages (default 2)  </td>
 	</tr>
 	<tr class="row19">
-		<td class="col0 leftalign"> --locs-needed=MIN     </td><td class="col1 leftalign"> omit terms appearing in less than MIN different original source files (default 2)  </td>
+		<td class="col0 leftalign"> --locs-needed=MIN     </td><td class="col1 leftalign"> omit terms appearing in less than MIN different original program locations (default 2)  </td>
 	</tr>
 	<tr class="row20">
 		<td class="col0 leftalign"> --sort=ORDER          </td><td class="col1 leftalign"> output sort order(s): frequency, dictionary, length (default is all orders in the above priority)  </td>
@@ -135,7 +136,7 @@
 </table>
 
 </div>
-<!-- SECTION "Usage" [760-2982] -->
+<!-- SECTION "Usage" [757-3035] -->
 <h2><a name="examples" id="examples">Examples</a></h2>
 <div class="level2">
 
@@ -159,7 +160,8 @@
 Generating a terminology file containing automatically extracted translations is possible as well, by using <acronym title="Gettext Portable Object">PO</acronym> files with translations for the input files:
 
 </p>
-<pre class="code">poterminology Pootle/po/pootle/fi/*.po --output fi/pootle-terminology.po --sort dictionary</pre>
+<pre class="code">poterminology Pootle/po/pootle/fi/*.po --output fi/pootle-terminology.po \
+  --sort dictionary</pre>
 
 <p>
 
@@ -187,7 +189,7 @@
   Pootle/po/pootle/es/*.po Pootle/po/terminology/es/gnome/es.po</pre>
 
 </div>
-<!-- SECTION "Examples" [2983-5331] -->
+<!-- SECTION "Examples" [3036-5390] -->
 <h3><a name="reduced_terminology_glossaries" id="reduced_terminology_glossaries">Reduced terminology glossaries</a></h3>
 <div class="level3">
 
@@ -220,10 +222,11 @@
 
 <p>
 However, in the first example above (generating terminology for Pootle itself), the term “not exist” passes the stoplist and threshold filters, but all occurrences of this term also contained the term “does not exist” which also passes the stoplist and threshold filters.  Given this duplication, the shorter phrase is eliminated in favor of the longer one, resulting in 23 terms (out of 25 that pass the threshold filters).
-</p>
-
-</div>
-<!-- SECTION "Reduced terminology glossaries" [5332-7299] -->
+
+</p>
+
+</div>
+<!-- SECTION "Reduced terminology glossaries" [5391-7357] -->
 <h2><a name="reducing_output_terminology_with_thresholding_options" id="reducing_output_terminology_with_thresholding_options">Reducing output terminology with thresholding options</a></h2>
 <div class="level2">
 
@@ -265,7 +268,7 @@
 </p>
 
 <p>
-Not all <acronym title="Gettext Portable Object">PO</acronym>/<acronym title="Gettext Portable Object Template">POT</acronym> files contain proper location comments.  If your input files don't have (good) location comments and the output terminology file is reduced to zero or very few entries by thresholding, you may need to override the default value for this threshold and set it to 1, which disables this check.
+Not all <acronym title="Gettext Portable Object">PO</acronym>/<acronym title="Gettext Portable Object Template">POT</acronym> files contain proper location comments.  If your input files don't have (good) location comments and the output terminology file is reduced to zero or very few entries by thresholding, you may need to override the default value for this threshold and set it to 0, which disables this check.
 </p>
 
 <p>
@@ -291,7 +294,7 @@
 </p>
 
 </div>
-<!-- SECTION "Reducing output terminology with thresholding options" [7300-10589] -->
+<!-- SECTION "Reducing output terminology with thresholding options" [7358-10647] -->
 <h2><a name="stop_word_files" id="stop_word_files">Stop word files</a></h2>
 <div class="level2">
 
@@ -325,15 +328,20 @@
 
 <p>
 Note that if you are using multiple stopword list files, as in the above, they will all be subject to the same case mapping (fold “Title Case” to lower case by default) - if you specify a different case mapping in the second file it will override the mapping for all the stopword list files.
-</p>
-
-</div>
-<!-- SECTION "Stop word files" [10590-12147] -->
+
+</p>
+
+</div>
+<!-- SECTION "Stop word files" [10648-12203] -->
 <h2><a name="issues" id="issues">Issues</a></h2>
 <div class="level2">
 
 <p>
 
+When using poterminology on Windows systems, file globbing for input is not supported (unless you have a version of Python built with cygwin, which is not common).  On Windows, a command like “poterminology -o test.po podir/*.po” will fail with an error “No such file or directory: 'podir\\*.po'” instead of expanding the podir/*.po glob expression.  (This problem affects all Translate Toolkit command-line tools, not just poterminology.)  You can work around this problem by making sure that the directory does not contain any files (or subdirectories) that you do not want to use for input, and just giving the directory name as the argument, e.g. “poterminology -o test.po podir” for the case above.
+</p>
+
+<p>
 When using terminology files generated by poterminology as input, a plethora of translator comments marked with (poterminology) may be generated, with the number of these increasing on each iteration.  You may wish to run <a href="toolkit-pocommentclean.html" class="wikilink1" title="toolkit-pocommentclean.html">pocommentclean</a> (or a slightly modified version of it which only removes (poterminology) comments) on the input and/or output files, especially since translator comments are displayed as tooltips by Pootle (thankfully, they are truncated at a few dozen characters).
 </p>
 
@@ -342,6 +350,14 @@
 </p>
 
 <p>
+Default threshold settings may eliminate all output terms; in this case, poterminology should suggest threshold option settings that would allow output to be generated (this enhancement is tracked as “bug” <a href="http://bugs.locamotion.org/show_bug.cgi?id=582" class="interwiki iw_bug" title="http://bugs.locamotion.org/show_bug.cgi?id=582">582</a>).
+</p>
+
+<p>
+While poterminology ignores <acronym title="Extensible Markup Language">XML</acronym>/<acronym title="HyperText Markup Language">HTML</acronym> entities and elements and %-style format strings (for C and Python), it does not ignore all types of “variables” that may occur, particularly in OpenOffice.org, Mozilla, or Gnome localization files.  These other types should be ignored as well (this enhancement is tracked as “bug” <a href="http://bugs.locamotion.org/show_bug.cgi?id=598" class="interwiki iw_bug" title="http://bugs.locamotion.org/show_bug.cgi?id=598">598</a>).
+</p>
+
+<p>
 Terms containing only words that are ignored individually, but not excluded from phrases (e.g. “you are you”) may be generated by poterminology, but aren't generally useful.  Adding a new threshold option --nonstop-needed could allow these to be suppressed.
 </p>
 
@@ -355,8 +371,9 @@
 
 <p>
 A single execution of poterminology can only perform automatic translation extraction for a single target language - having the ability to handle all target languages in one run would allow a single command to generate all terminology for an entire project.  Additionally, this could provide even more information for identifying variant terms by comparing the number of target languages that have variant translations.
-</p>
-
-</div>
-<!-- SECTION "Issues" [12148-] --></body>
+
+</p>
+
+</div>
+<!-- SECTION "Issues" [12204-] --></body>
 </html>

Added: translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-pretranslate.html
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-pretranslate.html?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-pretranslate.html (added)
+++ translate-toolkit/branches/upstream/current/translate/doc/user/toolkit-pretranslate.html Mon Dec 29 14:57:18 2008
@@ -1,0 +1,151 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+  <title></title>
+  <link rel="stylesheet" media="screen" type="text/css" href="./style.css" />
+  <link rel="stylesheet" media="screen" type="text/css" href="./design.css" />
+  <link rel="stylesheet" media="print" type="text/css" href="./print.css" />
+
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+</head>
+<body>
+<a href=.>start</a></br>
+
+
+
+<h1><a name="pretranslate" id="pretranslate">pretranslate</a></h1>
+<div class="level1">
+
+<p>
+
+Merge existing translations from an old translation file to a new one as well as fill any missing translations from translation memory via fuzzy matching.
+</p>
+
+<p>
+This functionality used to be part of pot2po and corresponds to “msgmerge” from the gettext package.
+</p>
+
+<p>
+pretranslate works on <acronym title="Gettext Portable Object">PO</acronym> and <acronym title="XML Localization Interchange File Format">XLIFF</acronym> files.
+</p>
+
+</div>
+<!-- SECTION "pretranslate" [1-329] -->
+<h2><a name="usage" id="usage">Usage</a></h2>
+<div class="level2">
+<pre class="code">pretranslate [options] <input> <output></pre>
+
+<p>
+
+Where:
+</p>
+<table class="inline">
+	<tr class="row0">
+		<td class="col0 leftalign"> <input>  </td><td class="col1 leftalign"> is the translation file or directory to be pretranslate   </td>
+	</tr>
+	<tr class="row1">
+		<td class="col0 leftalign"> <output>   </td><td class="col1 leftalign"> is the translation file or a directory where the pretranslated version will be stored  </td>
+	</tr>
+</table>
+
+<p>
+
+Options:
+</p>
+<table class="inline">
+	<tr class="row0">
+		<td class="col0 leftalign"> --version            </td><td class="col1 leftalign"> show program's version number and exit  </td>
+	</tr>
+	<tr class="row1">
+		<td class="col0 leftalign"> -h, --help           </td><td class="col1 leftalign"> show this help message and exit   </td>
+	</tr>
+	<tr class="row2">
+		<td class="col0 leftalign"> --manpage            </td><td class="col1 leftalign"> output a manpage based on the help  </td>
+	</tr>
+	<tr class="row3">
+		<td class="col0 leftalign"> <a href="toolkit-progress_progress.html" class="wikilink1" title="toolkit-progress_progress.html">--progress=PROGRESS</a>  </td><td class="col1 leftalign"> show progress as: dots, none, bar, names, verbose  </td>
+	</tr>
+	<tr class="row4">
+		<td class="col0 leftalign"> <a href="toolkit-errorlevel_errorlevel.html" class="wikilink1" title="toolkit-errorlevel_errorlevel.html">--errorlevel=ERRORLEVEL</a>  </td><td class="col1 leftalign"> show errorlevel as: none, message, exception, traceback  </td>
+	</tr>
+	<tr class="row5">
+		<td class="col0 leftalign"> -iINPUT, --input=INPUT   </td><td class="col1 leftalign"> read from INPUT in pot format  </td>
+	</tr>
+	<tr class="row6">
+		<td class="col0 leftalign"> -xEXCLUDE, --exclude=EXCLUDE  </td><td class="col1 leftalign"> exclude names matching EXCLUDE from input paths  </td>
+	</tr>
+	<tr class="row7">
+		<td class="col0 leftalign"> -oOUTPUT, --output=OUTPUT     </td><td class="col1 leftalign"> write to OUTPUT in po, pot formats  </td>
+	</tr>
+	<tr class="row8">
+		<td class="col0 leftalign"> -tTEMPLATE, --template=TEMPLATE   </td><td class="col1"> read old translations from TEMPLATE </td>
+	</tr>
+	<tr class="row9">
+		<td class="col0 leftalign"> <a href="toolkit-psyco_mode.html" class="wikilink1" title="toolkit-psyco_mode.html">--psyco=MODE</a>         </td><td class="col1 leftalign"> use psyco to speed up the operation, modes: none, full, profile  </td>
+	</tr>
+	<tr class="row10">
+		<td class="col0 leftalign"> --tm=TM              </td><td class="col1 leftalign"> The file to use as translation memory when fuzzy matching     </td>
+	</tr>
+	<tr class="row11">
+		<td class="col0 leftalign"> -sMIN_SIMILARITY, --similarity=MIN_SIMILARITY   </td><td class="col1"> The minimum similarity for inclusion (default: 75%) </td>
+	</tr>
+	<tr class="row12">
+		<td class="col0 leftalign"> --nofuzzymatching    </td><td class="col1 leftalign"> Disable all fuzzy matching  </td>
+	</tr>
+</table>
+
+</div>
+<!-- SECTION "Usage" [330-1603] -->
+<h2><a name="examples" id="examples">Examples</a></h2>
+<div class="level2">
+<pre class="code">pretranslate -t zu-1.0.1 -tm zu_tm.po zu-2.0.2 zu-2.0.2-translated </pre>
+
+<p>
+
+Here we are pretranslating the <acronym title="Gettext Portable Object">PO</acronym> or <acronym title="XML Localization Interchange File Format">XLIFF</acronym> files in <em>zu-2.0.2</em> using the old translations in <em>zu-1.0.1</em> and fuzzy matches from the zu_tm.po 
+compendium. the result is stored in <em>zu-2.0.2-translate</em>
+</p>
+
+<p>
+unlike pot2po pretranslate will not change anything in the input file except merge translations, no reordering or changes to headers.
+</p>
+
+</div>
+<!-- SECTION "Examples" [1604-2036] -->
+<h2><a name="merging" id="merging">Merging</a></h2>
+<div class="level2">
+
+<p>
+
+It helps to understand when and how pretranslate will merge. The default is to follow msgmerge's behaviour but we add some extra features with fuzzy matching:
+
+</p>
+<ul>
+<li class="level1"><div class="li"> If everything matches we carry that across</div>
+</li>
+<li class="level1"><div class="li"> We can resurrect obsolete messages for reuse</div>
+</li>
+<li class="level1"><div class="li"> If we cannot find a match we will first look through the current and obsolete messages and then through any global translation memory</div>
+</li>
+<li class="level1"><div class="li"> Fuzzy matching makes use of the <a href="toolkit-levenshtein_distance.html" class="wikilink1" title="toolkit-levenshtein_distance.html">Levenshtein distance</a> algorithm to detect the best matches</div>
+</li>
+</ul>
+
+</div>
+<!-- SECTION "Merging" [2037-2551] -->
+<h2><a name="performance" id="performance">Performance</a></h2>
+<div class="level2">
+
+<p>
+
+Fuzzy matches are usually of good quality. Installation of the <a href="https://sourceforge.net/project/showfiles.php?group_id=91920&package_id=260161" class="urlextern" title="https://sourceforge.net/project/showfiles.php?group_id=91920&package_id=260161">python-Levenshtein</a> package will speed up fuzzy matching. Without this a Python based matcher is used which is considerably slower.
+</p>
+
+<p>
+Install psyco for additional speedup (it is used by most toolkit tools if it is installed.)
+</p>
+
+</div>
+<!-- SECTION "Performance" [2552-] --></body>
+</html>

Added: translate-toolkit/branches/upstream/current/translate/lang/bn.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/lang/bn.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/lang/bn.py (added)
+++ translate-toolkit/branches/upstream/current/translate/lang/bn.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,32 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# 
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""This module represents Bengali language.
+
+For more information, see U{http://en.wikipedia.org/wiki/Bengali_language}
+"""
+
+from translate.lang import common
+
+class bn(common.Common):
+    """This class represents Bengali."""
+
+    ignoretests = ["startcaps", "simplecaps"]

Added: translate-toolkit/branches/upstream/current/translate/lang/kn.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/lang/kn.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/lang/kn.py (added)
+++ translate-toolkit/branches/upstream/current/translate/lang/kn.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,32 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# 
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""This module represents Kannada language.
+
+For more information, see U{http://en.wikipedia.org/wiki/Kannada_language}
+"""
+
+from translate.lang import common
+
+class kn(common.Common):
+    """This class represents Kannada."""
+
+    ignoretests = ["startcaps", "simplecaps"]

Added: translate-toolkit/branches/upstream/current/translate/lang/te.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/lang/te.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/lang/te.py (added)
+++ translate-toolkit/branches/upstream/current/translate/lang/te.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,32 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# 
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""This module represents Telugu language.
+
+For more information, see U{http://en.wikipedia.org/wiki/Telugu_language}
+"""
+
+from translate.lang import common
+
+class te(common.Common):
+    """This class represents Telugu."""
+
+    ignoretests = ["startcaps", "simplecaps"]

Added: translate-toolkit/branches/upstream/current/translate/misc/context.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/misc/context.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/misc/context.py (added)
+++ translate-toolkit/branches/upstream/current/translate/misc/context.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,48 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2002-2006 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+import sys
+
+def with_(mgr, body):
+    """A function to mimic the with statement introduced in Python 2.5
+    
+    The code below was taken from http://www.python.org/dev/peps/pep-0343/
+    """
+    exit = mgr.__exit__  # Not calling it yet
+    value = mgr.__enter__()
+    exc = True
+    try:
+        try:
+            if isinstance(value, (tuple, list)):
+                return body(*value)
+            else:
+                return body(value)
+        except:
+            # The exceptional case is handled here
+            exc = False
+            if not exit(*sys.exc_info()):
+                raise
+            # The exception is swallowed if exit() returns true
+    finally:
+        # The normal and non-local-goto cases are handled here
+        if exc:
+            exit(None, None, None)

Added: translate-toolkit/branches/upstream/current/translate/misc/contextlib.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/misc/contextlib.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/misc/contextlib.py (added)
+++ translate-toolkit/branches/upstream/current/translate/misc/contextlib.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,184 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2002-2006 Zuza Software Foundation
+# 
+# This file is part of translate.
+# The file was copied from the Python 2.5 source.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+# NB! IMPORTANT SEMANTIC DIFFERENCE WITH THE OFFICIAL contextlib.
+# In Python 2.5+, if an exception is thrown in a 'with' statement
+# which uses a generator-based context manager (that is, a
+# context manager created by decorating a generator with
+# @contextmanager), the exception will be propagated to the 
+# generator via the .throw method of the generator.
+#
+# This does not exist in Python 2.4. Thus, we just naively finish
+# off the context manager. This also means that generator-based
+# context managers can't deal with exceptions, so be warned.
+
+"""Utilities for with-statement contexts.  See PEP 343."""
+
+import sys
+
+__all__ = ["contextmanager", "nested", "closing"]
+
+class GeneratorContextManager(object):
+    """Helper for @contextmanager decorator."""
+
+    def __init__(self, gen):
+        self.gen = gen
+
+    def __enter__(self):
+        try:
+            return self.gen.next()
+        except StopIteration:
+            raise RuntimeError("generator didn't yield")
+
+    def __exit__(self, type, value, tb):
+        if type is None:
+            try:
+                self.gen.next()
+            except StopIteration:
+                return
+            else:
+                raise RuntimeError("generator didn't stop")
+        else:            
+            if value is None:
+                # Need to force instantiation so we can reliably
+                # tell if we get the same exception back
+                value = type()
+            try:
+                try:
+                    self.gen.next()
+                except StopIteration:
+                    import traceback
+                    traceback.print_exception(type, value, tb)
+                    raise value
+            except StopIteration, exc:
+                # Suppress the exception *unless* it's the same exception that
+                # was passed to throw().  This prevents a StopIteration
+                # raised inside the "with" statement from being suppressed
+                return exc is not value
+
+def contextmanager(func):
+    """@contextmanager decorator.
+
+    Typical usage:
+
+        @contextmanager
+        def some_generator(<arguments>):
+            <setup>
+            try:
+                yield <value>
+            finally:
+                <cleanup>
+
+    This makes this:
+
+        with some_generator(<arguments>) as <variable>:
+            <body>
+
+    equivalent to this:
+
+        <setup>
+        try:
+            <variable> = <value>
+            <body>
+        finally:
+            <cleanup>
+
+    """
+    def helper(*args, **kwds):
+        return GeneratorContextManager(func(*args, **kwds))
+    try:
+        helper.__name__ = func.__name__
+        helper.__doc__ = func.__doc__
+        helper.__dict__ = func.__dict__
+    except:
+        pass
+    return helper
+
+
+ at contextmanager
+def nested(*managers):
+    """Support multiple context managers in a single with-statement.
+
+    Code like this:
+
+        with nested(A, B, C) as (X, Y, Z):
+            <body>
+
+    is equivalent to this:
+
+        with A as X:
+            with B as Y:
+                with C as Z:
+                    <body>
+
+    """
+    exits = []
+    vars = []
+    exc = (None, None, None)
+
+    try:
+        for mgr in managers:
+            exit = mgr.__exit__
+            enter = mgr.__enter__
+            vars.append(enter())
+            exits.append(exit)
+        yield vars
+    except:
+        exc = sys.exc_info()
+
+    while exits:
+        exit = exits.pop()
+        try:
+            if exit(*exc):
+                exc = (None, None, None)
+        except:
+            exc = sys.exc_info()
+    if exc != (None, None, None):
+        # Don't rely on sys.exc_info() still containing
+        # the right information. Another exception may
+        # have been raised and caught by an exit method
+        raise exc[0], exc[1], exc[2]
+
+class closing(object):
+    """Context to automatically close something at the end of a block.
+
+    Code like this:
+
+        with closing(<module>.open(<arguments>)) as f:
+            <block>
+
+    is equivalent to this:
+
+        f = <module>.open(<arguments>)
+        try:
+            <block>
+        finally:
+            f.close()
+
+    """
+    def __init__(self, thing):
+        self.thing = thing
+    def __enter__(self):
+        return self.thing
+    def __exit__(self, *exc_info):
+        self.thing.close()

Added: translate-toolkit/branches/upstream/current/translate/misc/file_discovery.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/misc/file_discovery.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/misc/file_discovery.py (added)
+++ translate-toolkit/branches/upstream/current/translate/misc/file_discovery.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,54 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+__all__ = ['get_abs_data_filename']
+
+import sys
+import os
+
+def get_abs_data_filename(path_parts):
+    """Get the absolute path to the given file- or directory name in the current
+    running application's data directory.
+
+        @type  path_parts: list
+        @param path_parts: The path parts that can be joined by os.path.join().
+    """
+
+    if isinstance(path_parts, str):
+        path_parts = [path_parts]
+
+    BASE_DIRS = [
+        os.path.dirname(unicode(__file__, sys.getfilesystemencoding())),
+        os.path.dirname(unicode(sys.executable, sys.getfilesystemencoding()))
+    ]
+
+    DATA_DIRS = [
+        ["..", "share"],
+        ["share"]
+    ]
+
+    for basepath, data_dir in ((x, y) for x in BASE_DIRS for y in DATA_DIRS):
+        dir_and_filename = data_dir + path_parts
+        datafile = os.path.join(basepath or os.path.dirname(__file__), *dir_and_filename)
+        if os.path.exists(datafile):
+            return datafile
+    raise Exception('Could not find "%s"' % (os.path.join(*path_parts)))

Added: translate-toolkit/branches/upstream/current/translate/misc/rich.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/misc/rich.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/misc/rich.py (added)
+++ translate-toolkit/branches/upstream/current/translate/misc/rich.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# 
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+__all__ = ['only_strings', 'map_rich']
+
+from translate.storage.placeables import Placeable
+
+def map_content(f, chunk):
+    """If chunk is a Placeable and it has content, we need
+    to modify the content as well.
+
+    Note that this is NOT a pure function. For that, we would
+    need to copy the placeables themselves."""
+    if isinstance(chunk, Placeable):
+        if chunk.content is not None:
+            chunk.content = map_entry(f, chunk.content)
+    return chunk
+
+def map_entry(f, chunk_seq):
+    """Transform every chunk in chunk_seq with the function f,
+    including the inner content of any placeables."""
+    return [f(map_content(f, chunk)) for chunk in chunk_seq]
+
+def only_strings(f):
+    """A decorator to ensure that f is only applied to strings
+    and not Placeables. It's used to decorate the function
+    passed to map_rich."""
+    def decorated_f(arg):
+        if not isinstance(arg, Placeable):
+            return f(arg)
+        else:
+            return arg
+    return decorated_f
+
+def map_rich(f, rich_string):
+    """Return a new list of chunk sequences, where each chunk
+    sequence has f applied to it."""
+    return [map_entry(f, entry) for entry in rich_string]

Added: translate-toolkit/branches/upstream/current/translate/misc/typecheck/__init__.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/misc/typecheck/__init__.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/misc/typecheck/__init__.py (added)
+++ translate-toolkit/branches/upstream/current/translate/misc/typecheck/__init__.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,1559 @@
+__all__ = ['accepts', 'returns', 'yields', 'TypeCheckError', 'Length', 'Empty'
+          ,'TypeSignatureError', 'And', 'Any', 'Class', 'Exact', 'HasAttr'
+          ,'IsAllOf', 'IsCallable', 'IsIterable', 'IsNoneOf', 'IsOneOf'
+          ,'IsOnlyOneOf', 'Not', 'Or', 'Self', 'Xor', 'YieldSeq'
+          ,'register_type', 'is_registered_type', 'unregister_type'
+          ,'Function']
+
+import inspect
+import types
+
+from types import GeneratorType, FunctionType, MethodType, ClassType, TypeType
+
+# Controls whether typechecking is on (True) or off (False)
+enable_checking = True
+
+# Pretty little wrapper function around __typecheck__
+def check_type(type, func, val):
+    type.__typecheck__(func, val)
+
+### Internal exception classes (these MUST NOT get out to the user)
+### typecheck_{args,return,yield} should catch these and convert them to
+### appropriate Type{Check,Signature}Error instances
+
+# We can't inherit from object because raise doesn't like new-style classes
+# We can't use super() because we can't inherit from object
+class _TC_Exception(Exception):
+    def error_message(self):
+        raise NotImplementedError("Incomplete _TC_Exception subclass (%s)" % str(self.__class__))
+        
+    def format_bad_object(self, bad_object):
+        return ("for %s, " % str(bad_object), self)
+
+class _TC_LengthError(_TC_Exception):
+    def __init__(self, wrong, right=None):
+        _TC_Exception.__init__(self)
+    
+        self.wrong = wrong
+        self.right = right
+        
+    def error_message(self):
+        m = None
+        if self.right is not None:
+            m = ", expected %d" % self.right
+        return "length was %d%s" % (self.wrong, m or "")
+        
+class _TC_TypeError(_TC_Exception):
+    def __init__(self, wrong, right):
+        _TC_Exception.__init__(self)
+    
+        self.wrong = calculate_type(wrong)
+        self.right = right
+        
+    def error_message(self):
+        return "expected %s, got %s" % (self.right, self.wrong)
+
+class _TC_NestedError(_TC_Exception):
+    def __init__(self, inner_exception):
+        self.inner = inner_exception
+    
+    def error_message(self):
+        try:
+            return ", " + self.inner.error_message()
+        except:
+            print "'%s'" % self.inner.message
+            raw_input()
+            raise
+
+class _TC_IndexError(_TC_NestedError):
+    def __init__(self, index, inner_exception):
+        _TC_NestedError.__init__(self, inner_exception)
+    
+        self.index = index
+        
+    def error_message(self):
+        return ("at index %d" % self.index) + _TC_NestedError.error_message(self)
+
+# _TC_DictError exists as a wrapper around dict-related exceptions.
+# It provides a single place to sort the bad dictionary's keys in the error
+# message.
+class _TC_DictError(_TC_NestedError):
+    def format_bad_object(self, bad_object):
+        message = "for {%s}, " % ', '.join(["%s: %s" % (repr(k), repr(bad_object[k])) for k in sorted(bad_object.keys())])
+        
+        if not isinstance(self.inner, _TC_LengthError):
+            return (message, self)
+        return (message, self.inner)
+        
+    def error_message(self):
+        raise NotImplementedError("Incomplete _TC_DictError subclass: " + str(self.__class__))
+
+class _TC_KeyError(_TC_DictError):
+    def __init__(self, key, inner_exception):
+        _TC_NestedError.__init__(self, inner_exception)
+        
+        self.key = key
+
+    def error_message(self):
+        return ("for key %s" % repr(self.key)) + _TC_NestedError.error_message(self)
+        
+class _TC_KeyValError(_TC_KeyError):
+    def __init__(self, key, val, inner_exception):
+        _TC_KeyError.__init__(self, key, inner_exception)
+
+        self.val = val
+        
+    def error_message(self):
+        return ("at key %s, value %s" % (repr(self.key), repr(self.val))) + _TC_NestedError.error_message(self)
+        
+class _TC_GeneratorError(_TC_NestedError):
+    def __init__(self, yield_no, inner_exception):
+        _TC_NestedError.__init__(self, inner_exception)
+        
+        self.yield_no = yield_no
+        
+    def error_message(self):
+        raise RuntimeError("_TC_GeneratorError.message should never be called")
+        
+    def format_bad_object(self, bad_object):
+        bad_obj, start_message = self.inner.format_bad_object(bad_object)
+        message = "At yield #%d: %s" % (self.yield_no, bad_obj)
+        return (message, start_message)
+
+### These next three exceptions exist to give HasAttr better error messages     
+class _TC_AttrException(_TC_Exception):
+    def __init__(self, attr):
+        _TC_Exception.__init__(self, attr)
+        
+        self.attr = attr
+
+class _TC_AttrError(_TC_AttrException, _TC_NestedError):
+    def __init__(self, attr, inner_exception):
+        _TC_AttrException.__init__(self, attr)
+        _TC_NestedError.__init__(self, inner_exception)
+        
+    def error_message(self):
+        return ("as for attribute %s" % self.attr) + _TC_NestedError.error_message(self)
+        
+class _TC_MissingAttrError(_TC_AttrException):
+    def error_message(self):
+        return "missing attribute %s" % self.attr
+
+# This is like _TC_LengthError for YieldSeq     
+class _TC_YieldCountError(_TC_Exception):
+    def __init__(self, expected):
+        _TC_Exception.__init__(self, expected)
+        
+        self.expected = expected
+        
+    def format_bad_object(self, bad_object):
+        return ("", self)
+        
+    def error_message(self):
+        plural = "s"
+        if self.expected == 1:
+            plural = ""
+        
+        return "only expected the generator to yield %d time%s" % (self.expected, plural)
+
+# This exists to provide more detailed error messages about why a given
+# Xor() assertion failed
+class _TC_XorError(_TC_NestedError):
+    def __init__(self, matched_conds, inner_exception):
+        assert matched_conds in (0, 2)
+        assert isinstance(inner_exception, _TC_TypeError)
+        
+        _TC_Exception.__init__(self, matched_conds, inner_exception)
+        _TC_NestedError.__init__(self, inner_exception)
+        self.matched_conds = matched_conds
+        
+    def error_message(self):
+        if self.matched_conds == 0:
+            m = "neither assertion"
+        else:
+            m = "both assertions"
+    
+        return _TC_NestedError.error_message(self) + " (matched %s)" % m
+        
+class _TC_FunctionError(_TC_Exception):
+    def __init__(self, checking_func, obj):
+        self.checking_func = checking_func
+        self.rejected_obj = obj
+        
+    def error_message(self):
+        return " was rejected by %s" % self.checking_func
+        
+    def format_bad_object(self, bad_object):
+        return (str(bad_object), self)
+        
+class _TC_ExactError(_TC_Exception):
+    def __init__(self, wrong, right):
+        self.wrong = wrong
+        self.right = right
+        
+    def error_message(self):
+        return "expected %s, got %s" % (self.right, self.wrong)
+
+### The following exist to provide detailed TypeSignatureErrors
+class _TS_Exception(Exception):
+    def error_message(self):
+        raise NotImplementedError("Incomplete _TS_Exception subclass (%s)" % str(self.__class__))
+
+# This is used when there was an error related to an auto-unpacked tuple
+# in the function's signature
+class _TS_TupleError(_TS_Exception):
+    def __init__(self, parameters, types):
+        parameters = _rec_tuple(parameters)
+        types = _rec_tuple(types)
+        _TS_Exception.__init__(self, parameters, types)
+        
+        self.parameters = parameters
+        self.types = types
+        
+    def error_message(self):
+        return "the signature type %s does not match %s" % (str(self.types), str(self.parameters))
+        
+class _TS_ExtraKeywordError(_TS_Exception):
+    def __init__(self, keyword):
+        _TS_Exception.__init__(self, keyword)
+        
+        self.keyword = keyword
+        
+    def error_message(self):
+        return "the keyword '%s' in the signature is not in the function" % self.keyword
+        
+class _TS_ExtraPositionalError(_TS_Exception):
+    def __init__(self, type):
+        _TS_Exception.__init__(self, type)
+        
+        self.type = type
+        
+    def error_message(self):
+        return "an extra positional type has been supplied"
+    
+class _TS_MissingTypeError(_TS_Exception):
+    def __init__(self, parameter):
+        _TS_Exception.__init__(self, parameter)
+        
+        self.parameter = parameter
+        
+    def error_message(self):
+        return "parameter '%s' lacks a type" % self.parameter
+
+# If the user has given a keyword parameter a type both positionally and
+# with a keyword argument, this will be raised      
+class _TS_TwiceTypedError(_TS_Exception):
+    def __init__(self, parameter, kw_type, pos_type):
+        _TS_Exception.__init__(self, parameter, kw_type, pos_type)
+        
+        self.parameter = parameter
+        self.kw_type = kw_type
+        self.pos_type = pos_type
+        
+    def error_message(self):
+        return "parameter '%s' is provided two types (%s and %s)" % (self.parameter, str(self.kw_type), str(self.pos_type))
+
+### The following functions are the way new type handlers are registered
+### The Type function will iterate over all registered type handlers;
+### the first handler to return a non-None value is considered the winner
+#########################################################################
+
+_hooks = ("__typesig__", "__startchecking__", "__stopchecking__", "__switchchecking__")
+
+_registered_types = set()
+_registered_hooks = dict([(_h, set()) for _h in _hooks])
+
+def _manage_registration(add_remove, reg_type):
+    if not isinstance(reg_type, (types.ClassType, types.TypeType)):
+        raise ValueError("registered types must be classes or types")
+    
+    valid = False
+    for hook in _hooks:
+        if hasattr(reg_type, hook):
+            getattr(_registered_hooks[hook], add_remove)(reg_type)
+            valid = True
+
+    if valid:
+        getattr(_registered_types, add_remove)(reg_type)
+    else:
+        raise ValueError("registered types must have at least one of the following methods: " + ", ".join(_hooks))
+
+def register_type(reg_type):
+    _manage_registration('add', reg_type)
+    
+def unregister_type(reg_type):
+    _manage_registration('remove', reg_type)
+    
+def is_registered_type(reg_type):
+    return reg_type in _registered_types
+
+### Factory function; this is what should be used to dispatch
+### type-checker class requests
+
+def Type(obj):
+    # Note that registered types cannot count on being run in a certain order;
+    # their __typesig__ methods must be sufficiently flexible to account for
+    # this
+    for reg_type in _registered_hooks['__typesig__']:
+        v = reg_type.__typesig__(obj)
+        if v is not None:
+            return v
+
+    raise AssertionError("Object is of type '%s'; not a type" % str(type(obj)))
+
+def __checking(start_stop, *args):
+    attr = '__%schecking__' % start_stop
+
+    for reg_type in _registered_hooks[attr]:
+        getattr(reg_type, attr)(*args)
+    
+def start_checking(function):
+    __checking('start', function)
+
+def stop_checking(function):
+    __checking('stop', function)
+    
+def switch_checking(from_func, to_func):
+    for reg_type in _registered_types:
+        if hasattr(reg_type, '__switchchecking__'):
+            getattr(reg_type, '__switchchecking__')(from_func, to_func)
+        else:
+            if hasattr(reg_type, '__stopchecking__'):
+                getattr(reg_type, '__stopchecking__')(from_func)
+            if hasattr(reg_type, '__startchecking__'):
+                getattr(reg_type, '__startchecking__')(to_func)
+
+### Deduce the type of a data structure
+###
+### XXX: Find a way to allow registered utility classes
+### to hook into this
+def calculate_type(obj):
+    if isinstance(obj, types.InstanceType):
+        return obj.__class__
+    elif isinstance(obj, dict):
+        if len(obj) == 0:
+            return {}
+
+        key_types = set()
+        val_types = set()
+        
+        for (k,v) in obj.items():
+            key_types.add( calculate_type(k) )
+            val_types.add( calculate_type(v) )
+            
+        if len(key_types) == 1:
+            key_types = key_types.pop()
+        else:
+            key_types = Or(*key_types)
+            
+        if len(val_types) == 1:
+            val_types = val_types.pop()
+        else:
+            val_types = Or(*val_types)
+            
+        return {key_types: val_types}
+    elif isinstance(obj, tuple):
+        return tuple([calculate_type(t) for t in obj])
+    elif isinstance(obj, list):
+        length = len(obj)
+        if length == 0:
+            return []
+        obj = [calculate_type(o) for o in obj]
+
+        partitions = [1]
+        partitions.extend([i for i in range(2, int(length/2)+1) if length%i==0])
+        partitions.append(length)
+
+        def evaluate(items_per):
+            parts = length / items_per
+
+            for i in range(0, parts):
+                for j in range(0, items_per):
+                    if obj[items_per * i + j] != obj[j]:
+                        raise StopIteration
+            return obj[0:items_per]
+
+        for items_per in partitions:
+            try:
+                return evaluate(items_per)
+            except StopIteration:
+                continue
+    else:
+        return type(obj)
+
+### The following classes are the work-horses of the typechecker
+
+# The base class for all the other utility classes
+class CheckType(object):
+    def __repr__(self):
+        return type(self).name + '(' + ', '.join(sorted(repr(t) for t in self._types)) + ')'
+
+    __str__ = __repr__
+
+    def __eq__(self, other):
+        return not self != other
+        
+    def __ne__(self, other):
+        return not self == other
+
+    def __hash__(self):
+        raise NotImplementedError("Incomplete CheckType subclass: %s" % self.__class__)
+    
+    def __typecheck__(self, func, obj):
+        raise NotImplementedError("Incomplete CheckType subclass: %s" % self.__class__)
+    
+    @classmethod
+    def __typesig__(cls, obj):
+        if isinstance(obj, CheckType):
+            return obj
+            
+class Single(CheckType):
+    name = "Single"
+
+    def __init__(self, type):
+        if not isinstance(type, (types.ClassType, types.TypeType)):
+            raise TypeError("Cannot type-check a %s" % type(type))
+        else:
+            self.type = type
+            
+        self._types = [self.type]
+
+    def __typecheck__(self, func, to_check):
+        if not isinstance(to_check, self.type):
+            raise _TC_TypeError(to_check, self.type)
+        
+    def __eq__(self, other):
+        if other.__class__ is not self.__class__:
+            return False
+        return self.type == other.type
+        
+    def __hash__(self):
+        return hash(str(hash(self.__class__)) + str(hash(self.type)))
+    
+    # XXX Is this really a good idea?
+    # Removing this only breaks 3 tests; that seems suspiciously low
+    def __repr__(self):
+        return repr(self.type)
+        
+    @classmethod
+    def __typesig__(cls, obj):
+        if isinstance(obj, (types.ClassType, types.TypeType)):
+            return Single(obj)
+
+### Provide a way to enforce the empty-ness of iterators    
+class Empty(Single):
+    name = "Empty"
+    
+    def __init__(self, type):
+        if not hasattr(type, '__len__'):
+            raise TypeError("Can only assert emptyness for types with __len__ methods")
+        
+        Single.__init__(self, type)
+
+    def __typecheck__(self, func, to_check):
+        Single.__typecheck__(self, func, to_check)
+        
+        if len(to_check) > 0:
+            err = _TC_LengthError(len(to_check), 0)
+            if isinstance(to_check, dict):
+                raise _TC_DictError(err)
+            raise err
+
+class Dict(CheckType):
+    name = "Dict"
+
+    def __init__(self, key, val):
+        self.__check_key = Type(key)
+        self.__check_val = Type(val)
+        
+        self.type = {key: val}
+        self._types = [key, val]
+        
+    def __typecheck__(self, func, to_check):
+        if not isinstance(to_check, types.DictType):
+            raise _TC_TypeError(to_check, self.type)
+        
+        for (k, v) in to_check.items():
+            # Check the key
+            try:
+                check_type(self.__check_key, func, k)
+            except _TC_Exception, inner:
+                raise _TC_KeyError(k, inner)
+
+            # Check the value
+            try:
+                check_type(self.__check_val, func, v)
+            except _TC_Exception, inner:
+                raise _TC_KeyValError(k, v, inner)
+        
+    def __eq__(self, other):
+        if other.__class__ is not self.__class__:
+            return False
+        return self.type == other.type
+        
+    def __hash__(self):
+        cls = self.__class__
+        key = self.__check_key
+        val = self.__check_val
+        
+        def strhash(obj):
+            return str(hash(obj))
+    
+        return hash(''.join(map(strhash, [cls, key, val])))
+    
+    @classmethod
+    def __typesig__(cls, obj):
+        if isinstance(obj, dict):
+            if len(obj) == 0:
+                return Empty(dict)
+            return Dict(obj.keys()[0], obj.values()[0])
+
+### Provide typechecking for the built-in list() type
+class List(CheckType):
+    name = "List"
+
+    def __init__(self, *type):
+        self._types = [Type(t) for t in type]
+        self.type = [t.type for t in self._types]
+
+    def __typecheck__(self, func, to_check):
+        if not isinstance(to_check, list):
+            raise _TC_TypeError(to_check, self.type)
+        if len(to_check) % len(self._types):
+            raise _TC_LengthError(len(to_check))
+        
+        # lists can be patterned, meaning that [int, float]
+        # requires that the to-be-checked list contain an alternating
+        # sequence of integers and floats. The pattern must be completed
+        # (e.g, [5, 5.0, 6, 6.0] but not [5, 5.0, 6]) for the list to
+        # typecheck successfully.
+        #
+        # A list with a single type, [int], is a sub-case of patterned
+        # lists
+        #
+        # XXX: Investigate speed increases by special-casing single-typed
+        # lists 
+        pat_len = len(self._types)
+        type_tuples = [(i, val, self._types[i % pat_len]) for (i, val)
+                    in enumerate(to_check)]
+        for (i, val, type) in type_tuples:
+            try:
+                check_type(type, func, val)
+            except _TC_Exception, e:
+                raise _TC_IndexError(i, e)
+        
+    def __eq__(self, other):
+        if other.__class__ is not self.__class__:
+            return False
+            
+        if len(self._types) != len(other._types):
+            return False
+        
+        for (s, o) in zip(self._types, other._types):
+            if s != o:
+                return False
+        return True
+        
+    def __hash__(self):
+        def strhash(obj):
+            return str(hash(obj))
+            
+        return hash(''.join(map(strhash, [self.__class__] + self._types)))
+    
+    @classmethod    
+    def __typesig__(cls, obj):
+        if isinstance(obj, list):
+            if len(obj) == 0:
+                return Empty(list)
+            return List(*obj)
+
+### Provide typechecking for the built-in tuple() class
+class Tuple(List):
+    name = "Tuple"
+
+    def __init__(self, *type):
+        List.__init__(self, *type)
+        
+        self.type = tuple(self.type)
+
+    def __typecheck__(self, func, to_check):
+        # Note that tuples of varying length (e.g., (int, int) and (int, int, int))
+        # are separate types, not merely differences in length like lists
+        if not isinstance(to_check, types.TupleType) or len(to_check) != len(self._types):
+            raise _TC_TypeError(to_check, self.type)
+
+        for (i, (val, type)) in enumerate(zip(to_check, self._types)):
+            try:
+                check_type(type, func, val)
+            except _TC_Exception, inner:
+                raise _TC_IndexError(i, inner)
+        
+    @classmethod
+    def __typesig__(cls, obj):
+        if isinstance(obj, tuple):
+            return Tuple(*obj)
+            
+class TypeVariables(CheckType):
+    # This is a stack of {typevariable -> type} mappings
+    # It is intentional that it is class-wide; it maintains
+    # the mappings of the outer functions if we descend into
+    # nested typechecked functions
+    __mapping_stack = []
+
+    # This is the {typevariable -> type} mapping for the function
+    # currently being checked
+    __active_mapping = None
+
+    # This dict maps generators to their mappings
+    __gen_mappings = {}
+
+    def __init__(self, name):
+        self.type = name
+
+    def __str__(self):
+        return "TypeVariable(%s)" % self.type
+
+    __repr__ = __str__
+
+    def __hash__(self):
+        return hash(''.join([str(o) for o in self.__class__
+                                           , hash(type(self.type))
+                                           , hash(self.type)]))
+
+    def __eq__(self, other):
+        if self.__class__ is not other.__class__:
+            return False
+        return type(self.type) is type(other.type) and self.type == other.type
+
+    def __typecheck__(self, func, to_check):
+        name = self.type
+        if isinstance(func, GeneratorType):
+            active = self.__class__.__gen_mappings[func]
+        else:
+            active = self.__class__.__active_mapping
+
+        # We have to do this because u'a' == 'a'
+        lookup = (name, type(name))
+        if lookup in active:
+            check_type(active[lookup], func, to_check)
+        else:
+            # This is the first time we've encountered this
+            # typevariable for this function call.
+            #
+            # In this case, we automatically approve the object
+            active[lookup] = Type(calculate_type(to_check))
+
+    @classmethod
+    def __typesig__(cls, obj):
+        if isinstance(obj, basestring):
+            return cls(obj)
+
+    @classmethod
+    def __startchecking__(cls, func):
+        if isinstance(func, GeneratorType):
+            cls.__gen_mappings.setdefault(func, {})
+        elif isinstance(func, FunctionType):
+            cls.__mapping_stack.append(cls.__active_mapping)
+            cls.__active_mapping = {}
+        else:
+            raise TypeError(func)
+
+    @classmethod
+    def __switchchecking__(cls, from_func, to_func):
+        if isinstance(from_func, FunctionType):
+            if isinstance(to_func, GeneratorType):
+                cls.__gen_mappings[to_func] = cls.__active_mapping
+                cls.__stopchecking__(from_func)
+            elif isinstance(to_func, FunctionType):
+                cls.__stopchecking__(from_func)
+                cls.__startchecking__(to_func)
+            else:
+                raise TypeError(to_func)
+        else:
+            raise TypeError(from_func)
+
+    @classmethod
+    def __stopchecking__(cls, func):
+        if isinstance(func, GeneratorType):
+            del cls.__gen_mappings[func]
+        elif isinstance(func, FunctionType):
+            cls.__active_mapping = cls.__mapping_stack.pop()
+        else:
+            raise TypeError(func)
+            
+class Function(CheckType):
+    def __init__(self, func):
+        self._func = func
+        self.type = self
+    
+    @classmethod
+    def __typesig__(cls, obj):
+        if isinstance(obj, (FunctionType, MethodType)):
+            return cls(obj)
+            
+        # Snag callable class instances (that aren't types or classes)
+        if type(obj) not in (types.ClassType, type) and callable(obj):
+            return cls(obj)
+            
+    def __typecheck__(self, func, to_check):
+        if False == self._func(to_check):
+            raise _TC_FunctionError(self._func, to_check)
+            
+    def __str__(self):
+        return "Function(%s)" % self._func
+        
+    def __repr__(self):
+        return str(self)
+    
+    def __eq__(self, other):
+        if self.__class__ is not other.__class__:
+            return False
+        return self._func is other._func
+        
+    def __hash__(self):
+        return hash(str(self.__class__) + str(hash(self._func)))
+        
+# Register some of the above types so that Type() knows about them
+for c in (CheckType, List, Tuple, Dict, Single, TypeVariables, Function):
+    register_type(c)
+
+### The following are utility classes intended to make writing complex
+### signatures easier.
+######################################################################
+
+### Instances of Any() automatically approve of the object they're supposed
+### to be checking (ie, they don't actually check it; use this with caution)
+class Any(CheckType):
+    name = "Any"
+    
+    def __init__(self):
+        self.type = object
+    
+    def __typecheck__(self, func, to_check):
+        pass
+        
+    def __str__(self):
+        return "Any()"
+        
+    __repr__ = __str__
+
+    # All instances of this class are equal     
+    def __eq__(self, other):
+        return other.__class__ is self.__class__
+        
+    def __hash__(self):
+        return hash(self.__class__)
+
+### Base class for Or() and And()
+class _Boolean(CheckType):
+    def __init__(self, first_type, second_type, *types):
+        self._types = set()
+        
+        for t in (first_type, second_type)+types:
+            if type(t) is type(self):
+                self._types.update(t._types)
+            else:
+                self._types.add(Type(t))
+                
+        if len(self._types) < 2:
+            raise TypeError("there must be at least 2 distinct parameters to __init__()")
+
+        self.type = self
+        
+    def __eq__(self, other):
+        if other.__class__ is not self.__class__:
+            return False
+
+        return self._types == other._types
+        
+    def __hash__(self):
+        return hash(str(hash(self.__class__)) + str(hash(frozenset(self._types))))
+
+class Or(_Boolean):
+    name = "Or"
+
+    def __typecheck__(self, func, to_check):
+        for type in self._types:
+            try:
+                check_type(type, func, to_check)
+                return
+            except _TC_Exception:
+                pass
+
+        raise _TC_TypeError(to_check, self)
+
+class And(_Boolean):
+    name = "And"
+
+    def __typecheck__(self, func, to_check):
+        for type in self._types:
+            try:
+                check_type(type, func, to_check)
+            except _TC_Exception, e:
+                raise _TC_TypeError(to_check, self)
+
+class Not(Or):
+    name = "Not"
+    
+    # We override _Boolean's __init__ so that we can accept a single
+    # condition
+    def __init__(self, first_type, *types):
+        self._types = set([Type(t) for t in (first_type,)+types])
+                        
+        self.type = self
+    
+    def __typecheck__(self, func, to_check):
+        # Or does our work for us, but we invert its result
+        try:
+            Or.__typecheck__(self, func, to_check)
+        except _TC_Exception:
+            return
+        raise _TC_TypeError(to_check, self)
+        
+class Xor(_Boolean):
+    name = "Xor"
+
+    def __typecheck__(self, func, to_check):
+        already_met_1_cond = False
+        
+        for typ in self._types:
+            try:
+                check_type(typ, func, to_check)
+            except _TC_Exception:
+                pass
+            else:
+                if already_met_1_cond:
+                    raise _TC_XorError(2, _TC_TypeError(to_check, self))
+                already_met_1_cond = True
+                    
+        if not already_met_1_cond:
+            raise _TC_XorError(0, _TC_TypeError(to_check, self))        
+        
+class IsCallable(CheckType):
+    def __init__(self):
+        self.type = self
+        
+    def __str__(self):
+        return "IsCallable()"
+        
+    __repr__ = __str__
+    
+    # They're all the same
+    # XXX Change IsCallable to a singleton class    
+    def __hash__(self):
+        return id(self.__class__)
+    
+    def __eq__(self, other):
+        return self.__class__ is other.__class__
+    
+    def __typecheck__(self, func, to_check):
+        if not callable(to_check):
+            raise _TC_TypeError(to_check, 'a callable')
+            
+class HasAttr(CheckType):
+    def __init__(self, set_1, set_2=None):
+        attr_sets = {list: [], dict: {}}
+    
+        for (arg_1, arg_2) in ((set_1, set_2), (set_2, set_1)):
+            for t in (list, dict):
+                if isinstance(arg_1, t):
+                    attr_sets[t] = arg_1
+                    if isinstance(arg_2, t):
+                        raise TypeError("can only have one list and/or one dict")
+                        
+        self._attr_types = dict.fromkeys(attr_sets[list], Any())
+        
+        for (attr, typ) in attr_sets[dict].items():
+            self._attr_types[attr] = Type(typ)
+        
+    def __typecheck__(self, func, to_check):
+        for (attr, typ) in self._attr_types.items():
+            if not hasattr(to_check, attr):
+                raise _TC_MissingAttrError(attr)
+                
+            try:
+                check_type(typ, func, getattr(to_check, attr))
+            except _TC_Exception, e:
+                raise _TC_AttrError(attr, e)
+                
+    def __eq__(self, other):
+        if self.__class__ is not other.__class__:
+            return False
+        return self._attr_types == other._attr_types
+        
+    def __hash__(self):
+        return hash(str(hash(self.__class__)) + str(hash(str(self._attr_types))))
+        
+    def __str__(self):
+        any_type = []
+        spec_type = {}
+        
+        any = Any()
+        
+        for (attr, typ) in self._attr_types.items():
+            if typ == any:
+                any_type.append(attr)
+            else:
+                spec_type[attr] = typ
+
+        msg = [t for t in (any_type, spec_type) if len(t)]              
+    
+        return "HasAttr(" + ', '.join(map(str, msg)) + ")"
+        
+    __repr__ = __str__
+                
+class IsIterable(CheckType):
+    def __init__(self):
+        self.type = self
+        
+    def __eq__(self, other):
+        return self.__class__ is other.__class__
+    
+    # They're all the same
+    # XXX Change IsIterable to a singleton class    
+    def __hash__(self):
+        return id(self.__class__)
+        
+    def __str__(self):
+        return "IsIterable()"
+        
+    __repr__ = __str__
+        
+    def __typecheck__(self, func, to_check):
+        if not (hasattr(to_check, '__iter__') and callable(to_check.__iter__)):
+            raise _TC_TypeError(to_check, "an iterable")
+            
+class YieldSeq(CheckType):
+    _index_map = {}
+
+    def __init__(self, type_1, type_2, *types):
+        self.type = self
+        
+        self._type = [type_1, type_2] + list(types)
+        self._types = [Type(t) for t in self._type]
+        
+    def __hash__(self):
+        return id(self)
+        
+    def __str__(self):
+        return "YieldSeq(" + ", ".join(map(str, self._type)) + ")"
+        
+    __repr__ = __str__
+    
+    def __eq__(self, other):
+        if self.__class__ is not other.__class__:
+            return False
+        return self._types == other._types
+        
+    def __hash__(self):
+        return hash(str(self.__class__) + str([hash(t) for t in self._types]))
+    
+    # We have to use __{start,stop}checking__ so that the indexes get
+    # reset every time we run through the typechecking sequence
+    @classmethod
+    def __startchecking__(cls, gen):
+        if isinstance(gen, GeneratorType):
+            cls._index_map[gen] = {}
+    
+    @classmethod    
+    def __stopchecking__(cls, gen):
+        if gen in cls._index_map:
+            del cls._index_map[gen]
+    
+    def __typecheck__(self, gen, to_check):
+        index_map = self.__class__._index_map
+        
+        # There might be multiple YieldSeq's per signature
+        if self not in index_map[gen]:
+            index_map[gen][self] = -1
+        index = index_map[gen]
+
+        if index[self] >= len(self._types)-1:
+            raise _TC_YieldCountError(len(self._types))
+            
+        index[self] += 1        
+        check_type(self._types[index[self]], gen, to_check)
+                
+register_type(YieldSeq)
+
+class Exact(CheckType):
+    def __init__(self, obj):
+        self.type = self
+        self._obj = obj
+        
+    def __hash__(self):
+        try:
+            obj_hash = str(hash(self._obj))
+        except TypeError:
+            obj_hash = str(type(self._obj)) + str(self._obj)
+        
+        return hash(str(self.__class__) + obj_hash)
+        
+    def __eq__(self, other):
+        if self.__class__ is not other.__class__:
+            return False
+        return self._obj == other._obj
+        
+    def __typecheck__(self, func, to_check):
+        if self._obj != to_check:
+            raise _TC_ExactError(to_check, self._obj)
+            
+class Length(CheckType):
+    def __init__(self, length):
+        self.type = self
+        self._length = int(length)
+        
+    def __hash__(self):
+        return hash(str(self.__class__) + str(self._length))
+        
+    def __eq__(self, other):
+        if self.__class__ is not other.__class__:
+            return False
+        return self._length == other._length
+        
+    def __typecheck__(self, func, to_check):
+        try:
+            length = len(to_check)
+        except TypeError:
+            raise _TC_TypeError(to_check, "something with a __len__ method")
+            
+        if length != self._length:
+            raise _TC_LengthError(length, self._length)
+
+import sys          
+class Class(CheckType):
+    def __init__(self, class_name):
+        self.type = self
+        self.class_name = class_name
+        self.class_obj = None
+        self._frame = sys._getframe(1)
+        
+    def __hash__(self):
+        return hash(str(self.__class__) + self.class_name)
+        
+    def __str__(self):
+        return "Class('%s')" % self.class_name
+        
+    __repr__ = __str__
+        
+    def __eq__(self, other):
+        if self.__class__ is not other.__class__:
+            return False
+        return self.class_name == other.class_name
+        
+    def __typecheck__(self, func, to_check):
+        if self.class_obj is None:
+            class_name = self.class_name
+            frame = self._frame
+        
+            for f_dict in (frame.f_locals, frame.f_globals):
+                if class_name in frame.f_locals:
+                    if self is not frame.f_locals[class_name]:
+                        self.class_obj = frame.f_locals[class_name]
+                        self._frame = None
+                        break
+            else:
+                raise NameError("name '%s' is not defined" % class_name)
+        
+        if not isinstance(to_check, self.class_obj):
+            raise _TC_TypeError(to_check, self.class_obj)
+            
+class Typeclass(CheckType):
+    bad_members = dict.fromkeys(['__class__', '__new__', '__init__'], True)
+
+    def __init__(self, *types):
+        if len(types) == 0:
+            raise TypeError("Must supply at least one type to __init__()")
+    
+        self.type = self
+    
+        self._cache = set()
+        self._interface = set()
+        self._instances = set()
+        for t in types:
+            self.add_instance(t)
+                
+        self._calculate_interface()
+        
+    def recalculate_interface(self):
+        self._cache = self._instances.copy()
+        self._calculate_interface()
+                
+    def instances(self):
+        return list(self._instances)
+        
+    def interface(self):
+        return list(self._interface)
+        
+    def has_instance(self, instance):
+        return instance in self._instances
+        
+    def add_instance(self, instance):
+        if isinstance(instance, self.__class__):
+            for inst in instance.instances():
+                self._instances.add(inst)
+                self._cache.add(inst)
+        elif isinstance(instance, (ClassType, TypeType)):
+            self._instances.add(instance)
+            self._cache.add(instance)
+        else:
+            raise TypeError("All instances must be classes or types")
+        
+    def intersect(self, other):
+        if isinstance(other, self.__class__):
+            new_instances = other.instances()
+        else:
+            new_instances = other
+            
+        self._instances.update(new_instances)
+        self._cache.update(new_instances)
+        self._calculate_interface()
+        
+    def _calculate_interface(self):
+        bad_members = self.bad_members
+    
+        for instance in self._instances:
+            inst_attrs = []
+        
+            for attr, obj in instance.__dict__.items():
+                if callable(obj) and attr not in bad_members:
+                    inst_attrs.append(attr)
+            
+            if len(self._interface) == 0:
+                self._interface = set(inst_attrs)
+            else:
+                self._interface.intersection_update(inst_attrs)
+                
+    def __typecheck__(self, func, to_check):
+        if to_check.__class__ in self._cache:
+            return
+            
+        for method in self._interface:
+            if not hasattr(to_check, method):
+                raise _TC_MissingAttrError(method)
+
+            attr = getattr(to_check, method)
+            if not callable(attr):
+                raise _TC_AttrError(method, _TC_TypeError(attr, IsCallable()))
+                
+        self._cache.add(to_check.__class__)
+        
+    def __eq__(self, other):
+        if self.__class__ is not other.__class__:
+            return False
+        return self._instances == other._instances
+        
+    def __hash__(self):
+        return hash(str(self.__class__) + str(hash(frozenset(self._instances))))
+        
+    def __repr__(self):
+        return object.__repr__(self)
+        
+    def __str__(self):
+        return 'Typeclass(' + ', '.join(map(str, self._instances)) + ')'
+
+# The current implementation of Self relies on the TypeVariables machinery
+_Self = TypeVariables("this is the class of the invocant")
+def Self():
+    return _Self
+    
+### Aliases
+###########
+
+IsOneOf = Or
+IsAllOf = And
+IsNoneOf = Not
+IsOnlyOneOf = Xor
+
+### This is the public side of the module
+#########################################
+
+# This is for backwards compatibility with v0.1.6 and earlier
+class TypeCheckException(Exception):
+    pass
+
+class TypeCheckError(TypeCheckException):
+    def __init__(self, prefix, bad_object, exception):
+        TypeCheckException.__init__(self, prefix, bad_object, exception)
+        
+        self.prefix = prefix
+        self.internal = exception
+        self.bad_object = bad_object
+        
+        (bad_obj_str, start_message) = exception.format_bad_object(bad_object)
+        self.__message = prefix + bad_obj_str + start_message.error_message()
+        
+    def __str__(self):
+        return self.__message
+        
+class TypeSignatureError(Exception):
+    def __init__(self, internal_exc):
+        Exception.__init__(self, internal_exc)
+        
+        self.internal = internal_exc
+        self.__message = internal_exc.error_message()
+
+    def __str__(self):
+        return self.__message
+
+### Begin helper classes/functions for typecheck_args
+#####################################################
+def _rec_tuple(obj):
+    if isinstance(obj, list):
+        return tuple(_rec_tuple(o) for o in obj)
+    return obj
+
+def _rec_tuple_str(obj):
+    if not isinstance(obj, (list, tuple)):
+        return obj
+
+    if len(obj) == 1:
+        return '(%s,)' % obj
+
+    return '(' + ', '.join(_rec_tuple_str(o) for o in obj) + ')'
+
+def _gen_arg_to_param(func, (posargs, varargs, varkw, defaults)):
+    sig_args = list()
+    dic_args = list()
+    
+    for obj in posargs:
+        if isinstance(obj, list):
+            rts = _rec_tuple_str(obj)
+        
+            sig_args.append(rts)
+            dic_args.append((_rec_tuple(obj), rts))
+        else:
+            sig_args.append(str(obj))
+            dic_args.append(('"%s"' % obj, obj))
+    
+    func_code = ''
+    if varargs:
+        dic_args.append(('"%s"' % varargs, varargs))
+        sig_args.append('*' + varargs)
+        func_code = '\n\t%s = list(%s)' % (varargs, varargs)
+    if varkw:
+        dic_args.append(('"%s"' % varkw, varkw))
+        sig_args.append('**' + varkw)
+
+    func_name = func.func_name + '_'
+    while func_name in dic_args:
+        func_name += '_'
+
+    func_def = 'def %s(' % func.func_name
+    func_return = func_code \
+                + '\n\treturn {' \
+                + ', '.join('%s: %s' % kv for kv in dic_args) \
+                + '}'
+    
+    locals = {}
+    exec func_def + ','.join(sig_args) + '):' + func_return in locals
+    func = locals[func.func_name]
+    func.func_defaults = defaults
+    return func
+
+def _validate_tuple(ref, obj):
+    if not isinstance(ref, (list, tuple)):
+        return
+    if not isinstance(obj, (list, tuple)):
+        raise _TS_TupleError(ref, obj)
+
+    if len(ref) != len(obj):
+        raise _TS_TupleError(ref, obj)
+        
+    try:
+        for r, o in zip(ref, obj):
+            _validate_tuple(r, o)
+    except _TS_TupleError:
+        raise _TS_TupleError(ref, obj)
+
+def _param_to_type((params, varg_name, kwarg_name), vargs, kwargs):
+    vargs = list(vargs)
+    kwargs = dict(kwargs)
+    
+    # Make parameter names to values
+    param_value = dict()
+    
+    # There are excess positional arguments, but no *args parameter
+    if len(params) < len(vargs) and varg_name is None:
+        raise _TS_ExtraPositionalError(vargs[len(params)])
+    # There are not enough position args and no kwargs to draw from
+    if len(params) > len(vargs) and len(kwargs) == 0:
+        raise _TS_MissingTypeError(params[len(vargs)])
+    
+    # No reason to do this if there aren't any vargs
+    if len(vargs):
+        for p, a in zip(params, vargs):
+            # Make sure all auto-unpacked tuples match up
+            _validate_tuple(p, a)
+            param_value[_rec_tuple(p)] = a
+        
+    # No reason to do all this work if there aren't any kwargs
+    if len(kwargs) > 0:
+        # All params that still need values
+        params = set([k for k in params if k not in param_value])
+        if kwarg_name and kwarg_name not in param_value:
+            params.add(kwarg_name)
+        if varg_name and varg_name not in param_value:
+            params.add(varg_name)
+            
+        # Lift this out of the loop
+        no_double_star = kwarg_name is None
+        
+        # All parameter slots have been filled, but there are still keyword
+        # args remaining with no **kwargs parameter present
+        if len(params) == 0 and no_double_star:
+            raise _TS_ExtraKeywordError(kwargs.keys()[0])
+        
+        # Match up remaining keyword args with open parameter slots
+        for p, a in kwargs.items():
+            if p in param_value:
+                raise _TS_TwiceTypedError(p, a, param_value[p])
+            if p not in params and no_double_star:
+                raise _TS_ExtraKeywordError(p)
+
+            # Make sure all auto-unpacked tuples match up
+            _validate_tuple(p, a)
+
+            # Bookkeeping
+            params.remove(p)
+            param_value[p] = a
+        
+        # Any elements left in params indicate that the parameter is missing
+        # a value
+        if len(params):
+            raise _TS_MissingTypeError(params.pop())
+
+    return param_value
+
+def _make_fake_function(func):
+    def fake_function(*vargs, **kwargs):
+        # We call start_checking here, but __check_result
+        # has to call stop_checking on its own. The reason
+        # for this is so that typecheck_yield can call
+        # stop_checking on the function and then start_checking
+        # on the generator
+        start_checking(func)
+
+        # If either one of these operations fails, we need to call
+        # stop_checking()
+        try:
+            fake_function.__check_args(vargs, kwargs)
+            result = func(*vargs, **kwargs)
+        except:
+            stop_checking(func)
+            raise
+
+        return fake_function.__check_result(func, result)
+
+    # These are the default implementations of __check_args
+    # and __check_results
+    def _pass_args(vargs, kwargs):
+        pass
+    def _pass_result(func, result):
+        stop_checking(func)
+        return result
+
+    fake_function.__check_args = _pass_args
+    fake_function.__check_result = _pass_result
+    fake_function.__wrapped_func = func
+
+    # Mock-up the fake function to look as much like the
+    # real function as possible
+    fake_function.__module__ = func.__module__
+    fake_function.__name__ = func.__name__
+    fake_function.__doc__ = func.__doc__
+
+    return fake_function
+
+###################################################
+### End helper classes/functions for typecheck_args
+
+def typecheck_args(*v_sig, **kw_sig):
+    # typecheck_args is run to obtain the real decorator
+    def decorator(func):
+        if hasattr(func, '__wrapped_func'):
+            if hasattr(func, 'type_args'):
+                raise RuntimeError('Cannot use the same typecheck_* function more than once on the same function')
+            wrapped_func = func.__wrapped_func
+        else:
+            wrapped_func = func
+
+        param_list, varg_name, kwarg_name, defaults = inspect.getargspec(wrapped_func)
+        args_to_params = _gen_arg_to_param(wrapped_func, (param_list, varg_name, kwarg_name, defaults))
+
+        try:        
+            param_types = _param_to_type((param_list, varg_name, kwarg_name), v_sig, kw_sig)
+        except _TS_Exception, e:
+            raise TypeSignatureError(e)
+        
+        ### We need to fix-up the types of the *vargs and **kwargs parameters
+        #####################################################################
+        if varg_name:
+            if not isinstance(param_types[varg_name], list):
+                param_types[varg_name] = [param_types[varg_name]]
+
+        if kwarg_name:
+            if not isinstance(param_types[kwarg_name], dict):
+                param_types[kwarg_name] = {str: param_types[kwarg_name]}
+        
+        #####################################################################
+        ### /Fix-up
+        
+        # Convert the signatures to types now, rather than rebuild them in every function call
+        check_param_types = dict()
+        for k, v in param_types.items():
+            check_param_types[k] = Type(v)
+
+        def __check_args(__vargs, __kwargs):
+            # Type-checking can be turned on and off by toggling the
+            # value of the global enable_checking variable
+            if enable_checking:
+                arg_dict = args_to_params(*__vargs, **__kwargs)
+
+                # Type-check the keyword arguments
+                try:
+                    for name, val in arg_dict.items():
+                        check_type(check_param_types[name], wrapped_func, val)
+                except _TC_Exception, e:
+                    str_name = _rec_tuple_str(name)
+                    raise TypeCheckError("Argument %s: " % str_name, val, e)
+
+        if hasattr(func, '__check_result'):
+            # This is one of our wrapper functions, probably created by
+            # typecheck_yield or typecheck_return
+            fake_function = func
+        else:
+            # We need to build a wrapper
+            fake_function = _make_fake_function(func)
+
+        # Specify how argument checking should be done
+        fake_function.__check_args = __check_args
+
+        ### Add the publically-accessible signature information
+        fake_function.type_args = param_types
+
+        return fake_function
+    return decorator
+    
+# Refactor this out of typecheck_{return,yield} 
+def _decorator(signature, conflict_field, twice_field, check_result_func):
+    def decorator(func):
+        if hasattr(func, '__check_result'):
+            # This is one of our wrapper functions, probably created by
+            # typecheck_args
+            if hasattr(func, conflict_field):
+                raise RuntimeError("Cannot use typecheck_return and typecheck_yield on the same function")
+            elif hasattr(func, twice_field):
+                raise RuntimeError('Cannot use the same typecheck_* function more than once on the same function')
+
+            fake_function = func
+        else:
+            fake_function = _make_fake_function(func)
+                    
+        setattr(fake_function, twice_field, signature)
+        fake_function.__check_result = check_result_func
+        return fake_function
+    return decorator
+
+def typecheck_return(*signature):
+    if len(signature) == 1:
+        signature = signature[0]
+    sig_types = Type(signature)
+
+    def __check_return(func, return_vals):
+        if enable_checking:
+            try:
+                check_type(sig_types, func, return_vals)
+            except _TC_Exception, e:
+                stop_checking(func)
+                raise TypeCheckError("Return value: ", return_vals, e)
+
+        stop_checking(func)
+        return return_vals
+    return _decorator(signature, 'type_yield', 'type_return', __check_return)
+
+class Fake_generator(object):
+    def __init__(self, real_gen, signature):
+        # The generator should have the same yield signature
+        # as the function that produced it; however, we don't
+        # copy the args signature because the generator
+        # doesn't take arguments
+        self.type_yield = signature
+
+        self.__yield_no = 0     
+        self.__real_gen = real_gen
+        self.__sig_types = Type(signature)
+        self.__needs_stopping = True
+
+    def next(self):
+        gen = self.__real_gen
+    
+        self.__yield_no += 1
+
+        try:
+            return_vals = gen.next()
+        except StopIteration:
+            if self.__needs_stopping:
+                stop_checking(gen)
+                self.__needs_stopping = False
+            raise
+
+        if enable_checking:
+            try:
+                check_type(self.__sig_types, gen, return_vals)
+            except _TC_Exception, e:
+                # Insert this error into the chain so we can know
+                # which yield the error occurred at
+                middle_exc = _TC_GeneratorError(self.__yield_no, e)
+                raise TypeCheckError("", return_vals, middle_exc)
+
+        # Everything checks out. Return the results
+        return return_vals
+        
+    def __del__(self):
+        if self.__needs_stopping:
+            stop_checking(self.__real_gen)
+
+def typecheck_yield(*signature):
+    if len(signature) == 1:
+        signature = signature[0]
+
+    def __check_yield(func, gen):
+        # If the return value isn't a generator, we blow up
+        if not isinstance(gen, types.GeneratorType):
+            stop_checking(func)
+            raise TypeError("typecheck_yield only works for generators")
+
+        # Inform all listening classes that they might want to preserve any information
+        # from the function to the generator (*hint* TypeVariables *hint*)
+        #
+        # stop_checking() will not be invoked on the generator until it raises
+        # StopIteration or its refcount drops to 0
+        switch_checking(func, gen)
+    
+        # Otherwise, we build ourselves a fake generator
+        return Fake_generator(gen, signature)
+    return _decorator(signature, 'type_return', 'type_yield', __check_yield)
+
+_null_decorator = lambda *args, **kwargs: lambda f: f
+typecheck = _null_decorator
+accepts = _null_decorator
+returns = _null_decorator
+yields = _null_decorator
+
+# Aliases
+def enable_typechecking():
+    global typecheck
+    global accepts
+    global returns
+    global yields
+  
+    typecheck = typecheck_args
+    accepts = typecheck_args
+    returns = typecheck_return
+    yields = typecheck_yield
+
+import os
+if "PYTHONTYPECHECK" in os.environ:
+    enable_typechecking()
+

Added: translate-toolkit/branches/upstream/current/translate/misc/typecheck/doctest_support.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/misc/typecheck/doctest_support.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/misc/typecheck/doctest_support.py (added)
+++ translate-toolkit/branches/upstream/current/translate/misc/typecheck/doctest_support.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,36 @@
+"""
+This module allows doctest to find typechecked functions.
+
+Currently, doctest verifies functions to make sure that their
+globals() dict is the __dict__ of their module. In the case of
+decorated functions, the globals() dict *is* not the right one.
+
+To enable support for doctest do:
+    
+    import typecheck.doctest_support
+
+This import must occur before any calls to doctest methods.
+"""
+
+def __DocTestFinder_from_module(self, module, object):
+    """
+    Return true if the given object is defined in the given
+    module.
+    """
+    import inspect
+    
+    if module is None:
+        return True 
+    elif inspect.isfunction(object) or inspect.isclass(object):
+        return module.__name__ == object.__module__
+    elif inspect.getmodule(object) is not None:
+        return module is inspect.getmodule(object)
+    elif hasattr(object, '__module__'):
+        return module.__name__ == object.__module__
+    elif isinstance(object, property):
+        return True # [XX] no way not be sure.
+    else:
+        raise ValueError("object must be a class or function")
+
+import doctest as __doctest
+__doctest.DocTestFinder._from_module = __DocTestFinder_from_module

Added: translate-toolkit/branches/upstream/current/translate/misc/typecheck/mixins.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/misc/typecheck/mixins.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/misc/typecheck/mixins.py (added)
+++ translate-toolkit/branches/upstream/current/translate/misc/typecheck/mixins.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,84 @@
+from translate.misc.typecheck import _TC_NestedError, _TC_TypeError, check_type, Or
+from translate.misc.typecheck import register_type, _TC_Exception
+
+class _TC_IterationError(_TC_NestedError):
+    def __init__(self, iteration, value, inner_exception):
+        _TC_NestedError.__init__(self, inner_exception)
+    
+        self.iteration = iteration
+        self.value = value
+        
+    def error_message(self):
+        return ("at iteration %d (value: %s)" % (self.iteration, repr(self.value))) + _TC_NestedError.error_message(self)
+
+### This is the shadow class behind UnorderedIteratorMixin.
+### Again, it tries to pretend it doesn't exist by mimicing
+### the class of <obj> as much as possible.
+###
+### This mixin provides typechecking for iterator classes
+### where you don't care about the order of the types (ie,
+### you simply Or() the types together, as opposed to patterned
+### lists, which would be ordered mixins)
+class _UnorderedIteratorMixin(object):
+    def __init__(self, class_name, obj):
+        vals = [o for o in obj]
+    
+        self.type = self
+        self._type = Or(*vals)
+        self.__cls = obj.__class__
+        self.__vals = vals
+        # This is necessary because it's a huge pain in the ass
+        # to get the "raw" name of the class once it's created
+        self.__cls_name = class_name
+
+    def __typecheck__(self, func, to_check):
+        if not isinstance(to_check, self.__cls):
+            raise _TC_TypeError(to_check, self)
+
+        for i, item in enumerate(to_check):
+            try:
+                check_type(self._type, func, item)
+            except _TC_Exception, e:
+                raise _TC_IterationError(i, item, e)
+
+    @classmethod    
+    def __typesig__(cls, obj):
+        if isinstance(obj, cls):
+            return obj
+
+    def __str__(self):
+        return "%s(%s)" % (self.__cls_name, str(self._type))
+
+    __repr__ = __str__
+
+### This is included in a class's parent-class section like so:
+###  class MyClass(UnorderedIteratorMixin("MyClass")):
+###    blah blah blah
+###
+### This serves as a class factory, whose produced classes
+### attempt to mask the fact they exist. Their purpose
+### is to redirect __typesig__ calls to appropriate
+### instances of _UnorderedIteratorMixin
+def UnorderedIteratorMixin(class_name):
+    class UIM(object):
+        @classmethod
+        def __typesig__(cls, obj):
+            if isinstance(obj, cls):
+                return _UnorderedIteratorMixin(class_name, obj)
+
+        def __repr__(self):
+            return "%s%s" % (class_name, str(tuple(e for e in self)))
+
+    # We register each produced class anew
+    # If someone needs to unregister these classes, they should
+    # save a copy of it before including it in the class-definition:
+    #
+    # my_UIM = UnorderedIteratorMixin("FooClass")
+    # class FooClass(my_UIM):
+    #   ...
+    #
+    # Alternatively, you could just look in FooClass.__bases__ later; whatever
+    register_type(UIM)
+    return UIM
+    
+register_type(_UnorderedIteratorMixin)

Added: translate-toolkit/branches/upstream/current/translate/misc/typecheck/sets.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/misc/typecheck/sets.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/misc/typecheck/sets.py (added)
+++ translate-toolkit/branches/upstream/current/translate/misc/typecheck/sets.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,62 @@
+from translate.misc.typecheck import CheckType, _TC_TypeError, check_type, Type
+from translate.misc.typecheck import register_type, Or, _TC_Exception, _TC_KeyError
+from translate.misc.typecheck import _TC_LengthError
+
+### Provide typechecking for the built-in set() class
+###
+### XXX: Investigate rewriting this in terms of
+### UnorderedIteratorMixin or Or()          
+class Set(CheckType):
+    def __init__(self, set_list):
+        self.type = set(set_list)
+        self._types = [Type(t) for t in self.type]
+        
+        # self._type is used to build _TC_TypeError
+        if len(self._types) > 1:
+            self._type = Or(*self.type)
+        elif len(self._types) == 1:
+            # XXX Is there an easier way to get this?
+            t = self.type.pop()
+            self._type = t
+            self.type.add(t)
+    
+    def __str__(self):
+        return "Set(" + str([e for e in self.type]) + ")"
+        
+    __repr__ = __str__
+    
+    def __typecheck__(self, func, to_check):
+        if not isinstance(to_check, set):
+            raise _TC_TypeError(to_check, self.type)
+            
+        if len(self._types) == 0 and len(to_check) > 0:
+            raise _TC_LengthError(len(to_check), 0)
+            
+        for obj in to_check:
+            error = False
+            for type in self._types:
+                try:
+                    check_type(type, func, obj)
+                except _TC_Exception:
+                    error = True
+                    continue
+                else:
+                    error = False
+                    break
+            if error:
+                raise _TC_KeyError(obj, _TC_TypeError(obj, self._type))
+
+    def __eq__(self, other):
+        if self.__class__ is not other.__class__:
+            return False
+        return self.type == other.type
+        
+    def __hash__(self):
+        return hash(str(hash(self.__class__)) + str(hash(frozenset(self.type))))
+            
+    @classmethod
+    def __typesig__(self, obj):
+        if isinstance(obj, set):
+            return Set(obj)
+
+register_type(Set)

Added: translate-toolkit/branches/upstream/current/translate/misc/typecheck/typeclasses.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/misc/typecheck/typeclasses.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/misc/typecheck/typeclasses.py (added)
+++ translate-toolkit/branches/upstream/current/translate/misc/typecheck/typeclasses.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,35 @@
+from translate.misc.typecheck import Typeclass
+
+### Number
+####################################################
+
+_numbers = [int, float, complex, long, bool]
+try:
+    from decimal import Decimal
+    _numbers.append(Decimal)
+    del Decimal
+except ImportError:
+    pass
+    
+Number = Typeclass(*_numbers)
+del _numbers
+    
+### String -- subinstance of ImSequence
+####################################################
+
+String = Typeclass(str, unicode)
+    
+### ImSequence -- immutable sequences
+####################################################
+
+ImSequence = Typeclass(tuple, xrange, String)
+
+### MSequence -- mutable sequences
+####################################################
+
+MSequence = Typeclass(list)
+
+### Mapping
+####################################################
+
+Mapping = Typeclass(dict)

Modified: translate-toolkit/branches/upstream/current/translate/storage/base.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/base.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/base.py (original)
+++ translate-toolkit/branches/upstream/current/translate/storage/base.py Mon Dec 29 14:57:18 2008
@@ -31,6 +31,9 @@
 except:
     import pickle
 from exceptions import NotImplementedError
+from translate.storage.placeables.base import Placeable, as_string
+from translate.misc.typecheck import accepts, Self, IsOneOf
+from translate.misc.multistring import multistring
 
 def force_override(method, baseclass):
     """Forces derived classes to override method."""
@@ -314,6 +317,47 @@
             newunit.addnote(notes)
         return newunit
     buildfromunit = classmethod(buildfromunit)
+
+    def _rich_to_multistring(cls, value):
+        """Convert a placeables representation to a multistring.
+        >>> rich_string = [['a', X('42'), 'b'], ['foo', G('7', ['bar'])]]
+        >>> TranslationUnit._rich_to_multistring(rich_string)
+        multistring('a*b', 'foobar')
+        """
+        return multistring([as_string(chunk_seq) for chunk_seq in value])
+    _rich_to_multistring = classmethod(_rich_to_multistring)
+
+    def _multistring_to_rich(cls, value):
+        """Convert a multistring or unicode to a placeables presentation.
+        >>> TranslationUnit._multistring_to_rich(multistring('a', 'b'))
+        [['a'], ['b']]
+        """
+        if isinstance(value, (unicode, str)):
+            return [[unicode(value)]]
+        else:
+            return [[string] for string in value.strings]
+    _multistring_to_rich = classmethod(_multistring_to_rich)
+
+    @accepts(Self(), [[IsOneOf(Placeable, unicode)]])
+    def _set_rich_source(self, value):
+        self.source = self._rich_to_multistring(value)
+
+    def _get_rich_source(self):
+        return self._multistring_to_rich(self.source)
+
+    rich_source = property(_get_rich_source, _set_rich_source)
+
+    @accepts(Self(), [[IsOneOf(Placeable, unicode)]])
+    def _set_rich_target(self, value):
+        self.target = self._rich_to_multistring(value)
+
+    def _get_rich_target(self):
+        return self._multistring_to_rich(self.target)
+
+    rich_target = property(_get_rich_target, _set_rich_target)
+
+    xid = property(lambda self: None, lambda self, value: None)
+    rid = property(lambda self: None, lambda self, value: None)
 
 class TranslationStore(object):
     """Base class for stores for multiple translation units of type UnitClass."""

Modified: translate-toolkit/branches/upstream/current/translate/storage/dtd.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/dtd.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/dtd.py (original)
+++ translate-toolkit/branches/upstream/current/translate/storage/dtd.py Mon Dec 29 14:57:18 2008
@@ -138,6 +138,12 @@
                     else:
                         # plain comment
                         self.commenttype = "comment"
+                #FIXME: bloody entity might share a line with something important
+                elif not self.inentity and re.search("%.*;", line):
+                    # now work out the type of comment, and save it (remember we're not in the comment yet)
+                    self.comments.append(("comment", line))
+                    line = ""
+                    continue
 
             if self.incomment:
                 # some kind of comment

Modified: translate-toolkit/branches/upstream/current/translate/storage/lisa.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/lisa.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/lisa.py (original)
+++ translate-toolkit/branches/upstream/current/translate/storage/lisa.py Mon Dec 29 14:57:18 2008
@@ -25,6 +25,7 @@
 import re
 
 from translate.storage import base
+from translate.storage.placeables import lisa
 from translate.lang import data
 try:
     from lxml import etree
@@ -136,18 +137,70 @@
         """
         return namespaced(self.namespace, name)
 
+    def set_source_dom(self, dom_node):
+        languageNodes = self.getlanguageNodes()
+        if len(languageNodes) > 0:
+            self.xmlelement[0] = dom_node
+        else:
+            self.xmlelement.append(dom_node)
+    
+    def get_source_dom(self):
+        return self.getlanguageNode(lang=None, index=0)
+    source_dom = property(get_source_dom, set_source_dom)
+
+    def _ensure_singular(cls, value):
+        if value is not None and len(value) > 1:
+            raise Exception("XLIFF cannot handle plurals by default")
+    _ensure_singular = classmethod(_ensure_singular)
+
+    def set_rich_source(self, value, sourcelang='en'):
+        self._ensure_singular(value)
+        sourcelanguageNode = self.createlanguageNode(sourcelang, u'', "source")        
+        self.source_dom = lisa.insert_into_dom(sourcelanguageNode, value[0])
+
+    def get_rich_source(self):
+        return [lisa.extract_chunks(self.source_dom)]
+    rich_source = property(get_rich_source, set_rich_source)
+
     def setsource(self, text, sourcelang='en'):
         text = data.forceunicode(text)
+        self.source_dom = self.createlanguageNode(sourcelang, text, "source")
+
+    def getsource(self):
+        return self.getNodeText(self.source_dom)
+    source = property(getsource, setsource)
+
+    def set_target_dom(self, dom_node, append=False):
         languageNodes = self.getlanguageNodes()
-        sourcelanguageNode = self.createlanguageNode(sourcelang, text, "source")
-        if len(languageNodes) > 0:
-            self.xmlelement[0] = sourcelanguageNode
+        assert len(languageNodes) > 0
+        if dom_node is not None:
+            if append or len(languageNodes) == 1:
+                self.xmlelement.append(dom_node)
+            else:
+                self.xmlelement.insert(1, dom_node)
+        if not append and len(languageNodes) > 1:
+            self.xmlelement.remove(languageNodes[1])
+
+    def get_target_dom(self, lang=None):
+        if lang:
+            return self.getlanguageNode(lang=lang)
         else:
-            self.xmlelement.append(sourcelanguageNode)
-
-    def getsource(self):
-        return self.getNodeText(self.getlanguageNode(lang=None, index=0))
-    source = property(getsource, setsource)
+            return self.getlanguageNode(lang=None, index=1)
+    target_dom = property(get_target_dom)
+
+    def set_rich_target(self, value, lang='xx', append=False):
+        self._ensure_singular(value)
+        languageNode = None
+        if not value is None:
+            languageNode = self.createlanguageNode(lang, u'', "target")
+            lisa.insert_into_dom(languageNode, value[0])
+        self.set_target_dom(languageNode, append)
+
+    def get_rich_target(self, lang=None):
+        """retrieves the "target" text (second entry), or the entry in the 
+        specified language, if it exists"""
+        return [lisa.extract_chunks(self.get_target_dom(lang))]
+    rich_target = property(get_rich_target, set_rich_target)
 
     def settarget(self, text, lang='xx', append=False):
         #XXX: we really need the language - can't really be optional
@@ -156,25 +209,15 @@
         #Firstly deal with reinitialising to None or setting to identical string
         if self.gettarget() == text:
             return
-        languageNodes = self.getlanguageNodes()
-        assert len(languageNodes) > 0
+        languageNode = None
         if not text is None:
             languageNode = self.createlanguageNode(lang, text, "target")
-            if append or len(languageNodes) == 1:
-                self.xmlelement.append(languageNode)
-            else:
-                self.xmlelement.insert(1, languageNode)
-        if not append and len(languageNodes) > 1:
-            self.xmlelement.remove(languageNodes[1])
+        self.set_target_dom(languageNode, append)
 
     def gettarget(self, lang=None):
         """retrieves the "target" text (second entry), or the entry in the 
         specified language, if it exists"""
-        if lang:
-            node = self.getlanguageNode(lang=lang)
-        else:
-            node = self.getlanguageNode(lang=None, index=1)
-        return self.getNodeText(node)
+        return self.getNodeText(self.get_target_dom(lang))
     target = property(gettarget, settarget)
 
     def createlanguageNode(self, lang, text, purpose=None):
@@ -246,6 +289,15 @@
     def __str__(self):
         return etree.tostring(self.xmlelement, pretty_print=True, encoding='utf-8')
 
+    def _set_property(self, name, value):
+        self.xmlelement.attrib[name] = value
+
+    xid = property(lambda self:        self.xmlelement.attrib[self.namespaced('xid')],
+                   lambda self, value: self._set_property(self.namespaced('xid'), value))
+
+    rid = property(lambda self:        self.xmlelement.attrib[self.namespaced('rid')],
+                   lambda self, value: self._set_property(self.namespaced('rid'), value))
+
     def createfromxmlElement(cls, element):
         term = cls(None, empty=True)
         term.xmlelement = element

Modified: translate-toolkit/branches/upstream/current/translate/storage/mo.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/mo.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/mo.py (original)
+++ translate-toolkit/branches/upstream/current/translate/storage/mo.py Mon Dec 29 14:57:18 2008
@@ -174,7 +174,8 @@
                 target = unit.target
             if unit.target:
                 MESSAGES[source.encode("utf-8")] = target
-        hash_table = array.array("L", [0] * hash_size)
+        # using "I" works for 32- and 64-bit systems, but not for 16-bit!
+        hash_table = array.array("I", [0] * hash_size)
         keys = MESSAGES.keys()
         # the keys are sorted in the .mo file
         keys.sort()

Added: translate-toolkit/branches/upstream/current/translate/storage/odf_io.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/odf_io.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/odf_io.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/odf_io.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,37 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+import zipfile
+
+def open_odf(filename):
+    z = zipfile.ZipFile(filename, 'r')
+    return {'content.xml': z.read("content.xml"),
+            'meta.xml':    z.read("meta.xml"),
+            'styles.xml':  z.read("styles.xml")}
+
+def copy_odf(input_file, output_file, exclusion_list):
+    input_zip  = zipfile.ZipFile(input_file,  'r')
+    output_zip = zipfile.ZipFile(output_file, 'w', compression=zipfile.ZIP_DEFLATED)
+    for name in [name for name in input_zip.namelist() if name not in exclusion_list]:
+        output_zip.writestr(name, input_zip.read(name))
+    return output_zip
+

Added: translate-toolkit/branches/upstream/current/translate/storage/odf_shared.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/odf_shared.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/odf_shared.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/odf_shared.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,187 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2004-2006 Zuza Software Foundation
+#
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+def define_tables():
+    # Copied from git commit 96b9f1419453d8079dd1631c329f04d6e005baae from
+    # git://hforge.org/itools.git
+    config_uri = 'urn:oasis:names:tc:opendocument:xmlns:config:1.0'
+    dc_uri = 'http://purl.org/dc/elements/1.1/'
+    form_uri = 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'
+    meta_uri = 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'
+    number_uri = 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'
+    office_uri = 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'
+    presentation_uri = 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0'
+    text_uri = 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'
+    svg_uri = 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'
+    
+    inline_elements = [
+        (text_uri, 'page-count'),
+        (text_uri, 'page-number'),
+    
+        (text_uri, 'a'),
+        (text_uri, 'line-break'),
+        (text_uri, 'ruby-base'),
+        (text_uri, 's'),
+        (text_uri, 'span'),
+        (text_uri, 'tab')]
+    
+    no_translate_content_elements = [
+    
+        # Config
+        (config_uri, 'config-item'),
+    
+        # Dublin core
+        (dc_uri, 'creator'),
+        (dc_uri, 'date'),
+        #(dc_uri, 'description'),
+        (dc_uri, 'language'),
+        #(dc_uri, 'subject'),
+        #(dc_uri, 'title'),
+    
+        # Form
+        (form_uri, 'item'),
+        (form_uri, 'option'),
+    
+        # Meta
+        (meta_uri, 'creation-date'),
+        (meta_uri, 'date-string'),
+        (meta_uri, 'editing-cycles'),
+        (meta_uri, 'editing-duration'),
+        (meta_uri, 'generator'),
+        (meta_uri, 'initial-creator'),
+        #(meta_uri, 'keyword'),
+        (meta_uri, 'printed-by'),
+        (meta_uri, 'print-date'),
+        (meta_uri, 'user-defined'),
+    
+        # Number
+        (number_uri, 'currency-symbol'),
+        (number_uri, 'embedded-text'),
+        (number_uri, 'text'),
+    
+        # Office
+        (office_uri, 'binary-data'),
+    
+        # Presentation
+        (presentation_uri, 'date-time-decl'),
+        #(presentation_uri, 'footer-decl'),
+        #(presentation_uri, 'header-decl'),
+    
+        # Text
+        (text_uri, 'author-initials'),
+        (text_uri, 'author-name'),
+        # XXX (text_uri, 'bibliography-mark'),
+        (text_uri, 'bookmark-ref'),
+        #(text_uri, 'chapter'),
+        (text_uri, 'character-count'),
+        #(text_uri, 'conditional-text'),
+        (text_uri, 'creation-date'),
+        (text_uri, 'creation-time'),
+        (text_uri, 'creator'),
+        (text_uri, 'date'),
+        (text_uri, 'dde-connection'),
+        #(text_uri, 'description'),
+        (text_uri, 'editing-cycles'),
+        (text_uri, 'editing-duration'),
+        (text_uri, 'expression'),
+        (text_uri, 'file-name'),
+        #(text_uri, 'hidden-paragraph'),
+        #(text_uri, 'hidden-text'),
+        (text_uri, 'image-count'),
+        #(text_uri, 'index-entry-span'),
+        (text_uri, 'index-title-template'),
+        (text_uri, 'initial-creator'),
+        #(text_uri, 'keywords'),
+        (text_uri, 'linenumbering-separator'),
+        (text_uri, 'measure'),
+        (text_uri, 'modification-date'),
+        (text_uri, 'modification-time'),
+        #(text_uri, 'note-citation'),
+        #(text_uri, 'note-continuation-notice-backward'),
+        #(text_uri, 'note-continuation-notice-forward'),
+        (text_uri, 'note-ref'),
+        (text_uri, 'number'),
+        (text_uri, 'object-count'),
+        (text_uri, 'page-continuation'),
+        (text_uri, 'page-count'),
+        (text_uri, 'page-number'),
+        (text_uri, 'page-variable-get'),
+        (text_uri, 'page-variable-set'),
+        (text_uri, 'paragraph-count'),
+        #(text_uri, 'placeholder'),
+        (text_uri, 'print-date'),
+        (text_uri, 'print-time'),
+        (text_uri, 'printed-by'),
+        (text_uri, 'reference-ref'),
+        #(text_uri, 'ruby-text'),
+        (text_uri, 'script'),
+        (text_uri, 'sender-city'),
+        (text_uri, 'sender-company'),
+        (text_uri, 'sender-country'),
+        (text_uri, 'sender-email'),
+        (text_uri, 'sender-fax'),
+        (text_uri, 'sender-firstname'),
+        (text_uri, 'sender-initials'),
+        (text_uri, 'sender-lastname'),
+        (text_uri, 'sender-phone-private'),
+        (text_uri, 'sender-phone-work'),
+        #(text_uri, 'sender-position'),
+        (text_uri, 'sender-postal-code'),
+        (text_uri, 'sender-state-or-province'),
+        (text_uri, 'sender-street'),
+        #(text_uri, 'sender-title'),
+        (text_uri, 'sequence'),
+        (text_uri, 'sequence-ref'),
+        (text_uri, 'sheet-name'),
+        #(text_uri, 'subject'),
+        (text_uri, 'table-count'),
+        (text_uri, 'table-formula'),
+        (text_uri, 'template-name'),
+        (text_uri, 'text-input'),
+        (text_uri, 'time'),
+        #(text_uri, 'title'),
+        (text_uri, 'user-defined'),
+        (text_uri, 'user-field-get'),
+        (text_uri, 'user-field-input'),
+        (text_uri, 'variable-get'),
+        (text_uri, 'variable-input'),
+        (text_uri, 'variable-set'),
+        (text_uri, 'word-count'),
+    
+        # SVG
+        #(svg_uri, 'title'),
+        #(svg_uri, 'desc')
+    
+        # From translate
+        (text_uri, 'tracked-changes')
+        ]
+
+    globals()['inline_elements'] = inline_elements
+    globals()['no_translate_content_elements'] = no_translate_content_elements
+
+try:
+    from itools.odf.schema import inline_elements
+    from itools.odf.schema import no_translate_content_elements
+    
+except:
+    define_tables()
+

Added: translate-toolkit/branches/upstream/current/translate/storage/placeables/__init__.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/placeables/__init__.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/placeables/__init__.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/placeables/__init__.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,26 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# 
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""translate.storage.placeables is part of the translate package
+It contains classes that represent placeables (non-translatable inline 
+elements as native codes and variable markups)"""
+
+from base import *

Added: translate-toolkit/branches/upstream/current/translate/storage/placeables/base.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/placeables/base.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/placeables/base.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/placeables/base.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,132 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+"""This module implements basic functionality to support placeables.
+
+A placeable is used to represent things like:
+1. substitutions
+     for example, in ODF, footnotes appear in the ODF xml
+     where they are defined; so if we extract a paragraph with some
+     footnotes, the translator will have a lot of additional XML to with;
+     so we separate the footnotes out into separate translation units and
+     mark their positions in the original text with placeables.
+2. hiding of inline formatting data
+     the translator doesn't want to have to deal with all the weird
+     formatting conventions of wherever the text came from.
+3. marking variables
+     This is an old issue - translators translate variable names which
+     should remain untranslated. We can wrap placeables around variable
+     names to avoid this.
+
+The placeables model follows the XLIFF standard's list of placeables.
+Please refer to the XLIFF specification to get a better understanding.
+"""
+
+__all__ = ['Placeable', 'Bpt', 'Ept', 'X', 'Bx', 'Ex', 'G', 'It', 'Sub', 'Ph']
+
+def as_string(chunk_seq):
+    return u''.join([unicode(chunk) for chunk in chunk_seq])
+    
+class Placeable(object):
+    has_content = True
+    
+    def __init__(self, id, content=None, xid=None, rid=None):
+        self.id      = id
+        self.xid     = xid
+        self.rid     = rid
+        self.content = content
+
+    def __unicode__(self):
+        if self.has_content:
+            return as_string(self.content)
+        else:
+            return u'\ufffc'
+        
+    def __repr__(self):
+        if self.has_content:
+            return u'<%(tagname)s id=%(id)s>%(content)s</%(tagname)s>' % \
+                {'tagname': self.__class__.__name__,
+                 'id':      self.id,
+                 'content': as_string(self.content)}
+        else:
+            return u'<%(tagname)s id=%(id)s />' % {'tagname': self.__class__.__name__, 
+                                                   'id': self.id }
+        
+    def __eq__(self, other):
+        return self.id        == other.id        and \
+               self.content   == other.content   and \
+               self.xid       == other.xid       and \
+               self.rid       == other.rid       and \
+               self.__class__ == other.__class__
+
+class Delimiter(object):
+    pass
+
+class PairedDelimiter(object):
+    pass
+
+class MaskingPlaceable(Placeable):
+    def __init__(self, id, content, masked_code):
+        raise NotImplementedError
+
+class Bpt(MaskingPlaceable, PairedDelimiter):
+    pass
+
+class Ept(MaskingPlaceable, PairedDelimiter):
+    pass
+
+class Ph(MaskingPlaceable):
+    pass
+
+class It(MaskingPlaceable, Delimiter):
+    pass
+        
+class ReplacementPlaceable(Placeable):
+    pass
+
+class G(ReplacementPlaceable):
+    pass
+
+class Bx(ReplacementPlaceable, PairedDelimiter):
+    has_content = False
+
+    def __init__(self, id, xid = None):
+        ReplacementPlaceable.__init__(self, id, content = None, xid = xid)
+
+class Ex(ReplacementPlaceable, PairedDelimiter):
+    has_content = False
+
+    def __init__(self, id, xid = None):
+        ReplacementPlaceable.__init__(self, id, content = None, xid = xid)
+
+class X(ReplacementPlaceable, Delimiter):
+    has_content = False
+
+    def __init__(self, id, xid = None):
+        ReplacementPlaceable.__init__(self, id, content = None, xid = xid)
+
+class SubflowPlaceable(Placeable):
+    pass
+
+class Sub(SubflowPlaceable):
+    pass
+

Added: translate-toolkit/branches/upstream/current/translate/storage/placeables/lisa.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/placeables/lisa.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/placeables/lisa.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/placeables/lisa.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,125 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+from lxml import etree
+
+from translate.storage.placeables import base
+import translate.storage.placeables.misc as placeables_misc
+from translate.storage.xml_extract import misc
+
+def make_empty_replacement_placeable(klass, node):
+    return klass(node.attrib[u'id'])
+
+def make_g_placeable(klass, node):
+    return klass(node.attrib[u'id'], extract_chunks(node))
+
+def not_yet_implemented(klass, node):
+    raise NotImplementedError
+
+_class_dictionary = { u'bpt': (base.Bpt, not_yet_implemented), 
+                      u'bx' : (base.Bx,  make_empty_replacement_placeable), 
+                      u'ept': (base.Ept, not_yet_implemented),
+                      u'ex' : (base.Ex,  make_empty_replacement_placeable),
+                      u'g'  : (base.G,   make_g_placeable), 
+                      u'it' : (base.It,  not_yet_implemented),
+                      u'ph' : (base.Ph,  not_yet_implemented), 
+                      u'sub': (base.Sub, not_yet_implemented),
+                      u'x'  : (base.X,   make_empty_replacement_placeable) }
+
+def make_placeable(node):
+    _namespace, tag = misc.parse_tag(node.tag)
+    klass, maker = _class_dictionary[tag]
+    return maker(klass, node)
+
+def extract_chunks(dom_node):
+    result = []
+    if dom_node.text:
+        result.append(placeables_misc.as_unicode(dom_node.text))
+    for child_dom_node in dom_node:
+        result.append(make_placeable(child_dom_node))
+        if child_dom_node.tail:
+            result.append(placeables_misc.as_unicode(child_dom_node.tail))
+    return result
+
+# ==========================================================
+
+def placeable_as_dom_node(placeable, tagname):
+    dom_node = etree.Element(tagname)
+    dom_node.attrib['id'] = placeable.id
+    if placeable.xid is not None:
+        dom_node.attrib['xid'] = placeable.xid
+    if placeable.rid is not None:
+        dom_node.attrib['rid'] = placeable.rid
+    return dom_node
+
+_placeable_dictionary = { base.Bpt: lambda placeable: placeable_as_dom_node(placeable, 'bpt'), 
+                          base.Bx : lambda placeable: placeable_as_dom_node(placeable, 'bx'), 
+                          base.Ept: lambda placeable: placeable_as_dom_node(placeable, 'ept'),
+                          base.Ex : lambda placeable: placeable_as_dom_node(placeable, 'ex'),
+                          base.G  : lambda placeable: placeable_as_dom_node(placeable, 'g'), 
+                          base.It : lambda placeable: placeable_as_dom_node(placeable, 'it'),
+                          base.Ph : lambda placeable: placeable_as_dom_node(placeable, 'ph'), 
+                          base.Sub: lambda placeable: placeable_as_dom_node(placeable, 'sub'),
+                          base.X  : lambda placeable: placeable_as_dom_node(placeable, 'x') }
+
+class EOF: pass
+
+def end_with_eof(seq):
+    for item in seq:
+        yield item
+    while True:
+        yield EOF
+
+def collect_text(text, next, itr):
+    text = placeables_misc.as_unicode(text)
+    if isinstance(next, (unicode, str)):
+        return collect_text(text + placeables_misc.as_unicode(next), itr.next(), itr)
+    else:
+        return text, next
+    
+def get_placeable(result, next, itr):
+    if isinstance(next, base.Placeable):
+        return next, itr.next()
+    else:
+        return result, next
+
+def process_placeable(placeable, next, chunk_seq):
+    """Get all text appearing after """
+    text, next          = collect_text(u'', next, chunk_seq)
+    child_dom_node      = _placeable_dictionary[placeable.__class__](placeable)
+    child_dom_node.tail = text
+    if placeable.content is not None:
+        insert_into_dom(child_dom_node, placeable.content)
+    return child_dom_node, next
+
+def insert_into_dom(dom_node, chunk_seq):
+    """Enumerate the elements of chunk_seq, adding text and placeable
+    nodes to dom_node."""
+    
+    chunk_seq = end_with_eof(chunk_seq)
+    dom_node.text, next = collect_text(u'', chunk_seq.next(), chunk_seq)
+    while next != EOF:
+        placeable, next = get_placeable(None, next, chunk_seq)
+        if placeable is not None:
+            child_dom_node, next = process_placeable(placeable, next, chunk_seq)
+            dom_node.append(child_dom_node)
+    return dom_node

Added: translate-toolkit/branches/upstream/current/translate/storage/placeables/misc.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/placeables/misc.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/placeables/misc.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/placeables/misc.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,27 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+def as_unicode(string):
+    if isinstance(string, unicode):
+        return string
+    else:
+        return unicode(string.decode('utf-8'))

Added: translate-toolkit/branches/upstream/current/translate/storage/placeables/test_lisa.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/placeables/test_lisa.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/placeables/test_lisa.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/placeables/test_lisa.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,74 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2006-2007 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+from lxml import etree
+from translate.storage.placeables import lisa
+from translate.storage.placeables import X, Bx, Ex, G, Bpt, Ept, Ph, It, Sub
+
+def test_extract_chunks():
+    source = etree.fromstring(u'<source>a<x id="foo[1]/bar[1]/baz[1]"/></source>')
+    chunks = lisa.extract_chunks(source)
+    assert chunks == [u'a', X(u'foo[1]/bar[1]/baz[1]')]
+
+    source = etree.fromstring(u'<source>a<x id="foo[1]/bar[1]/baz[1]"/>é</source>')
+    chunks = lisa.extract_chunks(source)
+    assert chunks == [u'a', X(u'foo[1]/bar[1]/baz[1]'), u'é']
+
+    source = etree.fromstring(u'<source>a<g id="foo[2]/bar[2]/baz[2]">b<x id="foo[1]/bar[1]/baz[1]"/>c</g>é</source>')
+    chunks = lisa.extract_chunks(source)
+    assert chunks == [u'a', G(u'foo[2]/bar[2]/baz[2]', [u'b', X(id = u'foo[1]/bar[1]/baz[1]'), u'c']), u'é']
+
+def test_chunk_list():
+    left  = ['a', G('foo[2]/bar[2]/baz[2]', ['b', X(id = 'foo[1]/bar[1]/baz[1]'), 'c']), 'é']
+    right = ['a', G('foo[2]/bar[2]/baz[2]', ['b', X(id = 'foo[1]/bar[1]/baz[1]'), 'c']), 'é']
+    assert left == right
+
+def test_set_insert_into_dom():
+    source = etree.Element(u'source')
+    lisa.insert_into_dom(source, ['a'])
+    assert etree.tostring(source, encoding = 'UTF-8') == '<source>a</source>'
+
+    source = etree.Element(u'source')
+    lisa.insert_into_dom(source, ['a', 'é'])
+    assert etree.tostring(source, encoding = 'UTF-8') == '<source>aé</source>'
+
+    source = etree.Element(u'source')
+    lisa.insert_into_dom(source, [X('foo[1]/bar[1]/baz[1]')])
+    assert etree.tostring(source, encoding = 'UTF-8') == '<source><x id="foo[1]/bar[1]/baz[1]"/></source>'
+
+    source = etree.Element(u'source')
+    lisa.insert_into_dom(source, ['a', X('foo[1]/bar[1]/baz[1]')])
+    assert etree.tostring(source, encoding = 'UTF-8') == '<source>a<x id="foo[1]/bar[1]/baz[1]"/></source>'
+    
+    source = etree.Element(u'source')
+    lisa.insert_into_dom(source, ['a', X('foo[1]/bar[1]/baz[1]'), 'é'])
+    assert etree.tostring(source, encoding = 'UTF-8') == '<source>a<x id="foo[1]/bar[1]/baz[1]"/>é</source>'
+
+    source = etree.Element(u'source')
+    lisa.insert_into_dom(source, ['a', G('foo[2]/bar[2]/baz[2]', ['b', X(id = 'foo[1]/bar[1]/baz[1]'), 'c']), 'é'])
+    assert etree.tostring(source, encoding = 'UTF-8') == '<source>a<g id="foo[2]/bar[2]/baz[2]">b<x id="foo[1]/bar[1]/baz[1]"/>c</g>é</source>'
+
+if __name__ == '__main__':
+    test_chunk_list()
+    test_extract_chunks()
+    test_set_insert_into_dom()
+    

Modified: translate-toolkit/branches/upstream/current/translate/storage/statsdb.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/statsdb.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/statsdb.py (original)
+++ translate-toolkit/branches/upstream/current/translate/storage/statsdb.py Mon Dec 29 14:57:18 2008
@@ -105,7 +105,28 @@
         return result
 
     def as_string_for_db(self):
-      return ",".join([repr(x) for x in self.to_tuple()])
+        return ",".join([repr(x) for x in self.to_tuple()])
+
+def transaction(f):
+    """Modifies f to commit database changes if it executes without exceptions.
+    Otherwise it rolls back the database.
+    
+    ALL publicly accessible methods in StatsCache MUST be decorated with this
+    decorator.
+    """
+    
+    def decorated_f(self, *args, **kwargs):
+        try:
+            result = f(self, *args, **kwargs)
+            self.con.commit()
+            return result
+        except:
+            # If ANY exception is raised, we're left in an
+            # uncertain state and we MUST roll back any changes to avoid getting
+            # stuck in an inconsistent state.
+            self.con.rollback()
+            raise
+    return decorated_f
 
 UNTRANSLATED, TRANSLATED, FUZZY = 0, 1, 2
 def statefordb(unit):
@@ -126,7 +147,7 @@
             'translatedtargetwords']
 
     def db_keys(self):
-      return ",".join(self.keys)
+        return ",".join(self.keys)
 
     def __init__(self, cur):
         self.cur = cur
@@ -217,6 +238,7 @@
 def suggestion_filename(filename):
     return filename + suggestion_extension()
 
+# ALL PUBLICLY ACCESSIBLE METHODS MUST BE DECORATED WITH THE transaction DECORATOR.
 class StatsCache(object):
     """An object instantiated as a singleton for each statsfile that provides
     access to the database cache from a pool of StatsCache objects."""
@@ -319,10 +341,9 @@
 
         self.cur.execute("""CREATE INDEX IF NOT EXISTS uniterrorindex
             ON uniterrors(fileid, configid);""")
-
-        self.con.commit()
-
-    def _getfileid(self, filename, check_mod_info=True, store=None, errors_return_empty=False):
+    create = transaction(create)
+
+    def _getfileid(self, filename, check_mod_info=True, store=None):
         """Attempt to find the fileid of the given file, if it hasn't been
            updated since the last record update.
 
@@ -336,27 +357,21 @@
         self.cur.execute("""SELECT fileid, st_mtime, st_size FROM files
                 WHERE path=?;""", (realpath,))
         filerow = self.cur.fetchone()
-        try:
-            mod_info = get_mod_info(realpath)
-            if filerow:
-                fileid = filerow[0]
-                if not check_mod_info:
-                    # Update the mod_info of the file
-                    self.cur.execute("""UPDATE files
-                            SET st_mtime=?, st_size=?
-                            WHERE fileid=?;""", (mod_info[0], mod_info[1], fileid))
-                    return fileid
-                if (filerow[1], filerow[2]) == mod_info:
-                    return fileid
-            # We can only ignore the mod_info if the row already exists:
-            assert check_mod_info
-            store = store or factory.getobject(realpath)
-            return self._cachestore(store, realpath, mod_info)
-        except (base.ParseError, IOError, OSError, AssertionError):
-            if errors_return_empty:
-                return -1
-            else:
-                raise
+        mod_info = get_mod_info(realpath)
+        if filerow:
+            fileid = filerow[0]
+            if not check_mod_info:
+                # Update the mod_info of the file
+                self.cur.execute("""UPDATE files
+                        SET st_mtime=?, st_size=?
+                        WHERE fileid=?;""", (mod_info[0], mod_info[1], fileid))
+                return fileid
+            if (filerow[1], filerow[2]) == mod_info:
+                return fileid
+        # We can only ignore the mod_info if the row already exists:
+        assert check_mod_info
+        store = store or factory.getobject(realpath)
+        return self._cachestore(store, realpath, mod_info)
 
     def _getstoredcheckerconfig(self, checker):
         """See if this checker configuration has been used before."""
@@ -389,7 +404,6 @@
             values (?, ?, ?, ?, ?, ?, ?, ?);""",
             unitvalues)
         self.file_totals[fileid] = file_totals_record
-        self.con.commit()
         if unitindex:
             return state_strings[statefordb(units[0])]
         return ""
@@ -411,14 +425,8 @@
     def filetotals(self, filename):
         """Retrieves the statistics for the given file if possible, otherwise
         delegates to cachestore()."""
-        fileid = None
-        if not fileid:
-            try:
-                fileid = self._getfileid(filename)
-            except ValueError, e:
-                print >> sys.stderr, str(e)
-                return {}
-        return self.file_totals[fileid]
+        return self.file_totals[self._getfileid(filename)]
+    filetotals = transaction(filetotals)
 
     def _cacheunitschecks(self, units, fileid, configid, checker, unitindex=None):
         """Helper method for cachestorechecks() and recacheunit()"""
@@ -450,10 +458,9 @@
             (unitindex, fileid, configid, name, message)
             values (?, ?, ?, ?, ?);""",
             unitvalues)
-        self.con.commit()
         return errornames
 
-    def cachestorechecks(self, fileid, store, checker, configid):
+    def _cachestorechecks(self, fileid, store, checker, configid):
         """Calculates and caches the error statistics of the given store
         unconditionally."""
         # Let's purge all previous failures because they will probably just
@@ -469,7 +476,16 @@
             FROM     units
             WHERE    fileid=? AND unitid=?
         """, (fileid, unitid))
-        return values.fetchone()
+        result = values.fetchone()
+        if result is not None:
+            return result
+        else:
+            print >> sys.stderr, """WARNING: Database in inconsistent state. 
+            fileid %d and unitid %d have no entries in the table units.""" % (fileid, unitid)
+            # If values.fetchone() is None, then we return an empty list,
+            # to make FileTotals.new_record(*self.get_unit_stats(fileid, unitid))
+            # do the right thing.
+            return []
 
     def recacheunit(self, filename, checker, unit):
         """Recalculate all information for a specific unit. This is necessary
@@ -497,6 +513,7 @@
             checker.setsuggestionstore(factory.getobject(suggestion_filename(filename), ignore=suggestion_extension()))
         state.extend(self._cacheunitschecks([unit], fileid, configid, checker, unitindex))
         return state
+    recacheunit = transaction(recacheunit)
 
     def _checkerrors(self, filename, fileid, configid, checker, store):
         def geterrors():
@@ -516,7 +533,7 @@
         store = store or factory.getobject(filename)
         if os.path.exists(suggestion_filename(filename)):
             checker.setsuggestionstore(factory.getobject(suggestion_filename(filename), ignore=suggestion_extension()))
-        self.cachestorechecks(fileid, store, checker, configid)
+        self._cachestorechecks(fileid, store, checker, configid)
         return geterrors()
 
     def _geterrors(self, filename, fileid, configid, checker, store):
@@ -538,15 +555,8 @@
     def filechecks(self, filename, checker, store=None):
         """Retrieves the error statistics for the given file if possible,
         otherwise delegates to cachestorechecks()."""
-        fileid = None
-        configid = None
-        try:
-            fileid = self._getfileid(filename, store=store)
-            configid = self._get_config_id(fileid, checker)
-        except ValueError, e:
-            print >> sys.stderr, str(e)
-            return emptyfilechecks()
-
+        fileid = self._getfileid(filename, store=store)
+        configid = self._get_config_id(fileid, checker)
         values = self._geterrors(filename, fileid, configid, checker, store)
 
         errors = emptyfilechecks()
@@ -559,6 +569,7 @@
             errors[checkkey].append(value[1])   #value[1] is the unitindex
 
         return errors
+    filechecks = transaction(filechecks)
 
     def file_fails_test(self, filename, checker, name):
         fileid = self._getfileid(filename)
@@ -570,12 +581,12 @@
             FROM uniterrors 
             WHERE fileid=? and configid=? and name=?;""", (fileid, configid, name))
         return self.cur.fetchone() is not None
+    file_fails_test = transaction(file_fails_test)
         
     def filestats(self, filename, checker, store=None):
         """Return a dictionary of property names mapping sets of unit
         indices with those properties."""
         stats = emptyfilestats()
-
         stats.update(self.filechecks(filename, checker, store))
         fileid = self._getfileid(filename, store=store)
 
@@ -591,6 +602,7 @@
             stats["total"].append(value[1])
 
         return stats
+    filestats = transaction(filestats)
 
     def unitstats(self, filename, _lang=None, store=None):
         # For now, lang and store are unused. lang will allow the user to
@@ -617,3 +629,4 @@
             stats["targetwordcount"].append(targetcount)
 
         return stats
+    unitstats = transaction(unitstats)

Modified: translate-toolkit/branches/upstream/current/translate/storage/test_po.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/test_po.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/test_po.py (original)
+++ translate-toolkit/branches/upstream/current/translate/storage/test_po.py Mon Dec 29 14:57:18 2008
@@ -5,6 +5,7 @@
 from translate.storage import test_base
 from translate.misc import wStringIO
 from translate.misc.multistring import multistring
+from translate.storage.placeables import X, G
 from py.test import raises
 
 def test_roundtrip_quoting():
@@ -130,6 +131,16 @@
         unit.source = u"Goeiemôre"
         assert not unit.isheader()
 
+#     def test_rich_source(self):
+#         unit = self.unit
+#         unit.rich_source = [['a', X('42'), 'c']]
+#         assert unit.rich_source == [[u'a\ufffcc']]
+
+#     def test_rich_target(self):
+#         unit = self.unit
+#         unit.rich_target = [['a', G('42', ['b']), 'c']]
+#         assert unit.rich_target == [['abc']]
+
 class TestPOFile(test_base.TestTranslationStore):
     StoreClass = po.pofile
     def poparse(self, posource):

Modified: translate-toolkit/branches/upstream/current/translate/storage/test_xliff.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/test_xliff.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/test_xliff.py (original)
+++ translate-toolkit/branches/upstream/current/translate/storage/test_xliff.py Mon Dec 29 14:57:18 2008
@@ -2,6 +2,7 @@
 
 from translate.storage import xliff
 from translate.storage import test_base
+from translate.storage.placeables import X, G
 
 class TestXLIFFUnit(test_base.TestTranslationUnit):
     UnitClass = xliff.xliffunit
@@ -72,6 +73,78 @@
         assert newfile.findunit("Bla").source == "Bla"
         assert newfile.findunit("dit") is None
 
+    def test_rich_source(self):
+        xlifffile = xliff.xlifffile()
+        xliffunit = xlifffile.addsourceunit(u'')
+
+        # Test 1
+        xliffunit.rich_source = [['foo', X('bar'), 'baz']]
+        source_dom_node = xliffunit.getlanguageNode(None, 0)
+        x_placeable = source_dom_node[0]
+
+        assert source_dom_node.text == 'foo'
+        
+        assert x_placeable.tag == u'x'
+        assert x_placeable.attrib['id'] == 'bar'
+        assert x_placeable.tail == 'baz'
+        
+        assert xliffunit.rich_source == [['foo', X('bar'), 'baz']]
+
+        # Test 2
+        xliffunit.rich_source = [['foo', 'baz', G('oof', [G('zab', ['bar', 'rab'])])]]
+        source_dom_node = xliffunit.getlanguageNode(None, 0)
+        g_placeable = source_dom_node[0]
+        nested_g_placeable = g_placeable[0]
+
+        assert source_dom_node.text == u'foobaz'
+        
+        assert g_placeable.tag == u'g'
+        assert g_placeable.text == u''
+        assert g_placeable.attrib[u'id'] == u'oof'
+        assert g_placeable.tail == u''
+        
+        assert nested_g_placeable.tag == u'g'
+        assert nested_g_placeable.text == u'barrab'
+        assert nested_g_placeable.attrib[u'id'] == u'zab'
+        assert nested_g_placeable.tail == u''
+        
+        rich_source = xliffunit.rich_source
+        assert rich_source == [['foobaz', G('oof', [G('zab', ['barrab'])])]]
+
+    def test_rich_target(self):
+        xlifffile = xliff.xlifffile()
+        xliffunit = xlifffile.addsourceunit(u'')
+
+        # Test 1
+        xliffunit.set_rich_target([['foo', X('bar'), 'baz']], 'fr')
+        target_dom_node = xliffunit.getlanguageNode(None, 1)
+        x_placeable = target_dom_node[0]
+        
+        assert target_dom_node.text == 'foo'
+        assert x_placeable.tag == u'x'
+        assert x_placeable.attrib['id'] == 'bar'
+        assert x_placeable.tail == 'baz'
+
+        # Test 2
+        xliffunit.set_rich_target([['foo', 'baz', G('oof', [G('zab', ['bar', 'rab'])])]], 'fr')
+        target_dom_node = xliffunit.getlanguageNode(None, 1)
+        g_placeable = target_dom_node[0]
+        nested_g_placeable = g_placeable[0]
+
+        assert target_dom_node.text == u'foobaz'
+        
+        assert g_placeable.tag == u'g'
+        assert g_placeable.text == u''
+        assert g_placeable.attrib[u'id'] == u'oof'
+        assert g_placeable.tail == u''
+        
+        assert nested_g_placeable.tag == u'g'
+        assert nested_g_placeable.text == u'barrab'
+        assert nested_g_placeable.attrib[u'id'] == u'zab'
+        assert nested_g_placeable.tail == u''
+        
+        assert xliffunit.rich_target == [['foobaz', G('oof', [G('zab', ['barrab'])])]]
+
     def test_source(self):
         xlifffile = xliff.xlifffile()
         xliffunit = xlifffile.addsourceunit("Concept")

Modified: translate-toolkit/branches/upstream/current/translate/storage/xliff.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/xliff.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/xliff.py (original)
+++ translate-toolkit/branches/upstream/current/translate/storage/xliff.py Mon Dec 29 14:57:18 2008
@@ -69,7 +69,7 @@
             nodes.extend(sources[- (sourcesl - targetsl):])
         return nodes
 
-    def addalttrans(self, txt, origin=None, lang=None):
+    def addalttrans(self, txt, origin=None, lang=None, sourcetxt=None, matchquality=None):
         """Adds an alt-trans tag and alt-trans components to the unit.
         
         @type txt: String
@@ -83,6 +83,13 @@
         alttrans = etree.SubElement(self.xmlelement, self.namespaced("alt-trans"))
         alttarget = etree.SubElement(alttrans, self.namespaced("target"))
         alttarget.text = txt
+        if sourcetxt:
+            if isinstance(sourcetxt, str):
+                sourcetxt = sourcetxt.decode("utf-8")
+            altsource = etree.SubElement(alttrans, self.namespaced("source"))
+            altsource.text = sourcetxt
+        if matchquality:
+            alttrans.set("match-quality", matchquality)
         if origin:
             alttrans.set("origin", origin)
         if lang:
@@ -294,13 +301,15 @@
         """returns the restype attribute in the trans-unit tag"""
         return self.xmlelement.get("restype")
 
-    def merge(self, otherunit, overwrite=False, comments=True):
+    def merge(self, otherunit, overwrite=False, comments=True, authoritative=False):
         #TODO: consider other attributes like "approved"
         super(xliffunit, self).merge(otherunit, overwrite, comments)
         if self.target:
             self.marktranslated()
-        if otherunit.isfuzzy():
-            self.markfuzzy()
+            if otherunit.isfuzzy():
+                self.markfuzzy()
+            elif otherunit.source == self.source:
+                self.markfuzzy(False)
 
     def correctorigin(self, node, origin):
         """Check against node tag's origin (e.g note or alt-trans)"""

Added: translate-toolkit/branches/upstream/current/translate/storage/xml_extract/__init__.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/xml_extract/__init__.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/xml_extract/__init__.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/xml_extract/__init__.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,21 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2002-2006 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#

Added: translate-toolkit/branches/upstream/current/translate/storage/xml_extract/extract.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/xml_extract/extract.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/xml_extract/extract.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/xml_extract/extract.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,252 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2002-2006 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+from lxml import etree
+
+from translate.storage import base
+from translate.misc.typecheck import accepts, Self, IsCallable, IsOneOf, Any, Class
+from translate.misc.typecheck.typeclasses import Number
+from translate.misc.contextlib import contextmanager, nested
+from translate.misc.context import with_
+from translate.storage.xml_extract import xpath_breadcrumb
+from translate.storage.xml_extract import misc
+from translate.storage.placeables import X, G
+
+def Nullable(t):
+    return IsOneOf(t, type(None))
+
+TranslatableClass = Class('Translatable')
+
+class Translatable(object):
+    """A node corresponds to a translatable element. A node may
+       have children, which correspond to placeables."""
+    @accepts(Self(), unicode, unicode, etree._Element, [IsOneOf(TranslatableClass, unicode)])
+    def __init__(self, placeable_name, xpath, dom_node, source): 
+        self.placeable_name = placeable_name
+        self.source = source
+        self.xpath = xpath
+        self.is_inline = False
+        self.dom_node = dom_node
+
+    def _get_placeables(self):
+        return [placeable for placeable in self.source if isinstance(placeable, Translatable)]
+
+    placeables = property(_get_placeables)
+
+ at accepts(IsCallable(), Translatable, state=[Any()])
+def reduce_unit_tree(f, unit_node, *state):
+    return misc.reduce_tree(f, unit_node, unit_node, lambda unit_node: unit_node.placeables, *state)
+
+class ParseState(object):
+    """Maintain constants and variables used during the walking of a
+    DOM tree (via the function apply)."""
+    def __init__(self, no_translate_content_elements, inline_elements = {}, nsmap = {}):
+        self.no_translate_content_elements = no_translate_content_elements
+        self.inline_elements = inline_elements
+        self.is_inline = False
+        self.xpath_breadcrumb = xpath_breadcrumb.XPathBreadcrumb()
+        self.placeable_name = u"<top-level>"
+        self.nsmap = nsmap
+
+ at accepts(etree._Element, ParseState)
+def _process_placeable(dom_node, state):
+    """Run find_translatable_dom_nodes on the current dom_node"""
+    placeable = find_translatable_dom_nodes(dom_node, state)
+    # This happens if there were no recognized child tags and thus
+    # no translatable is returned. Make a placeable with the name
+    # "placeable"
+    if len(placeable) == 0:
+        return Translatable(u"placeable", state.xpath_breadcrumb.xpath, dom_node, [])
+    # The ideal situation: we got exactly one translateable back
+    # when processing this tree.
+    elif len(placeable) == 1:
+        return placeable[0]
+    else:
+        raise Exception("BUG: find_translatable_dom_nodes should never return more than a single translatable")
+
+ at accepts(etree._Element, ParseState)
+def _process_placeables(dom_node, state):
+    """Return a list of placeables and list with
+    alternating string-placeable objects. The former is
+    useful for directly working with placeables and the latter
+    is what will be used to build the final translatable string."""
+
+    source = []
+    for child in dom_node:
+        source.extend([_process_placeable(child, state), unicode(child.tail or u"")])
+    return source
+
+ at accepts(etree._Element, ParseState)
+def _process_translatable(dom_node, state):
+    source = [unicode(dom_node.text or u"")] + _process_placeables(dom_node, state)
+    translatable = Translatable(state.placeable_name, state.xpath_breadcrumb.xpath, dom_node, source)
+    translatable.is_inline = state.is_inline
+    return [translatable]
+
+ at accepts(etree._Element, ParseState)
+def _process_children(dom_node, state):
+    _namespace, tag = misc.parse_tag(dom_node.tag)
+    children = [find_translatable_dom_nodes(child, state) for child in dom_node]
+    # Flatten a list of lists into a list of elements
+    children = [child for child_list in children for child in child_list]
+    if len(children) > 1:
+        intermediate_translatable = Translatable(tag, state.xpath_breadcrumb.xpath, dom_node, children)
+        return [intermediate_translatable]
+    else:
+        return children
+
+def compact_tag(nsmap, namespace, tag):
+    if namespace in nsmap:
+        return u'%s:%s' % (nsmap[namespace], tag)
+    else:
+        return u'{%s}%s' % (namespace, tag)
+
+ at accepts(etree._Element, ParseState)
+def find_translatable_dom_nodes(dom_node, state):
+    # For now, we only want to deal with XML elements.
+    # And we want to avoid processing instructions, which 
+    # are XML elements (in the inheritance hierarchy).
+    if not isinstance(dom_node, etree._Element) or \
+           isinstance(dom_node, etree._ProcessingInstruction):
+        return []
+
+    namespace, tag = misc.parse_tag(dom_node.tag)
+
+    @contextmanager
+    def xpath_set():
+        state.xpath_breadcrumb.start_tag(compact_tag(state.nsmap, namespace, tag))
+        yield state.xpath_breadcrumb
+        state.xpath_breadcrumb.end_tag()
+        
+    @contextmanager
+    def placeable_set():
+        old_placeable_name = state.placeable_name
+        state.placeable_name = tag
+        yield state.placeable_name
+        state.placeable_name = old_placeable_name
+            
+    @contextmanager
+    def inline_set():
+        old_inline = state.is_inline
+        if (namespace, tag) in state.inline_elements:
+            state.is_inline = True
+        else:
+            state.is_inline = False
+        yield state.is_inline
+        state.is_inline = old_inline
+      
+    def with_block(xpath_breadcrumb, placeable_name, is_inline):
+        if (namespace, tag) not in state.no_translate_content_elements:
+            return _process_translatable(dom_node, state)
+        else:
+            return _process_children(dom_node, state)            
+    return with_(nested(xpath_set(), placeable_set(), inline_set()), with_block)
+
+class IdMaker(object):
+    def __init__(self):
+        self._max_id = 0
+        self._obj_id_map = {}
+
+    def get_id(self, obj):
+        if not self.has_id(obj):
+            self._obj_id_map[obj] = self._max_id
+            self._max_id += 1
+        return self._obj_id_map[obj]
+
+    def has_id(self, obj):
+        return obj in self._obj_id_map
+
+ at accepts(Nullable(Translatable), Translatable, IdMaker)
+def _to_placeables(parent_translatable, translatable, id_maker):
+    result = []
+    for chunk in translatable.source:
+        if isinstance(chunk, unicode):
+            result.append(chunk)
+        else:
+            id = unicode(id_maker.get_id(chunk))
+            if chunk.is_inline:
+                result.append(G(id, _to_placeables(parent_translatable, chunk, id_maker)))
+            else:
+                result.append(X(id, xid=chunk.xpath))
+    return result
+
+ at accepts(base.TranslationStore, Nullable(Translatable), Translatable, IdMaker)
+def _add_translatable_to_store(store, parent_translatable, translatable, id_maker):
+    """Construct a new translation unit, set its source and location
+    information and add it to 'store'.
+    """
+    unit = store.UnitClass(u'')
+    unit.rich_source = [_to_placeables(parent_translatable, translatable, id_maker)]
+    unit.addlocation(translatable.xpath)
+    if parent_translatable is not None:
+        unit.xid = parent_translatable.xpath
+    store.addunit(unit)
+
+ at accepts(Translatable)
+def _contains_translatable_text(translatable):
+    """Checks whether translatable contains any chunks of text which contain
+    more than whitespace.
+    
+    If not, then there's nothing to translate."""
+    for chunk in translatable.source:
+        if isinstance(chunk, unicode):
+            if chunk.strip() != u"":
+                return True
+    return False
+
+ at accepts(base.TranslationStore)
+def _make_store_adder(store):
+    """Return a function which, when called with a Translatable will add
+    a unit to 'store'. The placeables will represented as strings according
+    to 'placeable_quoter'."""
+    id_maker = IdMaker()
+
+    def add_to_store(parent_translatable, translatable, rid):
+        _add_translatable_to_store(store, parent_translatable, translatable, id_maker)
+            
+    return add_to_store
+
+ at accepts([Translatable], IsCallable(), Nullable(Translatable), Number)
+def _walk_translatable_tree(translatables, f, parent_translatable, rid):
+    for translatable in translatables:
+        if _contains_translatable_text(translatable) and not translatable.is_inline:
+            rid = rid + 1
+            new_parent_translatable = translatable
+            f(parent_translatable, translatable, rid)
+        else:
+            new_parent_translatable = parent_translatable
+
+        _walk_translatable_tree(translatable.placeables, f, new_parent_translatable, rid)
+
+def reverse_map(a_map):
+    return dict((value, key) for key, value in a_map.iteritems())
+
+ at accepts(lambda obj: hasattr(obj, "read"), base.TranslationStore, ParseState, Nullable(IsCallable()))
+def build_store(odf_file, store, parse_state, store_adder = None):
+    """Utility function for loading xml_filename"""    
+    store_adder = store_adder or _make_store_adder(store)
+    tree = etree.parse(odf_file)
+    root = tree.getroot()
+    parse_state.nsmap = reverse_map(root.nsmap)
+    translatables = find_translatable_dom_nodes(root, parse_state)
+    _walk_translatable_tree(translatables, store_adder, None, 0)
+    return tree

Added: translate-toolkit/branches/upstream/current/translate/storage/xml_extract/generate.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/xml_extract/generate.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/xml_extract/generate.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/xml_extract/generate.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,240 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2002-2006 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+import lxml.etree as etree
+
+from translate.storage import base
+
+from translate.misc.typecheck import accepts, IsCallable, Any
+from translate.storage.xml_extract import misc
+from translate.storage.xml_extract import extract
+from translate.storage.xml_extract import unit_tree
+from translate.storage.xml_name import XmlNamer
+
+ at accepts(etree._Element)
+def _get_tag_arrays(dom_node):
+    """Return a dictionary indexed by child tag names, where each tag is associated with an array
+    of all the child nodes with matching the tag name, in the order in which they appear as children
+    of dom_node.
+    
+    >>> xml = '<a><b></b><c></c><b></b><d/></a>'
+    >>> element = etree.fromstring(xml)
+    >>> get_tag_arrays(element)
+    {'b': [<Element a at 84df144>, <Element a at 84df148>], 'c': [<Element a at 84df120>], 'd': [<Element a at 84df152>]}
+    """
+    child_dict = {}
+    for child in dom_node:
+        if child.tag not in child_dict:
+            child_dict[child.tag] = []
+        child_dict[child.tag].append(child)
+    return child_dict
+
+ at accepts(etree._Element, unit_tree.XPathTree, extract.Translatable, IsCallable())
+def apply_translations(dom_node, unit_node, do_translate):
+    tag_array = _get_tag_arrays(dom_node)
+    for unit_child_index, unit_child in unit_node.children.iteritems():
+        tag, index = unit_child_index
+        try:
+            dom_child = tag_array[XmlNamer(dom_node).name(tag)][index]
+            apply_translations(dom_child, unit_child, do_translate)
+        # Raised if tag is not in tag_array. We might want to complain to the
+        # user in the future.
+        except KeyError:
+            pass
+        # Raised if index is not in tag_array[tag]. We might want to complain to
+        # the user in the future
+        except IndexError:
+            pass
+    # If there is a translation unit associated with this unit_node...
+    if unit_node.unit != None:
+        # The invoke do_translate on the dom_node and the unit; do_translate
+        # should replace the text in dom_node with the text in unit_node.
+        do_translate(dom_node, unit_node.unit)
+
+ at accepts(IsCallable(), etree._Element, vargs=[Any()])
+def reduce_dom_tree(f, dom_node, *state):
+    return misc.reduce_tree(f, dom_node, dom_node, lambda dom_node: dom_node, *state)
+
+ at accepts(etree._Element, etree._Element)
+def find_dom_root(parent_dom_node, dom_node):
+    """@see find_placeable_dom_tree_roots"""
+    if dom_node is None or parent_dom_node is None:
+        return None
+    if dom_node.getparent() == parent_dom_node:
+        return dom_node
+    elif dom_node.getparent() is None:
+        return None
+    else:
+        return find_dom_root(parent_dom_node, dom_node.getparent())    
+
+ at accepts(extract.Translatable)
+def find_placeable_dom_tree_roots(unit_node):
+    """For an inline placeable, find the root DOM node for the placeable in its
+    parent.
+    
+    Consider the diagram. In this pseudo-ODF example, there is an inline span
+    element. However, the span is contained in other tags (which we never process).
+    When splicing the template DOM tree (that is, the DOM which comes from 
+    the XML document we're using to generate a translated XML document), we'll
+    need to move DOM sub-trees around and we need the roots of these sub-trees.
+    
+    <p> This is text \/                <- Paragraph containing an inline placeable
+                     <blah>            <- Inline placeable's root (which we want to find)
+                     ...               <- Any number of intermediate DOM nodes
+                     <span> bold text  <- The inline placeable's Translatable 
+                                          holds a reference to this DOM node    
+    """
+
+    def set_dom_root_for_unit_node(parent_unit_node, unit_node, dom_tree_roots):
+            dom_tree_roots[unit_node] = find_dom_root(parent_unit_node.dom_node, unit_node.dom_node)
+            return dom_tree_roots
+    return extract.reduce_unit_tree(set_dom_root_for_unit_node, unit_node, {})
+      
+ at accepts(extract.Translatable, etree._Element)
+def _map_source_dom_to_doc_dom(unit_node, source_dom_node):
+    """Creating a mapping from the DOM nodes in source_dom_node which correspond to
+    placeables, with DOM nodes in the XML document template (this information is obtained
+    from unit_node). We are interested in DOM nodes in the XML document template which
+    are the roots of placeables. @see the diagram below, as well as 
+    find_placeable_dom_tree_roots.
+    
+    XLIFF Source (below)
+    <source>This is text <g> bold text</g> and a footnote<x/></source> 
+                         /                                 \________
+                        /                                           \
+    <p>This is text<blah>...<span> bold text</span>...</blah> and <note>...</note></p>
+    Input XML document used as a template (above)
+    
+    In the above diagram, the XLIFF source DOM node <g> is associated with the XML 
+    document DOM node <blah>, whereas the XLIFF source DOM node <x> is associated with
+    the XML document DOM node <note>.
+    """
+    dom_tree_roots = find_placeable_dom_tree_roots(unit_node)
+    source_dom_to_doc_dom = {}
+  
+    def loop(unit_node, source_dom_node):
+        for child_unit_node, child_source_dom in zip(unit_node.placeables, source_dom_node):
+            source_dom_to_doc_dom[child_source_dom] = dom_tree_roots[child_unit_node]
+            loop(child_unit_node, child_source_dom)
+    
+    loop(unit_node, source_dom_node)
+    return source_dom_to_doc_dom
+
+ at accepts(etree._Element, etree._Element)
+def _map_target_dom_to_source_dom(source_dom_node, target_dom_node):
+    """Associate placeables in source_dom_node and target_dom_node which
+    have the same 'id' attributes.
+    
+    We're using XLIFF placeables. The XLIFF standard requires that
+    placeables have unique ids. The id of a placeable is never modified,
+    which means that even if placeables are moved around in a translation,
+    we can easily associate placeables from the source text with placeables
+    in the target text.
+    
+    This function does exactly that.
+    """
+    
+    def map_id_to_dom_node(parent_node, node, id_to_dom_node):
+        # If this DOM node has an 'id' attribute, then add an id -> node
+        # mapping to 'id_to_dom_node'.
+        if u'id' in node.attrib:
+            id_to_dom_node[node.attrib[u'id']] = node
+        return id_to_dom_node
+    
+    # Build a mapping of id attributes to the DOM nodes which have these ids.
+    id_to_dom_node = reduce_dom_tree(map_id_to_dom_node, target_dom_node, {})
+    
+    def map_target_dom_to_source_dom_aux(parent_node, node, target_dom_to_source_dom):
+        # 
+        if u'id' in node.attrib and node.attrib[u'id'] in id_to_dom_node:
+            target_dom_to_source_dom[id_to_dom_node[node.attrib[u'id']]] = node
+        return target_dom_to_source_dom
+    
+    # For each node in the DOM tree rooted at source_dom_node:
+    # 1. Check whether the node has an 'id' attribute.
+    # 2. If so, check whether there is a mapping of this id to a target DOM node
+    #    in id_to_dom_node.
+    # 3. If so, associate this source DOM node with the target DOM node.
+    return reduce_dom_tree(map_target_dom_to_source_dom_aux, source_dom_node, {})
+
+def _build_target_dom_to_doc_dom(unit_node, source_dom, target_dom):
+    source_dom_to_doc_dom    = _map_source_dom_to_doc_dom(unit_node, source_dom)
+    target_dom_to_source_dom = _map_target_dom_to_source_dom(source_dom, target_dom)
+    return misc.compose_mappings(target_dom_to_source_dom, source_dom_to_doc_dom)
+
+ at accepts(etree._Element, {etree._Element: etree._Element})
+def _get_translated_node(target_node, target_dom_to_doc_dom):
+    """Convenience function to get node corresponding to 'target_node'
+    and to assign the tail text of 'target_node' to this node."""
+    dom_node = target_dom_to_doc_dom[target_node]
+    dom_node.tail = target_node.tail
+    return dom_node
+
+ at accepts(etree._Element, etree._Element, {etree._Element: etree._Element})
+def _build_translated_dom(dom_node, target_node, target_dom_to_doc_dom):
+    """Use the "shape" of 'target_node' (which is a DOM tree) to insert nodes
+    into the DOM tree rooted at 'dom_node'.
+    
+    The mapping 'target_dom_to_doc_dom' is used to map nodes from 'target_node'
+    to nodes which much be inserted into dom_node.
+    """
+    dom_node.text = target_node.text
+    # 1. Find all child nodes of target_node.
+    # 2. Filter out the children which map to None.
+    # 3. Call _get_translated_node on the remaining children; this maps a node in
+    #    'target_node' to a node in 'dom_node' and assigns the tail text of 'target_node'
+    #    to the mapped node.
+    # 4. Add all of these mapped nodes to 'dom_node' 
+    dom_node.extend(_get_translated_node(child, target_dom_to_doc_dom) for child in target_node 
+                    if target_dom_to_doc_dom[child] is not None)
+    # Recursively call this function on pairs of matched children in
+    # dom_node and target_node.
+    for dom_child, target_child in zip(dom_node, target_node):
+        _build_translated_dom(dom_child, target_child, target_dom_to_doc_dom)
+
+ at accepts(IsCallable())
+def replace_dom_text(make_parse_state):
+    """Return a function
+      action: etree_Element x base.TranslationUnit -> None
+    which takes a dom_node and a translation unit. The dom_node is rearranged
+    according to rearrangement of placeables in unit.target (relative to their
+    positions in unit.source).
+    """
+    
+    @accepts(etree._Element, base.TranslationUnit)
+    def action(dom_node, unit):
+        """Use the unit's target (or source in the case where there is no translation)
+        to update the text in the dom_node and at the tails of its children."""
+        source_dom = unit.source_dom
+        if unit.target_dom is not None:
+            target_dom = unit.target_dom
+        else:
+            target_dom = unit.source_dom
+        # Build a tree of (non-DOM) nodes which correspond to the translatable DOM nodes in 'dom_node'.
+        # Pass in a fresh parse_state every time, so as avoid working with stale parse state info.
+        unit_node             = extract.find_translatable_dom_nodes(dom_node, make_parse_state())[0]        
+        target_dom_to_doc_dom = _build_target_dom_to_doc_dom(unit_node, source_dom, target_dom)
+        # Before we start reconstructing the sub-tree rooted at dom_node, we must clear out its children
+        dom_node[:] = []
+        _build_translated_dom(dom_node, target_dom, target_dom_to_doc_dom)
+
+    return action

Added: translate-toolkit/branches/upstream/current/translate/storage/xml_extract/misc.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/xml_extract/misc.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/xml_extract/misc.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/xml_extract/misc.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,76 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2002-2006 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+import re
+
+from translate.misc.typecheck import accepts, Self, IsCallable, IsOneOf, Any
+
+ at accepts(IsCallable(), Any(), Any(), IsCallable(), state=[Any()])
+def reduce_tree(f, parent_unit_node, unit_node, get_children, *state):
+    """Enumerate a tree, applying f to in a pre-order fashion to each node.
+    
+    parent_unit_node contains the parent of unit_node. For the root of the tree,
+    parent_unit_node == unit_node.
+    
+    get_children is a single argument function applied to a unit_node to
+    get a list/iterator to its children.
+
+    state is used by f to modify state information relating to whatever f does
+    to the tree.
+    """
+    def as_tuple(x):
+        if isinstance(x, tuple):
+            return x
+        else:
+            return (x,)
+    
+    state = f(parent_unit_node, unit_node, *state)
+    for child_unit_node in get_children(unit_node):
+        state = reduce_tree(f, unit_node, child_unit_node, get_children, *as_tuple(state))
+    return state
+
+def compose_mappings(left, right):
+    """Given two mappings left: A -> B and right: B -> C, create a
+    hash result_map: A -> C. Only values in left (i.e. things from B)
+    which have corresponding keys in right will have their keys mapped
+    to values in right. """
+    result_map = {}
+    for left_key, left_val in left.iteritems():
+        try:
+            result_map[left_key] = right[left_val]
+        except KeyError:
+            pass
+    return result_map
+
+tag_pattern = re.compile('({(?P<namespace>(\w|[-:./])*)})?(?P<tag>(\w|[-])*)')
+
+def parse_tag(full_tag):
+    """
+    >>> parse_tag('{urn:oasis:names:tc:opendocument:xmlns:office:1.0}document-content')
+    ('urn:oasis:names:tc:opendocument:xmlns:office:1.0', 'document-content')
+    """
+    match = tag_pattern.match(full_tag)
+    if match is not None:
+        return unicode(match.groupdict()['namespace']), unicode(match.groupdict()['tag'])
+    else:
+        raise Exception('Passed an invalid tag')
+

Added: translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_misc.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_misc.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_misc.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_misc.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,73 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2002-2006 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+from translate.storage.xml_extract import misc
+
+# reduce_tree
+
+test_tree_1 = (u'a',
+               [(u'b', []),
+                (u'c', [(u'd', []), (u'e', [])]),
+                (u'f', [(u'g', [(u'h', [])])])])
+
+test_tree_2 = (1,
+               [(2, []),
+                (3, [(4, []), (5, [])]),
+                (6, [(7, [(8, [])])])])
+
+
+def get_children(node):
+    return node[1]
+
+def test_reduce_tree():
+    def concatenate(parent_node, node, string):
+        return string + node[0]
+
+    assert u'abcdefgh' == misc.reduce_tree(concatenate, test_tree_1, test_tree_1, get_children, u'')
+
+    def get_even_and_total(parent_node, node, even_lst, total):
+        num = node[0]
+        if num % 2 == 0:
+            even_lst.append(num)
+        return even_lst, total + num
+
+    assert ([2, 4, 6, 8], 36) == misc.reduce_tree(get_even_and_total, test_tree_2, test_tree_2, get_children, [], 0)
+
+# compose_mappings
+
+left_mapping     = {1:    u'a', 2:    u'b', 3: u'c', 4: u'd',  5: u'e'}
+right_mapping    = {u'a': -1,   u'b': -2,            u'd': -4, u'e': -5, u'f': -6}
+
+composed_mapping = {1: -1,      2: -2,               4: -4,    5: -5}
+
+def test_compose_mappings():
+    assert composed_mapping == misc.compose_mappings(left_mapping, right_mapping)
+
+# parse_tag
+
+def test_parse_tag():
+    assert (u'some-urn', u'some-tag') == \
+        misc.parse_tag(u'{some-urn}some-tag')
+
+    assert (u'urn:oasis:names:tc:opendocument:xmlns:office:1.0', u'document-content') == \
+        misc.parse_tag(u'{urn:oasis:names:tc:opendocument:xmlns:office:1.0}document-content')
+

Added: translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_unit_tree.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_unit_tree.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_unit_tree.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_unit_tree.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,101 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2002-2006 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+from translate.storage.xml_extract import unit_tree
+from translate.storage import factory
+
+# _split_xpath_component
+
+def test__split_xpath_component():
+    assert ('some-tag', 0) == unit_tree._split_xpath_component('some-tag[0]')
+
+# _split_xpath
+
+def test__split_xpath():
+    assert [(u'p', 4), (u'text', 3), (u'body', 2), (u'document-content', 1)] == \
+        unit_tree._split_xpath(u'document-content[1]/body[2]/text[3]/p[4]')
+    
+# _add_unit_to_tree
+
+def make_tree_1(unit):
+    root = unit_tree.XPathTree()
+    node = root
+    
+    node.children[u'document-content', 1] = unit_tree.XPathTree()
+    node = node.children[u'document-content', 1]
+    
+    node.children[u'body', 1] = unit_tree.XPathTree()
+    node = node.children[u'body', 1]
+
+    node.children[u'text', 1] = unit_tree.XPathTree()
+    node = node.children[u'text', 1]
+    
+    node.children[u'p', 1] = unit_tree.XPathTree()
+    node = node.children[u'p', 1]
+
+    node.unit = unit
+
+    return root
+
+def make_tree_2(unit_1, unit_2):
+    root = make_tree_1(unit_1)
+    node = root.children[u'document-content', 1]
+    
+    node.children[u'body', 2] = unit_tree.XPathTree()
+    node = node.children[u'body', 2]
+
+    node.children[u'text', 3] = unit_tree.XPathTree()
+    node = node.children[u'text', 3]
+    
+    node.children[u'p', 4] = unit_tree.XPathTree()
+    node = node.children[u'p', 4]
+
+    node.unit = unit_2
+
+    return root
+
+def test__add_unit_to_tree():
+    xliff_file = factory.classes[u'xlf']()
+
+    # Add the first unit
+    
+    unit_1 = xliff_file.UnitClass(u'Hello')
+    xpath_1 = u'document-content[1]/body[1]/text[1]/p[1]'
+
+    constructed_tree_1 = unit_tree.XPathTree()
+    unit_tree._add_unit_to_tree(constructed_tree_1,
+                                unit_tree._split_xpath(xpath_1), 
+                                unit_1)
+    test_tree_1 = make_tree_1(unit_1)
+    assert test_tree_1 == constructed_tree_1
+
+    # Add another unit
+
+    unit_2 = xliff_file.UnitClass(u'World')
+    xpath_2 = u'document-content[1]/body[2]/text[3]/p[4]'
+    
+    constructed_tree_2 = make_tree_1(unit_1)
+    unit_tree._add_unit_to_tree(constructed_tree_2, 
+                                unit_tree._split_xpath(xpath_2),
+                                unit_2)
+    test_tree_2 = make_tree_2(unit_1, unit_2)
+    assert test_tree_2 == constructed_tree_2

Added: translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_xpath_breadcrumb.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_xpath_breadcrumb.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_xpath_breadcrumb.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/xml_extract/test_xpath_breadcrumb.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,49 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2002-2006 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+import xpath_breadcrumb
+
+def test_breadcrumb():
+    xb = xpath_breadcrumb.XPathBreadcrumb()
+    assert xb.xpath == u''
+
+    xb.start_tag(u'a')
+    assert xb.xpath == u'a[0]'
+
+    xb.start_tag(u'b')
+    assert xb.xpath == u'a[0]/b[0]'
+    xb.end_tag()
+
+    assert xb.xpath == u'a[0]'
+
+    xb.start_tag(u'b')
+    assert xb.xpath == u'a[0]/b[1]'
+    xb.end_tag()
+
+    assert xb.xpath == u'a[0]'
+    xb.end_tag()
+
+    assert xb.xpath == u''
+
+    xb.start_tag('a')
+    assert xb.xpath == u'a[1]'
+

Added: translate-toolkit/branches/upstream/current/translate/storage/xml_extract/unit_tree.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/xml_extract/unit_tree.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/xml_extract/unit_tree.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/xml_extract/unit_tree.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,120 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2002-2006 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+from lxml import etree
+
+from translate.storage import base
+from translate.misc.typecheck import accepts, Self, IsCallable, IsOneOf, Any
+from translate.misc.typecheck.typeclasses import Number
+
+class XPathTree(object):
+    @accepts(Self(), base.TranslationUnit)
+    def __init__(self, unit = None):
+        self.unit = unit
+        self.children = {}
+
+    def __eq__(self, other):
+        return isinstance(other, XPathTree) and \
+            self.unit == other.unit and \
+            self.children == other.children
+
+ at accepts(unicode)
+def _split_xpath_component(xpath_component):
+    """Split an xpath component into a tag-index tuple.
+     
+    >>> split_xpath_component('{urn:oasis:names:tc:opendocument:xmlns:office:1.0}document-content[0]')
+    ('{urn:oasis:names:tc:opendocument:xmlns:office:1.0}document-content', 0).
+    """
+    lbrac = xpath_component.rfind(u'[')
+    rbrac = xpath_component.rfind(u']')
+    tag   = xpath_component[:lbrac]
+    index = int(xpath_component[lbrac+1:rbrac])
+    return tag, index
+
+ at accepts(unicode)
+def _split_xpath(xpath):
+    """Split an 'xpath' string separated by / into a reversed list of its components. Thus:
+    
+    >>> split_xpath('document-content[1]/body[2]/text[3]/p[4]')
+    [('p', 4), ('text', 3), ('body', 2), ('document-content', 1)]
+    
+    The list is reversed so that it can be used as a stack, where the top of the stack is
+    the first component.
+    """    
+    components = xpath.split(u'/')
+    components = [_split_xpath_component(component) for component in components]
+    return list(reversed(components))
+
+ at accepts(etree._Element, [(unicode, Number)], base.TranslationUnit)
+def _add_unit_to_tree(node, xpath_components, unit):
+    """Walk down the tree rooted a node, and follow nodes which correspond to the
+    components of xpath_components. When reaching the end of xpath_components,
+    set the reference of the node to unit.
+    
+    With reference to the tree diagram in build_unit_tree, 
+      
+      add_unit_to_tree(node, [('p', 2), ('text', 3), ('body', 2), ('document-content', 1)], unit)
+    
+    would begin by popping ('document-content', 1) from the path and following the node marked
+    ('document-content', 1) in the tree. Likewise, will descend down the nodes marked ('body', 2) 
+    and ('text', 3).
+    
+    Since the node marked ('text', 3) has no child node marked ('p', 2), this node is created. Then
+    the add_unit_to_tree descends down this node. When this happens, there are no xpath components
+    left to pop. Thus, node.unit = unit is executed. 
+    """
+    if len(xpath_components) > 0:
+        component = xpath_components.pop() # pop the stack; is a component such as ('p', 4)
+        # if the current node does not have any children indexed by 
+        # the current component, add such a child
+        if component not in node.children: 
+            node.children[component] = XPathTree()
+        _add_unit_to_tree(node.children[component], xpath_components, unit)
+    else:
+        node.unit = unit
+
+ at accepts(base.TranslationStore)
+def build_unit_tree(store):
+    """Enumerate a translation store and build a tree with XPath components as nodes
+    and where a node contains a unit if a path from the root of the tree to the node
+    containing the unit, is equal to the XPath of the unit.
+    
+    The tree looks something like this:
+    
+    root
+       `- ('document-content', 1)
+          `- ('body', 2)
+             |- ('text', 1)
+             |  `- ('p', 1)
+             |     `- <reference to a unit>
+             |- ('text', 2)
+             |  `- ('p', 1)
+             |     `- <reference to a unit>
+             `- ('text', 3)
+                `- ('p', 1)
+                   `- <reference to a unit>
+    """
+    tree = XPathTree()
+    for unit in store.units:
+        location = _split_xpath(unit.getlocations()[0])
+        _add_unit_to_tree(tree, location, unit)
+    return tree

Added: translate-toolkit/branches/upstream/current/translate/storage/xml_extract/xpath_breadcrumb.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/xml_extract/xpath_breadcrumb.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/xml_extract/xpath_breadcrumb.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/xml_extract/xpath_breadcrumb.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,80 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2002-2006 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+from translate.misc.typecheck import accepts, Self, IsCallable, IsOneOf, Any
+
+class XPathBreadcrumb(object):
+    """A class which is used to build XPath-like paths as a DOM tree is
+    walked. It keeps track of the number of times which it has seen
+    a certain tag, so that it will correctly create indices for tags.
+    
+    Initially, the path is empty. Thus
+    >>> xb = XPathBreadcrumb()
+    >>> xb.xpath
+    ""
+    
+    Suppose we walk down a DOM node for the tag <foo> and we want to
+    record this, we simply do
+    >>> xb.start_tag('foo')
+    
+    Now, the path is no longer empty. Thus
+    >>> xb.xpath
+    foo[0]
+    
+    Now suppose there are two <bar> tags under the tag <foo> (that is
+    <foo><bar></bar><bar></bar><foo>), then the breadcrumb will keep
+    track of the number of times it sees <bar>. Thus
+    
+    >>> xb.start_tag('bar')
+    >>> xb.xpath
+    foo[0]/bar[0]
+    >>> xb.end_tag()
+    >>> xb.xpath
+    foo[0]
+    >>> xb.start_tag('bar')
+    >>> xb.xpath
+    foo[0]/bar[1]
+    """
+
+    def __init__(self):
+        self._xpath = []
+        self._tagtally = [{}]
+        
+    @accepts(Self(), unicode)
+    def start_tag(self, tag):
+        tally_dict = self._tagtally[-1]
+        tally = tally_dict.get(tag, -1) + 1
+        tally_dict[tag] = tally
+        self._xpath.append((tag, tally))
+        self._tagtally.append({})
+      
+    def end_tag(self):
+        self._xpath.pop()
+        self._tagtally.pop()
+
+    def _get_xpath(self):
+        def str_component(component):
+            tag, pos = component
+            return u"%s[%d]" % (tag, pos)
+        return u"/".join(str_component(component) for component in self._xpath)
+    
+    xpath = property(_get_xpath)

Added: translate-toolkit/branches/upstream/current/translate/storage/xml_name.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/storage/xml_name.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/storage/xml_name.py (added)
+++ translate-toolkit/branches/upstream/current/translate/storage/xml_name.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,69 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# translate is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+class XmlNamespace(object):
+    def __init__(self, namespace):
+        self._namespace = namespace
+        
+    def name(self, tag):
+        return "{%s}%s" % (self._namespace, tag)
+
+class XmlNamer(object):
+    """Initialize me with a DOM node or a DOM document node (the
+    toplevel node you get when parsing an XML file). The use me
+    to get generate fully qualified XML names.
+
+    >>> xml = '<office:document-styles xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"></office>'
+    >>> from lxml import etree
+    >>> namer = XmlNamer(etree.fromstring(xml))
+    >>> namer.name('office', 'blah')
+    {urn:oasis:names:tc:opendocument:xmlns:office:1.0}blah
+    >>> namer.name('office:blah')
+    {urn:oasis:names:tc:opendocument:xmlns:office:1.0}blah
+
+    I can also give you XmlNamespace objects if you give me the abbreviated
+    namespace name. These are useful if you need to reference a namespace 
+    continuously.
+
+    >>> office_ns = name.namespace('office')
+    >>> office_ns.name('foo')
+    {urn:oasis:names:tc:opendocument:xmlns:office:1.0}foo
+    """
+
+    def __init__(self, dom_node):
+        # Allow the user to pass a dom node of the
+        # XML document nodle
+        if hasattr(dom_node, 'nsmap'):
+            self.nsmap = dom_node.nsmap
+        else:
+            self.nsmap = dom_node.getroot().nsmap
+
+    def name(self, namespace_shortcut, tag=None):
+        # If the user doesn't pass an argument into 'tag'
+        # then namespace_shortcut contains a tag of the form
+        # 'short-namespace:tag'
+        if tag is None:
+            namespace_shortcut, tag = namespace_shortcut.split(':')
+        return "{%s}%s" % (self.nsmap[namespace_shortcut], tag)
+
+    def namespace(self, namespace_shortcut):
+        return XmlNamespace(self.nsmap[namespace_shortcut])

Modified: translate-toolkit/branches/upstream/current/translate/tools/pocount.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/tools/pocount.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/tools/pocount.py (original)
+++ translate-toolkit/branches/upstream/current/translate/tools/pocount.py Mon Dec 29 14:57:18 2008
@@ -156,11 +156,13 @@
             self.totals[key] += stats[key]
 
     def handlefile(self, filename):
-        stats = calcstats(filename)
-        if stats:
+        try:
+            stats = calcstats(filename)
             self.updatetotals(stats)
             summarize(filename, stats, self.CSVstyle)
             self.filecount += 1
+        except: # This happens if we have a broken file.
+            print >> sys.stderr, sys.exc_info()[1]
 
     def handlefiles(self, dirname, filenames):
         for filename in filenames:

Modified: translate-toolkit/branches/upstream/current/translate/tools/podebug.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/tools/podebug.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/tools/podebug.py (original)
+++ translate-toolkit/branches/upstream/current/translate/tools/podebug.py Mon Dec 29 14:57:18 2008
@@ -26,9 +26,15 @@
 """
 
 from translate.storage import factory
+from translate.misc.rich import map_rich, only_strings
 import os
 import re
 import md5
+
+def add_prefix(prefix, strings):
+    for string in strings:
+        string.insert(0, prefix)
+    return strings
 
 class podebug:
     def __init__(self, format=None, rewritestyle=None, hash=None, ignoreoption=None):
@@ -135,16 +141,10 @@
                 hashable = unit.source
             prefix = md5.new(hashable).hexdigest()[:self.hash] + " "
         if self.rewritefunc:
-            unit.target = self.rewritefunc(unit.source)
+            unit.rich_target = map_rich(only_strings(self.rewritefunc), unit.rich_source)
         elif not unit.istranslated():
-            unit.target = unit.source
-        if unit.hasplural():
-            strings = unit.target.strings
-            for i, string in enumerate(strings):
-                strings[i] = prefix + string
-            unit.target = strings
-        else:
-            unit.target = prefix + unit.target
+            unit.rich_target = unit.rich_source
+        unit.rich_target = add_prefix(prefix, unit.rich_target)
         return unit
 
     def convertstore(self, store):

Modified: translate-toolkit/branches/upstream/current/translate/tools/poterminology.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/tools/poterminology.py?rev=1519&op=diff
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/tools/poterminology.py (original)
+++ translate-toolkit/branches/upstream/current/translate/tools/poterminology.py Mon Dec 29 14:57:18 2008
@@ -27,6 +27,7 @@
 from translate.misc import optrecurse
 from translate.storage import po
 from translate.storage import factory
+from translate.misc import file_discovery
 import os
 import re
 import sys
@@ -358,16 +359,6 @@
             termfile.units.append(unit)
         open(options.output, "w").write(str(termfile))
 
-def find_installed_file(filename):
-    root = __file__
-    if os.path.islink(root):
-        root = os.path.realpath(root)
-    filepath = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(root))), 'share', filename )
-
-    if not os.path.exists(filepath):
-        return None
-    return filepath
-
 def fold_case_option(option, opt_str, value, parser):
     parser.values.ignorecase = False
     parser.values.foldtitle = True
@@ -422,7 +413,7 @@
     parser.stoprelist = []
     parser.stopfoldtitle = True
     parser.stopignorecase = False
-    parser.defaultstopfile = find_installed_file('stoplist-en')
+    parser.defaultstopfile = file_discovery.get_abs_data_filename('stoplist-en')
     parser.add_option("-S", "--stopword-list", type="string", metavar="STOPFILE", 
         action="callback", callback=parse_stopword_file,
         help="read stopword (term exclusion) list from STOPFILE (default %s)" % parser.defaultstopfile,

Added: translate-toolkit/branches/upstream/current/translate/tools/pretranslate
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/tools/pretranslate?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/tools/pretranslate (added)
+++ translate-toolkit/branches/upstream/current/translate/tools/pretranslate Mon Dec 29 14:57:18 2008
@@ -1,0 +1,29 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# 
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""fill localization files with suggested translations based on
+translation memory and existing translations
+"""
+
+from translate.tools import pretranslate
+
+if __name__ == '__main__':
+  pretranslate.main()
+

Propchange: translate-toolkit/branches/upstream/current/translate/tools/pretranslate
------------------------------------------------------------------------------
    svn:executable = *

Added: translate-toolkit/branches/upstream/current/translate/tools/pretranslate.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/tools/pretranslate.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/tools/pretranslate.py (added)
+++ translate-toolkit/branches/upstream/current/translate/tools/pretranslate.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,179 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# 
+# Copyright 2008 Zuza Software Foundation
+# 
+# This file is part of translate.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""fill localization files with suggested translations based on
+translation memory and existing translations
+"""
+
+from translate.storage import factory
+from translate.storage import xliff
+from translate.search import match
+
+
+# We don't want to reinitialise the TM each time, so let's store it here.
+tmmatcher = None
+
+
+def memory(tmfiles, max_candidates=1, min_similarity=75, max_length=1000):
+    """Returns the TM store to use. Only initialises on first call."""
+    global tmmatcher
+    # Only initialise first time
+    if tmmatcher is None:
+        if isinstance(tmfiles, list):
+            tmstore = [factory.getobject(tmfile) for tmfile in tmfiles]
+        else:
+            tmstore = factory.getobject(tmfiles)
+        tmmatcher = match.matcher(tmstore, max_candidates=max_candidates, min_similarity=min_similarity, max_length=max_length)
+    return tmmatcher
+
+
+def pretranslate_file(input_file, output_file, template_file, tm=None, min_similarity=75, fuzzymatching=True):
+    """pretranslate any factory supported file with old translations and translation memory"""
+    input_store = factory.getobject(input_file)
+    template_store = None
+    if template_file is not None:
+        template_store = factory.getobject(template_file)
+        
+    output = pretranslate_store(input_store, template_store, tm, min_similarity, fuzzymatching)
+    output_file.write(str(output))
+    return 1
+
+
+def match_template_id (input_unit, template_store):
+    """returns a matching unit from a template"""
+    #since oo2po and moz2po use localtion as unique identifiers for strings
+    #we match against location first, then check for matching source strings
+    #FIXME: this makes absolutely no sense for other po files
+    for location in input_unit.getlocations():
+        matching_unit = template_store.locationindex.get(location, None)
+        #do we really want to discard units with matching locations but no matching source?
+        if matching_unit is not None and matching_unit.source == input_unit.source and len(matching_unit.target) > 0:
+            return matching_unit
+        else:
+            #if no match by location information search for identical source strings
+            #FIXME: need a better method for matching strings, we don't take context into account
+            #FIXME: need a better test for when not to use location info for matching
+            return template_store.findunit(input_unit.source)
+
+
+def match_fuzzy(input_unit, matchers):
+    """returns a fuzzy match from a queue of matchers"""
+    for matcher in matchers:
+        fuzzycandidates = matcher.matches(input_unit.source)
+        if fuzzycandidates:
+            return fuzzycandidates[0]
+
+
+def pretranslate_unit(input_unit, template_store, matchers=None, mark_reused=False) :
+    """returns a pretranslated unit, if no translation was found return input unit unchanged"""
+
+    matching_unit = None
+    #do template matching
+    if template_store:
+        matching_unit = match_template_id(input_unit, template_store)
+
+    if matching_unit and len(matching_unit.target) > 0:
+        input_unit.merge(matching_unit, authoritative=True)
+    elif matchers:
+        #do fuzzy matching
+        matching_unit = match_fuzzy(input_unit, matchers)
+        if matching_unit and len(matching_unit.target) > 0:
+            #FIXME: should we dispatch here instead of this crude type check
+            if isinstance(input_unit, xliff.xliffunit):
+                #FIXME: what about origin and lang?
+                input_unit.addalttrans(matching_unit.target, sourcetxt=matching_unit.source)
+            else:
+                input_unit.merge(matching_unit, authoritative=True)
+
+    #FIXME: ugly hack required by pot2po to mark old
+    #translations reused for new file. loops over
+    if mark_reused and matching_unit and template_store:
+        original_unit = template_store.findunit(matching_unit.source)
+        if original_unit is not None:
+            original_unit.reused = True
+
+    return input_unit
+
+def prepare_template_pofile(template_store):
+    """po format specific template preparation logic"""
+    #do we want to consider obsolete translations?
+    for unit in template_store.units:
+        if unit.isobsolete():
+            unit.resurrect()
+
+
+def pretranslate_store(input_store, template_store, tm=None, min_similarity=75, fuzzymatching=True):
+    """does the actual pretranslation"""
+    #preperation
+    matchers = []
+    #prepare template
+    if template_store is not None:
+        template_store.makeindex()
+        #template preparation based on type
+        prepare_template = "prepare_template_%s" % template_store.__class__.__name__
+        if  globals().has_key(prepare_template):
+            globals()[prepare_template](template_store)
+                
+        if fuzzymatching:
+            #create template matcher
+            #FIXME: max_length hardcoded
+            matcher = match.matcher(template_store, max_candidates=1, min_similarity=min_similarity, max_length=3000, usefuzzy=True)
+            matcher.addpercentage = False
+            matchers.append(matcher)
+
+    #prepare tm    
+    #create tm matcher
+    if tm and fuzzymatching:
+        #FIXME: max_length hardcoded
+        matcher = memory(tm, max_candidates=1, min_similarity=min_similarity, max_length=1000)
+        matcher.addpercentage = False
+        matchers.append(matcher)
+    
+    #main loop
+    for input_unit in input_store.units:
+        if  input_unit.istranslatable():
+            input_unit = pretranslate_unit(input_unit, template_store, matchers)
+    
+    return input_store
+
+
+def main(argv=None):
+    from translate.convert import convert
+    formats = {"pot": ("po", pretranslate_file), ("pot", "po"): ("po", pretranslate_file),
+               "po": ("po", pretranslate_file), ("po", "po"): ("po", pretranslate_file),
+               "xlf": ("xlf", pretranslate_file), ("xlf", "xlf"): ("xlf", pretranslate_file),
+               }
+    parser = convert.ConvertOptionParser(formats, usetemplates=True, 
+        allowmissingtemplate=True, description=__doc__)
+    parser.add_option("", "--tm", dest="tm", default=None,
+        help="The file to use as translation memory when fuzzy matching")
+    parser.passthrough.append("tm")
+    defaultsimilarity = 75
+    parser.add_option("-s", "--similarity", dest="min_similarity", default=defaultsimilarity,
+        type="float", help="The minimum similarity for inclusion (default: %d%%)" % defaultsimilarity)
+    parser.passthrough.append("min_similarity")
+    parser.add_option("--nofuzzymatching", dest="fuzzymatching", action="store_false", 
+        default=True, help="Disable fuzzy matching")
+    parser.passthrough.append("fuzzymatching")
+    parser.run(argv)
+
+
+if __name__ == '__main__':
+    main()

Added: translate-toolkit/branches/upstream/current/translate/tools/test_pretranslate.py
URL: http://svn.debian.org/wsvn/translate-toolkit/branches/upstream/current/translate/tools/test_pretranslate.py?rev=1519&op=file
==============================================================================
--- translate-toolkit/branches/upstream/current/translate/tools/test_pretranslate.py (added)
+++ translate-toolkit/branches/upstream/current/translate/tools/test_pretranslate.py Mon Dec 29 14:57:18 2008
@@ -1,0 +1,251 @@
+#!/usr/bin/env python
+
+from translate.tools import pretranslate
+from translate.convert import test_convert
+from translate.misc import wStringIO
+from translate.storage import po
+import warnings
+
+class TestPretranslate:
+    def setup_method(self, method):
+        warnings.resetwarnings()
+
+    def teardown_method(self, method):
+        warnings.resetwarnings()
+
+    def pretranslatepo(self, input_source, template_source=None):
+        """helper that converts strings to po source without requiring files"""
+        input_file = wStringIO.StringIO(input_source)
+        if template_source:
+            template_file = wStringIO.StringIO(template_source)
+        else:
+            template_file = None
+        output_file = wStringIO.StringIO()
+        
+        pretranslate.pretranslate_file(input_file, output_file, template_file)
+        output_file.seek(0)
+        return po.pofile(output_file.read())
+
+    def singleunit(self, pofile):
+        """checks that the pofile contains a single non-header unit, and returns it"""
+        if len(pofile.units) == 2 and  pofile.units[0].isheader():
+            print pofile.units[1]
+            return pofile.units[1]
+        else:
+            print pofile.units[0]
+            return pofile.units[0]
+        
+    def test_pretranslatepo_blank(self):
+        """checks that the pretranslatepo function is working for a simple file initialisation"""
+        input_source = '''#: simple.label%ssimple.accesskey\nmsgid "A &hard coded newline.\\n"\nmsgstr ""\n''' % po.lsep
+        newpo = self.pretranslatepo(input_source)
+        assert str(self.singleunit(newpo)) == input_source
+
+    def test_merging_simple(self):
+        """checks that the pretranslatepo function is working for a simple merge"""
+        input_source = '''#: simple.label%ssimple.accesskey\nmsgid "A &hard coded newline.\\n"\nmsgstr ""\n''' % po.lsep
+        template_source = '''#: simple.label%ssimple.accesskey\nmsgid "A &hard coded newline.\\n"\nmsgstr "&Hart gekoeerde nuwe lyne\\n"\n''' % po.lsep
+        newpo = self.pretranslatepo(input_source, template_source)
+        assert str(self.singleunit(newpo)) == template_source
+
+    def test_merging_messages_marked_fuzzy(self):
+        """test that when we merge PO files with a fuzzy message that it remains fuzzy"""
+        input_source = '''#: simple.label%ssimple.accesskey\nmsgid "A &hard coded newline.\\n"\nmsgstr ""\n''' % po.lsep
+        template_source = '''#: simple.label%ssimple.accesskey\n#, fuzzy\nmsgid "A &hard coded newline.\\n"\nmsgstr "&Hart gekoeerde nuwe lyne\\n"\n''' % po.lsep
+        newpo = self.pretranslatepo(input_source, template_source)
+        assert str(self.singleunit(newpo)) == template_source
+
+    def test_merging_plurals_with_fuzzy_matching(self):
+        """test that when we merge PO files with a fuzzy message that it remains fuzzy"""
+        input_source = r'''#: file.cpp:2
+msgid "%d manual"
+msgid_plural "%d manuals"
+msgstr[0] ""
+msgstr[1] ""
+'''
+        template_source = r'''#: file.cpp:3
+#, fuzzy
+msgid "%d manual"
+msgid_plural "%d manuals"
+msgstr[0] "%d handleiding."
+msgstr[1] "%d handleidings."
+'''
+        # The #: comment and msgid's are different between the pot and the po
+        poexpected = r'''#: file.cpp:2
+#, fuzzy
+msgid "%d manual"
+msgid_plural "%d manuals"
+msgstr[0] "%d handleiding."
+msgstr[1] "%d handleidings."
+'''
+        newpo = self.pretranslatepo(input_source, template_source)
+        assert str(self.singleunit(newpo)) == poexpected
+
+    def xtest_merging_msgid_change(self):
+        """tests that if the msgid changes but the location stays the same that we merge"""
+        input_source = '''#: simple.label\n#: simple.accesskey\nmsgid "Its &hard coding a newline.\\n"\nmsgstr ""\n'''
+        template_source = '''#: simple.label\n#: simple.accesskey\nmsgid "A &hard coded newline.\\n"\nmsgstr "&Hart gekoeerde nuwe lyne\\n"\n'''
+        poexpected = '''#: simple.label\n#: simple.accesskey\n#, fuzzy\nmsgid "Its &hard coding a newline.\\n"\nmsgstr "&Hart gekoeerde nuwe lyne\\n"\n'''
+        newpo = self.pretranslatepo(input_source, template_source)
+        print newpo
+        assert str(newpo) == poexpected
+
+    def test_merging_location_change(self):
+        """tests that if the location changes but the msgid stays the same that we merge"""
+        input_source = '''#: new_simple.label%snew_simple.accesskey\nmsgid "A &hard coded newline.\\n"\nmsgstr ""\n''' % po.lsep
+        template_source = '''#: simple.label%ssimple.accesskey\nmsgid "A &hard coded newline.\\n"\nmsgstr "&Hart gekoeerde nuwe lyne\\n"\n''' % po.lsep
+        poexpected = '''#: new_simple.label%snew_simple.accesskey\nmsgid "A &hard coded newline.\\n"\nmsgstr "&Hart gekoeerde nuwe lyne\\n"\n''' % po.lsep
+        newpo = self.pretranslatepo(input_source, template_source)
+        print newpo
+        assert str(newpo) == poexpected
+
+    def test_merging_location_and_whitespace_change(self):
+        """test that even if the location changes that if the msgid only has whitespace changes we can still merge"""
+        input_source = '''#: singlespace.label%ssinglespace.accesskey\nmsgid "&We have spaces"\nmsgstr ""\n''' % po.lsep
+        template_source = '''#: doublespace.label%sdoublespace.accesskey\nmsgid "&We  have  spaces"\nmsgstr "&One  het  spasies"\n''' % po.lsep
+        poexpected = '''#: singlespace.label%ssinglespace.accesskey\n#, fuzzy\nmsgid "&We have spaces"\nmsgstr "&One  het  spasies"\n''' % po.lsep
+        newpo = self.pretranslatepo(input_source, template_source)
+        print newpo
+        assert str(newpo) == poexpected
+
+    def wtest_merging_accelerator_changes(self):
+        """test that a change in the accelerator localtion still allows merging"""
+        input_source = '''#: someline.c\nmsgid "A&bout"\nmsgstr ""\n'''
+        template_source = '''#: someline.c\nmsgid "&About"\nmsgstr "&Info"\n'''
+        poexpected = '''#: someline.c\nmsgid "A&bout"\nmsgstr "&Info"\n'''
+        newpo = self.pretranslatepo(input_source, template_source)
+        print newpo
+        assert str(newpo) == poexpected
+
+    def xtest_lines_cut_differently(self):
+        """Checks that the correct formatting is preserved when pot an po lines differ."""
+        input_source = '''#: simple.label\nmsgid "Line split "\n"differently"\nmsgstr ""\n'''
+        template_source = '''#: simple.label\nmsgid "Line"\n" split differently"\nmsgstr "Lyne verskillend gesny"\n'''
+        newpo = self.pretranslatepo(input_source, template_source)
+        newpounit = self.singleunit(newpo)
+        assert str(newpounit) == template_source
+
+    def test_merging_automatic_comments_dont_duplicate(self):
+        """ensure that we can merge #. comments correctly"""
+        input_source = '''#. Row 35\nmsgid "&About"\nmsgstr ""\n'''
+        template_source = '''#. Row 35\nmsgid "&About"\nmsgstr "&Info"\n'''
+        newpo = self.pretranslatepo(input_source, template_source)
+        newpounit = self.singleunit(newpo)
+        assert str(newpounit) == template_source
+
+    def test_merging_automatic_comments_new_overides_old(self):
+        """ensure that new #. comments override the old comments"""
+        input_source = '''#. new comment\n#: someline.c\nmsgid "&About"\nmsgstr ""\n'''
+        template_source = '''#. old comment\n#: someline.c\nmsgid "&About"\nmsgstr "&Info"\n'''
+        poexpected = '''#. new comment\n#: someline.c\nmsgid "&About"\nmsgstr "&Info"\n'''
+        newpo = self.pretranslatepo(input_source, template_source)
+        newpounit = self.singleunit(newpo)
+        assert str(newpounit) == poexpected
+
+    def test_merging_comments_with_blank_comment_lines(self):
+        """test that when we merge a comment that has a blank line we keep the blank line"""
+        input_source = '''#: someline.c\nmsgid "About"\nmsgstr ""\n'''
+        template_source = '''# comment1\n#\n# comment2\n#: someline.c\nmsgid "About"\nmsgstr "Omtrent"\n'''
+        poexpected = template_source
+        newpo = self.pretranslatepo(input_source, template_source)
+        newpounit = self.singleunit(newpo)
+        assert str(newpounit) == poexpected
+
+    def test_empty_commentlines(self):
+        input_source = '''#: paneSecurity.title
+msgid "Security"
+msgstr ""
+'''
+        template_source = '''# - Contributor(s):
+# -
+# - Alternatively, the
+# -
+#: paneSecurity.title
+msgid "Security"
+msgstr "Sekuriteit"
+'''
+        poexpected = template_source
+        newpo = self.pretranslatepo(input_source, template_source)
+        newpounit = self.singleunit(newpo)
+        print "expected"
+        print poexpected
+        print "got:"
+        print str(newpounit)
+        assert str(newpounit) == poexpected
+
+    def test_merging_msgidcomments(self):
+        """ensure that we can merge msgidcomments messages"""
+        input_source = r'''#: window.width
+msgid ""
+"_: Do not translate this.\n"
+"36em"
+msgstr ""
+'''
+        template_source = r'''#: window.width
+msgid ""
+"_: Do not translate this.\n"
+"36em"
+msgstr "36em"
+'''
+        newpo = self.pretranslatepo(input_source, template_source)
+        newpounit = self.singleunit(newpo)
+        assert str(newpounit) == template_source
+
+    def test_merging_plurals(self):
+        """ensure that we can merge plural messages"""
+        input_source = '''msgid "One"\nmsgid_plural "Two"\nmsgstr[0] ""\nmsgstr[1] ""\n''' 
+        template_source = '''msgid "One"\nmsgid_plural "Two"\nmsgstr[0] "Een"\nmsgstr[1] "Twee"\nmsgstr[2] "Drie"\n'''
+        newpo = self.pretranslatepo(input_source, template_source)
+        print newpo
+        newpounit = self.singleunit(newpo)
+        assert str(newpounit) == template_source
+        
+    def test_merging_resurect_obsolete_messages(self):
+        """check that we can reuse old obsolete messages if the message comes back"""
+        input_source = '''#: resurect.c\nmsgid "&About"\nmsgstr ""\n'''
+        template_source = '''#~ msgid "&About"\n#~ msgstr "&Omtrent"\n'''
+        expected = '''#: resurect.c\nmsgid "&About"\nmsgstr "&Omtrent"\n'''
+        newpo = self.pretranslatepo(input_source, template_source)
+        print newpo
+        assert str(newpo) == expected
+
+    def test_merging_comments(self):
+        """Test that we can merge comments correctly"""
+        input_source = '''#. Don't do it!\n#: file.py:1\nmsgid "One"\nmsgstr ""\n''' 
+        template_source = '''#. Don't do it!\n#: file.py:2\nmsgid "One"\nmsgstr "Een"\n'''
+        poexpected = '''#. Don't do it!\n#: file.py:1\nmsgid "One"\nmsgstr "Een"\n'''
+        newpo = self.pretranslatepo(input_source, template_source)
+        print newpo
+        newpounit = self.singleunit(newpo)
+        assert str(newpounit) == poexpected
+        
+    def test_merging_typecomments(self):
+        """Test that we can merge with typecomments"""
+        input_source = '''#: file.c:1\n#, c-format\nmsgid "%d pipes"\nmsgstr ""\n''' 
+        template_source = '''#: file.c:2\nmsgid "%d pipes"\nmsgstr "%d pype"\n'''
+        poexpected = '''#: file.c:1\n#, c-format\nmsgid "%d pipes"\nmsgstr "%d pype"\n'''
+        newpo = self.pretranslatepo(input_source, template_source)
+        newpounit = self.singleunit(newpo)
+        print newpounit
+        assert str(newpounit) == poexpected
+
+        input_source = '''#: file.c:1\n#, c-format\nmsgid "%d computers"\nmsgstr ""\n''' 
+        template_source = '''#: file.c:2\n#, c-format\nmsgid "%s computers "\nmsgstr "%s-rekenaars"\n'''
+        poexpected = '''#: file.c:1\n#, fuzzy, c-format\nmsgid "%d computers"\nmsgstr "%s-rekenaars"\n'''
+        newpo = self.pretranslatepo(input_source, template_source)
+        newpounit = self.singleunit(newpo)
+        assert newpounit.isfuzzy()
+        assert newpounit.hastypecomment("c-format")
+
+class TestPretranslateCommand(test_convert.TestConvertCommand, TestPretranslate):
+    """Tests running actual pretranslate commands on files"""
+    convertmodule = pretranslate
+
+    def test_help(self):
+        """tests getting help"""
+        options = test_convert.TestConvertCommand.test_help(self)
+        options = self.help_check(options, "-t TEMPLATE, --template=TEMPLATE")
+        options = self.help_check(options, "--tm")
+        options = self.help_check(options, "-s MIN_SIMILARITY, --similarity=MIN_SIMILARITY")
+        options = self.help_check(options, "--nofuzzymatching", last=True)
+




More information about the Debian-l10n-commits mailing list