[Debian-l10n-commits] translate-toolkit branch master updated. debian/1.13.0-1

Stuart Prescott stuart at moszumanska.debian.org
Sun Sep 13 01:28:26 UTC 2015


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "translate-toolkit".

The branch, master has been updated
       via  fe1d5f2bf00ec9e921441e23f37fb2219d1c3d1e (commit)
       via  751b0369abe1bc40918f675f16653ffe1760373a (commit)
       via  2ccb8bf1e4a50104d71473548fa6909168ecbeb8 (commit)
       via  e64c8650fbd0516635115961c25fb584cef93005 (commit)
       via  424cdc59a404066a2001e033ef4d2ad558354f2a (commit)
       via  f69a398b6bae870f5b47d287973accbca7b817cb (commit)
       via  7a9a95dd9d4ca8657b5e4a624cdf60255cd914ec (commit)
       via  2ca8dc1efefb695a2737740262e173eee0386c98 (commit)
       via  cc3b72ee902ddf75547118421a0e61944fae480a (commit)
      from  94e7740318bc72a12554c8693a96d6fd8ab45f24 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------

http://anonscm.debian.org/gitweb/?p=debian-l10n/translate-toolkit.git;a=commitdiff;h=fe1d5f2bf00ec9e921441e23f37fb2219d1c3d1e

commit fe1d5f2bf00ec9e921441e23f37fb2219d1c3d1e
Author: Stuart Prescott <stuart at debian.org>
Date:   Sun Sep 13 00:54:46 2015 +1000

    Remove unneeded XS-Testsuite


http://anonscm.debian.org/gitweb/?p=debian-l10n/translate-toolkit.git;a=commitdiff;h=751b0369abe1bc40918f675f16653ffe1760373a

commit 751b0369abe1bc40918f675f16653ffe1760373a
Author: Stuart Prescott <stuart at debian.org>
Date:   Sun Sep 13 00:54:26 2015 +1000

    Bump standards-version (no changes required)


http://anonscm.debian.org/gitweb/?p=debian-l10n/translate-toolkit.git;a=commitdiff;h=2ccb8bf1e4a50104d71473548fa6909168ecbeb8

commit 2ccb8bf1e4a50104d71473548fa6909168ecbeb8
Author: Stuart Prescott <stuart at debian.org>
Date:   Fri Aug 7 00:06:51 2015 +1000

    Add changelog for release


http://anonscm.debian.org/gitweb/?p=debian-l10n/translate-toolkit.git;a=commitdiff;h=e64c8650fbd0516635115961c25fb584cef93005

commit e64c8650fbd0516635115961c25fb584cef93005
Author: Stuart Prescott <stuart at debian.org>
Date:   Sun Sep 13 00:35:26 2015 +1000

    Add xml.xsd to prevent network access


http://anonscm.debian.org/gitweb/?p=debian-l10n/translate-toolkit.git;a=commitdiff;h=424cdc59a404066a2001e033ef4d2ad558354f2a

commit 424cdc59a404066a2001e033ef4d2ad558354f2a
Author: Stuart Prescott <stuart at debian.org>
Date:   Thu Aug 6 23:59:35 2015 +1000

    Add extra entries to copyright


http://anonscm.debian.org/gitweb/?p=debian-l10n/translate-toolkit.git;a=commitdiff;h=f69a398b6bae870f5b47d287973accbca7b817cb

commit f69a398b6bae870f5b47d287973accbca7b817cb
Merge: 2ca8dc1 7a9a95d
Author: Stuart Prescott <stuart at debian.org>
Date:   Thu Aug 6 23:26:51 2015 +1000

    Merge tag 'upstream/1.13.0'
    
    Upstream version 1.13.0


http://anonscm.debian.org/gitweb/?p=debian-l10n/translate-toolkit.git;a=commitdiff;h=7a9a95dd9d4ca8657b5e4a624cdf60255cd914ec

commit 7a9a95dd9d4ca8657b5e4a624cdf60255cd914ec
Author: Stuart Prescott <stuart at debian.org>
Date:   Thu Aug 6 23:25:46 2015 +1000

    Imported Upstream version 1.13.0


http://anonscm.debian.org/gitweb/?p=debian-l10n/translate-toolkit.git;a=commitdiff;h=2ca8dc1efefb695a2737740262e173eee0386c98

commit 2ca8dc1efefb695a2737740262e173eee0386c98
Author: Stuart Prescott <stuart at debian.org>
Date:   Thu Aug 6 23:25:24 2015 +1000

    Stop excluding removed files from package


http://anonscm.debian.org/gitweb/?p=debian-l10n/translate-toolkit.git;a=commitdiff;h=cc3b72ee902ddf75547118421a0e61944fae480a

commit cc3b72ee902ddf75547118421a0e61944fae480a
Author: Stuart Prescott <stuart at debian.org>
Date:   Thu Aug 6 23:24:47 2015 +1000

    Update watch file to new location on github

-----------------------------------------------------------------------

Summary of changes:
 .coveragerc                                        |    8 +
 .gitignore                                         |   51 +
 .gitmodules                                        |    3 +
 .isort.cfg                                         |   15 +
 .travis.yml                                        |   37 +
 CREDITS                                            |   41 +
 LICENSES                                           |   27 +
 MANIFEST.in                                        |   81 -
 Makefile                                           |   92 +
 PKG-INFO                                           |   46 -
 README.rst                                         |   18 +
 debian/changelog                                   |    7 +
 debian/control                                     |    3 +-
 debian/copyright                                   |   59 +-
 debian/patches/series                              |    1 +
 debian/patches/xliff-xsd-no-network.patch          |  305 +++
 debian/watch                                       |    4 +-
 docs/_ext/translate_docs.py                        |    2 +
 docs/commands/index.rst                            |    2 +
 docs/commands/pofilter_tests.rst                   |  107 +-
 docs/commands/{json2po.rst => resx2po.rst}         |   63 +-
 docs/conf.py                                       |    6 +-
 docs/contents.rst.inc                              |    2 +-
 docs/developers/releasing.rst                      |  318 ++-
 docs/developers/styleguide.rst                     |  102 +-
 docs/formats/index.rst                             |    3 +-
 docs/formats/resx.rst                              |   36 +
 docs/installation.rst                              |   87 +-
 docs/releases/1.13.0-rc1.rst                       |   99 +
 docs/releases/1.13.0.rst                           |  184 ++
 docs/releases/dev.rst                              |   71 -
 docs/releases/index.rst                            |   12 +-
 pytest.ini                                         |    2 +
 requirements/dev.txt                               |    2 +-
 requirements/recommended.txt                       |    2 +-
 setup.cfg                                          |    5 -
 setup.py                                           |    8 +-
 .../data/test_po2prop_mozilla_files/out.properties |    4 +
 .../test_po2prop_mozilla_files/template.properties |    4 +
 .../test_po2prop_mozilla_files/translations.po     |    8 +
 tests/cli/data/test_pocount_po_file/one.po         |    2 +
 .../cli/data/test_pofilter_listfilters/stdout.txt  |   33 +-
 tests/cli/data/test_pofilter_manpage/stdout.txt    |    2 +-
 tests/cli/data/test_poswap_comments/af.po          |   11 +
 tests/cli/data/test_poswap_comments/fr.po          |   11 +
 tests/cli/data/test_poswap_comments/out.po         |   11 +
 tests/cli/data/test_poswap_fr_af/af.po             |    9 +
 tests/cli/data/test_poswap_fr_af/fr.po             |    8 +
 tests/cli/data/test_poswap_fr_af/out.po            |    9 +
 tests/cli/data/test_poswap_fr_af_reverse/fr.po     |    8 +
 tests/cli/data/test_poswap_fr_af_reverse/fr_af.po  |    8 +
 tests/cli/data/test_poswap_fr_af_reverse/out.po    |    8 +
 tests/cli/data/test_poswap_missing_units/af.po     |    5 +
 tests/cli/data/test_poswap_missing_units/fr.po     |    5 +
 tests/cli/data/test_poswap_missing_units/out.po    |    5 +
 tests/cli/data/test_prop2po_dirs/one/a.properties  |    1 +
 tests/cli/data/test_prop2po_dirs/out/a.po          |   17 +
 tests/cli/data/test_prop2po_files/one.properties   |    1 +
 tests/cli/data/test_prop2po_files/out.po           |   18 +
 .../test_prop2po_files_templates/one.properties    |    1 +
 tests/cli/data/test_prop2po_files_templates/out.po |   18 +
 .../test_prop2po_files_templates/two.properties    |    1 +
 tests/cli/data/test_rc2po/one.rc                   |  119 ++
 tests/cli/data/test_rc2po/out.po                   |   83 +
 tests/cli/example_test.sh                          |   20 +
 tests/cli/run_tests.sh                             |   16 +
 tests/cli/test.inc.sh                              |  275 +++
 tests/cli/test_po2prop_mozilla_files.sh            |    6 +
 tests/cli/test_pocount.sh                          |    8 +
 tests/cli/test_pocount_help.sh                     |    8 +
 tests/cli/test_pocount_mutually_exclusive.sh       |    6 +
 tests/cli/test_pocount_nonexistant.sh              |    6 +
 tests/cli/test_pocount_po_file.sh                  |    6 +
 tests/cli/test_pofilter_listfilters.sh             |    6 +
 tests/cli/test_pofilter_manpage.sh                 |    6 +
 tests/cli/test_poswap_comments.sh                  |    7 +
 tests/cli/test_poswap_fr_af.sh                     |    7 +
 tests/cli/test_poswap_fr_af_reverse.sh             |    7 +
 tests/cli/test_poswap_missing_units.sh             |    7 +
 tests/cli/test_prop2po.sh                          |    6 +
 tests/cli/test_prop2po_dirs.sh                     |    6 +
 tests/cli/test_prop2po_files.sh                    |    6 +
 tests/cli/test_prop2po_files_templates.sh          |    6 +
 tests/cli/test_rc2po.sh                            |    6 +
 .../odf_xliff/test_2-test_odf2xliff-reference.xlf  |   37 +
 tests/odf_xliff/test_2.odt                         |  Bin 0 -> 133081 bytes
 tests/odf_xliff/test_odf_xliff.py                  |  162 ++
 tests/xliff_conformance/af-pootle.po               | 1511 ++++++++++++++
 tests/xliff_conformance/en-US.sdf                  |  226 +++
 tests/xliff_conformance/test_xliff_conformance.py  |   91 +
 tests/xliff_conformance/xliff-core-1.1.xsd         | 2077 ++++++++++++++++++++
 .../mozilla/README.firefox_build_instructions.rst  |  167 ++
 tools/mozilla/Vagrantfile                          |   99 +
 tools/mozilla/accesskey_checker                    |   90 +
 tools/mozilla/accesskey_checker_PO                 |   63 +
 tools/mozilla/build_tb3_langs.sh                   |  179 ++
 tools/mozilla/compare-locales.sh                   |    5 +
 tools/mozilla/moz-l10n-builder                     |  342 ++++
 tools/mozilla/moz_l10n_builder.py                  |  687 +++++++
 tools/mozilla/mozcronbuild.py                      |   98 +
 tools/mozilla/mozilla-l10n.patch                   |   37 +
 tools/mozilla/mozzy.sh                             |  398 ++++
 tools/mozilla/postinstall.sh                       |   90 +
 tools/mozilla/setup_mozilla.sh                     |   14 +
 tools/pep8.sh                                      |   46 +
 tools/phase                                        |  669 +++++++
 tools/phaselist2goals                              |   35 +
 translate/__version__.py                           |    6 +-
 translate/{tools/podebug => convert/idml2po}       |   10 +-
 translate/convert/idml2po.py                       |   67 +
 translate/{tools/pomerge => convert/mozlang2po}    |   11 +-
 translate/convert/odf2xliff.py                     |  125 +-
 translate/convert/odfxml                           |   12 +
 translate/{filters/__init__.py => convert/po2idml} |   13 +-
 translate/convert/po2idml.py                       |  187 ++
 translate/convert/po2ini.py                        |   23 +-
 translate/convert/po2json.py                       |   13 +-
 translate/convert/po2moz.py                        |   16 +-
 translate/{tools/pomerge => convert/po2mozlang}    |   11 +-
 translate/convert/po2mozlang.py                    |    9 +-
 translate/convert/po2php.py                        |   48 +-
 translate/convert/po2prop.py                       |    3 +-
 translate/convert/{ini2po => po2resx}              |   11 +-
 translate/convert/{po2json.py => po2resx.py}       |   59 +-
 translate/convert/po2txt.py                        |   27 +-
 translate/convert/pot2po.py                        |    2 +
 translate/convert/{ini2po => resx2po}              |   11 +-
 translate/convert/{json2po.py => resx2po.py}       |  102 +-
 translate/convert/roundtrip-OOo                    |   60 +
 translate/convert/roundtrip-gaia                   |   58 +
 translate/convert/roundtrip-mozilla                |   59 +
 translate/convert/test_mozlang2po.py               |    9 +-
 translate/convert/test_po2dtd.py                   |    2 +-
 translate/convert/test_po2resx.py                  |  438 +++++
 translate/convert/test_resx2po.py                  |  237 +++
 translate/convert/xliff2odf.py                     |  155 +-
 translate/filters/checks.py                        |  586 +++++-
 translate/filters/pofilter.py                      |    3 +-
 translate/filters/test_checks.py                   |   37 +
 translate/lang/{lo.py => bo.by}                    |    8 +-
 translate/lang/data.py                             |   35 +-
 translate/lang/he.py                               |    2 +-
 translate/lang/test-language-teams.sh              |   23 +
 translate/lang/ug.py                               |    2 +-
 translate/lang/zh.py                               |    2 +-
 translate/lang/zh_cn.py                            |    2 +
 translate/lang/zh_hk.py                            |    2 +
 translate/lang/zh_tw.py                            |    2 +
 translate/misc/file_discovery.py                   |    1 +
 translate/misc/quote.py                            |    6 +-
 translate/storage/_factory_classes.py              |    2 +-
 translate/storage/aresource.py                     |  147 +-
 translate/storage/debug.properties                 |   20 +
 translate/storage/idml.py                          |  100 +
 translate/storage/jsonl10n.py                      |    7 +-
 translate/storage/mozilla_lang.py                  |    5 +-
 translate/storage/odf_io.py                        |   22 +-
 translate/storage/odf_shared.py                    |  324 ++-
 translate/storage/placeables/parse.py              |    2 +-
 translate/storage/po.py                            |   10 +-
 translate/storage/poheader.py                      |    4 +-
 translate/storage/properties.java                  |   30 +
 translate/storage/resx.py                          |  209 ++
 translate/storage/test_aresource.py                |  117 +-
 translate/storage/test_monolingual.py              |   10 +-
 translate/storage/test_resx.py                     |  101 +
 translate/storage/test_ts2.py                      |   64 +-
 translate/storage/ts2.py                           |    8 +-
 translate/storage/xliff.py                         |    2 +
 translate/storage/xml_extract/extract.py           |  352 +++-
 translate/storage/xml_extract/generate.py          |   52 +-
 translate/storage/xml_extract/misc.py              |    3 +
 translate/storage/xml_extract/unit_tree.py         |   18 +-
 translate/storage/xml_extract/xpath_breadcrumb.py  |    8 +-
 translate/storage/xml_name.py                      |    7 +-
 translate/{convert/csv2tbx => tools/phppo2pypo}    |   10 +-
 translate/tools/pretranslate.py                    |    6 +-
 translate/tools/{porestructure => pydiff}          |    7 +-
 translate/{convert/csv2tbx => tools/pypo2phppo}    |   10 +-
 translate_toolkit.egg-info/PKG-INFO                |   46 -
 translate_toolkit.egg-info/SOURCES.txt             | 1150 -----------
 translate_toolkit.egg-info/dependency_links.txt    |    1 -
 translate_toolkit.egg-info/requires.txt            |    3 -
 translate_toolkit.egg-info/top_level.txt           |    1 -
 184 files changed, 12633 insertions(+), 2585 deletions(-)
 create mode 100644 .coveragerc
 create mode 100644 .gitignore
 create mode 100644 .gitmodules
 create mode 100644 .isort.cfg
 create mode 100644 .travis.yml
 create mode 100644 CREDITS
 create mode 100644 LICENSES
 delete mode 100644 MANIFEST.in
 create mode 100644 Makefile
 delete mode 100644 PKG-INFO
 create mode 100644 debian/patches/xliff-xsd-no-network.patch
 copy docs/commands/{json2po.rst => resx2po.rst} (60%)
 create mode 100644 docs/formats/resx.rst
 create mode 100644 docs/releases/1.13.0-rc1.rst
 create mode 100644 docs/releases/1.13.0.rst
 delete mode 100644 docs/releases/dev.rst
 create mode 100644 pytest.ini
 delete mode 100644 setup.cfg
 create mode 100644 tests/cli/data/test_po2prop_mozilla_files/out.properties
 create mode 100644 tests/cli/data/test_po2prop_mozilla_files/template.properties
 create mode 100644 tests/cli/data/test_po2prop_mozilla_files/translations.po
 create mode 100644 tests/cli/data/test_pocount_po_file/one.po
 create mode 100644 tests/cli/data/test_poswap_comments/af.po
 create mode 100644 tests/cli/data/test_poswap_comments/fr.po
 create mode 100644 tests/cli/data/test_poswap_comments/out.po
 create mode 100644 tests/cli/data/test_poswap_fr_af/af.po
 create mode 100644 tests/cli/data/test_poswap_fr_af/fr.po
 create mode 100644 tests/cli/data/test_poswap_fr_af/out.po
 create mode 100644 tests/cli/data/test_poswap_fr_af_reverse/fr.po
 create mode 100644 tests/cli/data/test_poswap_fr_af_reverse/fr_af.po
 create mode 100644 tests/cli/data/test_poswap_fr_af_reverse/out.po
 create mode 100644 tests/cli/data/test_poswap_missing_units/af.po
 create mode 100644 tests/cli/data/test_poswap_missing_units/fr.po
 create mode 100644 tests/cli/data/test_poswap_missing_units/out.po
 create mode 100644 tests/cli/data/test_prop2po_dirs/one/a.properties
 create mode 100644 tests/cli/data/test_prop2po_dirs/out/a.po
 create mode 100644 tests/cli/data/test_prop2po_files/one.properties
 create mode 100644 tests/cli/data/test_prop2po_files/out.po
 create mode 100644 tests/cli/data/test_prop2po_files_templates/one.properties
 create mode 100644 tests/cli/data/test_prop2po_files_templates/out.po
 create mode 100644 tests/cli/data/test_prop2po_files_templates/two.properties
 create mode 100644 tests/cli/data/test_rc2po/one.rc
 create mode 100644 tests/cli/data/test_rc2po/out.po
 create mode 100644 tests/cli/example_test.sh
 create mode 100755 tests/cli/run_tests.sh
 create mode 100644 tests/cli/test.inc.sh
 create mode 100755 tests/cli/test_po2prop_mozilla_files.sh
 create mode 100755 tests/cli/test_pocount.sh
 create mode 100755 tests/cli/test_pocount_help.sh
 create mode 100755 tests/cli/test_pocount_mutually_exclusive.sh
 create mode 100755 tests/cli/test_pocount_nonexistant.sh
 create mode 100755 tests/cli/test_pocount_po_file.sh
 create mode 100755 tests/cli/test_pofilter_listfilters.sh
 create mode 100755 tests/cli/test_pofilter_manpage.sh
 create mode 100755 tests/cli/test_poswap_comments.sh
 create mode 100755 tests/cli/test_poswap_fr_af.sh
 create mode 100755 tests/cli/test_poswap_fr_af_reverse.sh
 create mode 100755 tests/cli/test_poswap_missing_units.sh
 create mode 100755 tests/cli/test_prop2po.sh
 create mode 100755 tests/cli/test_prop2po_dirs.sh
 create mode 100755 tests/cli/test_prop2po_files.sh
 create mode 100755 tests/cli/test_prop2po_files_templates.sh
 create mode 100755 tests/cli/test_rc2po.sh
 create mode 100644 tests/odf_xliff/test_2-test_odf2xliff-reference.xlf
 create mode 100644 tests/odf_xliff/test_2.odt
 create mode 100644 tests/odf_xliff/test_odf_xliff.py
 create mode 100644 tests/xliff_conformance/af-pootle.po
 create mode 100644 tests/xliff_conformance/en-US.sdf
 create mode 100644 tests/xliff_conformance/test_xliff_conformance.py
 create mode 100644 tests/xliff_conformance/xliff-core-1.1.xsd
 create mode 100644 tools/mozilla/README.firefox_build_instructions.rst
 create mode 100644 tools/mozilla/Vagrantfile
 create mode 100755 tools/mozilla/accesskey_checker
 create mode 100755 tools/mozilla/accesskey_checker_PO
 create mode 100755 tools/mozilla/build_tb3_langs.sh
 create mode 100755 tools/mozilla/compare-locales.sh
 create mode 100755 tools/mozilla/moz-l10n-builder
 create mode 100644 tools/mozilla/moz_l10n_builder.py
 create mode 100755 tools/mozilla/mozcronbuild.py
 create mode 100644 tools/mozilla/mozilla-l10n.patch
 create mode 100755 tools/mozilla/mozzy.sh
 create mode 100755 tools/mozilla/postinstall.sh
 create mode 100755 tools/mozilla/setup_mozilla.sh
 create mode 100755 tools/pep8.sh
 create mode 100755 tools/phase
 create mode 100755 tools/phaselist2goals
 copy translate/{tools/podebug => convert/idml2po} (80%)
 create mode 100644 translate/convert/idml2po.py
 copy translate/{tools/pomerge => convert/mozlang2po} (81%)
 create mode 100755 translate/convert/odfxml
 copy translate/{filters/__init__.py => convert/po2idml} (83%)
 mode change 100644 => 100755
 create mode 100644 translate/convert/po2idml.py
 copy translate/{tools/pomerge => convert/po2mozlang} (81%)
 copy translate/convert/{ini2po => po2resx} (76%)
 mode change 100755 => 100644
 copy translate/convert/{po2json.py => po2resx.py} (62%)
 copy translate/convert/{ini2po => resx2po} (76%)
 mode change 100755 => 100644
 copy translate/convert/{json2po.py => resx2po.py} (56%)
 create mode 100755 translate/convert/roundtrip-OOo
 create mode 100755 translate/convert/roundtrip-gaia
 create mode 100755 translate/convert/roundtrip-mozilla
 create mode 100644 translate/convert/test_po2resx.py
 create mode 100644 translate/convert/test_resx2po.py
 copy translate/lang/{lo.py => bo.by} (83%)
 create mode 100755 translate/lang/test-language-teams.sh
 create mode 100644 translate/storage/debug.properties
 create mode 100644 translate/storage/idml.py
 create mode 100644 translate/storage/properties.java
 create mode 100644 translate/storage/resx.py
 create mode 100644 translate/storage/test_resx.py
 copy translate/{convert/csv2tbx => tools/phppo2pypo} (67%)
 copy translate/tools/{porestructure => pydiff} (82%)
 copy translate/{convert/csv2tbx => tools/pypo2phppo} (67%)
 delete mode 100644 translate_toolkit.egg-info/PKG-INFO
 delete mode 100644 translate_toolkit.egg-info/SOURCES.txt
 delete mode 100644 translate_toolkit.egg-info/dependency_links.txt
 delete mode 100644 translate_toolkit.egg-info/requires.txt
 delete mode 100644 translate_toolkit.egg-info/top_level.txt

diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..fe1a85c
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,8 @@
+[run]
+omit =
+    tests/*
+    translate/test_*
+    translate/*/test_*
+    translate/*/*/test_*
+    translate/misc/selector.py
+    translate/misc/wsgiserver/*
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2be37cb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,51 @@
+# /
+/LICENSE
+
+# /docs/
+/docs/_build/
+
+# Python
+*.py[cod]
+*.egg-info
+
+# pytest
+.cache/
+
+# vim
+.*.swp
+*~
+
+# distutils
+/build/
+/dist/
+MANIFEST
+MANIFEST.in
+
+
+# Requirements generation
+.reqs
+requirements/min-versions.txt
+
+# Coverage
+.coverage*
+
+##############################
+# translate/ specific excludes
+##############################
+
+translate/storage/properties.class
+
+# Testing
+# #######
+# Roundtrip testing noise
+translate/convert/diff_*.diff
+translate/convert/mozilla-l10n/
+translate/convert/mozilla-gaia/
+translate/convert/rewritten-po/
+translate/convert/templates-recreated/
+
+# other
+tests/xliff_conformance/af-pootle.xlf
+
+# cli testing
+tests/cli/results
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..c2108d8
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "docs/_themes"]
+	path = docs/_themes
+	url = git://github.com/translate/sphinx-themes.git
diff --git a/.isort.cfg b/.isort.cfg
new file mode 100644
index 0000000..d3a4ad9
--- /dev/null
+++ b/.isort.cfg
@@ -0,0 +1,15 @@
+[settings]
+line_length=80
+force_to_top=file1.py,file2.py
+skip=docs,selector.py,wsgiserver
+known_standard_library=thread
+known_third_party=iniparse,lxml,vobject
+known_first_party=mylib1,mylib2
+indent='    '
+multi_line_output=0
+length_sort=
+forced_separate=django.contrib,django.utils
+default_section=FIRSTPARTY
+order_by_type=1
+combine_as_imports=1
+lines_after_imports=2
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..da2022a
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,37 @@
+# https://travis-ci.org/#!/translate/translate
+language: python
+python:
+  - 2.6
+  - 2.7
+env:
+  matrix:
+    - USECPO=0 MINVERSION=1
+    - USECPO=0 MINVERSION=
+    #- USECPO=1
+    #- USECPO=2
+matrix:
+  exclude:
+    - python: 2.6
+      env: USECPO=0 MINVERSION=1
+before_install:
+  - sudo apt-get install python-aeidon
+install:
+  - pip install coveralls
+  - if [[ $MINVERSION ]]; then make requirements/min-versions.txt; cat requirements/min-versions.txt;  CFLAGS="-O0" pip install -r requirements/min-versions.txt; pip install --upgrade pytest; fi
+  - if [[ ! $MINVERSION ]]; then  CFLAGS="-O0" pip install -r requirements/dev.txt; fi
+  # Still need to handle with indexing engines
+  - pip freeze
+script:
+  - python -m compileall -q -f .     # Compile all the files
+  - python setup.py --quiet build
+  - py.test --cov=. -r EfsxX
+  - pip install .
+  - make test-functional
+  - ./tools/pep8.sh travis
+  - make docs
+after_success:
+  coveralls
+notifications:
+  email:
+    on_failure: always
+    on_success: change
diff --git a/CREDITS b/CREDITS
new file mode 100644
index 0000000..4f78ce7
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,41 @@
+Translate Toolkit Credits
+=========================
+
+See the README file for an explanation of what the Translate Toolkit is
+See the ChangeLog (or version control history) for more detailed credits
+These are people who have contributed documentation or code, but bug reports are also a valuable contribution!
+Many people have contributed suggestions etc on the translate-devel list and these are also appreciated
+If you've been left out, let us know!
+
+Alphabetical Order of Contributors
+----------------------------------
+
+Alexander Dupuy: poterminology, quality checks
+Caio Begotti: documentation
+Clytie Siddall: testing and bugreporting
+Dan Schafer (Mozilla): improvements to html2po
+David Farning: testing
+David Fraser: main development
+Dwayne Bailey: added tests, checks in pofilter, some helpful bash scripts, testing
+Filip Miletic: fixes for unicode problems, skype conversion
+Fredrik Corneliusson: xliff work
+Friedel Wolff: bug fixes, development
+Geoffrey Hutchison: better Qt .ts support
+Grégory Journé: better .rc support
+Ivan Masár: improvements to pocount
+Javier Sola: documentation
+Kaloian Doganov: improvement of po2html
+Lars Kruse: version control, indexing, support, reviews
+Marek Wieckowski: Qt ts file enhancements
+Matt Chisholm: fixes
+Matthias Klose: extra file options for converters
+Miklos Vajna: patches and testing of version control
+Nicolas François: po4a integration, performance
+Ognyan Kulev: testing and fixes
+Pavel Janík: testing
+Rail Aliev (Раиль Алиев): testing, converters, podebug
+Thomas Fogwill: portal code
+Tom Cato Amundsen: patch to enable pogrep to search anywhere in the PO unit
+Torsten Martinsen: patches to po2ts
+Walter Leibbrandt: development
+Wynand Winterbach: development
diff --git a/LICENSES b/LICENSES
new file mode 100644
index 0000000..efa2d49
--- /dev/null
+++ b/LICENSES
@@ -0,0 +1,27 @@
+==================================
+Licenses of Toolkit and Other Code
+==================================
+
+The Translate Toolkit is released the license listed in COPYING.
+
+
+Other licenses
+==============
+
+We import or have used code from the following projects:
+
+CherryPy
+--------
+
+This is used by tmserver. Depending on the whole of CherryPy was overkill for
+just needing this server component.
+
+License: BSD copy in translate/misc/wsgiserver/LICENSE.txt
+
+Used in: translate/misc/wsgiserver/*
+
+From: CherryPy 3.2.4
+https://pypi.python.org/packages/source/C/CherryPy/CherryPy-3.2.4.tar.gz#md5=e2c8455e15c39c9d60e0393c264a4d16
+
+The code has been changed slightly:
+  1. from cherrypy import -> from translate.misc import
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 8552266..0000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,81 +0,0 @@
-# MANIFEST.in: the below autogenerated by setup.py from translate 1.12.0
-# things needed by translate setup.py to rebuild
-# informational fs
-global-include README.rst
-global-include COPYING
-global-include *.txt
-# C programs
-global-include *.c
-# scripts which don't get included by default in sdist
-include translate/convert/pot2po
-include translate/convert/moz2po
-include translate/convert/po2moz
-include translate/convert/oo2po
-include translate/convert/po2oo
-include translate/convert/oo2xliff
-include translate/convert/xliff2oo
-include translate/convert/prop2po
-include translate/convert/po2prop
-include translate/convert/csv2po
-include translate/convert/po2csv
-include translate/convert/txt2po
-include translate/convert/po2txt
-include translate/convert/ts2po
-include translate/convert/po2ts
-include translate/convert/html2po
-include translate/convert/po2html
-include translate/convert/ical2po
-include translate/convert/po2ical
-include translate/convert/ini2po
-include translate/convert/po2ini
-include translate/convert/json2po
-include translate/convert/po2json
-include translate/convert/tiki2po
-include translate/convert/po2tiki
-include translate/convert/php2po
-include translate/convert/po2php
-include translate/convert/rc2po
-include translate/convert/po2rc
-include translate/convert/xliff2po
-include translate/convert/po2xliff
-include translate/convert/sub2po
-include translate/convert/po2sub
-include translate/convert/symb2po
-include translate/convert/po2symb
-include translate/convert/po2tmx
-include translate/convert/po2wordfast
-include translate/convert/csv2tbx
-include translate/convert/odf2xliff
-include translate/convert/xliff2odf
-include translate/convert/web2py2po
-include translate/convert/po2web2py
-include translate/filters/pofilter
-include translate/tools/pocompile
-include translate/tools/poconflicts
-include translate/tools/pocount
-include translate/tools/podebug
-include translate/tools/pogrep
-include translate/tools/pomerge
-include translate/tools/porestructure
-include translate/tools/posegment
-include translate/tools/poswap
-include translate/tools/poclean
-include translate/tools/poterminology
-include translate/tools/pretranslate
-include translate/services/tmserver
-include translate/tools/build_tmdb
-include tools/junitmsgfmt
-include tools/mozilla/build_firefox.sh
-include tools/mozilla/buildxpi.py
-include tools/mozilla/get_moz_enUS.py
-include tools/pocommentclean
-include tools/pocompendium
-include tools/pomigrate2
-include tools/popuretext
-include tools/poreencode
-include tools/posplit
-# include our documentation
-graft docs
-prune docs/doctrees
-graft share
-# MANIFEST.in: end of autogenerated block
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..db7a0ba
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,92 @@
+DOCS_DIR = docs
+FORMATS=--formats=bztar
+
+.PHONY: all build docs requirements help publish-pypi sort-imports
+
+all: help
+
+build: docs
+	python setup.py sdist ${FORMATS}
+
+docs:
+	# Make sure that the submodule with docs theme is pulled and up-to-date.
+	git submodule update --init
+	# The following creates the HTML docs.
+	# NOTE: cd and make must be in the same line.
+	cd ${DOCS_DIR}; make SPHINXOPTS="-W -q" html ${TAIL}
+
+docs-review: docs
+	python -mwebbrowser file://$(shell pwd)/${DOCS_DIR}/_build/html/index.html
+
+publish-pypi:
+	python setup.py sdist ${FORMATS} upload
+
+sort-imports:
+	isort -rc .
+
+help:
+	@echo "Help"
+	@echo "----"
+	@echo
+	@echo "  build - create sdist with required prep"
+	@echo "  docs - build Sphinx docs"
+	@echo "  docs-review - launch webbrowser to review docs"
+	@echo "  requirements - (re)generate pinned and minimum requirements"
+	@echo "  sort-imports - sort Python imports"
+	@echo "  publish-pypi - publish on PyPI"
+	@echo "  test - run unit test suite"
+	@echo "  test-functional - run the functional test suite"
+
+# Perform forced build using -W for the (.PHONY) requirements target
+requirements:
+	$(MAKE) -W $(REQFILE) requirements/min-versions.txt requirements.txt
+
+REQS=.reqs
+REQFILE=requirements/recommended.txt
+
+requirements.txt: $(REQFILE)
+	@set -e;							\
+	 case `pip --version` in					\
+	   "pip 0"*|"pip 1.[012]"*)					\
+	     virtualenv --no-site-packages --clear $(REQS);		\
+	     source $(REQS)/bin/activate;				\
+	     echo starting clean install of requirements from PyPI;	\
+	     pip install --use-mirrors -r $(REQFILE);			\
+	     : trap removes partial/empty target on failure;		\
+	     trap 'if [ "$$?" != 0 ]; then rm -f $@; fi' 0;		\
+	     pip freeze | grep -v '^wsgiref==' | sort > $@ ;;		\
+	   *)								\
+	     : only pip 1.3.1+ processes --download recursively;	\
+	     rm -rf $(REQS); mkdir $(REQS);				\
+	     echo starting download of requirements from PyPI;		\
+	     pip install --download $(REQS) -r $(REQFILE);		\
+	     : trap removes partial/empty target on failure;		\
+	     trap 'if [ "$$?" != 0 ]; then rm -f $@; fi' 0;		\
+	     (cd $(REQS) && ls *.tar* |					\
+	      sed -e 's/-\([0-9]\)/==\1/' -e 's/\.tar.*$$//') > $@;	\
+	 esac; 
+
+requirements/min-versions.txt: requirements/*.txt
+	@if grep -q '>[0-9]' $^; then				\
+	   echo "Use '>=' not '>' for requirements"; exit 1;	\
+	 fi
+	@echo "creating $@"
+	@echo "# Automatically generated: DO NOT EDIT" > $@
+	@echo "# Regenerate using 'make requirements'" >> $@
+	@echo "# ====================================" >> $@
+	@echo "# Minimum Requirements" >> $@
+	@echo "# ====================================" >> $@
+	@echo "#" >> $@
+	@echo "# These are the minimum versions of dependencies that the developers" >> $@
+	@echo "# claim will work." >> $@
+	@echo "#" >> $@
+	@echo "# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" >> $@
+	@echo "#" >> $@
+	@echo >> $@
+	@cat $^ | sed -n '/=/{s/>=/==/;s/,<.*//;s/,!=.*//;p;};/^[-#]/d;/^$$/d;/=/d;p;' >> $@
+
+test:
+	@py.test --boxed -r EfsxX
+
+test-functional:
+	@tests/cli/run_tests.sh
diff --git a/PKG-INFO b/PKG-INFO
deleted file mode 100644
index 22d7624..0000000
--- a/PKG-INFO
+++ /dev/null
@@ -1,46 +0,0 @@
-Metadata-Version: 1.0
-Name: translate-toolkit
-Version: 1.12.0
-Summary: Tools and API for translation and localization engineering.
-Home-page: http://toolkit.translatehouse.org/
-Author: Translate
-Author-email: translate-devel at lists.sourceforge.net
-License: GNU General Public License (GPL)
-Download-URL: http://sourceforge.net/projects/translate/files/Translate Toolkit/1.12.0
-Description: 
-        The `Translate Toolkit <http://toolkit.translatehouse.org/>`_ is created by
-        localizers for localizers. It contains several utilities, as well as an API for
-        building localization tools.
-        
-        Some of the **tools** include:
-        
-        - File format `converters
-          <http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/index.html#converters>`_
-        - `Quality checking
-          <http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/index.html#quality-assurance>`_
-          tools
-        - Tools for counting, grepping, terminology extraction, and pseudo-localization
-        
-        Apart from the code for the tools above, some features of the **API** include:
-        
-        - Support for multiple `file formats
-          <http://docs.translatehouse.org/projects/translate-toolkit/en/latest/formats/index.html>`_
-        - Language information and language support code (including language detection)
-        - Code for translation memory, terminology matching and indexed search
-        - Several helper classes and functions for tools built on the Translate
-          Toolkit.
-        
-        
-Platform: any
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Environment :: Console
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: GNU General Public License (GPL)
-Classifier: Operating System :: OS Independent
-Classifier: Operating System :: Microsoft :: Windows
-Classifier: Operating System :: Unix
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: Topic :: Software Development :: Localization
diff --git a/README.rst b/README.rst
index da3d5fa..fcd7b7d 100644
--- a/README.rst
+++ b/README.rst
@@ -4,10 +4,27 @@ Translate Toolkit
 .. image:: https://travis-ci.org/translate/translate.png
     :alt: Build Status
     :target: https://travis-ci.org/translate/translate
+
 .. image:: https://coveralls.io/repos/translate/translate/badge.png?branch=master
     :alt: Coverage Status
     :target: https://coveralls.io/r/translate/translate?branch=master
 
+.. image:: https://pypip.in/download/translate-toolkit/badge.png
+    :alt: Downloads
+    :target: https://pypi.python.org/pypi/translate-toolkit/
+
+.. image:: https://pypip.in/py_versions/translate-toolkit/badge.png
+    :alt: Supported Python versions
+    :target: https://pypi.python.org/pypi/translate-toolkit/
+
+.. image:: https://pypip.in/status/translate-toolkit/badge.png
+    :alt: Development Status
+    :target: https://pypi.python.org/pypi/translate-toolkit/
+
+.. image:: https://pypip.in/license/translate-toolkit/badge.svg
+    :target: https://pypi.python.org/pypi/translate-toolkit/
+    :alt: License
+
 The Translate Toolkit is a set of software and documentation designed to help
 make the lives of localizers both more productive and less frustrating.
 The Toolkit is part of the translate.sourceforge.net project,
@@ -242,6 +259,7 @@ Use ``--help`` to find the syntax and options for all programs.
         ini2po   - convert .ini files to to PO
         ical2po  - Convert iCalendar files (*.ics) to PO
         sub2po   - Convert many subtitle files to PO
+        resx2po  - convert .Net Resource (.resx) files to PO
 
 * Tools (Quality Assurance)::
 
diff --git a/debian/changelog b/debian/changelog
index 3cb7a9a..d3075d4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+translate-toolkit (1.13.0-1) unstable; urgency=medium
+
+  * New upstream version (Closes: #794632).
+  * Add local copy of xml.xsd to prevent network access when running tests.
+
+ -- Stuart Prescott <stuart at debian.org>  Sun, 13 Sep 2015 00:46:09 +1000
+
 translate-toolkit (1.12.0+dfsg1-2) unstable; urgency=medium
 
   * Upload to unstable.
diff --git a/debian/control b/debian/control
index caa3638..e6153a0 100644
--- a/debian/control
+++ b/debian/control
@@ -31,11 +31,10 @@ Build-Depends-Indep:
 Build-Depends:
  debhelper (>= 9~),
  dh-python,
-Standards-Version: 3.9.5
+Standards-Version: 3.9.6
 Vcs-Git: git://anonscm.debian.org/debian-l10n/translate-toolkit.git
 Vcs-Browser: http://anonscm.debian.org/gitweb/?p=debian-l10n/translate-toolkit.git
 Homepage: http://toolkit.translatehouse.org/
-XS-Testsuite: autopkgtest
 
 Package: translate-toolkit
 Architecture: all
diff --git a/debian/copyright b/debian/copyright
index ef4f321..ab1ae5e 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -2,24 +2,18 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 Upstream-Name: Translate Toolkit
 Upstream-Contact: Zuza Software Foundation
 Source: http://toolkit.translatehouse.org/
-Files-Excluded:
-  docs/_themes
-  docs/_build
-  docs/_ext/translate_docs.pyc
-Comment: Pre-built documentation and sourceless theme files excluded
 
 Files: *
 Copyright: 2002-2013, Zuza Software Foundation,
     2002-2013, St James Software
 License: GPL-2+
 
-Files: translate/convert/po2tiki
- translate/convert/po2tiki.py
- translate/convert/tiki2po
- translate/convert/tiki2po.py
+Files: translate/convert/po2tiki*
+ translate/convert/po2tiki
+ translate/convert/tiki2po*
  translate/storage/tiki.py
- translate/tools/phppo2pypo.py
- translate/tools/pypo2phppo.py
+ translate/tools/phppo2pypo*
+ translate/tools/pypo2phppo*
 Copyright: 2008-2009, Mozilla Corporation, Zuza Software Foundation
 License: GPL-2+
 
@@ -48,6 +42,11 @@ Copyright: 2009, Zuza Software Foundation
  2014, F Wolff
 License: GPL-2+
 
+Files: translate/*/*resx2po* translate/*/*po2resx*
+Copyright: 2015, Zuza Software Foundation
+ 2015, Sarah Hale
+License: GPL-2+
+
 Files: translate/lang/ngram.py
 Copyright: 2006, Thomas Mangin
   2009-2010, Zuza Software Foundation
@@ -158,6 +157,44 @@ License: GPL-3+
 Comment: msghack was downloaded from the Fedora gettext source package.
   http://pkgs.fedoraproject.org/cgit/gettext.git/plain/msghack.py
 
+Files: debian/patches/xliff-xsd-no-network.patch tests/xliff_conformance/xml.xsd
+Copyright: 2009, W3C
+License: other
+ By obtaining and/or copying this work, you (the licensee) agree that you have
+ read, understood, and will comply with the following terms and conditions.
+ .
+ Permission to copy, modify, and distribute this work, with or without
+ modification, for any purpose and without fee or royalty is hereby granted,
+ provided that you include the following on ALL copies of the work or
+ portions thereof, including modifications:
+ .
+ * The full text of this NOTICE in a location viewable to users of the
+   redistributed or derivative work.
+ .
+ * Any pre-existing intellectual property disclaimers, notices, or terms and
+   conditions. If none exist, the W3C Software and Document Short Notice should be included.
+ .
+ * Notice of any changes or modifications, through a copyright statement on the
+   new code or document such as "This software or document includes material
+   copied from or derived from [title and URI of the W3C document]. Copyright
+   © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)."
+ .
+ Disclaimers
+ .
+ THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS
+ OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE
+ SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS,
+ TRADEMARKS OR OTHER RIGHTS.
+ .
+ COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR
+ CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT.
+ .
+ The name and trademarks of copyright holders may NOT be used in advertising or
+ publicity pertaining to the work without specific, written prior permission.
+ Title to copyright in this work will at all times remain with copyright
+ holders.
+
 License: GPL-2+
  On Debian systems, the complete text of the GNU General Public License,
  can be found in /usr/share/common-licenses/GPL-2.
diff --git a/debian/patches/series b/debian/patches/series
index c565ee7..cfee976 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,4 @@
+xliff-xsd-no-network.patch
 disable-sphinx-theme.patch
 storage_bzr
 poterminology_defaultstopfile
diff --git a/debian/patches/xliff-xsd-no-network.patch b/debian/patches/xliff-xsd-no-network.patch
new file mode 100644
index 0000000..2ae0121
--- /dev/null
+++ b/debian/patches/xliff-xsd-no-network.patch
@@ -0,0 +1,305 @@
+Description: Provide local version of XSD to prevent network access
+ The xliff xsd imports xml.xsd which will result in network access. Include
+ a local copy of this resource instead.
+Author: Stuart Prescott <stuart at debian.org>
+--- a/tests/xliff_conformance/xliff-core-1.1.xsd
++++ b/tests/xliff_conformance/xliff-core-1.1.xsd
+@@ -1,7 +1,7 @@
+ <?xml version="1.0" encoding="utf-8"?>

+ <xsd:schema targetNamespace="urn:oasis:names:tc:xliff:document:1.1" xmlns:xyz="urn:appInfo:Items" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xlf="urn:oasis:names:tc:xliff:document:1.1" elementFormDefault="qualified" xml:lang="en">

+ 	<!-- Import for xml:lang and xml:space -->

+-	<xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>

++	<xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/>

+ 	<!-- Attributes Lists -->

+ 	<xsd:simpleType name="XTend">

+ 		<xsd:restriction base="xsd:string">

+--- /dev/null
++++ b/tests/xliff_conformance/xml.xsd
+@@ -0,0 +1,287 @@
++<?xml version='1.0'?>
++<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
++<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" 
++  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
++  xmlns   ="http://www.w3.org/1999/xhtml"
++  xml:lang="en">
++
++ <xs:annotation>
++  <xs:documentation>
++   <div>
++    <h1>About the XML namespace</h1>
++
++    <div class="bodytext">
++     <p>
++      This schema document describes the XML namespace, in a form
++      suitable for import by other schema documents.
++     </p>
++     <p>
++      See <a href="http://www.w3.org/XML/1998/namespace.html">
++      http://www.w3.org/XML/1998/namespace.html</a> and
++      <a href="http://www.w3.org/TR/REC-xml">
++      http://www.w3.org/TR/REC-xml</a> for information 
++      about this namespace.
++     </p>
++     <p>
++      Note that local names in this namespace are intended to be
++      defined only by the World Wide Web Consortium or its subgroups.
++      The names currently defined in this namespace are listed below.
++      They should not be used with conflicting semantics by any Working
++      Group, specification, or document instance.
++     </p>
++     <p>   
++      See further below in this document for more information about <a
++      href="#usage">how to refer to this schema document from your own
++      XSD schema documents</a> and about <a href="#nsversioning">the
++      namespace-versioning policy governing this schema document</a>.
++     </p>
++    </div>
++   </div>
++  </xs:documentation>
++ </xs:annotation>
++
++ <xs:attribute name="lang">
++  <xs:annotation>
++   <xs:documentation>
++    <div>
++     
++      <h3>lang (as an attribute name)</h3>
++      <p>
++       denotes an attribute whose value
++       is a language code for the natural language of the content of
++       any element; its value is inherited.  This name is reserved
++       by virtue of its definition in the XML specification.</p>
++     
++    </div>
++    <div>
++     <h4>Notes</h4>
++     <p>
++      Attempting to install the relevant ISO 2- and 3-letter
++      codes as the enumerated possible values is probably never
++      going to be a realistic possibility.  
++     </p>
++     <p>
++      See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
++       http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
++      and the IANA language subtag registry at
++      <a href="http://www.iana.org/assignments/language-subtag-registry">
++       http://www.iana.org/assignments/language-subtag-registry</a>
++      for further information.
++     </p>
++     <p>
++      The union allows for the 'un-declaration' of xml:lang with
++      the empty string.
++     </p>
++    </div>
++   </xs:documentation>
++  </xs:annotation>
++  <xs:simpleType>
++   <xs:union memberTypes="xs:language">
++    <xs:simpleType>    
++     <xs:restriction base="xs:string">
++      <xs:enumeration value=""/>
++     </xs:restriction>
++    </xs:simpleType>
++   </xs:union>
++  </xs:simpleType>
++ </xs:attribute>
++
++ <xs:attribute name="space">
++  <xs:annotation>
++   <xs:documentation>
++    <div>
++     
++      <h3>space (as an attribute name)</h3>
++      <p>
++       denotes an attribute whose
++       value is a keyword indicating what whitespace processing
++       discipline is intended for the content of the element; its
++       value is inherited.  This name is reserved by virtue of its
++       definition in the XML specification.</p>
++     
++    </div>
++   </xs:documentation>
++  </xs:annotation>
++  <xs:simpleType>
++   <xs:restriction base="xs:NCName">
++    <xs:enumeration value="default"/>
++    <xs:enumeration value="preserve"/>
++   </xs:restriction>
++  </xs:simpleType>
++ </xs:attribute>
++ 
++ <xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
++   <xs:documentation>
++    <div>
++     
++      <h3>base (as an attribute name)</h3>
++      <p>
++       denotes an attribute whose value
++       provides a URI to be used as the base for interpreting any
++       relative URIs in the scope of the element on which it
++       appears; its value is inherited.  This name is reserved
++       by virtue of its definition in the XML Base specification.</p>
++     
++     <p>
++      See <a
++      href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
++      for information about this attribute.
++     </p>
++    </div>
++   </xs:documentation>
++  </xs:annotation>
++ </xs:attribute>
++ 
++ <xs:attribute name="id" type="xs:ID">
++  <xs:annotation>
++   <xs:documentation>
++    <div>
++     
++      <h3>id (as an attribute name)</h3> 
++      <p>
++       denotes an attribute whose value
++       should be interpreted as if declared to be of type ID.
++       This name is reserved by virtue of its definition in the
++       xml:id specification.</p>
++     
++     <p>
++      See <a
++      href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
++      for information about this attribute.
++     </p>
++    </div>
++   </xs:documentation>
++  </xs:annotation>
++ </xs:attribute>
++
++ <xs:attributeGroup name="specialAttrs">
++  <xs:attribute ref="xml:base"/>
++  <xs:attribute ref="xml:lang"/>
++  <xs:attribute ref="xml:space"/>
++  <xs:attribute ref="xml:id"/>
++ </xs:attributeGroup>
++
++ <xs:annotation>
++  <xs:documentation>
++   <div>
++   
++    <h3>Father (in any context at all)</h3> 
++
++    <div class="bodytext">
++     <p>
++      denotes Jon Bosak, the chair of 
++      the original XML Working Group.  This name is reserved by 
++      the following decision of the W3C XML Plenary and 
++      XML Coordination groups:
++     </p>
++     <blockquote>
++       <p>
++	In appreciation for his vision, leadership and
++	dedication the W3C XML Plenary on this 10th day of
++	February, 2000, reserves for Jon Bosak in perpetuity
++	the XML name "xml:Father".
++       </p>
++     </blockquote>
++    </div>
++   </div>
++  </xs:documentation>
++ </xs:annotation>
++
++ <xs:annotation>
++  <xs:documentation>
++   <div xml:id="usage" id="usage">
++    <h2><a name="usage">About this schema document</a></h2>
++
++    <div class="bodytext">
++     <p>
++      This schema defines attributes and an attribute group suitable
++      for use by schemas wishing to allow <code>xml:base</code>,
++      <code>xml:lang</code>, <code>xml:space</code> or
++      <code>xml:id</code> attributes on elements they define.
++     </p>
++     <p>
++      To enable this, such a schema must import this schema for
++      the XML namespace, e.g. as follows:
++     </p>
++     <pre>
++          <schema . . .>
++           . . .
++           <import namespace="http://www.w3.org/XML/1998/namespace"
++                      schemaLocation="http://www.w3.org/2001/xml.xsd"/>
++     </pre>
++     <p>
++      or
++     </p>
++     <pre>
++           <import namespace="http://www.w3.org/XML/1998/namespace"
++                      schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
++     </pre>
++     <p>
++      Subsequently, qualified reference to any of the attributes or the
++      group defined below will have the desired effect, e.g.
++     </p>
++     <pre>
++          <type . . .>
++           . . .
++           <attributeGroup ref="xml:specialAttrs"/>
++     </pre>
++     <p>
++      will define a type which will schema-validate an instance element
++      with any of those attributes.
++     </p>
++    </div>
++   </div>
++  </xs:documentation>
++ </xs:annotation>
++
++ <xs:annotation>
++  <xs:documentation>
++   <div id="nsversioning" xml:id="nsversioning">
++    <h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
++    <div class="bodytext">
++     <p>
++      In keeping with the XML Schema WG's standard versioning
++      policy, this schema document will persist at
++      <a href="http://www.w3.org/2009/01/xml.xsd">
++       http://www.w3.org/2009/01/xml.xsd</a>.
++     </p>
++     <p>
++      At the date of issue it can also be found at
++      <a href="http://www.w3.org/2001/xml.xsd">
++       http://www.w3.org/2001/xml.xsd</a>.
++     </p>
++     <p>
++      The schema document at that URI may however change in the future,
++      in order to remain compatible with the latest version of XML
++      Schema itself, or with the XML namespace itself.  In other words,
++      if the XML Schema or XML namespaces change, the version of this
++      document at <a href="http://www.w3.org/2001/xml.xsd">
++       http://www.w3.org/2001/xml.xsd 
++      </a> 
++      will change accordingly; the version at 
++      <a href="http://www.w3.org/2009/01/xml.xsd">
++       http://www.w3.org/2009/01/xml.xsd 
++      </a> 
++      will not change.
++     </p>
++     <p>
++      Previous dated (and unchanging) versions of this schema 
++      document are at:
++     </p>
++     <ul>
++      <li><a href="http://www.w3.org/2009/01/xml.xsd">
++	http://www.w3.org/2009/01/xml.xsd</a></li>
++      <li><a href="http://www.w3.org/2007/08/xml.xsd">
++	http://www.w3.org/2007/08/xml.xsd</a></li>
++      <li><a href="http://www.w3.org/2004/10/xml.xsd">
++	http://www.w3.org/2004/10/xml.xsd</a></li>
++      <li><a href="http://www.w3.org/2001/03/xml.xsd">
++	http://www.w3.org/2001/03/xml.xsd</a></li>
++     </ul>
++    </div>
++   </div>
++  </xs:documentation>
++ </xs:annotation>
++
++</xs:schema>
++
diff --git a/debian/watch b/debian/watch
index 7c726d8..08aa53e 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,3 +1,3 @@
 version=3
-opts="uversionmangle=s/(\d)[_.+-]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/,dversionmangle=s/\+(debian|dfsg|ds|deb)(\.\d+)?$//" \
-  http://sf.net/translate/translate-toolkit-(.*).tar.(?:gz|bz2)
+opts="uversionmangle=s/(\d)[_.+-]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/,dversionmangle=s/\+(debian|dfsg|ds|deb)(\.\d+)?$//,repacksuffix=+dfsg1,filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/translate-toolkit-$1\.tar\.gz/" \
+  https://github.com/translate/translate/tags .*/v?(\d\S*)\.tar\.gz
\ No newline at end of file
diff --git a/docs/_ext/translate_docs.py b/docs/_ext/translate_docs.py
index f086c3d..4c3fead 100644
--- a/docs/_ext/translate_docs.py
+++ b/docs/_ext/translate_docs.py
@@ -29,3 +29,5 @@ def setup(app):
         name="opt",
         nodeclass=docutils.nodes.literal
     )
+
+    return {"parallel_read_safe": True}
diff --git a/docs/commands/index.rst b/docs/commands/index.rst
index 6b9a948..f7eb471 100644
--- a/docs/commands/index.rst
+++ b/docs/commands/index.rst
@@ -28,6 +28,7 @@ Converters
    json2po
    web2py2po
    rc2po
+   resx2po
    symb2po
    tiki2po
    ts2po
@@ -74,6 +75,7 @@ understanding that will make the converters much easier to use and understand.
 * :doc:`web2py2po` -- web2py translation to PO converter
 * :doc:`rc2po <rc2po>` -- Windows Resource .rc (C++ Resource Compiler)
   converter
+* :doc:`resx2po <resx2po>` -- .Net Resource (.resx) file converter
 * :doc:`symb2po <symb2po>` -- Symbian-style translation to PO converter
 * :doc:`tiki2po <tiki2po>` -- `TikiWiki <http://tikiwiki.org/>`_ language.php
   converter
diff --git a/docs/commands/pofilter_tests.rst b/docs/commands/pofilter_tests.rst
index 2395b1f..023667f 100644
--- a/docs/commands/pofilter_tests.rst
+++ b/docs/commands/pofilter_tests.rst
@@ -14,7 +14,7 @@ limitations of each test.
 Keep in mind that the software might point to errors which are not necessarily
 wrong (false positives).
 
-Currently there are 47 tests.  You can always get a list of the currently
+Currently there are 48 tests.  You can always get a list of the currently
 available tests by running::
 
   pofilter -l
@@ -43,41 +43,63 @@ you determine which to run first.
 
 * Critical -- can break a program
 
-  * :ref:`pofilter_tests#escapes`,
-    :ref:`pofilter_tests#newlines`, :ref:`pofilter_tests#nplurals`,
-    :ref:`pofilter_tests#printf`, :ref:`pofilter_tests#tabs`,
-    :ref:`pofilter_tests#variables`, :ref:`pofilter_tests#xmltags`,
-    :ref:`pofilter_tests#dialogsizes`
+  * :ref:`pofilter_tests#dialogsizes`,
+    :ref:`pofilter_tests#escapes`,
+    :ref:`pofilter_tests#newlines`,
+    :ref:`pofilter_tests#nplurals`,
+    :ref:`pofilter_tests#printf`,
+    :ref:`pofilter_tests#pythonbraceformat`,
+    :ref:`pofilter_tests#tabs`,
+    :ref:`pofilter_tests#variables`,
+    :ref:`pofilter_tests#xmltags`
 
 * Functional -- may confuse the user
 
   * :ref:`pofilter_tests#accelerators`,
-    :ref:`pofilter_tests#acronyms`, :ref:`pofilter_tests#blank`,
-    :ref:`pofilter_tests#emails`, :ref:`pofilter_tests#filepaths`,
-    :ref:`pofilter_tests#functions`, :ref:`pofilter_tests#gconf`,
-    :ref:`pofilter_tests#kdecomments`, :ref:`pofilter_tests#long`,
+    :ref:`pofilter_tests#acronyms`,
+    :ref:`pofilter_tests#blank`,
+    :ref:`pofilter_tests#emails`,
+    :ref:`pofilter_tests#filepaths`,
+    :ref:`pofilter_tests#functions`,
+    :ref:`pofilter_tests#gconf`,
+    :ref:`pofilter_tests#kdecomments`,
+    :ref:`pofilter_tests#long`,
     :ref:`pofilter_tests#musttranslatewords`,
-    :ref:`pofilter_tests#notranslatewords`, :ref:`pofilter_tests#numbers`,
-    :ref:`pofilter_tests#options`, :ref:`pofilter_tests#purepunc`,
-    :ref:`pofilter_tests#sentencecount`, :ref:`pofilter_tests#short`,
-    :ref:`pofilter_tests#spellcheck`, :ref:`pofilter_tests#urls`,
+    :ref:`pofilter_tests#notranslatewords`,
+    :ref:`pofilter_tests#numbers`,
+    :ref:`pofilter_tests#options`,
+    :ref:`pofilter_tests#purepunc`,
+    :ref:`pofilter_tests#sentencecount`,
+    :ref:`pofilter_tests#short`,
+    :ref:`pofilter_tests#spellcheck`,
+    :ref:`pofilter_tests#urls`,
     :ref:`pofilter_tests#unchanged`
 
 * Cosmetic -- make it look better
 
-  * :ref:`pofilter_tests#brackets`, :ref:`pofilter_tests#doublequoting`,
-    :ref:`pofilter_tests#doublespacing`, :ref:`pofilter_tests#doublewords`,
-    :ref:`pofilter_tests#endpunc`, :ref:`pofilter_tests#endwhitespace`,
-    :ref:`pofilter_tests#puncspacing`, :ref:`pofilter_tests#simplecaps`,
-    :ref:`pofilter_tests#simpleplurals`, :ref:`pofilter_tests#startcaps`,
-    :ref:`pofilter_tests#singlequoting`, :ref:`pofilter_tests#startpunc`,
-    :ref:`pofilter_tests#startwhitespace`, :ref:`pofilter_tests#validchars`
+  * :ref:`pofilter_tests#brackets`,
+    :ref:`pofilter_tests#doublequoting`,
+    :ref:`pofilter_tests#doublespacing`,
+    :ref:`pofilter_tests#doublewords`,
+    :ref:`pofilter_tests#endpunc`,
+    :ref:`pofilter_tests#endwhitespace`,
+    :ref:`pofilter_tests#puncspacing`,
+    :ref:`pofilter_tests#simplecaps`,
+    :ref:`pofilter_tests#simpleplurals`,
+    :ref:`pofilter_tests#startcaps`,
+    :ref:`pofilter_tests#singlequoting`,
+    :ref:`pofilter_tests#startpunc`,
+    :ref:`pofilter_tests#startwhitespace`,
+    :ref:`pofilter_tests#validchars`
 
 * Extraction -- useful mainly for extracting certain types of string
 
-  * :ref:`pofilter_tests#compendiumconflicts`, :ref:`pofilter_tests#credits`,
-    :ref:`pofilter_tests#hassuggestion`, :ref:`pofilter_tests#isfuzzy`,
-    :ref:`pofilter_tests#isreview`, :ref:`pofilter_tests#untranslated`
+  * :ref:`pofilter_tests#compendiumconflicts`,
+    :ref:`pofilter_tests#credits`,
+    :ref:`pofilter_tests#hassuggestion`,
+    :ref:`pofilter_tests#isfuzzy`,
+    :ref:`pofilter_tests#isreview`,
+    :ref:`pofilter_tests#untranslated`
 
 .. _test_description:
 
@@ -147,7 +169,7 @@ extracts those for correction.
 credits
 -------
 
-Checks for messages containing translation credits instead of normal.
+Checks for messages containing translation credits instead of normal
 translations.
 
 Some projects have consistent ways of giving credit to translators by having a
@@ -271,8 +293,8 @@ escapes
 
 Checks whether escaping is consistent between the two strings.
 
-Checks escapes such as ``\n`` ``\uNNNN`` to ensure that if they exist in the.
-original that you have them in the translation.
+Checks escapes such as ``\n`` ``\uNNNN`` to ensure that if they exist in the
+original string you also have them in the translation.
 
 .. _pofilter_tests#filepaths:
 
@@ -455,6 +477,7 @@ test can also manage variables-reordering using the ``%1$s`` syntax.  The
 variables' type and details following data are tested to ensure that they are
 strictly identical, but they may be reordered.
 
+.. seealso:: :ref:`pofilter_tests#pythonbraceformat`
 .. seealso:: :wp:`printf Format String <Printf_format_string>`
 
 .. _pofilter_tests#puncspacing:
@@ -481,6 +504,36 @@ Checks that strings that are purely punctuation are not changed.
 
 This extracts strings like "+" or "-" as these usually should not be changed.
 
+.. _pofilter_tests#pythonbraceformat:
+
+pythonbraceformat
+-----------------
+
+Checks whether Python brace format strings match.
+
+Python supports both a variant of the :ref:`pofilter_tests#printf`
+formatting system, and its own formatting language which uses
+placeholders enclosed in braces. The placeholders can be named,
+numbered, or anonymous; the former two are filled in from positional
+args, the latter from keyword arguments. Example:: 
+
+    'the {} {0} hungry {insect}'.format('very', insect='caterpiller')
+    # --> 'the very very hungry caterpiller'
+
+The ``pythonbraceformat`` filter checks for the following problems:
+
+* named placeholders that are present in the original, but missing in
+  the translation, and vice versa.
+* originals and translations that require different numbers of
+  positional args.
+
+When the translation has variables not in the original, this can lead to
+program crashes. The translation not using all variables the original
+uses is safe. Nonetheless, this filter triggers in both cases.
+
+
+.. seealso:: `PEP 3101 -- Advanced String Formatting <http://legacy.python.org/dev/peps/pep-3101/>`_
+
 .. _pofilter_tests#sentencecount:
 
 sentencecount
diff --git a/docs/commands/json2po.rst b/docs/commands/resx2po.rst
similarity index 60%
copy from docs/commands/json2po.rst
copy to docs/commands/resx2po.rst
index c466be4..3c5274a 100644
--- a/docs/commands/json2po.rst
+++ b/docs/commands/resx2po.rst
@@ -1,31 +1,32 @@
 
-.. _json2po:
-.. _po2json:
+.. _resx2po:
+.. _po2resx:
 
-json2po
+resx2po
 *******
 
-Converts .json files to Gettext PO format.
+Converts .Net Resource (.resx) files to Gettext PO format, a monolingual file format used in
+Microsoft .Net Applications.
 
-.. _json2po#usage:
+.. _resx2po#usage:
 
 Usage
 =====
 
 ::
 
-  json2po [options] <json> <po>
-  po2json [options] -t <json> <po> <json>
+  resx2po [options] <resx> <po>
+  po2resx [options] <po> <resx> -t <resx>
 
 Where:
 
 +---------+---------------------------------------------------+
-| <json>  | is a valid .json file or directory of those files |
+| <resx>  | is a valid .resx file or directory of those files |
 +---------+---------------------------------------------------+
 | <po>    | is a directory of PO or POT files                 |
 +---------+---------------------------------------------------+
 
-Options (json2po):
+Options (resx2po):
 
 --version           show program's version number and exit
 -h, --help          show this help message and exit
@@ -34,19 +35,14 @@ Options (json2po):
 --errorlevel=ERRORLEVEL
                       show errorlevel as: :doc:`none, message, exception,
                       traceback <option_errorlevel>`
--i INPUT, --input=INPUT      read from INPUT in JSON format
+-i INPUT, --input=INPUT      read from INPUT in RESX format
 -x EXCLUDE, --exclude=EXCLUDE  exclude names matching EXCLUDE from input paths
 -o OUTPUT, --output=OUTPUT     write to OUTPUT in po, pot formats
--t TEMPLATE, --template=TEMPLATE  read from TEMPLATE in JSON format
+-t TEMPLATE, --template=TEMPLATE  read from TEMPLATE in RESX format
 -S, --timestamp       skip conversion if the output file has newer timestamp
 -P, --pot    output PO Templates (.pot) rather than PO files (.po)
---filter=FILTER  leaves to extract e.g. 'name,desc': (default: extract everything)
---duplicates=DUPLICATESTYLE
-                      what to do with duplicate strings (identical source
-                      text): :doc:`merge, msgctxt <option_duplicates>`
-                      (default: 'msgctxt')
 
-Options (po2json):
+Options (po2resx):
 
 --version            show program's version number and exit
 -h, --help           show this help message and exit
@@ -57,36 +53,33 @@ Options (po2json):
                       traceback <option_errorlevel>`
 -i INPUT, --input=INPUT  read from INPUT in po, pot formats
 -x EXCLUDE, --exclude=EXCLUDE   exclude names matching EXCLUDE from input paths
--o OUTPUT, --output=OUTPUT      write to OUTPUT in JSON format
--t TEMPLATE, --template=TEMPLATE  read from TEMPLATE in JSON format
+-o OUTPUT, --output=OUTPUT      write to OUTPUT in RESX format
+-t TEMPLATE, --template=TEMPLATE  read from TEMPLATE in RESX format
 -S, --timestamp      skip conversion if the output file has newer timestamp
---threshold=PERCENT  only convert files where the translation completion is above PERCENT
---fuzzy              use translations marked fuzzy
---nofuzzy            don't use translations marked fuzzy (default)
 
-.. _json2po#examples:
+.. _resx2po#examples:
 
 Examples
 ========
 
-This example looks at roundtrip of .json translations as well as recovery of
+This example looks at roundtrip of .resx translations as well as recovery of
 existing translations.
 
-First we need to create a set of POT files. ::
+First we need to create a set of POT files ::
 
-  json2po -P json/ pot/
+  resx2po -P resx/ pot/
 
-All .json files found in the ``json/`` directory are converted to Gettext POT
+All .resx files found in the ``resx/`` directory are converted to Gettext POT
 files and placed in the ``pot/`` directory.
 
-If you are translating for the first time then you can skip the next step.  If
-you need to recover your existing translations then we do the following::
+If you are translating for the first time then you can skip the next step. If
+you need to recover your existing translations then we do the following ::
 
-  json2po -t lang/ zu/ po-zu/
+  resx2po zu/ po-zu/ -t lang/
 
-Using the English .json files found in ``lang/`` and your existing Zulu
+Using the English .resx files found in ``lang/`` and your existing Zulu
 translation in ``zu/`` we create a set of PO files in ``po-zu/``.  These will
-now have your translations.  Please be aware that in order for the to work 100%
+now have your translations. Please be aware that in order for the to work 100%
 you need to have both English and Zulu at the same revision. If they are not,
 you will have to review all translations.
 
@@ -95,11 +88,11 @@ POT files.
 
 Once translated you can convert back as follows::
 
-  po2json -t lang/ po-zu/ zu/
+  po2resx po-zu/ zu/ -t lang/
 
 Your translations found in the Zulu PO directory, ``po-zu/``, will be converted
-to .json using the files in ``lang/`` as templates and placing your newly
-translated .json files in ``zu/``.
+to .resx using the files in ``lang/`` as templates and placing your newly
+translated .resx files in ``zu/``.
 
 To update your translations simply redo the POT creation step and make use of
 :doc:`pot2po` to bring your translation up-to-date.
diff --git a/docs/conf.py b/docs/conf.py
index fc4f999..aaa8516 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -58,16 +58,16 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'Translate Toolkit'
-copyright = u'2002-2014, Translate'
+copyright = u'2002-2015, Translate'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
 # The short X.Y version.
-version = '1.12.0'
+version = '1.13.0'
 # The full version, including alpha/beta/rc tags.
-release = '1.12.0'
+release = '1.13.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/docs/contents.rst.inc b/docs/contents.rst.inc
index ad31e6f..2dd4748 100644
--- a/docs/contents.rst.inc
+++ b/docs/contents.rst.inc
@@ -40,8 +40,8 @@ Changelog and legal information are included here.
 .. toctree::
    :maxdepth: 1
 
-   changelog
    releases/index
+   changelog
    history
    license
 
diff --git a/docs/developers/releasing.rst b/docs/developers/releasing.rst
index 10122e7..24f726a 100644
--- a/docs/developers/releasing.rst
+++ b/docs/developers/releasing.rst
@@ -1,49 +1,53 @@
-==================================
 Making a Translate Toolkit Release
-==================================
-
-Summary
-=======
-#. Git clone git at github.com:translate/translate.git translate-release
-#. Create release notes
-#. Up version number
-#. make build
-#. Test install and other tests
-#. Tag the release
-#. Publish on PyPI
-#. Upload to Github
-#. Upload to Sourceforge
-#. Release documentation
-#. Update translate website
-#. Unstage sourceforge
-#. Announce to the world
-#. Cleanup
-#. Other possible steps
-
-
-Detailed instructions
-=====================
+**********************************
+
+This page is divided in three sections. The first one lists the tasks that must
+be performed to get a valid package. The second section includes a list of
+tasks to get the package published and the release announced. The third one
+lists and suggests some possible cleanup tasks to be done after releasing.
+
+.. note:: Please note that this is not a complete list of tasks. Please feel
+   free to improve it.
+
+
+Create the package
+==================
+
+The first steps are to create and validate a package for the next release.
+
 
 Get a clean checkout
 --------------------
+
 We work from a clean checkout to ensure that everything you are adding to the
-build is what is in VC and doesn't contain any of your uncommitted changes.  It
-also ensure that someone else could replicate your process.
+build is what is in the repository and doesn't contain any of your uncommitted
+changes. It also ensures that someone else could replicate your process.
+
+.. code-block:: bash
+
+    $ git clone git at github.com:translate/translate.git translate-release
+    $ cd translate-release
+    $ git submodule update --init
+
+
+Check copyright dates
+---------------------
+
+Update any copyright dates in :file:`docs/conf.py:copyright` and anywhere else
+that needs fixing.
 
 .. code-block:: bash
 
-  $ git clone git at github.com:translate/translate.git translate-release
-  $ cd translate-release
-  $ git submodule update --init
+    $ git grep 2013  # Should pick up anything that should be examined
 
 
 Create release notes
 --------------------
+
 The release notes will be used in these places:
 
-- Toolkit website - `download page
+- Translate Toolkit website - `download page
   <http://toolkit.translatehouse.org/download.html>`_ (used in gh-pages)
-- Sourceforge download - README.rst (used to give user info)
 - Email announcements - text version
 
 We create our release notes in reStructured Text, since we use that elsewhere
@@ -54,14 +58,14 @@ done generically like this:
 
 .. code-block:: bash
 
-  $ git log $previous_version..HEAD > docs/release/$version.rst
+    $ git log $previous_version..HEAD > docs/release/$version.rst
 
 
 Or a more specific example:
 
 .. code-block:: bash
 
-  $ git log 1.10.0..HEAD > docs/releases/1.11.0-rc1.rst
+    $ git log 1.10.0..HEAD > docs/releases/1.11.0-rc1.rst
 
 
 Edit this file.  You can use the commits as a guide to build up the release
@@ -78,7 +82,8 @@ Read for grammar and spelling errors.
 .. note:: When writing the notes please remember:
 
    #. The voice is active. 'Translate has released a new version of the
-      toolkit', not 'A new version of the toolkit was release by Translate'.
+      Translate Toolkit', not 'A new version of the Translate Toolkit was
+      released by Translate'.
    #. The connection to the users is human not distant.
    #. We speak in familiar terms e.g. "I know you've been waiting for this
       release" instead of formal.
@@ -87,33 +92,28 @@ We create a list of contributors using this command:
 
 .. code-block:: bash
 
-  $ git log 1.10.0..HEAD --format='%aN, ' | awk '{arr[$0]++} END{for (i in arr){print arr[i], i;}}' | sort -rn | cut -d\  -f2-
-
-
-Add release notes for dev
--------------------------
-
-After updating the release notes for the about to be released version, it is
-necessary to add new release notes for the next release, tagged as ``dev``.
+    $ git log 1.10.0..HEAD --format='%aN, ' | awk '{arr[$0]++} END{for (i in arr){print arr[i], i;}}' | sort -rn | cut -d\  -f2-
 
 
 Up version numbers
 ------------------
+
 Update the version number in:
 
-- ``translate/__version__.py``
-- ``docs/conf.py``
+- :file:`translate/__version__.py`
+- :file:`docs/conf.py`
 
-In ``__version__.py``, bump the build number if anybody used the toolkit with
-the previous number, and there have been any changes to code touching stats or
-quality checks.  An increased build number will force a toolkit user, like
-Pootle, to regenerate the stats and checks.
+In :file:`translate/__version__.py`, bump the build number if anybody used the
+Translate Toolkit with the previous number, and there have been any changes to
+code touching stats or quality checks.  An increased build number will force a
+Translate Toolkit user, like Pootle, to regenerate the stats and checks.
 
-For ``conf.py`` change ``version`` and ``release``
+For :file:`docs/conf.py` change ``version`` and ``release``.
 
 .. todo:: FIXME - We might want to consolidate the version and release info so
    that we can update it in one place.
 
+
 The version string should follow the pattern::
 
     $MAJOR-$MINOR-$MICRO[-$EXTRA]
@@ -127,22 +127,27 @@ E.g. ::
 release of a ``$MINOR`` version will always have a ``$MICRO`` of ``.0``. So
 ``1.10.0`` and never just ``1.10``.
 
+.. note:: You probably will have to adjust the output of some of the functional
+   tests, specifically the manpage ones, to use the right new version.
+
 
 Build the package
 -----------------
-Building is the first step to testing that things work.  From your clean
+
+Building is the first step to testing that things work. From your clean
 checkout run:
 
 .. code-block:: bash
 
-  $ mkvirtualenv build-ttk-release
-  (build-ttk-release)$ pip install -r requirements/dev.txt
-  (build-ttk-release)$ make build
-  (build-ttk-release)$ deactivate
-  $ rmvirtualenv build-ttk-release
+    $ mkvirtualenv build-ttk-release
+    (build-ttk-release)$ pip install -r requirements/dev.txt
+    (build-ttk-release)$ make build
+    (build-ttk-release)$ deactivate
+    $ rmvirtualenv build-ttk-release
 
 
-This will create a tarball in ``dist/`` which you can use for further testing.
+This will create a tarball in :file:`dist/` which you can use for further
+testing.
 
 .. note:: We use a clean checkout just to make sure that no inadvertant changes
    make it into the release.
@@ -150,13 +155,14 @@ This will create a tarball in ``dist/`` which you can use for further testing.
 
 Test install and other tests
 ----------------------------
+
 The easiest way to test is in a virtualenv. You can test the installation of
-the new toolkit using:
+the new Translate Toolkit using:
 
 .. code-block:: bash
 
-  $ mkvirtualenv test-ttk-release
-  (releasing)$ pip install path/to/dist/translate-toolkit-$version.tar.bz2
+    $ mkvirtualenv test-ttk-release
+    (test-ttk-release)$ pip install $path_to_dist/translate-toolkit-$version.tar.bz2
 
 
 You can then proceed with other tests such as checking:
@@ -166,47 +172,66 @@ You can then proceed with other tests such as checking:
 
    .. code-block:: bash
 
-     (test-ttk-release)$ moz2po --help
-     (test-ttk-release)$ php2po --version
-     (test-ttk-release)$ deactivate
-     $ rmvirtualenv test-ttk-release
+       (test-ttk-release)$ moz2po --help
+       (test-ttk-release)$ php2po --version
+       (test-ttk-release)$ deactivate
+       $ rmvirtualenv test-ttk-release
 
 #. Meta information about the package is correct. This is stored in
    :file:`setup.py`, to see some options to display meta-data use:
 
    .. code-block:: bash
 
-     $ ./setup.py --help
+       $ ./setup.py --help
 
    Now you can try some options like:
 
    .. code-block:: bash
 
-     $ ./setup.py --name
-     $ ./setup.py --version
-     $ ./setup.py --author
-     $ ./setup.py --author-email
-     $ ./setup.py --url
-     $ ./setup.py --license
-     $ ./setup.py --description
-     $ ./setup.py --long-description
-     $ ./setup.py --classifiers
+       $ ./setup.py --name
+       $ ./setup.py --version
+       $ ./setup.py --author
+       $ ./setup.py --author-email
+       $ ./setup.py --url
+       $ ./setup.py --license
+       $ ./setup.py --description
+       $ ./setup.py --long-description
+       $ ./setup.py --classifiers
 
    The actual descriptions are taken from :file:`translate/__init__.py`.
 
 
+Publish the new release
+=======================
+
+Once we have a valid package it is necessary to publish it and announce the
+release.
+
+
 Tag and branch the release
 --------------------------
+
 You should only tag once you are happy with your release as there are some
 things that we can't undo. You can safely branch for a ``stable/`` branch
 before you tag.
 
 .. code-block:: bash
 
-  $ git checkout -b stable/1.10.0
-  $ git push origin stable/1.10.0
-  $ git tag -a 1.10.0 -m "Tag version 1.10.0"
-  $ git push --tags
+    $ git checkout -b stable/1.10.0
+    $ git push origin stable/1.10.0
+    $ git tag -a 1.10.0 -m "Tag version 1.10.0"
+    $ git push --tags
+
+
+Release documentation
+---------------------
+
+We need a tagged release before we can do this. The docs are published on Read
+The Docs.
+
+- https://readthedocs.org/dashboard/translate-toolkit/versions/
+
+Use the admin pages to flag a version that should be published.
 
 
 Publish on PyPI
@@ -225,23 +250,17 @@ Publish on PyPI
 
    .. code-block:: bash
 
-     $ ./setup.py register
+       $ ./setup.py register
 
    will create such file. It will also actually publish the meta-data so only
    do it when you are actually ready.
 
-To test before publishing run:
-
-.. code-block:: bash
-
-  $ make test-publish-pypi
-
 
-Then to actually publish:
+Run the following to publish the package on PyPI:
 
 .. code-block:: bash
 
-  $ make publish-pypi
+    $ make publish-pypi
 
 
 Create a release on Github
@@ -254,126 +273,95 @@ You will need:
 - Tarball of the release
 - Release notes in Markdown
 
+
+Do the following to create the release:
+
 #. Draft a new release with the corresponding tag version
-#. Convert the release notes to Markdown with `Pandoc
+#. Convert the major changes in the release notes to Markdown with `Pandoc
    <http://johnmacfarlane.net/pandoc/>`_ and add those to the release
+#. Include a link to the full release notes in the description
 #. Attach the tarball to the release
 #. Mark it as pre-release if it's a release candidate.
 
 
-Copy files to sourceforge
--------------------------
-
-.. note:: You need to have release permissions on sourceforge to perform this
-   step.
-
-- http://sourceforge.net/projects/translate/files/Translate%20Toolkit/
-
-You will need:
-
-- Tarball of the release
-- Release notes in reStructured Text
-
-
-These are the steps to perform:
-
-#. Create a new folder in the `Translate Toolkit
-   <https://sourceforge.net/projects/translate/files/Translate%20Toolkit/>`_
-   release folder using the 'Add Folder' button.  The folder must have the same
-   name as the release version e.g.  ``1.10.0-rc1``.  Mark this as being for
-   staging for the moment.
-#. ``make publish-sourceforge`` will give you the command to upload your
-   tarball and ``README.rst``.
-
-   #. Upload tarball for release.
-   #. Upload release notes as ``README.rst``.
-   #. Click on the info icon for ``README.rst`` and tick "Exclude Stats" to
-      exclude the README from stats counting.
-
-#. Check that the README.rst for the parent ``Translate Toolkit`` folder is
-   still appropriate, this is the text from ``translate/__info__.py``.
-#. Check all links for ``README.rst`` files, new release and parent.
-
-
-Release documentation
----------------------
-We need a tagged release before we can do this.  The docs are published on Read
-The Docs.
-
-- https://readthedocs.org/dashboard/translate-toolkit/versions/
-
-Use the admin pages to flag a version that should be published
-
-.. todo:: FIXME we might need to do this before publishing so that we can
-   update doc references to point to the tagged version as apposed to the
-   latest version.
-
+Update Translate Toolkit website
+--------------------------------
 
-Update translate website
-------------------------
 We use github pages for the website. First we need to checkout the pages:
 
 .. code-block:: bash
 
-  $ git checkout gh-pages
+    $ git checkout gh-pages
 
 
-#. In ``_posts/`` add a new release posting.  This is in Markdown format (for
-   now), so we need to change the release notes .rst to .md, which mostly means
-   changing URL links from ```xxx <link>`_`` to ``[xxx](link)``.
-#. Change $version as needed. See ``download.html``, ``_config.yml`` and
-   ``egrep -r $old_release *``
+#. In :file:`_posts/` add a new release posting.  This is in Markdown format
+   (for now), so we need to change the release notes .rst to .md, which mostly
+   means changing URL links from ```xxx <link>`_`` to ``[xxx](link)``.
+#. Change ``$version`` as needed. See :file:`download.html`,
+   :file:`_config.yml` and :command:`egrep -r $old_release *`
 #. :command:`git commit` and :command:`git push` -- changes are quite quick, so
    easy to review.
 
 
-Unstage on sourceforge
-----------------------
-If you have created a staged release folder, then unstage it now.
-
-
 Announce to the world
 ---------------------
+
 Let people know that there is a new version:
 
 #. Announce on mailing lists:
-   Send the announcement to the translate-announce mailing lists on
-   translate-announce at lists.sourceforge.net
+
+   - translate-announce at lists.sourceforge.net
+   - translate-pootle at lists.sourceforge.net
+
 #. Adjust the #pootle channel notice. Use ``/topic`` to change the topic.
 #. Email important users
 #. Tweet about it
-#. Update `Toolkit's Wikipedia page
+#. Update `Translate Toolkit's Wikipedia page
    <http://en.wikipedia.org/wiki/Translate_Toolkit>`_
 
 
-Cleanup
-=======
+Post-Releasing Tasks
+====================
+
 These are tasks not directly related to the releasing, but that are
 nevertheless completely necessary.
 
+
 Bump version to N+1-alpha1
 --------------------------
 
-Now that we've release lets make sure that master reflect the current state
-which would be ``{N+1}-alpha1``. This prevents anyone using master being
-confused with a stable release and we can easily check if they are using master
-or stable.
+If this new release is a stable one bump the version in ``master`` to
+``{N+1}-alpha1``. This prevents anyone using ``master`` being confused with a
+stable release and we can easily check if they are using ``master`` or
+``stable``.
+
+.. note:: You probably will have to adjust the output of some of the functional
+   tests, specifically the manpage ones, to use the right new version.
+
+
+Add release notes for dev
+-------------------------
+
+After updating the release notes for the about to be released version, it is
+necessary to add new release notes for the next release, tagged as ``dev``.
 
 
 Other possible steps
-====================
+--------------------
+
 Some possible cleanup tasks:
 
-- Remove any RC builds from the sourceforge download pages (maybe?).
-- Commit any release notes and such (or maybe do that before tagging).
-- Remove your translate-release checkout.
-- Update and fix these release notes.
+- Remove your ``translate-release`` checkout.
+- Update and fix these releasing notes:
+
+  - Make sure these releasing notes are updated on ``master``.
+  - Discuss any changes that should be made or new things that could be added.
+  - Add automation if you can.
 
 
 We also need to check and document these if needed:
 
 - Change URLs to point to the correct docs: do we want to change URLs to point
-  to the $version docs rather then 'latest'
-- Building on Windows, building for other Linux distros. We have produced
-  Windows builds in the past.
-- Communicating to upstream packagers
+  to the ``$version`` docs rather then ``latest``?
+- Building on Windows, building for other Linux distros.
+- Communicating to upstream packagers.
diff --git a/docs/developers/styleguide.rst b/docs/developers/styleguide.rst
index 5bdd772..e12f481 100644
--- a/docs/developers/styleguide.rst
+++ b/docs/developers/styleguide.rst
@@ -119,6 +119,48 @@ Example:
             return self.name.upper() + '!!!!111'
 
 
+Strings
+~~~~~~~
+
+- Double quotes are suggested over single quotes, but always try to respect the
+  surrounding coding style. This is overruled by escaping which you should always
+  try to avoid.
+
+  .. code-block:: python
+
+    # Good.
+    str1 = "Sauron's eye"
+    str2 = 'Its name is "Virtaal".'
+
+
+    # Bad.
+    str3 = 'Sauron\'s eye'
+    str4 = "Its name is \"Virtaal\"."
+
+
+String formatting
+~~~~~~~~~~~~~~~~~
+
+While str.format() is more powerful than %-formatting, the latter has been the
+canonical way of formatting strings in Python for a long time and the Python
+core team has shown no desire to settle on one syntax over the other.
+For simple, serial positional cases (non-translatable strings), the old "%s"
+way of formatting is preferred.
+For anything more complex, including translatable strings, str.format is
+preferred as it is significantly more powerful and often cleaner.
+
+.. code-block:: python
+
+    # Good
+    print("Hello, {thing}".format(thing="world"))
+    print("%s=%r" % ("hello", "world"))  # non-translatable strings
+
+    # Bad
+    print("%s, %s" % ("Hello", "world"))  # Translatable string.
+    print("Hello, %(thing)s" % {"thing": "world"})  # Use {thing}.
+    print("Hello, {}".format("world"))  # Incompatible with Python 2.6. Use %s.
+
+
 .. _styleguide-imports:
 
 Imports
@@ -263,43 +305,6 @@ Properties
     x = property(getx, setx, delx, "I'm the 'x' property.")
 
 
-Single vs double quoted strings
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-There is no preference on using single or double quotes for strings, except in
-some specific cases:
-
-- Always use single quotes for string dictionary keys:
-
-  .. code-block:: python
-
-    # Good.
-    demo = {
-        'language': language,
-    }
-
-
-    # Bad.
-    demo = {
-        "language": language,
-    }
-
-
-- When a single or double quote character needs to be escaped it is recommended
-  to instead enclose the string using the other quoting:
-
-  .. code-block:: python
-
-    # Good.
-    str1 = "Sauron's eye"
-    str2 = 'Its name is "Virtaal".'
-
-
-    # Bad.
-    str3 = 'Sauron\'s eye'
-    str4 = "Its name is \"Virtaal\"."
-
-
 Expressions and Statements
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -688,26 +693,3 @@ Docstring comments:
 .. _reStructuredText primer: http://sphinx-doc.org/rest.html
 .. _Sphinx documentation: http://sphinx-doc.org/contents.html
 .. _paragraph-level markup: http://sphinx-doc.org/markup/para.html#paragraph-level-markup
-
-
-String formatting
------------------
-
-While str.format() is more powerful than %-formatting, the latter has been the
-canonical way of formatting strings in Python for a long time and the Python
-core team has shown no desire to settle on one syntax over the other.
-For simple, serial positional cases (non-translatable strings), the old "%s"
-way of formatting is preferred.
-For anything more complex, including translatable strings, str.format is
-preferred as it is significantly more powerful and often cleaner.
-
-.. code-block:: python
-
-    # Good
-    print("Hello, {thing}".format(thing="world"))
-    print("%s=%r" % ("hello", "world"))  # non-translatable strings
-
-    # Bad
-    print("%s, %s" % ("Hello", "world"))  # Translatable string.
-    print("Hello, %(thing)s" % {"thing": "world"})  # Use {thing}.
-    print("Hello, {}".format("world"))  # Incompatible with Python 2.6. Use %s.
diff --git a/docs/formats/index.rst b/docs/formats/index.rst
index 2354b34..c86099c 100644
--- a/docs/formats/index.rst
+++ b/docs/formats/index.rst
@@ -44,6 +44,7 @@ Other translation formats
    flex
    catkeys
    android
+   resx
 
 * :doc:`csv`
 * :doc:`ini` (including Inno Setup .isl dialect)
@@ -58,6 +59,7 @@ Other translation formats
 * Adobe :doc:`flex` files (from version 1.8)
 * Haiku :doc:`catkeys` (from version 1.8)
 * :doc:`android` (supports storage, not conversion)
+* :doc:`resx` .NET Resource files (.resx)
 
 .. _formats#translation_memory_formats:
 
@@ -185,7 +187,6 @@ Formats that we would like to support but don't currently support:
   * :wp:`Rich Text Format <Rich_Text_Format>` (RTF) see also `pyrtf-ng
     <http://code.google.com/p/pyrtf-ng/>`_
   * :wp:`Open XML Paper Specification <Open_XML_Paper_Specification>`
-  * .NET Resource files (.resx) -- :issue:`Issue 396 <396>`
 
 * XML related
 
diff --git a/docs/formats/resx.rst b/docs/formats/resx.rst
new file mode 100644
index 0000000..0205272
--- /dev/null
+++ b/docs/formats/resx.rst
@@ -0,0 +1,36 @@
+.. _resx:
+
+.NET Resource files (.resx)
+***************************
+
+.Net Resource (.resx) files are a monolingual file format used in Microsoft .Net Applications. The .resx resource
+file format consists of XML entries, which specify objects and strings inside XML tags. It contains a
+standard set of header information, which describes the format of the resource entries and specifies the
+versioning information for the XML used to parse the data. Following the header information, each entry is
+described as a name/value pair.
+
+Comments can be added per string using the optional ``<comment>`` field. As only one comment field is available,
+both translator and developer comments are stored in the same place. Translator comments are
+automatically wrapped with brackets and pre-fixed with 'Translator Comment:' during the po2resx process to
+make it easy to distinguish comment origin inside the .resx files.
+
+Example:
+
+::
+
+    <data name="key">
+        <value>hello world</value>
+        <comment>Optional developer comment about the string [Translator Comment: Optional translator comment]</comment>
+    </data>
+
+resx2po and  po2resx are used for conversion.
+
+.. _resx#references:
+
+References
+==========
+
+* `Resources in .Resx File Format
+  <http://msdn.microsoft.com/en-us/library/ekyft91f%28v=VS.90%29.aspx>`_
+* `ASP.NET Web Page Resources Overview
+  <http://msdn.microsoft.com/en-us/library/ms227427.aspx>`_
diff --git a/docs/installation.rst b/docs/installation.rst
index d401a48..ff3f41d 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -16,6 +16,7 @@ from our packaged releases for some other reason.
 If your system already has the toolkit prepackaged, then please let us know
 what steps are required to install it.
 
+
 .. _installation#prerequisites:
 
 Prerequisites
@@ -23,15 +24,21 @@ Prerequisites
 
 * Remove old versions of toolkit on Debian
 
-The dollowing advice only applies to manual installation from tar ball.
+The following advice only applies to manual installation from tar ball.
+
+#. Find location of your python packages:
+
+   .. code-block:: bash
 
-#. Find location of your python packages::
+      $ python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"
 
-     python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
 
-#. Delete toolkit package from your Python site-packages directory e.g.::
+#. Delete toolkit package from your Python site-packages directory e.g.:
+
+   .. code-block:: bash
+
+      $ rm -R /usr/local/lib/python2.6/dist-packages/translate
 
-     rm /usr/local/lib/python2.5/dist-packages/translate -R
 
 .. _installation#building:
 
@@ -40,6 +47,7 @@ Building
 
 For build instructions, see the :doc:`developers/building` page.
 
+
 .. _installation#download:
 
 Download
@@ -63,6 +71,7 @@ System, or from a source release, you should check the README file for
 information on the dependencies that are needed. Some of the dependencies are
 optional. The README file documents this.
 
+
 .. _installation#installing_packaged_versions:
 
 Installing packaged versions
@@ -84,61 +93,83 @@ Get the package for your system:
 | .deb       | for Debian GNU/Linux (etch version)                        |
 +------------+------------------------------------------------------------+
 
-The RPM package can be installed by using the following command::
+The RPM package can be installed by using the following command:
+
+.. code-block:: bash
+
+   $ rpm -Uvh translate-toolkit-1.0.1.rpm
+
+
+To install a tar.bz2:
 
-  rpm -Uvh translate-toolkit-1.0.1.rpm
+.. code-block:: bash
 
-To install a tar.bz2::
+   $ tar xvjf translate-toolkit-1.1.0.tar.bz2
+   $ cd translate-toolkit-1.1.0
+   $ su
+   $ ./setup.py install
 
-  tar xvjf translate-toolkit-1.1.0.tar.bz2
-  cd translate-toolkit-1.1.0
-  su
-  ./setup.py install
 
 On Windows simply click on the .exe file and follow the instructions.
 
-On Debian (if you are on etch), just type the following command::
+On Debian (if you are on etch), just type the following command:
+
+.. code-block:: bash
+
+   $ aptitude install translate-toolkit
 
-  aptitude install translate-toolkit
 
 If you are using an old Debian stable system, you might want to install the
-.tar.bz2 version. Be sure to install python and python development first with::
+.tar.bz2 version. Be sure to install python and python development first with:
+
+.. code-block:: bash
+
+   $ apt-get install python python-dev
 
-  apt-get install python python-dev
 
 Alternatively newer packages might be in testing.
 
+
 .. _installation#installing_from_git:
 
 Installing from Git
 ===================
 
 If you want to try the bleeding edge, or just want to have the latest fixes
-from a stabilising branch then you need to use Git to get your sources.::
+from a stabilising branch then you need to use Git to get your sources:
+
+.. code-block:: bash
+
+   $ git clone https://github.com/translate/translate.git
 
-  git clone https://github.com/translate/translate.git
 
 This will retrieve the ``master`` branch of the Toolkit.  Further Git
 `instructions <http://git.or.cz/course/svn.html>`_ are also available.
 
-Once you have the sources you have two options, a full install::
+Once you have the sources you have two options, a full install:
+
+.. code-block:: bash
+
+   $ su
+   $ ./setup.py install
 
-  su
-  ./setup.py install
 
-or, running the tools from the source directory
+or, running the tools from the source directory:
 
-::
+.. code-block:: bash
+
+   $ ./setuppath # Only needed the first time
+   $ . setpath  # Do this once for a session
 
-    ./setuppath # Only needed the first time
-    . setpath  # Do this once for a session
 
 .. _installation#verify_installed_version:
 
 Verify installed version
 ========================
 
-To verify which version of the toolkit you have installed run::
+To verify which version of the toolkit you have installed run:
+
+.. code-block:: bash
 
-  [l10n at server]# moz2po --version
-  moz2po 1.1.0
+   $ moz2po --version
+   moz2po 1.1.0
diff --git a/docs/releases/1.13.0-rc1.rst b/docs/releases/1.13.0-rc1.rst
new file mode 100644
index 0000000..36567a9
--- /dev/null
+++ b/docs/releases/1.13.0-rc1.rst
@@ -0,0 +1,99 @@
+.. These notes are used in:
+   1. Our email announcements
+   2. The Translate Tools download page at toolkit.translatehouse.org
+   3. Sourceforge download page in
+      http://sourceforge.net/projects/translate/files/Translate%20Toolkit/1.13.0-rc1/README.rst/download
+
+Translate Toolkit 1.13.0-rc1
+****************************
+
+*Released on 12 November 2014*
+
+This release contains many improvements and bug fixes. While it contains many
+general improvements, it also specifically contains needed changes for the
+upcoming `Pootle <http://pootle.translatehouse.org/>`_ 2.6.0 and `Virtaal
+<http://virtaal.translatehouse.org>`_ releases.
+
+It is just over 3 months since the last release and there are many improvements
+across the board. A number of people contributed to this release and we've
+tried to credit them wherever possible (sorry if somehow we missed you).
+
+..
+  This is used for the email and other release notifications
+  Getting it and sharing it
+  =========================
+  * pip install translate-toolkit
+  * `Sourceforge download
+    <https://sourceforge.net/projects/translate/files/Translate%20Toolkit/1.13.0-rc1/>`_
+  * Please share this URL http://toolkit.translatehouse.org/download.html if
+    you'd like to tweet or post about the release.
+
+
+Highlighted improvements
+========================
+
+Major changes
+-------------
+
+- New converters for IDML format
+- Extensive cleanup on ODF converters
+- Some bugfixes and improvements
+
+
+Formats and Converters
+----------------------
+
+- IDML
+
+  - Added the ``idml2po`` and ``po2idml`` converters.
+
+- ODF
+
+  - Removed the ``--engine`` option in ``odf2xliff`` because the ``itools``
+    third party library is no longer used.
+
+- TS
+
+  - Pretty print output the same as Qt Linguist (:issue:`1420`)
+
+
+Quality Checks
+--------------
+
+- Added the ability to skip some quality checks for the he, ug, zh_CN, zh_HK
+  and zh_TW languages.
+
+
+Tools
+-----
+
+- Removed the unnecessary dependency on ``lxml`` in ``pretranslate``
+  (:issue:`1909`)
+
+
+General
+-------
+
+- Fixed bug in file discovery that prevented Pootle Pootle's terminology
+  feature from working properly in some scenarios.
+- Minor docs cleanups
+- ODF code extensive cleanups:
+
+  - Applied tons of PEP8 and style guide cleanups
+  - Removed unused code
+  - Removed unused test ODT file
+  - Added lots of docstrings
+  - Simplified code to ease maintainability and improve readability
+
+
+...and loads of general code cleanups and of course many many bugfixes.
+
+
+Contributors
+------------
+
+This release was made possible by the following people:
+
+Leandro Regueiro, Yaron Shahrabani, Julen Ruiz Aizpuru, Jerome Leclanche.
+
+And to all our bug finders and testers, a Very BIG Thank You.
diff --git a/docs/releases/1.13.0.rst b/docs/releases/1.13.0.rst
new file mode 100644
index 0000000..6869ab6
--- /dev/null
+++ b/docs/releases/1.13.0.rst
@@ -0,0 +1,184 @@
+.. These notes are used in:
+   1. Our email announcements
+   2. The Translate Tools download page at toolkit.translatehouse.org
+   3. Sourceforge download page in
+      http://sourceforge.net/projects/translate/files/Translate%20Toolkit/1.13.0/README.rst/download
+
+Translate Toolkit 1.13.0
+************************
+
+*Released on 13 May 2015*
+
+This release contains many improvements and bug fixes. While it contains many
+general improvements, it also specifically contains needed changes for the
+upcoming `Pootle <http://pootle.translatehouse.org/>`_ 2.6.0 and 2.7.0 and
+`Virtaal <http://virtaal.translatehouse.org>`_ releases.
+
+It is just over 6 months since the last release and there are many improvements
+across the board. A number of people contributed to this release and we've
+tried to credit them wherever possible (sorry if somehow we missed you).
+
+..
+  This is used for the email and other release notifications
+  Getting it and sharing it
+  =========================
+  * pip install translate-toolkit
+  * `Sourceforge download
+    <https://sourceforge.net/projects/translate/files/Translate%20Toolkit/1.13.0/>`_
+  * Please share this URL http://toolkit.translatehouse.org/download.html if
+    you'd like to tweet or post about the release.
+
+
+Highlighted improvements
+========================
+
+1.13.0 vs 1.13.0-rc1
+--------------------
+
+Changes since 1.13.0 RC1:
+
+- Support for new .Net Resource (.resx) format
+- Fixes in Android format
+- Correctly dump JSON file
+- Correctly roundtrip PHP with spaces after array
+- Import only real comments in Mozilla lang format
+
+- XLIFF
+
+  - Mark units as needing attention if sources don't match when merging units
+  - ``pot2po`` now also accepts files with .xliff extension
+
+- po2moz now correctly handles files with fullstop in filename
+- Added new quality check for Python brace format
+- Expanded printf quality check to support boost::format
+- Added new language plural forms, fixed a couple of plural forms, and other
+  minor changes in languages
+
+
+Major changes
+-------------
+
+- New converters for IDML format
+- Support for new .Net Resource (.resx) format
+- Extensive cleanup on ODF converters
+- New quality checks
+
+
+Formats and Converters
+----------------------
+
+- IDML
+
+  - Added the ``idml2po`` and ``po2idml`` converters.
+
+- .Net Resource (.resx)
+
+  - Added store to represent the format and the ``resx2po`` and ``po2resx``
+    converters.
+
+- Android
+
+  - Improved escape and unescape of Android resources with HTML markup.
+  - Fixed bug in canceling whitespaces with backslash when unescaping.
+
+- ODF
+
+  - Removed the ``--engine`` option in ``odf2xliff`` because the ``itools``
+    third party library is no longer used.
+
+- TS
+
+  - Pretty print output the same as Qt Linguist (:issue:`1420`)
+
+- JSON
+
+  - Dump content on memory instead of copy of parsed file (:issue:`3249`).
+
+- PHP
+
+  - Correctly roundtrip PHP with spaces after array (:issue:`3231`).
+
+- Mozilla lang
+
+  - Import only real comments (starting with #), not meta tags (starting with
+    ##).
+
+- XLIFF
+
+  - Mark units as needing attention if sources don't match when merging units.
+  - ``pot2po`` now also accepts files with .xliff extension
+
+- po2moz
+
+  - Fixed handling of files with fullstop in filename
+
+
+Quality Checks
+--------------
+
+- Added quality check for Python brace format.
+- Added the ability to skip some quality checks for the he, ug, zh_CN, zh_HK
+  and zh_TW languages.
+- Expanded printf quality check to support reordering `boost::format
+  <http://www.boost.org/doc/libs/1_55_0/libs/format/doc/format.html>`_
+  positional directives.
+- Expanded docstrings to include fully detailed descriptions in order to
+  display them on Pootle.
+
+
+Tools
+-----
+
+- Removed the unnecessary dependency on ``lxml`` in ``pretranslate``
+  (:issue:`1909`)
+
+
+Languages
+---------
+
+- Language plurals:
+
+  - Fixed plural forms for ga and pt_BR languages
+  - Added new plural forms for new languages
+
+- Adjusted punctuation for zh
+- Corrected "Songhay" language name
+
+
+
+General
+-------
+
+- Fixed bug in file discovery that prevented Pootle Pootle's terminology
+  feature from working properly in some scenarios.
+- Docs:
+
+  - Major rewrite of releasing instructions
+  - Reorganized string-related guidelines on styleguide
+  - Other minor docs cleanups
+
+- ODF code extensive cleanups:
+
+  - Applied tons of PEP8 and style guide cleanups
+  - Removed unused code
+  - Removed unused test ODT file
+  - Added lots of docstrings
+  - Simplified code to ease maintainability and improve readability
+
+- Dropped no longer working automatic publishing in PyPI and SourceForge
+- Several changes to speed up Travis builds
+- Unhid some tests
+
+...and loads of general code cleanups and of course many many bugfixes.
+
+
+Contributors
+------------
+
+This release was made possible by the following people:
+
+Leandro Regueiro, Dwayne Bailey, Yaron Shahrabani, Sarah Hale, Sietse Brouwer,
+Jerome Leclanche, Julen Ruiz Aizpuru, Michael Andres, William Grzybowski,
+SirAnthony, Rafael Ferreira, Luka Kama, Francesco Lodolo, Buganini, babycaseny.
+
+And to all our bug finders and testers, a Very BIG Thank You.
diff --git a/docs/releases/dev.rst b/docs/releases/dev.rst
deleted file mode 100644
index 2a8e65f..0000000
--- a/docs/releases/dev.rst
+++ /dev/null
@@ -1,71 +0,0 @@
-.. These notes are used in:
-   1. Our email announcements
-   2. The Translate Tools download page at toolkit.translatehouse.org
-   3. Sourceforge download page in
-      http://sourceforge.net/projects/translate/files/Translate%20Toolkit/1.12.0-rc1/README.rst/download
-
-Translate Toolkit 1.12.0-rc1
-****************************
-
-*Not yet released*
-
-This release contains many improvements and bug fixes. While it contains many
-general improvements, it also specifically contains needed changes and
-optimizations for the upcoming `Pootle <http://pootle.translatehouse.org/>`_
-2.6.0 and `Virtaal <http://virtaal.translatehouse.org>`_ releases.
-
-It is just over X months since the last release and there are many improvements
-across the board.  A number of people contributed to this release and we've
-tried to credit them wherever possible (sorry if somehow we missed you).
-
-..
-  This is used for the email and other release notifications
-  Getting it and sharing it
-  =========================
-  * pip install translate-toolkit
-  * `Sourceforge download
-    <https://sourceforge.net/projects/translate/files/Translate%20Toolkit/1.12.0/>`_
-  * Please share this URL http://toolkit.translatehouse.org/download.html if
-    you'd like to tweet or post about the release.
-
-Highlighted improvements
-========================
-
-Major changes
--------------
-
-- Properties and DTD formats fix a number of issues
-- Massive code cleanup looking forward Python 3 compatibility
-- Important changes in development process to ease testing
-
-
-Formats and Converters
-----------------------
-
-- Mozilla properties
-
-  - The ``\uNN`` characters are now properly handled
-  - Fixed conversion of successive Gaia plural units in prop2po
-
-- DTD
-
-  - Underscore character is now a valid character in entity names
-
-
-General
--------
-
-- Misc docs cleanups
-
-
-...and loads of general code cleanups and of course many many bugfixes.
-
-
-Contributors
-------------
-
-This release was made possible by the following people:
-
-%CONTRIBUTORS%
-
-And to all our bug finders and testers, a Very BIG Thank You.
diff --git a/docs/releases/index.rst b/docs/releases/index.rst
index e6fa131..35d720a 100644
--- a/docs/releases/index.rst
+++ b/docs/releases/index.rst
@@ -3,15 +3,15 @@
 Release Notes
 *************
 
-The following are release notes used on `PyPI
-<https://pypi.python.org/pypi/translate-toolkit>`_, `Sourceforge
-<http://sourceforge.net/projects/translate/files/Translate%20Toolkit/>`_ and
-mailing lists for Translate Toolkit releases.
+The following are release notes used on `PyPI 
+<https://pypi.python.org/pypi/translate-toolkit>`_ and mailing lists for
+Translate Toolkit releases.
 
 .. toctree::
    :maxdepth: 1
 
-   dev <dev>
+   1.13.0 <1.13.0>
+   1.13.0-rc1 <1.13.0-rc1>
    1.12.0 <1.12.0>
    1.12.0-rc1 <1.12.0-rc1>
    1.11.0 <1.11.0>
@@ -19,3 +19,5 @@ mailing lists for Translate Toolkit releases.
    1.10.0 <1.10.0>
    1.9.0 <1.9.0>
    1.8.1 <1.8.1>
+
+Check the :doc:`Changelog </changelog>` for older releases.
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 0000000..229edc2
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+norecursedirs = .git build docs
diff --git a/requirements/dev.txt b/requirements/dev.txt
index 95be1e1..068c8e0 100644
--- a/requirements/dev.txt
+++ b/requirements/dev.txt
@@ -5,4 +5,4 @@ pep8
 pytest>=2.2
 pytest-cov
 pytest-xdist
-Sphinx>=1.2.0
+Sphinx>=1.2.2
diff --git a/requirements/recommended.txt b/requirements/recommended.txt
index a78adcd..6170204 100644
--- a/requirements/recommended.txt
+++ b/requirements/recommended.txt
@@ -3,7 +3,7 @@
 ###############
 
 # lxml - for XML processing (XLIFF, TMX, TBX, Android)
-lxml>=2.2.0
+lxml>=2.3.6
 
 # Faster matching in e.g. pot2po
 # 0.11.0 is broken using pip, later versions are fixed
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 861a9f5..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-[egg_info]
-tag_build = 
-tag_date = 0
-tag_svn_revision = 0
-
diff --git a/setup.py b/setup.py
index d837162..21bdd0c 100755
--- a/setup.py
+++ b/setup.py
@@ -77,6 +77,7 @@ translatescripts = [join(*('translate', ) + script) for script in [
                   ('convert', 'tiki2po'), ('convert', 'po2tiki'),
                   ('convert', 'php2po'), ('convert', 'po2php'),
                   ('convert', 'rc2po'), ('convert', 'po2rc'),
+                  ('convert', 'resx2po'), ('convert', 'po2resx'),
                   ('convert', 'xliff2po'), ('convert', 'po2xliff'),
                   ('convert', 'sub2po'), ('convert', 'po2sub'),
                   ('convert', 'symb2po'), ('convert', 'po2symb'),
@@ -379,7 +380,9 @@ def getdatafiles():
     for subdir in ['docs', 'share']:
         docwalk = os.walk(subdir)
         for docs in docwalk:
-            docfiles.append(listfiles(docs[0]))
+            files = listfiles(docs[0])
+            if files[1]:
+                docfiles.append(files)
         datafiles += docfiles
     return datafiles
 
@@ -399,6 +402,9 @@ def buildmanifest_in(f, scripts):
     f.write("# include our documentation\n")
     f.write("graft docs\n")
     f.write("prune docs/doctrees\n")
+    f.write("graft tests\n")
+    f.write("global-exclude .coverage*\n")
+    f.write("global-exclude *~\n")
     f.write("graft share\n")
     f.write("# MANIFEST.in: end of autogenerated block")
 
diff --git a/tests/cli/data/test_po2prop_mozilla_files/out.properties b/tests/cli/data/test_po2prop_mozilla_files/out.properties
new file mode 100644
index 0000000..e35e75a
--- /dev/null
+++ b/tests/cli/data/test_po2prop_mozilla_files/out.properties
@@ -0,0 +1,4 @@
+buddy.authRequest.allow.label=Baimendu
+buddy.authRequest.allow.accesskey=B
+buddy.authRequest.deny.label=Ukatu
+buddy.authRequest.deny.accesskey=U
diff --git a/tests/cli/data/test_po2prop_mozilla_files/template.properties b/tests/cli/data/test_po2prop_mozilla_files/template.properties
new file mode 100644
index 0000000..588ed42
--- /dev/null
+++ b/tests/cli/data/test_po2prop_mozilla_files/template.properties
@@ -0,0 +1,4 @@
+buddy.authRequest.allow.label=Allow
+buddy.authRequest.allow.accesskey=A
+buddy.authRequest.deny.label=Deny
+buddy.authRequest.deny.accesskey=D
diff --git a/tests/cli/data/test_po2prop_mozilla_files/translations.po b/tests/cli/data/test_po2prop_mozilla_files/translations.po
new file mode 100644
index 0000000..0eaeff1
--- /dev/null
+++ b/tests/cli/data/test_po2prop_mozilla_files/translations.po
@@ -0,0 +1,8 @@
+#: buddy.authRequest.allow.label buddy.authRequest.allow.accesskey
+msgid "&Allow"
+msgstr "&Baimendu"
+
+#: buddy.authRequest.deny.label buddy.authRequest.deny.accesskey
+msgid "&Deny"
+msgstr "&Ukatu"
+
diff --git a/tests/cli/data/test_pocount_po_file/one.po b/tests/cli/data/test_pocount_po_file/one.po
new file mode 100644
index 0000000..958a4ab
--- /dev/null
+++ b/tests/cli/data/test_pocount_po_file/one.po
@@ -0,0 +1,2 @@
+msgid "We can count"
+msgstr "Ons kan tell"
diff --git a/tests/cli/data/test_pofilter_listfilters/stdout.txt b/tests/cli/data/test_pofilter_listfilters/stdout.txt
index 03f5418..620f758 100644
--- a/tests/cli/data/test_pofilter_listfilters/stdout.txt
+++ b/tests/cli/data/test_pofilter_listfilters/stdout.txt
@@ -1,16 +1,11 @@
-accelerators	Checks whether accelerators are consistent between the
-        two strings.
-        
+accelerators	Checks whether accelerators are consistent between the two strings.
 acronyms	Checks that acronyms that appear are unchanged.
-blank	Checks whether a translation only contains spaces.
+blank	Checks whether a translation is totally blank.
 brackets	Checks that the number of brackets in both strings match.
 compendiumconflicts	Checks for Gettext compendium conflicts (#-#-#-#-#).
 credits	Checks for messages containing translation credits instead of
         normal translations.
-        
-doublequoting	Checks whether doublequoting is consistent between the
-        two strings.
-        
+doublequoting	Checks whether doublequoting is consistent between the two strings.
 doublespacing	Checks for bad double-spaces by comparing to original.
 doublewords	Checks for repeated words in the translation.
 emails	Checks that emails are not translated.
@@ -19,55 +14,43 @@ endwhitespace	Checks whether whitespace at the end of the strings matches.
 escapes	Checks whether escaping is consistent between the two strings.
 filepaths	Checks that file paths have not been translated.
 functions	Checks that function names are not translated.
-hassuggestion	Checks if there is at least one suggested translation for this
-        unit.
-        
+hassuggestion	Checks if there is at least one suggested translation for this unit.
 isfuzzy	Check if the unit has been marked fuzzy.
 isreview	Check if the unit has been marked review.
 kdecomments	Checks to ensure that no KDE style comments appear in the
         translation.
-        
 long	Checks whether a translation is much longer than the original
         string.
-        
 musttranslatewords	Checks that words configured as definitely translatable don't appear
         in the translation.
 newlines	Checks whether newlines are consistent between the two strings.
 notranslatewords	Checks that words configured as untranslatable appear in the
         translation too.
-nplurals	Checks for the correct number of noun forms for plural
-        translations.
-        
+nplurals	Checks for the correct number of noun forms for plural translations.
 numbers	Checks whether numbers of various forms are consistent between the
         two strings.
-        
-options	Checks that options are not translated.
+options	Checks that command line options are not translated.
 printf	Checks whether printf format strings match.
 puncspacing	Checks for bad spacing after punctuation.
 purepunc	Checks that strings that are purely punctuation are not changed.
+pythonbraceformat	Checks whether python brace format strings match.
 sentencecount	Checks that the number of sentences in both strings match.
 short	Checks whether a translation is much shorter than the original
         string.
-        
 simplecaps	Checks the capitalisation of two strings isn't wildly different.
 simpleplurals	Checks for English style plural(s) for you to review.
 singlequoting	Checks whether singlequoting is consistent between the two strings.
 spellcheck	Checks words that don't pass a spell check.
 startcaps	Checks that the message starts with the correct capitalisation.
 startpunc	Checks whether punctuation at the beginning of the strings match.
-startwhitespace	Checks whether whitespace at the beginning of the strings
-        matches.
-        
+startwhitespace	Checks whether whitespace at the beginning of the strings matches.
 tabs	Checks whether tabs are consistent between the two strings.
 unchanged	Checks whether a translation is basically identical to the original
         string.
-        
 untranslated	Checks whether a string has been translated at all.
 urls	Checks that URLs are not translated.
 validchars	Checks that only characters specified as valid appear in the
         translation.
-        
 variables	Checks whether variables of various forms are consistent between the
         two strings.
-        
 xmltags	Checks that XML/HTML tags have not been translated.
diff --git a/tests/cli/data/test_pofilter_manpage/stdout.txt b/tests/cli/data/test_pofilter_manpage/stdout.txt
index 34a06b4..c6b8f1b 100644
--- a/tests/cli/data/test_pofilter_manpage/stdout.txt
+++ b/tests/cli/data/test_pofilter_manpage/stdout.txt
@@ -1,5 +1,5 @@
 .\" Autogenerated manpage
-.TH pofilter 1 "Translate Toolkit 1.12.0" "" "Translate Toolkit 1.12.0"
+.TH pofilter 1 "Translate Toolkit 1.13.0-rc1" "" "Translate Toolkit 1.13.0-rc1"
 .SH NAME
 pofilter \- Perform quality checks on Gettext PO, XLIFF and TMX localization files.
 .SH SYNOPSIS
diff --git a/tests/cli/data/test_poswap_comments/af.po b/tests/cli/data/test_poswap_comments/af.po
new file mode 100644
index 0000000..040adf2
--- /dev/null
+++ b/tests/cli/data/test_poswap_comments/af.po
@@ -0,0 +1,11 @@
+#: location.cpp
+msgid "One"
+msgstr "Een"
+
+#. Developer
+msgid "Two"
+msgstr "Twee"
+
+# Translator Afrikaans
+msgid "Three"
+msgstr "Drie"
diff --git a/tests/cli/data/test_poswap_comments/fr.po b/tests/cli/data/test_poswap_comments/fr.po
new file mode 100644
index 0000000..310d9b1
--- /dev/null
+++ b/tests/cli/data/test_poswap_comments/fr.po
@@ -0,0 +1,11 @@
+#: location.cpp
+msgid "One"
+msgstr "Un"
+
+#. Developer
+msgid "Two"
+msgstr "Duex"
+
+# Translator French
+msgid "Three"
+msgstr "Trois"
diff --git a/tests/cli/data/test_poswap_comments/out.po b/tests/cli/data/test_poswap_comments/out.po
new file mode 100644
index 0000000..fb58454
--- /dev/null
+++ b/tests/cli/data/test_poswap_comments/out.po
@@ -0,0 +1,11 @@
+#: location.cpp
+msgid "Un"
+msgstr "Een"
+
+#. Developer
+msgid "Duex"
+msgstr "Twee"
+
+# Translator Afrikaans
+msgid "Trois"
+msgstr "Drie"
diff --git a/tests/cli/data/test_poswap_fr_af/af.po b/tests/cli/data/test_poswap_fr_af/af.po
new file mode 100644
index 0000000..9a38049
--- /dev/null
+++ b/tests/cli/data/test_poswap_fr_af/af.po
@@ -0,0 +1,9 @@
+msgid "One"
+msgstr "Een"
+
+#, fuzzy
+msgid "Two"
+msgstr "Twee"
+
+msgid "Three"
+msgstr ""
diff --git a/tests/cli/data/test_poswap_fr_af/fr.po b/tests/cli/data/test_poswap_fr_af/fr.po
new file mode 100644
index 0000000..cffbc65
--- /dev/null
+++ b/tests/cli/data/test_poswap_fr_af/fr.po
@@ -0,0 +1,8 @@
+msgid "One"
+msgstr "Un"
+
+msgid "Two"
+msgstr "Duex"
+
+msgid "Three"
+msgstr "Trois"
diff --git a/tests/cli/data/test_poswap_fr_af/out.po b/tests/cli/data/test_poswap_fr_af/out.po
new file mode 100644
index 0000000..9599bf2
--- /dev/null
+++ b/tests/cli/data/test_poswap_fr_af/out.po
@@ -0,0 +1,9 @@
+msgid "Un"
+msgstr "Een"
+
+#, fuzzy
+msgid "Duex"
+msgstr "Twee"
+
+msgid "Trois"
+msgstr ""
diff --git a/tests/cli/data/test_poswap_fr_af_reverse/fr.po b/tests/cli/data/test_poswap_fr_af_reverse/fr.po
new file mode 100644
index 0000000..cffbc65
--- /dev/null
+++ b/tests/cli/data/test_poswap_fr_af_reverse/fr.po
@@ -0,0 +1,8 @@
+msgid "One"
+msgstr "Un"
+
+msgid "Two"
+msgstr "Duex"
+
+msgid "Three"
+msgstr "Trois"
diff --git a/tests/cli/data/test_poswap_fr_af_reverse/fr_af.po b/tests/cli/data/test_poswap_fr_af_reverse/fr_af.po
new file mode 100644
index 0000000..3f59eb0
--- /dev/null
+++ b/tests/cli/data/test_poswap_fr_af_reverse/fr_af.po
@@ -0,0 +1,8 @@
+msgid "Un"
+msgstr "Een"
+
+msgid "Duex"
+msgstr "Twee"
+
+msgid "Trois"
+msgstr "Drie"
diff --git a/tests/cli/data/test_poswap_fr_af_reverse/out.po b/tests/cli/data/test_poswap_fr_af_reverse/out.po
new file mode 100644
index 0000000..77ad8ce
--- /dev/null
+++ b/tests/cli/data/test_poswap_fr_af_reverse/out.po
@@ -0,0 +1,8 @@
+msgid "One"
+msgstr "Een"
+
+msgid "Two"
+msgstr "Twee"
+
+msgid "Three"
+msgstr "Drie"
diff --git a/tests/cli/data/test_poswap_missing_units/af.po b/tests/cli/data/test_poswap_missing_units/af.po
new file mode 100644
index 0000000..5e7082f
--- /dev/null
+++ b/tests/cli/data/test_poswap_missing_units/af.po
@@ -0,0 +1,5 @@
+msgid "One"
+msgstr "Een"
+
+msgid "Two"
+msgstr "Twee"
diff --git a/tests/cli/data/test_poswap_missing_units/fr.po b/tests/cli/data/test_poswap_missing_units/fr.po
new file mode 100644
index 0000000..a85bb29
--- /dev/null
+++ b/tests/cli/data/test_poswap_missing_units/fr.po
@@ -0,0 +1,5 @@
+msgid "One"
+msgstr "Un"
+
+msgid "Three"
+msgstr "Trois"
diff --git a/tests/cli/data/test_poswap_missing_units/out.po b/tests/cli/data/test_poswap_missing_units/out.po
new file mode 100644
index 0000000..e820671
--- /dev/null
+++ b/tests/cli/data/test_poswap_missing_units/out.po
@@ -0,0 +1,5 @@
+msgid "Un"
+msgstr "Een"
+
+msgid "Trois"
+msgstr ""
diff --git a/tests/cli/data/test_prop2po_dirs/one/a.properties b/tests/cli/data/test_prop2po_dirs/one/a.properties
new file mode 100644
index 0000000..7b89edb
--- /dev/null
+++ b/tests/cli/data/test_prop2po_dirs/one/a.properties
@@ -0,0 +1 @@
+key=value
diff --git a/tests/cli/data/test_prop2po_dirs/out/a.po b/tests/cli/data/test_prop2po_dirs/out/a.po
new file mode 100644
index 0000000..8c3b33f
--- /dev/null
+++ b/tests/cli/data/test_prop2po_dirs/out/a.po
@@ -0,0 +1,17 @@
+#. extracted from ./data/test_prop2po_dirs-one/a.properties
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2014-03-07 20:15+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
+"Language-Team: LANGUAGE <LL at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.11.0\n"
+
+#: key
+msgid "value"
+msgstr ""
diff --git a/tests/cli/data/test_prop2po_files/one.properties b/tests/cli/data/test_prop2po_files/one.properties
new file mode 100644
index 0000000..7b89edb
--- /dev/null
+++ b/tests/cli/data/test_prop2po_files/one.properties
@@ -0,0 +1 @@
+key=value
diff --git a/tests/cli/data/test_prop2po_files/out.po b/tests/cli/data/test_prop2po_files/out.po
new file mode 100644
index 0000000..7f79e49
--- /dev/null
+++ b/tests/cli/data/test_prop2po_files/out.po
@@ -0,0 +1,18 @@
+#. extracted from ./data/test_prop2po_files/one.properties
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2014-03-07 19:45+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
+"Language-Team: LANGUAGE <LL at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.11.0\n"
+
+#: key
+msgid "value"
+msgstr ""
diff --git a/tests/cli/data/test_prop2po_files_templates/one.properties b/tests/cli/data/test_prop2po_files_templates/one.properties
new file mode 100644
index 0000000..7b89edb
--- /dev/null
+++ b/tests/cli/data/test_prop2po_files_templates/one.properties
@@ -0,0 +1 @@
+key=value
diff --git a/tests/cli/data/test_prop2po_files_templates/out.po b/tests/cli/data/test_prop2po_files_templates/out.po
new file mode 100644
index 0000000..2976f32
--- /dev/null
+++ b/tests/cli/data/test_prop2po_files_templates/out.po
@@ -0,0 +1,18 @@
+#. extracted from ./data/test_prop2po_files_templates/one.properties, ./data/test_prop2po_files_templates/two.properties
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2014-03-09 21:05+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
+"Language-Team: LANGUAGE <LL at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.11.0\n"
+
+#: key
+msgid "value"
+msgstr "waarde"
diff --git a/tests/cli/data/test_prop2po_files_templates/two.properties b/tests/cli/data/test_prop2po_files_templates/two.properties
new file mode 100644
index 0000000..7dbc1ef
--- /dev/null
+++ b/tests/cli/data/test_prop2po_files_templates/two.properties
@@ -0,0 +1 @@
+key=waarde
diff --git a/tests/cli/data/test_rc2po/one.rc b/tests/cli/data/test_rc2po/one.rc
new file mode 100644
index 0000000..5d73d0b
--- /dev/null
+++ b/tests/cli/data/test_rc2po/one.rc
@@ -0,0 +1,119 @@
+
+/*
+ * Mini test file.
+ * Multiline comments.
+ */
+
+// Test file, one line comment. //
+
+#include "other_file.h" // This must be ignored
+
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+    "#define _AFX_NO_OLE_RESOURCES\r\n"
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+    "\r\n"
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESN)\r\n"
+    "LANGUAGE 10, 3\r\n"  // This language must be ignored, is a string.
+    "#pragma code_page(1252)\r\n"
+    "#include ""res\\regGHC.rc2""
+    "#include ""afxres.rc""
+    "#endif\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME           ICON                    "res\\ico00007.ico"
+IDR_MAINFRAME1          ICON                    "res\\idr_main.ico"
+IDR_MAINFRAME2          ICON                    "res\\ico00006.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_REGGHC_DIALOG DIALOGEX 0, 0, 211, 191
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "License dialog"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+    PUSHBUTTON      "Help",ID_HELP,99,162,48,15
+    PUSHBUTTON      "Close",IDCANCEL,151,162,48,15
+    PUSHBUTTON      "Activate instalation",IDC_BUTTON1,74,76,76,18
+    CTEXT           "My very good program",IDC_STATIC1,56,21,109,19,SS_SUNKEN
+    CTEXT           "You can use it without registering it",IDC_STATIC,35,131,128,19,SS_SUNKEN
+    PUSHBUTTON      "Offline",IDC_OFFLINE,149,108,42,13
+    PUSHBUTTON      "See license",IDC_LICENCIA,10,162,85,15
+    RTEXT           "If you don't have internet, please use magic.",IDC_STATIC,23,105,120,18
+    ICON            IDR_MAINFRAME,IDC_STATIC,44,74,20,20
+    CTEXT           "Use your finger to activate the program.",IDC_ACTIVADA,17,50,175,17
+    ICON            IDR_MAINFRAME1,IDC_STATIC6,18,19,20,20
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+    IDP_REGISTRONOV         "Data isn't valid"
+    IDS_ACTIVARINSTALACION  "You need to try again and again."
+    IDS_NOREGISTRADO        "Error when making something important"
+    IDS_REGISTRADO          "All done correctly.\nThank you very much."
+    IDS_ACTIVADA            "This is what you do:\n%s"
+    IDS_ERRORACTIV          "Error doing things"
+END
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESN)
+// This will change the default language
+LANGUAGE 10, 3
+#pragma code_page(1252)
+#include "res\regGHC.rc2"  // Recursos editados que no son de Microsoft Visual C++
+#include "afxres.rc"         // Standar components
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
diff --git a/tests/cli/data/test_rc2po/out.po b/tests/cli/data/test_rc2po/out.po
new file mode 100644
index 0000000..bc3b8f1
--- /dev/null
+++ b/tests/cli/data/test_rc2po/out.po
@@ -0,0 +1,83 @@
+#. extracted from ./data/test_rc2po/one.rc
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2014-08-01 12:00+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
+"Language-Team: LANGUAGE <LL at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Translate Toolkit 1.12.0\n"
+"X-Accelerator-Marker: &\n"
+"X-Merge-On: location\n"
+
+#: DIALOGEX.IDD_REGGHC_DIALOG.CAPTION
+msgid "License dialog"
+msgstr ""
+
+#: DIALOGEX.IDD_REGGHC_DIALOG.PUSHBUTTON.ID_HELP
+msgid "Help"
+msgstr ""
+
+#: DIALOGEX.IDD_REGGHC_DIALOG.PUSHBUTTON.IDCANCEL
+msgid "Close"
+msgstr ""
+
+#: DIALOGEX.IDD_REGGHC_DIALOG.PUSHBUTTON.IDC_BUTTON1
+msgid "Activate instalation"
+msgstr ""
+
+#: DIALOGEX.IDD_REGGHC_DIALOG.CTEXT.IDC_STATIC1
+msgid "My very good program"
+msgstr ""
+
+#: DIALOGEX.IDD_REGGHC_DIALOG.CTEXT.IDC_STATIC
+msgid "You can use it without registering it"
+msgstr ""
+
+#: DIALOGEX.IDD_REGGHC_DIALOG.PUSHBUTTON.IDC_OFFLINE
+msgid "Offline"
+msgstr ""
+
+#: DIALOGEX.IDD_REGGHC_DIALOG.PUSHBUTTON.IDC_LICENCIA
+msgid "See license"
+msgstr ""
+
+#: DIALOGEX.IDD_REGGHC_DIALOG.RTEXT.IDC_STATIC
+msgid "If you don't have internet, please use magic."
+msgstr ""
+
+#: DIALOGEX.IDD_REGGHC_DIALOG.CTEXT.IDC_ACTIVADA
+msgid "Use your finger to activate the program."
+msgstr ""
+
+#: STRINGTABLE.IDP_REGISTRONOV
+msgid "Data isn't valid"
+msgstr ""
+
+#: STRINGTABLE.IDS_ACTIVARINSTALACION
+msgid "You need to try again and again."
+msgstr ""
+
+#: STRINGTABLE.IDS_NOREGISTRADO
+msgid "Error when making something important"
+msgstr ""
+
+#: STRINGTABLE.IDS_REGISTRADO
+msgid ""
+"All done correctly.\n"
+"Thank you very much."
+msgstr ""
+
+#: STRINGTABLE.IDS_ACTIVADA
+msgid ""
+"This is what you do:\n"
+"%s"
+msgstr ""
+
+#: STRINGTABLE.IDS_ERRORACTIV
+msgid "Error doing things"
+msgstr ""
diff --git a/tests/cli/example_test.sh b/tests/cli/example_test.sh
new file mode 100644
index 0000000..f1da3e1
--- /dev/null
+++ b/tests/cli/example_test.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Import the test framework
+source $(basename $0)/test.inc.sh
+
+# You can put any extra preperation here
+
+# Your actual command line to test No need for redirecting to /dev/stdout as
+# the test framework will do that automatically
+myprogram $one $two -o $out
+
+# Check that the results of the test match your reference resulst
+check_results  # does start_check and diff_all
+
+# OR do the following
+# start_checks - begin checking
+# has_stdout|has_stderr|has $file - checks that the file exists we don't care for content
+# startswith $file|startswith_stderr|startswith_stdout - the output starts with some expression
+# startswithi $file|startswithi_stderr|startswithi_stdout - case insensitive startswith
+# end_checks
diff --git a/tests/cli/run_tests.sh b/tests/cli/run_tests.sh
new file mode 100755
index 0000000..9929935
--- /dev/null
+++ b/tests/cli/run_tests.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+cd $(dirname $0)
+for test in $(ls test_*.sh) 
+do
+	echo -n "$test ... "
+	eval ./$test
+	result=$?
+	if [ $result -ne 0 ]; then
+		echo "FAIL"
+	else
+		echo "pass"
+	fi
+	failure=$(($failure + $result))
+done
+exit $failure
diff --git a/tests/cli/test.inc.sh b/tests/cli/test.inc.sh
new file mode 100644
index 0000000..caacaae
--- /dev/null
+++ b/tests/cli/test.inc.sh
@@ -0,0 +1,275 @@
+#!/bin/bash
+
+# Config
+basedir=$(dirname $0)
+data=data
+results=results
+base_data_dir=$basedir/$data
+base_results_dir=$basedir/$results
+
+
+# Automatic variable setup
+test_name=$(basename $0 .sh)
+datadir=$base_data_dir/$test_name
+resultsdir=$base_results_dir/$test_name
+
+function _make_file {
+	base=$1
+	name=$2
+	ext=${3:-"txt"}
+	echo ${base}/${name}.${ext}
+}
+
+function make_result_file {
+	_make_file $resultsdir $1 $2
+}
+
+function make_data_file {
+	_make_file $datadir $1 $2
+}
+
+function _make_dir {
+	base=$1
+	name=$2
+	echo ${base}/${name}
+}
+
+function make_result_dir {
+	_make_dir $resultdir $1
+}
+
+function make_data_dir {
+	_make_dir $datadir $1
+}
+
+# Create automatic variables
+# Find files in $datadir that match the test name
+# Create a variable name after $test/$var.ext
+# For results files e.g. stdout, stderr and out we create those in the $results
+# dir and create a $var_expected for the $data dir
+# So you can diff $out $out_expected etc
+for file in $(ls ${datadir}/*)
+do
+	[[ -f $file ]] && var=$(basename $file | sed "s/\([^.]*\)[.][^.]*$/\1/")
+	[[ -d $file ]] && var=$file
+	if [[ ("$var" == "out") || ("$var" == "stdout") || ("$var" == "stderr") ]]; then
+		eval ${var}_expected=$file
+		file=$(echo $file | sed "s/$data/$results/")
+	fi
+	eval $var=$file
+done
+if [[ ! "$out" ]]; then
+	out=$(make_result_file out)
+	out_expected=/dev/null
+fi
+if [[ ! "$stdout" ]]; then
+	stdout=$(make_result_file stdout)
+	stdout_expected=/dev/null
+fi
+if [[ ! "$stderr" ]]; then
+	stderr=$(make_result_file stderr)
+	stderr_expected=/dev/null
+fi
+
+
+# Redirecting stdout and stderr
+
+function redirect {
+	exec 5>&1
+	exec 6>&2
+	exec 1>$stdout
+	exec 2>$stderr
+}
+
+function unredirect {
+	exec 1>&5 5>&-
+	exec 2>&6 6>&-
+}
+
+function redirect_for_prep {
+	stdout=$(echo $stdout | sed "s/$results/$data/")
+	stderr=$(echo $stderr | sed "s/$results/$data/")
+}
+
+
+# Commands
+
+function tdiff {
+	# Special test diff that will do special adaptations depending on what
+	# format it is diffing and that will recurse when dealing with
+	# directories
+	options="-u -N"
+	[[ -d $1 ]] && options="$options -r"
+	[[ "$*" ]] && diff $options --ignore-matching-lines='^"POT-Creation'  --ignore-matching-lines='^"X-Generator' $*
+}
+
+# Handle failures
+
+function FAIL {
+	failures=$(($failures + 1))
+}
+
+# Check resuls of the tests
+function start_checks {
+	unredirect
+}
+
+function end_checks {
+	exit $failures
+}
+
+function check_results {
+	unredirect
+	if [[ ! "$prepmode" ]]; then
+		tdiff $out_expected $out || FAIL && rm -rf $out
+		tdiff $stdout_expected $stdout || FAIL && rm -rf $stdout
+		tdiff $stderr_expected $stderr || FAIL && rm -rf $stderr
+	fi
+	if [[ "$prepmode" ]]; then
+		[[ ! -s "$stdout" ]] && rm $stdout
+		[[ ! -s "$stderr" ]] && rm $stderr
+	fi
+	end_checks
+}
+
+function has {
+	file=$1
+	[[ -f $1 ]] || FAIL
+}
+
+function has_stdout {
+	has $stdout
+}
+
+function has_stderr {
+	has $stderr
+}
+
+function startswith {
+	file=$1
+	search_string=$2
+	(head -1 $file | egrep -q "^$search_string") || FAIL
+}
+
+function startswithi {
+	file=$1
+	search_string=$2
+	head -1 $file | egrep -q -i "^$search_string" || FAIL
+}
+
+function startswith_stdout {
+	startswith $stdout $1
+}
+
+function startswith_stderr {
+	startswith $stderr $1
+}
+
+function startswithi_stdout {
+	startswithi $stdout $1
+}
+
+function startswithi_stderr {
+	startswithi $stderr $1
+}
+
+function contains {
+	file=$1
+	search_string=$2
+	egrep -q "$search_string" || FAIL
+}
+
+function contains_stdout {
+	contains $stdout $1
+}
+
+function contains_stderr {
+	contains $stderr $1
+}
+
+function containsi {
+	file=$1
+	search_string=$2
+	egrep -q -i "$search_string" || FAIL
+}
+
+function containsi_stdout {
+	containsi $stdout $1
+}
+
+function contains_stderr {
+	containsi $stderr $1
+}
+
+function endswith {
+	file=$1
+	search_string=$2
+	(tail -1 $file | egrep -q "$search_string$") || FAIL
+}
+
+function endswithi {
+	file=$1
+	search_string=$2
+	tail -1 $file | egrep -q -i "$search_string$" || FAIL
+}
+
+function endswith_stdout {
+	endswith $stdout $1
+}
+
+function endswith_stderr {
+	endswith $stderr $1
+}
+
+function endswithi_stdout {
+	endswithi $stdout $1
+}
+
+function endswithi_stderr {
+	endswithi $stderr $1
+}
+
+# Options
+
+function usage {
+	echo
+	echo "Usage: $(basename $0)"
+	echo 
+	echo "With no options the test will run and show diffs for any failures"
+	echo "--help - show this help"
+	echo "--prep - prepare files, i.e. don't check but intialise output files"
+	echo
+	exit 0
+}
+
+function check_options {
+	for option in $*
+	do
+		case $option in
+			--help)
+				usage
+				;;
+			--prep)
+				prepmode="yes"
+				redirect_for_prep
+				shift
+				;;
+			*)
+				break
+				;;
+		esac
+	done
+}
+
+#####################
+# Execution
+####################
+
+check_options $*
+
+# Initial setup
+mkdir -p $resultsdir
+
+# Need to do this on source'ing this file so that tests redirect correcly but
+# after all the data is setup
+redirect
diff --git a/tests/cli/test_po2prop_mozilla_files.sh b/tests/cli/test_po2prop_mozilla_files.sh
new file mode 100755
index 0000000..fbc702e
--- /dev/null
+++ b/tests/cli/test_po2prop_mozilla_files.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+po2prop --personality=mozilla --progress=none -t $template $translations $out
+check_results
diff --git a/tests/cli/test_pocount.sh b/tests/cli/test_pocount.sh
new file mode 100755
index 0000000..1133dfa
--- /dev/null
+++ b/tests/cli/test_pocount.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+pocount
+start_checks
+startswithi_stderr "Usage"
+end_checks
diff --git a/tests/cli/test_pocount_help.sh b/tests/cli/test_pocount_help.sh
new file mode 100755
index 0000000..6bbdab2
--- /dev/null
+++ b/tests/cli/test_pocount_help.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+pocount -h
+start_checks
+has_stdout
+end_checks
diff --git a/tests/cli/test_pocount_mutually_exclusive.sh b/tests/cli/test_pocount_mutually_exclusive.sh
new file mode 100755
index 0000000..69efd67
--- /dev/null
+++ b/tests/cli/test_pocount_mutually_exclusive.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+pocount --short --csv .
+check_results
diff --git a/tests/cli/test_pocount_nonexistant.sh b/tests/cli/test_pocount_nonexistant.sh
new file mode 100755
index 0000000..b2e5b45
--- /dev/null
+++ b/tests/cli/test_pocount_nonexistant.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+pocount missing.po
+check_results
diff --git a/tests/cli/test_pocount_po_file.sh b/tests/cli/test_pocount_po_file.sh
new file mode 100755
index 0000000..af139f8
--- /dev/null
+++ b/tests/cli/test_pocount_po_file.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+pocount $one
+check_results
diff --git a/tests/cli/test_pofilter_listfilters.sh b/tests/cli/test_pofilter_listfilters.sh
new file mode 100755
index 0000000..88894c0
--- /dev/null
+++ b/tests/cli/test_pofilter_listfilters.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+pofilter --listfilters
+check_results
diff --git a/tests/cli/test_pofilter_manpage.sh b/tests/cli/test_pofilter_manpage.sh
new file mode 100755
index 0000000..1bac057
--- /dev/null
+++ b/tests/cli/test_pofilter_manpage.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+pofilter --manpage
+check_results
diff --git a/tests/cli/test_poswap_comments.sh b/tests/cli/test_poswap_comments.sh
new file mode 100755
index 0000000..427cd7e
--- /dev/null
+++ b/tests/cli/test_poswap_comments.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+# out == fr-af.po
+poswap --progress=none -t $af $fr $out
+check_results
diff --git a/tests/cli/test_poswap_fr_af.sh b/tests/cli/test_poswap_fr_af.sh
new file mode 100755
index 0000000..427cd7e
--- /dev/null
+++ b/tests/cli/test_poswap_fr_af.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+# out == fr-af.po
+poswap --progress=none -t $af $fr $out
+check_results
diff --git a/tests/cli/test_poswap_fr_af_reverse.sh b/tests/cli/test_poswap_fr_af_reverse.sh
new file mode 100755
index 0000000..0d9e90e
--- /dev/null
+++ b/tests/cli/test_poswap_fr_af_reverse.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+# out == en-af.po
+poswap --progress=none --reverse -t $fr_af $fr $out
+check_results
diff --git a/tests/cli/test_poswap_missing_units.sh b/tests/cli/test_poswap_missing_units.sh
new file mode 100755
index 0000000..427cd7e
--- /dev/null
+++ b/tests/cli/test_poswap_missing_units.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+# out == fr-af.po
+poswap --progress=none -t $af $fr $out
+check_results
diff --git a/tests/cli/test_prop2po.sh b/tests/cli/test_prop2po.sh
new file mode 100755
index 0000000..61f8200
--- /dev/null
+++ b/tests/cli/test_prop2po.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+prop2po
+check_results
diff --git a/tests/cli/test_prop2po_dirs.sh b/tests/cli/test_prop2po_dirs.sh
new file mode 100755
index 0000000..e9005f9
--- /dev/null
+++ b/tests/cli/test_prop2po_dirs.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+prop2po $one $out
+check_results
diff --git a/tests/cli/test_prop2po_files.sh b/tests/cli/test_prop2po_files.sh
new file mode 100755
index 0000000..7d8df13
--- /dev/null
+++ b/tests/cli/test_prop2po_files.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+prop2po --progress=none $one $out
+check_results
diff --git a/tests/cli/test_prop2po_files_templates.sh b/tests/cli/test_prop2po_files_templates.sh
new file mode 100755
index 0000000..c962975
--- /dev/null
+++ b/tests/cli/test_prop2po_files_templates.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+prop2po --progress=none -t $one $two $out
+check_results
diff --git a/tests/cli/test_rc2po.sh b/tests/cli/test_rc2po.sh
new file mode 100755
index 0000000..3ffd203
--- /dev/null
+++ b/tests/cli/test_rc2po.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source $(dirname $0)/test.inc.sh
+
+rc2po --progress=none -i $one -o $out
+check_results
diff --git a/tests/odf_xliff/test_2-test_odf2xliff-reference.xlf b/tests/odf_xliff/test_2-test_odf2xliff-reference.xlf
new file mode 100644
index 0000000..a1d69e9
--- /dev/null
+++ b/tests/odf_xliff/test_2-test_odf2xliff-reference.xlf
@@ -0,0 +1,37 @@
+<?xml version='1.0' encoding='utf-8'?>
+<xliff xmlns="urn:oasis:names:tc:xliff:document:1.1" version="1.1">
+  <file original="test_2.odt" source-language="en" datatype="plaintext">
+    <body>
+      <trans-unit xml:space="preserve" id="office:document-content[0]/office:body[0]/office:text[0]/text:p[0]">
+        <source>This <g id="0">is a</g> test<x id="1" xid="office:document-content[0]/office:body[0]/office:text[0]/text:p[0]/text:note[0]"/>, hooray.</source>
+      </trans-unit>
+      <trans-unit xml:space="preserve" id="office:document-content[0]/office:body[0]/office:text[0]/text:p[0]/text:note[0]/text:note-citation[0]">
+        <source>1</source>
+      </trans-unit>
+      <trans-unit xml:space="preserve" id="office:document-content[0]/office:body[0]/office:text[0]/text:p[0]/text:note[0]/text:note-body[0]/text:p[0]">
+        <source>A test is a thing which is, well, you know, a test!</source>
+      </trans-unit>
+      <trans-unit xml:space="preserve" id="office:document-content[0]/office:body[0]/office:text[0]/text:p[0]/text:note[0]/text:note-body[0]/text:p[1]">
+        <source>And blah, <x id="2" xid="office:document-content[0]/office:body[0]/office:text[0]/text:p[0]/text:note[0]/text:note-body[0]/text:p[1]/draw:frame[0]"/>, blah, blah.</source>
+      </trans-unit>
+      <trans-unit xml:space="preserve" id="office:document-content[0]/office:body[0]/office:text[0]/table:table[0]/table:table-row[0]/table:table-cell[0]/text:p[0]">
+        <source><g id="3">This </g><g id="4">is</g><g id="5"> a</g> cell<x id="6" xid="office:document-content[0]/office:body[0]/office:text[0]/table:table[0]/table:table-row[0]/table:table-cell[0]/text:p[0]/text:note[0]"/>.</source>
+      </trans-unit>
+      <trans-unit xml:space="preserve" id="office:document-content[0]/office:body[0]/office:text[0]/table:table[0]/table:table-row[0]/table:table-cell[0]/text:p[0]/text:note[0]/text:note-citation[0]">
+        <source>2</source>
+      </trans-unit>
+      <trans-unit xml:space="preserve" id="office:document-content[0]/office:body[0]/office:text[0]/table:table[0]/table:table-row[0]/table:table-cell[0]/text:p[0]/text:note[0]/text:note-body[0]/text:p[0]">
+        <source>I'm sure that you know by know just how comprehensive my definition of the word “cell” will be.</source>
+      </trans-unit>
+      <trans-unit xml:space="preserve" id="office:document-content[0]/office:body[0]/office:text[0]/table:table[0]/table:table-row[0]/table:table-cell[1]/text:p[0]">
+        <source>The table </source>
+      </trans-unit>
+      <trans-unit xml:space="preserve" id="office:document-content[0]/office:body[0]/office:text[0]/table:table[0]/table:table-row[0]/table:table-cell[1]/table:table[0]/table:table-row[0]/table:table-cell[0]/text:p[0]">
+        <source>This is a small table.</source>
+      </trans-unit>
+      <trans-unit xml:space="preserve" id="office:document-content[0]/office:body[0]/office:text[0]/table:table[0]/table:table-row[0]/table:table-cell[1]/text:p[1]">
+        <source>is a rather small table.</source>
+      </trans-unit>
+    </body>
+  </file>
+</xliff>
diff --git a/tests/odf_xliff/test_2.odt b/tests/odf_xliff/test_2.odt
new file mode 100644
index 0000000..57d9274
Binary files /dev/null and b/tests/odf_xliff/test_2.odt differ
diff --git a/tests/odf_xliff/test_odf_xliff.py b/tests/odf_xliff/test_odf_xliff.py
new file mode 100644
index 0000000..c30e954
--- /dev/null
+++ b/tests/odf_xliff/test_odf_xliff.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 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 this program; if not, see <http://www.gnu.org/licenses/>.
+
+import difflib
+import os
+import os.path as path
+import sys
+import zipfile
+
+from lxml import etree
+
+# get directory of this test
+dir = os.path.dirname(os.path.abspath(__file__))
+# get top-level directory (moral equivalent of ../..)
+dir = os.path.dirname(os.path.dirname(dir))
+# load python modules from top-level
+sys.path.insert(0, dir)
+
+from translate.convert import odf2xliff, xliff2odf
+from translate.storage import factory, xliff
+
+
+def setup_module(module):
+    os.chdir(path.dirname(__file__))
+
+
+def args(src, tgt, **kwargs):
+    arg_list = []
+    arg_list.extend([u'--errorlevel=traceback', src, tgt])
+    for flag, value in kwargs.iteritems():
+        value = unicode(value)
+        if len(flag) == 1:
+            arg_list.append(u'-%s' % flag)
+        else:
+            arg_list.append(u'--%s' % flag)
+        if value is not None:
+            arg_list.append(value)
+    return arg_list
+
+
+def xliff___eq__(self, other):
+    return self.units == other.units
+
+xliff.xlifffile.__eq__ = xliff___eq__
+
+
+def print_diff(store1, store2):
+    for line in difflib.unified_diff(str(store1).split('\n'), str(store2).split('\n')):
+        print(line)
+
+SOURCE_ODF = u'test_2.odt'
+REFERENCE_XLF = u'test_2-test_odf2xliff-reference.xlf'
+GENERATED_XLF_ITOOLS = u'test_2-test_odf2xliff-itools.xlf'
+GENERATED_XLF_TOOLKIT = u'test_2-test_odf2xliff-toolkit.xlf'
+
+TARGET_XLF = u'test_2-test_roundtrip.xlf'
+REFERENCE_ODF = u'test_2.odt'
+GENERATED_ODF = u'test_2-test_roundtrip-generated.odt'
+
+
+def test_odf2xliff():
+    reference_xlf = factory.getobject(REFERENCE_XLF)
+
+    odf2xliff.main(args(SOURCE_ODF, GENERATED_XLF_TOOLKIT))
+    generated_xlf_toolkit = factory.getobject(GENERATED_XLF_TOOLKIT)
+    print_diff(reference_xlf, generated_xlf_toolkit)
+    assert reference_xlf == generated_xlf_toolkit
+
+    odf2xliff.main(args(SOURCE_ODF, GENERATED_XLF_ITOOLS))
+    generated_xlf_itools = factory.getobject(GENERATED_XLF_ITOOLS)
+    print_diff(reference_xlf, generated_xlf_itools)
+    assert reference_xlf == generated_xlf_itools
+
+
+def is_content_file(filename):
+    return filename in (u'content.xml', u'meta.xml', u'styles.xml')
+
+
+class ODF(object):
+
+    def __init__(self, filename):
+        self.odf = zipfile.ZipFile(filename)
+
+    def _get_data(self, filename):
+        return self.odf.read(filename)
+
+    def _get_doc_root(self, filename):
+        return etree.tostring(etree.fromstring(self._get_data(filename)), pretty_print=True)
+
+    def __eq__(self, other):
+        if other is None:
+            return False
+        l1 = sorted(zi.filename for zi in self.odf.infolist())
+        l2 = sorted(zi.filename for zi in other.odf.infolist())
+        if l1 != l2:
+            print("File lists don't match:")
+            print(l1)
+            print(l2)
+            return False
+        for filename in l1:
+            if is_content_file(filename):
+                l = self._get_doc_root(filename)
+                r = other._get_doc_root(filename)
+                if l != r:
+                    print("difference for file named", filename)
+                    return False
+            else:
+                if self._get_data(filename) != other._get_data(filename):
+                    print("difference for file named", filename)
+                    return False
+        return True
+
+    def __str__(self):
+        return self._get_doc_root('content.xml')
+
+
+def test_roundtrip():
+
+    odf2xliff.main(args(SOURCE_ODF, TARGET_XLF))
+    xliff2odf.main(args(TARGET_XLF, GENERATED_ODF, t=SOURCE_ODF))
+
+    reference_odf = ODF(REFERENCE_ODF)
+    generated_odf = ODF(GENERATED_ODF)
+
+    print_diff(reference_odf, generated_odf)
+    assert reference_odf == generated_odf
+
+
+def remove(filename):
+    """Removes the file if it exists."""
+    if os.path.exists(filename):
+        os.unlink(filename)
+
+
+def teardown_module(module):
+    remove(GENERATED_XLF_TOOLKIT)
+    remove(GENERATED_ODF)
+    remove(GENERATED_XLF_ITOOLS)
+    remove(TARGET_XLF)
+
+
+if __name__ == '__main__':
+    setup_module(None)
+    test_roundtrip()
+    teardown_module(None)
diff --git a/tests/xliff_conformance/af-pootle.po b/tests/xliff_conformance/af-pootle.po
new file mode 100644
index 0000000..43c4c1d
--- /dev/null
+++ b/tests/xliff_conformance/af-pootle.po
@@ -0,0 +1,1511 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: translate-pootle at lists.sourceforge.net\n"
+"POT-Creation-Date: 2007-04-13 12:24+0200\n"
+"PO-Revision-Date: 2007-05-04 19:57+0200\n"
+"Last-Translator: F Wolff <friedel at translate.org.za>\n"
+"Language-Team: LANGUAGE <LL at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Pootle 1.0rc1\n"
+"Generated-By: pygettext.py 1.1\n"
+
+#. l10n: Verb
+#: projects.py:136
+msgid "View"
+msgstr "Bekyk"
+
+#: projects.py:137 translatepage.py:613
+msgid "Suggest"
+msgstr "Stel voor"
+
+#: projects.py:138
+msgid "Translate"
+msgstr "Vertaal"
+
+#. l10n: radio button text
+#: projects.py:139 indexpage.py:548
+msgid "Overwrite"
+msgstr "Oorskryf"
+
+#. l10n: Verb
+#: projects.py:141
+msgid "Review"
+msgstr "Sien na"
+
+#. l10n: Verb
+#: projects.py:143
+msgid "Archive"
+msgstr "Argiveer"
+
+#. l10n: This refers to generating the binary .mo file
+#: projects.py:145
+msgid "Compile PO files"
+msgstr "Bou PO-lêers"
+
+#: projects.py:146
+msgid "Assign"
+msgstr "Ken toe"
+
+#: projects.py:147 indexpage.py:134
+msgid "Administrate"
+msgstr "Administreer"
+
+#. l10n: Commit to version control (like CVS or Subversion)
+#: projects.py:148 indexpage.py:748
+msgid "Commit"
+msgstr "Stuur weergawe in"
+
+#. l10n: Don't translate "nobody" or "default"
+#: projects.py:228
+msgid "You cannot remove the \"nobody\" or \"default\" user"
+msgstr "U kan nie die \"nobody\"- of \"default\"-gebruiker verwyder nie."
+
+#: projects.py:380 projects.py:442
+msgid "You do not have rights to alter goals here"
+msgstr "U het nie regte om doelwitte hier te wysig nie."
+
+#: projects.py:505
+msgid "You do not have rights to upload files here"
+msgstr "U het nie regte om lêers hier op te laai nie."
+
+#: projects.py:508
+msgid "You do not have rights to overwrite files here"
+msgstr "U het nie regte om lêers hier te oorskryf nie."
+
+#: projects.py:510
+msgid "You do not have rights to upload new files here"
+msgstr "U het nie regte om nuwe lêers hier op te laai nie."
+
+#: projects.py:519
+msgid "You do not have rights to update files here"
+msgstr "U het nie regte om lêers hier op te dateer nie."
+
+#: projects.py:590
+msgid "You do not have rights to commit files here"
+msgstr "U het nie regte om lêerweergawes hier in te stuur nie."
+
+#: projects.py:919 projects.py:960
+msgid "You do not have rights to alter assignments here"
+msgstr "U het nie die regte om toekennings hier te verander nie."
+
+#: projects.py:1141
+msgid "You do not have rights to change translations here"
+msgstr "U het nie die regte om vertalings hier te verander nie."
+
+#: projects.py:1151
+msgid "You do not have rights to suggest changes here"
+msgstr "U het nie die regte om veranderings hier voor te stel nie."
+
+#: projects.py:1167 projects.py:1185
+msgid "You do not have rights to review suggestions here"
+msgstr "U het nie die regte om voorstelle hier na te gaan nie."
+
+#: translatepage.py:89
+#, python-format
+msgid ""
+"%d/%d translated\n"
+"(%d blank, %d fuzzy)"
+msgstr ""
+"%d/%d vertaal\n"
+"(%d leeg, %d wasig)"
+
+#: translatepage.py:94 adminpages.py:35 adminpages.py:74 adminpages.py:132
+#: adminpages.py:197 adminpages.py:284 adminpages.py:344 pagelayout.py:72
+#: users.py:58 users.py:95 users.py:131 users.py:153 indexpage.py:73
+#: indexpage.py:96 indexpage.py:136 indexpage.py:194 indexpage.py:256
+#: indexpage.py:346
+msgid "Pootle Demo"
+msgstr "Pootle-demonstrasie"
+
+#. l10n: first parameter: name of the installation (like "Pootle")
+#. l10n: second parameter: project name
+#. l10n: third parameter: target language
+#. l10n: fourth parameter: file name
+#: translatepage.py:99
+#, python-format
+msgid "%s: translating %s into %s: %s"
+msgstr "%s: vertaal %s in %s: %s"
+
+#. l10n: Heading above the table column with the source language
+#: translatepage.py:114
+msgid "Original"
+msgstr "Oorspronklike"
+
+#. l10n: Heading above the table column with the target language
+#: translatepage.py:116
+msgid "Translation"
+msgstr "Vertaling"
+
+#: translatepage.py:119
+msgid "Accept"
+msgstr "Aanvaar"
+
+#: translatepage.py:120
+msgid "Reject"
+msgstr "Verwerp"
+
+#: translatepage.py:121 pagelayout.py:243
+msgid "Fuzzy"
+msgstr "Wasig"
+
+#. l10n: Heading above the textarea for translator comments.
+#: translatepage.py:123
+msgid "Translator comments"
+msgstr "Vertaler se kommentaar"
+
+#. l10n: Heading above the comments extracted from the programing source code
+#: translatepage.py:125
+msgid "Developer comments"
+msgstr "Programmeerder se kommentaar"
+
+#. l10n: This heading refers to related translations and terminology
+#: translatepage.py:127
+msgid "Related"
+msgstr "Verwant"
+
+#. l10n: text next to search field
+#: translatepage.py:131 indexpage.py:356
+msgid "Search"
+msgstr "Soek"
+
+#. l10n: "batch" refers to the set of translations that were reviewed
+#: translatepage.py:145
+msgid "End of batch"
+msgstr "Einde van bondel"
+
+#: translatepage.py:147
+msgid "Click here to return to the index"
+msgstr "Kliek hier om terug te keer na indeks"
+
+#. l10n: noun (the start)
+#: translatepage.py:161 translatepage.py:164
+msgid "Start"
+msgstr "Begin"
+
+#. l10n: the parameter refers to the number of messages
+#: translatepage.py:168 translatepage.py:171
+#, python-format
+msgid "Previous %d"
+msgstr "Vorige %d"
+
+#. l10n: the third parameter refers to the total number of messages in the file
+#: translatepage.py:173
+#, python-format
+msgid "Items %d to %d of %d"
+msgstr "Items %d tot %d van %d"
+
+#. l10n: the parameter refers to the number of messages
+#: translatepage.py:178 translatepage.py:181
+#, python-format
+msgid "Next %d"
+msgstr "Volgende %d"
+
+#. l10n: noun (the end)
+#: translatepage.py:184 translatepage.py:187
+msgid "End"
+msgstr "Einde"
+
+#. l10n: the parameter is the name of one of the quality checks, like "fuzzy"
+#: translatepage.py:204
+#, python-format
+msgid "checking %s"
+msgstr "gaan \"%s\" na"
+
+#: translatepage.py:211 translatepage.py:214 indexpage.py:526 indexpage.py:529
+msgid "Assign Strings"
+msgstr "Ken stringe toe"
+
+#: translatepage.py:212 indexpage.py:528
+msgid "Assign to User"
+msgstr "Ken toe aan gebruiker"
+
+#: translatepage.py:213 indexpage.py:527
+msgid "Assign Action"
+msgstr "Ken aksie toe"
+
+#: translatepage.py:368
+#, python-format
+msgid "There are no items matching that search ('%s')"
+msgstr "Daar is geen items wat met u soeknavraag ('%s') ooreenstem nie"
+
+#: translatepage.py:370
+msgid "You have finished going through the items you selected"
+msgstr "U het klaar deur die items wat u gekies het, gegaan"
+
+#: translatepage.py:578
+msgid "Singular"
+msgstr "Enkelvoud"
+
+#: translatepage.py:579
+msgid "Plural"
+msgstr "Meervoud"
+
+#. l10n: verb
+#: translatepage.py:593
+msgid "Edit"
+msgstr "Redigeer"
+
+#. l10n: verb
+#: translatepage.py:609
+msgid "Copy"
+msgstr "Kopieer"
+
+#: translatepage.py:610 translatepage.py:784
+msgid "Skip"
+msgstr "Slaan oor"
+
+#. l10n: verb
+#: translatepage.py:612 translatepage.py:783 users.py:256
+msgid "Back"
+msgstr "Terug"
+
+#: translatepage.py:614
+msgid "Submit"
+msgstr "Dien in"
+
+#. l10n: action that increases the height of the textarea
+#: translatepage.py:617
+msgid "Grow"
+msgstr "Verleng"
+
+#. l10n: action that decreases the height of the textarea
+#: translatepage.py:619
+msgid "Shrink"
+msgstr "Verkort"
+
+#: translatepage.py:641 translatepage.py:735 translatepage.py:772
+#: translatepage.py:805
+#, python-format
+msgid "Plural Form %d"
+msgstr "Meervoudsvorm %d"
+
+#. l10n: This is an error message that will display if the relevant problem occurs
+#: translatepage.py:657
+msgid ""
+"Translation not possible because plural information for your language is not "
+"available. Please contact the site administrator."
+msgstr ""
+"Vertaling onmoontlik omdat meervoudinligting vir u taal nie beskikbaar is "
+"nie. Kontak asseblief die werfadministrateur."
+
+#: translatepage.py:739
+msgid "Current Translation:"
+msgstr "Huidige vertaling:"
+
+#. l10n: First parameter: number
+#. l10n: Second parameter: name of translator
+#: translatepage.py:752
+#, python-format
+msgid "Suggestion %d by %s:"
+msgstr "Voorstel %d deur %s:"
+
+#: translatepage.py:754
+#, python-format
+msgid "Suggestion %d:"
+msgstr "Voorstel %d:"
+
+#. l10n: parameter: name of translator
+#: translatepage.py:758
+#, python-format
+msgid "Suggestion by %s:"
+msgstr "Voorstel deur %s:"
+
+#: translatepage.py:760
+msgid "Suggestion:"
+msgstr "Voorstel:"
+
+#: adminpages.py:43 adminpages.py:82 adminpages.py:140 adminpages.py:205
+#: pagelayout.py:36
+msgid "Home"
+msgstr "Tuisblad"
+
+#: adminpages.py:44 adminpages.py:207
+msgid "Users"
+msgstr "Gebruikers"
+
+#: adminpages.py:45 adminpages.py:84 indexpage.py:94
+msgid "Languages"
+msgstr "Tale"
+
+#: adminpages.py:46 adminpages.py:142 indexpage.py:95
+msgid "Projects"
+msgstr "Projekte"
+
+#: adminpages.py:47
+msgid "General options"
+msgstr "Algemene keuses"
+
+#: adminpages.py:48 users.py:157
+msgid "Option"
+msgstr "Keuses"
+
+#: adminpages.py:49 users.py:158
+msgid "Current value"
+msgstr "Huidige waarde"
+
+#: adminpages.py:50 adminpages.py:85 adminpages.py:143 adminpages.py:208
+#: users.py:172
+msgid "Save changes"
+msgstr "Stoor veranderinge"
+
+#: adminpages.py:54
+msgid "Title"
+msgstr "Titel"
+
+#: adminpages.py:55
+msgid "Description"
+msgstr "Beskrywing"
+
+#: adminpages.py:56
+msgid "Base URL"
+msgstr "Basis-URL"
+
+#: adminpages.py:57
+msgid "Home Page"
+msgstr "Tuisblad"
+
+#: adminpages.py:83 adminpages.py:141 adminpages.py:206
+msgid "Main admin page"
+msgstr "Hoof-adminblad"
+
+#: adminpages.py:89
+msgid "ISO Code"
+msgstr "ISO-kode"
+
+#: adminpages.py:90 adminpages.py:148 adminpages.py:213 users.py:104
+msgid "Full Name"
+msgstr "Volle naam"
+
+#: adminpages.py:91
+msgid "(add language here)"
+msgstr "(voeg taal hier by)"
+
+#: adminpages.py:92
+msgid "Special Chars"
+msgstr "Spes. karakters"
+
+#: adminpages.py:92
+msgid "(special characters)"
+msgstr "(spesiale karakters)"
+
+#: adminpages.py:93 indexpage.py:217
+msgid "Number of Plurals"
+msgstr "Aantal meervoude"
+
+#: adminpages.py:93
+msgid "(number of plurals)"
+msgstr "(aantal meervoude)"
+
+#: adminpages.py:94 indexpage.py:218
+msgid "Plural Equation"
+msgstr "Meervoudvergelyking"
+
+#: adminpages.py:94
+msgid "(plural equation)"
+msgstr "(meervoudvergelyking)"
+
+#: adminpages.py:95
+msgid "Remove Language"
+msgstr "Verwyder taal"
+
+#. l10n: The parameter is a languagecode, projectcode or username
+#: adminpages.py:110 adminpages.py:177 adminpages.py:240 adminpages.py:410
+#, python-format
+msgid "Remove %s"
+msgstr "Vee %s uit"
+
+#: adminpages.py:129
+msgid "Standard"
+msgstr "Standaard"
+
+#: adminpages.py:147
+msgid "Project Code"
+msgstr "Projekkode"
+
+#: adminpages.py:149
+msgid "(add project here)"
+msgstr "(voeg projek hier by)"
+
+#: adminpages.py:150
+msgid "Project Description"
+msgstr "Projekbeskrywing"
+
+#: adminpages.py:150
+msgid "(project description)"
+msgstr "(projekbeskrywing)"
+
+#: adminpages.py:151
+msgid "Checker Style"
+msgstr "Toetserstyl"
+
+#: adminpages.py:152
+msgid "File Type"
+msgstr "Lêertipe"
+
+#: adminpages.py:153
+msgid "Create MO Files"
+msgstr "Skep MO-lêers"
+
+#: adminpages.py:154
+msgid "Remove Project"
+msgstr "Verwyder projek"
+
+#: adminpages.py:212 users.py:66
+msgid "Login"
+msgstr "Meld aan"
+
+#: adminpages.py:214 users.py:347
+msgid "(add full name here)"
+msgstr "(voeg volle naam hier by)"
+
+#: adminpages.py:215 users.py:101
+msgid "Email Address"
+msgstr "E-posadres"
+
+#: adminpages.py:215 users.py:350
+msgid "(add email here)"
+msgstr "(voeg e-pos hier by)"
+
+#: adminpages.py:216 users.py:107 users.py:163
+msgid "Password"
+msgstr "Wagwoord"
+
+#: adminpages.py:216 users.py:344
+msgid "(add password here)"
+msgstr "(voeg wagwoord hier by)"
+
+#: adminpages.py:217
+msgid "Activated"
+msgstr "Geaktiveer"
+
+#: adminpages.py:217
+msgid "Activate New User"
+msgstr "Aktiveer nuwe gebruiker"
+
+#: adminpages.py:218
+msgid "Remove User"
+msgstr "Verwyder gebruiker"
+
+#: adminpages.py:272
+msgid "Back to main page"
+msgstr "Terug na hoofblad"
+
+#: adminpages.py:273
+msgid "Existing languages"
+msgstr "Bestaande tale"
+
+#. l10n: This refers to updating the translation files from the templates like with .pot files
+#: adminpages.py:277
+msgid "Update Languages"
+msgstr "Dateer tale op"
+
+#: adminpages.py:278
+#, python-format
+msgid "Pootle Admin: %s"
+msgstr "Pootle-admin: %s"
+
+#: adminpages.py:279 adminpages.py:341
+msgid "You do not have the rights to administer this project."
+msgstr "U het nie administrasieregte vir hierdie projek nie."
+
+#. l10n: This refers to updating the translation files from the templates like with .pot files
+#: adminpages.py:281
+msgid "Update from templates"
+msgstr "Dateer op vanaf sjablone"
+
+#: adminpages.py:289
+msgid "Add Language"
+msgstr "Voeg taal by"
+
+#. l10n: This is the page title. The first parameter is the language name, the second parameter is the project name
+#: adminpages.py:321
+#, python-format
+msgid "Pootle Admin: %s %s"
+msgstr "Pootle admin: %s %s"
+
+#: adminpages.py:322
+msgid "Project home page"
+msgstr "Projektuisblad"
+
+#: adminpages.py:340
+#, python-format
+msgid "Cannot set rights for username %s - user does not exist"
+msgstr ""
+"Kan nie regte verstel vir gebruikersnaam %s nie - gebruiker bestaan nie"
+
+#: adminpages.py:357
+msgid "This is a GNU-style project (one directory, files named per language)."
+msgstr ""
+"Hierdie is 'n GNU-styl projek (een gids waarin die lêers volgens taal genoem "
+"word)."
+
+#: adminpages.py:359
+msgid "This is a standard style project (one directory per language)."
+msgstr "Hierdie is 'n standaardstyl projek (een gids per taal)."
+
+#: adminpages.py:360
+msgid "User Permissions"
+msgstr "Gebruikersregte"
+
+#: adminpages.py:361 users.py:98 users.py:134
+msgid "Username"
+msgstr "Gebruikersnaam"
+
+#: adminpages.py:362
+msgid "(select to add user)"
+msgstr "(kies om gebruiker by te voeg)"
+
+#: adminpages.py:363
+msgid "Rights"
+msgstr "Regte"
+
+#: adminpages.py:364 indexpage.py:998
+msgid "Remove"
+msgstr "Haal uit"
+
+#: adminpages.py:391
+msgid "Update Rights"
+msgstr "Dateer regte op"
+
+#: pagelayout.py:37
+msgid "All projects"
+msgstr "Alle projekte"
+
+#: pagelayout.py:38
+msgid "All languages"
+msgstr "Alle tale"
+
+#: pagelayout.py:39
+msgid "My account"
+msgstr "My rekening"
+
+#: pagelayout.py:40 pagelayout.py:168 indexpage.py:200 indexpage.py:262
+msgid "Admin"
+msgstr "Admin"
+
+#: pagelayout.py:41
+msgid "Docs & help"
+msgstr "Dokumentasie & hulp"
+
+#: pagelayout.py:42
+msgid "Log out"
+msgstr "Meld af"
+
+#: pagelayout.py:43
+msgid "Log in"
+msgstr "Meld aan"
+
+#. l10n: Verb, as in "to register"
+#: pagelayout.py:45
+msgid "Register"
+msgstr "Registreer"
+
+#: pagelayout.py:46
+msgid "Activate"
+msgstr "Aktiveer"
+
+#: pagelayout.py:80
+msgid "Pootle Logo"
+msgstr "Pootle-embleem"
+
+#: pagelayout.py:81
+msgid "WordForge Translation Project"
+msgstr "WordForge-vertaalprojek"
+
+#: pagelayout.py:83
+msgid "About this Pootle server"
+msgstr "Aangaande hierdie Pootle-bediener"
+
+#: pagelayout.py:157
+msgid "All goals"
+msgstr "Alle doelwitte"
+
+#: pagelayout.py:228
+#, python-format
+msgid "%d/%d files"
+msgstr "%d/%d lêers"
+
+#: pagelayout.py:231
+#, python-format
+msgid "%d file"
+msgid_plural "%d files"
+msgstr[0] "%d lêer"
+msgstr[1] "%d lêers"
+
+#: pagelayout.py:232 indexpage.py:995
+#, python-format
+msgid "%d/%d words (%d%%) translated"
+msgstr "%d/%d woorde (%d%%) vertaal"
+
+#: pagelayout.py:233
+#, python-format
+msgid "%d/%d strings"
+msgstr "%d/%d stringe"
+
+#: pagelayout.py:239 users.py:159
+msgid "Name"
+msgstr "Naam"
+
+#: pagelayout.py:240
+msgid "Translated"
+msgstr "Vertaal"
+
+#: pagelayout.py:241
+msgid "Translated percentage"
+msgstr "Vertaalpersentasie"
+
+#: pagelayout.py:242
+msgid "Translated words"
+msgstr "Vertaalde woorde"
+
+#: pagelayout.py:244
+msgid "Fuzzy percentage"
+msgstr "Wasigpersentasie"
+
+#: pagelayout.py:245
+msgid "Fuzzy words"
+msgstr "Wasige woorde"
+
+#: pagelayout.py:246 indexpage.py:786
+msgid "Untranslated"
+msgstr "Onvertaald"
+
+#: pagelayout.py:247
+msgid "Untranslated percentage"
+msgstr "Onvertaalde persentasie"
+
+#: pagelayout.py:248
+msgid "Untranslated words"
+msgstr "Onvertaalde woorde"
+
+#: pagelayout.py:249
+msgid "Total"
+msgstr "Totaal"
+
+#: pagelayout.py:250
+msgid "Total words"
+msgstr "Totale woorde"
+
+#. l10n: noun. The graphical representation of translation status
+#: pagelayout.py:252
+msgid "Graph"
+msgstr "Grafiek"
+
+#: users.py:39
+#, python-format
+msgid "You must supply a valid password of at least %d characters."
+msgstr "U moet 'n wagwoord van minstens %d karakters voorsien."
+
+#: users.py:41
+msgid "The password is not the same as the confirmation."
+msgstr "Die wagwoord stem nie ooreen met die bevestiging nie."
+
+#: users.py:55
+msgid "Login to Pootle"
+msgstr "Meld aan by Pootle"
+
+#: users.py:61
+msgid "Username:"
+msgstr "Gebruikernaam:"
+
+#: users.py:63
+msgid "Password:"
+msgstr "Wagwoord:"
+
+#: users.py:64
+msgid "Language:"
+msgstr "Taal:"
+
+#: users.py:73
+msgid "Default"
+msgstr "Verstek"
+
+#: users.py:89
+msgid "Please enter your registration details"
+msgstr "Tik asb. u registrasie-inligting in"
+
+#: users.py:92 users.py:419
+msgid "Pootle Registration"
+msgstr "Pootle-registrasie"
+
+#: users.py:99 users.py:135
+msgid "Your requested username"
+msgstr "U aangevraagde wagwoord"
+
+#: users.py:102 users.py:373
+msgid "You must supply a valid email address"
+msgstr "U moet 'n geldige e-posadres verskaf"
+
+#: users.py:105
+msgid "Your full name"
+msgstr "U volledige naam"
+
+#: users.py:108
+msgid "Your desired password"
+msgstr "U verkose wagwoord"
+
+#: users.py:110 users.py:164
+msgid "Confirm password"
+msgstr "Bevestig wagwoord"
+
+#: users.py:111
+msgid "Type your password again to ensure it is entered correctly"
+msgstr "Tik u wagwoord weer om te verseker dat dit reg is"
+
+#: users.py:113
+msgid "Register Account"
+msgstr "Registreer rekening"
+
+#: users.py:122
+msgid "Please enter your activation details"
+msgstr "Tik asb. u aktiveringsinligting in"
+
+#: users.py:127
+msgid "Pootle Account Activation"
+msgstr "Pootle-rekeningaktivering"
+
+#: users.py:137
+msgid "Activation Code"
+msgstr "Aktiveringskode"
+
+#: users.py:138
+msgid "The activation code you received"
+msgstr "Die aktiveringskode wat u ontvang het"
+
+#: users.py:140
+msgid "Activate Account"
+msgstr "Aktiveer rekening"
+
+#: users.py:151
+#, python-format
+msgid "Options for: %s"
+msgstr "Keuses vir: %s"
+
+#: users.py:156
+msgid "Personal Details"
+msgstr "Persoonlike detail"
+
+#: users.py:161
+msgid "Email"
+msgstr "E-pos"
+
+#: users.py:165
+msgid "Translation Interface Configuration"
+msgstr "Opstelling van vertaalkoppelvlak"
+
+#: users.py:166
+msgid "User Interface language"
+msgstr "Taal vir gebruikerkoppelvlak"
+
+#: users.py:167
+msgid "My Projects"
+msgstr "My projekte"
+
+#: users.py:169
+msgid "My Languages"
+msgstr "My tale"
+
+#: users.py:171
+msgid "Home page"
+msgstr "Tuisblad"
+
+#: users.py:207
+msgid "Input Height (in lines)"
+msgstr "Invoerhoogte (in lyne)"
+
+#: users.py:208
+msgid "Number of rows in view mode"
+msgstr "Aantal rye in bekyk-modus"
+
+#: users.py:209
+msgid "Number of rows in translate mode"
+msgstr "Aantal rye in vertaal-modus"
+
+#: users.py:251
+msgid "Error"
+msgstr "Fout"
+
+#: users.py:303
+msgid "You need to be siteadmin to change users"
+msgstr "U moet die werfadministrateur wees om gebruikers te kan verander."
+
+#: users.py:367
+msgid ""
+"Username must be alphanumeric, and must start with an alphabetic character."
+msgstr ""
+"Gebruikernaam moet alfanumeries wees en moet met 'n alfabetletter begin."
+
+#: users.py:382
+msgid ""
+"You (or someone else) attempted to register an account with your username.\n"
+msgstr ""
+"U (of iemand anders) het probeer om 'n rekening met u gebruikernaam te "
+"registreer.\n"
+
+#: users.py:383
+msgid "We don't store your actual password but only a hash of it.\n"
+msgstr ""
+"Ons stoor nie u werklike wagwoord nie, maar slegs 'n hutsvorm daarvan.\n"
+
+#: users.py:385
+#, python-format
+msgid "If you have a problem with registration, please contact %s.\n"
+msgstr "Indien u 'n probleem ondervind met registrasie, kontak asseblief %s.\n"
+
+#: users.py:387
+msgid ""
+"If you have a problem with registration, please contact the site "
+"administrator.\n"
+msgstr ""
+"Indien u 'n probleem ondervind met registrasie, kontak asseblief die "
+"werfadministrateur.\n"
+
+#: users.py:388
+msgid ""
+"That username already exists. An email will be sent to the registered email "
+"address.\n"
+msgstr ""
+"Daardie gebruikernaam bestaan reeds. 'n E-pos sal gestuur word aan die "
+"geregestreerde e-posadres.\n"
+
+#: users.py:390
+#, python-format
+msgid "Proceeding to <a href='%s'>login</a>\n"
+msgstr "Gaan nou voortgaan na <a href='%s'>aanmelding</a>\n"
+
+#: users.py:396
+msgid "A Pootle account has been created for you using this email address.\n"
+msgstr "'n Pootle-rekening is vir u geskep met hierdie e-posadres.\n"
+
+#: users.py:398
+msgid "To activate your account, follow this link:\n"
+msgstr "Om u rekening te aktiveer, gebruik hierdie skakel:\n"
+
+#: users.py:404
+#, python-format
+msgid ""
+"Your activation code is:\n"
+"%s\n"
+msgstr ""
+"U aktiveringskode is:\n"
+"%s\n"
+
+#: users.py:406
+msgid ""
+"If you are unable to follow the link, please enter the above code at the "
+"activation page.\n"
+msgstr ""
+"Indien u nie die skakel kan gebruik nie, gebruik die bogenoemde "
+"aktiveringskode op die aktiveringsblad.\n"
+
+#: users.py:407
+msgid ""
+"This message is sent to verify that the email address is in fact correct. If "
+"you did not want to register an account, you may simply ignore the message.\n"
+msgstr ""
+"Hierdie boodskap is gestuur om te kontroleer dat die e-posadres inderdaad "
+"korrek is. Indien u nie 'n rekening wou registreer nie, ignoreer bloot "
+"hierdie boodskap.\n"
+
+#: users.py:409
+#, python-format
+msgid ""
+"Account created. You will be emailed login details and an activation code. "
+"Please enter your activation code on the <a href='%s'>activation page</a>."
+msgstr ""
+"Rekening geskep. 'n E-pos met aanmelddetail en 'n aktiveringskode sal aan u "
+"gestuur word. Voer asseblief u aktiveringskode in by die <a href='%"
+"s'>aktiveringsblad</a>."
+
+#: users.py:411
+msgid "(Or simply click on the activation link in the email)"
+msgstr "(Of klik bloot op die aktiveringskakel in die e-pos)"
+
+#: users.py:413
+#, python-format
+msgid "Your user name is: %s\n"
+msgstr "U gebruikernaam is: %s\n"
+
+#: users.py:415
+#, python-format
+msgid "Your password is: %s\n"
+msgstr "U wagwoord is: %s\n"
+
+#: users.py:416
+#, python-format
+msgid "Your registered email address is: %s\n"
+msgstr "U geregistreerde e-posadres is: %s\n"
+
+#: users.py:442
+msgid "Redirecting to Registration Page..."
+msgstr "Gaan nou aanstuur na registrasieblad..."
+
+#: users.py:466
+msgid "Redirecting to login Page..."
+msgstr "Gaan nou aanstuur na aanmeldblad..."
+
+#: users.py:469
+msgid "Your account has been activated! Redirecting to login..."
+msgstr "U rekening is geaktiveer! Gaan nou aanstuur vir aanmelding..."
+
+#: users.py:473
+msgid "The activation information was not valid."
+msgstr "Die aktiveringsdetail was nie geldig nie."
+
+#: users.py:474
+msgid "Activation Failed"
+msgstr "Aktivering het misluk"
+
+#: users.py:583
+msgid "Input height must be numeric"
+msgstr "Invoerhoogte moet numeries wees"
+
+#: users.py:584
+msgid "Input width must be numeric"
+msgstr "Invoerwydte moet numeries wees"
+
+#: users.py:585
+msgid "The number of rows displayed in view mode must be numeric"
+msgstr "Aantal rye in bekykmodus moet numeries wees"
+
+#: users.py:586
+msgid "The number of rows displayed in translate mode must be numeric"
+msgstr "Aantal rye in vertaalmodus moet numeries wees"
+
+#: pootle.py:293
+msgid "Login failed"
+msgstr "Aanmeld gefaal"
+
+#: pootle.py:337 pootle.py:368
+msgid "Redirecting to login..."
+msgstr "Gaan nou aanstuur vir aanmelding..."
+
+#: pootle.py:340
+msgid "Need to log in to access home page"
+msgstr "Moet aanteken vir toegang tot tuisblad"
+
+#: pootle.py:353
+msgid "Personal details updated"
+msgstr "Persoonlike detail opgedateer"
+
+#: pootle.py:371
+msgid "Need to log in to access admin page"
+msgstr "Moet aanteken vir toegang tot adminblad"
+
+#: pootle.py:378
+msgid "Redirecting to home..."
+msgstr "Gaan nou aanstuur na tuisblad..."
+
+#: pootle.py:381
+msgid "You do not have the rights to administer pootle."
+msgstr "U het nie administrasieregte vir pootle nie."
+
+#: indexpage.py:61
+msgid "About Pootle"
+msgstr "Aangaande Pootle"
+
+#. l10n: Take care to use HTML tags correctly. A markup error could cause a display error.
+#: indexpage.py:63
+msgid ""
+"<strong>Pootle</strong> is a simple web portal that should allow you to "
+"<strong>translate</strong>! Since Pootle is <strong>Free Software</strong>, "
+"you can download it and run your own copy if you like. You can also help "
+"participate in the development in many ways (you don't have to be able to "
+"program)."
+msgstr ""
+"<strong>Pootle</strong> is 'n eenvoudige webportaal wat mens toelaat om te "
+"<strong>vertaal</strong>! Aangesien Pootle <strong>vrye sagteware</strong> "
+"is, kan mens dit aflaai en 'n eie kopie loop as mens wil. U kan ook hand "
+"bysit met die ontwikkeling op verskillende maniere (u hoef nie noodwendig "
+"eers te kan programeer nie)."
+
+#: indexpage.py:64
+msgid ""
+"The Pootle project itself is hosted at <a href=\"http://translate."
+"sourceforge.net/\">translate.sourceforge.net</a> where you can find the "
+"details about source code, mailing lists etc."
+msgstr ""
+"Die Pootle-projek word gehuisves by <a href=\"http://translate.sourceforge."
+"net/\">translate.sourceforge.net</a> waar detail oor die bronkode, poslyste, "
+"ens. gekry kan word."
+
+#. l10n: If your language uses right-to-left layout and you leave the English untranslated, consider enclosing the necessary text with <span dir="ltr">.......</span> to help browsers to display it correctly.
+#. l10n: Take care to use HTML tags correctly. A markup error could cause a display error.
+#: indexpage.py:67
+msgid ""
+"The name stands for <b>PO</b>-based <b>O</b>nline <b>T</b>ranslation / <b>L</"
+"b>ocalization <b>E</b>ngine, but you may need to read <a href=\"http://www."
+"thechestnut.com/flumps.htm\">this</a>."
+msgstr ""
+"Die naam staan vir <b>PO</b>-based <b>O</b>nline <b>T</b>ranslation / <b>L</"
+"b>ocalization <b>E</b>ngine, maar u moet dalk <a href=\"http://www."
+"thechestnut.com/flumps.htm\">hierdie</a> lees."
+
+#: indexpage.py:68
+msgid "Versions"
+msgstr "Weergawes"
+
+#. l10n: If your language uses right-to-left layout and you leave the English untranslated, consider enclosing the necessary text with <span dir="ltr">.......</span> to help browsers to display it correctly.
+#. l10n: Take care to use HTML tags correctly. A markup error could cause a display error.
+#: indexpage.py:71
+#, python-format
+msgid ""
+"This site is running:<br />Pootle %s<br />Translate Toolkit %s<br />jToolkit "
+"%s<br />Kid %s<br />ElementTree %s<br />Python %s (on %s/%s)"
+msgstr ""
+"Hierdie werf loop:<br />Pootle %s<br />Translate Toolkit %s<br />jToolkit %"
+"s<br />Kid %s<br />ElementTree %s<br />Python %s (on %s/%s)"
+
+#: indexpage.py:130
+#, python-format
+msgid "User Page for: %s"
+msgstr "Gebruikersblad vir: %s"
+
+#: indexpage.py:132
+msgid "Change options"
+msgstr "Verander keuses"
+
+#: indexpage.py:133
+msgid "Admin page"
+msgstr "Adminblad"
+
+#: indexpage.py:135
+msgid "Quick Links"
+msgstr "Snelskakels"
+
+#: indexpage.py:139
+msgid "Please click on 'Change options' and select some languages and projects"
+msgstr "Kliek asb. op 'Verander keuses' en kies u tale en projekte"
+
+#: indexpage.py:192
+#, python-format
+msgid "%d project, average %d%% translated"
+msgid_plural "%d projects, average %d%% translated"
+msgstr[0] "%d projek, gemiddeld %d%% vertaal"
+msgstr[1] "%d projekte, gemiddeld %d%% vertaal"
+
+#. l10n: The first parameter is the name of the installation
+#. l10n: The second parameter is the name of the project/language
+#. l10n: This is used as a page title. Most languages won't need to change this
+#: indexpage.py:198 indexpage.py:260
+#, python-format
+msgid "%s: %s"
+msgstr "%s: %s"
+
+#: indexpage.py:214
+msgid "Language Code"
+msgstr "Taalkode"
+
+#: indexpage.py:215
+msgid "Language Name"
+msgstr "Taalnaam"
+
+#: indexpage.py:252
+#, python-format
+msgid "%d language, average %d%% translated"
+msgid_plural "%d languages, average %d%% translated"
+msgstr[0] "%d taal, gemiddeld %d%% vertaal"
+msgstr[1] "%d tale, gemiddeld %d%% vertaal"
+
+#: indexpage.py:265
+msgid "Language"
+msgstr "Taal"
+
+#. l10n: The first parameter is the name of the installation (like "Pootle")
+#: indexpage.py:348
+#, python-format
+msgid "%s: Project %s, Language %s"
+msgstr "%s: projek %s, taal %s"
+
+#: indexpage.py:413
+msgid "Cannot upload file, no file attached"
+msgstr "Kan nie lêer oplaai nie, geen lêer aangeheg nie."
+
+#: indexpage.py:419
+msgid "Can only upload PO files and zips of PO files"
+msgstr "Kan slegs PO-lêers en ZIP's van PO-lêers oplaai."
+
+#: indexpage.py:534
+msgid "goals"
+msgstr "doelwitte"
+
+#: indexpage.py:535
+msgid "Enter goal name"
+msgstr "Tik die doelwit se naam in"
+
+#: indexpage.py:536
+msgid "Add Goal"
+msgstr "Voeg doelwit by"
+
+#: indexpage.py:541 indexpage.py:543
+msgid "Upload File"
+msgstr "Laai lêer op"
+
+#: indexpage.py:542
+msgid "Select file to upload"
+msgstr "Kies lêer om op te laai"
+
+#. l10n: tooltip
+#: indexpage.py:550
+msgid "Overwrite the current file if it exists"
+msgstr "Oorskryf die huidige lêer as dit bestaan"
+
+#. l10n: radio button text
+#: indexpage.py:552
+msgid "Merge"
+msgstr "Voeg saam"
+
+#. l10n: tooltip
+#: indexpage.py:554
+msgid ""
+"Merge the file with the current file and turn conflicts into suggestions"
+msgstr ""
+"Maak 'n samevoeging van die lêer met die huidige lêer en verander konflikte "
+"na voorstelle"
+
+#: indexpage.py:657
+msgid "Not in a goal"
+msgstr "Nie in 'n doelwit nie"
+
+#: indexpage.py:677
+msgid "Add User"
+msgstr "Voeg gebruiker by"
+
+#: indexpage.py:719
+msgid "PO file"
+msgstr "PO-lêer"
+
+#: indexpage.py:723
+msgid "XLIFF file"
+msgstr "XLIFF-lêer"
+
+#: indexpage.py:727
+msgid "Qt .ts file"
+msgstr "Qt .ts-lêer"
+
+#: indexpage.py:731
+msgid "CSV file"
+msgstr "CSV-lêer"
+
+#: indexpage.py:736
+msgid "MO file"
+msgstr "MO-lêer"
+
+#. l10n: Update from version control (like CVS or Subversion)
+#: indexpage.py:742
+msgid "Update"
+msgstr "Dateer op"
+
+#: indexpage.py:785
+msgid "All Strings"
+msgstr "Alle stringe"
+
+#: indexpage.py:787
+msgid "Unassigned"
+msgstr "Nie toegeken nie"
+
+#: indexpage.py:788
+msgid "Unassigned and Untranslated"
+msgstr "Nie toegeken nie en onvertaald"
+
+#: indexpage.py:795
+msgid "Set Goal"
+msgstr "Stel doelwit"
+
+#: indexpage.py:799
+msgid "Select Multiple"
+msgstr "Kies verskeie"
+
+#: indexpage.py:801
+msgid "Assign To"
+msgstr "Ken toe aan"
+
+#: indexpage.py:830
+msgid "Show Editing Functions"
+msgstr "Wys redigeerfunksies"
+
+#: indexpage.py:831
+msgid "Show Statistics"
+msgstr "Wys statistiek"
+
+#: indexpage.py:832
+msgid "Show Tracks"
+msgstr "Wys naspeursels"
+
+#: indexpage.py:832
+msgid "Hide Tracks"
+msgstr "Versteek naspeursels"
+
+#. l10n: "Checks" are quality checks that Pootle performs on translations to test for common mistakes
+#: indexpage.py:834
+msgid "Show Checks"
+msgstr "Wys toetse"
+
+#: indexpage.py:834
+msgid "Hide Checks"
+msgstr "Versteek toetse"
+
+#: indexpage.py:835
+msgid "Show Goals"
+msgstr "Wys doelwitte"
+
+#: indexpage.py:835
+msgid "Hide Goals"
+msgstr "Versteek doelwitte"
+
+#: indexpage.py:836
+msgid "Show Assigns"
+msgstr "Wys toekennings"
+
+#: indexpage.py:836
+msgid "Hide Assigns"
+msgstr "Versteek toekennings"
+
+#: indexpage.py:845
+#, python-format
+msgid "All Goals: %s"
+msgstr "Alle doelwitte: %s"
+
+#: indexpage.py:851
+msgid "Translate My Strings"
+msgstr "Vertaal my stringe"
+
+#: indexpage.py:853
+msgid "View My Strings"
+msgstr "Bekyk my stringe"
+
+#: indexpage.py:858
+msgid "No strings assigned to you"
+msgstr "Geen stringe aan u toegeken nie"
+
+#: indexpage.py:862
+msgid "Quick Translate My Strings"
+msgstr "Snel-vertaal my stringe"
+
+#: indexpage.py:866
+msgid "No untranslated strings assigned to you"
+msgstr "Geen onvertaalde stringe aan u toegeken nie"
+
+#: indexpage.py:870
+msgid "Review Suggestions"
+msgstr "Gaan voorstelle na"
+
+#: indexpage.py:872
+msgid "View Suggestions"
+msgstr "Wys voorstelle"
+
+#: indexpage.py:877
+msgid "Quick Translate"
+msgstr "Snel-vertaal"
+
+#: indexpage.py:879
+msgid "View Untranslated"
+msgstr "Wys onvertaalde"
+
+#: indexpage.py:883
+msgid "No untranslated items"
+msgstr "Geen onvertaalde items"
+
+#: indexpage.py:886
+msgid "Translate All"
+msgstr "Vertaal alles"
+
+#: indexpage.py:901
+msgid "ZIP of goal"
+msgstr "ZIP van doelwit"
+
+#: indexpage.py:903
+msgid "ZIP of folder"
+msgstr "ZIP van gids"
+
+#: indexpage.py:910
+msgid "Generate SDF"
+msgstr "Genereer SDF"
+
+#: indexpage.py:963
+#, python-format
+msgid "%d string (%d%%) failed"
+msgid_plural "%d strings (%d%%) failed"
+msgstr[0] "%d string (%d%%) het misluk"
+msgstr[1] "%d stringe (%d%%) het misluk"
+
+#: indexpage.py:993
+#, python-format
+msgid "%d/%d words (%d%%) assigned"
+msgstr "%d/%d woorde (%d%%) toegeken"
+
+#: indexpage.py:994 indexpage.py:996
+#, python-format
+msgid "[%d/%d strings]"
+msgstr "[%d/%d stringe]"
+
+#~ msgid "Broaden"
+#~ msgstr "Verbreed"
+
+#~ msgid "Narrow"
+#~ msgstr "Vernou"
+
+#~ msgid "Reset"
+#~ msgstr "Herstel"
+
+#~ msgid "Must be a valid email address"
+#~ msgstr "Moet 'n geldige e-posadres wees"
+
+#~ msgid "Input Width (in characters)"
+#~ msgstr "Invoerwydte (in karakters)"
+
+#~ msgid "Pootle"
+#~ msgstr "Pootle"
+
+#~ msgid "Pootle: %s"
+#~ msgstr "Pootle: %s"
+
+#~ msgid ""
+#~ "<strong>Pootle</strong> is a simple web portal that should allow you to "
+#~ "<strong>translate</strong>!"
+#~ msgstr ""
+#~ "<strong>Pootle</strong> is 'n eenvoudige web-portaal wat u toelaat om te "
+#~ "<strong>vertaal</strong>!"
+
+#~ msgid "parent folder"
+#~ msgstr "ouer-vouer"
+
+#~ msgid "<h3 class=\"title\">Projects</h3>"
+#~ msgstr "<h3 class=\"title\">Projekte</h3>"
+
+#~ msgid "%d files, %d/%d strings (%d%%) translated"
+#~ msgstr "%d lêers, %d/%d stringe (%d%%) reeds vertaal"
+
+#~ msgid "%s language"
+#~ msgstr "%s taal"
+
+#~ msgid "%d strings (%d%%) failed"
+#~ msgstr "%d stringe (%d%%) het misluk"
+
+#~ msgid "this is a demo installation of pootle"
+#~ msgstr "hierdie is 'n demonstrasie-installasie van pootle"
+
+#~ msgid "current folder"
+#~ msgstr "huidige lêer"
+
+#~ msgid "Log In"
+#~ msgstr "Teken in"
+
+#~ msgid "login status"
+#~ msgstr "intekenings-status"
+
+#~ msgid "project root"
+#~ msgstr "projek-basis"
+
+#~ msgid "%s project"
+#~ msgstr "%s projek"
+
+#~ msgid "you do not have rights to suggest changes here"
+#~ msgstr "u het nie regte om hier voorstelle te verskaf nie"
+
+#~ msgid "you do not have rights to change translations here"
+#~ msgstr "u het nie regte om hier te vertaal nie"
+
+#~ msgid "%d/%d strings (%d%%) translated"
+#~ msgstr "%d/%d stringe (%d%%) reeds vertaal"
+
+#~ msgid "%d files, "
+#~ msgstr "%d lêers,"
+
+#~ msgid "<h3 class=\"title\">Languages</h3>"
+#~ msgstr "<h3 class=\"title\">Tale</h3>"
+
+#~ msgid "current file"
+#~ msgstr "huidige lêer"
+
+#~ msgid "not logged in"
+#~ msgstr "nie tans ingeteken nie"
+
+#~ msgid "Pootle Admin Page"
+#~ msgstr "Pootle Administrasieblad"
+
+#~ msgid "Pootle Languages Admin Page"
+#~ msgstr "Pootle Taaladministrasie-blad"
+
+#~ msgid "Pootle Projects Admin Page"
+#~ msgstr "Pootle projek-administrasieblad"
+
+#~ msgid "(checker style)"
+#~ msgstr "(toetser-styl)"
+
+#~ msgid "You do not have the rights to administer Pootle."
+#~ msgstr "Jy het nie die regte toegang om Pootle te administreer nie."
+
+#~ msgid "Pootle User Admin Page"
+#~ msgstr "Pootle-gebruiker admin-blad"
+
+#~ msgid "%d strings (%d%%) assigned"
+#~ msgstr "%d stringe (%d%%) toegeken"
+
+#~ msgid "suggest"
+#~ msgstr "stel voor"
+
+#~ msgid "Input Width"
+#~ msgstr "Invoerwydte"
+
+#~ msgid "skip"
+#~ msgstr "slaan oor"
+
+#~ msgid "Log Out"
+#~ msgstr "Teken uit"
+
+#~ msgid "<b>Current Translation:</b>"
+#~ msgstr "<b>Huidige vertaling:</b>"
+
+#~ msgid "General Options"
+#~ msgstr "Algemene opsies"
+
+#~ msgid "Main Admin page"
+#~ msgstr "Hoof Admin-blad"
+
+#~ msgid "Remove language"
+#~ msgstr "Vee taal uit"
+
+#~ msgid "Remove project"
+#~ msgstr "Vee projek uit"
+
+#~ msgid "No goal"
+#~ msgstr "Geen doelwit"
+
+#~ msgid "Docs & Help"
+#~ msgstr "Dokumente & hulp"
+
+#~ msgid "translation"
+#~ msgstr "vertaling"
+
+#~ msgid ""
+#~ "This site is running:<br/>Pootle %s</br>jToolkit %s</br>Python %s (on %s/%"
+#~ "s)"
+#~ msgstr ""
+#~ "Hierdie webwerf loop:<br/>Pootle %s</br>jToolkit %s</br>Python %s (op %s/%"
+#~ "s)"
+
+#~ msgid "All Projects"
+#~ msgstr "Alle projekte"
+
+#~ msgid "All Languages"
+#~ msgstr "Alle tale"
+
+#~ msgid "copy"
+#~ msgstr "kopieer"
+
+#~ msgid "submit"
+#~ msgstr "dien in"
+
+#~ msgid "accept"
+#~ msgstr "aanvaar"
+
+#~ msgid "reject"
+#~ msgstr "verwerp"
+
+#~ msgid "Input Height"
+#~ msgstr "Invoerhoogte"
diff --git a/tests/xliff_conformance/en-US.sdf b/tests/xliff_conformance/en-US.sdf
new file mode 100644
index 0000000..5c6ff46
--- /dev/null
+++ b/tests/xliff_conformance/en-US.sdf
@@ -0,0 +1,226 @@
+accessibility	source\helper\accessiblestrings.src	0	string	RID_STR_ACC_NAME_BROWSEBUTTON				13691	en-US	Browse				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_OPEN				13691	en-US	Open				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_INSERT				13691	en-US	Apply				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_PLAY				13691	en-US	Play				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_PAUSE				13691	en-US	Pause				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_STOP				13691	en-US	Stop				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_ENDLESS				13691	en-US	Repeat				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_MUTE				13691	en-US	Mute				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_ZOOM				13691	en-US	View				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_ZOOM_50				13691	en-US	50%				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_ZOOM_100				13691	en-US	100%				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_ZOOM_200				13691	en-US	200%				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_ZOOM_FIT				13691	en-US	Scaled				2002-02-02 02:02:02
+avmedia	source\framework\mediacontrol.src	0	string	AVMEDIA_STR_MEDIAPLAYER				13691	en-US	Media Player				2002-02-02 02:02:02
+avmedia	source\viewer\mediawindow.src	0	string	AVMEDIA_STR_INSERTMEDIA_DLG				13691	en-US	Insert Movie and Sound				2002-02-02 02:02:02
+avmedia	source\viewer\mediawindow.src	0	string	AVMEDIA_STR_OPENMEDIA_DLG				13691	en-US	Open Movie and Sound				2002-02-02 02:02:02
+avmedia	source\viewer\mediawindow.src	0	string	AVMEDIA_STR_ALL_MEDIAFILES				13691	en-US	All movie and sound files				2002-02-02 02:02:02
+avmedia	source\viewer\mediawindow.src	0	string	AVMEDIA_STR_ALL_FILES				13691	en-US	All files (*.*)				2002-02-02 02:02:02
+avmedia	source\viewer\mediawindow.src	0	errorbox	AVMEDIA_ERR_URL				13691	en-US	The format of the selected file is not supported.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_FILTER_ALLFILES				13691	en-US	<All>				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_NOMODULE				13691	en-US	< No Module >				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_WRONGPASSWORD				13691	en-US	Incorrect Password				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_OPEN				13691	en-US	Load				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_SAVE				13691	en-US	Save				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_SOURCETOBIG				13691	en-US	The source text is too large and can be neither compiled nor saved.\nDelete some of the comments or transfer some methods into another module.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_ERROROPENSTORAGE				13691	en-US	Error opening file				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_ERROROPENLIB				13691	en-US	Error loading library				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_NOLIBINSTORAGE				13691	en-US	The file does not contain any BASIC libraries				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_BADSBXNAME				13691	en-US	Invalid Name				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_LIBNAMETOLONG				13691	en-US	A library name can have up to 30 characters.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_ERRORCHOOSEMACRO				13691	en-US	Macros from other documents are not accessible.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_LIBISREADONLY				13691	en-US	This library is read-only.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_REPLACELIB				13691	en-US	'XX' cannot be replaced.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_IMPORTNOTPOSSIBLE				13691	en-US	'XX' cannot be added.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_NOIMPORT				13691	en-US	'XX' was not added.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_ENTERPASSWORD				13691	en-US	Enter password for 'XX'				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_SBXNAMEALLREADYUSED				13691	en-US	Name already exists				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_SIGNED				13691	en-US	(Signed)				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_SBXNAMEALLREADYUSED2				13691	en-US	Object with same name already exists				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_FILEEXISTS				13691	en-US	The 'XX' file already exists				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_CANNOTRUNMACRO				13691	en-US	For security reasons, you cannot run this macro.\n\nFor more information, check the security settings.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_COMPILEERROR				13691	en-US	Compile Error: 				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_RUNTIMEERROR				13691	en-US	Runtime Error: #				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_SEARCHNOTFOUND				13691	en-US	Search key not found				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_SEARCHFROMSTART				13691	en-US	Search to last module complete. Continue at first module?				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_SEARCHREPLACES				13691	en-US	Search key replaced XX times				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_COULDNTREAD				13691	en-US	The file could not be read				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_COULDNTWRITE				13691	en-US	The file could not be saved				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_CANNOTCHANGENAMESTDLIB				13691	en-US	The name of the default library cannot be changed.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_CANNOTCHANGENAMEREFLIB				13691	en-US	The name of a referenced library cannot be changed.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_CANNOTUNLOADSTDLIB				13691	en-US	The default library cannot be deactivated				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_GENERATESOURCE				13691	en-US	Generating source				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_FILENAME				13691	en-US	File name:				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_APPENDLIBS				13691	en-US	Import Libraries				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_QUERYDELMACRO				13691	en-US	Do you want to delete the macro XX ?				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_QUERYDELDIALOG				13691	en-US	Do you want to delete the XX dialog?				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_QUERYDELLIB				13691	en-US	Do you want to delete the XX library?				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_QUERYDELLIBREF				13691	en-US	Do you want to delete the reference to the XX library?				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_QUERYDELMODULE				13691	en-US	Do you want to delete the XX module?				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_OBJNOTFOUND				13691	en-US	Object or method not found				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_BASIC				13691	en-US	BASIC				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_LINE				13691	en-US	Ln				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_COLUMN				13691	en-US	Col				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_DOC				13691	en-US	Document				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_BASICIDE_OBJECTBAR				13691	en-US	Macro Bar				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_CANNOTCLOSE				13691	en-US	The window cannot be closed while BASIC is running.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_REPLACESTDLIB				13691	en-US	The default library cannot be replaced.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_REFNOTPOSSIBLE				13691	en-US	Reference to 'XX' not possible.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_WATCHNAME				13691	en-US	Watch				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_WATCHVARIABLE				13691	en-US	Variable				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_WATCHVALUE				13691	en-US	Value				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_WATCHTYPE				13691	en-US	Type				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_STACKNAME				13691	en-US	Call Stack				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_INITIDE				13691	en-US	BASIC Initialization				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_STDMODULENAME				13691	en-US	Module				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_STDDIALOGNAME				13691	en-US	Dialog				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_STDLIBNAME				13691	en-US	Library				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_NEWLIB				13691	en-US	New Library				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_NEWMOD				13691	en-US	New Module				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_NEWDLG				13691	en-US	New Dialog				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_ALL				13691	en-US	All				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_PAGE				13691	en-US	Page				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_MACRONAMEREQ				13691	en-US	A name must be entered.				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_WILLSTOPPRG				13691	en-US	You will have to restart the program after this edit.\nContinue?				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_SEARCHALLMODULES				13691	en-US	Do you want to replace the text in all active modules?				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	imagebutton	RID_IMGBTN_REMOVEWATCH		HID_BASICIDE_REMOVEWATCH		80	en-US	-		Remove Watch		2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_REMOVEWATCH				80	en-US	Watch:				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_STACK				80	en-US	Calls: 				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_USERMACROS				80	en-US	My Macros				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_USERDIALOGS				80	en-US	My Dialogs				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_USERMACROSDIALOGS				80	en-US	My Macros & Dialogs				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_SHAREMACROS				80	en-US	%PRODUCTNAME Macros				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_SHAREDIALOGS				80	en-US	%PRODUCTNAME Dialogs				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_SHAREMACROSDIALOGS				80	en-US	%PRODUCTNAME Macros & Dialogs				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menuitem	RID_POPUP_BRKPROPS	RID_ACTIV	HID_BASICIDE_ACTIV		13691	en-US	Active				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menuitem	RID_POPUP_BRKPROPS	RID_BRKPROPS	HID_BASICIDE_BRKPROPS		13691	en-US	Properties...				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menu	RID_POPUP_BRKPROPS				80	en-US	Properties				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menuitem	RID_POPUP_BRKDLG	RID_BRKDLG	HID_BASICIDE_BRKDLG		13691	en-US	Manage Breakpoints...				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menu	RID_POPUP_BRKDLG				80	en-US	Manage Breakpoints				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menuitem	RID_POPUP_TABBAR.RID_INSERT	SID_BASICIDE_NEWMODULE	SID_BASICIDE_NEWMODULE		0	en-US	BASIC Module				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menuitem	RID_POPUP_TABBAR.RID_INSERT	SID_BASICIDE_NEWDIALOG	SID_BASICIDE_NEWDIALOG		0	en-US	BASIC Dialog				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menuitem	RID_POPUP_TABBAR	RID_INSERT			13691	en-US	Insert				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menuitem	RID_POPUP_TABBAR	SID_BASICIDE_DELETECURRENT	SID_BASICIDE_DELETECURRENT		13691	en-US	Delete				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menuitem	RID_POPUP_TABBAR	SID_BASICIDE_RENAMECURRENT	SID_BASICIDE_RENAMECURRENT		13691	en-US	Rename				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menuitem	RID_POPUP_TABBAR	SID_BASICIDE_HIDECURPAGE	SID_BASICIDE_HIDECURPAGE		13691	en-US	Hide				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menuitem	RID_POPUP_TABBAR	SID_BASICIDE_MODULEDLG	SID_BASICIDE_MODULEDLG		13691	en-US	Modules...				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	menuitem	RID_POPUP_DLGED	SID_SHOW_PROPERTYBROWSER	SID_SHOW_PROPERTYBROWSER		13691	en-US	Properties...				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_QUERYREPLACEMACRO				80	en-US	Do you want to overwrite the XX macro?				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_TRANSLATION_NOTLOCALIZED				80	en-US	<Not localized>				2002-02-02 02:02:02
+basctl	source\basicide\basidesh.src	0	string	RID_STR_TRANSLATION_DEFAULT				80	en-US	[Default Language]				2002-02-02 02:02:02
+basctl	source\basicide\brkdlg.src	0	pushbutton	RID_BASICIDE_BREAKPOINTDLG	RID_PB_NEW			50	en-US	New				2002-02-02 02:02:02
+basctl	source\basicide\brkdlg.src	0	pushbutton	RID_BASICIDE_BREAKPOINTDLG	RID_PB_DEL			50	en-US	Delete				2002-02-02 02:02:02
+basctl	source\basicide\brkdlg.src	0	checkbox	RID_BASICIDE_BREAKPOINTDLG	RID_CHKB_ACTIVE			40	en-US	Active				2002-02-02 02:02:02
+basctl	source\basicide\brkdlg.src	0	fixedtext	RID_BASICIDE_BREAKPOINTDLG	RID_FT_PASS			35	en-US	Pass Count:				2002-02-02 02:02:02
+basctl	source\basicide\brkdlg.src	0	fixedtext	RID_BASICIDE_BREAKPOINTDLG	RID_FT_BRKPOINTS			40	en-US	Breakpoints				2002-02-02 02:02:02
+basctl	source\basicide\brkdlg.src	0	modaldialog	RID_BASICIDE_BREAKPOINTDLG				178	en-US	Manage Breakpoints				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	fixedtext	RID_MACROCHOOSER	RID_TXT_MACROSIN			100	en-US	Existing macros ~in:				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	fixedtext	RID_MACROCHOOSER	RID_TXT_MACRONAME			100	en-US	~Macro name				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	fixedtext	RID_MACROCHOOSER	RID_TXT_MACROFROM			100	en-US	Macro ~from				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	fixedtext	RID_MACROCHOOSER	RID_TXT_SAVEMACRO			100	en-US	Save m~acro in				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	fixedtext	RID_MACROCHOOSER	RID_TXT_DESCRIPTION			100	en-US	De~scription				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	pushbutton	RID_MACROCHOOSER	RID_PB_RUN			50	en-US	R~un				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	cancelbutton	RID_MACROCHOOSER	RID_PB_CLOSE			50	en-US	Close				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	pushbutton	RID_MACROCHOOSER	RID_PB_ASSIGN			50	en-US	~Assign...				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	pushbutton	RID_MACROCHOOSER	RID_PB_EDIT			50	en-US	~Edit				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	pushbutton	RID_MACROCHOOSER	RID_PB_NEWLIB			50	en-US	New ~Library				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	pushbutton	RID_MACROCHOOSER	RID_PB_NEWMOD			50	en-US	New M~odule				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	pushbutton	RID_MACROCHOOSER	RID_PB_DEL			50	en-US	~Delete				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	pushbutton	RID_MACROCHOOSER	RID_PB_ORG			50	en-US	~Organizer...				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	modaldialog	RID_MACROCHOOSER				287	en-US	%PRODUCTNAME Basic Macros				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	string	RID_STR_STDMACRONAME				287	en-US	Macro				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	string	RID_STR_BTNDEL				287	en-US	~Delete				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	string	RID_STR_BTNNEW				287	en-US	~New				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	string	RID_STR_CLOSE				287	en-US	Close				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	string	RID_STR_CHOOSE				287	en-US	Choose				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	string	RID_STR_RUN				287	en-US	Run				2002-02-02 02:02:02
+basctl	source\basicide\macrodlg.src	0	string	RID_STR_RECORD				287	en-US	~Save				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pageitem	RID_TD_ORGANIZE.RID_TC_ORGANIZE	RID_TP_MOD			0	en-US	Modules				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pageitem	RID_TD_ORGANIZE.RID_TC_ORGANIZE	RID_TP_DLG			0	en-US	Dialogs				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pageitem	RID_TD_ORGANIZE.RID_TC_ORGANIZE	RID_TP_LIB			0	en-US	Libraries				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	tabdialog	RID_TD_ORGANIZE				13691	en-US	%PRODUCTNAME Basic Macro Organizer				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	fixedtext	RID_TP_MODULS	RID_STR_LIB			130	en-US	M~odule				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_MODULS	RID_PB_EDIT			60	en-US	~Edit				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	cancelbutton	RID_TP_MODULS	RID_PB_CLOSE			60	en-US	Close				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_MODULS	RID_PB_NEWMOD			60	en-US	~New...				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_MODULS	RID_PB_NEWDLG			60	en-US	~New...				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_MODULS	RID_PB_DELETE			60	en-US	~Delete				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	fixedtext	RID_TP_DLGS	RID_STR_LIB			130	en-US	Dialog				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_DLGS	RID_PB_EDIT			60	en-US	~Edit				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	cancelbutton	RID_TP_DLGS	RID_PB_CLOSE			60	en-US	Close				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_DLGS	RID_PB_NEWMOD			60	en-US	~New...				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_DLGS	RID_PB_NEWDLG			60	en-US	~New...				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_DLGS	RID_PB_DELETE			60	en-US	~Delete				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	fixedtext	RID_TP_LIBS	RID_STR_BASICS			130	en-US	L~ocation				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	fixedtext	RID_TP_LIBS	RID_STR_LIB			130	en-US	~Library				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_LIBS	RID_PB_EDIT			60	en-US	~Edit				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	cancelbutton	RID_TP_LIBS	RID_PB_CLOSE			60	en-US	Close				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_LIBS	RID_PB_PASSWORD			60	en-US	~Password...				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_LIBS	RID_PB_NEWLIB			60	en-US	~New...				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_LIBS	RID_PB_APPEND			60	en-US	~Import...				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_LIBS	RID_PB_EXPORT			60	en-US	E~xport...				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	pushbutton	RID_TP_LIBS	RID_PB_DELETE			60	en-US	~Delete				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	fixedline	RID_DLG_LIBS	RID_FL_OPTIONS			156	en-US	Options				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	checkbox	RID_DLG_LIBS	RID_CB_REF			146	en-US	Insert as reference (read-only)				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	checkbox	RID_DLG_LIBS	RID_CB_REPL			146	en-US	Replace existing libraries				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	fixedtext	RID_DLG_NEWLIB	RID_FT_NEWLIB			100	en-US	~Name:				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	radiobutton	RID_DLG_EXPORT	RB_EXPORTASPACKAGE			103	en-US	Export as ~extension				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	radiobutton	RID_DLG_EXPORT	RB_EXPORTASBASIC			103	en-US	Export as BASIC library				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	modaldialog	RID_DLG_EXPORT				115	en-US	Export Basic library				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	string	RID_STR_EXPORTPACKAGE				115	en-US	Export library as extension				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	string	RID_STR_EXPORTBASIC				115	en-US	Export as BASIC library				2002-02-02 02:02:02
+basctl	source\basicide\moduldlg.src	0	string	RID_STR_PACKAGE_BUNDLE				115	en-US	Extension				2002-02-02 02:02:02
+basctl	source\basicide\moptions.src	0	fixedtext	RID_MACROOPTIONS	RID_FT_DESCR			69	en-US	Description				2002-02-02 02:02:02
+basctl	source\basicide\moptions.src	0	fixedline	RID_MACROOPTIONS	RID_FL_HELP			212	en-US	Help information				2002-02-02 02:02:02
+basctl	source\basicide\moptions.src	0	fixedtext	RID_MACROOPTIONS	RID_FT_HELPID			80	en-US	Help ID				2002-02-02 02:02:02
+basctl	source\basicide\moptions.src	0	fixedtext	RID_MACROOPTIONS	RID_FT_HELPNAME			80	en-US	Help file name				2002-02-02 02:02:02
+basctl	source\basicide\moptions.src	0	modaldialog	RID_MACROOPTIONS				224	en-US	Description				2002-02-02 02:02:02
+basctl	source\basicide\objdlg.src	0	toolboxitem	RID_BASICIDE_OBJCAT.RID_TB_TOOLBOX	TBITEM_SHOW	HID_BASICIDE_OBJCAT_SHOW		13691	en-US	Show				2002-02-02 02:02:02
+basctl	source\basicide\objdlg.src	0	floatingwindow	RID_BASICIDE_OBJCAT				191	en-US	Objects				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	string	RID_TBXCONTROLS	RID_TOOLBOX			13691	en-US	Controls				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	floatingwindow	RID_TBXCONTROLS		HID_BASICIDE_CONTROLS		13691	en-US	Controls				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_PUSHBUTTON	SID_INSERT_PUSHBUTTON		0	en-US	Button				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_CHECKBOX	SID_INSERT_CHECKBOX		0	en-US	Check Box				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_FIXEDTEXT	SID_INSERT_FIXEDTEXT		0	en-US	Label field				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_LISTBOX	SID_INSERT_LISTBOX		0	en-US	List Box				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_HSCROLLBAR	SID_INSERT_HSCROLLBAR		0	en-US	Horizontal Scroll Bar				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_GROUPBOX	SID_INSERT_GROUPBOX		0	en-US	Group Box				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_HFIXEDLINE	SID_INSERT_HFIXEDLINE		0	en-US	Horizontal Line				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_DATEFIELD	SID_INSERT_DATEFIELD		0	en-US	Date Field				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_NUMERICFIELD	SID_INSERT_NUMERICFIELD		0	en-US	Numeric Field				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_FORMATTEDFIELD	SID_INSERT_FORMATTEDFIELD		0	en-US	Formatted Field				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_FILECONTROL	SID_INSERT_FILECONTROL		0	en-US	File Selection				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_TREECONTROL	SID_INSERT_TREECONTROL		0	en-US	Tree Control				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_SHOW_PROPERTYBROWSER	SID_SHOW_PROPERTYBROWSER		0	en-US	Properties				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_IMAGECONTROL	SID_INSERT_IMAGECONTROL		0	en-US	Image Control				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_RADIOBUTTON	SID_INSERT_RADIOBUTTON		0	en-US	Option Button				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_EDIT	SID_INSERT_EDIT		0	en-US	Text Box				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_COMBOBOX	SID_INSERT_COMBOBOX		0	en-US	Combo Box				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_VSCROLLBAR	SID_INSERT_VSCROLLBAR		0	en-US	Vertical Scroll Bar				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_PROGRESSBAR	SID_INSERT_PROGRESSBAR		0	en-US	Progress Bar				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_VFIXEDLINE	SID_INSERT_VFIXEDLINE		0	en-US	Vertical Line				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_TIMEFIELD	SID_INSERT_TIMEFIELD		0	en-US	Time Field				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_CURRENCYFIELD	SID_INSERT_CURRENCYFIELD		0	en-US	Currency Field				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_PATTERNFIELD	SID_INSERT_PATTERNFIELD		0	en-US	Pattern Field				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_INSERT_SELECT	SID_INSERT_SELECT		0	en-US	Select				2002-02-02 02:02:02
+basctl	source\basicide\tbxctl.src	0	toolboxitem	RID_TOOLBOX	SID_DIALOG_TESTMODE	SID_DIALOG_TESTMODE		0	en-US	Activate Test Mode				2002-02-02 02:02:02
+basctl	source\dlged\dlgresid.src	0	string	RID_STR_BRWTITLE_PROPERTIES				13691	en-US	Properties: 				2002-02-02 02:02:02
+basctl	source\dlged\dlgresid.src	0	string	RID_STR_BRWTITLE_NO_PROPERTIES				13691	en-US	No Control marked				2002-02-02 02:02:02
+basctl	source\dlged\dlgresid.src	0	string	RID_STR_BRWTITLE_MULTISELECT				13691	en-US	Multiselection				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	fixedtext	RID_DLG_MANAGE_LANGUAGE	FT_LANGUAGE			0	en-US	Present Languages				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	pushbutton	RID_DLG_MANAGE_LANGUAGE	PB_ADD_LANG			0	en-US	Add...				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	pushbutton	RID_DLG_MANAGE_LANGUAGE	PB_DEL_LANG			0	en-US	Delete				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	pushbutton	RID_DLG_MANAGE_LANGUAGE	PB_MAKE_DEFAULT			0	en-US	Default				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	fixedtext	RID_DLG_MANAGE_LANGUAGE	FT_INFO			0	en-US	The default language is used if no localization for a user interface locale is present. Furthermore all strings from the default language are copied to resources of newly added languages.				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	okbutton	RID_DLG_MANAGE_LANGUAGE	PB_CLOSE			0	en-US	~Close				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	string	RID_DLG_MANAGE_LANGUAGE	STR_DEF_LANG			0	en-US	[Default Language]				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	string	RID_DLG_MANAGE_LANGUAGE	STR_DELETE			0	en-US	~Delete				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	string	RID_DLG_MANAGE_LANGUAGE	STR_CREATE_LANG			0	en-US	<Press 'Add' to create language resources>				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	modaldialog	RID_DLG_MANAGE_LANGUAGE		HID_BASICIDE_MANAGE_LANGUAGE		0	en-US	Manage User Interface Languages [$1]				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	querybox	RID_QRYBOX_LANGUAGE				0	en-US	You are about to delete the resources for the selected language(s). All user interface strings for this language(s) will be deleted.\n\nDo you want to delete the resources of the selected language(s)?			Delete Language Resources	2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	fixedtext	RID_DLG_SETDEF_LANGUAGE	FT_DEF_LANGUAGE			0	en-US	Default language				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	fixedtext	RID_DLG_SETDEF_LANGUAGE	FT_DEF_INFO			0	en-US	Select a language to define the default user interface language. All currently present strings will be assigned to the resources created for the selected language.				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	string	RID_DLG_SETDEF_LANGUAGE	STR_ADDLANG_TITLE			0	en-US	Add User Interface Languages				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	string	RID_DLG_SETDEF_LANGUAGE	STR_ADDLANG_LABEL			0	en-US	Available Languages				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	string	RID_DLG_SETDEF_LANGUAGE	STR_ADDLANG_INFO			0	en-US	Select languages to be added. Resources for these languages will be created in the library. Strings of the current default user interface language will be copied to these new resources by default.				2002-02-02 02:02:02
+basctl	source\dlged\managelang.src	0	modaldialog	RID_DLG_SETDEF_LANGUAGE		HID_BASICIDE_SETDEFAULT_LANGUAGE		0	en-US	Set Default User Interface Language				2002-02-02 02:02:02
diff --git a/tests/xliff_conformance/test_xliff_conformance.py b/tests/xliff_conformance/test_xliff_conformance.py
new file mode 100644
index 0000000..64eb590
--- /dev/null
+++ b/tests/xliff_conformance/test_xliff_conformance.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 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 this program; if not, see <http://www.gnu.org/licenses/>.
+
+import os
+import os.path as path
+import sys
+from subprocess import call
+
+from lxml import etree
+
+
+# get directory of this test
+dir = os.path.dirname(os.path.abspath(__file__))
+# get top-level directory (moral equivalent of ../..)
+dir = os.path.dirname(os.path.dirname(dir))
+# load python modules from top-level
+sys.path.insert(0, dir)
+# add top-level to PYTHONPATH for subprocesses
+os.environ["PYTHONPATH"] = os.pathsep.join(sys.path)
+# add {top-level}/translate/convert to PATH for [po]o2xliff
+os.environ["PATH"] = os.pathsep.join([os.path.join(dir,
+                                                   "translate", "convert"),
+                                      os.environ["PATH"]])
+
+schema = None
+
+
+def xmllint(fullpath):
+    return schema.validate(etree.parse(fullpath))
+
+
+def setup_module(module):
+    global schema
+    os.chdir(path.dirname(__file__))
+    schema = etree.XMLSchema(etree.parse('xliff-core-1.1.xsd'))
+
+
+def find_files(base, check_ext):
+    for dirpath, _dirnames, filenames in os.walk(base):
+        for filename in filenames:
+            fullpath = path.join(dirpath, filename)
+            _namepath, ext = path.splitext(fullpath)
+            if check_ext == ext:
+                yield fullpath
+
+
+def test_open_office_to_xliff():
+    assert call(['oo2xliff', 'en-US.sdf', '-l', 'fr', 'fr']) == 0
+    for filepath in find_files('fr', '.xlf'):
+        assert xmllint(filepath)
+    cleardir('fr')
+
+
+def test_po_to_xliff():
+    OUTPUT = 'af-pootle.xlf'
+    assert call(['po2xliff', 'af-pootle.po', OUTPUT]) == 0
+    assert xmllint(OUTPUT)
+
+
+def teardown_module(module):
+    pass
+
+
+def cleardir(testdir):
+    """removes the test directory"""
+    if os.path.exists(testdir):
+        for dirpath, subdirs, filenames in os.walk(testdir, topdown=False):
+            for name in filenames:
+                os.remove(os.path.join(dirpath, name))
+            for name in subdirs:
+                os.rmdir(os.path.join(dirpath, name))
+    if os.path.exists(testdir):
+        os.rmdir(testdir)
+    assert not os.path.exists(testdir)
diff --git a/tests/xliff_conformance/xliff-core-1.1.xsd b/tests/xliff_conformance/xliff-core-1.1.xsd
new file mode 100644
index 0000000..7cb6e77
--- /dev/null
+++ b/tests/xliff_conformance/xliff-core-1.1.xsd
@@ -0,0 +1,2077 @@
+<?xml version="1.0" encoding="utf-8"?>

+<xsd:schema targetNamespace="urn:oasis:names:tc:xliff:document:1.1" xmlns:xyz="urn:appInfo:Items" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xlf="urn:oasis:names:tc:xliff:document:1.1" elementFormDefault="qualified" xml:lang="en">

+	<!-- Import for xml:lang and xml:space -->

+	<xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>

+	<!-- Attributes Lists -->

+	<xsd:simpleType name="XTend">

+		<xsd:restriction base="xsd:string">

+			<xsd:pattern value="x-[^\s]+"/>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="context-typeValueList">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'context-type'.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:string">

+			<xsd:enumeration value="database">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a database content.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="element">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the content of an element within an XML document.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="elementtitle">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the name of an element within an XML document.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="linenumber">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the line number from the sourcefile (see context-type="sourcefile") where the <source> is found.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="numparams">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a the number of parameters contained within the <source>.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="paramnotes">

+				<xsd:annotation>

+					<xsd:documentation>Indicates notes pertaining to the parameters in the <source>.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="record">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the content of a record within a database.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="recordtitle">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the name of a record within a database.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="sourcefile">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the original source file in the case that multiple files are merged to form the original file from which the XLIFF file is created. This differs from the original <file> attribute in that this sourcefile is one of many that make up that file.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="count-typeValueList">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'count-type'.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="num-usages">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the count units are items that are used X times in a certain context;

+example: this is a reusable text unit which is used 42 times in other texts.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="repetition">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the count units are translation units existing already in the same document.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="total">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a total count.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="InlineDelimitersValueList">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'ctype' when used other elements than <ph> or <x>.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="bold">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a run of bolded text.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="italic">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a run of text in italics.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="underlined">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a run of underlined text.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="link">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a run of hyper-text.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="InlinePlaceholdersValueList">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'ctype' when used with <ph> or <x>.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="image">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a inline image.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="pb">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a page break.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="lb">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a line break.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="mime-typeValueList">

+		<xsd:restriction base="xsd:string">

+			<xsd:pattern value="(text|multipart|message|application|image|audio|video|model)(/.+)*"/>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="datatypeValueList">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'datatype'.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="asp">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Active Server Page data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="c">

+				<xsd:annotation>

+					<xsd:documentation>Indicates C source file data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="cdf">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Channel Definition Format (CDF) data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="cfm">

+				<xsd:annotation>

+					<xsd:documentation>Indicates ColdFusion data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="cpp">

+				<xsd:annotation>

+					<xsd:documentation>Indicates C++ source file data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="csharp">

+				<xsd:annotation>

+					<xsd:documentation>Indicates C-Sharp data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="cstring">

+				<xsd:annotation>

+					<xsd:documentation>Indicates strings from C, ASM, and driver files data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="csv">

+				<xsd:annotation>

+					<xsd:documentation>Indicates comma-separated values data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="database">

+				<xsd:annotation>

+					<xsd:documentation>Indicates database data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="documentfooter">

+				<xsd:annotation>

+					<xsd:documentation>Indicates portions of document that follows data and contains metadata.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="documentheader">

+				<xsd:annotation>

+					<xsd:documentation>Indicates portions of document that precedes data and contains metadata.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="filedialog">

+				<xsd:annotation>

+					<xsd:documentation>Indicates data from standard UI file operations dialogs (e.g.,  Open,  Save,  Save As,  Export,  Import).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="form">

+				<xsd:annotation>

+					<xsd:documentation>Indicates standard user input screen data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="html">

+				<xsd:annotation>

+					<xsd:documentation>Indicates HyperText Markup Language (HTML) data - document instance.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="htmlbody">

+				<xsd:annotation>

+					<xsd:documentation>Indicates content within an HTML document’s <body> element.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="ini">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Windows INI file data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="interleaf">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Interleaf data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="javaclass">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Java source file data (extension '.java').</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="javapropertyresourcebundle">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Java property resource bundle data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="javalistresourcebundle">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Java list resource bundle data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="javascript">

+				<xsd:annotation>

+					<xsd:documentation>Indicates JavaScript source file data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="jscript">

+				<xsd:annotation>

+					<xsd:documentation>Indicates JScript source file data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="layout">

+				<xsd:annotation>

+					<xsd:documentation>Indicates information relating to formatting.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="lisp">

+				<xsd:annotation>

+					<xsd:documentation>Indicates LISP source file data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="margin">

+				<xsd:annotation>

+					<xsd:documentation>Indicates information relating to margin formats.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="menufile">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a file containing menu.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="messagefile">

+				<xsd:annotation>

+					<xsd:documentation>Indicates numerically identified string table.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="mif">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Maker Interchange Format (MIF) data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="mimetype">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that the datatype attribute value is a MIME Type value and is defined in the mime-type attribute.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="mo">

+				<xsd:annotation>

+					<xsd:documentation>Indicates GNU Machine Object data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="msglib">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Message Librarian strings created by Novell's Message Librarian Tool.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="pagefooter">

+				<xsd:annotation>

+					<xsd:documentation>Indicates information to be displayed at the bottom of each page of a document.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="pageheader">

+				<xsd:annotation>

+					<xsd:documentation>Indicates information to be displayed at the top of each page of a document.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="parameters">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a list of property values (e.g., settings within INI files or preferences dialog).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="pascal">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Pascal source file data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="php">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Hypertext Preprocessor data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="plaintext">

+				<xsd:annotation>

+					<xsd:documentation>Indicates plain text file (no formatting other than, possibly, wrapping).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="po">

+				<xsd:annotation>

+					<xsd:documentation>Indicates GNU Portable Object file.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="report">

+				<xsd:annotation>

+					<xsd:documentation>Indicates dynamically generated user defined document. e.g. Oracle Report,  Crystal Report,  etc.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="resources">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Windows .NET binary resources.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="resx">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Windows .NET Resources.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="rtf">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Rich Text Format (RTF) data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="sgml">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Standard Generalized Markup Language (SGML) data - document instance.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="sgmldtd">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Standard Generalized Markup Language (SGML) data - Document Type Definition (DTD).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="svg">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Scalable Vector Graphic (SVG) data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="vbscript">

+				<xsd:annotation>

+					<xsd:documentation>Indicates VisualBasic Script source file.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="warning">

+				<xsd:annotation>

+					<xsd:documentation>Indicates warning message.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="winres">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Windows (Win32) resources (i.e. resources extracted from an RC script, a message file, or a compiled file).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="xhtml">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Extensible HyperText Markup Language (XHTML) data - document instance.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="xml">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Extensible Markup Language (XML) data - document instance.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="xmldtd">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Extensible Markup Language (XML) data - Document Type Definition (DTD).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="xsl">

+				<xsd:annotation>

+					<xsd:documentation>Indicates Extensible Stylesheet Language (XSL) data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="xul">

+				<xsd:annotation>

+					<xsd:documentation>Indicates XUL elements.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="mtypeValueList">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'mtype'.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="abbrev">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the marked text is an abbreviation.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="abbreviated-form">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.8: A term resulting from the omission of any part of the full term while designating the same concept.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="abbreviation">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.8.1: An abbreviated form of a simple term resulting from the omission of some of its letters (e.g. 'adj.' for 'adjective').</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="acronym">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.8.4: An abbreviated form of a term made up of letters from the full form of a multiword term strung together into a sequence pronounced only syllabically (e.g. 'radar' for 'radio detecting and ranging').</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="appellation">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620: A proper-name term, such as the name of an agency or other proper entity.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="collocation">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.18.1: A recurrent word combination characterized by cohesion in that the components of the collocation must co-occur within an utterance or series of utterances, even though they do not necessarily have to maintain immediate proximity to one another.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="common-name">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.5: A synonym for an international scientific term that is used in general discourse in a given language.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="datetime">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the marked text is a date and/or time.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="equation">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.15: An expression used to represent a concept based on a statement that two mathematical expressions are, for instance, equal as identified by the equal sign (=), or assigned to one another by a similar sign.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="expanded-form">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.7: The complete representation of a term for which there is an abbreviated form.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="formula">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.14: Figures, symbols or the like used to express a concept briefly, such as a mathematical or chemical formula.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="head-term">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.1: The concept designation that has been chosen to head a terminological record.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="initialism">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.8.3: An abbreviated form of a term consisting of some of the initial letters of the words making up a multiword term or the term elements making up a compound term when these letters are pronounced individually (e.g. 'BSE' for 'bovine spongiform encephalopathy').</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="international-scientific-term">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.4: A term that is part of an international scientific nomenclature as adopted by an appropriate scientific body.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="internationalism">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.6: A term that has the same or nearly identical orthographic or phonemic form in many languages.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="logical-expression">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.16: An expression used to represent a concept based on mathematical or logical relations, such as statements of inequality, set relationships, Boolean operations, and the like.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="materials-management-unit">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.17: A unit to track object.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="name">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the marked text is a name.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="near-synonym">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.3: A term that represents the same or a very similar concept as another term in the same language, but for which interchangeability is limited to some contexts and inapplicable in others.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="part-number">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.17.2: A unique alphanumeric designation assigned to an object in a manufacturing system.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="phrase">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the marked text is a phrase.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="phraseological-unit">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.18: Any group of two or more words that form a unit, the meaning of which frequently cannot be deduced based on the combined sense of the words making up the phrase.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="protected">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the marked text should not be translated.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="romanized-form">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.12: A form of a term resulting from an operation whereby non-Latin writing systems are converted to the Latin alphabet.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="set-phrase">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.18.2: A fixed, lexicalized phrase.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="short-form">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.8.2: A variant of a multiword term that includes fewer words than the full form of the term (e.g. 'Group of Twenty-four' for 'Intergovernmental Group of Twenty-four on International Monetary Affairs').</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="sku">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.17.1: Stock keeping unit, an inventory item identified by a unique alphanumeric designation assigned to an object in an inventory control system.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="standard-text">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.19: A fixed chunk of recurring text.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="symbol">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.13: A designation of a concept by letters, numerals, pictograms or any combination thereof.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="synonym">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.2: Any term that represents the same or a very similar concept as the main entry term in a term entry.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="synonymous-phrase">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.18.3: Phraseological unit in a language that expresses the same semantic content as another phrase in that same language.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="term">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the marked text is a term.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="transcribed-form">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.11: A form of a term resulting from an operation whereby the characters of one writing system are represented by characters from another writing system, taking into account the pronunciation of the characters converted.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="transliterated-form">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.10: A form of a term resulting from an operation whereby the characters of an alphabetic writing system are represented by characters from another alphabetic writing system.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="truncated-term">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.8.5: An abbreviated form of a term resulting from the omission of one or more term elements or syllables (e.g. 'flu' for 'influenza').</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="variant">

+				<xsd:annotation>

+					<xsd:documentation>ISO-12620 2.1.9: One of the alternate forms of a term.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="restypeValueList">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'restype'.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="auto3state">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC AUTO3STATE control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="autocheckbox">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC AUTOCHECKBOX control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="autoradiobutton">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC AUTORADIOBUTTON control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="bedit">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC BEDIT control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="bitmap">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a bitmap, for example a BITMAP resource in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="button">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a button object, for example a BUTTON control Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="caption">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a caption, such as the caption of a dialog box.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="cell">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the cell in a table, for example the content of the <td> element in HTML.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="checkbox">

+				<xsd:annotation>

+					<xsd:documentation>Indicates check box object, for example a CHECKBOX control in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="checkboxmenuitem">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a menu item with an associated checkbox.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="checkedlistbox">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a list box, but with a check-box for each item.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="colorchooser">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a color selection dialog.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="combobox">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a combination of edit box and listbox object, for example a COMBOBOX control in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="comboboxexitem">

+				<xsd:annotation>

+					<xsd:documentation>Indicates an initialization entry of an extended combobox DLGINIT resource block. (code 0x1234).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="comboboxitem">

+				<xsd:annotation>

+					<xsd:documentation>Indicates an initialization entry of a combobox DLGINIT resource block (code 0x0403).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="component">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a UI base class element that cannot be represented by any other element.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="contextmenu">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a context menu.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="ctext">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC CTEXT control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="cursor">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a cursor, for example a CURSOR resource in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="datetimepicker">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a date/time picker.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="defpushbutton">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC DEFPUSHBUTTON control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="dialog">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a dialog box.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="dlginit">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC DLGINIT resource block.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="edit">

+				<xsd:annotation>

+					<xsd:documentation>Indicates an edit box object, for example an EDIT control in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="file">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a filename.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="filechooser">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a file dialog.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="fn">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a footnote.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="font">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a font name.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="footer">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a footer.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="frame">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a frame object.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="grid">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a XUL grid element.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="groupbox">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a groupbox object, for example a GROUPBOX control in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="header">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a header item.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="heading">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a heading, such has the content of <h1>, <h2>, etc. in HTML.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="hedit">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC HEDIT control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="hscrollbar">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a horizontal scrollbar.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="icon">

+				<xsd:annotation>

+					<xsd:documentation>Indicates an icon, for example an ICON resource in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="iedit">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC IEDIT control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="keywords">

+				<xsd:annotation>

+					<xsd:documentation>Indicates keyword list, such as the content of the Keywords meta-data in HTML, or a K footnote in WinHelp RTF.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="label">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a label object.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="linklabel">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a label that is also a HTML link (not necessarily a URL).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="list">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a list (a group of list-items, for example an <ol> or <ul> element in HTML).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="listbox">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a listbox object, for example an LISTBOX control in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="listitem">

+				<xsd:annotation>

+					<xsd:documentation>Indicates an list item (an entry in a list).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="ltext">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC LTEXT control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="menu">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a menu (a group of menu-items).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="menubar">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a toolbar containing one or more tope level menus.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="menuitem">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a menu item (an entry in a menu).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="menuseparator">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a XUL menuseparator element.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="message">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a message, for example an entry in a MESSAGETABLE resource in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="monthcalendar">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a calendar control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="numericupdown">

+				<xsd:annotation>

+					<xsd:documentation>Indicates an edit box beside a spin control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="panel">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a catch all for rectangular areas.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="popupmenu">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a standalone menu not necessarily associated with a menubar.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="pushbox">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a pushbox object, for example a PUSHBOX control in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="pushbutton">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC PUSHBUTTON control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="radio">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a radio button object.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="radiobuttonmenuitem">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a menuitem with associated radio button.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="rcdata">

+				<xsd:annotation>

+					<xsd:documentation>Indicates raw data resources for an application.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="row">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a row in a table.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="rtext">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC RTEXT control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="scrollpane">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a user navigable container used to show a portion of a document.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="separator">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a generic divider object (e.g. menu group separator).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="shortcut">

+				<xsd:annotation>

+					<xsd:documentation>Windows accelerators, shortcuts in resource or property files.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="spinner">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a UI control to indicate process activity but not progress.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="splitter">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a splitter bar.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="state3">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC STATE3 control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="statusbar">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a window for providing feedback to the users, like 'read-only', etc.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="string">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a string, for example an entry in a STRINGTABLE resource in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="tabcontrol">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a layers of controls with a tab to select layers.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="table">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a display and edits regular two-dimensional tables of cells.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="textbox">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a XUL textbox element.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="togglebutton">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a UI button that can be toggled to on or off state.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="toolbar">

+				<xsd:annotation>

+					<xsd:documentation>Indicates an array of controls, usually buttons.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="tooltip">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a pop up tool tip text.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="trackbar">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a bar with a pointer indicating a position within a certain range.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="tree">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a control that displays a set of hierarchical data.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="uri">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a URI (URN or URL).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="userbutton">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a Windows RC USERBUTTON control.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="usercontrol">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a user-defined control like CONTROL control in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="var">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the text of a variable.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+	 		<xsd:enumeration value="versioninfo">

+				<xsd:annotation>

+					<xsd:documentation>Indicates version information about a resource like VERSIONINFO in Windows.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="vscrollbar">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a vertical scrollbar.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="window">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a graphical window.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="size-unitValueList">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'size-unit'.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="byte">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in 8-bit bytes.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="char">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in Unicode characters.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="col">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in columns. Used for HTML text area.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="cm">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in centimeters.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="dlgunit">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in dialog units, as defined in Windows resources.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="em">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in 'font-size' units (as defined in CSS).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="ex">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in 'x-height' units (as defined in CSS).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="glyph">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in glyphs. A glyph is considered to be one or more combined Unicode characters that represent a single displayable text character. Sometimes referred to as a 'grapheme cluster'</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="in">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in inches.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="mm">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in millimeters.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="percent">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in percentage.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="pixel">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in pixels.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="point">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in point.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="row">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a size in rows. Used for HTML text area.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="stateValueList">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'state'.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="final">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the terminating state.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="needs-adaptation">

+				<xsd:annotation>

+					<xsd:documentation>Indicates only non-textual information needs adaptation.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="needs-l10n">

+				<xsd:annotation>

+					<xsd:documentation>Indicates both text and non-textual information needs adaptation.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="needs-review-adaptation">

+				<xsd:annotation>

+					<xsd:documentation>Indicates only non-textual information needs review.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="needs-review-l10n">

+				<xsd:annotation>

+					<xsd:documentation>Indicates both text and non-textual information needs review.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="needs-review-translation">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that only the text of the item needs to be reviewed.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="needs-translation">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that the item needs to be translated.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="new">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that the item is new. For example, translation units that were not in a previous version of the document.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="signed-off">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that changes are reviewed and approved.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="translated">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that the item has been translated.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="state-qualifierValueList">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'state-qualifier'.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="exact-match">

+				<xsd:annotation>

+					<xsd:documentation>Indicates an exact match. An exact match occurs when a source text of a segment is exactly the same as the source text of a segment that was translated previously.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="fuzzy-match">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a fuzzy match. A fuzzy match occurs when a source text of a segment is very similar to the source text of a segment that was translated previously (e.g. when the difference is casing, a few changed words, white-space discripancy, etc.).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="id-match">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a match based on matching IDs (in addition to matching text).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="leveraged-glossary">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a translation derived from a glossary.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="leveraged-inherited">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a translation derived from existing translation.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="leveraged-mt">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a translation derived from machine translation.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="leveraged-repository">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a translation derived from a translation repository.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="leveraged-tm">

+				<xsd:annotation>

+					<xsd:documentation>Indicates a translation derived from a translation memory.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="mt-suggestion">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the translation is suggested by machine translation.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="rejected-grammar">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that the item has been rejected because of incorrect grammar.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="rejected-inaccurate">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that the item has been rejected because it is incorrect.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="rejected-length">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that the item has been rejected because it is too long or too short.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="rejected-spelling">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that the item has been rejected because of incorrect spelling.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="tm-suggestion">

+				<xsd:annotation>

+					<xsd:documentation>Indicates the translation is suggested by translation memory.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="unitValueList">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'unit'.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="word">

+				<xsd:annotation>

+					<xsd:documentation>Refers to words.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="page">

+				<xsd:annotation>

+					<xsd:documentation>Refers to pages.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="trans-unit">

+				<xsd:annotation>

+					<xsd:documentation>Refers to <trans-unit> elements.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="bin-unit">

+				<xsd:annotation>

+					<xsd:documentation>Refers to <bin-unit> elements.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="glyph">

+				<xsd:annotation>

+					<xsd:documentation>Refers to glyphs.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="item">

+				<xsd:annotation>

+					<xsd:documentation>Refers to <trans-unit> and/or <bin-unit> elements.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="instance">

+				<xsd:annotation>

+					<xsd:documentation>Refers to the occurrences of instances defined by the count-type value.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="character">

+				<xsd:annotation>

+					<xsd:documentation>Refers to characters.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="line">

+				<xsd:annotation>

+					<xsd:documentation>Refers to lines.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="sentence">

+				<xsd:annotation>

+					<xsd:documentation>Refers to sentences.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="paragraph">

+				<xsd:annotation>

+					<xsd:documentation>Refers to paragraphs.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="segment">

+				<xsd:annotation>

+					<xsd:documentation>Refers to segments.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="placeable">

+				<xsd:annotation>

+					<xsd:documentation>Refers to placeables (inline elements).</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="priorityValueList">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'priority'.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:positiveInteger">

+			<xsd:enumeration value="1">

+				<xsd:annotation>

+					<xsd:documentation>Highest priority.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="2">

+				<xsd:annotation>

+					<xsd:documentation>High priority.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="3">

+				<xsd:annotation>

+					<xsd:documentation>High priority, but not as important as 2.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="4">

+				<xsd:annotation>

+					<xsd:documentation>High priority, but not as important as 3.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="5">

+				<xsd:annotation>

+					<xsd:documentation>Medium priority, but more important than 6.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="6">

+				<xsd:annotation>

+					<xsd:documentation>Medium priority, but less important than 5.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="7">

+				<xsd:annotation>

+					<xsd:documentation>Low priority, but more important than 8.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="8">

+				<xsd:annotation>

+					<xsd:documentation>Low priority, but more important than 9.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="9">

+				<xsd:annotation>

+					<xsd:documentation>Low priority.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="10">

+				<xsd:annotation>

+					<xsd:documentation>Lowest priority.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="reformatValueYesNo">

+		<xsd:restriction base="xsd:string">

+			<xsd:enumeration value="yes">

+				<xsd:annotation>

+					<xsd:documentation>This value indicate that all properties can be reformatted. This value must be used alone.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="no">

+				<xsd:annotation>

+					<xsd:documentation>This value indicate that no properties should be reformatted. This value must be used alone.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="reformatValueList">

+		<xsd:list>

+			<xsd:simpleType>

+				<xsd:restriction base="xsd:string">

+					<xsd:enumeration value="coord">

+						<xsd:annotation>

+							<xsd:documentation>This value indicates that all information in the coord attribute can be modified.</xsd:documentation>

+						</xsd:annotation>

+					</xsd:enumeration>

+					<xsd:enumeration value="coord-x">

+						<xsd:annotation>

+							<xsd:documentation>This value indicates that the x information in the coord attribute can be modified.</xsd:documentation>

+						</xsd:annotation>

+					</xsd:enumeration>

+					<xsd:enumeration value="coord-y">

+						<xsd:annotation>

+							<xsd:documentation>This value indicates that the y information in the coord attribute can be modified.</xsd:documentation>

+						</xsd:annotation>

+					</xsd:enumeration>

+					<xsd:enumeration value="coord-cx">

+						<xsd:annotation>

+							<xsd:documentation>This value indicates that the cx information in the coord attribute can be modified.</xsd:documentation>

+						</xsd:annotation>

+					</xsd:enumeration>

+					<xsd:enumeration value="coord-cy">

+						<xsd:annotation>

+							<xsd:documentation>This value indicates that the cy information in the coord attribute can be modified.</xsd:documentation>

+						</xsd:annotation>

+					</xsd:enumeration>

+					<xsd:enumeration value="font">

+						<xsd:annotation>

+							<xsd:documentation>This value indicates that all the information in the font attribute can be modified.</xsd:documentation>

+						</xsd:annotation>

+					</xsd:enumeration>

+					<xsd:enumeration value="font-name">

+						<xsd:annotation>

+							<xsd:documentation>This value indicates that the name information in the font attribute can be modified.</xsd:documentation>

+						</xsd:annotation>

+					</xsd:enumeration>

+					<xsd:enumeration value="font-size">

+						<xsd:annotation>

+							<xsd:documentation>This value indicates that the size information in the font attribute can be modified.</xsd:documentation>

+						</xsd:annotation>

+					</xsd:enumeration>

+					<xsd:enumeration value="font-weight">

+						<xsd:annotation>

+							<xsd:documentation>This value indicates that the weight information in the font attribute can be modified.</xsd:documentation>

+						</xsd:annotation>

+					</xsd:enumeration>

+					<xsd:enumeration value="css-style">

+						<xsd:annotation>

+							<xsd:documentation>This value indicates that the information in the css-style attribute can be modified.</xsd:documentation>

+						</xsd:annotation>

+					</xsd:enumeration>

+					<xsd:enumeration value="style">

+						<xsd:annotation>

+							<xsd:documentation>This value indicates that the information in the style attribute can be modified.</xsd:documentation>

+						</xsd:annotation>

+					</xsd:enumeration>

+					<xsd:enumeration value="ex-style">

+						<xsd:annotation>

+							<xsd:documentation>This value indicates that the information in the exstyle attribute can be modified.</xsd:documentation>

+						</xsd:annotation>

+					</xsd:enumeration>

+				</xsd:restriction>

+			</xsd:simpleType>

+		</xsd:list>

+	</xsd:simpleType>

+	<xsd:simpleType name="purposeValueList">

+		<xsd:restriction base="xsd:string">

+			<xsd:enumeration value="information">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that the context is informational in nature, specifying for example, how a term should be translated. Thus, should be displayed to anyone editing the XLIFF document.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="location">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that the context-group is used to specify where the term was found in the translatable source. Thus, it is not displayed.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+			<xsd:enumeration value="match">

+				<xsd:annotation>

+					<xsd:documentation>Indicates that the context information should be used during translation memory lookups. Thus, it is not displayed.</xsd:documentation>

+				</xsd:annotation>

+			</xsd:enumeration>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<!-- Other Types -->

+	<xsd:complexType name="ElemType_ExternalReference">

+		<xsd:choice>

+			<xsd:element name="internal-file" type="xlf:ElemType_internal-file"/>

+			<xsd:element name="external-file" type="xlf:ElemType_external-file"/>

+		</xsd:choice>

+	</xsd:complexType>

+	<xsd:simpleType name="AttrType_purpose">

+		<xsd:list>

+			<xsd:simpleType>

+				<xsd:annotation>

+					<xsd:appinfo>

+						<xyz:user-defined>yes</xyz:user-defined>

+					</xsd:appinfo>

+				</xsd:annotation>

+				<xsd:union memberTypes="xlf:purposeValueList xlf:XTend"/>

+			</xsd:simpleType>

+		</xsd:list>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_datatype">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:datatypeValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_restype">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:restypeValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_context-type">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:context-typeValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_state">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:stateValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_state-qualifier">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:state-qualifierValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_count-type">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:restypeValueList xlf:count-typeValueList xlf:datatypeValueList xlf:stateValueList xlf:state-qualifierValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_InlineDelimiters">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:InlineDelimitersValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_InlinePlaceholders">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:InlinePlaceholdersValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_size-unit">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:size-unitValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_mtype">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:mtypeValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_unit">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:unitValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_priority">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:priorityValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_reformat">

+		<xsd:annotation>

+			<xsd:appinfo>

+				<xyz:user-defined>yes</xyz:user-defined>

+			</xsd:appinfo>

+		</xsd:annotation>

+		<xsd:union memberTypes="xlf:reformatValueYesNo xlf:reformatValueList xlf:XTend"/>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_YesNo">

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="yes"/>

+			<xsd:enumeration value="no"/>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_Position">

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="open"/>

+			<xsd:enumeration value="close"/>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_assoc">

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="preceding"/>

+			<xsd:enumeration value="following"/>

+			<xsd:enumeration value="both"/>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_annotates">

+		<xsd:restriction base="xsd:NMTOKEN">

+			<xsd:enumeration value="source"/>

+			<xsd:enumeration value="target"/>

+			<xsd:enumeration value="general"/>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_Coordinates">

+		<xsd:annotation>

+			<xsd:documentation>Values for the attribute 'coord'.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:string">

+			<xsd:pattern value="(-?\d+|#);(-?\d+|#);(-?\d+|#);(-?\d+|#)"/>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<xsd:simpleType name="AttrType_Version">

+		<xsd:annotation>

+			<xsd:documentation>Version values: 1.0 is allowed for backward compatibility.</xsd:documentation>

+		</xsd:annotation>

+		<xsd:restriction base="xsd:string">

+			<xsd:enumeration value="1.1"/>

+			<xsd:enumeration value="1.0"/>

+		</xsd:restriction>

+	</xsd:simpleType>

+	<!-- Groups -->

+	<xsd:group name="ElemGroup_TextContent">

+		<xsd:choice>

+			<xsd:element name="g" type="xlf:ElemType_g"/>

+			<xsd:element name="bpt" type="xlf:ElemType_bpt"/>

+			<xsd:element name="ept" type="xlf:ElemType_ept"/>

+			<xsd:element name="ph" type="xlf:ElemType_ph"/>

+			<xsd:element name="it" type="xlf:ElemType_it"/>

+			<xsd:element name="mrk" type="xlf:ElemType_mrk"/>

+			<xsd:element name="x" type="xlf:ElemType_x"/>

+			<xsd:element name="bx" type="xlf:ElemType_bx"/>

+			<xsd:element name="ex" type="xlf:ElemType_ex"/>

+		</xsd:choice>

+	</xsd:group>

+	<!-- XLIFF Structure -->

+	<xsd:element name="xliff">

+		<xsd:complexType>

+			<xsd:sequence maxOccurs="unbounded">

+				<xsd:element name="file" type="xlf:ElemType_file"/>

+			</xsd:sequence>

+			<xsd:attribute name="version" type="xlf:AttrType_Version" use="required"/>

+			<xsd:attribute ref="xml:lang" use="optional"/>

+		</xsd:complexType>

+	</xsd:element>

+	<xsd:complexType name="ElemType_file">

+		<xsd:sequence>

+			<xsd:element name="header" type="xlf:ElemType_header" minOccurs="0"/>

+			<xsd:element name="body" type="xlf:ElemType_body"/>

+		</xsd:sequence>

+		<xsd:attribute name="original" type="xsd:string" use="required"/>

+		<xsd:attribute name="source-language" type="xsd:language" use="required"/>

+		<xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="required"/>

+		<xsd:attribute name="tool" type="xsd:string" use="optional" default="manual"/>

+		<xsd:attribute name="date" type="xsd:dateTime" use="optional"/>

+		<xsd:attribute ref="xml:space" use="optional"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="category" type="xsd:string" use="optional"/>

+		<xsd:attribute name="target-language" type="xsd:language" use="optional"/>

+		<xsd:attribute name="product-name" type="xsd:string" use="optional"/>

+		<xsd:attribute name="product-version" type="xsd:string" use="optional"/>

+		<xsd:attribute name="build-num" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_header">

+		<xsd:sequence>

+			<xsd:element name="skl" type="xlf:ElemType_ExternalReference" minOccurs="0"/>

+			<xsd:element name="phase-group" type="xlf:ElemType_phase-group" minOccurs="0"/>

+			<xsd:choice minOccurs="0" maxOccurs="unbounded">

+				<xsd:element name="glossary" type="xlf:ElemType_ExternalReference"/>

+				<xsd:element name="reference" type="xlf:ElemType_ExternalReference"/>

+				<xsd:element name="count-group" type="xlf:ElemType_count-group"/>

+				<xsd:element name="prop-group" type="xlf:ElemType_prop-group"/>

+				<xsd:element name="note" type="xlf:ElemType_note"/>

+				<xsd:element name="tool" type="xlf:ElemType_tool"/>

+			</xsd:choice>

+			<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>

+		</xsd:sequence>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_internal-file">

+		<xsd:simpleContent>

+			<xsd:extension base="xsd:string">

+				<xsd:attribute name="form" type="xsd:string"/>

+				<xsd:attribute name="crc" type="xsd:NMTOKEN"/>

+			</xsd:extension>

+		</xsd:simpleContent>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_external-file">

+		<xsd:attribute name="href" type="xsd:string" use="required"/>

+		<xsd:attribute name="crc" type="xsd:NMTOKEN"/>

+		<xsd:attribute name="uid" type="xsd:NMTOKEN"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_note">

+		<xsd:simpleContent>

+			<xsd:extension base="xsd:string">

+				<xsd:attribute ref="xml:lang" use="optional"/>

+				<xsd:attribute name="priority" type="xlf:AttrType_priority" use="optional" default="1"/>

+				<xsd:attribute name="from" type="xsd:string" use="optional"/>

+				<xsd:attribute name="annotates" type="xlf:AttrType_annotates" use="optional" default="general"/>

+			</xsd:extension>

+		</xsd:simpleContent>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_phase-group">

+		<xsd:sequence maxOccurs="unbounded">

+			<xsd:element name="phase" type="xlf:ElemType_phase"/>

+		</xsd:sequence>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_phase">

+		<xsd:sequence minOccurs="0" maxOccurs="unbounded">

+			<xsd:element name="note" type="xlf:ElemType_note"/>

+		</xsd:sequence>

+		<xsd:attribute name="phase-name" type="xsd:string" use="required"/>

+		<xsd:attribute name="process-name" type="xsd:string" use="required"/>

+		<xsd:attribute name="company-name" type="xsd:string" use="optional"/>

+		<xsd:attribute name="tool" type="xsd:string" use="optional"/>

+		<xsd:attribute name="date" type="xsd:dateTime" use="optional"/>

+		<xsd:attribute name="job-id" type="xsd:string" use="optional"/>

+		<xsd:attribute name="contact-name" type="xsd:string" use="optional"/>

+		<xsd:attribute name="contact-email" type="xsd:string" use="optional"/>

+		<xsd:attribute name="contact-phone" type="xsd:string" use="optional"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_count-group">

+		<xsd:sequence minOccurs="0" maxOccurs="unbounded">

+			<xsd:element name="count" type="xlf:ElemType_count"/>

+		</xsd:sequence>

+		<xsd:attribute name="name" type="xsd:string" use="required"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_count">

+		<xsd:simpleContent>

+			<xsd:extension base="xsd:string">

+				<xsd:attribute name="count-type" type="xlf:AttrType_count-type" use="optional"/>

+				<xsd:attribute name="phase-name" type="xsd:string" use="optional"/>

+				<xsd:attribute name="unit" type="xlf:AttrType_unit" use="optional" default="word"/>

+			</xsd:extension>

+		</xsd:simpleContent>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_context-group">

+		<xsd:sequence maxOccurs="unbounded">

+			<xsd:element name="context" type="xlf:ElemType_context"/>

+		</xsd:sequence>

+		<xsd:attribute name="name" type="xsd:string" use="required"/>

+		<xsd:attribute name="crc" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="purpose" type="xlf:AttrType_purpose" use="optional"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_context">

+		<xsd:simpleContent>

+			<xsd:extension base="xsd:string">

+				<xsd:attribute name="context-type" type="xlf:AttrType_context-type" use="required"/>

+				<xsd:attribute name="match-mandatory" type="xlf:AttrType_YesNo" use="optional" default="no"/>

+				<xsd:attribute name="crc" type="xsd:NMTOKEN" use="optional"/>

+			</xsd:extension>

+		</xsd:simpleContent>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_prop-group">

+		<xsd:sequence maxOccurs="unbounded">

+			<xsd:element name="prop" type="xlf:ElemType_prop"/>

+		</xsd:sequence>

+		<xsd:attribute name="name" type="xsd:string" use="optional"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_prop">

+		<xsd:simpleContent>

+			<xsd:extension base="xsd:string">

+				<xsd:attribute name="prop-type" type="xsd:string" use="required"/>

+				<xsd:attribute ref="xml:lang" use="optional"/>

+			</xsd:extension>

+		</xsd:simpleContent>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_tool" mixed="true">

+		<xsd:sequence minOccurs="0" maxOccurs="unbounded">

+			<xsd:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>

+		</xsd:sequence>

+		<xsd:attribute name="tool-id" type="xsd:string" use="required"/>

+		<xsd:attribute name="tool-name" type="xsd:string" use="required"/>

+		<xsd:attribute name="tool-version" type="xsd:string" use="optional"/>

+		<xsd:attribute name="tool-company" type="xsd:string" use="optional"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_body">

+		<xsd:choice minOccurs="0" maxOccurs="unbounded">

+			<xsd:element name="group" type="xlf:ElemType_group" minOccurs="0" maxOccurs="unbounded"/>

+			<xsd:element name="trans-unit" type="xlf:ElemType_trans-unit" minOccurs="0" maxOccurs="unbounded"/>

+			<xsd:element name="bin-unit" type="xlf:ElemType_bin-unit" minOccurs="0" maxOccurs="unbounded"/>

+		</xsd:choice>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_group">

+		<xsd:sequence>

+			<xsd:sequence>

+				<xsd:element name="context-group" type="xlf:ElemType_context-group" minOccurs="0" maxOccurs="unbounded"/>

+				<xsd:element name="count-group" type="xlf:ElemType_count-group" minOccurs="0" maxOccurs="unbounded"/>

+				<xsd:element name="prop-group" type="xlf:ElemType_prop-group" minOccurs="0" maxOccurs="unbounded"/>

+				<xsd:element name="note" type="xlf:ElemType_note" minOccurs="0" maxOccurs="unbounded"/>

+				<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>

+			</xsd:sequence>

+			<xsd:choice maxOccurs="unbounded">

+				<xsd:element name="group" type="xlf:ElemType_group" minOccurs="0" maxOccurs="unbounded"/>

+				<xsd:element name="trans-unit" type="xlf:ElemType_trans-unit" minOccurs="0" maxOccurs="unbounded"/>

+				<xsd:element name="bin-unit" type="xlf:ElemType_bin-unit" minOccurs="0" maxOccurs="unbounded"/>

+			</xsd:choice>

+		</xsd:sequence>

+		<xsd:attribute name="id" type="xsd:string" use="optional"/>

+		<xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>

+		<xsd:attribute ref="xml:space" use="optional" default="default"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>

+		<xsd:attribute name="resname" type="xsd:string" use="optional"/>

+		<xsd:attribute name="extradata" type="xsd:string" use="optional"/>

+		<xsd:attribute name="extype" type="xsd:string" use="optional"/>

+		<xsd:attribute name="help-id" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="menu" type="xsd:string" use="optional"/>

+		<xsd:attribute name="menu-option" type="xsd:string" use="optional"/>

+		<xsd:attribute name="menu-name" type="xsd:string" use="optional"/>

+		<xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>

+		<xsd:attribute name="font" type="xsd:string" use="optional"/>

+		<xsd:attribute name="css-style" type="xsd:string" use="optional"/>

+		<xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="translate" type="xlf:AttrType_YesNo" use="optional" default="yes"/>

+		<xsd:attribute name="reformat" type="xlf:AttrType_reformat" use="optional" default="yes"/>

+		<xsd:attribute name="size-unit" type="xlf:AttrType_size-unit" use="optional" default="pixel"/>

+		<xsd:attribute name="maxwidth" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="minwidth" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="maxheight" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="minheight" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="maxbytes" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="minbytes" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="charclass" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_trans-unit">

+		<xsd:sequence>

+			<xsd:element name="source" type="xlf:ElemType_source"/>

+			<xsd:element name="target" type="xlf:ElemType_target" minOccurs="0"/>

+			<xsd:element name="context-group" type="xlf:ElemType_context-group" minOccurs="0" maxOccurs="unbounded"/>

+			<xsd:element name="count-group" type="xlf:ElemType_count-group" minOccurs="0" maxOccurs="unbounded"/>

+			<xsd:element name="prop-group" type="xlf:ElemType_prop-group" minOccurs="0" maxOccurs="unbounded"/>

+			<xsd:element name="note" type="xlf:ElemType_note" minOccurs="0" maxOccurs="unbounded"/>

+			<xsd:element name="alt-trans" type="xlf:ElemType_alt-trans" minOccurs="0" maxOccurs="unbounded"/>

+			<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>

+		</xsd:sequence>

+		<xsd:attribute name="id" type="xsd:string" use="required"/>

+		<xsd:attribute name="approved" type="xlf:AttrType_YesNo" use="optional"/>

+		<xsd:attribute name="translate" type="xlf:AttrType_YesNo" use="optional" default="yes"/>

+		<xsd:attribute name="reformat" type="xlf:AttrType_reformat" use="optional" default="yes"/>

+		<xsd:attribute ref="xml:space" use="optional" default="default"/>

+		<xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="phase-name" type="xsd:string" use="optional"/>

+		<xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>

+		<xsd:attribute name="resname" type="xsd:string" use="optional"/>

+		<xsd:attribute name="extradata" type="xsd:string" use="optional"/>

+		<xsd:attribute name="extype" type="xsd:string" use="optional"/>

+		<xsd:attribute name="help-id" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="menu" type="xsd:string" use="optional"/>

+		<xsd:attribute name="menu-option" type="xsd:string" use="optional"/>

+		<xsd:attribute name="menu-name" type="xsd:string" use="optional"/>

+		<xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>

+		<xsd:attribute name="font" type="xsd:string" use="optional"/>

+		<xsd:attribute name="css-style" type="xsd:string" use="optional"/>

+		<xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="size-unit" type="xlf:AttrType_size-unit" use="optional" default="pixel"/>

+		<xsd:attribute name="maxwidth" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="minwidth" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="maxheight" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="minheight" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="maxbytes" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="minbytes" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="charclass" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_source" mixed="true">

+		<xsd:group ref="xlf:ElemGroup_TextContent" minOccurs="0" maxOccurs="unbounded"/>

+		<xsd:attribute ref="xml:lang" use="optional"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_target" mixed="true">

+		<xsd:group ref="xlf:ElemGroup_TextContent" minOccurs="0" maxOccurs="unbounded"/>

+		<xsd:attribute name="state" type="xlf:AttrType_state" use="optional"/>

+		<xsd:attribute name="state-qualifier" type="xlf:AttrType_state-qualifier" use="optional"/>

+		<xsd:attribute name="phase-name" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute ref="xml:lang" use="optional"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>

+		<xsd:attribute name="resname" type="xsd:string" use="optional"/>

+		<xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>

+		<xsd:attribute name="font" type="xsd:string" use="optional"/>

+		<xsd:attribute name="css-style" type="xsd:string" use="optional"/>

+		<xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_alt-trans">

+		<xsd:sequence>

+			<xsd:element name="source" type="xlf:ElemType_source" minOccurs="0"/>

+			<xsd:element name="target" type="xlf:ElemType_target" maxOccurs="unbounded"/>

+			<xsd:element name="context-group" type="xlf:ElemType_context-group" minOccurs="0" maxOccurs="unbounded"/>

+			<xsd:element name="prop-group" type="xlf:ElemType_prop-group" minOccurs="0" maxOccurs="unbounded"/>

+			<xsd:element name="note" type="xlf:ElemType_note" minOccurs="0" maxOccurs="unbounded"/>

+			<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>

+		</xsd:sequence>

+		<xsd:attribute name="match-quality" type="xsd:string" use="optional"/>

+		<xsd:attribute name="tool" type="xsd:string" use="optional"/>

+		<xsd:attribute name="crc" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute ref="xml:lang" use="optional"/>

+		<xsd:attribute name="origin" type="xsd:string" use="optional"/>

+		<xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>

+		<xsd:attribute ref="xml:space" use="optional" default="default"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>

+		<xsd:attribute name="resname" type="xsd:string" use="optional"/>

+		<xsd:attribute name="extradata" type="xsd:string" use="optional"/>

+		<xsd:attribute name="extype" type="xsd:string" use="optional"/>

+		<xsd:attribute name="help-id" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="menu" type="xsd:string" use="optional"/>

+		<xsd:attribute name="menu-option" type="xsd:string" use="optional"/>

+		<xsd:attribute name="menu-name" type="xsd:string" use="optional"/>

+		<xsd:attribute name="coord" type="xlf:AttrType_Coordinates" use="optional"/>

+		<xsd:attribute name="font" type="xsd:string" use="optional"/>

+		<xsd:attribute name="css-style" type="xsd:string" use="optional"/>

+		<xsd:attribute name="style" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="exstyle" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_bin-unit">

+		<xsd:sequence>

+			<xsd:element name="bin-source" type="xlf:ElemType_bin-source"/>

+			<xsd:element name="bin-target" type="xlf:ElemType_bin-target" minOccurs="0"/>

+			<xsd:choice minOccurs="0" maxOccurs="unbounded">

+				<xsd:element name="context-group" type="xlf:ElemType_context-group"/>

+				<xsd:element name="count-group" type="xlf:ElemType_count-group"/>

+				<xsd:element name="prop-group" type="xlf:ElemType_prop-group"/>

+				<xsd:element name="note" type="xlf:ElemType_note"/>

+				<xsd:element name="trans-unit" type="xlf:ElemType_trans-unit"/>

+			</xsd:choice>

+			<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>

+		</xsd:sequence>

+		<xsd:attribute name="id" type="xsd:string" use="required"/>

+		<xsd:attribute name="mime-type" type="xlf:mime-typeValueList" use="required"/>

+		<xsd:attribute name="approved" type="xlf:AttrType_YesNo" use="optional"/>

+		<xsd:attribute name="translate" type="xlf:AttrType_YesNo" use="optional" default="yes"/>

+		<xsd:attribute name="reformat" type="xlf:AttrType_reformat" use="optional" default="yes"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>

+		<xsd:attribute name="resname" type="xsd:string" use="optional"/>

+		<xsd:attribute name="phase-name" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_bin-source">

+		<xsd:choice>

+			<xsd:element name="internal-file" type="xlf:ElemType_internal-file"/>

+			<xsd:element name="external-file" type="xlf:ElemType_external-file"/>

+		</xsd:choice>

+		<xsd:attribute name="ts" type="xsd:string"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_bin-target">

+		<xsd:choice>

+			<xsd:element name="internal-file" type="xlf:ElemType_internal-file"/>

+			<xsd:element name="external-file" type="xlf:ElemType_external-file"/>

+		</xsd:choice>

+		<xsd:attribute name="mime-type" type="xlf:mime-typeValueList" use="optional"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="state" type="xlf:AttrType_state" use="optional"/>

+		<xsd:attribute name="state-qualifier" type="xlf:AttrType_state-qualifier" use="optional"/>

+		<xsd:attribute name="phase-name" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="restype" type="xlf:AttrType_restype" use="optional"/>

+		<xsd:attribute name="resname" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<!-- Element for inline codes -->

+	<xsd:complexType name="ElemType_g" mixed="true">

+		<xsd:group ref="xlf:ElemGroup_TextContent" minOccurs="0" maxOccurs="unbounded"/>

+		<xsd:attribute name="id" type="xsd:string" use="required"/>

+		<xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>

+		<xsd:attribute name="clone" type="xlf:AttrType_YesNo" use="optional" default="yes"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="xid" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_x">

+		<xsd:attribute name="id" type="xsd:string" use="required"/>

+		<xsd:attribute name="ctype" type="xlf:AttrType_InlinePlaceholders" use="optional"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="clone" type="xlf:AttrType_YesNo" use="optional" default="yes"/>

+		<xsd:attribute name="xid" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_bx">

+		<xsd:attribute name="id" type="xsd:string" use="required"/>

+		<xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>

+		<xsd:attribute name="clone" type="xlf:AttrType_YesNo" use="optional" default="yes"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="xid" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_ex">

+		<xsd:attribute name="id" type="xsd:string" use="required"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="xid" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_ph" mixed="true">

+		<xsd:sequence minOccurs="0" maxOccurs="unbounded">

+			<xsd:element name="sub" type="xlf:ElemType_sub"/>

+		</xsd:sequence>

+		<xsd:attribute name="id" type="xsd:string" use="required"/>

+		<xsd:attribute name="ctype" type="xlf:AttrType_InlinePlaceholders" use="optional"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="crc" type="xsd:string" use="optional"/>

+		<xsd:attribute name="assoc" type="xlf:AttrType_assoc" use="optional"/>

+		<xsd:attribute name="xid" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_bpt" mixed="true">

+		<xsd:sequence minOccurs="0" maxOccurs="unbounded">

+			<xsd:element name="sub" type="xlf:ElemType_sub"/>

+		</xsd:sequence>

+		<xsd:attribute name="id" type="xsd:string" use="required"/>

+		<xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="crc" type="xsd:string" use="optional"/>

+		<xsd:attribute name="xid" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_ept" mixed="true">

+		<xsd:sequence minOccurs="0" maxOccurs="unbounded">

+			<xsd:element name="sub" type="xlf:ElemType_sub"/>

+		</xsd:sequence>

+		<xsd:attribute name="id" type="xsd:string" use="required"/>

+		<xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="crc" type="xsd:string" use="optional"/>

+		<xsd:attribute name="xid" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_it" mixed="true">

+		<xsd:sequence minOccurs="0" maxOccurs="unbounded">

+			<xsd:element name="sub" type="xlf:ElemType_sub"/>

+		</xsd:sequence>

+		<xsd:attribute name="id" type="xsd:string" use="required"/>

+		<xsd:attribute name="pos" type="xlf:AttrType_Position" use="required"/>

+		<xsd:attribute name="rid" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:attribute name="crc" type="xsd:string" use="optional"/>

+		<xsd:attribute name="xid" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_sub" mixed="true">

+		<xsd:group ref="xlf:ElemGroup_TextContent" minOccurs="0" maxOccurs="unbounded"/>

+		<xsd:attribute name="datatype" type="xlf:AttrType_datatype" use="optional"/>

+		<xsd:attribute name="ctype" type="xlf:AttrType_InlineDelimiters" use="optional"/>

+		<xsd:attribute name="xid" type="xsd:string" use="optional"/>

+	</xsd:complexType>

+	<xsd:complexType name="ElemType_mrk" mixed="true">

+		<xsd:group ref="xlf:ElemGroup_TextContent" minOccurs="0" maxOccurs="unbounded"/>

+		<xsd:attribute name="mtype" type="xlf:AttrType_mtype" use="required"/>

+		<xsd:attribute name="mid" type="xsd:NMTOKEN" use="optional"/>

+		<xsd:attribute name="comment" type="xsd:string" use="optional"/>

+		<xsd:attribute name="ts" type="xsd:string" use="optional"/>

+		<xsd:anyAttribute namespace="##any" processContents="lax"/>

+	</xsd:complexType>

+</xsd:schema>

diff --git a/tools/mozilla/README.firefox_build_instructions.rst b/tools/mozilla/README.firefox_build_instructions.rst
new file mode 100644
index 0000000..81c8189
--- /dev/null
+++ b/tools/mozilla/README.firefox_build_instructions.rst
@@ -0,0 +1,167 @@
+================
+Firefox Building
+================  
+
+The following are instructions for setting up a build environment
+to use the Translate Toolkit and Pootle hosted at pootle.locamotion.org
+to build Firefox and Firefox Mobile.
+
+There are bound to be issues as we progress but generally the scripts
+and tools are widely tested managing over 15 languages.
+
+
+Setting up your environment
+===========================
+
+We use vagrant to manage VirtualBox VMs easily
+
+1. Install VirtualBox
+   Downloads https://www.virtualbox.org/wiki/Downloads
+   Vagrant installation instructions http://vagrantup.com/v1/docs/getting-started/index.html
+2. Install Vagrant
+   Downloads http://downloads.vagrantup.com/
+3. Create a directory for your Firefox work.  We use ~/dev/mozilla
+   # mkdir -p ~/dev/mozilla
+   # cd ~/dev/mozilla
+4. # wget https://raw.github.com/translate/translate/master/tools/mozilla/Vagrantfile
+5. # vagrant up
+6. # vagrant ssh
+7. # sudo ./postinstall.sh
+8. # exit
+9. # vagrant halt
+10. # vagrant up
+11. # vagrant ssh
+12. # ./setup_mozilla.sh
+
+You now have a VM that we will use exclusively for Firefox localisation.
+
+
+Configuring your development setup
+==================================
+
+We need to setup some things so that you can work with
+version control and have access to the servers.
+
+1. Setup SSH for access to Mozilla mercurial
+   Your SSH setup is copied from your computer into vagrant so if
+   this already works on your computer then it is already setup.
+2. Copy ~/.hgrc and ~/.gitconfig into $HOME on vagrant
+3. Send your public key for access to the Pootle server (usually ~/.ssh/id_dsa.pub)
+4. Request commit access to the SourceForge ZAF project to store your PO files
+
+Now you should be able to commit changes in PO and Mozilla files. You should
+also be able to get and push translations to the Pootle server.
+
+
+Building Firefox
+================
+
+The previous steps are once off.  You have a build setup and access to version control.
+The following are steps that you will repeat for every build.
+In the following examples we are working with the fictitious language zz.  Replace zz
+with your language code.
+
+1. Get ready.
+   # vagrant ssh
+   # cd firefox
+2. Get the new PO translations from Pootle.
+   # cd po
+   # svn up zz
+   # ./get-from-pootle.sh zz
+3. Review and commit translations.
+   # svndiff zz
+   Review the diff and check for any glaring errors.  If you 
+   are happy then commit.  We commit before we work on the files so that we
+   have something to go back to. Please use a good message as this is used by
+   others to track the changes.  E.g. could be.  "Update to 100% in user1 for Zedzed",
+   "Update translations following Zedzed sprint"
+   # svn ci zz
+   Files are now committed and we can get ready to process.
+4. Begin updateing. You might want to tell your team that you are doing this
+   as any changes they make on Pootle will be lost at a later step.
+   # cd ~/firefox
+   # ./build_firefox.sh zz
+   A lot of processing will happen and it will take some time.  Check for any errors in the process.
+5. Now check the updated PO files
+   # cd po-updated
+   # svndiff zz
+   Review for any glaring errors.  You probably only care about such updates after
+   a large migration e.g. Aurora 12 to Aurora 13.  If you are still in the same Aurora cycle then
+   you don't really care about po-updated output.  Happy? Then commit as you did in po/
+   Find any errors?  Fix them on Pootle or in the files in po/zz and run build_firefox.sh
+   again.
+6. Now we push our work to Mozilla
+   # cd ~/firefox/l10n
+   Check that Axel's compare locales pass
+   # ./compare-locales.sh zz
+   Check for any errors and correct.  Removed files should be fixed here. Errors in 
+   translations should be fixed on Pootle or in po/
+   # cd zz
+   # hg status
+   Check for any new or removed files. ? means a file not in version control.  ! means a files
+   that was in version control and now isn't which usually means we don't need it anymore.
+   # hg addremove path/to/files.dtd
+   Add the files and please carefully check what you are adding.  You shouldn't be adding anything
+   ending in .orig
+   # hg diff
+   Review the changes and check that you haven't broken anything. Happy?
+   # hg commit
+   # hg push
+   If your push fails with remote: 'ssl required' then you need to do the following.  Edit
+   l10/zz/.hg/hgrc, duplicate the line 'default = http:....' and replace default with default-push,
+   replace http:// with ssh://
+   Now try push again.
+7. Wait for Mozilla to build your stuff
+   Go to https://l10n-stage-sj.mozilla.org/teams/zz (Change zz of course) and check
+   that you have been built.
+   Get your nightly test build from
+   http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/latest-mozilla-aurora/
+   Once you have tested.  Signoff your build at the URL above.
+8. Push changes back to Pootle
+   If you made committed changes in po-updated/zz then:
+   # cd ~/firefox/po
+   # cd zz
+   # svn up
+   Or commit any changes you made in po/zz
+   # svn ci
+   Please please tell us what the commit is about
+   Now you need to push the files to Pootle
+   # ./push-to-pootle.sh zz
+   You will be asked if you want to proceed.  This is just a check that first syncs files on
+   Pootle to check that nobody has made any changes.  Remember your files will overwrite
+   anything done in your language on Pootle.
+   Happy? Press y<enter>
+   You are now synced and can tell your team to continue translating.
+
+
+Handling types of errors
+========================
+
+* The best place to fix anything is on Pootle.  So try to do it there if possible.
+* If you need to do it on the PO files, make sure you get-from-pootle.sh before you work
+  and push-to-pootle.sh after your changes.  When pushing check that nobody has done any
+  work while you were busy, do that by checking the last activity column at
+  http://mozilla.locamotion.org/projects/firefox/
+* compare-locale fixes are best done with the files in po/zz for speed.  Fix them all before
+  doing another build
+* If you see Mozilla bugs against your language:  Fix them in Pootle, then close the bug.  Your fix
+  will come through in your next update.  If it is urgent you probably want to fix it in PO and
+  make sure you push it through to Mozilla.
+* If you see your translators making a common error please share it on the firefox-l10n
+  list and try to educate them.
+
+
+build_firefox.sh options
+------------------------
+
+--no-vc - No version control.  Won't update anything from Mozilla.  This is helpful if you are working on
+          e.g. Aurora 12 and we haven't moved to Aurora 13.  Nothing should change in the source 
+          text.  This options will shave off a lot of time.  If uncertain leave this off.
+--xpi - Build a language pack.  If you aren't in Mozilla this is the only way to build one.  If your
+        language is in Mozilla Mercurial, best to let Mozilla build your langpack.
+
+
+Notes
+=====
+As long as you commit before major work you will be able to rollback any major issue.
+So be brave and careful.
diff --git a/tools/mozilla/Vagrantfile b/tools/mozilla/Vagrantfile
new file mode 100644
index 0000000..40bb031
--- /dev/null
+++ b/tools/mozilla/Vagrantfile
@@ -0,0 +1,99 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+Vagrant::Config.run do |config|
+  # All Vagrant configuration is done here. The most common configuration
+  # options are documented and commented below. For a complete reference,
+  # please see the online documentation at vagrantup.com.
+
+  # Every Vagrant virtual environment requires a box to build off of.
+  config.vm.box = "firefox"
+
+  # The url from where the 'config.vm.box' box will be fetched if it
+  # doesn't already exist on the user's system.
+  config.vm.box_url = "http://downloads.locamotion.org/aurora/firefox.box"
+
+  # Boot with a GUI so you can see the screen. (Default is headless)
+  # config.vm.boot_mode = :gui
+
+  # Assign this VM to a host-only network IP, allowing you to access it
+  # via the IP. Host-only networks can talk to the host machine as well as
+  # any other machines on the same network, but cannot be accessed (through this
+  # network interface) by any external networks.
+  #config.vm.network :hostonly, "192.168.33.10"
+
+  # Assign this VM to a bridged network, allowing you to connect directly to a
+  # network using the host's network device. This makes the VM appear as another
+  # physical device on your network.
+  # config.vm.network :bridged
+
+  # Forward a port from the guest to the host, which allows for outside
+  # computers to access the VM, whereas host only networking does not.
+  # config.vm.forward_port 80, 8080
+
+  # Share an additional folder to the guest VM. The first argument is
+  # an identifier, the second is the path on the guest to mount the
+  # folder, and the third is the path on the host to the actual folder.
+  config.vm.share_folder("v-root", "/vagrant", ".")
+  config.vm.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/v-root", "1"]
+  config.vm.share_folder("v-ssh", "~/.ssh/ssh_host", ENV['HOME'] + "/.ssh")
+  config.vm.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/v-ssh", "1"]
+
+  # Enable provisioning with Puppet stand alone.  Puppet manifests
+  # are contained in a directory path relative to this Vagrantfile.
+  # You will need to create the manifests directory and a manifest in
+  # the file myubuntu.pp in the manifests_path directory.
+  #
+  # An example Puppet manifest to provision the message of the day:
+  #
+  # # group { "puppet":
+  # #   ensure => "present",
+  # # }
+  # #
+  # # File { owner => 0, group => 0, mode => 0644 }
+  # #
+  # # file { '/etc/motd':
+  # #   content => "Welcome to your Vagrant-built virtual machine!
+  # #               Managed by Puppet.\n"
+  # # }
+  #
+  # config.vm.provision :puppet do |puppet|
+  #   puppet.manifests_path = "manifests"
+  #   puppet.manifest_file  = "myubuntu.pp"
+  # end
+
+  # Enable provisioning with chef solo, specifying a cookbooks path (relative
+  # to this Vagrantfile), and adding some recipes and/or roles.
+  #
+  # config.vm.provision :chef_solo do |chef|
+  #   chef.cookbooks_path = "cookbooks"
+  #   chef.add_recipe "mysql"
+  #   chef.add_role "web"
+  #
+  #   # You may also specify custom JSON attributes:
+  #   chef.json = { :mysql_password => "foo" }
+  # end
+
+  # Enable provisioning with chef server, specifying the chef server URL,
+  # and the path to the validation key (relative to this Vagrantfile).
+  #
+  # The Opscode Platform uses HTTPS. Substitute your organization for
+  # ORGNAME in the URL and validation key.
+  #
+  # If you have your own Chef Server, use the appropriate URL, which may be
+  # HTTP instead of HTTPS depending on your configuration. Also change the
+  # validation key to validation.pem.
+  #
+  # config.vm.provision :chef_client do |chef|
+  #   chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
+  #   chef.validation_key_path = "ORGNAME-validator.pem"
+  # end
+  #
+  # If you're using the Opscode platform, your validator client is
+  # ORGNAME-validator, replacing ORGNAME with your organization name.
+  #
+  # IF you have your own Chef Server, the default validation client name is
+  # chef-validator, unless you changed the configuration.
+  #
+  #   chef.validation_client_name = "ORGNAME-validator"
+end
diff --git a/tools/mozilla/accesskey_checker b/tools/mozilla/accesskey_checker
new file mode 100755
index 0000000..2085617
--- /dev/null
+++ b/tools/mozilla/accesskey_checker
@@ -0,0 +1,90 @@
+#!/bin/bash
+#
+# Copyright 2005, 2012 Zuza Software Foundation
+#
+# 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Finds problems with accesskeys in Mozilla DTD files
+#
+# Mozilla uses a system of naming such that:
+#   something.label
+#   something.accesskey
+# can create something in the UI with a label and accelerator/mnemonic.
+#
+# The Translate Toolkit uses this alignment to convert the seperate lable and
+# accesskey into one entry with the accelerator preceded by an ampersand.
+#
+# This tool tries to find problems with this alignment. These could include:
+#  * Missing .label entry
+#  * Strangely named accesskeys
+#
+
+function header()
+{
+    echo
+    echo "### $1 ###"
+}
+
+header "Find .acecsskey items and report those which don't have a corresponding .label in DTD"
+for accesskeysuffix in accesskey accessKey akey
+do
+    for d in `find . -name "*.dtd"`
+    do
+        for accesskeyprefix in `grep "[.]${accesskeysuffix} " $d | sed 's/^.* \([^ ]*\).'"${accesskeysuffix}"'.*$/\1/'`
+        do
+            otheroptions=`grep "[ ]${accesskeyprefix}[.]" $d | sed 's/^.* '"${accesskeyprefix}"'[.]\([^ ]*\).*$/\1/'`
+            echo $d $accesskeyprefix: $otheroptions | egrep -v '\<(label|title)\>'
+        done
+    done
+done
+
+header "Report all non-standard .akey, etc suffixes in DTD"
+for accesskeysuffix in akey access
+do
+    for d in `find . -name "*.dtd"`
+    do
+        for accesskeyprefix in `grep "[.]${accesskeysuffix} " $d | sed 's/^.* \([^ ]*\).'"${accesskeysuffix}"'.*$/\1/'`
+        do
+            otheroptions=`grep "[ ]${accesskeyprefix}[.]" $d | sed 's/^.* '"${accesskeyprefix}"'[.]\([^ ]*\).*$/\1/'`
+            echo $d $accesskeyprefix: $otheroptions
+        done
+    done
+done
+
+header "Find .accesskey items and report those which don't have a corresponding .label in .properties"
+for accesskeysuffix in accesskey accessKey akey
+do
+    for d in `find . -name "*.properties"`
+    do
+        for accesskeyprefix in `grep "[._]${accesskeysuffix}.*=" $d | sed 's/^[ ]*\([^ ]*\)[._]'"${accesskeysuffix}"'.*$/\1/'`
+        do
+            otheroptions=`grep "^[ ]*${accesskeyprefix}[._]" $d | sed 's/^[ ]*'"${accesskeyprefix}"'[._]\([^= ]*\).*$/\1/'`
+            echo $d $accesskeyprefix: $otheroptions | egrep -v '\<(label|title)\>'
+        done
+    done
+done
+
+header "Report all non-standard .akey, etc suffixes in .properties"
+for accesskeysuffix in akey access
+do
+    for d in `find . -name "*.properties§"`
+    do
+        for accesskeyprefix in `grep "[._]${accesskeysuffix}.*=" $d | sed 's/^[ ]*\([^ ]*\)[._]'"${accesskeysuffix}"'.*$/\1/'`
+        do
+            otheroptions=`grep "^[ ]*${accesskeyprefix}[._]" $d | sed 's/^[ ]*'"${accesskeyprefix}"'[._]\([^= ]*\).*$/\1/'`
+            echo $d $accesskeyprefix: $otheroptions
+        done
+    done
+done
diff --git a/tools/mozilla/accesskey_checker_PO b/tools/mozilla/accesskey_checker_PO
new file mode 100755
index 0000000..98e2713
--- /dev/null
+++ b/tools/mozilla/accesskey_checker_PO
@@ -0,0 +1,63 @@
+#!/bin/bash
+#
+# Copyright 2012 Zuza Software Foundation
+#
+# 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Finds problems with accesskeys in Gettext PO files
+#
+# This is really only useful for Mozilla PO files.  It finds single
+# character msgids, filters out those that we've reviewed and found
+# to not be stray accesskeys.  It counts them and then leaves the
+# filtered PO files for later examination.
+
+function usage()
+{
+	echo "Usage: $(basename $0) [dir]"
+	exit
+}
+
+if [ $# -ne 1 ]; then
+	usage
+fi
+if [ ! -d $1 ]; then
+	usage
+fi
+
+sourcedir=$1
+singledir=${sourcedir}-single
+accesskeydir=${sourcedir}-accesskey
+
+# Full entity names of items that should be ignored
+ignore_full_dtd="privatebrowsingpage.clearRecentHistoryAfter|firstdayofweek.default|noStyleSheet-tip-end.label|rememberActions.post.label|dontrememberActions.post.label|syncKey.findOutMore2.label|syncKey.footer3.label|aboutApps.noApps.post|aboutPage.licenseLinkSuffix|consoleEvaluate.label|rights.intro-point2-c|rights.intro-point3c|rights.intro-point4c|rights2.webservices-c"
+ignore_full_properties="gecko.handlerService.defaultHandlersVersion|Byte|Kilo|Mega|Giga|CertDumpAVACountry|CertDumpAVALocality|CertDumpAVAOrg|CertDumpPK9Email|pluralRule|intl.ellipsis|VK_SHIFT|VK_META|VK_ALT|VK_CONTROL|MODIFIER_SEPARATOR"
+
+# Items with these suffixes should be ignored
+ignore_suffix="commandkey|key|macCommandKey|commandKey"
+
+rm -rf $singledir $accesskeydir
+
+pogrep --progress=none --search=source -e "^.$" $sourcedir $singledir
+pogrep --progress=none --search=locations -e "($ignore_full_dtd|$ignore_full_properties|\.($ignore_suffix))" -v $singledir $accesskeydir
+
+rm -rf $singledir
+
+echo "DTD potential errors"
+pocount $(find $accesskeydir -name "*dtd*") | tail
+
+echo "Properties potential errors"
+pocount $(find $accesskeydir -name "*properties*") | tail
+
+echo "Actual problem files are located in directory: $accesskeydir"
diff --git a/tools/mozilla/build_tb3_langs.sh b/tools/mozilla/build_tb3_langs.sh
new file mode 100755
index 0000000..d70198d
--- /dev/null
+++ b/tools/mozilla/build_tb3_langs.sh
@@ -0,0 +1,179 @@
+#!/bin/bash
+#
+# Copyright 2008 Zuza Software Foundation
+#
+# This file is part of Virtaal.
+#
+# 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/>.
+
+##########################################################################
+# NOTE: Documentation regarding (the use of) this script can be found at #
+# http://translate.sourceforge.net/wiki/toolkit/mozilla_l10n_scripts     #
+##########################################################################
+
+BUILD_DIR="/path/to/buid/root"
+COMM_DIR="${BUILD_DIR}/comm-central" # Change "../comm-central" on line 35 too if you change this var
+#HG_LANGS="af ar as be bg bn-IN ca cs da de el en-GB en-ZA es-AR es-ES et eu fa fi fr fy-NL ga-IE gl gu-IN he hi-IN hu hy-AM id is it ja ja-JP-mac ka kn ko ku langs lt lv mk ml mn mr nb-NO ne-NP nl nn-NO nr nso pa-IN pl ro ru rw si sk sl sq sr ss st sv-SE ta te th tn tr ts uk ve xh zh-CN zh-TW zu"
+HG_LANGS="af"
+L10N_DIR="${BUILD_DIR}/l10n"
+PO_DIR="${BUILD_DIR}/po"
+POPACK_DIR="${BUILD_DIR}/popacks"
+PORECOVER_DIR="${BUILD_DIR}/po-recover"
+POT_INCLUDES="../README.mozilla-pot"
+POTPACK_DIR="${BUILD_DIR}/potpacks"
+POUPDATED_DIR="${BUILD_DIR}/po-updated"
+PRODUCT_DIRS="mail editor other-licenses/branding/thunderbird" # Directories in language repositories to clear before running po2moz
+LANGPACK_DIR="${BUILD_DIR}/xpi"
+TB_VERSION="3.0b3"
+
+
+# Include current dir in path (for buildxpi and others)
+CURDIR=`dirname $0`
+if [ x"${CURDIR}" == x ] || [ x"${CURDIR}" == x. ]; then
+	CURDIR=`pwd`
+fi
+PATH=${CURDIR}:${PATH}
+
+# Make sure all directories exist
+for dir in ${COMM_DIR} ${L10N_DIR} ${PO_DIR} ${POPACK_DIR} ${PORECOVER_DIR} ${POTPACK_DIR} ${POUPDATED_DIR} ${LANGPACK_DIR}
+do
+	[ ! -d ${dir} ] && mkdir -p ${dir}
+done
+
+# Compute relative paths of ${L10N_DIR} and ${POUPDATED_DIR}.
+# (This assumes that both directories are sub-directories of ${BUILD_DIR}
+L10N_DIR_REL=`echo ${L10N_DIR} | sed "s#${BUILD_DIR}/##"`
+POUPDATED_DIR_REL=`echo ${POUPDATED_DIR} | sed "s#${BUILD_DIR}/##"`
+
+(cd ${COMM_DIR}; hg pull -u; hg update -C)
+(find ${COMM_DIR} -name '*.orig' | xargs rm) || /bin/true
+
+cd ${L10N_DIR}
+
+# Update all Mercurial-managed languages
+for lang in ${HG_LANGS}
+do
+	[ -d ${lang}/.hg ] && (cd ${lang}; hg revert --all -r default; hg pull -u; hg update -C)
+	(find ${lang} -name '*.orig' | xargs rm) || /bin/true
+done
+
+rm en-US
+rm -rf pot
+
+# en-US and all languages should be up-to-date now
+[ -d en-US_mail ] && rm -rf en-US_mail
+get_moz_enUS.py -s ../comm-central -d . -p mail -v
+mv en-US{,_mail}
+ln -sf en-US_mail ./en-US
+# CREATE POT FILES FROM en-US
+moz2po --progress=none -P --duplicates=msgctxt --exclude '.hg' en-US pot
+find pot \( -name '*.html.pot' -o -name '*.xhtml.pot' \) -exec rm -f {} \;
+
+# Create POT pack
+# Comment out the lines starting with "tar" and/or "zip" to keep from building archives in the specific format(s).
+PACKNAME="${POTPACK_DIR}/thunderbird-${TB_VERSION}-`date +%Y%m%d`"
+tar chjf ${PACKNAME}.tar.bz2 pot en-US ${POT_INCLUDES}
+zip -qr9 ${PACKNAME}.zip pot en-US ${POT_INCLUDES}
+
+# The following functions are used in the loop following it
+function copyfile {
+	filename=$1
+	language=$2
+	directory=$(dirname $filename)
+	if [ -f ${L10N_DIR}/en-US/$filename ]; then
+		mkdir -p ${L10N_DIR}/$language/$directory
+		cp -p ${L10N_DIR}/en-US/$filename ${L10N_DIR}/$language/$directory
+	fi
+}
+
+function copyfiletype {
+	filetype=$1
+	language=$2
+	files=$(cd ${L10N_DIR}/en-US; find . -name "$filetype")
+	for file in $files
+	do
+		copyfile $file $language
+	done
+}
+
+function copydir {
+	dir=$1
+	language=$2
+	if [ -d ${L10N_DIR}/en-US/$dir ]; then
+		files=$(cd ${L10N_DIR}/en-US/$dir; find . -type f)
+		for file in $files
+		do
+			copyfile $dir/$file $language
+		done
+	fi
+}
+
+for lang in ${HG_LANGS}
+do
+	## RECOVER - Recover PO files from existing l10n directory.
+	## Comment out the following "moz2po"-line if recovery should not be done.
+	[ ! -d ${PORECOVER_DIR}/${lang} ] && mkdir -p ${PORECOVER_DIR}/${lang}
+	#moz2po --progress=none --errorlevel=traceback --duplicates=msgctxt --exclude=".#*" --exclude='.hg' \
+	#	-t ${L10N_DIR}/en-US ${L10N_DIR}/${lang} ${PORECOVER_DIR}/${lang}
+
+	[ ! -d ${PO_DIR}/${lang} ] && cp -R ${PORECOVER_DIR}/${lang} ${PO_DIR}
+
+	# Try and update existing PO files
+	updated=""
+	[ -z ${updated} ] && [ -d ${PO_DIR}/${lang}/CVS ] && (cd ${PO_DIR}/${lang}; cvs up) && updated="1"
+	[ -z ${updated} ] && [ -d ${PO_DIR}/${lang}/.hg ] && (cd ${PO_DIR}/${lang}; hg pull -u) && updated="1"
+	[ -z ${updated} ] && [ -d ${PO_DIR}/${lang}/.svn ] && (cd ${PO_DIR}/${lang}; svn up) && updated="1"
+
+	# Copy directory structure while preserving version control metadata
+	rm -rf ${POUPDATED_DIR}/${lang}
+	cp -R ${PO_DIR}/${lang} ${POUPDATED_DIR}
+	find ${POUPDATED_DIR}/${lang} -name '*.po' -exec rm -f {} \;
+
+	## MIGRATE - Migrate PO files to new POT files.
+	# Comment out the following "pomigrate2"-line if migration should not be done.
+	tempdir=`mktemp -d`
+	cp -R ${PO_DIR}/${lang} ${tempdir}/${lang}
+	pomigrate2 --use-compendium --quiet --pot2po ${tempdir}/${lang} ${POUPDATED_DIR}/${lang} ${L10N_DIR}/pot
+	rm -rf ${tempdir}
+
+	# Pre-po2moz hacks
+	lang_product_dirs=
+	for dir in ${PRODUCT_DIRS}; do lang_product_dirs="${lang_product_dirs} ${L10N_DIR}/$lang/$dir"; done
+	[ -d ${L10N_DIR}/${lang} ] && find ${lang_product_dirs} \( -name '*.dtd' -o -name '*.properties' \) -exec rm -f {} \;
+	find ${POUPDATED_DIR} \( -name '*.html.po' -o -name '*.xhtml.po' \) -exec rm -f {} \;
+
+	## PO2MOZ - Create Mozilla l10n layout from migrated PO files.
+	# Comment out the "po2moz"-line below to prevent l10n files to be updated to the current PO files.
+	po2moz --progress=none --errorlevel=traceback --exclude=".svn" --exclude=".hg" \
+		-t ${L10N_DIR}/en-US -i ${POUPDATED_DIR}/${lang} -o ${L10N_DIR}/${lang}
+
+	# Copy files not handled by moz2po/po2moz
+	copyfiletype "*.xhtml" ${lang} # Our XHTML and HTML is broken
+	copyfiletype "*.html" ${lang}
+	copyfiletype "*.rdf" ${lang}   # Don't support .rdf files
+	copyfiletype "*.txt" ${lang}
+	
+	## CREATE PO PACK - Create archives of PO files.
+	# Comment out the lines starting with "tar" and/or "zip" to keep from building archives in the specific format(s).
+	PACKNAME="${POPACK_DIR}/thunderbird-${TB_VERSION}-${lang}-`date +%Y%m%d`"
+	(
+		cd ${BUILD_DIR}
+		tar cjf ${PACKNAME}.tar.bz2 --exclude '.svn' --exclude '.hg' ${L10N_DIR_REL}/${lang} ${POUPDATED_DIR_REL}/${lang}
+		zip -qr9 ${PACKNAME}.zip ${L10N_DIR_REL}/${lang} ${POUPDATED_DIR_REL}/${lang} -x '*.svn*' -x "*.hg*"
+	)
+
+	## CREATE XPI LANGPACK
+	# Comment out the "buildxpi"-line below if XPI langpacks should not be built.
+	#buildxpi.py -L ${L10N_DIR} -s ${COMM_DIR} -o ${LANGPACK_DIR} -p mail ${lang}
+done
diff --git a/tools/mozilla/compare-locales.sh b/tools/mozilla/compare-locales.sh
new file mode 100755
index 0000000..7377ccc
--- /dev/null
+++ b/tools/mozilla/compare-locales.sh
@@ -0,0 +1,5 @@
+for lang in $*
+do
+	compare-locales ../mozilla-aurora/browser/locales/l10n.ini . $lang
+	compare-locales ../mozilla-aurora/mobile/locales/l10n.ini . $lang
+done
diff --git a/tools/mozilla/moz-l10n-builder b/tools/mozilla/moz-l10n-builder
new file mode 100755
index 0000000..6ac3c7f
--- /dev/null
+++ b/tools/mozilla/moz-l10n-builder
@@ -0,0 +1,342 @@
+#!/bin/bash
+#
+# Copyright 2005, 2007-2008 Zuza Software Foundation
+#
+# This file is part of The Translate Toolkit.
+#
+# The Translate Toolkit 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
+
+# moz-l10n-builder - takes a set of PO files, migrates them to a Mozilla build
+# and creates XPIs and Windows .exe files.
+
+# Prerequisites:
+# * nsis installer
+# * wine - to run the nsis installer
+# * Translate Toolkit - together with the bash scripts pomigrate2 and friends
+# * l10n.mk patch - patch to enable some make functionality needed in 
+#   existing makefiles
+# * Checkout of Mozilla and l10n/ sources with mozilla/client.mk checked 
+#   out to the correct branch or releaes tag
+# * Firefox and/or Thunderbird Windows .exe - an existing en-US build 
+#   that we will unwrap and remake with your translations. In this 
+#   case you probably want to be building on a RELEASE not BRANCH tag.
+
+langs="af en_ZA nr nso ss st tn ts ve xh zu en_DE"
+#tag='FIREFOX_3_0b4_RELEASE'
+langpackrelease=1
+targetapp=browser
+mozversion=3
+
+l10ndir="l10n"
+mozilladir="mozilla"
+podir="po"
+potpacks="potpacks"
+
+if [ "$tag" != "" ]; then
+	tag="-r $tag"
+else
+	tag="-A"
+fi
+
+
+function usage() {
+        echo "Usage `basename $0` [options] <lang|ALL>"
+        echo
+        echo "Options:"
+        echo "   --mozilla-product        - which product to build (default: $targetapp)"
+        echo "   --mozilla-checkout       - update of the Mozilla l10n files and POT files"
+        echo "   --update-translations    - update translations"
+        echo "   --diff                   - create diffs for migrated translations and l10n/"
+        echo "   --potpack                - create packages of the en-US and pot directories with today's timestamp in $potpacks/"
+        echo "   --langpack               - build a langpack"
+        echo "   --debug                  - add podebug debug markers"
+        exit 1
+}
+
+# Define some options
+option_mozilla_checkout=""
+option_update_translations="" 
+option_diff=""
+option_potpack=""
+option_langpack=""
+option_debug=""
+option_recovery=""
+
+
+while true
+do
+        case $1 in
+                --mozilla-product*)
+			tempproduct=$(echo $1 | sed "s/--mozilla-product=\?//")
+                        targetapp=${tempproduct:-$targetapp}
+                        shift
+                        ;;
+                --mozilla-checkout)
+                        option_mozilla_checkout="mozilla_checkout"
+                        shift
+                        ;;
+                --update-translations)
+                        option_update_translations="update_translations"
+                        shift
+                        ;;
+                --diff)
+                        option_diff="option_diff"
+                        shift
+                        ;;
+                --potpack)
+                        option_potpack="option_potpack"
+                        shift
+                        ;;
+                --langpack)
+                        option_langpack="option_langpack"
+                        shift
+                        ;;
+                --debug)
+                        option_debug="option_debug"
+						use_fuzzy="--fuzzy"
+                        shift
+						;;
+				--recovery)
+						option_recovery="option_recovery"
+						shift
+						;;
+                -*|--*)
+                        usage
+                        ;;
+                *)
+                        break
+                        ;;
+        esac
+done
+
+lang=$*
+
+if [ $# -lt 1 ]; then
+	usage
+fi
+
+case $lang in
+	ALL)
+		if [ ! -f $mozilladir/$targetapp/locales/shipped-locales ]; then
+			echo "Error: Could not find '$mozilladir/$targetapp/locales/shipped-locales'"
+			exit 1
+		fi
+		langs=$(cat $mozilladir/$targetapp/locales/shipped-locales | awk '{ print $1 }')
+		;;
+	ZA)
+		langs="af en_ZA nr nso ss st tn ts ve xh zu"
+		;;
+esac
+
+# Check for programs that we need to use
+for program in moz2po po2moz txt2po po2txt pomigrate2 podebug
+do
+	if ! which $program >/dev/null; then
+		echo "Missing program: $program"
+		exit 1
+	fi
+done
+
+if [ "$option_mozilla_checkout" != "" ]; then
+	#(cd $mozilladir; cvs up $tag browser/config client.mk build config )
+	if [ ! -d $mozilladir ]; then
+		cvs -d:pserver:anonymous at cvs-mirror.mozilla.org:/cvsroot co $tag $mozilladir/client.mk
+		cvs -d:pserver:anonymous at cvs-mirror.mozilla.org:/cvsroot co $mozilladir/tools/l10n
+	fi
+	(cd $mozilladir
+	cvs up $tag client.mk
+	make -f client.mk l10n-checkout MOZ_CO_PROJECT=$targetapp
+	)
+
+	if [ ! -d $l10ndir ]; then
+		cvs -d:pserver:anonymous at cvs-mirror.mozilla.org:/l10n co -d $l10ndir -l l10n
+	fi
+	(cd $l10ndir
+	
+	for lang in $langs
+	do
+		if [ -d $lang ]; then
+			cvs up $lang
+		else
+			cvs -d:pserver:anonymous at cvs.mozilla.org:/l10n co $lang
+		fi
+	done
+	)
+
+	# Make latest POT file
+	rm -rf $l10ndir/en-US $l10ndir/pot
+	(cd $mozilladir
+	cvs up tools/l10n
+	python tools/l10n/l10n.py --dest="../$l10ndir" --app=$targetapp en-US
+	)
+	(cd $l10ndir
+	moz2po -P --duplicates=msgctxt en-US pot
+	if [ $mozversion != "3" ]; then
+		txt2po -P en-US/browser/README.txt pot/browser/README.txt.pot
+		txt2po -P en-US/browser/os2/README.txt pot/browser/os2/README.txt.pot
+		txt2po -P en-US/mail/README.txt pot/mail/README.txt.pot
+		txt2po -P en-US/mail/os2/README.txt pot/mail/os2/README.txt.pot
+	fi
+	)
+fi
+
+if [ "$option_potpack" != "" ]; then
+	mkdir -p $potpacks
+	timestamp=$(date +"%Y%m%d")
+	tar cjf $potpacks/$targetapp-$mozversion-$timestamp.tar.bz2 $l10ndir/en-US $l10ndir/pot
+	zip -qr9 $potpacks/$targetapp-$mozversion-$timestamp.zip $l10ndir/en-US $l10ndir/pot
+fi
+	
+
+function copyfile {
+	filename=$1
+	language=$2
+	directory=$(dirname $filename)
+	if [ -f $l10ndir/en-US/$filename ]; then
+		mkdir -p $l10ndir/$language/$directory
+		cp -p $l10ndir/en-US/$filename $l10ndir/$language/$directory
+	fi
+}
+
+function copyfiletype {
+	filetype=$1
+	language=$2
+	files=$(cd $l10ndir/en-US; find . -name "$filetype")
+	for file in $files
+	do
+		copyfile $file $language
+	done
+}
+
+function copydir {
+	dir=$1
+	language=$2
+	files=$(cd $l10ndir/en-US/$dir; find . -type f | egrep -v CVS)
+	for file in $files
+	do
+		copyfile $dir/$file $language
+	done
+}
+
+for lang in $langs
+do
+	echo "Language: $lang"
+	buildlang=$(echo $lang | sed "s/_/-/g")
+
+	if [ "$lang" != "en_DE" ]; then
+		if [ "$option_update_translations" != "" ]; then
+			# Get the lastest po and l10n files
+			( cd $podir; svn up $lang)
+			( cd $l10ndir; cvs up $lang)
+		fi
+		
+		# Migrate language from current PO to latest POT
+		if [ -d $podir ]; then
+			rm -rf $podir-updated/.svn
+			cp -rp $podir/.svn $podir-updated
+			rm -rf $podir-updated/$lang
+			cp -rp $podir/$lang $podir-updated
+			rm -f `find $podir-updated/$lang -name "*.po"`
+		fi
+		
+		# Protect the real original PO dir
+		
+		temp_po=`mktemp -d`
+		cp -rp $podir/$lang/* $temp_po
+		
+		##### Hacks - pre po2moz ########
+		# Fix the fact that various editor files are in the wrong place
+		if [ "$lang" == "zu" -o "$lang" == "xh" ]; then
+			rm -rf $temp_po/editor/ui
+			mkdir -p $temp_po/editor/ui
+			mv $temp_po/editor/chrome $temp_po/editor/ui
+		fi
+
+		# Fix for languages that have no Windows codepage
+		if [ "$lang" == "ve" ]; then
+			cp -p $podir/en_ZA/browser/installer/*.properties $temp_po/browser/installer/
+		fi
+
+		pomigrate2 --use-compendium --quiet --pot2po $temp_po $podir-updated/$lang $l10ndir/pot
+	else
+		rm -rf $podir-updated/$lang
+		mkdir -p $podir-updated/$lang
+		poen $l10ndir/pot $podir-updated/$lang
+	fi
+	rm -f `find $podir-updated/$lang -name "*.xhtml.po" -o -name "*.html.po"`
+
+        if [ "$option_debug" != "" -o "$lang" == "en_DE" ]; then
+		(cd $podir-updated/$lang; podebug --errorlevel=traceback --ignore=mozilla . .)
+	fi
+
+	# Create l10n related files
+	[ -d $l10ndir/$buildlang ] && rm -rf `find $l10ndir/$buildlang -name "*.properties" -o -name "*.dtd"`
+	po2moz --errorlevel=traceback --exclude=".svn" $use_fuzzy -t $l10ndir/en-US $podir-updated/$lang $l10ndir/$buildlang
+	
+	##### Hacks - post po2moz ########
+	# Hack to fix creating Thunderbird instaler
+	if [ -f $podir-updated/$lang/mail/installer/installer.inc.po ]; then
+		cp $podir-updated/$lang/mail/installer/installer.inc.po /tmp/installer.$lang.properties.po
+		cp $l10ndir/en-US/mail/installer/installer.inc /tmp/installer.properties
+		po2prop  --progress=none --errorlevel=traceback -t /tmp/installer.properties /tmp/installer.$lang.properties.po /tmp/installer.$lang.properties
+		mv /tmp/installer.$lang.properties $l10ndir/$buildlang/mail/installer/installer.inc
+	fi
+
+	# Copy and update non-translatable files
+	copyfiletype "*.xhtml" $buildlang # Our XHTML and HTML is broken
+	copyfiletype "*.html" $buildlang
+	copyfiletype "*.rdf" $buildlang   # Don't support .rdf files
+	copyfile browser/extra-jar.mn $buildlang
+	copyfile browser/firefox-l10n.js $buildlang
+	copyfile browser/microsummary-generators/list.txt $buildlang
+	copyfile browser/profile/chrome/userChrome-example.css $buildlang
+	copyfile browser/profile/chrome/userContent-example.css $buildlang
+	#copydir browser/searchplugins $buildlang # Only need the list.txt file
+	copyfile browser/searchplugins/list.txt $buildlang
+	copyfile extensions/reporter/chrome/reporterOverlay.properties $buildlang
+	copyfile mail/all-l10n.js $buildlang
+	copyfile toolkit/chrome/global/intl.css $buildlang
+	#copyfile toolkit/installer/windows/charset.mk $buildlang
+
+	# Clean up where we made real tabs \t
+	if [ $mozversion != "3" ]; then
+		sed -i "/^USAGE_MSG/s/\\\t/\t/g" $l10ndir/$buildlang/toolkit/installer/unix/install.it
+		sed -i "/^#define MSG_USAGE/s/\\\t/\t/g" $l10ndir/$buildlang/browser/installer/installer.inc
+	fi
+
+	# Fix bookmark file to point to the locale
+	# FIXME - need some way to preserve this file if its been translated already
+	sed -i "s/en-US/$buildlang/g" $l10ndir/$buildlang/browser/profile/bookmarks.html
+
+	if [ "$option_diff" != "" ]; then
+		(cd $l10ndir; cvs diff --new-file $buildlang > ../diff/$lang-l10n.diff)
+		(cd $podir-updated/$lang; svn diff --diff-cmd diff -x "-u --ignore-matching-lines=^\"POT\|^\"X-Gene" > ../../diff/$lang-po.diff)
+	fi
+	
+	# Cleanup
+	rm -rf $temp_po
+	
+	if [ "$option_langpack" != "" -a -d $mozilladir ]; then
+		# Build XPI and installer
+		( cd $mozilladir; ./configure --disable-compile-environment --disable-xft --enable-application=$targetapp )
+		( 
+		cd $mozilladir/$targetapp/locales;
+		make langpack-$buildlang \
+			MOZ_BRANDING_DIRECTORY=other-licenses/branding/firefox \
+			LANGPACK_FILE='$(_ABS_DIST)'"/install/Firefox-Languagepack-"'$(MOZ_APP_VERSION)'-$langpackrelease'.$(AB_CD)'".xpi"
+		)
+#		( cd $mozilladir/$targetapp/locales; make repackage-win32-installer-af MOZ_BRANDING_DIRECTORY=other-licenses/branding/firefox WIN32_INSTALLER_IN=../../../Firefox-Setup-2.0.exe WIN32_INSTALLER_OUT='$(_ABS_DIST)'"/install/sea/Firefox-Setup-"'$(MOZ_APP_VERSION).$(AB_CD)'".exe" )
+	fi
+done
diff --git a/tools/mozilla/moz_l10n_builder.py b/tools/mozilla/moz_l10n_builder.py
new file mode 100644
index 0000000..aae7633
--- /dev/null
+++ b/tools/mozilla/moz_l10n_builder.py
@@ -0,0 +1,687 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008 Zuza Software Foundation
+#
+# This file is part of the Translate Toolkit.
+#
+# 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/>.
+#
+# moz-l10n-builder - takes a set of PO files, migrates them to a Mozilla build
+# and creates XPIs and Windows .exe files.
+
+"""Contains a Python-port of the moz-l10n-builder bash script."""
+
+# NOTE: Because this script is adapted from a Bash script, some things in here
+#       might be a little less Pythonic. See os.system() calls for more
+#       details.
+
+import glob
+import os
+import shutil
+import StringIO
+import tempfile
+import time
+from subprocess import Popen, PIPE, STDOUT
+
+join = os.path.join
+
+try:
+    # Make sure that all convertion tools are available
+    from translate.convert import moz2po
+    from translate.convert import po2moz
+    from translate.convert import po2prop
+    from translate.convert import txt2po
+except ImportError:
+    raise Exception('Could not find the Translate Toolkit convertion tools. Please check your installation.')
+
+DEFAULT_TARGET_APP = 'browser'
+langpack_release = '1'
+targetapp = 'browser'
+mozversion = '3'
+l10ndir = 'l10n'
+mozilladir = "mozilla"
+podir = "po"
+podir_recover = podir + '-recover'
+podir_updated = podir + '-updated'
+potpacks = "potpacks"
+popacks = 'popacks'
+#: Mapping of possible "targetapp"s to product names.
+products = {'browser': 'firefox'}
+
+devnull = open(os.devnull, 'wb')
+#: Global program options
+options = {'verbose': True}
+USAGE = 'Usage: %prog [options] <langs...|ALL>'
+
+
+class CommandError(StandardError):
+    """Exception raised if a command does not return its expected value."""
+
+    def __init__(self, cmd, status):
+        self.cmd = cmd
+        self.status = status
+
+    def __str__(self):
+        return '"%s" return unexptected status %d' % (self.cmd, self.status)
+
+
+##### Utility Functions #####
+
+
+def delfiles(pattern, path, files):
+    """Delete files with names in C{files} matching glob-pattern C{glob} in the
+        directory specified by C{path}.
+
+        This function is meant to be used with C{os.walk}
+        """
+    path = os.path.abspath(path)
+    match_files = glob.glob(join(path, pattern))
+    for f in files:
+        if join(path, f) in match_files:
+            os.unlink(join(path, f))
+
+
+def run(cmd, expected_status=0, stdout=None, stderr=None, shell=False):
+    global options
+    if options['verbose']:
+        print('>>> %s $ %s' % (os.getcwd(), ' '.join(cmd)))
+    p = Popen(cmd, stdout=stdout, stderr=stderr, shell=shell)
+    cmd_status = p.wait()
+
+    if stdout == PIPE:
+        print(p.stdout.read())
+    elif stderr == PIPE:
+        print(p.stderr.read())
+
+    if cmd_status != expected_status:
+        print('!!! "%s" returned unexpected status %d' % (' '.join(cmd),
+                                                          cmd_status))
+        #raise CommandError(cmd, cmd_status)
+
+
+def get_langs(lang_args):
+    """Returns the languages to handle based on the languages specified on the
+        command-line.
+
+        If "ALL" was specified, the languages are read from the Mozilla
+        product's C{shipped-locales} file. If "ZA" was specified, all South
+        African languages are selected.
+        """
+
+    langs = []
+
+    if isinstance(lang_args, str):
+        if lang_args == 'ALL':
+            lang_args = ['ALL']
+        elif lang_args == 'ZA':
+            lang_args = ['ZA']
+        else:
+            lang_args = []
+
+    if not lang_args:
+        print(USAGE)
+        exit(1)
+
+    for lang in lang_args:
+        if lang == 'ALL':
+            # Get all available languages from the locales file
+            locales_filename = join(mozilladir, targetapp,
+                                    'locales', 'shipped-locales')
+            for line in open(locales_filename).readlines():
+                langcode = line.split()[0]
+                if langcode != 'en-US':
+                    langs.append(langcode)
+
+        elif lang == 'ZA':
+            # South African languages
+            langs = langs + ["af", "en_ZA", "nr", "nso", "ss",
+                             "st", "tn", "ts", "ve", "xh", "zu"]
+        elif lang != 'en-US':
+            langs.append(lang)
+
+    langs = list(set(langs))  # Remove duplicates from langs
+
+    print('Selected languages: %s' % (' '.join(langs)))
+
+    return langs
+#############################
+
+
+def checkout(cvstag, langs):
+    """Check-out needed files from Mozilla's CVS."""
+
+    olddir = os.getcwd()
+    if cvstag != '-A':
+        cvstag = "-r %s" % (cvstag)
+
+    if not os.path.exists(mozilladir):
+        run(['cvs', '-d:pserver:anonymous at cvs-mirror.mozilla.org:/cvsroot',
+             'co', cvstag, join(mozilladir, 'client.mk')])
+        run(['cvs', '-d:pserver:anonymous at cvs-mirror.mozilla.org:/cvsroot',
+             'co', join(mozilladir, 'tools', 'l10n')])
+
+    os.chdir(mozilladir)
+    run(['cvs', 'up', cvstag, 'client.mk'])
+    run(['make', '-f', 'client.mk', 'l10n-checkout',
+         'MOZ_CO_PROJECT=%s' % (targetapp)])
+    os.chdir(olddir)
+
+    if not os.path.exists(l10ndir):
+        run(['cvs', '-d:pserver:anonymous at cvs-mirror.mozilla.org:/l10n',
+             'co', '-d', l10ndir, '-l', 'l10n'])
+
+    os.chdir(l10ndir)
+    for lang in langs:
+        print('    %s' % (lang))
+        buildlang = lang.replace('_', '-')
+        if os.path.isdir(buildlang):
+            run(['cvs', 'up', buildlang])
+        else:
+            run(['cvs', '-d:pserver:anonymous at cvs-mirror.mozilla.org:/l10n',
+                 'co', '-d', buildlang, join('l10n', buildlang)])
+    os.chdir(olddir)
+
+    # Make latest POT file
+    for rmdir in ('en-US', 'pot'):
+        try:
+            shutil.rmtree(join(l10ndir, rmdir))
+        except OSError as oe:
+            # "No such file or directory" errors are fine.
+            # The rest we raise again.
+            if oe.errno != 2:
+                raise oe
+
+    os.chdir(mozilladir)
+    run(['cvs', 'up', join('tools', 'l10n')])
+    run(['python', 'tools/l10n/l10n.py',
+         '--dest=' + join(os.pardir, l10ndir),
+         '--app=' + targetapp,
+         'en-US'])
+    os.chdir(olddir)
+
+    os.chdir(l10ndir)
+    run(['moz2po', '--progress=none', '-P', '--duplicates=msgctxt',
+         'en-US', 'pot'])
+
+    # Delete the help-related POT-files, seeing as Firefox help is now on-line.
+    try:
+        shutil.rmtree(join('pot', 'browser', 'chrome', 'help'))
+    except OSError as oe:
+        # "No such file or directory" errors are fine. The rest we raise again.
+        if oe.errno != 2:
+            raise oe
+
+    if mozversion < '3':
+        for f in ['en-US/browser/README.txt pot/browser/README.txt.pot',
+                  'en-US/browser/os2/README.txt pot/browser/os2/README.txt.pot',
+                  'en-US/mail/README.txt pot/mail/README.txt.pot',
+                  'en-US/mail/os2/README.txt pot/mail/os2/README.txt.pot',]:
+            run(['txt2po', '--progress=none', '-P', f])
+    os.chdir(olddir)
+
+
+def recover_lang(lang, buildlang):
+    print('    %s' % (lang))
+    if not os.path.isdir(join(podir_recover, buildlang)):
+        os.makedirs(join(podir_recover, buildlang))
+
+    run(['moz2po', '--progress=none', '--errorlevel=traceback',
+         '--duplicates=msgctxt', '--exclude=".#*"',
+         '-t', join(l10ndir, 'en-US'),
+         join(l10ndir, buildlang),
+         join(podir_recover, buildlang)])
+
+
+def pack_pot(includes):
+    timestamp = time.strftime('%Y%m%d')
+
+    inc = []
+    for fn in includes:
+        if not os.path.exists(fn):
+            print('!!! Warning: Path "%s" does not exist. Skipped.' % (fn))
+        else:
+            inc.append(fn)
+
+    try:
+        os.makedirs(potpacks)
+    except OSError:
+        pass
+
+    packname = join(potpacks, '%s-%s-%s' % (products[targetapp],
+                                            mozversion, timestamp))
+    run(['tar', 'cjf', packname + '.tar.bz2',
+         join(l10ndir, 'en-US'), join(l10ndir, 'pot')] + inc)
+    run(['zip', '-qr9', packname + '.zip',
+         join(l10ndir, 'en-US'), join(l10ndir, 'pot')] + inc)
+
+
+def pack_po(lang, buildlang):
+    timestamp = time.strftime('%Y%m%d')
+
+    try:
+        os.makedirs(popacks)
+    except OSError:
+        pass
+
+    print('    %s' % (lang))
+    packname = join(popacks, '%s-%s-%s-%s' % (products[targetapp], mozversion,
+                                              buildlang, timestamp))
+    run(['tar', 'cjf', packname + '.tar.bz2', '--exclude', '.svn',
+         join(l10ndir, buildlang), join(podir, buildlang)])
+    run(['zip', '-qr9', packname + '.zip', join(l10ndir, buildlang),
+         join(podir, buildlang)], '-x', '*.svn*')
+
+
+def pre_po2moz_hacks(lang, buildlang, debug):
+    """Hacks that should be run before running C{po2moz}."""
+
+    # Protect the real original PO dir
+    temp_po = tempfile.mkdtemp()
+    shutil.copytree(join(podir, buildlang), join(temp_po, buildlang))
+
+    # Fix for languages that have no Windows codepage
+    if lang == 've':
+        srcs = glob.glob(join(podir, 'en_ZA',
+                              'browser', 'installer', '*.properties'))
+        dest = join(temp_po, buildlang, 'browser', 'installer')
+
+        for src in srcs:
+            shutil.copy2(src, dest)
+
+    old = join(temp_po, buildlang)
+    new = join(podir_updated, buildlang)
+    templates = join(l10ndir, 'pot')
+    run(['pomigrate2', '--use-compendium', '--quiet', '--pot2po',
+         old, new, templates])
+
+    for dirpath, dirnames, filenames in os.walk(join(podir_updated, buildlang)):
+        delfiles("*.html.po", dirpath, dirnames + filenames)
+        delfiles("*.xhtml.po", dirpath, dirnames + filenames)
+
+    if debug:
+        olddir = os.getcwd()
+        os.chdir(join("%s" % (podir_updated), buildlang))
+        run(['podebug', '--progress=none', '--errorlevel=traceback',
+             '--ignore=mozilla',
+             '.', '.'])
+        os.chdir(olddir)
+
+    # Create l10n related files
+    if os.path.isdir(join(l10ndir, buildlang)):
+        for dirpath, dirnames, filenames in os.walk(join(l10ndir, buildlang)):
+            delfiles("*.dtd", dirpath, dirnames + filenames)
+            delfiles("*.properties", dirpath, dirnames + filenames)
+
+    shutil.rmtree(temp_po)
+
+
+def post_po2moz_hacks(lang, buildlang):
+    """Hacks that should be run after running C{po2moz}."""
+
+    # Hack to fix creating Thunderber installer
+    inst_inc_po = join(podir_updated, lang,
+                       'mail', 'installer', 'installer.inc.po')
+    if os.path.isfile(inst_inc_po):
+        tempdir = tempfile.mkdtemp()
+        tmp_po = join(tempdir, 'installer.%s.properties.po' % (lang))
+        shutil.copy2(inst_po, tmp_po)
+
+        inst_inc = join(l10ndir, 'en-US', 'mail', 'installer', 'installer.inc')
+        tmp_properties = join(tempdir, 'installer.properties')
+        shutil.copy2(inst_inc, tmp_properties)
+
+        run(['po2prop', '--progress=none', '--errorlevel=traceback',
+             '-t', tmp_properties,  # -t /tmp/installer.properties
+             tmp_po,                # /tmp/installer.$lang.properties.po
+             tmp_po[:-3]])          # /tmp/installer.$lang.properties
+
+        # mv /tmp/installer.$lang.properties \
+        #    $l10ndir/$buildlang/mail/installer/installer.inc
+        shutil.move(
+            tmp_po[:-3],
+            join(l10ndir, buildlang, 'mail', 'installer', 'installer.inc')
+        )
+
+        shutil.rmtree(tempdir)
+
+    def copyfile(filename, language):
+        enUS = join(l10ndir, 'en-US')
+        dir, filename = os.path.split(filename)
+
+        if dir.startswith(enUS):
+            dir = dir[len(enUS)+1:]
+
+        if os.path.isfile(join(enUS, dir, filename)):
+            try:
+                os.makedirs(join(l10ndir, language, dir))
+            except OSError:
+                pass  # Don't worry if the directory already exists
+            shutil.copy2(
+                join(enUS, dir, filename),
+                join(l10ndir, language, dir)
+            )
+
+    def copyfiletype(filetype, language):
+        for dirpath, dirnames, filenames in os.walk(join(l10ndir, "en-US")):
+            for f in dirnames + filenames:
+                if f.endswith(filetype):
+                    copyfile(join(dirpath, f), language)
+
+    # Copy and update non-translatable files
+    for ft in ('.xhtml', '.html', '.rdf'):
+        copyfiletype(ft, buildlang)
+
+    for f in (join('browser', 'extra-jar.mn'),
+              join('browser', 'firefox-l10n.js'),
+              join('browser', 'README.txt'),
+              join('browser', 'microsummary-generators', 'list.txt'),
+              join('browser', 'profile', 'chrome', 'userChrome-example.css'),
+              join('browser', 'profile', 'chrome', 'userContent-example.css'),
+              join('browser', 'searchplugins', 'list.txt'),
+              join('extensions', 'reporter', 'chrome',
+                   'reporterOverlay.properties'),
+              join('mail', 'all-l10n.js'),
+              join('toolkit', 'chrome', 'global', 'intl.css'),
+              join('toolkit', 'installer', 'windows', 'charset.mk')):
+        copyfile(f, buildlang)
+
+
+def migrate_lang(lang, buildlang, recover, update_transl, debug):
+    print('    %s' % (lang))
+
+    if recover and not os.path.isdir(join(podir, buildlang)):
+        # If we recovered the .po files for lang, but there is no other po
+        # directory, we use the recovered .po files
+        try:
+            os.mkdir(podir)
+        except OSError as oe:
+            # "File exists" errors are fine. The rest we raise again.
+            if oe.errno != 17:
+                raise oe
+
+        shutil.copytree(join(podir_recover, buildlang), join(podir, buildlang))
+
+    if update_transl:
+        olddir = os.getcwd()
+        os.chdir(podir)
+        run(['svn', 'up', buildlang])
+        os.chdir(olddir)
+
+        os.chdir(l10ndir)
+        run(['cvs', 'up', buildlang])
+        os.chdir(olddir)
+
+    # Migrate language from current PO to latest POT
+    if os.path.isdir(join(podir, '.svn')):
+        shutil.rmtree(join(podir_updated, '.svn'))
+        shutil.copytree(join(podir, '.svn'), podir_updated)
+    if os.path.isdir(join(podir_updated, buildlang)):
+        shutil.rmtree(join(podir_updated, buildlang))
+    shutil.copytree(join(podir, buildlang), join(podir_updated, buildlang))
+
+    for dirpath, dirnames, filenames in os.walk(join(podir_updated, buildlang)):
+        delfiles("*.po", dirpath, dirnames + filenames)
+
+    pre_po2moz_hacks(lang, buildlang, debug)
+
+    ###################################################
+    args = [
+        '--progress=none',
+        '--errorlevel=traceback',
+        '--exclude=".svn"',
+        '-t', join(l10ndir, 'en-US'),
+        '-i', join(podir_updated, buildlang),
+        '-o', join(l10ndir, buildlang)
+    ]
+
+    if debug:
+        args.append('--fuzzy')
+
+    run(['po2moz'] + args)
+    ###################################################
+
+    post_po2moz_hacks(lang, buildlang)
+
+    # Clean up where we made real tabs \t
+    if mozversion < '3':
+        run(['sed', '-i', '"/^USAGE_MSG/s/\\\t/\t/g"',
+             join(l10ndir, buildlang,
+                  'toolkit', 'installer', 'unix', 'install.it')])
+        run(['sed', '-i', '"/^#define MSG_USAGE/s/\\\t/\t/g"',
+             join(l10ndir, buildlang,
+                  'browser', 'installer', 'installer.inc')])
+
+    # Fix bookmark file to point to the locale
+    # FIXME - need some way to preserve this file if its been translated
+    # already
+    run(['sed', '-i', 's/en-US/%s/g' % (buildlang),
+         join(l10ndir, buildlang, 'browser', 'profile', 'bookmarks.html')])
+
+
+def create_diff(lang, buildlang):
+    """Create CVS-diffs for all languages."""
+
+    if not os.path.isdir('diff'):
+        os.mkdir('diff')
+
+    print('    %s' % (lang))
+    olddir = os.getcwd()
+
+    os.chdir(l10ndir)
+    outfile = join(os.pardir, 'diff', buildlang + '-l10n.diff')
+    run(['cvs', 'diff', '--newfile', buildlang], stdout=open(outfile, 'w'))
+    os.chdir(olddir)
+
+    os.chdir(join(podir_updated, buildlang))
+    outfile = join(os.pardir, os.pardir, 'diff', buildlang + '-po.diff')
+    run(['svn', 'diff',
+         '--diff-cmd',
+         'diff -x "-u --ignore-matching-lines=^\"POT\|^\"X-Gene"'],
+         stdout=open(outfile, 'w'))
+    os.chdir(olddir)
+
+
+def create_langpack(lang, buildlang):
+    """Builds a XPI and installers for languages."""
+
+    print('    %s' % (lang))
+
+    olddir = os.getcwd()
+
+    os.chdir(mozilladir)
+    run(['./configure', '--disable-compile-environment', '--disable-xft',
+         '--enable-application=%s' % (targetapp)])
+    os.chdir(olddir)
+
+    os.chdir(join(mozilladir, targetapp, 'locales'))
+    langpack_name = 'langpack-' + buildlang
+    moz_brand_dir = join('other-licenses', 'branding', 'firefox')
+    langpack_file = join("'$(_ABS_DIST)'", 'install',
+                         "Firefox-Languagepack-'$(MOZ_APP_VERSION)'-%s.'$(AB_CD)'.xpi" % langpack_release)
+    run(['make', langpack_name, 'MOZ_BRANDING_DIRECTORY=' + moz_brand_dir,
+         'LANGPACK_FILE=' + langpack_file])
+    # The commented out (and very long) line below was found commented
+    # out in the source script as well.
+    #( cd $mozilladir/$targetapp/locales; make repackage-win32-installer-af MOZ_BRANDING_DIRECTORY=other-licenses/branding/firefox WIN32_INSTALLER_IN=../../../Firefox-Setup-2.0.exe WIN32_INSTALLER_OUT='$(_ABS_DIST)'"/install/sea/Firefox-Setup-"'$(MOZ_APP_VERSION).$(AB_CD)'".exe" )
+    os.chdir(olddir)
+
+
+def create_option_parser():
+    """Creates and returns cmd-line option parser."""
+
+    from argparse import ArgumentParser
+
+    parser = ArgumentParser(usage=USAGE)
+
+    parser.add_argument(
+        '-q', '--quiet',
+        dest='verbose',
+        action='store_false',
+        default=True,
+        help='Print as little as possible output.'
+    )
+    parser.add_argument(
+        '--mozilla-product',
+        dest='mozproduct',
+        default=DEFAULT_TARGET_APP,
+        help='Which product to build'
+    )
+    parser.add_argument(
+        '--mozilla-checkout',
+        dest='mozcheckout',
+        action='store_true',
+        default=False,
+        help="Update of the Mozilla l10n files and POT files"
+    )
+    parser.add_argument(
+        '--recover',
+        dest='recover',
+        action='store_true',
+        default=False,
+        help="build PO files from Mozilla's l10n files"
+    )
+    parser.add_argument(
+        '--mozilla-tag',
+        dest='moztag',
+        default='-A',
+        help='The tag to check out of CVS (implies --mozilla-checkout)'
+    )
+    parser.add_argument(
+        '--update-translations',
+        dest='update_translations',
+        action='store_true',
+        default=False,
+        help="Update translations"
+    )
+    parser.add_argument(
+        '--diff',
+        dest='diff',
+        action='store_true',
+        default=False,
+        help='Create diffs for migrated translations and localized Mozilla files'
+    )
+    parser.add_argument(
+        '--potpack',
+        dest='potpack',
+        action='store_true',
+        default=False,
+        help="Create packages of the en-US and POT directories with today's timestamp"
+    )
+    parser.add_argument(
+        '--pot-include',
+        dest='potincl',
+        action='append',
+        default=[],
+        help='Files to include in the POT pack (only used with --potpack)'
+    )
+    parser.add_argument(
+        '--nomigrate',
+        dest='migrate',
+        action='store_false',
+        default=True,
+        help="Don't migrate"
+    )
+    parser.add_argument(
+        '--popack',
+        dest='popack',
+        action='store_true',
+        default=False,
+        help="Create packages of all specified languages' PO-files with today's timestamp"
+    )
+    parser.add_argument(
+        '--langpack',
+        dest='langpack',
+        action='store_true',
+        default=False,
+        help="Build a langpack"
+    )
+    parser.add_argument(
+        '--debug',
+        dest='debug',
+        action='store_true',
+        default=False,
+        help="Add podebug debug markers"
+    )
+
+    return parser
+
+
+def main(langs=['ALL'], mozproduct='browser', mozcheckout=False, moztag='-A',
+         recover=False, potpack=False, potincl=[], migrate=True, popack=False,
+         update_trans=False, debug=False, diff=False, langpack=False,
+         verbose=True):
+    global options
+    options['verbose'] = verbose
+    targetapp = mozproduct
+    langs = get_langs(langs)
+
+    if mozcheckout:
+        print('Checking out')
+        checkout(moztag, langs)
+
+    if potpack:
+        print('Packing POT files')
+        pack_pot(potincl)
+
+    for lang in langs:
+        buildlang = lang.replace('_', '-')
+
+        if recover:
+            print('Recovering')
+            recover_lang(lang, buildlang)
+
+        if migrate:
+            print('Migrating')
+            migrate_lang(lang, buildlang, recover, update_trans, debug)
+
+        if popack:
+            print('Creating PO-packs')
+            pack_po(lang, buildlang)
+
+        if diff:
+            print('Creating diffs')
+            create_diff(lang, buildlang)
+
+        if langpack:
+            print('Creating langpacks')
+            create_langpack(lang, buildlang)
+
+    print('FIN')
+    devnull.close()
+
+
+def main_cmd_line():
+    options, langs = create_option_parser().parse_known_args()
+
+    main(
+        langs=langs,
+        mozproduct=targetapp,
+        mozcheckout=args.mozcheckout,
+        moztag=args.moztag,
+        recover=args.recover,
+        potpack=args.potpack,
+        potincl=args.potincl,
+        migrate=args.migrate,
+        popack=args.popack,
+        update_trans=args.update_translations,
+        debug=args.debug,
+        diff=args.diff,
+        langpack=args.langpack,
+        verbose=args.verbose
+    )
+
+
+if __name__ == '__main__':
+    main_cmd_line()
diff --git a/tools/mozilla/mozcronbuild.py b/tools/mozilla/mozcronbuild.py
new file mode 100755
index 0000000..7db39ef
--- /dev/null
+++ b/tools/mozilla/mozcronbuild.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2008 Zuza Software Foundation
+#
+# This file is part of the Translate Toolkit.
+#
+# 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/>.
+
+import os
+
+from tools.mozilla import moz_l10n_builder
+
+
+MOZDIR = os.path.join(os.path.expanduser('~'), 'mozbuild')
+
+
+def build_langs(langs, verbose):
+    olddir = os.getcwd()
+    os.chdir(MOZDIR)
+
+    moz_l10n_builder.main(
+        langs=langs,
+        mozcheckout=True,
+        recover=True,
+        potpack=True,
+        potincl=['README.mozilla-pot'],
+        popack=True,
+        update_trans=True,
+        diff=False,
+        langpack=True,
+        verbose=verbose
+    )
+
+    os.chdir(olddir)
+
+
+def check_potpacks():
+    """Copy new and check available POT-packs."""
+    pass
+
+
+def update_rss():
+    """Update the RSS feed with the available POT-packs."""
+    pass
+
+
+USAGE = '%prog [<options>]'
+
+
+def create_option_parser():
+    """Creates and returns cmd-line option parser."""
+
+    from argparse import ArgumentParser
+
+    parser = ArgumentParser(usage=USAGE)
+    parser.add_argument(
+        '-q', '--quiet',
+        dest='verbose',
+        action='store_false',
+        default=True,
+        help='Print as little as possible output.'
+    )
+
+    return parser
+
+
+def main(langs, verbose):
+    if not langs:
+        langs = ['ALL']
+
+    if not os.path.isdir(MOZDIR):
+        os.makedirs(MOZDIR)
+
+    build_langs(langs, verbose)
+    check_potpacks()
+    update_rss()
+
+
+def main_cmd_line():
+    """Processes command-line arguments and send them to main()."""
+    args, langs = create_option_parser().parse_args()
+
+    main(langs, args.verbose)
+
+if __name__ == '__main__':
+    main_cmd_line()
diff --git a/tools/mozilla/mozilla-l10n.patch b/tools/mozilla/mozilla-l10n.patch
new file mode 100644
index 0000000..79d1117
--- /dev/null
+++ b/tools/mozilla/mozilla-l10n.patch
@@ -0,0 +1,37 @@
+Index: tools/l10n/l10n.mk
+===================================================================
+RCS file: /cvsroot/mozilla/tools/l10n/l10n.mk,v
+retrieving revision 1.1.2.3
+diff -u -3 -p -r1.1.2.3 l10n.mk
+--- tools/l10n/l10n.mk	16 Feb 2006 14:01:04 -0000	1.1.2.3
++++ tools/l10n/l10n.mk	17 Nov 2006 11:39:27 -0000
+@@ -53,8 +53,28 @@ create-%:
+ 	    echo $(TOPSRCDIR)/../l10n/$*/$$mod already exists; \
+ 	  else \
+ 	    echo Creating $(TOPSRCDIR)/../l10n/$*/$$mod from $(TOPSRCDIR)/$$mod/locales/en-US; \
+-	    mkdirhier ../l10n/$*/$$mod; \
++	    mkdir -p ../l10n/$*/$$mod; \
+ 	    cp -r $(TOPSRCDIR)/$$mod/locales/en-US/* $(TOPSRCDIR)/../l10n/$*/$$mod; \
+ 	    find $(TOPSRCDIR)/../l10n/$*/$$mod -name CVS | xargs rm -rf; \
+ 	  fi; \
+ 	done;
++
++pot-create: create-en-US
++	rm -rf $(TOPSRCDIR)/../l10n/pot
++	moz2po -P --duplicates=msgid_comment $(TOPSRCDIR)/../l10n/en-US $(TOPSRCDIR)/../l10n/pot
++
++pot-count:
++	pocount `find $(TOPSRCDIR)/../l10n/pot -name "*.pot"`
++
++po-count-%:
++	pocount `find $(TOPSRCDIR)/../l10n/$*-po -name "*.po"`
++
++po-create-%: create-en-US
++	moz2po --errorlevel=traceback -t $(TOPSRCDIR)/../l10n/en-US $(TOPSRCDIR)/../l10n/$* $(TOPSRCDIR)/../l10n/$*-po
++
++po-l10n-%:
++	po2moz --errorlevel=traceback -t $(TOPSRCDIR)/../l10n/en-US $(TOPSRCDIR)/../l10n/$*-po $(TOPSRCDIR)/../l10n/$*
++
++po-update-%: pot-create
++	mv $(TOPSRCDIR)/../l10n/$*-po $(TOPSRCDIR)/../l10n/$*-po.old
++	pot2po -t $(TOPSRCDIR)/../l10n/$*-po.old $(TOPSRCDIR)/../l10n/pot $(TOPSRCDIR)/../l10n/$*-po
diff --git a/tools/mozilla/mozzy.sh b/tools/mozilla/mozzy.sh
new file mode 100755
index 0000000..929712d
--- /dev/null
+++ b/tools/mozilla/mozzy.sh
@@ -0,0 +1,398 @@
+#!/bin/bash -e
+# Based heavily on Rail Aliev's translate-toolkit-mozilla script:
+# http://bitbucket.org/rail/translate-toolkit-mozilla
+
+for external in buildxpi.py get_moz_enUS.py moz2po pomigrate2 po2moz wget
+do
+	if [ -z `which $external` ]; then
+		echo "Could not find $external in PATH"
+		exit 1
+	fi
+done
+
+CWD=$(pwd)
+GECKO_VERSION="1.9.2"
+LANGS="xx"
+PRODUCT="browser"
+#L10N_BASE_URL="http://hg.mozilla.org/l10n-central"
+L10N_BASE_URL="http://hg.mozilla.org/releases/l10n-mozilla-$GECKO_VERSION"
+L10N_DIR="l10n"
+LANGPACK_DIR="xpi"
+PHASEDIRS="config1 config2 configx install lang mac never notnb other security unix user1 user2 user3 user4 win"
+PO_URL_HG=
+PO_URL_HTTP=
+PO_URL_SVN=
+SOURCE_DIR="mozilla-$GECKO_VERSION"
+#SOURCE_URL="http://hg.mozilla.org/mozilla-central"
+SOURCE_URL="http://hg.mozilla.org/releases/mozilla-$GECKO_VERSION"
+VERBOSE=1
+
+debuglog() {
+	[[ x$VERBOSE != x ]] && echo ">>> $*"
+}
+
+function usage() {
+	echo "Usage `basename $0` [options]"
+	echo
+	echo "Options:"
+	echo "   --fennec                 - Set defaults for Fennec building. Implies:"
+	echo "                                  --l10n-dir=l10n-central"
+	echo "                                  --l10n-repo-url=http://hg.mozilla.org/l10n-central/"
+	echo "                                  --lang-po-url=http://pootle.locamotion.org/archives/fennec/fennec-%LANG%.tar.bz2"
+	echo "                                  --moz-product=mobile"
+	echo "                                  --src-dir=mobile"
+	echo "                                  --src-repo-url=http://hg.mozilla.org/mobile-browser/"
+	echo "   --gecko-ver=<version>    - The Gecko version to build. Equivalent to (replace %VER% with given value):"
+	echo "                                  --l10n-repo-url=http://hg.mozilla.org/releases/l10n-mozilla-%VER%"
+	echo "                                  --src-dir=mozilla-%VER%"
+	echo "                                  --src-repo-url=http://hg.mozilla.org/releases/mozilla-%VER%"
+	echo "   --l10n-dir=<dir>         - The directory where Mozilla l10n files live (default: $L10N_DIR)"
+	echo "   --l10n-repo-url=<url>    - The base URL (without language code) of Mozilla l10n repositories (default: $L10N_BASE_URL)"
+	echo "   --lang-po-hg=<url>       - The Mercurial repository URL where language PO files should be checked out from"
+	echo "                              (%LANG% is replaced with the language code)"
+	echo "   --lang-po-http=<url>     - The URL where a tarball of language PO files should be downloaded from"
+	echo "                              (%LANG% is replaced with the language code)"
+	echo "   --lang-po-svn=<url>      - The Subversion repository URL where language PO files should be checked out from"
+	echo "                              (%LANG% is replaced with the language code)"
+	echo "   --langs=aa[,bb[,cc]]     - Handle specified languages (default: $LANGS)"
+	echo "   --moz-product=<prod>     - The Mozilla product name (default: $PRODUCT)"
+	echo "   --skip-en                - Don't extract en-US from the Mozilla source tree"
+	echo "   --skip-lang-get-po       - Don't get language PO files from Pootle server"
+	echo "   --skip-lang-mozgen       - Don't generate Mozilla l10n files from updated PO files"
+	echo "   --skip-lang-pull         - Don't pull Mozilla l10n files from Mozilla repositories"
+	echo "   --skip-lang-update       - Don't update the language's PO files from its VCS"
+	echo "   --skip-lang-update-po    - Don't update PO files to current POT files"
+	echo "   --skip-lang-xpi          - Don't build language packs"
+	echo "   --skip-langs             - Skip processing of individual languages"
+	echo "   --skip-pot               - Don't create POT files (it should already exist)"
+	echo "   --skip-src-pull          - Don't do \"hg pull\" in Mozilla source repository directory"
+	echo "   --src-dir=<dir>          - The directory containing the Mozilla source repository (default: $SOURCE_DIR)"
+	echo "   --src-repo-url=<url>     - The URL of the Mozilla source repository (default: $SOURCE_URL)"
+	echo "   --xpi-dir=<dir>          - The output directory for language packs (default: $LANGPACK_DIR)"
+	exit 1
+}
+
+SKIP_EN=
+SKIP_LANG_GETPO=
+SKIP_LANG_MOZGEN=
+SKIP_LANG_PULL=
+SKIP_LANG_UPDATE=
+SKIP_LANG_UPDATE_PO=
+SKIP_LANG_XPI=
+SKIP_LANGS=
+SKIP_POT=
+SKIP_SRC_PULL=
+
+##### COMMAND-LINE ARGUMENT PROCESSING #####
+while true
+do
+	case $1 in
+		--fennec)
+			L10N_DIR="l10n-central"
+			L10N_BASE_URL="http://hg.mozilla.org/l10n-central/"
+			PO_URL_HTTP="http://pootle.locamotion.org/archives/fennec/fennec-%LANG%.tar.bz2"
+			PRODUCT="mobile"
+			SOURCE_DIR="mobile"
+			SOURCE_URL="http://hg.mozilla.org/mobile-browser/"
+			shift
+			;;
+		--gecko-ver=*)
+			GECKO_VERSION=$(echo $1 | sed 's/\-\-gecko\-ver=//')
+			L10N_BASE_URL="http://hg.mozilla.org/releases/l10n-mozilla-$GECKO_VERSION"
+			SOURCE_DIR="mozilla-$GECKO_VERSION"
+			SOURCE_URL="http://hg.mozilla.org/releases/mozilla-$GECKO_VERSION"
+			shift
+			;;
+		--l10n-dir=*)
+			L10N_DIR=$(echo $1 | sed 's/\-\-l10n\-dir=//')
+			shift
+			;;
+		--l10n-repo-url=*)
+			L10N_BASE_URL=$(echo $1 | sed 's/\-\-l10n\-repo\-url=//')
+			shift
+			;;
+		--lang-po-hg=*)
+			PO_URL_HG=$(echo $1 | sed 's/\-\-lang\-po\-hg=//')
+			shift
+			;;
+		--lang-po-http=*)
+			PO_URL_HTTP=$(echo $1 | sed 's/\-\-lang\-po\-http=//')
+			shift
+			;;
+		--lang-po-svn=*)
+			PO_URL_SVN=$(echo $1 | sed 's/\-\-lang\-po\-svn=//')
+			shift
+			;;
+		--langs=*)
+			LANGS=$(echo $1 | sed 's/\-\-langs=//; s/,/ /g')
+			shift
+			;;
+		--moz-product=*)
+			PRODUCT=$(echo $1 | sed 's/\-\-moz\-product=//')
+			shift
+			;;
+		--skip-en)
+			# Don't extract en-US from the source tree
+			SKIP_EN=1
+			shift
+			;;
+		--skip-lang-get-po)
+			# Don't get language PO files from the Pootle server
+			SKIP_LANG_GETPO=1
+			shift
+			;;
+		--skip-lang-mozgen)
+			# Don't generate Mozilla l10n files from updated PO files
+			SKIP_LANG_MOZGEN=1
+			shift
+			;;
+		--skip-lang-pull)
+			# Don't pull Mozilla l10n files from Mozilla repository
+			SKIP_LANG_PULL=1
+			shift
+			;;
+		--skip-lang-update)
+			# Don't update the language's PO files from its VCS
+			SKIP_LANG_UPDATE=1
+			shift
+			;;
+		--skip-lang-update-po)
+			# Don't update PO files to current POT files
+			SKIP_LANG_UPDATE_PO=1
+			shift
+			;;
+		--skip-lang-xpi)
+			# Don't build language packs
+			SKIP_LANG_XPI=1
+			shift
+			;;
+		--skip-langs)
+			# Skip processing of individual languages
+			SKIP_LANGS=1
+			shift
+			;;
+		--skip-pot)
+			# Don't create POT files (it should already exist)
+			SKIP_POT=1
+			shift
+			;;
+		--skip-src-pull)
+			# Don't do "hg pull" in Mozilla source repo dir
+			SKIP_SRC_PULL=1
+			shift
+			;;
+		--src-dir=*)
+			SOURCE_DIR=$(echo $1 | sed 's/\-\-src\-dir=//')
+			shift
+			;;
+		--src-repo-url=*)
+			SOURCE_URL=$(echo $1 | sed 's/\-\-src\-repo\-url=//')
+			shift
+			;;
+		--xpi-dir=*)
+			LANGPACK_DIR=$(echo $1 | sed 's/\-\-xpi\-dir=//')
+			shift
+			;;
+		-*|--*)
+			echo "Unknown option: $1"
+			usage
+			;;
+		*)
+			break
+			;;
+	esac
+done
+############################################
+
+for dir in $L10N_DIR $LANGPACK_DIR po po-updated
+do
+	if [ ! -d $dir ]; then
+		debuglog "Creating directory: $dir"
+		mkdir -p $dir
+		[ ! -d $dir ] && echo "Unable to create directory: $dir" && exit 2
+	fi
+done
+
+##### FUNCTIONS #####
+update_hg() {
+	url=$1
+	dir=$2
+	hgfailed=
+	if [ -d $dir -a -d $dir/.hg ]; then
+		debuglog "Updating repository: $dir"
+		pushd $dir > /dev/null
+		hg revert --all -r default --no-backup
+		hg pull -u
+		hg update -C
+		popd > /dev/null
+	else
+		[ -d $dir ] && rm -rf $dir
+		debuglog "Cloning repository $url to $dir"
+		mkdir -p $dir
+		rmdir $dir
+		hg clone $url $dir || hgfailed=1
+	fi
+
+	true
+}
+
+get_po_files() {
+	lang=$1
+	if [[ x$PO_URL_HG == x && x$PO_URL_HTTP == x && x$PO_URL_SVN == x ]]; then
+		return
+	fi
+
+	if [ -d po/$lang ]; then
+		debuglog "Language directory exists: po/$lang. Moving to po/$lang.$$."
+		if [ -d po/$lang.$$ ]; then
+			debuglog "Backup language directory exists: po/$lang.$$. Deleting it."
+			rm -rm po/$lang.$$
+		fi
+		mv po/${lang} po/$lang.$$
+	fi
+
+	if [[ x$PO_URL_HTTP != x ]]; then
+		wget_url=$(echo $PO_URL_HTTP | sed "s/%LANG%/$lang/g")
+		debuglog "Getting PO files from HTTP server: $wget_url"
+		wget $wget_url -O po/$lang.tar.bz2
+		if [ $? != 0 ]; then
+			echo "Failed to get PO files for language $lang from $wget_url"
+			return
+		fi
+
+		pushd po > /dev/null
+		tar xf $lang.tar.bz2
+
+		# Check if the PO files are split up into phases
+		phased=1
+		for phase in $PHASEDIRS; do
+			if [ ! -d $lang/$phase ]; then
+				phased=
+				break
+			fi
+		done
+
+		# If it is split up into phases, copy all files to $lang/
+		if [ -n $phased ]; then
+			for phase in $PHASEDIRS; do
+				cp -R $lang/$phase/* $lang
+				rm -rf $lang/$phase
+			done
+		fi
+
+		popd > /dev/null
+	elif [[ x$PO_URL_SVN != x ]]; then
+		svn_url=$(echo $PO_URL_SVN | sed "s/%LANG%/$lang/g")
+		debuglog "Checking out PO files from Subversion repository: $svn_url"
+		(cd po; svn checkout $svn_url $lang)
+	elif [[ x$PO_URL_HG != x ]]; then
+		hg_url=$(echo $PO_URL_HG | sed "s/%LANG%/$lang/g")
+		debuglog "Cloning PO files from Mercurial repository: $hg_url"
+		(cd po; hg clone $hg_url $lang)
+	fi
+}
+
+update_po() {
+	lang=$1
+	debuglog "<update_po lang=$lang>"
+	po_dir=po/$lang
+	po_updated_dir=po-updated/$lang
+
+	# Update from VCS
+	[ -d $po_dir/.hg ]  && (cd $po_dir && hg revert --all -r default --no-backup && hg pull -u && hg update -C)
+	[ -d $po_dir/.svn ] && (cd $po_dir && svn up)
+
+	rm -rf $po_updated_dir
+	# Preserve VCS metadata
+	cp -R $po_dir $po_updated_dir
+	find $po_updated_dir -name '*.po' -exec rm -f '{}' \;
+
+	if [[ x$SKIP_LANG_UPDATE_PO == x ]]; then
+		tempdir=`mktemp -d`
+		cp -R $po_dir $tempdir
+		pomigrate2 --use-compendium --quiet --pot2po $tempdir $po_updated_dir pot
+		rm -rf $tempdir
+	fi
+	debuglog "</update_po lang=$lang>"
+}
+
+merge_back() {
+	lang=$1
+	debuglog "<merge_back lang=$lang>"
+	if [ ! -d po-updated/$lang ]; then
+		mkdir -p po-updated/$lang
+		echo "Could not find updated PO directory: $(pwd)/po-updated/$lang. Creating it..."
+	fi
+	po2moz --progress=none --errorlevel=traceback --exclude=".svn" --exclude=".hg*" \
+		-t en-US -i po-updated/$lang -o $L10N_DIR/$lang
+	debuglog "</merge_back lang=$lang>"
+}
+
+build_xpi() {
+	lang=$1
+	debuglog "<buildxpi lang=$lang>"
+	if [ -d $L10N_DIR/$lang ]; then
+		buildxpi.py -d -L $L10N_DIR -s $SOURCE_DIR -o $LANGPACK_DIR $lang || true
+	else
+		echo "Could not find l10n directory: $L10N_DIR/$lang"
+	fi
+	debuglog "</buildxpi lang=$lang>"
+}
+#####################
+
+
+##### MAIN START #####
+if [[ x$SKIP_SRC_PULL == x ]]; then
+	# Update source repository
+	update_hg $SOURCE_URL $SOURCE_DIR
+fi
+
+enUSchanged=
+if [[ x$SKIP_EN == x ]]; then
+	# Get en-US files
+	[ -d en-US.old ] && rm -rf en-US.old
+	[ -d en-US ] && mv en-US{,.old} || enUSchanged=1
+
+	debuglog "Extracting en-US for product \"$PRODUCT\" from $SOURCE_DIR"
+	srcdir=$SOURCE_DIR
+	#[ $PRODUCT = 'fennec' ] && srcdir=""
+	get_moz_enUS.py -s $srcdir -d . -p "$PRODUCT" -v
+
+	if [ -d en-US.old ]; then
+		diff en-US{,.old} > /dev/null
+		[ $? != 0 ] && echo "en-US changed" && enUSchanged=1
+		rm -rf en-US.old
+	fi
+fi
+
+if [[ x$SKIP_POT == x ]]; then
+	# Generate POT files
+	if [[ x$enUSchanged != x ]]; then
+		if [ -d pot ]; then
+			rm -rf pot
+		fi
+		debuglog "Generating POT files from en-US"
+		moz2po --progress=none -P --duplicates=msgctxt en-US pot
+	else
+		debuglog "No changes in en-US. POT generation skipped."
+	fi
+fi
+
+[[ x$SKIP_LANGS == x ]] || exit 0
+
+# Update language l10n files
+for l in $LANGS; do
+	debuglog "<language name=$l>"
+	[[ x$SKIP_LANG_PULL == x ]] && update_hg $L10N_BASE_URL/$l $L10N_DIR/$l
+	[ ! -d "$L10N_DIR/$l" ] && cp -R en-US "$L10N_DIR/$l"
+	#FIXME: The following should be done by moz2po, ie. moz2po should copy files from
+	#       the en-US that is not present in the translation.
+	[ ! -d "$L10N_DIR/$l" ] && mkdir -p $L10N_DIR/$l && cp -R en-US/* $L10N_DIR/$l
+	[[ x$SKIP_LANG_GETPO == x ]] && get_po_files $l
+	[ ! -d po/$l ] && echo "!!! Skipping language $l" && continue
+	[[ x$SKIP_LANG_UPDATE == x && x$enUSchanged == x ]] && update_po $l
+	[[ x$SKIP_LANG_MOZGEN == x ]] && merge_back $l
+	[[ x$SKIP_LANG_XPI == x ]]    && build_xpi $l
+	debuglog "</language>"
+done
+######################
diff --git a/tools/mozilla/postinstall.sh b/tools/mozilla/postinstall.sh
new file mode 100755
index 0000000..810afe7
--- /dev/null
+++ b/tools/mozilla/postinstall.sh
@@ -0,0 +1,90 @@
+#!/bin/bash
+
+# Apt-install various things necessary for Ruby, guest additions,
+# etc., and remove optional things to trim down the machine.
+apt-get -y update
+apt-get -y remove apparmor
+apt-get -y install linux-headers-$(uname -r) build-essential
+apt-get -y install zlib1g zlib1g-dev libxml2 libxml2-dev libxslt-dev libssl-dev openssl libreadline5-dev
+apt-get clean
+
+# Remove this file to avoid dhclient issues with networking
+rm -f /etc/udev/rules.d/70-persistent-net.rules
+
+# Setup sudo to allow no-password sudo for "admin". Additionally,
+# make "admin" an exempt group so that the PATH is inherited.
+cp /etc/sudoers /etc/sudoers.orig
+sed -i -e '/Defaults\s\+env_reset/a Defaults\texempt_group=admin' /etc/sudoers
+sed -i -e 's/%admin ALL=(ALL) ALL/%admin ALL=NOPASSWD:ALL/g' /etc/sudoers
+
+# Configure SSH specifically:
+# This tells SSH not to look up the remote hostname for SSHing. This
+# speeds up connection and helps when you're connecting with no outside
+# internet connection.
+echo 'UseDNS no' >> /etc/ssh/sshd_config
+
+# Install NFS client
+apt-get -y install nfs-common
+
+# Install insecure Vagrant SSH keys
+mkdir /home/vagrant/.ssh
+chmod 700 /home/vagrant/.ssh
+cd /home/vagrant/.ssh
+wget --no-check-certificate 'http://github.com/mitchellh/vagrant/raw/master/keys/vagrant.pub' -O authorized_keys
+chown -R vagrant /home/vagrant/.ssh
+
+# Install VirtualBox guest additions
+VBOX_VERSION=$(cat /home/vagrant/.vbox_version)
+cd /tmp
+wget http://download.virtualbox.org/virtualbox/$VBOX_VERSION/VBoxGuestAdditions_$VBOX_VERSION.iso
+mount -o loop VBoxGuestAdditions_$VBOX_VERSION.iso /mnt
+sh /mnt/VBoxLinuxAdditions.run
+umount /mnt
+rm VBoxGuestAdditions_$VBOX_VERSION.iso
+
+# Remove items used for building, since they aren't needed anymore
+apt-get -y remove linux-headers-$(uname -r) build-essential
+apt-get -y autoremove
+
+# Zero free space to aid VM compression
+dd if=/dev/zero of=/EMPTY bs=1M
+rm -f /EMPTY
+
+# Removing leftover leases and persistent rules
+echo "cleaning up dhcp leases"
+rm /var/lib/dhcp3/*
+
+# Make sure Udev doesn't block our network
+# http://6.ptmc.org/?p=164
+echo "cleaning up udev rules"
+rm /etc/udev/rules.d/70-persistent-net.rules
+mkdir /etc/udev/rules.d/70-persistent-net.rules
+rm -rf /dev/.udev/
+rm /lib/udev/rules.d/75-persistent-net-generator.rules
+
+echo "Adding a 2 sec delay to the interface up, to make the dhclient happy"
+echo "pre-up sleep 2" >> /etc/network/interfaces
+
+# Fix /etc/hosts by removing the 127.0.1.1 line and then adding
+# a new one after the localhost line
+sed -i -e '/^127\.0\.1\.1/d' /etc/hosts
+sed -i -e "/^127\.0\.0\.1/a 127.0.1.1\t`hostname`" /etc/hosts
+
+
+# Make sure we have a build environment, 
+apt-get -y install subversion git mercurial # version control
+apt-get -y install patchutils colordiff # development general
+apt-get -y install python-py # Translate development
+apt-get -y install autoconf2.13 zip unzip yasm # Mozilla langpack building
+apt-get -y install vim # edit files
+apt-get -y install gettext python-levenshtein python-lxml # msgcat and friends
+
+# Mozilla compare-locales
+apt-get -y install python-pip 
+easy_install -U compare-locales
+
+# SSH customisations
+cp ~/.ssh/ssh_host/config ~/.ssh
+#cp ~/.ssh/ssh_host/id_rsa ~/.ssh/id_rsa
+
+exit
diff --git a/tools/mozilla/setup_mozilla.sh b/tools/mozilla/setup_mozilla.sh
new file mode 100755
index 0000000..3d179d9
--- /dev/null
+++ b/tools/mozilla/setup_mozilla.sh
@@ -0,0 +1,14 @@
+# Checkout tools if it doesn't exist
+mkdir -p /vagrant/firefox
+ln -s /vagrant/firefox
+cd firefox
+rm -f build_firefox.sh
+wget https://raw.github.com/translate/translate/master/tools/mozilla/build_firefox.sh
+chmod +x build_firefox.sh
+./build_firefox.sh af
+rm build_firefox.sh
+ln -s tools/translate/tools/mozilla/build_firefox.sh
+
+# Things we need to do
+# TODO
+# Copy .hgrc file to the correct place and any other needed configurations e.g. Subversion and friends.  If none exist then use a default.
diff --git a/tools/pep8.sh b/tools/pep8.sh
new file mode 100755
index 0000000..32d3bf2
--- /dev/null
+++ b/tools/pep8.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# Usage:
+# blank - run all tests
+# check numbers - run that specific test
+# travis - run a set of checks that should always pass
+
+exclude_toolkit=\
+selector.py,\
+wsgiserver,\
+mozilla-l10n,\
+build
+
+exclude_pootle=\
+djblets,\
+_site
+
+exclude=\
+$exclude_toolkit,\
+$exclude_pootle
+
+if [ -f "$1" -o -d "$1" ]; then
+	files=$1
+	shift
+else
+	files="."
+fi
+
+if [ "$1" == "travis" ]; then
+	# For codes see http://pep8.readthedocs.org/en/latest/intro.html#error-codes
+	select="--select=E10,E11,E261,E262,E27,E401,E70,E711,E721,W191,W291,W292,W293,W391,W60"
+	count="--count"
+elif [ $1 ]; then
+	select="--select=$1"
+else
+	quiet="-qq"
+	ignore="--ignore="
+fi
+
+pep8 $quiet \
+     $count \
+     --statistics \
+     --exclude=$exclude \
+     $select \
+     $ignore \
+     $files
diff --git a/tools/phase b/tools/phase
new file mode 100755
index 0000000..4ca6934
--- /dev/null
+++ b/tools/phase
@@ -0,0 +1,669 @@
+#!/bin/bash
+#
+# Copyright 2005 Zuza Software Foundation
+#
+# This file is part of The Translate Toolkit.
+#
+# The Translate Toolkit 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
+
+
+# phase - is a set of commands that allows you to break up a translation package 
+# and create phases to send to translators.  It will manage the return, checking and
+# integration of changes.  Ultimately this should convert to Python so that
+# other people on less well known platforms like Windows can use them.
+
+
+# Commands error handling
+
+function error_notacommand {
+	echo "$1 is not a valid command"
+	usage
+}
+
+function usagecommands {
+	cat <<EOF
+Commands:
+	makephaselist <template-dir> <new-phase-list-name> -- creates a phase list
+	listphases <phase-list> -- lists the different phases that appear in the phase-list file
+	listfiles <phase-list> <phase-name> -- list all files for the given phase in the phase-list file
+	checkphaselist <language-dir> <phase-list> -- checks to see which files are not included in the phaselist
+	countpo <language-dir> <phase-list> <phase-name> -- counts PO file in the given phase
+	countpot <template-dir> <phase-list> <phase-name> -- counts POT file in the given phase
+	missingpo <language-dir> <phase-list> <phase-name> -- lists files that have not been returned for a phase
+	packpot <template-dir> <phase-list> <phase-name> -- packs all POT files for a given phase into a ZIP file
+	packpo <language-dir> <phase-list> <phase-name> -- packs all PO files for a given phase into a ZIP file
+	packall <template-dir> <phase-list> -- packs all phases found in the phase list
+	packallpo <language-dir> <phase-list> -- packs all phases found in the phase list for the given language
+	countmismatch <language-dir> <template-dir> <phase-list> <phase-name> -- compares the source word count between PO and POT to determine if there are any file errors.
+	editpo <language-dir> <phase-list> <phase-name> -- edit the PO files in a phase
+	editpochecks <language> <phase-list> <phase-name> -- edit the PO checks output by checkpo
+	editconflicts <language-dir> <phase-list> <phase-name> -- edit the extracted conconflict items
+	checkpo <language-dir> <phase-list> <phase-name> [pofilter options] -- run pofilter checks against the given phase
+	greppo <language-dir> <phase-list> <phase-name> [pogrep options] -- run pogrep against the given phase
+	mergepo <language> <phase-list> <phase-name> -- merge the checks back into the main language directory
+	conflictpo <language-dir> <phase-list> <phase-name> [poconflict options] -- run poconflict checks against the given phase
+	diffpo <language-dir> <phase-list> <phase-name> -- perform a cvs diff for the phase
+	cvslog <language-dir> <phase-list> <phase-name> -- perform a cvs log against files in the phase
+	lastlog <language-dir> <phase-list> <phase-name> -- retreives the last cvs log entry for each file in a phase
+	cvsadd <languages-dir> <phase-list> <phase-name> -- CVS adds files and directories that are not already in CVS
+	reviewpo <language-dir> <phase-list> <phase-name> [pofilter options] -- extract items marked for review for the given phase
+	editreviews <language-dir> <phase-list> <phase-name> -- edit the extracted review items
+	countreviews <language-dir> <phase-list> <phase-name> -- count the number of strings and words under review
+	checkinpo <language-dir> <phase-list> <phase-name> -- cvs checkin the files in the given phase
+	creategsi <language-dir> <en-US.gsi> <traget-language> [scp target destination] -- creates a BZ2 GSI/SDF file for the language against the en-US GSI file
+	reviewsinout <language> <phase-name> -- counts the number of review files returned vs sent and shows which are missing 
+	reviewsdiff <language> <phase-name> -- create a diff between what was sent for review and what was returned
+
+Note:
+	A phase-name of ALL will perform the operation against all phases.
+	phase-name can be a regex that usable by egrep eg. "(firefox|thunderbird)"
+EOF
+	#emailpot <template-dir> <phase-list> <phase-name> <emails> -- emails the POT files with wordcount to the addresses
+	#emailpo <language-dir> <phase-list> <phase-name> <emails> -- emails the PO files with wordcount to the addresses
+	#emailreview <language> <phase-name> <emails> -- emails the prepared review files to the addresses
+}
+
+function usage() {
+	programname=`basename $0`
+    	echo "Usage: $programname <command> options"
+	usagecommands
+	exit 1
+}
+
+# Operation
+
+function report {
+	if [ "$*" == "DONE" ]; then
+		echo " done."
+	else
+		echo -n "$* "
+	fi
+}
+
+function getphasefiles {
+	# Returns a list of files that are valid for this phase
+	filelist=$1
+	phase=$2
+	if [ "$phase" != "ALL" ]; then
+                for i in `echo $phase | sed "s/,/ /g"`
+		do
+			egrep --count "^$i\b" $filelist > /dev/null
+			if [ $? -ne 0 ]; then
+				echo "No such phase exists" > /dev/stderr
+				exit 1
+			fi
+			egrep "^$i\b" $filelist
+		done
+	else
+		cat $filelist
+	fi | cut -f 2 | sort
+}
+
+function getphases {
+	# Retuns a list of all the defines phases
+	filelist=$1
+	cut -f1 $filelist | sort | uniq
+}
+
+function countpo {
+	# Counts PO files
+	directory=$1
+	filelist=$2
+	phase=$3
+	files=$(getphasefiles $filelist $phase)
+	cd $directory
+	pocount $files
+}
+
+function countreviews {
+	# Counts PO files for review
+	language=$1
+	filelist=$2
+	phase=$3
+	pocount $(find $language-$phase-review -name "*.po")
+}
+
+function countpot {
+	# Counts POT files
+	directory=$1
+	filelist=$2
+	phase=$3
+	files=$(getphasefiles $filelist $phase | sed "s/\.po$/\.pot/")
+	cd $directory
+	pocount $files
+}
+
+function missingpo {
+	# Reports PO files that are missing from the filelist
+	directory=$1
+	filelist=$2
+	phase=$3
+	files=$(getphasefiles $filelist $phase)
+	cd $directory
+	for file in $files
+	do
+		if [ ! -f $file ]; then
+			echo $file
+			missingfiles=$( echo $missingfiles $file)
+		fi
+	done
+}
+
+function copy_po_to_temp_dir {
+	basedir=$1
+	tempdir=$2
+	shift 2
+	files=$*
+	for file in $files
+	do
+		fromdir=$(dirname $file)	
+		mkdir -p $tempdir/$fromdir
+		cp -p $basedir/$file $tempdir/$fromdir
+	done
+}
+
+function packpot {
+	# Packs POT files that match the file list
+	directory=$1
+	filelist=$2
+	phase=$3
+    	outdir=phase$phase-templates
+	rm -rf $outdir
+	files=$(getphasefiles $filelist $phase | sed "s/\.po$/\.pot/")
+		report "Packpot: creating"
+	copy_po_to_temp_dir $directory $outdir $files
+		report ": wordcount"
+	pocount $(find $outdir -name "*.pot") > $outdir/wordcount.txt
+		report ', PO'
+	for potfile in $(find $outdir -name "*.pot")
+	do
+		pofile=$(echo $potfile | sed "s/\.pot$/\.po/")
+		msginit --no-translator --locale=af_ZA -i $potfile -o $pofile > /dev/null 2>&1
+	done
+		report ", CSV"
+	po2csv --progress=none $outdir $outdir
+		report ", tarball"
+	tar czf $outdir.tar.gz $outdir
+		report ", zip"
+	zip -qr9 $outdir.zip $outdir
+		report DONE
+}	
+
+function packpo {
+	# Packs PO files that match the file list
+	language=$1
+	filelist=$2
+	phase=$3
+	outdir=$language-$phase-translations
+	rm -rf $outdir
+	files=$(getphasefiles $filelist $phase)
+		report "Packpo: creating"
+	copy_po_to_temp_dir $language $outdir $files
+		report ": wordcount"
+	pocount $(find $outdir -name "*.po") > $outdir/wordcount.txt
+		report ", CSV"
+	po2csv --progress=none $outdir $outdir
+		report ", tarball"
+	tar czf $outdir.tar.gz $outdir
+		report ", zip"
+	zip -qr9 $outdir.zip $outdir
+		report DONE
+}	
+
+function packall {
+	# Pack all phases in a project
+		report "Packing all phases:"
+	for phase in $(getphases $2)
+	do
+			report $phase
+		packpot $1 $2 $phase
+	done
+		report DONE
+}
+
+function packallpo {
+	# Pack all phases in a project for a language
+	language=$1
+	filelist=$2
+		report "Packing all phases:"
+	for phase in $(getphases $2)
+	do
+			report $phase
+		packpo $1 $2 $phase
+	done
+		report DONE
+}
+
+function count_source_words {
+	file=$1
+	pocount --csv $file | tail -1 | cut -d"," -f10
+}
+
+function countmismatch {
+	# Checks that the source wordcount matches in each returned file in a phase
+	language=$1
+	templates=$2
+	filelist=$3
+	phase=$4
+	files=$(getphasefiles $filelist $phase)
+	for file in $files
+	do
+		if [ -f $language/$file ]; then
+			powords=$(count_source_words $language/$file)
+		else
+			powords=0
+		fi
+		potfile=$templates/$(echo $file | sed "s/\.po$/.pot/")
+		if [ -f $potfile ]; then
+			potwords=$(count_source_words $potfile)
+		else
+			potwords=0
+		fi
+		if [ $powords -ne $potwords ]; then
+			echo "Mismatch: $file - expected $potwords got $powords"
+		fi
+	done
+}
+
+function editpo {
+	# Edit the PO files for this phase
+	language=$1
+	filelist=$2
+	phase=$3
+	editor="vim"
+	files=$(getphasefiles $filelist $phase)
+	(cd $language; exec $editor $files)
+}
+
+function editreviews {
+	# Edit the PO files for this phase
+	language=$1
+	phaselist=$2
+	phase=$3
+	editor="vim"
+	files=$(getphasefiles $phaselist $phase)
+	if [ -d $language-$phase-review ]; then
+		for file in $files
+		do
+			[ -f $language-$phase-review/$file ] && present_files=$(echo $present_files $file)
+		done
+		(cd $language-$phase-review; exec $editor $present_files)
+	else
+		echo "No reviews present for language $language phase $phase."
+		echo "Run reviewpo to create them"
+		exit 1
+	fi
+}
+
+function editconflicts {
+	# Edit the PO files for this phase
+	language=$1
+	phaselist=$2
+	phase=$3
+	editor="vim"
+	if [ -d $language-$phase-conflicts ]; then
+		(cd $language-$phase-conflicts; exec $editor $(ls *.po))
+	else
+		echo "No conflicts present for language $language phase $phase."
+		echo "Run conflictpo to create them"
+		exit 1
+	fi
+}
+
+function editpochecks {
+	language=$1
+	phaselist=$2
+	phase=$3
+	editor="vim"
+	files=$(getphasefiles $phaselist $phase)
+	if [ -d $language-$phase-check ]; then
+		for file in $files
+		do
+			[ -f $language-$phase-check/$file ] && present_files=$(echo $present_files $file)
+		done
+		(cd $language-$phase-check; exec $editor $(echo $present_files| sort))
+	else
+		echo "No checks present for language $language phase $phase."
+		echo "Run checkpo to create them"
+		exit 1
+	fi
+}
+
+function checkpo {
+	# Uses pofilter to check a language
+	language=$1
+	filelist=$2
+	phase=$3
+	shift 3
+	otheroptions=$*
+	files=$(getphasefiles $filelist $phase)
+	tempdir=`mktemp -d tmp.XXXXXXXXXX`
+	copy_po_to_temp_dir $language $tempdir $files
+	pofilter --excludefilter=untranslated $otheroptions $tempdir $language-$phase-check
+        rm -rf $tempdir
+}
+
+function greppo {
+	# Uses pogrep to grep a language
+	language=$1
+	filelist=$2
+	phase=$3
+	shift 3
+	otheroptions=$*
+	files=$(getphasefiles $filelist $phase)
+	tempdir=`mktemp -d tmp.XXXXXXXXXX`
+	copy_po_to_temp_dir $language $tempdir $files
+	pogrep $otheroptions $tempdir $language-$phase-grep
+        rm -rf $tempdir
+}
+
+function conflictpo {
+	# Uses pofilter to check a language
+	language=$1
+	filelist=$2
+	phase=$3
+	shift 3
+	otheroptions=$*
+	files=$(getphasefiles $filelist $phase)
+	tempdir=`mktemp -d tmp.XXXXXXXXXX`
+	copy_po_to_temp_dir $language $tempdir $files
+        rm -rf $language-$phase-conflicts
+	(curdir=$(pwd); cd $tempdir ; poconflicts $otheroptions . $curdir/$language-$phase-conflicts)
+        rm -rf $tempdir
+        zip -qr9 $language-$phase-conflicts.zip $language-$phase-conflicts
+}
+
+function mergepo {
+	language=$1
+	filelist=$2
+	phase=$3
+	pomerge -t $language -o $language -i $language-$phase-check
+}
+
+function diffpo {
+	language=$1
+	filelist=$2
+	phase=$3
+	files=$(getphasefiles $filelist $phase)
+	for file in $files
+	do
+		if [ -f $language/$file ]; then
+			present_files=$(echo $present_files $file)
+		else
+			echo "Skipping - $file - file not found"
+		fi	
+	done
+	(cd $language; cvs diff -u $present_files)
+}
+
+function reviewpo {
+	# Uses pofilter to extract the review items for a language
+	language=$1
+	filelist=$2
+	phase=$3
+	shift 3
+	otheroptions=$*
+	files=$(getphasefiles $filelist $phase)
+	tempdir=`mktemp -d tmp.XXXXXXXXXX`
+	copy_po_to_temp_dir $language $tempdir $files
+	review_dir=$language-$phase-review
+        rm -rf $review_dir
+	pofilter -t isreview -t untranslated -t blank -t isfuzzy $otheroptions $tempdir $review_dir
+	po2csv $review_dir $review_dir
+	# Transform "#, review" to # REVIEW
+	sed -i "/#, review/s/#, review/# REVIEW/" $(find $review_dir -name "*.po")
+	(cat <<-EOF
+	These are the review comments for $language phase $phase.
+
+	The format of this file is as follows:
+	Each file with errors is introduced with a line starting with the word 'File:'.  Thereafter
+	the errors appear.  Each error is separated from the next by a blank line.  They should correspond
+	to the lines in the CSV file or the messages in the PO file.  Please edit the corrections taking
+	into consideration the comments in this file.
+
+	The error is presented first with a comment starting with #. This desribes the error.  After
+	the comments you will see a line starting with 'msgid' - this is for information only and is
+	there to assist you in locating the error if you lose your place.  Make all corrections in the
+	CSV or PO file NOT in this file.  This file is simply for your information, not for editing.
+
+	Now for the review comments:
+
+	EOF
+	cd $review_dir; for review_file in $(find . -name "*.po")
+	do
+		echo "File: $review_file (the following comments relate to this file)"
+		echo
+		egrep "^$|^# REVIEW|^#_ |^# \(pofilter\)|^# \(review\)|^msgid \"" $review_file | egrep -v "^#_ isreview"
+	done ) > $review_dir/review-notes.txt
+	unix2dos $review_dir/review-notes.txt
+	pocount $(find $review_dir -name "*.po") > $review_dir/wordcount.txt
+	unix2dos $review_dir/wordcount.txt
+	zip -qr9 $review_dir.zip $review_dir
+        rm -rf tempdir
+}
+
+function checkinpo {
+	# Check the files into CVS but only those in the phase
+	language=$1
+	filelist=$2
+	phase=$3
+	files=$(getphasefiles $filelist $phase)
+	# remove files that are missing
+	for file in $files
+	do
+		if [ -f $language/$file ]; then
+			exists="$exists $file"
+		else
+			echo "$file - missing ignoring"
+		fi
+	done
+	files=$exists
+	(cd $language; cvs ci $files)
+}
+
+function creategsi {
+	# Creates a GSI file for the given language
+	language=$1
+	enusgsi=$2
+	if [ "$3" == "" -o "$3" == "-" ]; then
+		targetgsilanguage=$language
+	else
+		targetgsilanguage=$3
+	fi
+        publish=$4
+	po2oo --filteraction=warn -l $targetgsilanguage -t $enusgsi $language GSI_$targetgsilanguage.sdf && rm -f GSI_$targetgsilanguage.sdf.bz2 && bzip2 GSI_$targetgsilanguage.sdf
+        if [ "$publish" != "" ]; then
+		echo "Publishing GSI"
+		scp -p GSI_$targetgsilanguage.sdf.bz2 $publish
+	fi
+}
+
+function reviewsinout {
+	# Checks which files have not been returned from a review
+	language=$1
+	phase=$2
+	reviewdir=$language-$phase-review
+	returndir=$language-$phase-review-returned
+	reviewlist=`mktemp tmp.XXXXXXXXXX`
+	returnlist=`mktemp tmp.XXXXXXXXXX`
+	(cd $reviewdir; find . -type f -name "*.po" | sort ) > $reviewlist
+	(cd $returndir; find . -type f -name "*.po" | sort ) > $returnlist
+	echo "Reviews out: `cat $reviewlist | wc -l`"
+	echo "Reviews returned: `cat $returnlist | wc -l`"
+	diff -u $reviewlist $returnlist
+	rm $reviewlist $returnlist
+}
+
+function reviewsdiff {
+	# Creates a diff between what was sent for review and what was returned
+	language=$1
+	phase=$2
+	diff -ur $language-$phase-review $language-$phase-review-returned
+}
+
+function checkphaselist {
+	# Checks the files against the phase-list to see wich are in and which are out
+	language=$1
+	phaselist=$2
+	currentlist=`mktemp tmp.XXXXXXXXXX`
+	tempphaselist=`mktemp tmp.XXXXXXXXXX`
+	(cd $language; find . -name "*.po" | sort ) > $currentlist
+	cat $phaselist | cut -f2- | sort > $tempphaselist
+	echo "+ new files that are not in your phaselist (you need to add these)"
+	echo "- files no longer in the destination but in your phaselist (you need to remove these)"
+	diff -u $tempphaselist $currentlist
+	rm $currentlist $tempphaselist
+}
+
+function cvslog {
+	# Run CVS log against a phase so you can see what has happened
+	language=$1
+	phaselist=$2
+	phase=$3
+	options=$4
+	files=$(getphasefiles $phaselist $phase)
+	for file in $files
+	do
+		if [ -f $language/$file ]; then
+			present_files=$(echo $present_files $file)
+		else
+			echo "Skipping - $file - file not found"
+		fi	
+	done
+	(cd $language; cvs log $options $present_files)
+}
+
+function cvsadd {
+	# Run CVS add against a phase so you can add files not already in CVS
+	language=$1
+	phaselist=$2
+	phase=$3
+	files=$(getphasefiles $phaselist $phase)
+	# First check for un-added directories
+	for file in $files
+	do
+		dir=`dirname $file`
+		while [ $dir != "" -a $dir != "." ]
+		do
+			potential_dirs=$(echo $potential_dirs $dir)
+			dir=`dirname $dir`
+		done
+	done
+	for dir in `cd $language; find $potential_dirs -type d | sed "s/\/CVS$//" | sort -u`
+	do
+		if [ ! -d $language/$dir/CVS ]; then
+			dir_to_add=$(echo $dir_to_add $dir)
+		fi	
+	done
+	if [ "$dir_to_add" != "" ]; then
+		(cd $language; cvs add $dir_to_add)
+	fi
+	# Now check and add un-added files
+	for file in $files
+	do
+		filename=`basename $file`
+		cvs_entry=`dirname $file`/CVS/Entries
+		if [ "$(cd $language; egrep $filename $cvs_entry)" == "" ]; then
+			files_to_add=$(echo $files_to_add $file)
+		fi
+	done
+	if [ "$files_to_add" != "" ]; then
+		(cd $language; cvs add $files_to_add)
+	fi
+}
+
+function makephaselist {
+	templatedir=$1
+	newphaselist=$2
+	(cd $templatedir; find . -name "*.pot") | sed "s/\.pot$/.po/" | sed "s/\(^.*$\)/1	\\1/" | LC_ALL="C" sort > $newphaselist
+}
+
+function listphases {
+	phaselist=$1
+	cat $phaselist | cut -d"	" -f 1 | sort | uniq -c
+}
+
+command=$1
+shift
+case $command in
+        -h|--help) usagecommands
+	  	;;
+	makephaselist) makephaselist $1 $2
+		;;
+	listphases) listphases $1
+		;;
+	listfiles) getphasefiles $1 $2
+		;;
+	checkphaselist) checkphaselist $1 $2
+		;;
+	countpo) countpo $1 $2 $3
+		;;
+	countpot) countpot $1 $2 $3
+		;;
+	missingpo) missingpo $1 $2 $3
+		;;
+	packpot) packpot $1 $2 $3
+		;;
+	packpo) packpo $1 $2 $3
+		;;
+	packall) packall $1 $2
+		;;
+	packallpo) packallpo $1 $2
+		;;
+	countmismatch) countmismatch $1 $2 $3 $4
+		;;
+	editpo) editpo $1 $2 $3
+		;;
+	editpochecks) editpochecks $1 $2 $3
+		;;
+	checkpo) checkpo $*
+		;;
+	greppo) greppo $*
+		;;
+	mergepo) mergepo $1 $2 $3
+		;;
+	conflictpo) conflictpo $*
+		;;
+	diffpo) diffpo $1 $2 $3
+		;;
+	cvslog) cvslog $1 $2 $3
+		;;
+	lastlog) cvslog $1 $2 $3 -r
+		;;
+	cvsadd) cvsadd $1 $2 $3
+		;;
+	reviewpo) reviewpo $*
+		;;
+	editreviews) editreviews $1 $2 $3
+		;;
+	editconflicts) editconflicts $1 $2 $3
+		;;
+	countreviews) countreviews $1 $2 $3
+		;;
+	checkinpo) checkinpo $1 $2 $3
+		;;
+	creategsi) creategsi $1 $2 $3 $4
+		;;
+        reviewsinout) reviewsinout $1 $2
+		;;
+	reviewsdiff) reviewsdiff $1 $2
+		;;
+	"") usage
+		;;
+	*) error_notacommand $command
+		;;
+esac
+
+
diff --git a/tools/phaselist2goals b/tools/phaselist2goals
new file mode 100755
index 0000000..a64d98d
--- /dev/null
+++ b/tools/phaselist2goals
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+function goalkeeper () {
+	goal=$1
+	file=$2
+	if [ "$lastgoal" == "" ]; then
+		lastgoal=$goal
+	fi
+	if [ "$goal" != "$lastgoal" ]; then
+		echo "  u'"$lastgoal"':"
+		echo "    files = u'"$files"'"
+		lastgoal=$goal
+		files=""
+	fi
+	if [ "$files" == "" ]; then
+		files=$file
+	else
+		files="$files, $file"
+	fi
+}
+
+
+lastgoal=""
+files=""
+EOF=$(mktemp)
+echo "zzzzzzz	zzzzzzzzzz"> $EOF
+echo "# Generated by $0 - insert this into your projects .prefs file"
+echo
+echo "goals:"
+cat $1 $EOF | sort | while read line
+do
+	goal=$(echo $line | sed "s/\s.*$//")
+	file=$(echo $line | sed "s/^[^ ]\+\s\.\///")
+	goalkeeper $goal $file
+done
diff --git a/translate/__version__.py b/translate/__version__.py
index 7edd807..145d306 100644
--- a/translate/__version__.py
+++ b/translate/__version__.py
@@ -20,16 +20,16 @@
 
 """This file contains the version of the Translate Toolkit."""
 
-build = 12021
+build = 13002
 """The build number is used by external users of the Translate Toolkit to
 trigger refreshes.  Thus increase the build number whenever changes are made to
 code touching stats or quality checks.  An increased build number will force a
 toolkit user, like Pootle, to regenerate it's stored stats and check
 results."""
 
-sver = "1.12.0"
+sver = "1.13.0"
 """Human readable version number. Used for version number display."""
 
-ver = (1, 12, 0)
+ver = (1, 13, 0)
 """Machine readable version number. Used by tools that need to adjust code
 paths based on a Translate Toolkit release number."""
diff --git a/translate/tools/podebug b/translate/convert/idml2po
similarity index 80%
copy from translate/tools/podebug
copy to translate/convert/idml2po
index ef37bfc..a1db8f2 100755
--- a/translate/tools/podebug
+++ b/translate/convert/idml2po
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 # 
-# Copyright 2004 Zuza Software Foundation
+# Copyright 2014 Zuza Software Foundation
 # 
 # This file is part of translate.
 #
@@ -17,10 +17,10 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
-"""simple script to insert debug messages into po file translations"""
+"""Simple script to convert a IDML file to a XLIFF localization file."""
 
-from translate.tools import podebug
+from translate.convert import idml2po
 
-if __name__ == '__main__':
-  podebug.main()
 
+if __name__ == '__main__':
+    idml2po.main()
diff --git a/translate/convert/idml2po.py b/translate/convert/idml2po.py
new file mode 100644
index 0000000..57cfe88
--- /dev/null
+++ b/translate/convert/idml2po.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2004-2014 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 this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""Convert IDML files to PO localization files."""
+
+from cStringIO import StringIO
+
+from translate.convert import convert
+from translate.storage import factory
+from translate.storage.idml import (INLINE_ELEMENTS, NO_TRANSLATE_ELEMENTS,
+                                    open_idml)
+from translate.storage.xml_extract.extract import (IdMaker, ParseState,
+                                                   build_idml_store,
+                                                   make_postore_adder)
+
+
+def convert_idml(inputfile, outputfile, template):
+    """Convert an IDML package to PO."""
+    # Since the convertoptionsparser will give us an open file, we risk that
+    # it could have been opened in non-binary mode on Windows, and then we'll
+    # have problems, so let's make sure we have what we want.
+    inputfile.close()
+    inputfile = file(inputfile.name, mode='rb')
+
+    store = factory.getobject(outputfile)
+
+    contents = open_idml(inputfile)
+
+    id_maker = IdMaker()  # Create it here to avoid having repeated ids.
+
+    for filename, translatable_file in contents.iteritems():
+        parse_state = ParseState(NO_TRANSLATE_ELEMENTS, INLINE_ELEMENTS)
+        po_store_adder = make_postore_adder(store, id_maker, filename)
+        build_idml_store(StringIO(translatable_file), store, parse_state,
+                         store_adder=po_store_adder)
+
+    store.save()
+    return True
+
+
+def main(argv=None):
+    formats = {
+        "idml": ("po", convert_idml),
+    }
+    parser = convert.ConvertOptionParser(formats, description=__doc__)
+    parser.run(argv)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/translate/tools/pomerge b/translate/convert/mozlang2po
similarity index 81%
copy from translate/tools/pomerge
copy to translate/convert/mozlang2po
index 75aa68e..f90d75e 100755
--- a/translate/tools/pomerge
+++ b/translate/convert/mozlang2po
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
-# 
-# Copyright 2004 Zuza Software Foundation
+#
+# Copyright 2011 Zuza Software Foundation
 # 
 # This file is part of translate.
 #
@@ -16,11 +16,12 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
 
-"""script that merges .po files and overrides translations"""
+"""Converts Mozilla .lang files to Gettext PO files"""
 
-from translate.tools import pomerge
+from translate.convert import mozlang2po
 
 if __name__ == '__main__':
-  pomerge.main()
+    mozlang2po.main()
 
diff --git a/translate/convert/odf2xliff.py b/translate/convert/odf2xliff.py
index 08ac475..ac10c25 100644
--- a/translate/convert/odf2xliff.py
+++ b/translate/convert/odf2xliff.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-# Copyright 2004-2006 Zuza Software Foundation
+# Copyright 2004-2014 Zuza Software Foundation
 #
 # This file is part of translate.
 #
@@ -17,7 +17,6 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
-#
 
 """Convert OpenDocument (ODF) files to XLIFF localization files.
 
@@ -25,106 +24,62 @@ See: http://docs.translatehouse.org/projects/translate-toolkit/en/latest/command
 for examples and usage instructions.
 """
 
-from contextlib import contextmanager
 from cStringIO import StringIO
 
-from translate.storage import factory, odf_io
-
-
-def convertodf(inputfile, outputfile, templates, engine='toolkit'):
-    """reads in stdin using fromfileclass, converts using convertorclass,
-       writes to stdout
-    """
-
-    def translate_toolkit_implementation(store):
-        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(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)
+from translate.convert import convert
+from translate.storage import factory
+from translate.storage.odf_io import open_odf
+from translate.storage.odf_shared import (inline_elements,
+                                          no_translate_content_elements)
+from translate.storage.xml_extract.extract import ParseState, build_store
 
-        try:
-            get_units = handler.get_units
-        except AttributeError:
-            raise AttributeError('error: the file "%s" could not be processed' % 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)
-        try:
-            store.setfilename(store.getfilenode('NoName'), inputfile.name)
-        except:
-            print("couldn't set origin filename")
-        yield store
-        store.save()
 
+def convertodf(inputfile, outputfile, templates):
+    """Convert an ODF package to XLIFF."""
     # Since the convertoptionsparser will give us an open file, we risk that
     # it could have been opened in non-binary mode on Windows, and then we'll
     # have problems, so let's make sure we have what we want.
     inputfile.close()
     inputfile = file(inputfile.name, mode='rb')
 
-    with store_context() as store:
-        if engine == "toolkit":
-            translate_toolkit_implementation(store)
-        else:
-            itools_implementation(store)
+    store = factory.getobject(outputfile)
 
-    return True
+    try:
+        store.setfilename(store.getfilenode('NoName'), inputfile.name)
+    except:
+        print("couldn't set origin filename")
 
+    contents = open_odf(inputfile)
+    for data in contents.values():
+        parse_state = ParseState(no_translate_content_elements, inline_elements)
+        build_store(StringIO(data), store, parse_state)
 
-# For formats see OpenDocument 1.2 draft 7 Appendix C
-formats = {
-    "sxw": ("xlf", convertodf),
-    "odt": ("xlf", convertodf),  # Text
-    "ods": ("xlf", convertodf),  # Spreadsheet
-    "odp": ("xlf", convertodf),  # Presentation
-    "odg": ("xlf", convertodf),  # Drawing
-    "odc": ("xlf", convertodf),  # Chart
-    "odf": ("xlf", convertodf),  # Formula
-    "odi": ("xlf", convertodf),  # Image
-    "odm": ("xlf", convertodf),  # Master Document
-    "ott": ("xlf", convertodf),  # Text template
-    "ots": ("xlf", convertodf),  # Spreadsheet template
-    "otp": ("xlf", convertodf),  # Presentation template
-    "otg": ("xlf", convertodf),  # Drawing template
-    "otc": ("xlf", convertodf),  # Chart template
-    "otf": ("xlf", convertodf),  # Formula template
-    "oti": ("xlf", convertodf),  # Image template
-    "oth": ("xlf", convertodf),  # Web page template
-}
+    store.save()
+    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
+    # For formats see OpenDocument 1.2 draft 7 Appendix C
+    formats = {
+        "sxw": ("xlf", convertodf),
+        "odt": ("xlf", convertodf),  # Text
+        "ods": ("xlf", convertodf),  # Spreadsheet
+        "odp": ("xlf", convertodf),  # Presentation
+        "odg": ("xlf", convertodf),  # Drawing
+        "odc": ("xlf", convertodf),  # Chart
+        "odf": ("xlf", convertodf),  # Formula
+        "odi": ("xlf", convertodf),  # Image
+        "odm": ("xlf", convertodf),  # Master Document
+        "ott": ("xlf", convertodf),  # Text template
+        "ots": ("xlf", convertodf),  # Spreadsheet template
+        "otp": ("xlf", convertodf),  # Presentation template
+        "otg": ("xlf", convertodf),  # Drawing template
+        "otc": ("xlf", convertodf),  # Chart template
+        "otf": ("xlf", convertodf),  # Formula template
+        "oti": ("xlf", convertodf),  # Image template
+        "oth": ("xlf", convertodf),  # Web page template
+    }
     parser = convert.ConvertOptionParser(formats, description=__doc__)
-    add_options(parser)
     parser.run(argv)
 
 
diff --git a/translate/convert/odfxml b/translate/convert/odfxml
new file mode 100755
index 0000000..2534186
--- /dev/null
+++ b/translate/convert/odfxml
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Uncompresses the supplied ODF file, reflows it for easy viewing and displays 
+# the bits needed for understanding the localisable bits.
+
+dest=.odf
+
+mkdir -p $dest
+unzip -q -o "$1" -d $dest
+tidy -raw -indent -modify -quiet -xml $dest/content.xml
+tidy -raw -indent -modify -quiet -xml $dest/styles.xml
+vim -o $dest/content.xml $dest/styles.xml
diff --git a/translate/filters/__init__.py b/translate/convert/po2idml
old mode 100644
new mode 100755
similarity index 83%
copy from translate/filters/__init__.py
copy to translate/convert/po2idml
index 6032321..de2df99
--- a/translate/filters/__init__.py
+++ b/translate/convert/po2idml
@@ -1,15 +1,14 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright 2002, 2003 Zuza Software Foundation
 #
+# Copyright 2014 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
@@ -18,4 +17,8 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
-"""Filters that can be used on translations..."""
+from translate.convert import po2idml
+
+
+if __name__ == '__main__':
+  po2idml.main()
diff --git a/translate/convert/po2idml.py b/translate/convert/po2idml.py
new file mode 100644
index 0000000..d7b9c14
--- /dev/null
+++ b/translate/convert/po2idml.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2014 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 this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""Takes an IDML template file and a PO file containing translations of
+strings in the IDML template. It creates a new IDML file using the translations
+of the PO file.
+"""
+
+from cStringIO import StringIO
+from zipfile import ZIP_DEFLATED, ZipFile
+
+import lxml.etree as etree
+
+from translate.convert import convert
+from translate.storage import factory
+from translate.storage.idml import (NO_TRANSLATE_ELEMENTS,
+                                    INLINE_ELEMENTS, copy_idml, open_idml)
+from translate.storage.xml_extract.extract import (ParseState,
+                                                   process_idml_translatable)
+from translate.storage.xml_extract.generate import (apply_translations,
+                                                    replace_dom_text)
+from translate.storage.xml_extract.unit_tree import XPathTree, build_unit_tree
+
+
+def translate_idml(template, input_file, translatable_files):
+
+    def load_dom_trees(template):
+        """Return a dict with translatable files in the template IDML package.
+
+        The keys are the filenames inside the IDML package, and the values are
+        the etrees for each of those translatable files.
+        """
+        idml_data = open_idml(template)
+        parser = etree.XMLParser(strip_cdata=False)
+        return dict((filename, etree.fromstring(data, parser).getroottree())
+                    for filename, data in idml_data.iteritems())
+
+    def load_unit_tree(input_file):
+        """Return a dict with the translations grouped by files IDML package.
+
+        The keys are the filenames inside the template IDML package, and the
+        values are XPathTree instances for each of those files.
+        """
+        store = factory.getobject(input_file)
+
+        def extract_unit_tree(filename, root_dom_element_name):
+            """Find the subtree in 'tree' which corresponds to the data in XML
+            file 'filename'
+            """
+            tree = build_unit_tree(store, filename)
+
+            try:
+                file_tree = tree.children[root_dom_element_name, 0]
+            except KeyError:
+                file_tree = XPathTree()
+
+            return (filename, file_tree)
+
+        return dict(extract_unit_tree(filename, 'idPkg:Story')
+                    for filename in translatable_files)
+
+    def translate_dom_trees(unit_trees, dom_trees):
+        """Return a dict with the translated files for the IDML package.
+
+        The keys are the filenames for the translatable files inside the
+        template IDML package, and the values are etree ElementTree instances
+        for each of those files.
+        """
+        def get_po_doms(unit):
+            """Return a tuple with unit source and target DOM objects.
+
+            This method is method is meant to provide a way to retrieve the DOM
+            objects for the unit source and target for PO stores.
+
+            Since POunit doesn't have any source_dom nor target_dom attributes,
+            it is necessary to craft those objects.
+            """
+            def add_node_content(string, node):
+                """Append the translatable content to the node.
+
+                The string is going to have XLIFF placeables, so we have to
+                parse it as XML in order to get the right nodes to append to
+                the node.
+                """
+                # Add a wrapper "whatever" tag to avoid problems when parsing
+                # several sibling tags at the root level.
+                fake_string = "<whatever>" + string + "</whatever>"
+
+                # Copy the children to the XLIFF unit's source or target node.
+                fake_node = etree.fromstring(fake_string)
+                node.extend(fake_node.getchildren())
+
+                return node
+
+            source_dom = etree.Element("source")
+            source_dom = add_node_content(unit.source, source_dom)
+            target_dom = etree.Element("target")
+
+            if unit.target:
+                target_dom = add_node_content(unit.target, target_dom)
+            else:
+                target_dom = add_node_content(unit.source, target_dom)
+
+            return (source_dom, target_dom)
+
+        make_parse_state = lambda: ParseState(NO_TRANSLATE_ELEMENTS,
+                                              INLINE_ELEMENTS)
+        for filename, dom_tree in dom_trees.iteritems():
+            file_unit_tree = unit_trees[filename]
+            apply_translations(dom_tree.getroot(), file_unit_tree,
+                               replace_dom_text(make_parse_state,
+                                                dom_retriever=get_po_doms,
+                                                process_translatable=process_idml_translatable))
+        return dom_trees
+
+    dom_trees = load_dom_trees(template)
+    unit_trees = load_unit_tree(input_file)
+    return translate_dom_trees(unit_trees, dom_trees)
+
+
+def write_idml(template_zip, output_file, dom_trees):
+    """Write the translated IDML package."""
+    output_zip = ZipFile(output_file, 'w', compression=ZIP_DEFLATED)
+
+    # Copy the IDML package.
+    output_zip = copy_idml(template_zip, output_zip, dom_trees.keys())
+
+    # Replace the translated files in the IDML package.
+    for filename, dom_tree in dom_trees.iteritems():
+        output_zip.writestr(filename, etree.tostring(dom_tree,
+                                                     encoding='UTF-8',
+                                                     xml_declaration=True,
+                                                     standalone='yes'))
+
+
+def convertpo(input_file, output_file, template):
+    """Create a translated IDML using an IDML template and a PO file."""
+    # Since the convertoptionsparser will give us a open files, we risk that
+    # they could have been opened in non-binary mode on Windows, and then we'll
+    # have problems, so let's make sure we have what we want.
+    template.close()
+    template = file(template.name, mode='rb')
+    output_file.close()
+    output_file = file(output_file.name, mode='wb')
+
+    # Now proceed with the conversion.
+    template_zip = ZipFile(template, 'r')
+
+    translatable_files = [filename for filename in template_zip.namelist()
+                          if filename.startswith('Stories/')]
+
+    po_data = input_file.read()
+    dom_trees = translate_idml(template, StringIO(po_data), translatable_files)
+
+    write_idml(template_zip, output_file, dom_trees)
+    output_file.close()
+    return True
+
+
+def main(argv=None):
+    formats = {
+        ('po', 'idml'): ("idml", convertpo),
+    }
+    parser = convert.ConvertOptionParser(formats, usetemplates=True,
+                                         description=__doc__)
+    parser.run(argv)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/translate/convert/po2ini.py b/translate/convert/po2ini.py
index 3329d53..361acbe 100644
--- a/translate/convert/po2ini.py
+++ b/translate/convert/po2ini.py
@@ -52,8 +52,9 @@ class reini:
         return str(self.templatestore)
 
 
-def convertini(inputfile, outputfile, templatefile, includefuzzy=False, dialect="default",
-               outputthreshold=None):
+def convertini(inputfile, outputfile, templatefile, includefuzzy=False,
+               dialect="default", outputthreshold=None):
+
     inputstore = factory.getobject(inputfile)
 
     if not convert.should_output_store(inputstore, outputthreshold):
@@ -63,24 +64,26 @@ def convertini(inputfile, outputfile, templatefile, includefuzzy=False, dialect=
         raise ValueError("must have template file for ini files")
     else:
         convertor = reini(templatefile, inputstore, dialect)
+
     outputstring = convertor.convertstore(includefuzzy)
     outputfile.write(outputstring)
-    return 1
+    return True
+
 
+def convertisl(inputfile, outputfile, templatefile, includefuzzy=False,
+               dialect="inno", outputthreshold=None):
 
-def convertisl(inputfile, outputfile, templatefile, includefuzzy=False, dialect="inno",
-               outputthreshold=None):
     convertini(inputfile, outputfile, templatefile, includefuzzy, dialect,
                outputthreshold=outputthreshold)
 
 
 def main(argv=None):
-    # handle command line options
     formats = {
-               ("po", "ini"): ("ini", convertini),
-               ("po", "isl"): ("isl", convertisl),
-              }
-    parser = convert.ConvertOptionParser(formats, usetemplates=True, description=__doc__)
+        ("po", "ini"): ("ini", convertini),
+        ("po", "isl"): ("isl", convertisl),
+    }
+    parser = convert.ConvertOptionParser(formats, usetemplates=True,
+                                         description=__doc__)
     parser.add_threshold_option()
     parser.add_fuzzy_option()
     parser.run(argv)
diff --git a/translate/convert/po2json.py b/translate/convert/po2json.py
index 11e855e..3f582d3 100644
--- a/translate/convert/po2json.py
+++ b/translate/convert/po2json.py
@@ -25,13 +25,12 @@ for examples and usage instructions.
 """
 
 from translate.convert import convert
-from translate.storage import factory
+from translate.storage import factory, jsonl10n
 
 
 class rejson:
 
     def __init__(self, templatefile, inputstore):
-        from translate.storage import jsonl10n
         self.templatefile = templatefile
         self.templatestore = jsonl10n.JsonFile(templatefile)
         self.inputstore = inputstore
@@ -60,18 +59,18 @@ def convertjson(inputfile, outputfile, templatefile, includefuzzy=False,
 
     if templatefile is None:
         raise ValueError("Must have template file for JSON files")
-    else:
-        convertor = rejson(templatefile, inputstore)
+
+    convertor = rejson(templatefile, inputstore)
     outputstring = convertor.convertstore(includefuzzy)
     outputfile.write(outputstring)
-    return 1
+    return True
 
 
 def main(argv=None):
     # handle command line options
     formats = {
-               ("po", "json"): ("json", convertjson),
-              }
+        ("po", "json"): ("json", convertjson),
+    }
     parser = convert.ConvertOptionParser(formats, usetemplates=True,
                                          description=__doc__)
     parser.add_threshold_option()
diff --git a/translate/convert/po2moz.py b/translate/convert/po2moz.py
index dcb27dd..b5926d2 100644
--- a/translate/convert/po2moz.py
+++ b/translate/convert/po2moz.py
@@ -38,14 +38,18 @@ class MozConvertOptionParser(convert.ConvertOptionParser):
                                              description=description)
 
     def splitinputext(self, inputpath):
-        """splits a inputpath into name and extension"""
-        # TODO: not sure if this should be here, was in po2moz
+        """splits a inputpath into name and extension
+
+        Special adaptation to handle po2moz case where extensions are
+        e.g. properties.po
+        """
         d, n = os.path.dirname(inputpath), os.path.basename(inputpath)
-        s = n.find(".")
-        if s == -1:
+        s1 = n.rfind(".")
+        s2 = n.rfind(".", 0, s1)
+        if s2 == -1:
             return (inputpath, "")
-        root = os.path.join(d, n[:s])
-        ext = n[s+1:]
+        root = os.path.join(d, n[:s2])
+        ext = n[s2+1:]
         return (root, ext)
 
     def recursiveprocess(self, options):
diff --git a/translate/tools/pomerge b/translate/convert/po2mozlang
similarity index 81%
copy from translate/tools/pomerge
copy to translate/convert/po2mozlang
index 75aa68e..3148fde 100755
--- a/translate/tools/pomerge
+++ b/translate/convert/po2mozlang
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
-# 
-# Copyright 2004 Zuza Software Foundation
+#
+# Copyright 2011 Zuza Software Foundation
 # 
 # This file is part of translate.
 #
@@ -16,11 +16,12 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
 
-"""script that merges .po files and overrides translations"""
+"""Convert Gettext PO files and Mozilla .lang files"""
 
-from translate.tools import pomerge
+from translate.convert import po2mozlang
 
 if __name__ == '__main__':
-  pomerge.main()
+    po2mozlang.main()
 
diff --git a/translate/convert/po2mozlang.py b/translate/convert/po2mozlang.py
index 427b4b0..07f313c 100644
--- a/translate/convert/po2mozlang.py
+++ b/translate/convert/po2mozlang.py
@@ -25,7 +25,7 @@
 """
 
 from translate.convert import convert
-from translate.storage import mozilla_lang as lang, po
+from translate.storage import mozilla_lang, po
 
 
 class po2lang:
@@ -36,7 +36,7 @@ class po2lang:
 
     def convertstore(self, inputstore, includefuzzy=False):
         """converts a file to .lang format"""
-        thetargetfile = lang.LangStore(mark_active=self.mark_active)
+        thetargetfile = mozilla_lang.LangStore(mark_active=self.mark_active)
 
         # Run over the po units
         for pounit in inputstore.units:
@@ -62,11 +62,12 @@ def convertlang(inputfile, outputfile, templates, includefuzzy=False, mark_activ
         return False
 
     if inputstore.isempty():
-        return 0
+        return False
+
     convertor = po2lang(mark_active=mark_active)
     outputstore = convertor.convertstore(inputstore, includefuzzy)
     outputfile.write(str(outputstore))
-    return 1
+    return True
 
 
 formats = {
diff --git a/translate/convert/po2php.py b/translate/convert/po2php.py
index 52a6d12..c90ecfe 100644
--- a/translate/convert/po2php.py
+++ b/translate/convert/po2php.py
@@ -49,14 +49,17 @@ class rephp:
         self.includefuzzy = includefuzzy
         self.inputstore.makeindex()
         outputlines = []
+
         for line in self.templatefile.readlines():
             outputstr = self.convertline(line)
             outputlines.append(outputstr)
+
         return outputlines
 
     def convertline(self, line):
         line = unicode(line, 'utf-8')
         returnline = ""
+
         # handle multiline msgid if we're in one
         if self.inmultilinemsgid:
             # see if there's more
@@ -70,7 +73,7 @@ class rephp:
         # otherwise, this could be a comment
         elif line.strip()[:2] == '//' or line.strip()[:2] == '/*':
             returnline = quote.rstripeol(line) + eol
-        elif line.find('array(') != -1:
+        elif line.lower().replace(" ", "").find('array(') != -1:
             self.inarray = True
             self.prename = line[:line.find('=')].strip() + "->"
             self.equaldel = "=>"
@@ -92,6 +95,7 @@ class rephp:
             elif 0 <= hashpos < equalspos:
                 # Assume that this is a '#' comment line
                 returnline = quote.rstripeol(line) + eol
+
             # otherwise, this is a definition
             else:
                 # now deal with the current string...
@@ -109,35 +113,49 @@ class rephp:
                     inlinecomment = line[inlinecomment_pos+2:]
                 else:
                     inlinecomment = ""
+
                 if lookupkey in self.inputstore.locationindex:
                     unit = self.inputstore.locationindex[lookupkey]
-                    if (unit.isfuzzy() and not self.includefuzzy) or len(unit.target) == 0:
+                    if ((unit.isfuzzy() and not self.includefuzzy) or
+                        len(unit.target) == 0):
                         value = unit.source
                     else:
                         value = unit.target
+
                     value = php.phpencode(value, self.quotechar)
                     self.inecho = False
+
                     if isinstance(value, str):
                         value = value.decode('utf8')
-                    returnline = "%(key)s%(pre)s%(del)s%(post)s%(quote)s%(value)s%(quote)s%(enddel)s%(comment)s%(eol)s" % {
-                                     "key": key,
-                                     "pre": prespace, "del": self.equaldel,
-                                     "post": postspace,
-                                     "quote": self.quotechar, "value": value,
-                                     "enddel": self.enddel,
-                                     "comment": inlinecomment, "eol": eol,
-                                  }
+
+                    params = {
+                        "key": key,
+                        "pre": prespace,
+                        "del": self.equaldel,
+                        "post": postspace,
+                        "quote": self.quotechar,
+                        "value": value,
+                        "enddel": self.enddel,
+                        "comment": inlinecomment,
+                        "eol": eol,
+                    }
+                    returnline = ("%(key)s%(pre)s%(del)s%(post)s%(quote)s"
+                                  "%(value)s%(quote)s%(enddel)s%(comment)s"
+                                  "%(eol)s" % params)
                 else:
                     self.inecho = True
                     returnline = line + eol
+
                 # no string termination means carry string on to next line
                 endpos = line.rfind("%s%s" % (self.quotechar, self.enddel))
                 # if there was no '; or the quote is escaped, we have to
                 # continue
                 if endpos == -1 or line[endpos-1] == '\\':
                     self.inmultilinemsgid = True
+
         if isinstance(returnline, unicode):
             returnline = returnline.encode('utf-8')
+
         return returnline
 
 
@@ -150,9 +168,8 @@ def convertphp(inputfile, outputfile, templatefile, includefuzzy=False,
 
     if templatefile is None:
         raise ValueError("must have template file for php files")
-        # convertor = po2php()
-    else:
-        convertor = rephp(templatefile, inputstore)
+
+    convertor = rephp(templatefile, inputstore)
     outputphplines = convertor.convertstore(includefuzzy)
     outputfile.writelines(outputphplines)
     return 1
@@ -161,8 +178,8 @@ def convertphp(inputfile, outputfile, templatefile, includefuzzy=False,
 def main(argv=None):
     # handle command line options
     formats = {
-            ("po", "php"): ("php", convertphp),
-            ("po", "html"): ("html", convertphp),
+        ("po", "php"): ("php", convertphp),
+        ("po", "html"): ("html", convertphp),
     }
     parser = convert.ConvertOptionParser(formats, usetemplates=True,
                                          description=__doc__)
@@ -170,5 +187,6 @@ def main(argv=None):
     parser.add_fuzzy_option()
     parser.run(argv)
 
+
 if __name__ == '__main__':
     main()
diff --git a/translate/convert/po2prop.py b/translate/convert/po2prop.py
index 869ed97..e526cbf 100644
--- a/translate/convert/po2prop.py
+++ b/translate/convert/po2prop.py
@@ -229,7 +229,8 @@ def convertprop(inputfile, outputfile, templatefile, personality="java",
                            remove_untranslated)
     outputprop = convertor.convertstore(includefuzzy)
     outputfile.write(outputprop)
-    return 1
+    return True
+
 
 formats = {
     ("po", "properties"): ("properties", convertprop),
diff --git a/translate/convert/ini2po b/translate/convert/po2resx
old mode 100755
new mode 100644
similarity index 76%
copy from translate/convert/ini2po
copy to translate/convert/po2resx
index 008983f..4051f44
--- a/translate/convert/ini2po
+++ b/translate/convert/po2resx
@@ -1,6 +1,7 @@
 #!/usr/bin/env python
 # 
-# Copyright 2002, 2003 Zuza Software Foundation
+# Copyright 2015 Zuza Software Foundation
+# Copyright 2015 Sarah Hale
 # 
 # This file is part of translate.
 #
@@ -17,11 +18,11 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
-"""Simple script to convert a .ini file to a gettext .po localization file."""
-
-from translate.convert import ini2po
+"""simple script to convert a Gettext PO localisation file to a
+.Net Resource (.resx) file"""
 
+from translate.convert import po2resx
 
 if __name__ == '__main__':
-    ini2po.main()
+    po2resx.main()
 
diff --git a/translate/convert/po2json.py b/translate/convert/po2resx.py
similarity index 62%
copy from translate/convert/po2json.py
copy to translate/convert/po2resx.py
index 11e855e..7663c45 100644
--- a/translate/convert/po2json.py
+++ b/translate/convert/po2resx.py
@@ -1,7 +1,8 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-# Copyright 2002-2006 Zuza Software Foundation
+# Copyright 2015 Zuza Software Foundation
+# Copyright 2015 Sarah Hale
 #
 # This file is part of translate.
 #
@@ -18,29 +19,29 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
-"""Convert Gettext PO localization files to JSON files.
+"""Convert Gettext PO localisation files to .Net Resource (.resx) files.
 
-See: http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/json2po.html
+See: http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/resx2po.html
 for examples and usage instructions.
 """
 
 from translate.convert import convert
-from translate.storage import factory
+from translate.storage import factory, resx
 
 
-class rejson:
-
+class po2resx:
     def __init__(self, templatefile, inputstore):
-        from translate.storage import jsonl10n
         self.templatefile = templatefile
-        self.templatestore = jsonl10n.JsonFile(templatefile)
+        self.templatestore = resx.RESXFile(templatefile)
         self.inputstore = inputstore
 
     def convertstore(self, includefuzzy=False):
         self.includefuzzy = includefuzzy
         self.inputstore.makeindex()
+
         for unit in self.templatestore.units:
             inputunit = self.inputstore.locationindex.get(unit.getid())
+
             if inputunit is not None:
                 if inputunit.isfuzzy() and not self.includefuzzy:
                     unit.target = unit.source
@@ -48,33 +49,53 @@ class rejson:
                     unit.target = inputunit.target
             else:
                 unit.target = unit.source
+
+            if inputunit is not None:
+                self.addcomments(inputunit, unit)
+
         return str(self.templatestore)
 
+    def addcomments(self, inputunit, unit):
+        comments = []
+
+        # Handle #. automatic comments
+        autocomment = inputunit.getnotes("developer")
+        comments.append(autocomment)
 
-def convertjson(inputfile, outputfile, templatefile, includefuzzy=False,
+        # Handle # comments
+        transcomment = inputunit.getnotes("translator")
+        if transcomment:
+            comments.append("[Translator Comment: " + transcomment + "]")
+
+        # Join automatic and translator comments with a newline as per
+        # convention.
+        combocomment = '\n'.join(comments)
+
+        if combocomment:
+            unit.addnote(combocomment)
+
+
+def convertresx(inputfile, outputfile, templatefile, includefuzzy=False,
                 outputthreshold=None):
-    inputstore = factory.getobject(inputfile)
 
-    if not convert.should_output_store(inputstore, outputthreshold):
-        return False
+    inputstore = factory.getobject(inputfile)
 
     if templatefile is None:
-        raise ValueError("Must have template file for JSON files")
+        raise ValueError("Must have template file for RESX files")
     else:
-        convertor = rejson(templatefile, inputstore)
+        convertor = po2resx(templatefile, inputstore)
+
     outputstring = convertor.convertstore(includefuzzy)
     outputfile.write(outputstring)
-    return 1
+    return True
 
 
 def main(argv=None):
-    # handle command line options
     formats = {
-               ("po", "json"): ("json", convertjson),
-              }
+        ("po", "resx"): ("resx", convertresx),
+    }
     parser = convert.ConvertOptionParser(formats, usetemplates=True,
                                          description=__doc__)
-    parser.add_threshold_option()
     parser.add_fuzzy_option()
     parser.run(argv)
 
diff --git a/translate/convert/po2txt.py b/translate/convert/po2txt.py
index c479a72..82ad9be 100644
--- a/translate/convert/po2txt.py
+++ b/translate/convert/po2txt.py
@@ -31,7 +31,10 @@ from translate.storage import factory
 
 
 class po2txt:
-    """po2txt can take a po file and generate txt. best to give it a template file otherwise will just concat msgstrs"""
+    """po2txt can take a po file and generate txt.
+
+    best to give it a template file otherwise will just concat msgstrs
+    """
 
     def __init__(self, wrap=None):
         self.wrap = wrap
@@ -40,7 +43,8 @@ class po2txt:
         """rewraps text as required"""
         if self.wrap is None:
             return message
-        return "\n".join([textwrap.fill(line, self.wrap, replace_whitespace=False) for line in message.split("\n")])
+        return "\n".join([textwrap.fill(line, self.wrap, replace_whitespace=False)
+                          for line in message.split("\n")])
 
     def convertstore(self, inputstore, includefuzzy):
         """converts a file to txt format"""
@@ -49,9 +53,9 @@ class po2txt:
             if unit.isheader():
                 continue
             if unit.istranslated() or (includefuzzy and unit.isfuzzy()):
-                txtresult += self.wrapmessage(unit.target) + "\n" + "\n"
+                txtresult += self.wrapmessage(unit.target) + "\n\n"
             else:
-                txtresult += self.wrapmessage(unit.source) + "\n" + "\n"
+                txtresult += self.wrapmessage(unit.source) + "\n\n"
         return txtresult.rstrip()
 
     def mergestore(self, inputstore, templatetext, includefuzzy):
@@ -70,8 +74,8 @@ class po2txt:
         return txtresult
 
 
-def converttxt(inputfile, outputfile, templatefile, wrap=None, includefuzzy=False, encoding='utf-8',
-               outputthreshold=None):
+def converttxt(inputfile, outputfile, templatefile, wrap=None,
+               includefuzzy=False, encoding='utf-8', outputthreshold=None):
     """reads in stdin using fromfileclass, converts using convertorclass, writes to stdout"""
     inputstore = factory.getobject(inputfile)
 
@@ -79,20 +83,27 @@ def converttxt(inputfile, outputfile, templatefile, wrap=None, includefuzzy=Fals
         return False
 
     convertor = po2txt(wrap=wrap)
+
     if templatefile is None:
         outputstring = convertor.convertstore(inputstore, includefuzzy)
     else:
         templatestring = templatefile.read().decode(encoding)
         outputstring = convertor.mergestore(inputstore, templatestring, includefuzzy)
+
     outputfile.write(outputstring.encode('utf-8'))
-    return 1
+    return True
 
 
 def main(argv=None):
     from translate.misc import stdiotell
     import sys
     sys.stdout = stdiotell.StdIOWrapper(sys.stdout)
-    formats = {("po", "txt"): ("txt", converttxt), ("po"): ("txt", converttxt), ("xlf", "txt"): ("txt", converttxt), ("xlf"): ("txt", converttxt)}
+    formats = {
+        ("po", "txt"): ("txt", converttxt),
+        ("po"): ("txt", converttxt),
+        ("xlf", "txt"): ("txt", converttxt),
+        ("xlf"): ("txt", converttxt),
+    }
     parser = convert.ConvertOptionParser(formats, usetemplates=True, description=__doc__)
     parser.add_option("", "--encoding", dest="encoding", default='utf-8', type="string",
             help="The encoding of the template file (default: UTF-8)")
diff --git a/translate/convert/pot2po.py b/translate/convert/pot2po.py
index 13b9e5a..95707ae 100644
--- a/translate/convert/pot2po.py
+++ b/translate/convert/pot2po.py
@@ -264,6 +264,8 @@ def main(argv=None):
         ("pot", "po"): ("po", convertpot),
         "xlf": ("xlf", convertpot),
         ("xlf", "xlf"): ("xlf", convertpot),
+        "xliff": ("xliff", convertpot),
+        ("xliff", "xliff"): ("xliff", convertpot),
         "ts": ("ts", convertpot),
         "lang": ("lang", convertpot),
         ("lang", "lang"): ("lang", convertpot),
diff --git a/translate/convert/ini2po b/translate/convert/resx2po
old mode 100755
new mode 100644
similarity index 76%
copy from translate/convert/ini2po
copy to translate/convert/resx2po
index 008983f..e1487de
--- a/translate/convert/ini2po
+++ b/translate/convert/resx2po
@@ -1,6 +1,7 @@
 #!/usr/bin/env python
 # 
-# Copyright 2002, 2003 Zuza Software Foundation
+# Copyright 2015 Zuza Software Foundation
+# Copyright 2015 Sarah Hale
 # 
 # This file is part of translate.
 #
@@ -17,11 +18,11 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
-"""Simple script to convert a .ini file to a gettext .po localization file."""
-
-from translate.convert import ini2po
+"""simple script to convert a .Net Resource (.resx) file to a
+Gettext PO localisation file"""
 
+from translate.convert import resx2po
 
 if __name__ == '__main__':
-    ini2po.main()
+    resx2po.main()
 
diff --git a/translate/convert/json2po.py b/translate/convert/resx2po.py
similarity index 56%
copy from translate/convert/json2po.py
copy to translate/convert/resx2po.py
index 0a91ab9..bf17dcd 100644
--- a/translate/convert/json2po.py
+++ b/translate/convert/resx2po.py
@@ -1,7 +1,8 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-# Copyright 2007, 2010 Zuza Software Foundation
+# Copyright 2015 Zuza Software Foundation
+# Copyright 2015 Sarah Hale
 #
 # This file is part of translate.
 #
@@ -18,9 +19,9 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
-"""Convert JSON files to Gettext PO localization files.
+"""Convert .Net Resource (.resx) to  Gettext PO localisation files  files.
 
-See: http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/json2po.html
+See: http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/resx2po.html
 for examples and usage instructions.
 """
 
@@ -28,31 +29,37 @@ import logging
 
 from translate.storage import po
 
-
 logger = logging.getLogger(__name__)
 
-
-class json2po:
-    """Convert a JSON file to a PO file"""
+class resx2po:
+    """Convert a RESX file to a PO file for handling translation"""
 
     def convert_store(self, input_store, duplicatestyle="msgctxt"):
-        """Converts a JSON file to a PO file"""
+        """Converts a RESX file to a PO file"""
         output_store = po.pofile()
-        output_header = output_store.header()
-        output_header.addnote("extracted from %s" % input_store.filename,
-                              "developer")
+        output_header = output_store.init_headers(charset="UTF-8",
+                                                  encoding="8bit",
+                                                  x_accelerator_marker="&")
+        output_header.addnote("extracted from %s" % input_store.filename, "developer")
         for input_unit in input_store.units:
-            output_unit = self.convert_unit(input_unit, "developer")
-            if output_unit is not None:
-                output_store.addunit(output_unit)
+            if input_unit.istranslatable():
+                output_unit = self.convert_unit(input_unit, "developer")
+                if output_unit is not None:
+
+                    # Split out translator & dev comments before adding them
+                    self.split_comments(output_unit, output_unit)
+
+                    output_store.addunit(output_unit)
+
         output_store.removeduplicates(duplicatestyle)
         return output_store
 
-    def merge_store(self, template_store, input_store, blankmsgstr=False,
-                    duplicatestyle="msgctxt"):
-        """Converts two JSON files to a PO file"""
+    def merge_store(self, template_store, input_store, blankmsgstr=False, duplicatestyle="msgctxt"):
+        """Converts two RESX files to a PO file"""
         output_store = po.pofile()
-        output_header = output_store.header()
+        output_header = output_store.init_headers(charset="UTF-8",
+                                                  encoding="8bit",
+                                                  x_accelerator_marker="&")
         output_header.addnote("extracted from %s, %s" % (template_store.filename,
                                                          input_store.filename),
                               "developer")
@@ -60,53 +67,65 @@ class json2po:
         input_store.makeindex()
         for template_unit in template_store.units:
             origpo = self.convert_unit(template_unit, "developer")
+
             # try and find a translation of the same name...
             template_unit_name = "".join(template_unit.getlocations())
             if template_unit_name in input_store.locationindex:
-                translatedjson = input_store.locationindex[template_unit_name]
-                translatedpo = self.convert_unit(translatedjson, "translator")
+                translatedresx = input_store.locationindex[template_unit_name]
+                translatedpo = self.convert_unit(translatedresx, "translator")
             else:
                 translatedpo = None
+
             # if we have a valid po unit, get the translation and add it...
             if origpo is not None:
                 if translatedpo is not None and not blankmsgstr:
                     origpo.target = translatedpo.source
+
+                    # Split out translator & dev comments before adding them
+                    self.split_comments(origpo, translatedpo)
+
                 output_store.addunit(origpo)
+
             elif translatedpo is not None:
-                logger.error("error converting original JSON definition %s",
-                             origpo.name)
+                logger.error("Error converting original RESX definition %s" % origpo)
+
         output_store.removeduplicates(duplicatestyle)
         return output_store
 
-    def convert_unit(self, input_unit, commenttype):
-        """Converts a JSON unit to a PO unit
+    def split_comments(self, origpo, translatedpo):
+        autocomments = translatedpo.getnotes("developer")
+        if autocomments:
+            devcomment, transcomment = autocomments.partition('[Translator Comment: ')[::2]
+            if transcomment:
+                    origpo.addnote(transcomment.replace("]", ""), origin="translator")
+            if devcomment:
+                origpo.addnote(devcomment.strip(), origin="developer", position="merge")
 
-        :return: None if empty or not for translation
+    def convert_unit(self, input_unit, commenttype):
+        """Converts a RESX unit to a PO unit
+        @return: None if empty or not for translation
         """
         if input_unit is None:
             return None
-        # escape unicode
+
         output_unit = po.pounit(encoding="UTF-8")
         output_unit.addlocation(input_unit.getid())
         output_unit.source = input_unit.source
+        output_unit.addnote(input_unit.getnotes("developer"), "developer")
         output_unit.target = ""
+
         return output_unit
 
+def convert_resx(input_file, output_file, template_file, pot=False, duplicatestyle="msgctxt", filter=None):
+
+    from translate.storage import resx
 
-def convertjson(input_file, output_file, template_file, pot=False,
-                duplicatestyle="msgctxt", dialect="default", filter=None):
-    """Reads in *input_file* using jsonl10n, converts using :class:`json2po`,
-    writes to *output_file*."""
-    from translate.storage import jsonl10n
-    if filter is not None:
-        filter = filter.split(',')
-    input_store = jsonl10n.JsonFile(input_file, filter=filter)
-    convertor = json2po()
+    input_store = resx.RESXFile(input_file)
+    convertor = resx2po()
     if template_file is None:
-        output_store = convertor.convert_store(input_store,
-                                               duplicatestyle=duplicatestyle)
+        output_store = convertor.convert_store(input_store, duplicatestyle=duplicatestyle)
     else:
-        template_store = jsonl10n.JsonFile(template_file)
+        template_store = resx.RESXFile(template_file)
         output_store = convertor.merge_store(template_store, input_store,
                                              blankmsgstr=pot,
                                              duplicatestyle=duplicatestyle)
@@ -119,11 +138,10 @@ def convertjson(input_file, output_file, template_file, pot=False,
 def main(argv=None):
     from translate.convert import convert
     formats = {
-               "json": ("po", convertjson),
-               ("json", "json"): ("po", convertjson),
+               "resx": ("po", convert_resx),
+               ("resx", "resx"): ("po", convert_resx),
               }
-    parser = convert.ConvertOptionParser(formats, usetemplates=True,
-                                         usepots=True, description=__doc__)
+    parser = convert.ConvertOptionParser(formats, usetemplates=True, usepots=True, description=__doc__)
     parser.add_option("", "--filter", dest="filter", default=None,
             help="leaves to extract e.g. 'name,desc': (default: extract everything)",
             metavar="FILTER")
diff --git a/translate/convert/roundtrip-OOo b/translate/convert/roundtrip-OOo
new file mode 100755
index 0000000..8fbb95f
--- /dev/null
+++ b/translate/convert/roundtrip-OOo
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+enpodir=en-po
+gsidir=.gsi
+
+mkdir -p $gsidir
+
+which oo2po
+if [ $? -ne 0 ]; then
+	echo "Please install oo2po and friends"
+	exit 1
+fi
+
+cd $gsidir
+
+# Get files from Pavel
+if [ "$1" != "--no-download" ]; then
+	echo "Downloading files:"
+	curl --remote-time --remote-name ftp://ftp.linux.cz/pub/localization/OpenOffice.org/devel/POT/OpenOffice.org-POT-stable-latest.tar.gz 
+	curl --remote-time --remote-name ftp://ftp.linux.cz/pub/localization/OpenOffice.org/devel/POT/OpenOffice.org-POT-latest.tar.gz 
+fi
+
+for gsi in $(ls OpenOffice.org*POT*.tar.gz)
+do
+        gsiroot=$(echo $gsi | sed "s/\.tar\.gz//")
+        echo "### Checking $gsi ###"
+        echo "Untarring"
+	tar xzf $gsi || break
+	rm -rf pot
+
+	echo "Convert GSI to POT and XLIFF:"
+        potdir=$gsiroot.pot
+        xlfdir=$gsiroot.xlf
+        mkdir -p $potdir $xlfdir
+	oo2po -P en-US.sdf $potdir
+	oo2xliff -l en-XX en-US.sdf $xlfdir
+	
+        enpodir=$gsiroot.en.po
+        enxlfdir=$gsiroot.en.xlf
+	echo "Create English 'translations':"
+        rm -rf $enpodir $enxlfdir
+        mkdir -p $enpodir $enxlfdir
+	podebug -f "" --rewrite=en $potdir $enpodir
+	podebug -f "" --rewrite=en $xlfdir $enxlfdir
+
+	
+        targetposdf=$gsiroot.po.sdf
+        targetxlfsdf=$gsiroot.xlf.sdf
+	echo "Create $targetposdf and $targetxlfsdf:"
+	po2oo -l en-XX -t en-US.sdf $enpodir $targetposdf
+	xliff2oo -l en-XX -t en-US.sdf $enpodir $targetxlfsdf
+	
+	# Check for lines that are not duplicated
+	echo "Analysing (you should see nothing between START and END, anything else is a roundtrip issue):"
+        echo "---START - Gettext PO---"
+	cut -f11,13,14 $targetposdf | uniq -u
+        echo "---START - XLIFF---"
+	cut -f11,13,14 $targetxlfsdf | uniq -u
+        echo "----END----"
+done
diff --git a/translate/convert/roundtrip-gaia b/translate/convert/roundtrip-gaia
new file mode 100755
index 0000000..4072708
--- /dev/null
+++ b/translate/convert/roundtrip-gaia
@@ -0,0 +1,58 @@
+#!/bin/bash
+# Script for getting a diff between real Mozilla translation files and the ones
+# obtained after a roundtrip conversion of those.
+
+# Check if necessary commands are installed.
+check_if_is_installed () {
+    if [ ! `command -v $1` ]
+    then
+        echo >&2
+        echo >&2 "Error: $1 is not installed. Aborting."
+        echo >&2
+        exit 1
+    fi
+}
+check_if_is_installed git
+check_if_is_installed mkdir
+check_if_is_installed rm
+check_if_is_installed moz2po
+check_if_is_installed podebug
+check_if_is_installed po2moz
+check_if_is_installed diff
+check_if_is_installed date
+
+# Get or update the Mozilla translation template files.
+GIT_REPO="mozilla-gaia"
+if [ -d "$GIT_REPO/.git" ]
+then
+    # If repo is already cloned, then just pull the latest changes.
+    cd $GIT_REPO
+    git pull origin master
+    cd ../
+else
+    # If repo is missing, then clone it.
+    git clone git://github.com/translate/$GIT_REPO.git $GIT_REPO
+fi
+echo
+
+# Set the variables.
+TEMPLATES_DIR="$GIT_REPO/build/locales/en-US/"
+PO_DIR="po/"
+REWRITTEN_DIR="rewritten-po/"
+RESULTS_DIR="templates-recreated/"
+
+# Prepare the working directories.
+mkdir -p $PO_DIR
+mkdir -p $REWRITTEN_DIR
+mkdir -p $RESULTS_DIR
+rm -rf $PO_DIR*
+rm -rf $REWRITTEN_DIR*
+rm -rf $RESULTS_DIR*
+
+# Run the tools for the roundtrip.
+prop2po --personality=gaia --progress=none $TEMPLATES_DIR $PO_DIR
+podebug --progress=none --rewrite=en $PO_DIR $REWRITTEN_DIR
+po2prop --personality=gaia --progress=none -t $TEMPLATES_DIR $REWRITTEN_DIR $RESULTS_DIR
+
+# Diff the resulting templates against the original ones.
+diff -u -r $TEMPLATES_DIR $RESULTS_DIR > diff_$(date -u +%F_%T).diff
diff --git a/translate/convert/roundtrip-mozilla b/translate/convert/roundtrip-mozilla
new file mode 100755
index 0000000..b567b8e
--- /dev/null
+++ b/translate/convert/roundtrip-mozilla
@@ -0,0 +1,59 @@
+#!/bin/bash
+# Script for getting a diff between real Mozilla translation files and the ones
+# obtained after a roundtrip conversion of those.
+
+# Check if necessary commands are installed.
+check_if_is_installed () {
+    if [ ! `command -v $1` ]
+    then
+        echo >&2
+        echo >&2 "Error: $1 is not installed. Aborting."
+        echo >&2
+        exit 1
+    fi
+}
+check_if_is_installed git
+check_if_is_installed mkdir
+check_if_is_installed rm
+check_if_is_installed moz2po
+check_if_is_installed podebug
+check_if_is_installed po2moz
+check_if_is_installed diff
+check_if_is_installed date
+
+# Get or update the Mozilla translation template files.
+GIT_REPO="mozilla-l10n"
+if [ -d "$GIT_REPO/.git" ]
+then
+    # If repo is already cloned, then just pull the latest changes.
+    cd $GIT_REPO
+    git pull origin master
+    cd ../
+else
+    # If repo is missing, then clone it.
+    git clone git://github.com/translate/mozilla-l10n.git $GIT_REPO
+fi
+echo
+
+# Set the variables.
+TEMPLATES_DIR="$GIT_REPO/templates-en-US/"
+PO_DIR="po/"
+REWRITTEN_DIR="rewritten-po/"
+RESULTS_DIR="templates-recreated/"
+
+# Prepare the working directories.
+mkdir -p $PO_DIR
+mkdir -p $REWRITTEN_DIR
+mkdir -p $RESULTS_DIR
+rm -rf $PO_DIR*
+rm -rf $REWRITTEN_DIR*
+rm -rf $RESULTS_DIR*
+
+# Run the tools for the roundtrip.
+moz2po --progress=none $TEMPLATES_DIR $PO_DIR
+podebug --progress=none --rewrite=en $PO_DIR $REWRITTEN_DIR
+po2moz --progress=none -t $TEMPLATES_DIR $REWRITTEN_DIR $RESULTS_DIR
+
+# Diff the resulting templates against the original ones.
+diff -u -r $TEMPLATES_DIR $RESULTS_DIR > diff_$(date -u +%F_%T).diff
+
diff --git a/translate/convert/test_mozlang2po.py b/translate/convert/test_mozlang2po.py
index c931b18..a2a864f 100644
--- a/translate/convert/test_mozlang2po.py
+++ b/translate/convert/test_mozlang2po.py
@@ -45,7 +45,7 @@ class TestLang2PO:
         assert pounit.source == "One"
         assert pounit.target == "Een"
 
-    def test_simpleentry(self):
+    def test_simplecomment(self):
         """Handle simple comments"""
         source = '# Comment\n;One\nEen\n'
         pofile = self.lang2po(source)
@@ -54,6 +54,13 @@ class TestLang2PO:
         assert pounit.target == "Een"
         assert pounit.getnotes() == "Comment"
 
+    def test_meta_tags(self):
+        """Meta tags are not extracted"""
+        source = '## tag\n# Comment\n;One\nEen\n'
+        pofile = self.lang2po(source)
+        pounit = self.singleelement(pofile)
+        assert not "tag" in pounit.getnotes()
+
 
 class TestLang2POCommand(test_convert.TestConvertCommand, TestLang2PO):
     """Tests running actual lang2po commands on files"""
diff --git a/translate/convert/test_po2dtd.py b/translate/convert/test_po2dtd.py
index 2241075..ebf7397 100644
--- a/translate/convert/test_po2dtd.py
+++ b/translate/convert/test_po2dtd.py
@@ -452,7 +452,7 @@ msgstr "Simple string 3"
         print(dtdfile)
         assert str(dtdfile) == dtdexpected
 
-    def test_preserving_spaces(self):
+    def test_preserving_spaces_after_value(self):
         """Preseve spaces after value. Bug 1662"""
         # Space between value and >
         posource = '''#: simple.label\nmsgid "One"\nmsgstr "Een"\n'''
diff --git a/translate/convert/test_po2resx.py b/translate/convert/test_po2resx.py
new file mode 100644
index 0000000..623b652
--- /dev/null
+++ b/translate/convert/test_po2resx.py
@@ -0,0 +1,438 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2015 Zuza Software Foundation
+# Copyright 2015 Sarah Hale
+#
+# 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 this program; if not, see <http://www.gnu.org/licenses/>.
+
+""" Tests converting Gettext PO localisation files to .Net Resource (.resx) files """
+
+from translate.convert import po2resx, test_convert
+from translate.storage import po
+from translate.misc import wStringIO
+
+
+class TestPO2RESX:
+    XMLskeleton = '''<?xml version='1.0' encoding='utf-8'?>
+<root>
+  <xsd:schema xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0"/>
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string"/>
+              <xsd:attribute name="type" type="xsd:string"/>
+              <xsd:attribute name="mimetype" type="xsd:string"/>
+              <xsd:attribute ref="xml:space"/>
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string"/>
+              <xsd:attribute name="name" type="xsd:string"/>
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
+              <xsd:attribute ref="xml:space"/>
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required"/>
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  %s
+</root>
+'''
+
+    def po2resx(self, resxsource, po_source):
+        """ Helper that merges po translations to .resx source without requiring files """
+        po_store = po.pofile(po_source)
+        template_file = wStringIO.StringIO(resxsource)
+        convertor = po2resx.po2resx(template_file, po_store)
+        output_resx = convertor.convertstore()
+        return output_resx
+
+    def test_simpleunit(self):
+        """ Checks that a simple po entry definition converts properly to a resx entry """
+        po_source = r'''#: key
+msgid "Source Text"
+msgstr "Some translated text"'''
+        resx_template = self.XMLskeleton % '''<data name="key" xml:space="preserve">
+        <value></value>
+        </data>'''
+        expected_output = self.XMLskeleton % '''<data name="key" xml:space="preserve">
+        <value>Some translated text</value>
+    </data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_basic(self):
+        po_source = r"""# Afrikaans translation of program ABC
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2014-12-22 23:20+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
+"Language-Team: LANGUAGE <LL at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ResourceKey
+msgid "Applications"
+msgstr "Toepassings"
+"""
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        </data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Toepassings</value>
+    </data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_multiline(self):
+        """ Test multiline po entry """
+        po_source = r'''#: ResourceKey
+msgid "First part "
+"and extra"
+msgstr "Eerste deel "
+"en ekstra"'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        </data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Eerste deel en ekstra</value>
+    </data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_escapednewlines(self):
+        """ Test the escaping of newlines """
+        po_source = r'''#: ResourceKey
+msgid "First line\nSecond line"
+msgstr "Eerste lyn\nTweede lyn"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        </data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Eerste lyn
+Tweede lyn</value>
+    </data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_escapedtabs(self):
+        """ Test the escaping of tabs """
+        po_source = r'''#: ResourceKey
+msgid "First column\tSecond column"
+msgstr "Eerste kolom\tTweede kolom"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        </data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Eerste kolom\tTweede kolom</value>
+    </data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_escapedquotes(self):
+        """ Test the escaping of quotes (and slash) """
+        po_source = r'''#: ResourceKey
+msgid "Hello \"Everyone\""
+msgstr "Good day \"All\""
+
+msgid "Use \\\"."
+msgstr "Gebruik \\\"."
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        </data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Good day "All"</value>
+    </data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_exclusions(self):
+        """ Test that empty and fuzzy messages are excluded """
+        po_source = r'''#: ResourceKey
+#, fuzzy
+msgid "One"
+msgstr "Een"
+
+#: ResourceKey2
+msgid "Two"
+msgstr ""
+
+#: ResourceKey3
+msgid ""
+msgstr "Drie"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value/>
+    </data>
+<data name="ResourceKey2" xml:space="preserve">
+    <value/>
+</data>
+<data name="ResourceKey3" xml:space="preserve">
+    <value/>
+</data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value/>
+    </data>
+<data name="ResourceKey2" xml:space="preserve">
+    <value/>
+</data>
+<data name="ResourceKey3" xml:space="preserve">
+    <value/>
+</data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_automaticcomments(self):
+        """ Tests that automatic comments are imported """
+        po_source = r'''#. This is a comment
+#: ResourceKey
+msgid "Bézier curve"
+msgstr "Bézier-kurwe"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        </data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Bézier-kurwe</value>
+    <comment>This is a comment</comment></data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_automaticcomments_existingcomment(self):
+        """ Tests a differing automatic comment is added if there is an existing automatic comment """
+        po_source = r'''#. This is a new comment
+#: ResourceKey
+msgid "Bézier curve"
+msgstr "Bézier-kurwe"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        <comment>This is an existing comment</comment></data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Bézier-kurwe</value>
+    <comment>This is an existing comment
+This is a new comment</comment></data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_automaticcomments_existingduplicatecomment(self):
+        """ Tests there is no duplication of automatic comments if it already exists and hasn't changed """
+        po_source = r'''#. This is an existing comment
+#: ResourceKey
+msgid "Bézier curve"
+msgstr "Bézier-kurwe"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        <comment>This is an existing comment</comment></data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Bézier-kurwe</value>
+    <comment>This is an existing comment</comment></data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_automaticcomments_existingduplicatecommentwithwhitespace(self):
+        """ Tests there is no duplication of automatic comments if it already exists, hasn't changed but has leading or
+        trailing whitespaces """
+        po_source = r'''#.  This is an existing comment with leading and trailing spaces
+#: ResourceKey
+msgid "Bézier curve"
+msgstr "Bézier-kurwe"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        <comment> This is an existing comment with leading and trailing spaces </comment></data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Bézier-kurwe</value>
+    <comment>This is an existing comment with leading and trailing spaces</comment></data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_translatorcomments(self):
+        """ Tests that translator comments are imported """
+        po_source = r'''# This is a translator comment : 22.12.14
+#: ResourceKey
+msgid "Bézier curve"
+msgstr "Bézier-kurwe"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        </data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Bézier-kurwe</value>
+    <comment>[Translator Comment: This is a translator comment : 22.12.14]</comment></data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_translatorcomments_existingcomment(self):
+        """ Tests a differing translator comment is added if there is an existing translator comment """
+        po_source = r'''# This is a new translator comment
+#: ResourceKey
+msgid "Bézier curve"
+msgstr "Bézier-kurwe"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        <comment>[Translator Comment: This is an existing comment]</comment></data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Bézier-kurwe</value>
+    <comment>[Translator Comment: This is an existing comment]
+[Translator Comment: This is a new translator comment]</comment></data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_translatorcomments_existingduplicatecomment(self):
+        """ Tests there is no duplication of translator comments if it already exists and hasn't changed """
+        po_source = r'''# This is an existing translator comment
+#: ResourceKey
+msgid "Bézier curve"
+msgstr "Bézier-kurwe"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        <comment>[Translator Comment: This is an existing translator comment]</comment></data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Bézier-kurwe</value>
+    <comment>[Translator Comment: This is an existing translator comment]</comment></data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_combocomments(self):
+        """ Tests that translator comments and automatic comments are imported """
+        po_source = r'''#. This is a developer comment
+# This is a translator comment : 22.12.14
+#: ResourceKey
+msgid "Bézier curve"
+msgstr "Bézier-kurwe"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        </data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Bézier-kurwe</value>
+    <comment>This is a developer comment
+[Translator Comment: This is a translator comment : 22.12.14]</comment></data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_combocomments_existingduplicatecomment(self):
+        """ Tests there is no duplication of automatic comment if it already exists and hasn't changed, but still adds
+        the translator comment """
+        po_source = r'''#. This is an existing comment
+# This is a translator comment : 22.12.14
+#: ResourceKey
+msgid "Bézier curve"
+msgstr "Bézier-kurwe"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        <comment>This is an existing comment</comment></data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Bézier-kurwe</value>
+    <comment>This is an existing comment
+[Translator Comment: This is a translator comment : 22.12.14]</comment></data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_combocomments_existingcomment(self):
+        """ Tests a differing automatic comment is added if there is an existing automatic comment, but still adds
+        the translator comment """
+        po_source = r'''#. This is a new comment
+# This is a translator comment : 22.12.14
+#: ResourceKey
+msgid "Bézier curve"
+msgstr "Bézier-kurwe"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        <comment>This is an existing comment</comment></data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Bézier-kurwe</value>
+    <comment>This is an existing comment
+This is a new comment
+[Translator Comment: This is a translator comment : 22.12.14]</comment></data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+    def test_existingcomments(self):
+        """ Tests that no extra space is added when there are no changes to existing comments"""
+        po_source = r'''#. This is an existing comment
+# This is an existing translator comment : 22.12.14
+#: ResourceKey
+msgid "Bézier curve"
+msgstr "Bézier-kurwe"
+'''
+        resx_template = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value></value>
+        <comment>This is an existing comment
+[Translator Comment: This is an existing translator comment : 22.12.14]</comment></data>'''
+        expected_output = self.XMLskeleton % '''<data name="ResourceKey" xml:space="preserve">
+        <value>Bézier-kurwe</value>
+    <comment>This is an existing comment
+[Translator Comment: This is an existing translator comment : 22.12.14]</comment></data>'''
+        resx_file = self.po2resx(resx_template, po_source)
+        assert resx_file == expected_output
+
+
+class TestPO2TSCommand(test_convert.TestConvertCommand, TestPO2RESX):
+    """ Tests running actual po2ts commands on files """
+    convertmodule = po2resx
+
+    def test_help(self):
+        """ Tests getting help """
+        options = test_convert.TestConvertCommand.test_help(self)
+        options = self.help_check(options, "-t TEMPLATE, --template=TEMPLATE")
diff --git a/translate/convert/test_resx2po.py b/translate/convert/test_resx2po.py
new file mode 100644
index 0000000..95b650a
--- /dev/null
+++ b/translate/convert/test_resx2po.py
@@ -0,0 +1,237 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2015 Zuza Software Foundation
+# Copyright 2015 Sarah Hale
+#
+# 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 this program; if not, see <http://www.gnu.org/licenses/>.
+
+""" Tests converting .Net Resource (.resx) to Gettext PO localisation files """
+
+from translate.convert import test_convert, resx2po
+from translate.misc import wStringIO
+from translate.storage import po, resx
+from translate.storage.poheader import poheader
+from translate.storage.test_base import headerless_len
+
+
+class TestRESX2PO:
+    target_filetype = po.pofile
+    XMLskeleton = '''<?xml version="1.0" encoding="utf-8"?>
+    <root>
+      <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+        <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+        <xsd:element name="root" msdata:IsDataSet="true">
+          <xsd:complexType>
+            <xsd:choice maxOccurs="unbounded">
+              <xsd:element name="metadata">
+                <xsd:complexType>
+                  <xsd:sequence>
+                    <xsd:element name="value" type="xsd:string" minOccurs="0" />
+                  </xsd:sequence>
+                  <xsd:attribute name="name" use="required" type="xsd:string" />
+                  <xsd:attribute name="type" type="xsd:string" />
+                  <xsd:attribute name="mimetype" type="xsd:string" />
+                  <xsd:attribute ref="xml:space" />
+                </xsd:complexType>
+              </xsd:element>
+              <xsd:element name="assembly">
+                <xsd:complexType>
+                  <xsd:attribute name="alias" type="xsd:string" />
+                  <xsd:attribute name="name" type="xsd:string" />
+                </xsd:complexType>
+              </xsd:element>
+              <xsd:element name="data">
+                <xsd:complexType>
+                  <xsd:sequence>
+                    <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                    <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+                  </xsd:sequence>
+                  <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+                  <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+                  <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+                  <xsd:attribute ref="xml:space" />
+                </xsd:complexType>
+              </xsd:element>
+              <xsd:element name="resheader">
+                <xsd:complexType>
+                  <xsd:sequence>
+                    <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                  </xsd:sequence>
+                  <xsd:attribute name="name" type="xsd:string" use="required" />
+                </xsd:complexType>
+              </xsd:element>
+            </xsd:choice>
+          </xsd:complexType>
+        </xsd:element>
+      </xsd:schema>
+      <resheader name="resmimetype">
+        <value>text/microsoft-resx</value>
+      </resheader>
+      <resheader name="version">
+        <value>2.0</value>
+      </resheader>
+      %s
+    </root>
+    '''
+
+    def resx2po(self, resxsource, template=None, filter=None):
+        """ Helper that converts resx source to po source without requiring files """
+        inputfile = wStringIO.StringIO(resxsource)
+        inputresx = resx.RESXFile(inputfile)
+        convertor = resx2po.resx2po()
+        outputpo = convertor.convert_store(inputresx)
+        return outputpo
+
+    def test_simple(self):
+        """ Test the most basic resx conversion """
+        resx_source = self.XMLskeleton % '''<data name="key" xml:space="preserve">
+        <value>A simple string</value>
+        </data>'''
+        poexpected = '''#: key
+msgid "A simple string"
+msgstr ""
+'''
+        po_result = self.resx2po(resx_source)
+
+        assert str(po_result.units[1]) == poexpected
+        assert headerless_len(po_result.units) == 1
+
+    def test_multiple_units(self):
+        """ Test that we can handle resx with multiple units """
+        resx_source = self.XMLskeleton % '''<data name="key" xml:space="preserve">
+        <value>A simple string</value>
+        </data>
+        <data name="key_two" xml:space="preserve">
+        <value>A second simple string with a @@placeholder@@</value>
+        </data>'''
+
+        po_result = self.resx2po(resx_source)
+        assert po_result.units[0].isheader()
+        assert len(po_result.units) == 3
+
+    def test_automaticcomments(self):
+        """ Tests developer comments """
+        resx_source = self.XMLskeleton % '''<data name="key" xml:space="preserve">
+        <value>A simple string</value>
+        <comment>This is a comment</comment>
+        </data>
+        <data name="key_two" xml:space="preserve">
+        <value>A second simple string with a @@placeholder@@</value>
+        </data>'''
+        po_result = self.resx2po(resx_source)
+
+        assert len(po_result.units) == 3
+        assert po_result.units[1].getnotes("developer") == u"This is a comment"
+        assert po_result.units[2].getnotes("developer") == u""
+
+    def test_translatorcomments(self):
+        """ Tests translator comments """
+        resx_source = self.XMLskeleton % '''<data name="key" xml:space="preserve">
+        <value>A simple string</value>
+        <comment>This is a developer comment
+[Translator Comment: This is a translator comment]</comment>
+        </data>
+        <data name="key_two" xml:space="preserve">
+        <value>A second simple string with a @@placeholder@@</value>
+        </data>'''
+        po_result = self.resx2po(resx_source)
+
+        assert len(po_result.units) == 3
+        assert po_result.units[1].getnotes("developer") == u"This is a developer comment"
+        assert po_result.units[1].getnotes("translator") == u"This is a translator comment"
+        assert po_result.units[2].getnotes("developer") == u""
+        assert po_result.units[2].getnotes("translator") == u""
+
+    def test_locations(self):
+        """ Tests location comments (#:) """
+        resx_source = self.XMLskeleton % '''<data name="key" xml:space="preserve">
+        <value>A simple string</value>
+        <comment>This is a developer comment</comment>
+        </data>
+        <data name="key_two" xml:space="preserve">
+        <value>A second simple string with a @@placeholder@@</value>
+        </data>'''
+
+        po_result = self.resx2po(resx_source)
+
+        assert len(po_result.units) == 3
+        assert po_result.units[1].getlocations()[0].startswith("key")
+        assert po_result.units[2].getlocations()[0].startswith("key_two")
+
+class TestRESX2POCommand(test_convert.TestConvertCommand, TestRESX2PO):
+    """ Tests running actual resx2po commands on files """
+    convertmodule = resx2po
+    defaultoptions = {"progress": "none"}
+
+    def test_help(self):
+        """ Tests getting help"""
+        options = test_convert.TestConvertCommand.test_help(self)
+        options = self.help_check(options, "-P, --pot")
+        options = self.help_check(options, "--duplicates")
+        options = self.help_check(options, "-t TEMPLATE, --template=TEMPLATE")
+        options = self.help_check(options, "--filter", last=True)
+
+    def single_element(self, pofile):
+        """ Checks that the pofile contains a single non-header element, and returns it """
+        if isinstance(pofile, poheader):
+            assert len(pofile.units) == 2
+            assert pofile.units[0].isheader()
+            return pofile.units[1]
+        else:
+            assert len(pofile.units) == 1
+            return pofile.units[0]
+
+    def test_simple_pot(self):
+        """ Tests the simplest possible conversion to a pot file """
+        resx_source = self.XMLskeleton % '''<data name="key" xml:space="preserve">
+        <value>A simple string</value>
+        </data>'''
+
+        self.create_testfile("simple.resx", resx_source)
+        self.run_command("simple.resx", "simple.pot", pot=True)
+        po_result = po.pofile(self.open_testfile("simple.pot"))
+        po_element = self.single_element(po_result)
+
+        assert po_element.source == u"A simple string"
+        assert po_element.target == u""
+
+    def test_simple_po(self):
+        """ Tests the simplest possible conversion to a po file """
+        resx_source = self.XMLskeleton % '''<data name="key" xml:space="preserve">
+        <value>A simple string</value>
+        </data>'''
+        self.create_testfile("simple.resx", resx_source)
+        self.run_command("simple.resx", "simple.po")
+        po_result = po.pofile(self.open_testfile("simple.po"))
+        po_element = self.single_element(po_result)
+        assert po_element.source == "A simple string"
+        assert po_element.target == ""
+
+    def test_remove_duplicates(self):
+        """ Test that removing of duplicates works correctly """
+        resx_source = self.XMLskeleton % '''<data name="key" xml:space="preserve">
+        <value>A simple string</value>
+        </data>
+        <data name="key" xml:space="preserve">
+        <value>A simple string</value>
+        </data>'''
+        self.create_testfile("simple.resx", resx_source)
+        self.run_command("simple.resx", "simple.po", error="traceback", duplicates="merge")
+        po_result = self.target_filetype(self.open_testfile("simple.po"))
+
+        assert len(po_result.units) == 2
+        assert po_result.units[1].source == u"A simple string"
diff --git a/translate/convert/xliff2odf.py b/translate/convert/xliff2odf.py
index 07dc3e3..b0e899b 100644
--- a/translate/convert/xliff2odf.py
+++ b/translate/convert/xliff2odf.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-# Copyright 2004-2006 Zuza Software Foundation
+# Copyright 2004-2014 Zuza Software Foundation
 #
 # This file is part of translate.
 #
@@ -17,122 +17,141 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
-#
 
 """Convert XLIFF translation files to OpenDocument (ODF) files.
 
 See: http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/odf2xliff.html
 for examples and usage instructions.
 """
+
 import zipfile
 from cStringIO import StringIO
 
 import lxml.etree as etree
 
-from translate.storage import factory, odf_io, odf_shared
-from translate.storage.xml_extract import extract, generate, unit_tree
-
-
-def first_child(unit_node):
-    return unit_node.children.values()[0]
+from translate.convert import convert
+from translate.storage import factory
+from translate.storage.odf_io import copy_odf, open_odf
+from translate.storage.odf_shared import (inline_elements,
+                                          no_translate_content_elements)
+from translate.storage.xml_extract.extract import ParseState
+from translate.storage.xml_extract.generate import (apply_translations,
+                                                    replace_dom_text)
+from translate.storage.xml_extract.unit_tree import XPathTree, build_unit_tree
 
 
 def translate_odf(template, input_file):
 
     def load_dom_trees(template):
-        odf_data = odf_io.open_odf(template)
-        return dict((filename, etree.parse(StringIO(data))) for filename, data in odf_data.iteritems())
+        """Return a dict with translatable files in the template ODF package.
+
+        The keys are the filenames inside the ODF package, and the values are
+        the etrees for each of those translatable files.
+        """
+        odf_data = open_odf(template)
+        return dict((filename, etree.parse(StringIO(data)))
+                    for filename, data in odf_data.iteritems())
+
+    def load_unit_tree(input_file):
+        """Return a dict with the translations grouped by files ODF package.
 
-    def load_unit_tree(input_file, dom_trees):
+        The keys are the filenames inside the template ODF package, and the
+        values are XPathTree instances for each of those files.
+        """
         store = factory.getobject(input_file)
-        tree = unit_tree.build_unit_tree(store)
+        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'"""
+            """Find the subtree in 'tree' which corresponds to the data in XML
+            file 'filename'.
+            """
+            try:
+                file_tree = tree.children[root_dom_element_name, 0]
+            except KeyError:
+                file_tree = XPathTree()
 
-            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 (filename, file_tree)
 
-        return dict([extract_unit_tree('content.xml', 'document-content'),
-                     extract_unit_tree('meta.xml', 'document-meta'),
-                     extract_unit_tree('styles.xml', 'document-styles')])
+        return dict([extract_unit_tree('content.xml', 'office:document-content'),
+                     extract_unit_tree('meta.xml', 'office:document-meta'),
+                     extract_unit_tree('styles.xml', 'office: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)
+        """Return a dict with the translated files for the ODF package.
+
+        The keys are the filenames for the translatable files inside the
+        template ODF package, and the values are etree ElementTree instances
+        for each of those files.
+        """
+        make_parse_state = lambda: ParseState(no_translate_content_elements,
+                                              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))
+            apply_translations(dom_tree.getroot(), file_unit_tree,
+                               replace_dom_text(make_parse_state))
         return dom_trees
 
-    # Since the convertoptionsparser will give us an open file, we risk that
-    # it could have been opened in non-binary mode on Windows, and then we'll
-    # have problems, so let's make sure we have what we want.
-    template.close()
-    template = file(template.name, mode='rb')
     dom_trees = load_dom_trees(template)
-    unit_trees = load_unit_tree(input_file, dom_trees)
+    unit_trees = load_unit_tree(input_file)
     return translate_dom_trees(unit_trees, dom_trees)
 
 
-def write_odf(xlf_data, template, output_file, dom_trees):
+def write_odf(template, output_file, dom_trees):
+    """Write the translated ODF package.
 
-    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))
+    The resulting ODF package is a copy of the template ODF package, with the
+    translatable files replaced by their translated versions.
+    """
+    template_zip = zipfile.ZipFile(template, 'r')
+    output_zip = zipfile.ZipFile(output_file, 'w',
+                                 compression=zipfile.ZIP_DEFLATED)
+
+    # Copy the ODF package.
+    output_zip = copy_odf(template_zip, output_zip, dom_trees.keys())
 
+    # Overwrite the translated files to the ODF package.
+    for filename, dom_tree in dom_trees.iteritems():
+        output_zip.writestr(filename, etree.tostring(dom_tree,
+                                                     encoding='UTF-8',
+                                                     xml_declaration=True))
+
+
+def convertxliff(input_file, output_file, template):
+    """Create a translated ODF using an ODF template and a XLIFF file."""
     # Since the convertoptionsparser will give us an open file, we risk that
     # it could have been opened in non-binary mode on Windows, and then we'll
     # have problems, so let's make sure we have what we want.
     template.close()
     template = file(template.name, mode='rb')
-    template_zip = zipfile.ZipFile(template, 'r')
     output_file.close()
     output_file = file(output_file.name, mode='wb')
-    output_zip = zipfile.ZipFile(output_file, 'w', compression=zipfile.ZIP_DEFLATED)
-    # Let's keep the XLIFF file out of the generated ODF for now. Note the
-    # weird handling of the manifest since it can only be written to the ZIP
-    # file once.
-#    output_zip = odf_io.copy_odf(template_zip, output_zip, dom_trees.keys() + ['META-INF/manifest.xml'])
-#    output_zip = odf_io.add_file(output_zip, template_zip.read('META-INF/manifest.xml'), 'translation.xlf', xlf_data)
-    output_zip = odf_io.copy_odf(template_zip, output_zip, 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"""
     xlf_data = input_file.read()
     dom_trees = translate_odf(template, StringIO(xlf_data))
-    write_odf(xlf_data, template, output_file, dom_trees)
+    write_odf(template, output_file, dom_trees)
     output_file.close()
     return True
 
-formats = {
-    ('xlf', 'odt'): ("odt", convertxliff),  # Text
-    ('xlf', 'ods'): ("ods", convertxliff),  # Spreadsheet
-    ('xlf', 'odp'): ("odp", convertxliff),  # Presentation
-    ('xlf', 'odg'): ("odg", convertxliff),  # Drawing
-    ('xlf', 'odc'): ("odc", convertxliff),  # Chart
-    ('xlf', 'odf'): ("odf", convertxliff),  # Formula
-    ('xlf', 'odi'): ("odi", convertxliff),  # Image
-    ('xlf', 'odm'): ("odm", convertxliff),  # Master Document
-    ('xlf', 'ott'): ("ott", convertxliff),  # Text template
-    ('xlf', 'ots'): ("ots", convertxliff),  # Spreadsheet template
-    ('xlf', 'otp'): ("otp", convertxliff),  # Presentation template
-    ('xlf', 'otg'): ("otg", convertxliff),  # Drawing template
-    ('xlf', 'otc'): ("otc", convertxliff),  # Chart template
-    ('xlf', 'otf'): ("otf", convertxliff),  # Formula template
-    ('xlf', 'oti'): ("oti", convertxliff),  # Image template
-    ('xlf', 'oth'): ("oth", convertxliff),  # Web page template
-}
-
 
 def main(argv=None):
-    from translate.convert import convert
-
+    formats = {
+        ('xlf', 'odt'): ("odt", convertxliff),  # Text
+        ('xlf', 'ods'): ("ods", convertxliff),  # Spreadsheet
+        ('xlf', 'odp'): ("odp", convertxliff),  # Presentation
+        ('xlf', 'odg'): ("odg", convertxliff),  # Drawing
+        ('xlf', 'odc'): ("odc", convertxliff),  # Chart
+        ('xlf', 'odf'): ("odf", convertxliff),  # Formula
+        ('xlf', 'odi'): ("odi", convertxliff),  # Image
+        ('xlf', 'odm'): ("odm", convertxliff),  # Master Document
+        ('xlf', 'ott'): ("ott", convertxliff),  # Text template
+        ('xlf', 'ots'): ("ots", convertxliff),  # Spreadsheet template
+        ('xlf', 'otp'): ("otp", convertxliff),  # Presentation template
+        ('xlf', 'otg'): ("otg", convertxliff),  # Drawing template
+        ('xlf', 'otc'): ("otc", convertxliff),  # Chart template
+        ('xlf', 'otf'): ("otf", convertxliff),  # Formula template
+        ('xlf', 'oti'): ("oti", convertxliff),  # Image template
+        ('xlf', 'oth'): ("oth", convertxliff),  # Web page template
+    }
     parser = convert.ConvertOptionParser(formats, usetemplates=True, description=__doc__)
     parser.run(argv)
 
diff --git a/translate/filters/checks.py b/translate/filters/checks.py
index bf954f5..63c31bd 100644
--- a/translate/filters/checks.py
+++ b/translate/filters/checks.py
@@ -52,6 +52,8 @@ logger = logging.getLogger(__name__)
 # (see https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html)
 printf_pat = re.compile('''
         %(                          # initial %
+        (?P<boost_ord>\d+)%         # boost::format style variable order, like %1%
+        |
               (?:(?P<ord>\d+)\$|    # variable order, like %1$s
               \((?P<key>\w+)\))?    # Python style variables, like %(var)s
         (?P<fullvar>
@@ -59,7 +61,7 @@ printf_pat = re.compile('''
             (?:\d+)?                # width
             (?:\.\d+)?              # precision
             (hh\|h\|l\|ll)?         # length formatting
-            (?P<type>[\w%@]))       # type (%s, %d, etc.)
+            (?P<type>[\w@]))        # type (%s, %d, etc.)
         )''', re.VERBOSE)
 
 # The name of the XML tag
@@ -615,7 +617,11 @@ class StandardChecker(TranslationChecker):
 
     @extraction
     def untranslated(self, str1, str2):
-        """Checks whether a string has been translated at all."""
+        """Checks whether a string has been translated at all.
+
+        This check is really only useful if you want to extract untranslated
+        strings so that they can be translated independently of the main work.
+        """
         str2 = prefilters.removekdecomments(str2)
 
         return not (len(str1.strip()) > 0 and len(str2) == 0)
@@ -625,6 +631,10 @@ class StandardChecker(TranslationChecker):
     def unchanged(self, str1, str2):
         """Checks whether a translation is basically identical to the original
         string.
+
+        This checks to see if the translation isn’t just a copy of the English
+        original. Sometimes, this is what you want, but other times you will
+        detect words that should have been translated.
         """
         str1 = self.filteraccelerators(self.removevariables(str1)).strip()
         str2 = self.filteraccelerators(self.removevariables(str2)).strip()
@@ -656,7 +666,13 @@ class StandardChecker(TranslationChecker):
 
     @functional
     def blank(self, str1, str2):
-        """Checks whether a translation only contains spaces."""
+        """Checks whether a translation is totally blank.
+
+        This will check to see if a translation has inadvertently been
+        translated as blank i.e. as spaces. This is different from untranslated
+        which is completely empty. This test is useful in that if something is
+        translated as "  " it will appear to most tools as if it is translated.
+        """
         len1 = len(str1.strip())
         len2 = len(str2.strip())
 
@@ -670,6 +686,11 @@ class StandardChecker(TranslationChecker):
     def short(self, str1, str2):
         """Checks whether a translation is much shorter than the original
         string.
+
+        This is most useful in the special case where the translation is 1
+        characters long while the source text is multiple characters long.
+        Otherwise, we use a general ratio that will catch very big differences
+        but is set conservatively to limit the number of false positives.
         """
         len1 = len(str1.strip())
         len2 = len(str2.strip())
@@ -684,6 +705,12 @@ class StandardChecker(TranslationChecker):
     def long(self, str1, str2):
         """Checks whether a translation is much longer than the original
         string.
+
+        This is most useful in the special case where the translation is
+        multiple characters long while the source text is only 1 character
+        long. Otherwise, we use a general ratio that will catch very big
+        differences but is set conservatively to limit the number of false
+        positives.
         """
         len1 = len(str1.strip())
         len2 = len(str2.strip())
@@ -696,7 +723,11 @@ class StandardChecker(TranslationChecker):
 
     @critical
     def escapes(self, str1, str2):
-        """Checks whether escaping is consistent between the two strings."""
+        """Checks whether escaping is consistent between the two strings.
+
+        Checks escapes such as ``\\n`` ``\uNNNN`` to ensure that if they exist
+        in the original string you also have them in the translation.
+        """
         if not helpers.countsmatch(str1, str2, (u"\\", u"\\\\")):
             escapes1 = u", ".join([u"'%s'" % word for word in str1.split() if u"\\" in word])
             escapes2 = u", ".join([u"'%s'" % word for word in str2.split() if u"\\" in word])
@@ -710,7 +741,11 @@ class StandardChecker(TranslationChecker):
 
     @critical
     def newlines(self, str1, str2):
-        """Checks whether newlines are consistent between the two strings."""
+        """Checks whether newlines are consistent between the two strings.
+
+        Counts the number of ``\\n`` newlines (and variants such as ``\\r\\n``)
+        and reports and error if they differ.
+        """
         if not helpers.countsmatch(str1, str2, (u"\n", u"\r")):
             raise FilterFailure(u"Different line endings")
 
@@ -725,7 +760,11 @@ class StandardChecker(TranslationChecker):
 
     @critical
     def tabs(self, str1, str2):
-        """Checks whether tabs are consistent between the two strings."""
+        """Checks whether tabs are consistent between the two strings.
+
+        Counts the number of ``\\t`` tab markers and reports an error if they
+        differ.
+        """
         if not helpers.countmatch(str1, str2, "\t"):
             raise SeriousFilterFailure(u"Different tabs")
         else:
@@ -734,7 +773,15 @@ class StandardChecker(TranslationChecker):
 
     @cosmetic
     def singlequoting(self, str1, str2):
-        """Checks whether singlequoting is consistent between the two strings."""
+        """Checks whether singlequoting is consistent between the two strings.
+
+        The same as doublequoting but checks for the ``'`` character. Because
+        this is used in contractions like it's and in possessive forms like
+        user's, this test can output spurious errors if your language doesn't
+        use such forms. If a quote appears at the end of a sentence in the
+        translation, i.e. ``'.``, this might not be detected properly by the
+        check.
+        """
         str1 = self.filterwordswithpunctuation(self.filteraccelerators(self.filtervariables(str1)))
         str1 = self.config.lang.punctranslate(str1)
 
@@ -748,8 +795,12 @@ class StandardChecker(TranslationChecker):
 
     @cosmetic
     def doublequoting(self, str1, str2):
-        """Checks whether doublequoting is consistent between the
-        two strings.
+        """Checks whether doublequoting is consistent between the two strings.
+
+        Checks on double quotes ``"`` to ensure that you have the same number
+        in both the original and the translated string. This tests takes into
+        account that several languages use different quoting characters, and
+        will test for them instead.
         """
         str1 = self.filteraccelerators(self.filtervariables(str1))
         str1 = self.filterxml(str1)
@@ -767,7 +818,13 @@ class StandardChecker(TranslationChecker):
 
     @cosmetic
     def doublespacing(self, str1, str2):
-        """Checks for bad double-spaces by comparing to original."""
+        """Checks for bad double-spaces by comparing to original.
+
+        This will identify if you have [space][space] in when you don't have it
+        in the original or it appears in the original but not in your
+        translation. Some of these are spurious and how you correct them
+        depends on the conventions of your language.
+        """
         str1 = self.filteraccelerators(str1)
         str2 = self.filteraccelerators(str2)
 
@@ -779,7 +836,16 @@ class StandardChecker(TranslationChecker):
 
     @cosmetic
     def puncspacing(self, str1, str2):
-        """Checks for bad spacing after punctuation."""
+        """Checks for bad spacing after punctuation.
+
+        In the case of [full-stop][space] in the original, this test checks
+        that your translation does not remove the space. It checks also for
+        [comma], [colon], etc.
+
+        Some languages don't use spaces after common punctuation marks,
+        especially where full-width punctuation marks are used. This check will
+        take that into account.
+        """
         # Convert all nbsp to space, and just check spaces. Useful intermediate
         # step to stricter nbsp checking?
         str1 = self.filteraccelerators(self.filtervariables(str1))
@@ -819,7 +885,21 @@ class StandardChecker(TranslationChecker):
 
     @critical
     def printf(self, str1, str2):
-        """Checks whether printf format strings match."""
+        """Checks whether printf format strings match.
+
+        If the printf formatting variables are not identical, then this will
+        indicate an error. Printf statements are used by programs to format
+        output in a human readable form (they are placeholders for variable
+        data). They allow you to specify lengths of string variables, string
+        padding, number padding, precision, etc. Generally they will look like
+        this: ``%d``, ``%5.2f``, ``%100s``, etc. The test can also manage
+        variables-reordering using the ``%1$s`` syntax. The variables' type and
+        details following data are tested to ensure that they are strictly
+        identical, but they may be reordered.
+
+        See also `printf Format String
+        <http://en.wikipedia.org/wiki/Printf_format_string>`_.
+        """
         count1 = count2 = plural = None
 
         # self.hasplural only set by run_filters, not always available
@@ -828,43 +908,52 @@ class StandardChecker(TranslationChecker):
 
         for var_num2, match2 in enumerate(printf_pat.finditer(str2)):
             count2 = var_num2 + 1
-            str2ord = match2.group('ord')
+            str2ord = match2.group('ord') if not match2.group('boost_ord') else match2.group('boost_ord')
             str2key = match2.group('key')
+            str2fullvar = match2.group('fullvar') if not match2.group('boost_ord') else '%'
 
             if str2ord:
                 str1ord = None
+                gotmatch = False
 
                 for var_num1, match1 in enumerate(printf_pat.finditer(str1)):
                     count1 = var_num1 + 1
+                    localstr1ord = match1.group('ord') if not match1.group('boost_ord') else match1.group('boost_ord')
 
-                    if match1.group('ord'):
-                        if str2ord == match1.group('ord'):
+                    if localstr1ord:
+                        if str2ord == localstr1ord:
                             str1ord = str2ord
+                            str1fullvar = match1.group('fullvar') if not match1.group('boost_ord') else '%'
 
-                            if match2.group('fullvar') != match1.group('fullvar'):
-                                raise FilterFailure(u"Different printf variable: %s" % match2.group())
+                            if str2fullvar == str1fullvar:
+                                gotmatch = True
                     elif int(str2ord) == var_num1 + 1:
                         str1ord = str2ord
+                        str1fullvar = match1.group('fullvar') if not match1.group('boost_ord') else '%'
 
-                        if match2.group('fullvar') != match1.group('fullvar'):
-                            raise FilterFailure(u"Different printf variable: %s" % match2.group())
+                        if str2fullvar == str1fullvar:
+                            gotmatch = True
 
                 if str1ord is None:
                     raise FilterFailure(u"Added printf variable: %s" % match2.group())
+
+                if not gotmatch:
+                    raise FilterFailure(u"Different printf variable: %s" % match2.group())
             elif str2key:
                 str1key = None
 
                 for var_num1, match1 in enumerate(printf_pat.finditer(str1)):
                     count1 = var_num1 + 1
+                    str1fullvar = match1.group('fullvar') if not match1.group('boost_ord') else '%'
 
                     if match1.group('key') and str2key == match1.group('key'):
                         str1key = match1.group('key')
 
                         # '%.0s' "placeholder" in plural will match anything
-                        if plural and match2.group('fullvar') == '.0s':
+                        if plural and str2fullvar == '.0s':
                             continue
 
-                        if match1.group('fullvar') != match2.group('fullvar'):
+                        if str1fullvar != str2fullvar:
                             raise FilterFailure(u"Different printf variable: %s" % match2.group())
 
                 if str1key is None:
@@ -872,12 +961,13 @@ class StandardChecker(TranslationChecker):
             else:
                 for var_num1, match1 in enumerate(printf_pat.finditer(str1)):
                     count1 = var_num1 + 1
+                    str1fullvar = match1.group('fullvar') if not match1.group('boost_ord') else '%'
 
                     # '%.0s' "placeholder" in plural will match anything
-                    if plural and match2.group('fullvar') == '.0s':
+                    if plural and str2fullvar == '.0s':
                         continue
 
-                    if (var_num1 == var_num2) and (match1.group('fullvar') != match2.group('fullvar')):
+                    if (var_num1 == var_num2) and (str1fullvar != str2fullvar):
                         raise FilterFailure(u"Different printf variable: %s" % match2.group())
 
         if count2 is None:
@@ -892,10 +982,125 @@ class StandardChecker(TranslationChecker):
         return 1
 
 
+    @critical
+    def pythonbraceformat(self, str1, str2):
+        """Checks whether python brace format strings match."""
+
+        # Helper function
+        def max_anons(anons):
+            """
+            Takes a list of anonymous placeholder variables, e.g.
+            ['', '1', ...]
+            Determines how many anonymous formatting args the string
+            they come from requires. Motivation for this function:
+              * max_anons(vars_from_original) tells us how many
+                anonymous placeholders are supported (at least).
+              * max_anons(vars_from_translation) should not
+                exceed it.
+            """
+
+            # implicit_n: you need at least as many anonymous args as
+            # there are anonymous placeholders.
+            implicit_n = anons.count('')
+            # explicit_n: you need at least as many anonymous args as
+            # the highest '{99}'-style placeholder. (The `+ 1` is to
+            # correct for 0-indexing)
+            try:
+                explicit_n = max([
+                    int(numbered_anon) + 1
+                    for numbered_anon in anons
+                    if len(numbered_anon) >= 1
+                ])
+            except ValueError:
+                explicit_n = 0
+
+            highest_n = max(implicit_n, explicit_n)
+
+            return highest_n
+
+        messages = []
+        # Possible failure states: 0 = ok, 1 = mild, 2 = serious
+        STATE_OK, STATE_MILD, STATE_SERIOUS = 0, 1, 2
+        failure_state = STATE_OK
+        pythonbraceformat_pat = re.compile('{[^}]*}')
+        data1 = {}
+        data2 = {}
+
+        # Populate the data1 and data2 dicts.
+        for data_, str_ in [(data1, str1),
+                            (data2, str2)]:
+            # Remove all escaped braces {{ and }}
+            data_['strclean'] = re.sub('{{|}}', '', str_)
+            data_['allvars'] = pythonbraceformat_pat.findall(data_['strclean'])
+            data_['anonvars'] = [
+                var[1:-1]
+                for var in data_['allvars']
+                if re.match(r'^{[0-9]*}$', var)
+            ]
+            data_['namedvars'] = [
+                var
+                for var in data_['allvars']
+                if not re.match(r'^{[0-9]*}$', var)
+            ]
+
+        max1 = max_anons(data1['anonvars'])
+        max2 = max_anons(data2['anonvars'])
+
+        if max1 == max2:
+            pass
+        elif max1 < max2:
+            failure_state = max(failure_state, STATE_SERIOUS)
+            messages.append(
+                u"Translation requires %s anonymous formatting args, original only %s." %
+                    (max2, max1)
+            )
+        else:
+            failure_state = max(failure_state, STATE_MILD)
+            messages.append(
+                u"Highest anonymous placeholder in original is %s, in translation %s" %
+                    (max1, max2)
+            )
+
+        if set(data1['namedvars']) == set(data2['namedvars']):
+            pass
+
+        extra_in_2 = set(data2['namedvars']).difference(set(data1['namedvars']))
+        if 0 < len(extra_in_2):
+            failure_state = max(failure_state, STATE_SERIOUS)
+            messages.append(
+                u"Unknown named placeholders in translation: %s\n" %
+                    ', '.join(extra_in_2)
+            )
+
+        extra_in_1 = set(data1['namedvars']).difference(set(data2['namedvars']))
+        if 0 < len(extra_in_1):
+            failure_state = max(failure_state, STATE_MILD)
+            messages.append(
+                u"Named placeholders absent in translation: %s" %
+                    ', '.join(extra_in_1)
+            )
+
+        if failure_state == STATE_OK:
+            return 1
+        elif failure_state == STATE_MILD:
+            raise FilterFailure(messages)
+        elif failure_state == STATE_SERIOUS:
+            raise SeriousFilterFailure(messages)
+        else:
+            raise ValueError(u"Something wrong in python brace checks: unreachable state reached.")
+
+
     @functional
     def accelerators(self, str1, str2):
-        """Checks whether accelerators are consistent between the
-        two strings.
+        """Checks whether accelerators are consistent between the two strings.
+
+        This test is capable of checking the different type of accelerators
+        that are used in different projects, like Mozilla or KDE. The test will
+        pick up accelerators that are missing and ones that shouldn't be there.
+
+        See `accelerators on the localization guide
+        <http://docs.translatehouse.org/projects/localization-guide/en/latest/guide/translation/accelerators.html>`_
+        for a full description on accelerators.
         """
         str1 = self.filtervariables(str1)
         str2 = self.filtervariables(str2)
@@ -957,6 +1162,11 @@ class StandardChecker(TranslationChecker):
     def variables(self, str1, str2):
         """Checks whether variables of various forms are consistent between the
         two strings.
+
+        This checks to make sure that variables that appear in the original
+        also appear in the translation. It can handle variables from projects
+        like KDE or OpenOffice. It does not at the moment cope with variables
+        that use the reordering syntax of Gettext PO files.
         """
         messages = []
         mismatch1, mismatch2 = [], []
@@ -1007,7 +1217,11 @@ class StandardChecker(TranslationChecker):
 
     @functional
     def functions(self, str1, str2):
-        """Checks that function names are not translated."""
+        """Checks that function names are not translated.
+
+        Checks that function names e.g. ``rgb()`` or ``getEntity.Name()`` are
+        not translated.
+        """
         # We can't just use helpers.funcmatch() since it doesn't ignore order
         if not set(decoration.getfunctions(str1)).symmetric_difference(set(decoration.getfunctions(str2))):
             return True
@@ -1017,7 +1231,13 @@ class StandardChecker(TranslationChecker):
 
     @functional
     def emails(self, str1, str2):
-        """Checks that emails are not translated."""
+        """Checks that emails are not translated.
+
+        Generally you should not be translating email addresses. This check
+        will look to see that email addresses e.g. ``info at example.com`` are not
+        translated. In some cases of course you should translate the address
+        but generally you shouldn't.
+        """
         if helpers.funcmatch(str1, str2, decoration.getemails):
             return True
         else:
@@ -1026,7 +1246,16 @@ class StandardChecker(TranslationChecker):
 
     @functional
     def urls(self, str1, str2):
-        """Checks that URLs are not translated."""
+        """Checks that URLs are not translated.
+
+        This checks only basic URLs (http, ftp, mailto etc.) not all URIs (e.g.
+        afp, smb, file). Generally, you don't want to translate URLs, unless
+        they are example URLs (http://your_server.com/filename.html). If the
+        URL is for configuration information, then you need to query the
+        developers about placing configuration information in PO files. It
+        shouldn't really be there, unless it is very clearly marked: such
+        information should go into a configuration file.
+        """
         if helpers.funcmatch(str1, str2, decoration.geturls):
             return True
         else:
@@ -1037,6 +1266,10 @@ class StandardChecker(TranslationChecker):
     def numbers(self, str1, str2):
         """Checks whether numbers of various forms are consistent between the
         two strings.
+
+        You will see some errors where you have either written the number in
+        full or converted it to the digit in your translation. Also changes in
+        order will trigger this error.
         """
         if helpers.countsmatch(str1, str2, decoration.getnumbers(str1)):
             return True
@@ -1046,8 +1279,9 @@ class StandardChecker(TranslationChecker):
 
     @cosmetic
     def startwhitespace(self, str1, str2):
-        """Checks whether whitespace at the beginning of the strings
-        matches.
+        """Checks whether whitespace at the beginning of the strings matches.
+
+        As in endwhitespace but you will see fewer errors.
         """
         if helpers.funcmatch(str1, str2, decoration.spacestart):
             return True
@@ -1057,7 +1291,18 @@ class StandardChecker(TranslationChecker):
 
     @cosmetic
     def endwhitespace(self, str1, str2):
-        """Checks whether whitespace at the end of the strings matches."""
+        """Checks whether whitespace at the end of the strings matches.
+
+        Operates the same as endpunc but is only concerned with whitespace.
+        This filter is particularly useful for those strings which will
+        evidently be followed by another string in the program, e.g.
+        [Password: ] or [Enter your username: ]. The whitespace is an inherent
+        part of the string. This filter makes sure you don't miss those
+        important but otherwise invisible spaces!
+
+        If your language uses full-width punctuation (like Chinese), the visual
+        spacing in the character might be enough without an added extra space.
+        """
         str1 = self.config.lang.punctranslate(str1)
 
         if helpers.funcmatch(str1, str2, decoration.spaceend):
@@ -1068,7 +1313,10 @@ class StandardChecker(TranslationChecker):
 
     @cosmetic
     def startpunc(self, str1, str2):
-        """Checks whether punctuation at the beginning of the strings match."""
+        """Checks whether punctuation at the beginning of the strings match.
+
+        Operates as endpunc but you will probably see fewer errors.
+        """
         str1 = self.filterxml(self.filterwordswithpunctuation(self.filteraccelerators(self.filtervariables(str1))))
         str1 = self.config.lang.punctranslate(str1)
         str2 = self.filterxml(self.filterwordswithpunctuation(self.filteraccelerators(self.filtervariables(str2))))
@@ -1081,7 +1329,31 @@ class StandardChecker(TranslationChecker):
 
     @cosmetic
     def endpunc(self, str1, str2):
-        """Checks whether punctuation at the end of the strings match."""
+        """Checks whether punctuation at the end of the strings match.
+
+        This will ensure that the ending of your translation has the same
+        punctuation as the original. E.g. if it ends in :[space] then so should
+        yours. It is useful for ensuring that you have ellipses [...] in all
+        your translations, not simply three separate full-stops. You may pick
+        up some errors in the original: feel free to keep your translation and
+        notify the programmers. In some languages, characters such as ``?`` or
+        ``!`` are always preceded by a space e.g. [space]? — do what your
+        language customs dictate. Other false positives you will notice are,
+        for example, if through changes in word-order you add "), etc. at the
+        end of the sentence. Do not change these: your language word-order
+        takes precedence.
+
+        It must be noted that if you are tempted to leave out [full-stop] or
+        [colon] or add [full-stop] to a sentence, that often these have been
+        done for a reason, e.g. a list where fullstops make it look cluttered.
+        So, initially match them with the English, and make changes once the
+        program is being used.
+
+        This check is aware of several language conventions for punctuation
+        characters, such as the custom question marks for Greek and Arabic,
+        Devanagari Danda, full-width punctuation for CJK languages, etc.
+        Support for your language can be added easily if it is not there yet.
+        """
         str1 = self.filtervariables(str1)
         str1 = self.config.lang.punctranslate(str1)
         str2 = self.filtervariables(str2)
@@ -1096,7 +1368,11 @@ class StandardChecker(TranslationChecker):
 
     @functional
     def purepunc(self, str1, str2):
-        """Checks that strings that are purely punctuation are not changed."""
+        """Checks that strings that are purely punctuation are not changed.
+
+        This extracts strings like ``+`` or ``-`` as these usually should not
+        be changed.
+        """
         # this test is a subset of startandend
         if (decoration.ispurepunctuation(str1)):
             success = str1 == str2
@@ -1111,7 +1387,11 @@ class StandardChecker(TranslationChecker):
 
     @cosmetic
     def brackets(self, str1, str2):
-        """Checks that the number of brackets in both strings match."""
+        """Checks that the number of brackets in both strings match.
+
+        If ``([{`` or ``}])`` appear in the original this will check that the
+        same number appear in the translation.
+        """
         str1 = self.filtervariables(str1)
         str2 = self.filtervariables(str2)
 
@@ -1142,7 +1422,16 @@ class StandardChecker(TranslationChecker):
 
     @functional
     def sentencecount(self, str1, str2):
-        """Checks that the number of sentences in both strings match."""
+        """Checks that the number of sentences in both strings match.
+
+        Adds the number of sentences to see that the sentence count is the same
+        between the original and translated string. You may not always want to
+        use this test, if you find you often need to reformat your translation,
+        because the original is badly-expressed, or because the structure of
+        your language works better that way. Do what works best for your
+        language: it's the meaning of the original you want to convey, not the
+        exact way it was written in the English.
+        """
         str1 = self.filteraccelerators(str1)
         str2 = self.filteraccelerators(str2)
 
@@ -1158,7 +1447,15 @@ class StandardChecker(TranslationChecker):
 
     @functional
     def options(self, str1, str2):
-        """Checks that options are not translated."""
+        """Checks that command line options are not translated.
+
+        In messages that contain command line options, such as ``--help``,
+        this test will check that these remain untranslated. These could be
+        translated in the future if programs can create a mechanism to allow
+        this, but currently they are not translated. If the options has a
+        parameter, e.g. ``--file=FILE``, then the test will check that the
+        parameter has been translated.
+        """
         str1 = self.filtervariables(str1)
 
         for word1 in str1.split():
@@ -1179,7 +1476,17 @@ class StandardChecker(TranslationChecker):
 
     @cosmetic
     def startcaps(self, str1, str2):
-        """Checks that the message starts with the correct capitalisation."""
+        """Checks that the message starts with the correct capitalisation.
+
+        After stripping whitespace and common punctuation characters, it then
+        checks to see that the first remaining character is correctly
+        capitalised. So, if the sentence starts with an upper-case letter, and
+        the translation does not, an error is produced.
+
+        This check is entirely disabled for many languages that don't make a
+        distinction between upper and lower case. Contact us if this is not yet
+        disabled for your language.
+        """
         str1 = self.filteraccelerators(str1)
         str2 = self.filteraccelerators(str2)
 
@@ -1202,7 +1509,16 @@ class StandardChecker(TranslationChecker):
 
     @cosmetic
     def simplecaps(self, str1, str2):
-        """Checks the capitalisation of two strings isn't wildly different."""
+        """Checks the capitalisation of two strings isn't wildly different.
+
+        This will pick up many false positives, so don't be a slave to it. It
+        is useful for identifying translations that don't start with a capital
+        letter (upper-case letter) when they should, or those that do when they
+        shouldn't. It will also highlight sentences that have extra capitals;
+        depending on the capitalisation convention of your language, you might
+        want to change these to Title Case, or change them all to normal
+        sentence case.
+        """
         str1 = self.removevariables(str1)
         str2 = self.removevariables(str2)
         # TODO: review this. The 'I' is specific to English, so it probably
@@ -1243,7 +1559,14 @@ class StandardChecker(TranslationChecker):
 
     @functional
     def acronyms(self, str1, str2):
-        """Checks that acronyms that appear are unchanged."""
+        """Checks that acronyms that appear are unchanged.
+
+        If an acronym appears in the original this test will check that it
+        appears in the translation. Translating acronyms is a language decision
+        but many languages leave them unchanged. In that case this test is
+        useful for tracking down translations of the acronym and correcting
+        them.
+        """
         acronyms = []
         allowed = []
 
@@ -1273,7 +1596,14 @@ class StandardChecker(TranslationChecker):
 
     @cosmetic
     def doublewords(self, str1, str2):
-        """Checks for repeated words in the translation."""
+        """Checks for repeated words in the translation.
+
+        Words that have been repeated in a translation will be highlighted with
+        this test e.g. "the the", "a a". These are generally typos that need
+        correcting. Some languages may have valid repeated words in their
+        structure, in that case either ignore those instances or switch this
+        test off.
+        """
         lastword = ""
         without_newlines = "\n".join(str2.split("\n"))
         words = self.filteraccelerators(self.removevariables(self.filterxml(without_newlines))).replace(u".", u"").lower().split()
@@ -1289,7 +1619,13 @@ class StandardChecker(TranslationChecker):
     @functional
     def notranslatewords(self, str1, str2):
         """Checks that words configured as untranslatable appear in the
-        translation too."""
+        translation too.
+
+        Many brand names should not be translated, this test allows you to
+        easily make sure that words like: Word, Excel, Impress, Calc, etc. are
+        not translated. You must specify a file containing all of the
+        *no translate* words using ``--notranslatefile``.
+        """
         if not self.config.notranslatewords:
             return True
 
@@ -1316,7 +1652,14 @@ class StandardChecker(TranslationChecker):
     @functional
     def musttranslatewords(self, str1, str2):
         """Checks that words configured as definitely translatable don't appear
-        in the translation."""
+        in the translation.
+
+        If for instance in your language you decide that you must translate
+        'OK' then this test will flag any occurrences of 'OK' in the
+        translation if it appeared in the source string. You must specify a
+        file containing all of the *must translate* words using
+        ``--musttranslatefile``.
+        """
         if not self.config.musttranslatewords:
             return True
 
@@ -1343,6 +1686,19 @@ class StandardChecker(TranslationChecker):
     def validchars(self, str1, str2):
         """Checks that only characters specified as valid appear in the
         translation.
+
+        Often during character conversion to and from UTF-8 you get some
+        strange characters appearing in your translation. This test presents a
+        simple way to try and identify such errors.
+
+        This test will only run of you specify the ``--validcharsfile`` command
+        line option. This file contains all the characters that are valid in
+        your language. You must use UTF-8 encoding for the characters in the
+        file.
+
+        If the test finds any characters not in your valid characters file then
+        the test will print the character together with its Unicode value
+        (e.g. 002B).
         """
         if not self.config.validcharsmap:
             return True
@@ -1359,7 +1715,12 @@ class StandardChecker(TranslationChecker):
 
     @functional
     def filepaths(self, str1, str2):
-        """Checks that file paths have not been translated."""
+        """Checks that file paths have not been translated.
+
+        Checks that paths such as ``/home/user1`` have not been translated.
+        Generally you do not translate a file path, unless it is being used as
+        an example, e.g. ``your_user_name/path/to/filename.conf``.
+        """
         for word1 in self.filteraccelerators(self.filterxml(str1)).split():
             if word1.startswith(u"/"):
                 if not helpers.countsmatch(str1, str2, (word1,)):
@@ -1370,7 +1731,20 @@ class StandardChecker(TranslationChecker):
 
     @critical
     def xmltags(self, str1, str2):
-        """Checks that XML/HTML tags have not been translated."""
+        """Checks that XML/HTML tags have not been translated.
+
+        This check finds the number of tags in the source string and checks
+        that the same number are in the translation. If the counts don't match
+        then either the tag is missing or it was mistakenly translated by the
+        translator, both of which are errors.
+
+        The check ignores tags or things that look like tags that cover the
+        whole string e.g. ``<Error>`` but will produce false positives for
+        things like ``An <Error> occurred`` as here ``Error`` should be
+        translated. It also will allow translation of the *alt* attribute in
+        e.g. ``<img src="bob.png" alt="Image description">`` or similar
+        translatable attributes in OpenOffice.org help files.
+        """
         tags1 = tag_re.findall(str1)
 
         if len(tags1) > 0:
@@ -1409,19 +1783,42 @@ class StandardChecker(TranslationChecker):
     def kdecomments(self, str1, str2):
         """Checks to ensure that no KDE style comments appear in the
         translation.
+
+        KDE style translator comments appear in PO files as
+        ``"_: comment\\n"``. New translators often translate the comment. This
+        test tries to identify instances where the comment has been translated.
         """
         return str2.find(u"\n_:") == -1 and not str2.startswith(u"_:")
 
 
     @extraction
     def compendiumconflicts(self, str1, str2):
-        """Checks for Gettext compendium conflicts (#-#-#-#-#)."""
+        """Checks for Gettext compendium conflicts (#-#-#-#-#).
+
+        When you use msgcat to create a PO compendium it will insert
+        ``#-#-#-#-#`` into entries that are not consistent. If the compendium
+        is used later in a message merge then these conflicts will appear in
+        your translations. This test quickly extracts those for correction.
+        """
         return str2.find(u"#-#-#-#-#") == -1
 
 
     @cosmetic
     def simpleplurals(self, str1, str2):
-        """Checks for English style plural(s) for you to review."""
+        """Checks for English style plural(s) for you to review.
+
+        This test will extract any message that contains words with a final
+        "(s)" in the source text. You can then inspect the message, to check
+        that the correct plural form has been used for your language. In some
+        languages, plurals are made by adding text at the beginning of words,
+        making the English style messy. In this case, they often revert to the
+        plural form. This test allows an editor to check that the plurals used
+        are correct. Be aware that this test may create a number of false
+        positives.
+
+        For languages with no plural forms (only one noun form) this test will
+        simply test that nothing like "(s)" was used in the translation.
+        """
 
         def numberofpatterns(string, patterns):
             number = 0
@@ -1450,7 +1847,25 @@ class StandardChecker(TranslationChecker):
 
     @functional
     def spellcheck(self, str1, str2):
-        """Checks words that don't pass a spell check."""
+        """Checks words that don't pass a spell check.
+
+        This test will check for misspelled words in your translation. The test
+        first checks for misspelled words in the original (usually English)
+        text, and adds those to an exclusion list. The advantage of this
+        exclusion is that many words that are specific to the application will
+        not raise errors e.g. program names, brand names, function names.
+
+        The checker works with `PyEnchant
+        <http://pythonhosted.org/pyenchant/>`_. You need to have PyEnchant
+        installed as well as a dictionary for your language (for example, one
+        of the `Hunspell <https://wiki.openoffice.org/wiki/Dictionaries>`_ or
+        `aspell <http://ftp.gnu.org/gnu/aspell/dict/>`_ dictionaries). This
+        test will only work if you have specified the ``--language`` option.
+
+        The pofilter error that is created, lists the misspelled word, plus
+        suggestions returned from the spell checker. That makes it easy for you
+        to identify the word and select a replacement.
+        """
         if not self.config.targetlanguage:
             return True
 
@@ -1494,6 +1909,13 @@ class StandardChecker(TranslationChecker):
     def credits(self, str1, str2):
         """Checks for messages containing translation credits instead of
         normal translations.
+
+        Some projects have consistent ways of giving credit to translators by
+        having a unit or two where translators can fill in their name and
+        possibly their contact details. This test allows you to find these
+        units easily to check that they are completed correctly and also
+        disables other tests that might incorrectly get triggered for these
+        units (such as urls, emails, etc.)
         """
         if str1 in self.config.credit_sources:
             raise FilterFailure(u"Don't translate. Just credit the translators.")
@@ -1512,6 +1934,7 @@ class StandardChecker(TranslationChecker):
                          "sentencecount", "numbers", "isfuzzy",
                          "isreview", "notranslatewords", "musttranslatewords",
                          "emails", "simpleplurals", "urls", "printf",
+                         "pythonbraceformat",
                          "tabs", "newlines", "functions", "options",
                          "blank", "nplurals", "gconf", "dialogsizes",
                          "validxml"),
@@ -1524,6 +1947,7 @@ class StandardChecker(TranslationChecker):
                     "sentencecount", "numbers", "isfuzzy",
                     "isreview", "notranslatewords", "musttranslatewords",
                     "emails", "simpleplurals", "urls", "printf",
+                    "pythonbraceformat",
                     "tabs", "newlines", "functions", "options",
                     "gconf", "dialogsizes", "validxml"),
           "credits": ("simplecaps", "variables", "startcaps",
@@ -1533,6 +1957,7 @@ class StandardChecker(TranslationChecker):
                       "filepaths", "doublespacing",
                       "sentencecount", "numbers",
                       "emails", "simpleplurals", "urls", "printf",
+                      "pythonbraceformat",
                       "tabs", "newlines", "functions", "options",
                       "validxml"),
          "purepunc": ("startcaps", "options"),
@@ -1660,6 +2085,13 @@ class MozillaChecker(StandardChecker):
     def credits(self, str1, str2):
         """Checks for messages containing translation credits instead of
         normal translations.
+
+        Some projects have consistent ways of giving credit to translators by
+        having a unit or two where translators can fill in their name and
+        possibly their contact details. This test allows you to find these
+        units easily to check that they are completed correctly and also
+        disables other tests that might incorrectly get triggered for these
+        units (such as urls, emails, etc.)
         """
         for location in self.locations:
             if location in ['MOZ_LANGPACK_CONTRIBUTORS', 'credit.translation']:
@@ -1680,7 +2112,18 @@ class MozillaChecker(StandardChecker):
 
     @critical
     def dialogsizes(self, str1, str2):
-        """Checks that dialog sizes are not translated."""
+        """Checks that dialog sizes are not translated.
+
+        This is a Mozilla specific test. Mozilla uses a language called XUL to
+        define dialogues and screens. This can make use of CSS to specify
+        properties of the dialogue. These properties include things such as the
+        width and height of the box. The size might need to be changed if the
+        dialogue size changes due to longer translations. Thus translators can
+        change these settings. But you are only meant to change the number not
+        translate the words 'width' or 'height'. This check capture instances
+        where these are translated. It will also catch other types of errors in
+        these units.
+        """
         # Example: "width: 635px; height: 400px;"
         if "width" in str1 or "height" in str1:
             str1pairs = self.mozilla_dialog_re.findall(str1)
@@ -1783,7 +2226,13 @@ class GnomeChecker(StandardChecker):
 
     @functional
     def gconf(self, str1, str2):
-        """Checks if we have any gconf config settings translated."""
+        """Checks if we have any gconf config settings translated.
+
+        Gconf settings should not be translated so this check checks that gconf
+        settings such as "name" or "modification_date" are not translated in
+        the translation. It allows you to change the surrounding quotes but
+        will ensure that the setting values remain untranslated.
+        """
         for location in self.locations:
             if location.find('schemas.in') != -1 or location.find('gschema.xml.in') != -1:
                 gconf_attributes = gconf_attribute_re.findall(str1)
@@ -1872,20 +2321,41 @@ class StandardUnitChecker(UnitChecker):
 
     @extraction
     def isfuzzy(self, unit):
-        """Check if the unit has been marked fuzzy."""
+        """Check if the unit has been marked fuzzy.
+
+        If a message is marked fuzzy in the PO file then it is extracted.
+        Note this is different from ``--fuzzy`` and ``--nofuzzy`` options which
+        specify whether tests should be performed against messages marked
+        fuzzy.
+        """
         return not unit.isfuzzy()
 
 
     @extraction
     def isreview(self, unit):
-        """Check if the unit has been marked review."""
+        """Check if the unit has been marked review.
+
+        If you have made use of the 'review' flags in your translations::
+
+          # (review) reason for review
+          # (pofilter) testname: explanation for translator
+
+        Then if a message is marked for review in the PO file it will be
+        extracted. Note this is different from ``--review`` and ``--noreview``
+        options which specify whether tests should be performed against
+        messages already marked as under review.
+        """
         return not unit.isreview()
 
 
     @critical
     def nplurals(self, unit):
-        """Checks for the correct number of noun forms for plural
-        translations.
+        """Checks for the correct number of noun forms for plural translations.
+
+        This uses the plural information in the language module of the
+        Translate Toolkit. This is the same as the Gettext nplural value. It
+        will check that the number of plurals required is the same as the
+        number supplied in your translation.
         """
         if unit.hasplural():
             # if we don't have a valid nplurals value, don't run the test
@@ -1899,8 +2369,12 @@ class StandardUnitChecker(UnitChecker):
 
     @extraction
     def hassuggestion(self, unit):
-        """Checks if there is at least one suggested translation for this
-        unit.
+        """Checks if there is at least one suggested translation for this unit.
+
+        If a message has a suggestion (an alternate translation stored in
+        alt-trans units in XLIFF and .pending files in PO) then these will be
+        extracted. This is used by Pootle and is probably only useful in
+        pofilter when using XLIFF files.
         """
         self.suggestion_store = getattr(self, 'suggestion_store', None)
         suggestions = []
diff --git a/translate/filters/pofilter.py b/translate/filters/pofilter.py
index 5345e4c..8c620c6 100644
--- a/translate/filters/pofilter.py
+++ b/translate/filters/pofilter.py
@@ -96,7 +96,8 @@ class pocheckfilter:
     def getfilterdocs(self):
         """Lists the docs for filters available on checker."""
         filterdict = self.checker.getfilters()
-        filterdocs = ["%s\t%s" % (name, filterfunc.__doc__) for (name, filterfunc) in filterdict.iteritems()]
+        filterdocs = ["%s\t%s" % (name, filterfunc.__doc__.split('\n\n')[0])
+                      for (name, filterfunc) in filterdict.iteritems()]
         filterdocs.sort()
 
         return "\n".join(filterdocs)
diff --git a/translate/filters/test_checks.py b/translate/filters/test_checks.py
index 3cd11b9..bc2bf3d 100644
--- a/translate/filters/test_checks.py
+++ b/translate/filters/test_checks.py
@@ -570,6 +570,43 @@ def test_printf():
     assert fails(stdchecker.printf, "Object %@ and object %@", "String %1$@ en string %3$@")  # out of bounds
     assert fails(stdchecker.printf, "I am %@", "Ek is %s")  # wrong specification
     assert passes(stdchecker.printf, "Object %@ and string %s", "Object %1$@ en string %2$s")  # correct sentence
+    # Checking boost format.
+    # Boost classic printf.
+    assert passes(stdchecker.printf, "writing %1%,  x=%2% : %3%-th try", "escribindo %1%,  x=%2% : %3%-esimo intento")
+    # Reordering boost.
+    assert passes(stdchecker.printf, "%1% %2% %3% %2% %1%", "%1% %2% %3% %2% %1%")
+    # Boost posix format.
+    assert passes(stdchecker.printf, "(x,y) = (%1$+5d,%2$+5d)", "(x,y) = (%1$+5d,%2$+5d)")
+    # Boost several ways to express the same.
+    assert passes(stdchecker.printf, "(x,y) = (%+5d,%+5d)", "(x,y) = (%+5d,%+5d)")
+    assert passes(stdchecker.printf, "(x,y) = (%|+5|,%|+5|)", "(x,y) = (%|+5|,%|+5|)")
+    assert passes(stdchecker.printf, "(x,y) = (%1$+5d,%2$+5d)", "(x,y) = (%1$+5d,%2$+5d)")
+    assert passes(stdchecker.printf, "(x,y) = (%|1$+5|,%|2$+5|)", "(x,y) = (%|1$+5|,%|2$+5|)")
+    # Boost using manipulators.
+    assert passes(stdchecker.printf, "_%1$+5d_ %1$d", "_%1$+5d_ %1$d")  # This is failing.
+    assert passes(stdchecker.printf, "_%1%_ %1%", "_%1%_ %1%")
+    # Boost absolute tabulations.
+    assert passes(stdchecker.printf, "%1%, %2%, %|40t|%3%", "%1%, %2%, %|40t|%3%")
+
+
+def test_pythonbraceformat():
+    """Tests python brace format placeholds"""
+    stdchecker = checks.StandardChecker()
+    # anonymous formats
+    assert passes(stdchecker.pythonbraceformat,   "String {} and number {}",     "String {} en nommer {}")
+    assert passes(stdchecker.pythonbraceformat,   "String {1}",                  "Nommer {} en string {}")
+    assert passes(stdchecker.pythonbraceformat,   "String {1} and number {0}",   "Nommer {0} en string {1}")
+    assert fails(stdchecker.pythonbraceformat,            "String {}, {}",       "String {}")
+    assert fails_serious(stdchecker.pythonbraceformat,    "String {}",           "String {} en nommer {}")
+    assert fails_serious(stdchecker.pythonbraceformat,    "String {}",           "Nommer {1}")
+    assert fails_serious(stdchecker.pythonbraceformat,    "String {0}",          "Nommer {1}")
+    assert fails_serious(stdchecker.pythonbraceformat,    "String {0} {}",       "Nommer {1}")
+
+    # Named formats
+    assert passes(stdchecker.pythonbraceformat, "String {str} and number {num}", "Nommer {num} en string {str}")
+    # TODO: check for a mixture of substitution techniques
+    assert fails(stdchecker.pythonbraceformat, "String {str} and number {num}", "Nommer {num} en string %s")
+    assert fails_serious(stdchecker.pythonbraceformat, "String {str} and number {num}", "Nommer {onbekend} en string {str}")
 
 
 def test_puncspacing():
diff --git a/translate/lang/lo.py b/translate/lang/bo.by
similarity index 83%
copy from translate/lang/lo.py
copy to translate/lang/bo.by
index af4b9eb..98ab785 100644
--- a/translate/lang/lo.py
+++ b/translate/lang/bo.by
@@ -18,16 +18,16 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
-"""This module represents the Lao language.
+"""This module represents the Tibetan language.
 
-.. seealso:: http://en.wikipedia.org/wiki/Lao_language
+.. seealso:: http://en.wikipedia.org/wiki/Tibetan_language
 """
 
 from translate.lang import common
 
 
-class lo(common.Common):
-    """This class represents Lao."""
+class bo(common.Common):
+    """This class represents Tibetan."""
 
     mozilla_nplurals = 2
     mozilla_pluralequation = "n!=1 ? 1 : 0"
diff --git a/translate/lang/data.py b/translate/lang/data.py
index 0d1f8ae..fff6828 100644
--- a/translate/lang/data.py
+++ b/translate/lang/data.py
@@ -22,14 +22,18 @@
 
 
 languages = {
+    'ach': (u'Acholi', 2, 'n > 1'),
     'af': (u'Afrikaans', 2, '(n != 1)'),
     'ak': (u'Akan', 2, 'n > 1'),
     'am': (u'Amharic', 2, 'n > 1'),
     'an': (u'Aragonese', 2, '(n != 1)'),
+    'anp': (u'Angika', 2, '(n != 1)'),
     'ar': (u'Arabic', 6,
            'n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5'),
     'arn': (u'Mapudungun; Mapuche', 2, 'n > 1'),
+    'as': (u'Assamese', 2, '(n != 1)'),
     'ast': (u'Asturian; Bable; Leonese; Asturleonese', 2, '(n != 1)'),
+    'ay': (u'Aymará', 1, '0'),
     'az': (u'Azerbaijani', 2, '(n != 1)'),
     'be': (u'Belarusian', 3,
            'n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2'),
@@ -38,16 +42,19 @@ languages = {
     'bn_IN': (u'Bengali (India)', 2, '(n != 1)'),
     'bo': (u'Tibetan', 1, '0'),
     'br': (u'Breton', 2, 'n > 1'),
+    'brx': (u'Bodo', 2, '(n != 1)'),
     'bs': (u'Bosnian', 3,
            'n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2'),
     'ca': (u'Catalan; Valencian', 2, '(n != 1)'),
     'ca at valencia': (u'Catalan; Valencian (Valencia)', 2, '(n != 1)'),
+    'cgg': (u'Chiga', 1, '0'),
     'cs': (u'Czech', 3, '(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2'),
     'csb': (u'Kashubian', 3,
             'n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2'),
     'cy': (u'Welsh', 2, '(n==2) ? 1 : 0'),
     'da': (u'Danish', 2, '(n != 1)'),
     'de': (u'German', 2, '(n != 1)'),
+    'doi': (u'Dogri', 2, '(n != 1)'),
     'dz': (u'Dzongkha', 1, '0'),
     'el': (u'Greek, Modern (1453-)', 2, '(n != 1)'),
     'en': (u'English', 2, '(n != 1)'),
@@ -55,6 +62,7 @@ languages = {
     'en_ZA': (u'English (South Africa)', 2, '(n != 1)'),
     'eo': (u'Esperanto', 2, '(n != 1)'),
     'es': (u'Spanish; Castilian', 2, '(n != 1)'),
+    'es_AR': (u'Argentinean Spanish', 2, '(n != 1)'),
     'et': (u'Estonian', 2, '(n != 1)'),
     'eu': (u'Basque', 2, '(n != 1)'),
     'fa': (u'Persian', 1, '0'),
@@ -65,7 +73,7 @@ languages = {
     'fr': (u'French', 2, '(n > 1)'),
     'fur': (u'Friulian', 2, '(n != 1)'),
     'fy': (u'Frisian', 2, '(n != 1)'),
-    'ga': (u'Irish', 5, 'n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4'),
+    'ga': (u'Irish', 5, 'n==1 ? 0 : n==2 ? 1 : (n>2 && n<7) ? 2 :(n>6 && n<11) ? 3 : 4'),
     'gd': (u'Gaelic; Scottish Gaelic', 4, '(n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3'),
     'gl': (u'Galician', 2, '(n != 1)'),
     'gu': (u'Gujarati', 2, '(n != 1)'),
@@ -73,18 +81,21 @@ languages = {
     'ha': (u'Hausa', 2, '(n != 1)'),
     'he': (u'Hebrew', 2, '(n != 1)'),
     'hi': (u'Hindi', 2, '(n != 1)'),
-    'hy': (u'Armenian', 1, '0'),
+    'hne': (u'Chhattisgarhi', 2, '(n != 1)'),
     'hr': (u'Croatian', 3, '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)'),
     'ht': (u'Haitian; Haitian Creole', 2, '(n != 1)'),
     'hu': (u'Hungarian', 2, '(n != 1)'),
+    'hy': (u'Armenian', 1, '0'),
     'ia': (u"Interlingua (International Auxiliary Language Association)", 2, '(n != 1)'),
     'id': (u'Indonesian', 1, '0'),
     'is': (u'Icelandic', 2, '(n != 1)'),
     'it': (u'Italian', 2, '(n != 1)'),
     'ja': (u'Japanese', 1, '0'),
+    'jbo': (u'Lojban', 1, '0'),
     'jv': (u'Javanese', 2, '(n != 1)'),
     'ka': (u'Georgian', 1, '0'),
     'kk': (u'Kazakh', 1, '0'),
+    'kl': (u'Greenlandic', 2, '(n != 1)'),
     'km': (u'Central Khmer', 1, '0'),
     'kn': (u'Kannada', 2, '(n != 1)'),
     'ko': (u'Korean', 1, '0'),
@@ -103,10 +114,13 @@ languages = {
     'mk': (u'Macedonian', 2, 'n==1 || n%10==1 ? 0 : 1'),
     'ml': (u'Malayalam', 2, '(n != 1)'),
     'mn': (u'Mongolian', 2, '(n != 1)'),
+    'mni': (u'Manipuri', 2, '(n != 1)'),
+    'mnk': (u'Mandinka', 3, '(n==0 ? 0 : n==1 ? 1 : 2)'),
     'mr': (u'Marathi', 2, '(n != 1)'),
     'ms': (u'Malay', 1, '0'),
     'mt': (u'Maltese', 4,
            '(n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3)'),
+    'my': (u'Burmese', 1, '0'),
     'nah': (u'Nahuatl languages', 2, '(n != 1)'),
     'nap': (u'Neapolitan', 2, '(n != 1)'),
     'nb': (u'Bokmål, Norwegian; Norwegian Bokmål', 2, '(n != 1)'),
@@ -124,13 +138,17 @@ languages = {
     'pms': (u'Piemontese', 2, '(n != 1)'),
     'ps': (u'Pushto; Pashto', 2, '(n != 1)'),
     'pt': (u'Portuguese', 2, '(n != 1)'),
-    'pt_BR': (u'Portuguese (Brazil)', 2, '(n != 1)'),
+    'pt_BR': (u'Portuguese (Brazil)', 2, '(n > 1)'),
     'rm': (u'Romansh', 2, '(n != 1)'),
     'ro': (u'Romanian', 3, '(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2);'),
     'ru': (u'Russian', 3,
           '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)'),
+    'rw': (u'Kinyarwanda', 2, '(n != 1)'),
     'sah': (u'Yakut', 1, '0'),
+    'sat': (u'Santali', 2, '(n != 1)'),
     'sco': (u'Scots', 2, '(n != 1)'),
+    'sd': (u'Sindhi', 2, '(n != 1)'),
+    'se': (u'Northern Sami', 2, '(n != 1)'),
     'si': (u'Sinhala; Sinhalese', 2, '(n != 1)'),
     'sk': (u'Slovak', 3, '(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2'),
     'sl': (u'Slovenian', 4, '(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3)'),
@@ -146,16 +164,18 @@ languages = {
     'ta': (u'Tamil', 2, '(n != 1)'),
     'te': (u'Telugu', 2, '(n != 1)'),
     'tg': (u'Tajik', 2, '(n != 1)'),
-    'ti': (u'Tigrinya', 2, '(n > 1)'),
     'th': (u'Thai', 1, '0'),
+    'ti': (u'Tigrinya', 2, '(n > 1)'),
     'tk': (u'Turkmen', 2, '(n != 1)'),
     'tr': (u'Turkish', 1, '0'),
     'tt': (u'Tatar', 1, '0'),
     'ug': (u'Uighur; Uyghur', 1, '0'),
     'uk': (u'Ukrainian', 3,
            '(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)'),
-    'vi': (u'Vietnamese', 1, '0'),
+    'ur': (u'Urdu', 2, '(n != 1)'),
+    'uz': (u'Uzbek', 2, '(n > 1)'),
     've': (u'Venda', 2, '(n != 1)'),
+    'vi': (u'Vietnamese', 1, '0'),
     'wa': (u'Walloon', 2, '(n > 1)'),
     'wo': (u'Wolof', 2, '(n != 1)'),
     'yo': (u'Yoruba', 2, '(n != 1)'),
@@ -200,6 +220,7 @@ _fixed_names = {
     u"Pedi; Sepedi; Northern Sotho": u"Northern Sotho",
     u"Pushto; Pashto": u"Pashto",
     u"Sinhala; Sinhalese": u"Sinhala",
+    u"Songhai languages": u"Songhay",
     u"Sotho, Southern": u"Sotho",
     u"Spanish; Castilian": u"Spanish",
     u"Uighur; Uyghur": u"Uyghur",
@@ -411,8 +432,8 @@ def simplify_to_common(language_code, languages=languages):
 
     if (normalize_code(language_code) in __normalised_languages):
         return language_code
-    else:
-        return simplify_to_common(simpler)
+
+    return simplify_to_common(simpler)
 
 
 def get_language(code):
diff --git a/translate/lang/he.py b/translate/lang/he.py
index 3a17ec8..a8849d9 100644
--- a/translate/lang/he.py
+++ b/translate/lang/he.py
@@ -29,4 +29,4 @@ from translate.lang import common
 class he(common.Common):
     """This class represents Hebrew."""
 
-    ignoretests = ["startcaps", "simplecaps"]
+    ignoretests = ["startcaps", "simplecaps", "acronyms"]
diff --git a/translate/lang/test-language-teams.sh b/translate/lang/test-language-teams.sh
new file mode 100755
index 0000000..32e8a57
--- /dev/null
+++ b/translate/lang/test-language-teams.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+# This script generates a python file that tests the detection of language code
+# from the team information in the .mo files in /usr/share/locale.
+
+cd /usr/share/locale/
+cat <<EOF
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# A generated test script to test the detection of language code the team
+# information found in the .mo files in /usr/share/locale.
+
+from translate.lang.team import guess_language
+
+EOF
+
+for lang in $(ls)
+do
+	echo "print \"LANGUAGE: $lang\""
+	for translation in $(find $lang -name "*.mo")
+	do
+		msgunfmt $translation | msgconv --to-code=utf-8 --no-wrap
+	done | egrep "Language-Team:" | sort -u | sed "s/\"Language-Team:/print guess_language(u\"/;s/\\\\n\"$/\"\)/"
+done
diff --git a/translate/lang/ug.py b/translate/lang/ug.py
index ef5cc50..1c74399 100644
--- a/translate/lang/ug.py
+++ b/translate/lang/ug.py
@@ -37,4 +37,4 @@ class ug(common.Common):
         u"?": u"؟",
     }
 
-    ignoretests = ["startcaps", "simplecaps"]
+    ignoretests = ["startcaps", "simplecaps", "acronyms"]
diff --git a/translate/lang/zh.py b/translate/lang/zh.py
index e97e566..b3cee38 100644
--- a/translate/lang/zh.py
+++ b/translate/lang/zh.py
@@ -33,7 +33,7 @@ class zh(common.Common):
 
     listseperator = u"、"
 
-    sentenceend = u"。!?…"
+    sentenceend = u"。!?!?…"
 
     # Compared to common.py, we make the space after the sentence ending
     # optional and don't demand an uppercase letter to follow.
diff --git a/translate/lang/zh_cn.py b/translate/lang/zh_cn.py
index 225ab1d..cd696ea 100644
--- a/translate/lang/zh_cn.py
+++ b/translate/lang/zh_cn.py
@@ -28,3 +28,5 @@ from translate.lang.zh import zh
 
 class zh_cn(zh):
     specialchars = u"←→↔×÷©…—‘’“”【】《》"
+
+    ignoretests = ["startcaps", "simplecaps", "acronyms"]
diff --git a/translate/lang/zh_hk.py b/translate/lang/zh_hk.py
index 392a5f4..fdbc60d 100644
--- a/translate/lang/zh_hk.py
+++ b/translate/lang/zh_hk.py
@@ -28,3 +28,5 @@ from translate.lang.zh import zh
 
 class zh_hk(zh):
     specialchars = u"←→↔×÷©…—‘’“”「」『』【】《》"
+
+    ignoretests = ["startcaps", "simplecaps", "acronyms"]
diff --git a/translate/lang/zh_tw.py b/translate/lang/zh_tw.py
index 2db19d4..2487c67 100644
--- a/translate/lang/zh_tw.py
+++ b/translate/lang/zh_tw.py
@@ -28,3 +28,5 @@ from translate.lang.zh import zh
 
 class zh_tw(zh):
     specialchars = u"←→↔×÷©…—‘’“”「」『』【】《》"
+
+    ignoretests = ["startcaps", "simplecaps", "acronyms"]
diff --git a/translate/misc/file_discovery.py b/translate/misc/file_discovery.py
index 5c94495..ac65c72 100644
--- a/translate/misc/file_discovery.py
+++ b/translate/misc/file_discovery.py
@@ -46,6 +46,7 @@ def get_abs_data_filename(path_parts, basedirs=None):
         # Toolkit's data files
         base = os.path.dirname(unicode(__file__, sys.getfilesystemencoding()))
         BASE_DIRS = [
+                base,
                 os.path.join(base, os.path.pardir),
         ]
 
diff --git a/translate/misc/quote.py b/translate/misc/quote.py
index 448858b..02cc581 100644
--- a/translate/misc/quote.py
+++ b/translate/misc/quote.py
@@ -200,8 +200,9 @@ def entityencode(source, codepoint2name):
     """Encode ``source`` using entities from ``codepoint2name``.
 
     :param unicode source: Source string to encode
-    :param dict codepoint2name: Dictionary mapping code points to entity names
+    :param codepoint2name: Dictionary mapping code points to entity names
            (without the the leading ``&`` or the trailing ``;``)
+    :type codepoint2name: :meth:`dict`
     """
     output = u""
     inentity = False
@@ -242,8 +243,9 @@ def entitydecode(source, name2codepoint):
     """Decode ``source`` using entities from ``name2codepoint``.
 
     :param unicode source: Source string to decode
-    :param dict name2codepoint: Dictionary mapping entity names (without the
+    :param name2codepoint: Dictionary mapping entity names (without the
            the leading ``&`` or the trailing ``;``) to code points
+    :type name2codepoint: :meth:`dict`
     """
     output = u""
     inentity = False
diff --git a/translate/storage/_factory_classes.py b/translate/storage/_factory_classes.py
index 2d0d8b2..e4c5995 100644
--- a/translate/storage/_factory_classes.py
+++ b/translate/storage/_factory_classes.py
@@ -38,5 +38,5 @@ import xliff
 
 try:
     import trados
-except ImportError as e:
+except ImportError:
     pass
diff --git a/translate/storage/aresource.py b/translate/storage/aresource.py
index d815e19..044d8ad 100755
--- a/translate/storage/aresource.py
+++ b/translate/storage/aresource.py
@@ -21,6 +21,7 @@
 
 """Module for handling Android String and Plurals resource files."""
 
+import copy
 import re
 import os
 
@@ -102,33 +103,34 @@ class AndroidResourceUnit(base.TranslationUnit):
         while i < len(text):
             c = text[i]
 
-            # Handle whitespace collapsing
-            if c is not EOF and c in WHITESPACE:
-                space_count += 1
-            elif space_count > 1:
-                # Remove duplicate whitespace; Pay attention: We
-                # don't do this if we are currently inside a quote,
-                # except for one special case: If we have unbalanced
-                # quotes, e.g. we reach eof while a quote is still
-                # open, we *do* collapse that trailing part; this is
-                # how Android does it, for some reason.
-                if not active_quote or c is EOF:
-                    # Replace by a single space, will get rid of
-                    # non-significant newlines/tabs etc.
-                    text[i-space_count : i] = ' '
-                    i -= space_count - 1
-                space_count = 0
-            elif space_count == 1:
-                # At this point we have a single whitespace character,
-                # but it might be a newline or tab. If we write this
-                # kind of insignificant whitespace into the .po file,
-                # it will be considered significant on import. So,
-                # make sure that this kind of whitespace is always a
-                # standard space.
-                text[i-1] = ' '
-                space_count = 0
-            else:
-                space_count = 0
+            if not active_escape:
+                # Handle whitespace collapsing
+                if c is not EOF and c in WHITESPACE:
+                    space_count += 1
+                elif space_count > 1:
+                    # Remove duplicate whitespace; Pay attention: We
+                    # don't do this if we are currently inside a quote,
+                    # except for one special case: If we have unbalanced
+                    # quotes, e.g. we reach eof while a quote is still
+                    # open, we *do* collapse that trailing part; this is
+                    # how Android does it, for some reason.
+                    if not active_quote or c is EOF:
+                        # Replace by a single space, will get rid of
+                        # non-significant newlines/tabs etc.
+                        text[i-space_count : i] = ' '
+                        i -= space_count - 1
+                    space_count = 0
+                elif space_count == 1:
+                    # At this point we have a single whitespace character,
+                    # but it might be a newline or tab. If we write this
+                    # kind of insignificant whitespace into the .po file,
+                    # it will be considered significant on import. So,
+                    # make sure that this kind of whitespace is always a
+                    # standard space.
+                    text[i-1] = ' '
+                    space_count = 0
+                else:
+                    space_count = 0
 
             # Handle quotes
             if c == '"' and not active_escape:
@@ -213,10 +215,15 @@ class AndroidResourceUnit(base.TranslationUnit):
         # Join the string together again, but w/o EOF marker
         return "".join(text[:-1])
 
-    def escape(self, text, add_quote=True):
-        '''
-        Escape all the characters which need to be escaped in an Android XML file.
-        '''
+    def escape(self, text, quote_wrapping_whitespaces=True):
+        """Escape all the characters which need to be escaped in an Android XML
+        file.
+
+        :param text: Text to escape
+        :param quote_wrapping_whitespaces: If True, heading and trailing
+               whitespaces will be quoted placing the entire resulting text in
+               double quotes.
+        """
         if text is None:
             return
         if len(text) == 0:
@@ -234,7 +241,8 @@ class AndroidResourceUnit(base.TranslationUnit):
         if text.startswith('@'):
             text = '\\@' + text[1:]
         # Quote strings with more whitespace
-        if add_quote and (text[0] in WHITESPACE or text[-1] in WHITESPACE or len(MULTIWHITESPACE.findall(text)) > 0):
+        if ((quote_wrapping_whitespaces and (text[0] in WHITESPACE or text[-1] in WHITESPACE))
+                or len(MULTIWHITESPACE.findall(text))) > 0:
             return '"%s"' % text
         return text
 
@@ -251,33 +259,31 @@ class AndroidResourceUnit(base.TranslationUnit):
 
     def set_xml_text_value(self, target, xmltarget):
         if '<' in target:
-            # Handle text with possible markup
-            target = target.replace('&', '&')
             try:
-                # Try as XML
+                # Try to handle it as legacy XML
                 newstring = etree.fromstring('<string>%s</string>' % target)
             except:
                 # Fallback to string with XML escaping
-                target = target.replace('<', '<')
-                newstring = etree.fromstring('<string>%s</string>' % target)
-            # Update text
-            if newstring.text is None:
-                xmltarget.text = ''
+                xmltarget.text = self.escape(target)
             else:
+                # Escape all text parts.
+                if newstring.text is not None:
+                    newstring.text = self.escape(newstring.text, False)
+                for x in newstring.iterdescendants():
+                    if x.text is not None:
+                        x.text = self.escape(x.text, False)
+                    if x.tail is not None:
+                        x.tail = self.escape(x.tail, False)
+
+                # Update text
                 xmltarget.text = newstring.text
-            # Remove old elements
-            for x in xmltarget.iterchildren():
-                xmltarget.remove(x)
-            # Escape all text parts
-            for x in newstring.iter():
-                x.text = self.escape(x.text, False)
-                if x.prefix is not None:
-                    x.prefix = self.escape(x.prefix, False)
-                if x.tail is not None:
-                    x.tail = self.escape(x.tail, False)
-            # Add new elements
-            for x in newstring.iterchildren():
-                xmltarget.append(x)
+
+                # Remove old elements
+                for x in xmltarget.iterchildren():
+                    xmltarget.remove(x)
+                # Add new elements
+                for x in newstring.iterchildren():
+                    xmltarget.append(x)
         else:
             # Handle text only
             xmltarget.text = self.escape(target)
@@ -288,6 +294,7 @@ class AndroidResourceUnit(base.TranslationUnit):
             if self.xmlelement.tag != "plurals":
                 old_id = self.getid()
                 self.xmlelement = etree.Element("plurals")
+                self.xmlelement.tail = '\n'
                 self.setid(old_id)
 
             lang_tags = set(Locale(self.gettargetlanguage()).plural_form.tags)
@@ -329,6 +336,7 @@ class AndroidResourceUnit(base.TranslationUnit):
             if self.xmlelement.tag != "string":
                 old_id = self.getid()
                 self.xmlelement = etree.Element("string")
+                self.xmlelement.tail = '\n'
                 self.setid(old_id)
 
             self.set_xml_text_value(target, self.xmlelement)
@@ -336,11 +344,34 @@ class AndroidResourceUnit(base.TranslationUnit):
         super(AndroidResourceUnit, self).settarget(target)
 
     def get_xml_text_value(self, xmltarget):
-        # Grab inner text
-        target = self.unescape(xmltarget.text or u'')
-        # Include markup as well
-        target += u''.join([data.forceunicode(etree.tostring(child, encoding='utf-8')) for child in xmltarget.iterchildren()])
-        return target
+        if (len(xmltarget) == 0):
+            # There are no html markups, so unescaping it as plain text.
+            return self.unescape(xmltarget.text)
+        else:
+            # There are html markups, so clone it to perform unescaping for all elements.
+            cloned_target = copy.deepcopy(xmltarget)
+
+            # Unescaping texts.
+            if (cloned_target.text is not None):
+                cloned_target.text = self.unescape(cloned_target.text)
+            for xmlelement in cloned_target.iterdescendants():
+                if (xmlelement.text is not None):
+                    xmlelement.text = self.unescape(xmlelement.text)
+                if (xmlelement.tail is not None):
+                    xmlelement.tail = self.unescape(xmlelement.tail)
+
+            # Grab root text (using a temporary xml element for text escaping)
+            if (cloned_target.text is not None):
+                tmp_element = etree.Element('t')
+                tmp_element.text = cloned_target.text
+                target = data.forceunicode(etree.tostring(tmp_element, encoding='utf-8')[3:-4])
+            else:
+                target = u''
+
+            # Include markup as well
+            target += u''.join([data.forceunicode(etree.tostring(child, encoding='utf-8'))
+                                for child in cloned_target.iterchildren()])
+            return target
 
     def gettarget(self, lang=None):
         if (self.xmlelement.tag == "plurals"):
diff --git a/translate/storage/debug.properties b/translate/storage/debug.properties
new file mode 100644
index 0000000..0363f5f
--- /dev/null
+++ b/translate/storage/debug.properties
@@ -0,0 +1,20 @@
+# = and : as delimiters
+a = b
+c : d
+
+# Escaped whitespace in the key and value
+\ e\  = \ f 
+
+# Whitespace as a delimiter: space then tab
+g h
+i	j
+
+# Key without value
+k
+
+# Value with no key (this is valid, believe it or not)
+=l
+
+# You can actually have the empty string for key and value
+# This overrides =l above, so is commented out
+# =
diff --git a/translate/storage/idml.py b/translate/storage/idml.py
new file mode 100644
index 0000000..cb299fa
--- /dev/null
+++ b/translate/storage/idml.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2014 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 this program; if not, see <http://www.gnu.org/licenses/>.
+
+import zipfile
+
+
+# Tags to be extracted as placeables (tags that are within translatable texts).
+INLINE_ELEMENTS = [
+    ('', 'CharacterStyleRange'),
+    ('', 'Content'),
+#    ('', 'Br'),
+]
+
+
+# Skipping one of these tags doesn't imply nested acceptable tags are not
+# extracted.
+NO_TRANSLATE_ELEMENTS = [
+    ('http://ns.adobe.com/AdobeInDesign/idml/1.0/packaging', 'Story'),
+
+    ('', 'Story'),  # This is a different Story tag than the one above.
+    ('', 'StoryPreference'),
+    ('', 'InCopyExportOption'),
+    #('', 'ParagraphStyleRange'),
+    #('', 'CharacterStyleRange'),
+
+    ('', 'MetadataPacketPreference'),
+
+    ('', 'Contents'),  # Don't confuse with Content tag. This tag contains a
+    # lot of CDATA we don't want to parse.
+
+    ('', 'Properties'),
+    ('', 'Leading'),
+    ('', 'AppliedFont'),
+
+    ('', 'TextFrame'),
+    ('', 'PathGeometry'),
+    ('', 'GeometryPathType'),
+    ('', 'PathPointArray'),
+    ('', 'PathPointType'),
+
+    ('', 'AnchoredObjectSetting'),
+    ('', 'TextFramePreference'),
+    ('', 'TextWrapPreference'),
+    ('', 'TextWrapOffset'),
+    ('', 'ContourOption'),
+
+    ('', 'EPS'),
+    ('', 'GraphicBounds'),
+    ('', 'Link'),
+    ('', 'ClippingPathSettings'),
+    ('', 'FrameFittingOption'),
+
+    ('', 'ObjectExportOption'),
+    ('', 'AltMetadataProperty'),
+    ('', 'ActualMetadataProperty'),
+
+
+    ('', 'TabList'),
+    ('', 'ListItem'),
+    ('', 'Alignment'),
+    ('', 'AlignmentCharacter'),
+    ('', 'Leader'),
+    ('', 'Position'),
+
+    ('', 'Rectangle'),
+    #('', 'Br'),
+]
+
+
+def open_idml(filename):
+    z = zipfile.ZipFile(filename, 'r')
+    # Return a dictionary containing all the files inside the Stories
+    # subdirectory, being the keys the filenames (for example
+    # 'Stories/Story_u49f.xml' and the values the strings for those files.
+    return dict((filename, z.read(filename))
+                for filename in z.namelist() if filename.startswith('Stories/'))
+
+
+def copy_idml(input_zip, output_zip, exclusion_list):
+    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
diff --git a/translate/storage/jsonl10n.py b/translate/storage/jsonl10n.py
index 9a2526a..1b10a4a 100644
--- a/translate/storage/jsonl10n.py
+++ b/translate/storage/jsonl10n.py
@@ -107,7 +107,6 @@ class JsonUnit(base.TranslationUnit):
                 return str(value)
             return value
 
-            return newvalue
         if isinstance(self._ref, list):
             return change_type(self._ref[self._item])
         elif isinstance(self._ref, dict):
@@ -155,7 +154,11 @@ class JsonFile(base.TranslationStore):
             self.parse(inputfile)
 
     def __str__(self):
-        return json.dumps(self._file, sort_keys=True,
+        units = {}
+        for unit in self.unit_iter():
+            path = unit.getid().lstrip('.')
+            units[path] = unit.target
+        return json.dumps(units, sort_keys=True, separators=(',', ': '),
                           indent=4, ensure_ascii=False).encode('utf-8')
 
     def _extract_translatables(self, data, stop=None, prev="", name_node=None,
diff --git a/translate/storage/mozilla_lang.py b/translate/storage/mozilla_lang.py
index a1117eb..4b78326 100644
--- a/translate/storage/mozilla_lang.py
+++ b/translate/storage/mozilla_lang.py
@@ -67,7 +67,7 @@ class LangStore(txt.TxtFile):
         super(LangStore, self).__init__(inputfile, flavour, encoding)
 
     def parse(self, lines):
-        #Have we just seen a ';' line, and so are ready for a translation
+        # Have we just seen a ';' line, and so are ready for a translation
         readyTrans = False
         comment = ""
 
@@ -91,7 +91,8 @@ class LangStore(txt.TxtFile):
                 readyTrans = False  # We already have our translation
                 continue
 
-            if line.startswith('#'):  # A comment
+            if line.startswith('#') and not line.startswith('##'):
+                # Read comments, but not meta tags (e.g. '## TAG')
                 comment += line[1:].strip() + "\n"
 
             if line.startswith(';'):
diff --git a/translate/storage/odf_io.py b/translate/storage/odf_io.py
index bc4bc66..5c3a4f8 100644
--- a/translate/storage/odf_io.py
+++ b/translate/storage/odf_io.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-# Copyright 2008 Zuza Software Foundation
+# Copyright 2008, 2014 Zuza Software Foundation
 #
 # This file is part of translate.
 #
@@ -17,7 +17,6 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
-#
 
 import zipfile
 
@@ -37,22 +36,3 @@ def copy_odf(input_zip, output_zip, exclusion_list):
     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
-
-
-def namespaced(nsmap, short_namespace, tag):
-    return '{%s}%s' % (nsmap[short_namespace], tag)
-
-
-def add_file(output_zip, manifest_data, new_filename, new_data):
-    root = etree.fromstring(manifest_data)
-    namer = XmlNamer(root)
-    namespacer = namer.namespace('manifest')
-    file_entry_tag = namespacer.name('file-entry')
-    media_type_attr = namespacer.name('media-type')
-    full_path_attr = namespacer.name('full-path')
-
-    root.append(etree.Element(file_entry_tag, {media_type_attr: 'application/x-xliff+xml',
-                                               full_path_attr: new_filename}))
-    output_zip.writestr(new_filename, new_data)
-    output_zip.writestr('META-INF/manifest.xml', etree.tostring(root, xml_declaration=True, encoding="UTF-8"))
-    return output_zip
diff --git a/translate/storage/odf_shared.py b/translate/storage/odf_shared.py
index ee116ef..8c16b81 100644
--- a/translate/storage/odf_shared.py
+++ b/translate/storage/odf_shared.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-# Copyright 2004-2006 Zuza Software Foundation
+# Copyright 2004-2014 Zuza Software Foundation
 #
 # This file is part of translate.
 #
@@ -17,171 +17,161 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
-#
 
 
-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()
+# 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 = [  # It is named skip_content_elements in itools.
+
+    # 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'),
+]
diff --git a/translate/storage/placeables/parse.py b/translate/storage/placeables/parse.py
index adf697f..45ec062 100644
--- a/translate/storage/placeables/parse.py
+++ b/translate/storage/placeables/parse.py
@@ -66,7 +66,7 @@ def parse(tree, parse_funcs):
 
         subleaves = parse_func(unileaf)
         if subleaves is not None:
-            if (len(subleaves) == 1 and type(leaf) is type(subleaves[0]) and
+            if (len(subleaves) == 1 and isinstance(subleaves[0], type(leaf)) and
                 leaf == subleaves[0]):
                 pass
             elif isinstance(leaf, unicode):
diff --git a/translate/storage/po.py b/translate/storage/po.py
index 48ca840..4bc3645 100644
--- a/translate/storage/po.py
+++ b/translate/storage/po.py
@@ -19,11 +19,13 @@
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 """A class loader that will load C or Python implementations of the PO class
-depending on the USECPO variable.
+depending on the ``USECPO`` variable.
 
-Use the environment variable USECPO=2 (or 1) to choose the C implementation which
-uses Gettext's libgettextpo for high parsing speed.  Otherise the local
-Python based parser is used (slower but very well tested)."""
+Use the environment variable ``USECPO=2`` (or ``USECPO=1``) to choose the
+C implementation which uses Gettext's libgettextpo for high parsing speed.
+Otherwise the local Python based parser is used (slower but very well
+tested).
+"""
 
 import logging
 import os
diff --git a/translate/storage/poheader.py b/translate/storage/poheader.py
index 326222f..89267ae 100644
--- a/translate/storage/poheader.py
+++ b/translate/storage/poheader.py
@@ -79,7 +79,7 @@ def update(existing, add=False, **kwargs):
     only if add is true.
 
     :return: Updated dictionary of header entries
-    :rtype: dict
+    :rtype: dict of strings
     """
     headerargs = OrderedDict()
     fixedargs = cidict()
@@ -155,7 +155,7 @@ class poheader(object):
         or a value (datetime or string)
 
         :return: Dictionary with the header items
-        :rtype: dict
+        :rtype: dict of strings
         """
         if project_id_version is None:
             project_id_version = "PACKAGE VERSION"
diff --git a/translate/storage/properties.java b/translate/storage/properties.java
new file mode 100644
index 0000000..b3887cc
--- /dev/null
+++ b/translate/storage/properties.java
@@ -0,0 +1,30 @@
+// Read in debug.properties file and output the Java interpretation.
+//
+// This file is intended for debugging purposes.  Make your changes to a file
+// called debug.properties and observe the Java interpretation.
+//
+// To compile:
+//    javac properties.java
+//
+// To run:
+//    java properties
+
+import java.util.*;
+import java.io.*;
+
+class properties{
+	public static void main(String args[]) {
+
+		Properties properties = new Properties();
+		try {
+		    properties.load(new FileInputStream("debug.properties"));
+		    PrintWriter outwriter = new PrintWriter(System.out);
+		    properties.list(System.out);
+		    System.out.println(properties);
+		    outwriter.flush();
+		} catch (IOException e) {
+			System.out.println("Some error occured");
+		}
+	}
+}
+
diff --git a/translate/storage/resx.py b/translate/storage/resx.py
new file mode 100644
index 0000000..fa82b56
--- /dev/null
+++ b/translate/storage/resx.py
@@ -0,0 +1,209 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2015 Zuza Software Foundation
+# Copyright 2015 Sarah Hale
+#
+# 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 this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""Module for handling .Net Resource (.resx) files."""
+
+from lxml import etree
+
+from translate.lang import data
+from translate.storage import base, lisa
+from translate.storage.placeables import general
+
+class RESXUnit(lisa.LISAunit):
+    """A single term in the RESX file."""
+
+    rootNode = "data"
+    languageNode = "value"
+    textNode = ""
+    namespace = ""
+    rich_parsers = general.parsers
+
+    def createlanguageNode(self, lang, text, purpose):
+        """Returns an xml Element setup with given parameters."""
+
+        langset = etree.Element(self.namespaced(self.languageNode))
+
+        langset.text = text
+        return langset
+
+    def _gettargetnode(self):
+        return self.xmlelement.find(self.namespaced(self.languageNode))
+
+    def getsource(self):
+        return self.gettarget()
+
+    def settarget(self, text, lang='xx', append=False):
+        # Firstly deal with reinitialising to None or setting to identical
+        # string.
+        self._rich_target = None
+        if self.gettarget() == text:
+            return
+        strings = []
+        if isinstance(text, list):
+            strings = text
+        else:
+            strings = [text]
+        targetnode = self._gettargetnode()
+        targetnode.clear()
+        targetnode.text = data.forceunicode(text) or u""
+        targetnode.tail = u"\n    "
+
+    def gettarget(self, lang=None):
+        targetnode = self._gettargetnode()
+        if targetnode is None:
+            etree.SubElement(self.xmlelement, self.namespaced("value"))
+            return None
+        return data.forceunicode(targetnode.text) or u""
+    target = property(gettarget, settarget)
+    rich_target = property(base.TranslationUnit._get_rich_target, base.TranslationUnit._set_rich_target)
+
+    def addnote(self, text, origin=None, position="append"):
+        """Add a note specifically in the appropriate "comment" tag"""
+        if isinstance(text, str):
+            text = text.decode("utf-8")
+        current_notes = self.getnotes(origin)
+        self.removenotes(origin)
+        note = etree.SubElement(self.xmlelement, self.namespaced("comment"))
+        text_stripped = text.strip()
+        if position == "append":
+            if current_notes.strip() in text_stripped:
+                # Don't add duplicate comments
+                note.text = text_stripped
+            else:
+                note.text = "\n".join(filter(None, [current_notes, text_stripped]))
+        else:
+            note.text = text_stripped
+
+    def getnotes(self, origin=None):
+        comments = []
+        notenode = self.xmlelement.find(self.namespaced("comment"))
+        if notenode is not None and notenode.text is not None:
+            comments.append(notenode.text)
+        return '\n'.join(comments)
+
+    def removenotes(self, origin=None):
+        note = self.xmlelement.find(self.namespaced("comment"))
+        if not note is None:
+            self.xmlelement.remove(note)
+
+    def setid(self, value):
+        if id is None:
+            return False
+        else:
+            self.xmlelement.set("name", value)
+
+    def getid(self):
+        return self.xmlelement.get("name")
+
+    def getlocations(self):
+        return [self.getid()]
+
+    def merge(self, otherunit, overwrite=False, comments=True, authoritative=False):
+        super(RESXUnit, self).merge(otherunit, overwrite, comments)
+        if otherunit.isfuzzy():
+            self.markfuzzy()
+
+
+class RESXFile(lisa.LISAfile):
+    """Class representing a RESX file store."""
+    UnitClass = RESXUnit
+    Name = ".NET RESX File"
+    Mimetypes = ["text/microsoft-resx"]
+    Extensions = ["resx"]
+    rootNode = "root"
+    # We will switch out .body to fit with the context we are working on
+    bodyNode = ""
+    XMLskeleton = '''<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+</root>
+'''
+    namespace = ''
+
+    def __init__(self, *args, **kwargs):
+        lisa.LISAfile.__init__(self, *args, **kwargs)
+        self._messagenum = 0
+
+    def initbody(self):
+        """Initialises self.body."""
+        self.namespace = self.document.getroot().nsmap.get(None, None)
+        self.header = self.document.getroot()
+        self.body = self.document.getroot()
+
+    def addunit(self, unit, new=True):
+        """Adds the given unit to the body node."""
+        super(RESXFile, self).addunit(unit, new)
+        lisa.setXMLspace(unit.xmlelement, "preserve")
+        if unit.getid() is None:
+            self._messagenum += 1
+            unit.setid(u"%s" % unit.source.strip(' '))
+        return unit
diff --git a/translate/storage/test_aresource.py b/translate/storage/test_aresource.py
index c435032..7c2dd1c 100644
--- a/translate/storage/test_aresource.py
+++ b/translate/storage/test_aresource.py
@@ -75,6 +75,11 @@ class TestAndroidResourceUnit(test_monolingual.TestMonolingualUnit):
         xml = '<string name="Test String">" leading space"</string>\n\n'
         self.__check_escape(string, xml)
 
+    def test_escape_trailing_space(self):
+        string = 'leading space '
+        xml = '<string name="Test String">"leading space "</string>\n\n'
+        self.__check_escape(string, xml)
+
     def test_escape_xml_entities(self):
         string = '>xml&entities'
         xml = '<string name="Test String">>xml&entities</string>\n\n'
@@ -99,8 +104,9 @@ class TestAndroidResourceUnit(test_monolingual.TestMonolingualUnit):
 
     def test_escape_link(self):
         string = '<a href="http://example.net">link</a>'
-        xml = ('<string name="Test String"><a href="http://example.net">link'
-               '</a></string>\n\n')
+        xml = ('<string name="Test String">\n'
+               '  <a href="http://example.net">link</a>\n'
+               '</string>\n\n')
         self.__check_escape(string, xml)
 
     def test_escape_link_and_text(self):
@@ -119,9 +125,52 @@ class TestAndroidResourceUnit(test_monolingual.TestMonolingualUnit):
         xml = ('<plurals name="Test String">\n\t'
                  '<item quantity="one">one message\\nwith newline</item>\n\t'
                  '<item quantity="other">other message\\nwith newline</item>\n'
-               '</plurals>\n')
+               '</plurals>\n\n')
         self.__check_escape(mString, xml, 'en')
 
+    def test_escape_html_quote(self):
+        string = 'start \'here\' <b>html code \'to escape\'</b> also \'here\''
+        xml = ('<string name="Test String">start \\\'here\\\' <b>html code \\\'to escape\\\'</b> also \\\'here\\\''
+               '</string>\n\n')
+        self.__check_escape(string, xml)
+
+    def test_escape_html_leading_space(self):
+        string = ' <b>html code \'to escape\'</b> some \'here\''
+        xml = ('<string name="Test String"> <b>html code \\\'to escape\\\'</b> some \\\'here\\\''
+               '</string>\n\n')
+        self.__check_escape(string, xml)
+
+    def test_escape_html_trailing_space(self):
+        string = '<b>html code \'to escape\'</b> some \'here\' '
+        xml = ('<string name="Test String"><b>html code \\\'to escape\\\'</b> some \\\'here\\\' '
+               '</string>\n\n')
+        self.__check_escape(string, xml)
+
+    def test_escape_html_with_ampersand(self):
+        string = '<b>html code \'to escape\'</b> some \'here\' with & char'
+        xml = ('<string name="Test String"><b>html code \\\'to escape\\\'</b> some \\\'here\\\' with & char'
+               '</string>\n\n')
+        self.__check_escape(string, xml)
+
+    def test_escape_html_double_space(self):
+        string = '<b>html code \'to  escape\'</b> some \'here\''
+        xml = ('<string name="Test String"><b>"html code \\\'to  escape\\\'"</b> some \\\'here\\\''
+               '</string>\n\n')
+        self.__check_escape(string, xml)
+
+    def test_escape_html_deep_double_space(self):
+        string = '<b>html code \'to  <i>escape</i>\'</b> some \'here\''
+        xml = ('<string name="Test String"><b>"html code \\\'to  "<i>escape</i>\\\'</b> some \\\'here\\\''
+               '</string>\n\n')
+        self.__check_escape(string, xml)
+
+    def test_escape_complex_xml(self):
+        string = '<g:test xmlns:g="ttt" g:somevalue="aaaa  "  aaa">value</g:test> & outer > <br/>text'
+        xml = ('<string name="Test String">'
+               '<g:test xmlns:g="ttt" g:somevalue="aaaa  "  aaa">value</g:test> & outer > <br/>text'
+               '</string>\n\n')
+        self.__check_escape(string, xml)
+
     ############################ Check string parse ###########################
 
     def test_parse_message_with_newline(self):
@@ -130,8 +179,8 @@ class TestAndroidResourceUnit(test_monolingual.TestMonolingualUnit):
         self.__check_parse(string, xml)
 
     def test_parse_message_with_newline_in_xml(self):
-        string = 'message \nwith newline in xml'
-        xml = ('<string name="Test String">message\n\\nwith newline in xml'
+        string = 'message \nwith\n newline\nin xml'
+        xml = ('<string name="Test String">message\n\\nwith\\n\nnewline\\n\\\nin xml'
                '</string>\n\n')
         self.__check_parse(string, xml)
 
@@ -218,10 +267,64 @@ class TestAndroidResourceUnit(test_monolingual.TestMonolingualUnit):
         mString = multistring(['one message\nwith newline', 'other message\nwith newline'])
         xml = ('<plurals name="Test String">\n\t'
                  '<item quantity="one">one message\\nwith newline</item>\n\t'
-                 '<item quantity="other">other message\\nwith newline</item>\n'
-               '</plurals>\n')
+                 '<item quantity="other">other message\\nwith newline</item>\n\n'
+               '</plurals>\n\n')
         self.__check_parse(mString, xml)
 
+    def test_parse_html_quote(self):
+        string = 'start \'here\' <b>html code \'to escape\'</b> also \'here\''
+        xml = ('<string name="Test String">start \\\'here\\\' <b>html code \\\'to escape\\\'</b> also \\\'here\\\''
+               '</string>\n\n')
+        self.__check_parse(string, xml)
+
+    def test_parse_html_leading_space(self):
+        string = ' <b>html code \'to escape\'</b> some \'here\''
+        xml = ('<string name="Test String"> <b>html code \\\'to escape\\\'</b> some \\\'here\\\''
+               '</string>\n\n')
+        self.__check_parse(string, xml)
+
+    def test_parse_html_leading_space_quoted(self):
+        string = ' <b>html code \'to escape\'</b> some \'here\''
+        xml = ('<string name="Test String">" "<b>"html code \'to escape\'"</b>" some \'here\'"'
+               '</string>\n\n')
+        self.__check_parse(string, xml)
+
+    def test_parse_html_trailing_space(self):
+        string = '<b>html code \'to escape\'</b> some \'here\' '
+        xml = ('<string name="Test String"><b>html code \\\'to escape\\\'</b> some \\\'here\\\' '
+               '</string>\n\n')
+        self.__check_parse(string, xml)
+
+    def test_parse_html_trailing_space_quoted(self):
+        string = '<b>html code \'to escape\'</b> some \'here\' '
+        xml = ('<string name="Test String"><b>"html code \'to escape\'"</b>" some \'here\' "'
+               '</string>\n\n')
+        self.__check_parse(string, xml)
+
+    def test_parse_html_with_ampersand(self):
+        string = '<b>html code \'to escape\'</b> some \'here\' with & char'
+        xml = ('<string name="Test String"><b>html code \\\'to escape\\\'</b> some \\\'here\\\' with & char'
+               '</string>\n\n')
+        self.__check_parse(string, xml)
+
+    def test_parse_html_double_space_quoted(self):
+        string = '<b>html code \'to  escape\'</b> some \'here\''
+        xml = ('<string name="Test String"><b>"html code \'to  escape\'"</b>" some \'here\'"'
+               '</string>\n\n')
+        self.__check_parse(string, xml)
+
+    def test_parse_html_deep_double_space_quoted(self):
+        string = '<b>html code \'to  <i>  escape</i>\'</b> some \'here\''
+        xml = ('<string name="Test String"><b>"html code \'to  "<i>"  escape"</i>\\\'</b> some \\\'here\\\''
+               '</string>\n\n')
+        self.__check_parse(string, xml)
+
+    def test_parse_complex_xml(self):
+        string = '<g:test xmlns:g="ttt" g:somevalue="aaaa  "  aaa">value</g:test> outer & text'
+        xml = ('<string name="Test String">'
+               '<g:test xmlns:g="ttt" g:somevalue="aaaa  "  aaa">value</g:test> outer & text'
+               '</string>\n\n')
+        self.__check_parse(string, xml)
 
 class TestAndroidResourceFile(test_monolingual.TestMonolingualStore):
     StoreClass = aresource.AndroidResourceFile
diff --git a/translate/storage/test_monolingual.py b/translate/storage/test_monolingual.py
index 8d44adb..a2fe341 100644
--- a/translate/storage/test_monolingual.py
+++ b/translate/storage/test_monolingual.py
@@ -41,11 +41,11 @@ class TestMonolingualStore(test_base.TestTranslationStore):
             store2unit = store2.units[n]
 
             if str(store1unit) != str(store2unit):
-                print(("match failed between elements %d of %d" % ((n + 1), len(store1.units))))
+                print("match failed between elements %d of %d" % (n+1, len(store1.units)))
                 print("store1:")
-                print((str(store1)))
+                print(str(store1))
                 print("store2:")
-                print((str(store2)))
-                print(("store1.units[%d].__dict__:" % n, store1unit.__dict__))
-                print(("store2.units[%d].__dict__:" % n, store2unit.__dict__))
+                print(str(store2))
+                print("store1.units[%d].__dict__:" % n, store1unit.__dict__)
+                print("store2.units[%d].__dict__:" % n, store2unit.__dict__)
                 assert str(store1unit) == str(store2unit)
diff --git a/translate/storage/test_resx.py b/translate/storage/test_resx.py
new file mode 100644
index 0000000..408118d
--- /dev/null
+++ b/translate/storage/test_resx.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2015 Zuza Software Foundation
+# Copyright 2015 Sarah Hale
+#
+# 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 this program; if not, see <http://www.gnu.org/licenses/>.
+
+from translate.misc import wStringIO
+from translate.storage import test_monolingual, resx
+
+
+class TestRESXUnit(test_monolingual.TestMonolingualUnit):
+    UnitClass = resx.RESXUnit
+
+class TestRESXUnitFromParsedString(TestRESXUnit):
+    resxsource = XMLskeleton = '''<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <data name="key" xml:space="preserve">
+     <value>Test String</value>
+  </data>
+  %s
+</root>'''
+
+    def setup_method(self, method):
+        store = resx.RESXFile.parsestring(self.resxsource)
+        self.unit = store.units[0]
+
+class TestRESXfile(test_monolingual.TestMonolingualUnit):
+    StoreClass = resx.RESXFile
+
+    def resxparse(self, resxsource):
+        """helper that parses resx source without requiring files"""
+        dummyfile = wStringIO.StringIO(resxsource)
+        txtfile = self.StoreClass(dummyfile)
+        return txtfile
diff --git a/translate/storage/test_ts2.py b/translate/storage/test_ts2.py
index 5decda3..279c9f5 100644
--- a/translate/storage/test_ts2.py
+++ b/translate/storage/test_ts2.py
@@ -32,6 +32,35 @@ from translate.storage.placeables import parse, xliff
 from translate.storage.placeables.lisa import xml_to_strelem
 
 
+TS_NUMERUS = """<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE TS>
+<TS version="2.1">
+<context>
+    <name>Dialog2</name>
+    <message numerus="yes">
+        <source>%n files</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message id="this_is_some_id" numerus="yes">
+        <source>%n cars</source>
+        <translation type="unfinished">
+            <numerusform></numerusform>
+        </translation>
+    </message>
+    <message>
+        <source>Age: %1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message id="this_is_another_id">
+        <source>func3</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+</TS>
+"""
+
 xliffparsers = []
 for attrname in dir(xliff):
     attr = getattr(xliff, attrname)
@@ -216,35 +245,12 @@ class TestTSfile(test_base.TestTranslationStore):
 
     def test_getid(self):
         """test that getid works well"""
-        tsstr = """<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS>
-<TS version="2.1">
-<context>
-    <name>Dialog2</name>
-    <message numerus="yes">
-        <source>%n files</source>
-        <translation type="unfinished">
-            <numerusform></numerusform>
-        </translation>
-    </message>
-    <message id="this_is_some_id" numerus="yes">
-        <source>%n cars</source>
-        <translation type="unfinished">
-            <numerusform></numerusform>
-        </translation>
-    </message>
-    <message>
-        <source>Age: %1</source>
-        <translation type="unfinished"></translation>
-    </message>
-    <message id="this_is_another_id">
-        <source>func3</source>
-        <translation type="unfinished"></translation>
-    </message>
-</context>
-</TS>"""
-
-        tsfile = ts.tsfile.parsestring(tsstr)
+        tsfile = ts.tsfile.parsestring(TS_NUMERUS)
         assert tsfile.units[0].getid() == "Dialog2%n files"
         assert tsfile.units[1].getid() == "Dialog2\nthis_is_some_id%n cars"
         assert tsfile.units[3].getid() == "Dialog2\nthis_is_another_idfunc3"
+
+    def test_backnforth(self):
+        """test that ts files are read and output properly"""
+        tsfile = ts.tsfile.parsestring(TS_NUMERUS)
+        assert str(tsfile) == TS_NUMERUS
diff --git a/translate/storage/ts2.py b/translate/storage/ts2.py
index a6be907..32ac899 100644
--- a/translate/storage/ts2.py
+++ b/translate/storage/ts2.py
@@ -481,5 +481,11 @@ class tsfile(lisa.LISAfile):
 
     def __str__(self):
         """Converts to a string containing the file's XML."""
-        return etree.tostring(self.document, pretty_print=True,
+        root = self.document.getroot()
+        doctype = self.document.docinfo.doctype
+        # Iterate over empty tags without children and force empty text
+        # This will prevent self-closing tags in pretty_print mode
+        for e in root.xpath("//*[not(./node()) and not(text())]"):
+            e.text = ""
+        return etree.tostring(root, doctype=doctype, pretty_print=True,
                               xml_declaration=True, encoding='utf-8')
diff --git a/translate/storage/xliff.py b/translate/storage/xliff.py
index c012552..0de62f2 100644
--- a/translate/storage/xliff.py
+++ b/translate/storage/xliff.py
@@ -488,6 +488,8 @@ class xliffunit(lisa.LISAunit):
                 self.markfuzzy()
             elif otherunit.source == self.source:
                 self.markfuzzy(False)
+            elif otherunit.source != self.source:
+                self.markfuzzy(True)
         if comments:
             self.addnote(otherunit.getnotes())
 
diff --git a/translate/storage/xml_extract/extract.py b/translate/storage/xml_extract/extract.py
index a66dae4..ff4a1f2 100644
--- a/translate/storage/xml_extract/extract.py
+++ b/translate/storage/xml_extract/extract.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-# Copyright 2008-2009 Zuza Software Foundation
+# Copyright 2008-2014 Zuza Software Foundation
 #
 # This file is part of the Translate Toolkit.
 #
@@ -18,7 +18,7 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
-from contextlib import contextmanager, nested
+from contextlib import contextmanager
 
 from lxml import etree
 
@@ -31,28 +31,42 @@ class Translatable(object):
     """A node corresponds to a translatable element. A node may
        have children, which correspond to placeables."""
 
-    def __init__(self, placeable_name, xpath, dom_node, source):
+    def __init__(self, placeable_name, xpath, dom_node, source,
+                 is_inline=False):
         self.placeable_name = placeable_name
         self.source = source
         self.xpath = xpath
-        self.is_inline = False
+        self.is_inline = is_inline
         self.dom_node = dom_node
 
-    def _get_placeables(self):
-        return [placeable for placeable in self.source if isinstance(placeable, Translatable)]
+    @property
+    def placeables(self):
+        return [placeable for placeable in self.source
+                if isinstance(placeable, Translatable)]
+
+    @property
+    def has_translatable_text(self):
+        """Check if it contains any chunk of text with more than whitespace.
 
-    placeables = property(_get_placeables)
+        If not, then there's nothing to translate.
+        """
+        for chunk in self.source:
+            if isinstance(chunk, unicode) and chunk.strip() != u"":
+                return True
+        return False
 
 
 def reduce_unit_tree(f, unit_node, *state):
-    return misc.reduce_tree(f, unit_node, unit_node, lambda unit_node: unit_node.placeables, *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={}):
+    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
@@ -62,47 +76,142 @@ class ParseState(object):
 
 
 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"
+    """Process current placeable.
+
+    This returns all nested translatable content for this placeable as a single
+    Translatable object, or just returns an empty Translatable object for this
+    placeable if there is no nested translatable content.
+    """
+    placeable = find_translatable_dom_nodes(dom_node, state,
+                                            process_translatable)
+
     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.
+        # There are no recognized child tags and thus no Translatable object is
+        # returned. So create a Translatable with the name "placeable".
+        return Translatable(u"placeable", state.xpath_breadcrumb.xpath,
+                            dom_node, [])
     elif len(placeable) == 1:
+        # The ideal situation: we got exactly one Translatable back when
+        # processing this tree.
         return placeable[0]
     else:
-        raise Exception("BUG: find_translatable_dom_nodes should never return more than a single translatable")
+        raise Exception("BUG: find_translatable_dom_nodes should never return "
+                        "more than a single Translatable object")
+
+
+def process_translatable(dom_node, state):
+    """Process a translatable DOM node.
+
+    Any translatable content present in a child node is treated as a placeable.
+    """
+    source = [unicode(dom_node.text or u"")]
+
+    # Append Translatable objects and unicode strings for the translatable
+    # content for all the children.
+    for child in dom_node:
+        source.append(_process_placeable(child, state))
+        source.append(unicode(child.tail or u""))
+
+    translatable = Translatable(state.placeable_name,
+                                state.xpath_breadcrumb.xpath, dom_node, source,
+                                state.is_inline)
+    return [translatable]
+
+
+def _has_idml_translatable_content(dom_node):
+    has_translatable_content = True
+    if dom_node.tag == 'ParagraphStyleRange':
+        has_translatable_content = False
+
+        for content_node in dom_node.findall('.//Content'):
+            # Iterate over all the Content tags in this ParagraphStyleRange tag.
+            if content_node.text is not None and content_node.text.strip():
+                return True
+
+            for child in content_node.iterdescendants():
+                # The Content node can just have a child before any nested
+                # text, and therefore its text is None, so we have to check if
+                # it has children, and if any of its children has text.
+                if (not isinstance(child, etree._ProcessingInstruction) and
+                    child.text is not None and child.text.strip()):
+                    return True
 
+                if child.tail is not None and child.tail.strip():
+                    return True
 
-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."""
+    return has_translatable_content
 
+
+def _retrieve_idml_placeables(dom_node, state):
     source = []
     for child in dom_node:
-        source.extend([_process_placeable(child, state), unicode(child.tail or u"")])
+        if not isinstance(child, etree._Element):
+            continue
+
+        if isinstance(child, etree._ProcessingInstruction):
+            #TODO this probably won't be using the right xpath.
+            source.append(Translatable(u"placeable",
+                                       state.xpath_breadcrumb.xpath, child, [],
+                                       False))
+
+            if child.tail is not None and child.tail.strip():
+                source.append(unicode(child.tail))
+
+            continue
+
+        namespace, tag = misc.parse_tag(child.tag)
+
+        with parse_status_set(namespace, tag, state):
+            # Ensure we extract all the tags below ParagraphStyleRange as
+            # placeables, independently of them being translatable or not.
+            #state.is_inline = True
+
+            nested_stuff = []
+
+            if child.text is not None and child.text.strip():
+                nested_stuff = [unicode(child.text)]
+
+            nested_stuff.extend(_retrieve_idml_placeables(child, state))
+
+            source.append(Translatable(u"placeable",
+                                       state.xpath_breadcrumb.xpath, child,
+                                       nested_stuff, state.is_inline))
+
+            if child.tail is not None and child.tail.strip():
+                source.append(unicode(child.tail))
+
     return source
 
 
-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]
+def process_idml_translatable(dom_node, state):
+    if _has_idml_translatable_content(dom_node):
+        source = _retrieve_idml_placeables(dom_node, state)
+
+        translatable = Translatable(state.placeable_name,
+                                    state.xpath_breadcrumb.xpath, dom_node,
+                                    source, state.is_inline)
+        return [translatable]
+
+    return []
 
 
-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]
+def _process_children(dom_node, state, process_func):
+    """Process an untranslatable DOM node.
+
+    Since the node is untranslatable it just returns any translatable content
+    present in its child nodes.
+    """
+    children = [find_translatable_dom_nodes(child, state, process_func)
+                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)
+        _namespace, tag = misc.parse_tag(dom_node.tag)
+        intermediate_translatable = Translatable(tag,
+                                                 state.xpath_breadcrumb.xpath,
+                                                 dom_node, children)
         return [intermediate_translatable]
     else:
         return children
@@ -115,44 +224,45 @@ def compact_tag(nsmap, namespace, tag):
         return u'{%s}%s' % (namespace, tag)
 
 
-def find_translatable_dom_nodes(dom_node, state):
+ at contextmanager
+def parse_status_set(namespace, tag, state):
+    # Set XPath breadcrumb item for the current node.
+    xpath_item = compact_tag(state.nsmap, namespace, tag)
+    state.xpath_breadcrumb.start_tag(xpath_item)
+
+    # Set the placeable name for the current node.
+    old_placeable_name = state.placeable_name
+    state.placeable_name = tag
+
+    # Set the inline status for the current node.
+    old_inline = state.is_inline
+    state.is_inline = (namespace, tag) in state.inline_elements
+
+    yield state
+
+    # Reset inline status, placeable name and XPath breadcrumb to the
+    # previous values.
+    state.is_inline = old_inline
+    state.placeable_name = old_placeable_name
+    state.xpath_breadcrumb.end_tag()
+
+
+def find_translatable_dom_nodes(dom_node, state,
+                                process_func=process_translatable):
     # 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):
+    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
-
-    with nested(xpath_set(), placeable_set(), inline_set()):
+    with parse_status_set(namespace, tag, state):
         if (namespace, tag) not in state.no_translate_content_elements:
-            return _process_translatable(dom_node, state)
+            return process_func(dom_node, state)
         else:
-            return _process_children(dom_node, state)
+            return _process_children(dom_node, state, process_func)
 
 
 class IdMaker(object):
@@ -172,6 +282,9 @@ class IdMaker(object):
 
 
 def _to_placeables(parent_translatable, translatable, id_maker):
+    """Convert the translatable object to a list of strings and XLIFF
+    placeables.
+    """
     result = []
     for chunk in translatable.source:
         if isinstance(chunk, unicode):
@@ -179,68 +292,117 @@ def _to_placeables(parent_translatable, translatable, id_maker):
         else:
             id = unicode(id_maker.get_id(chunk))
             if chunk.is_inline:
-                result.append(xliff.G(sub=_to_placeables(parent_translatable, chunk, id_maker), id=id))
+                sub = _to_placeables(parent_translatable, chunk, id_maker)
+                result.append(xliff.G(id=id, sub=sub))
             else:
                 result.append(xliff.X(id=id, xid=chunk.xpath))
     return result
 
 
-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'.
+def _make_store_adder(store):
+    """Return a function which, when called with a Translatable will add
+    a unit to 'store'. The placeables will be represented as strings according
+    to 'placeable_quoter'.
     """
-    unit = store.UnitClass(u'')
-    unit.rich_source = [StringElem(_to_placeables(parent_translatable, translatable, id_maker))]
-    unit.addlocation(translatable.xpath)
-    store.addunit(unit)
+    id_maker = IdMaker()
 
+    def add_translatable_to_store(parent_translatable, translatable):
+        """Construct a new translation unit, set its source and location
+        information and add it to 'store'.
+        """
+        unit = store.UnitClass(u'')
+        unit.rich_source = [StringElem(_to_placeables(parent_translatable,
+                                                      translatable, id_maker))]
+        unit.addlocation(translatable.xpath)
+        store.addunit(unit)
 
-def _contains_translatable_text(translatable):
-    """Checks whether translatable contains any chunks of text which contain
-    more than whitespace.
+    return add_translatable_to_store
 
-    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
 
-
-def _make_store_adder(store):
+def make_postore_adder(store, id_maker, filename):
     """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()
+    a unit to 'store'. The placeables will be represented as strings according
+    to 'placeable_quoter'.
+    """
+    from translate.storage.xliff import xliffunit
 
-    def add_to_store(parent_translatable, translatable, rid):
-        _add_translatable_to_store(store, parent_translatable, translatable, id_maker)
+    def add_translatable_to_store(parent_translatable, translatable):
+        """Construct a new translation unit, set its source and location
+        information and add it to 'store'.
+        """
+        xliff_unit = xliffunit(u'')
+        placeables = _to_placeables(parent_translatable, translatable, id_maker)
+        xliff_unit.rich_source = [StringElem(placeables)]
 
-    return add_to_store
+        # Get the plain text for the unit source. The output is enclosed within
+        # XLIFF source tags we don't want, so strip them.
+        unit_source = etree.tostring(xliff_unit.source_dom)
+        unit_source = unit_source[unit_source.find(">", 1) + 1:]
+        unit_source = unit_source[:unit_source.rfind("<", 1)]
 
+        # Create the PO unit and add it to the PO store.
+        po_unit = store.UnitClass(unit_source)
+        po_unit.addlocation(translatable.xpath)
+        po_unit.addlocation(filename)
+        store.addunit(po_unit)
 
-def _walk_translatable_tree(translatables, f, parent_translatable, rid):
+    return add_translatable_to_store
+
+
+def _walk_idml_translatable_tree(translatables, store_adder,
+                                 parent_translatable):
+    """Traverse all the found IDML translatables and add them to the Store.
+
+    Inline translatables are not added to the Store.
+    """
+    for translatable in translatables:
+        if translatable.dom_node.tag == "ParagraphStyleRange":
+            store_adder(parent_translatable, translatable)
+            continue
+
+        new_parent_translatable = parent_translatable
+        _walk_idml_translatable_tree(translatable.placeables, store_adder,
+                                     new_parent_translatable)
+
+
+def _walk_translatable_tree(translatables, store_adder, parent_translatable):
+    """Traverse all the found translatables and add them to the Store.
+
+    Inline translatables are not added to the Store.
+    """
     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)
+        if translatable.has_translatable_text and not translatable.is_inline:
+            store_adder(parent_translatable, translatable)
+            new_parent_translatable = parent_translatable
         else:
             new_parent_translatable = parent_translatable
 
-        _walk_translatable_tree(translatable.placeables, f, new_parent_translatable, rid)
+        _walk_translatable_tree(translatable.placeables, store_adder,
+                                new_parent_translatable)
 
 
 def reverse_map(a_map):
     return dict((value, key) for key, value in a_map.iteritems())
 
 
+def build_idml_store(odf_file, store, parse_state, store_adder=None):
+    """Build a store for the given IDML file."""
+    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,
+                                                process_idml_translatable)
+    _walk_idml_translatable_tree(translatables, store_adder, None)
+    return tree
+
+
 def build_store(odf_file, store, parse_state, store_adder=None):
-    """Utility function for loading xml_filename"""
+    """Build a store for the given XML file."""
     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)
+    _walk_translatable_tree(translatables, store_adder, None)
     return tree
diff --git a/translate/storage/xml_extract/generate.py b/translate/storage/xml_extract/generate.py
index 6dae05e..74ebc0c 100644
--- a/translate/storage/xml_extract/generate.py
+++ b/translate/storage/xml_extract/generate.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
-# Copyright 2002-2006 Zuza Software Foundation
+# Copyright 2002-2014 Zuza Software Foundation
 #
 # This file is part of translate.
 #
@@ -17,7 +17,6 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
-#
 
 import lxml.etree as etree
 
@@ -161,7 +160,6 @@ def _map_target_dom_to_source_dom(source_dom_node, target_dom_node):
     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
@@ -195,14 +193,20 @@ def _build_translated_dom(dom_node, target_node, target_dom_to_doc_dom):
     The mapping 'target_dom_to_doc_dom' is used to map nodes from 'target_node'
     to nodes which much be inserted into dom_node.
     """
+    if isinstance(dom_node, etree._ProcessingInstruction):
+        # If the DOM node is a processing instruction we can safely skip it,
+        # because we don't want to change it and it has no children.
+        return
+
     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.
+    # 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
+    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.
@@ -210,7 +214,21 @@ def _build_translated_dom(dom_node, target_node, target_dom_to_doc_dom):
         _build_translated_dom(dom_child, target_child, target_dom_to_doc_dom)
 
 
-def replace_dom_text(make_parse_state):
+def get_xliff_source_target_doms(unit):
+    """Return a tuple with unit source and target DOM objects.
+
+    This method is method is meant to provide a way to retrieve the DOM objects
+    for the unit source and target for XLIFF stores.
+    """
+    if unit.target_dom is not None:
+        return (unit.source_dom, unit.target_dom)
+
+    return (unit.source_dom, unit.source_dom)
+
+
+def replace_dom_text(make_parse_state,
+                     dom_retriever=get_xliff_source_target_doms,
+                     process_translatable=extract.process_translatable):
     """Return a function::
 
           action: etree_Element x base.TranslationUnit -> None
@@ -219,18 +237,18 @@ def replace_dom_text(make_parse_state):
       according to rearrangement of placeables in unit.target (relative to their
       positions in unit.source).
     """
-
     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
+        """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, target_dom = dom_retriever(unit)
+
         # 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]
+        unit_node = extract.find_translatable_dom_nodes(dom_node,
+                                                        make_parse_state(),
+                                                        process_translatable)[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[:] = []
diff --git a/translate/storage/xml_extract/misc.py b/translate/storage/xml_extract/misc.py
index bae5770..996483f 100644
--- a/translate/storage/xml_extract/misc.py
+++ b/translate/storage/xml_extract/misc.py
@@ -66,6 +66,7 @@ def compose_mappings(left, right):
             pass
     return result_map
 
+
 tag_pattern = re.compile('({(?P<namespace>(\w|[-:./])*)})?(?P<tag>(\w|[-])*)')
 
 
@@ -73,6 +74,8 @@ 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')
+    >>> parse_tag('document-content')
+    ('', 'document-content')
     """
     match = tag_pattern.match(full_tag)
     if match is not None:
diff --git a/translate/storage/xml_extract/unit_tree.py b/translate/storage/xml_extract/unit_tree.py
index f7b8ab7..90587d7 100644
--- a/translate/storage/xml_extract/unit_tree.py
+++ b/translate/storage/xml_extract/unit_tree.py
@@ -31,9 +31,8 @@ class XPathTree(object):
         self.children = {}
 
     def __eq__(self, other):
-        return isinstance(other, XPathTree) and \
-            self.unit == other.unit and \
-            self.children == other.children
+        return (isinstance(other, XPathTree) and self.unit == other.unit and
+                self.children == other.children)
 
 
 def _split_xpath_component(xpath_component):
@@ -95,7 +94,7 @@ def _add_unit_to_tree(node, xpath_components, unit):
         node.unit = unit
 
 
-def build_unit_tree(store):
+def build_unit_tree(store, filename=None):
     """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.
@@ -117,7 +116,14 @@ def build_unit_tree(store):
     """
     tree = XPathTree()
     for unit in store.units:
-        if not unit.isfuzzy():
-            location = _split_xpath(unit.getlocations()[0])
+        if unit.source and not unit.isfuzzy():
+            locations = unit.getlocations()
+            if (filename is not None and len(locations) > 1 and
+                filename != locations[1]):
+                # Skip units that don't come from the filename we are currently
+                # trying to get units for.
+                # This is not used for ODF, right now only for IDML.
+                continue
+            location = _split_xpath(locations[0])
             _add_unit_to_tree(tree, location, unit)
     return tree
diff --git a/translate/storage/xml_extract/xpath_breadcrumb.py b/translate/storage/xml_extract/xpath_breadcrumb.py
index 94a6765..607dbbe 100644
--- a/translate/storage/xml_extract/xpath_breadcrumb.py
+++ b/translate/storage/xml_extract/xpath_breadcrumb.py
@@ -17,7 +17,6 @@
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
-#
 
 
 class XPathBreadcrumb(object):
@@ -52,7 +51,6 @@ class XPathBreadcrumb(object):
     >>> xb.xpath
     foo[0]/bar[1]
     """
-
     def __init__(self):
         self._xpath = []
         self._tagtally = [{}]
@@ -68,11 +66,9 @@ class XPathBreadcrumb(object):
         self._xpath.pop()
         self._tagtally.pop()
 
-    def _get_xpath(self):
-
+    @property
+    def 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)
diff --git a/translate/storage/xml_name.py b/translate/storage/xml_name.py
index ac1030f..dd00155 100644
--- a/translate/storage/xml_name.py
+++ b/translate/storage/xml_name.py
@@ -64,7 +64,12 @@ class XmlNamer(object):
         # then namespace_shortcut contains a tag of the form
         # 'short-namespace:tag'
         if tag is None:
-            namespace_shortcut, tag = namespace_shortcut.split(':')
+            try:
+                namespace_shortcut, tag = namespace_shortcut.split(':')
+            except ValueError:
+                # If there is no namespace in namespace_shortcut.
+                tag = namespace_shortcut.lstrip("{}")
+                return tag
         return "{%s}%s" % (self.nsmap[namespace_shortcut], tag)
 
     def namespace(self, namespace_shortcut):
diff --git a/translate/convert/csv2tbx b/translate/tools/phppo2pypo
similarity index 67%
copy from translate/convert/csv2tbx
copy to translate/tools/phppo2pypo
index c50a3f3..f5d064d 100755
--- a/translate/convert/csv2tbx
+++ b/translate/tools/phppo2pypo
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 # 
-# Copyright 2006 Zuza Software Foundation
+# Copyright 2009 Mozilla Corporation, Zuza Software Foundation
 # 
 # This file is part of translate.
 #
@@ -17,10 +17,12 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
-"""simple script to convert a comma-separated values (.csv) file to a .tbx glossary file"""
+"""simple script to convert a PHP style .po file to a Python style .po file.  The manual 
+(http://www.gnu.org/software/gettext/manual/gettext.html) explains the differences, but it's mainly 
+substitution style. """
 
-from translate.convert import csv2tbx
+from translate.convert import phppo2pypo
 
 if __name__ == '__main__':
-  csv2tbx.main()
+    phppo2pypo.main()
 
diff --git a/translate/tools/pretranslate.py b/translate/tools/pretranslate.py
index 372eaff..cdf30aa 100644
--- a/translate/tools/pretranslate.py
+++ b/translate/tools/pretranslate.py
@@ -26,7 +26,7 @@ for examples and usage instructions.
 """
 
 from translate.search import match
-from translate.storage import factory, xliff
+from translate.storage import factory
 
 
 # We don't want to reinitialise the TM each time, so let's store it here.
@@ -138,8 +138,8 @@ def pretranslate_unit(input_unit, template_store, matchers=None,
             matching_unit = match_fuzzy(input_unit, matchers)
 
         if matching_unit and matching_unit.gettargetlen() > 0:
-            # FIXME: should we dispatch here instead of this crude type check
-            if isinstance(input_unit, xliff.xliffunit):
+            # FIXME: should we dispatch here instead of this crude attr check
+            if hasattr(input_unit, "addalttrans"):
                 # FIXME: what about origin, lang and matchquality
                 input_unit.addalttrans(matching_unit.target, origin="fish",
                                        sourcetxt=matching_unit.source)
diff --git a/translate/tools/porestructure b/translate/tools/pydiff
similarity index 82%
copy from translate/tools/porestructure
copy to translate/tools/pydiff
index 167280f..66a93ac 100755
--- a/translate/tools/porestructure
+++ b/translate/tools/pydiff
@@ -17,10 +17,11 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
-"""tool to restructure po files according to poconflicts directives"""
+"""diff tool like GNU diff, but lets you have special options that
+are useful in dealing with PO files"""
 
-from translate.tools import porestructure 
+from translate.tools import pydiff
 
 if __name__ == '__main__':
-    porestructure.main()
+  pydiff.main()
 
diff --git a/translate/convert/csv2tbx b/translate/tools/pypo2phppo
similarity index 67%
copy from translate/convert/csv2tbx
copy to translate/tools/pypo2phppo
index c50a3f3..a40cd8b 100755
--- a/translate/convert/csv2tbx
+++ b/translate/tools/pypo2phppo
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 # 
-# Copyright 2006 Zuza Software Foundation
+# Copyright 2009 Mozilla Corporation, Zuza Software Foundation
 # 
 # This file is part of translate.
 #
@@ -17,10 +17,12 @@
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
-"""simple script to convert a comma-separated values (.csv) file to a .tbx glossary file"""
+"""simple script to convert a PHP style .po file to a Python style .po file.  The manual 
+(http://www.gnu.org/software/gettext/manual/gettext.html) explains the differences, but it's mainly 
+substitution style. """
 
-from translate.convert import csv2tbx
+from translate.convert import pypo2phppo
 
 if __name__ == '__main__':
-  csv2tbx.main()
+    pypo2phppo.main()
 
diff --git a/translate_toolkit.egg-info/PKG-INFO b/translate_toolkit.egg-info/PKG-INFO
deleted file mode 100644
index 22d7624..0000000
--- a/translate_toolkit.egg-info/PKG-INFO
+++ /dev/null
@@ -1,46 +0,0 @@
-Metadata-Version: 1.0
-Name: translate-toolkit
-Version: 1.12.0
-Summary: Tools and API for translation and localization engineering.
-Home-page: http://toolkit.translatehouse.org/
-Author: Translate
-Author-email: translate-devel at lists.sourceforge.net
-License: GNU General Public License (GPL)
-Download-URL: http://sourceforge.net/projects/translate/files/Translate Toolkit/1.12.0
-Description: 
-        The `Translate Toolkit <http://toolkit.translatehouse.org/>`_ is created by
-        localizers for localizers. It contains several utilities, as well as an API for
-        building localization tools.
-        
-        Some of the **tools** include:
-        
-        - File format `converters
-          <http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/index.html#converters>`_
-        - `Quality checking
-          <http://docs.translatehouse.org/projects/translate-toolkit/en/latest/commands/index.html#quality-assurance>`_
-          tools
-        - Tools for counting, grepping, terminology extraction, and pseudo-localization
-        
-        Apart from the code for the tools above, some features of the **API** include:
-        
-        - Support for multiple `file formats
-          <http://docs.translatehouse.org/projects/translate-toolkit/en/latest/formats/index.html>`_
-        - Language information and language support code (including language detection)
-        - Code for translation memory, terminology matching and indexed search
-        - Several helper classes and functions for tools built on the Translate
-          Toolkit.
-        
-        
-Platform: any
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Environment :: Console
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: GNU General Public License (GPL)
-Classifier: Operating System :: OS Independent
-Classifier: Operating System :: Microsoft :: Windows
-Classifier: Operating System :: Unix
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: Topic :: Software Development :: Localization
diff --git a/translate_toolkit.egg-info/SOURCES.txt b/translate_toolkit.egg-info/SOURCES.txt
deleted file mode 100644
index a03aa09..0000000
--- a/translate_toolkit.egg-info/SOURCES.txt
+++ /dev/null
@@ -1,1150 +0,0 @@
-COPYING
-MANIFEST.in
-README.rst
-min-required.txt
-requirements.txt
-setup.py
-docs/Makefile
-docs/changelog.rst
-docs/conf.py
-docs/contents.rst.inc
-docs/features.rst
-docs/history.rst
-docs/index.rst
-docs/installation.rst
-docs/license.rst
-docs/make.bat
-docs/_build/doctrees/changelog.doctree
-docs/_build/doctrees/environment.pickle
-docs/_build/doctrees/features.doctree
-docs/_build/doctrees/history.doctree
-docs/_build/doctrees/index.doctree
-docs/_build/doctrees/installation.doctree
-docs/_build/doctrees/license.doctree
-docs/_build/doctrees/api/convert.doctree
-docs/_build/doctrees/api/filters.doctree
-docs/_build/doctrees/api/index.doctree
-docs/_build/doctrees/api/lang.doctree
-docs/_build/doctrees/api/misc.doctree
-docs/_build/doctrees/api/search.doctree
-docs/_build/doctrees/api/services.doctree
-docs/_build/doctrees/api/storage.doctree
-docs/_build/doctrees/api/tools.doctree
-docs/_build/doctrees/commands/csv2po.doctree
-docs/_build/doctrees/commands/csv2tbx.doctree
-docs/_build/doctrees/commands/general_usage.doctree
-docs/_build/doctrees/commands/html2po.doctree
-docs/_build/doctrees/commands/ical2po.doctree
-docs/_build/doctrees/commands/index.doctree
-docs/_build/doctrees/commands/ini2po.doctree
-docs/_build/doctrees/commands/json2po.doctree
-docs/_build/doctrees/commands/junitmsgfmt.doctree
-docs/_build/doctrees/commands/levenshtein_distance.doctree
-docs/_build/doctrees/commands/moz-l10n-builder.doctree
-docs/_build/doctrees/commands/moz2po.doctree
-docs/_build/doctrees/commands/mozilla_l10n_scripts.doctree
-docs/_build/doctrees/commands/odf2xliff.doctree
-docs/_build/doctrees/commands/oo2po.doctree
-docs/_build/doctrees/commands/option_accelerator.doctree
-docs/_build/doctrees/commands/option_duplicates.doctree
-docs/_build/doctrees/commands/option_errorlevel.doctree
-docs/_build/doctrees/commands/option_filteraction.doctree
-docs/_build/doctrees/commands/option_multifile.doctree
-docs/_build/doctrees/commands/option_personality.doctree
-docs/_build/doctrees/commands/option_progress.doctree
-docs/_build/doctrees/commands/option_rewrite.doctree
-docs/_build/doctrees/commands/phase.doctree
-docs/_build/doctrees/commands/php2po.doctree
-docs/_build/doctrees/commands/po2tmx.doctree
-docs/_build/doctrees/commands/po2wordfast.doctree
-docs/_build/doctrees/commands/poclean.doctree
-docs/_build/doctrees/commands/pocommentclean.doctree
-docs/_build/doctrees/commands/pocompendium.doctree
-docs/_build/doctrees/commands/pocompile.doctree
-docs/_build/doctrees/commands/poconflicts.doctree
-docs/_build/doctrees/commands/pocount.doctree
-docs/_build/doctrees/commands/podebug.doctree
-docs/_build/doctrees/commands/pofilter.doctree
-docs/_build/doctrees/commands/pofilter_tests.doctree
-docs/_build/doctrees/commands/pogrep.doctree
-docs/_build/doctrees/commands/pomerge.doctree
-docs/_build/doctrees/commands/pomigrate2.doctree
-docs/_build/doctrees/commands/popuretext.doctree
-docs/_build/doctrees/commands/poreencode.doctree
-docs/_build/doctrees/commands/porestructure.doctree
-docs/_build/doctrees/commands/posegment.doctree
-docs/_build/doctrees/commands/posplit.doctree
-docs/_build/doctrees/commands/poswap.doctree
-docs/_build/doctrees/commands/pot2po.doctree
-docs/_build/doctrees/commands/poterminology.doctree
-docs/_build/doctrees/commands/poterminology_stopword_file.doctree
-docs/_build/doctrees/commands/pretranslate.doctree
-docs/_build/doctrees/commands/prop2po.doctree
-docs/_build/doctrees/commands/rc2po.doctree
-docs/_build/doctrees/commands/sub2po.doctree
-docs/_build/doctrees/commands/symb2po.doctree
-docs/_build/doctrees/commands/tiki2po.doctree
-docs/_build/doctrees/commands/tmserver.doctree
-docs/_build/doctrees/commands/ts2po.doctree
-docs/_build/doctrees/commands/txt2po.doctree
-docs/_build/doctrees/commands/web2py2po.doctree
-docs/_build/doctrees/commands/xliff2po.doctree
-docs/_build/doctrees/developers/building.doctree
-docs/_build/doctrees/developers/contributing.doctree
-docs/_build/doctrees/developers/deprecation.doctree
-docs/_build/doctrees/developers/developers.doctree
-docs/_build/doctrees/developers/releasing.doctree
-docs/_build/doctrees/developers/styleguide.doctree
-docs/_build/doctrees/developers/testing.doctree
-docs/_build/doctrees/formats/android.doctree
-docs/_build/doctrees/formats/base_classes.doctree
-docs/_build/doctrees/formats/catkeys.doctree
-docs/_build/doctrees/formats/conformance.doctree
-docs/_build/doctrees/formats/csv.doctree
-docs/_build/doctrees/formats/dtd.doctree
-docs/_build/doctrees/formats/flex.doctree
-docs/_build/doctrees/formats/gsi.doctree
-docs/_build/doctrees/formats/html.doctree
-docs/_build/doctrees/formats/ical.doctree
-docs/_build/doctrees/formats/index.doctree
-docs/_build/doctrees/formats/ini.doctree
-docs/_build/doctrees/formats/json.doctree
-docs/_build/doctrees/formats/l20n.doctree
-docs/_build/doctrees/formats/mo.doctree
-docs/_build/doctrees/formats/odf.doctree
-docs/_build/doctrees/formats/omegat_glossary.doctree
-docs/_build/doctrees/formats/php.doctree
-docs/_build/doctrees/formats/po.doctree
-docs/_build/doctrees/formats/properties.doctree
-docs/_build/doctrees/formats/qm.doctree
-docs/_build/doctrees/formats/qt_phrase_book.doctree
-docs/_build/doctrees/formats/quoting_and_escaping.doctree
-docs/_build/doctrees/formats/rc.doctree
-docs/_build/doctrees/formats/strings.doctree
-docs/_build/doctrees/formats/subtitles.doctree
-docs/_build/doctrees/formats/tbx.doctree
-docs/_build/doctrees/formats/text.doctree
-docs/_build/doctrees/formats/tmx.doctree
-docs/_build/doctrees/formats/ts.doctree
-docs/_build/doctrees/formats/utx.doctree
-docs/_build/doctrees/formats/wiki.doctree
-docs/_build/doctrees/formats/wml.doctree
-docs/_build/doctrees/formats/wordfast.doctree
-docs/_build/doctrees/formats/xliff.doctree
-docs/_build/doctrees/guides/checking_for_inconsistencies.doctree
-docs/_build/doctrees/guides/cleanup_translator_comments.doctree
-docs/_build/doctrees/guides/creating_a_terminology_list_from_your_existing_translations.doctree
-docs/_build/doctrees/guides/creating_mozilla_pot_files.doctree
-docs/_build/doctrees/guides/document_translation.doctree
-docs/_build/doctrees/guides/index.doctree
-docs/_build/doctrees/guides/migrating_translations.doctree
-docs/_build/doctrees/guides/running_the_tools_on_microsoft_windows.doctree
-docs/_build/doctrees/guides/using_csv2po.doctree
-docs/_build/doctrees/guides/using_oo2po.doctree
-docs/_build/doctrees/guides/using_pofilter.doctree
-docs/_build/doctrees/releases/1.10.0.doctree
-docs/_build/doctrees/releases/1.11.0-rc1.doctree
-docs/_build/doctrees/releases/1.11.0.doctree
-docs/_build/doctrees/releases/1.12.0-rc1.doctree
-docs/_build/doctrees/releases/1.12.0.doctree
-docs/_build/doctrees/releases/1.8.1.doctree
-docs/_build/doctrees/releases/1.9.0.doctree
-docs/_build/doctrees/releases/dev.doctree
-docs/_build/doctrees/releases/index.doctree
-docs/_build/html/.buildinfo
-docs/_build/html/changelog.html
-docs/_build/html/features.html
-docs/_build/html/genindex.html
-docs/_build/html/history.html
-docs/_build/html/index.html
-docs/_build/html/installation.html
-docs/_build/html/license.html
-docs/_build/html/objects.inv
-docs/_build/html/py-modindex.html
-docs/_build/html/search.html
-docs/_build/html/searchindex.js
-docs/_build/html/_sources/changelog.txt
-docs/_build/html/_sources/features.txt
-docs/_build/html/_sources/history.txt
-docs/_build/html/_sources/index.txt
-docs/_build/html/_sources/installation.txt
-docs/_build/html/_sources/license.txt
-docs/_build/html/_sources/api/convert.txt
-docs/_build/html/_sources/api/filters.txt
-docs/_build/html/_sources/api/index.txt
-docs/_build/html/_sources/api/lang.txt
-docs/_build/html/_sources/api/misc.txt
-docs/_build/html/_sources/api/search.txt
-docs/_build/html/_sources/api/services.txt
-docs/_build/html/_sources/api/storage.txt
-docs/_build/html/_sources/api/tools.txt
-docs/_build/html/_sources/commands/csv2po.txt
-docs/_build/html/_sources/commands/csv2tbx.txt
-docs/_build/html/_sources/commands/general_usage.txt
-docs/_build/html/_sources/commands/html2po.txt
-docs/_build/html/_sources/commands/ical2po.txt
-docs/_build/html/_sources/commands/index.txt
-docs/_build/html/_sources/commands/ini2po.txt
-docs/_build/html/_sources/commands/json2po.txt
-docs/_build/html/_sources/commands/junitmsgfmt.txt
-docs/_build/html/_sources/commands/levenshtein_distance.txt
-docs/_build/html/_sources/commands/moz-l10n-builder.txt
-docs/_build/html/_sources/commands/moz2po.txt
-docs/_build/html/_sources/commands/mozilla_l10n_scripts.txt
-docs/_build/html/_sources/commands/odf2xliff.txt
-docs/_build/html/_sources/commands/oo2po.txt
-docs/_build/html/_sources/commands/option_accelerator.txt
-docs/_build/html/_sources/commands/option_duplicates.txt
-docs/_build/html/_sources/commands/option_errorlevel.txt
-docs/_build/html/_sources/commands/option_filteraction.txt
-docs/_build/html/_sources/commands/option_multifile.txt
-docs/_build/html/_sources/commands/option_personality.txt
-docs/_build/html/_sources/commands/option_progress.txt
-docs/_build/html/_sources/commands/option_rewrite.txt
-docs/_build/html/_sources/commands/phase.txt
-docs/_build/html/_sources/commands/php2po.txt
-docs/_build/html/_sources/commands/po2tmx.txt
-docs/_build/html/_sources/commands/po2wordfast.txt
-docs/_build/html/_sources/commands/poclean.txt
-docs/_build/html/_sources/commands/pocommentclean.txt
-docs/_build/html/_sources/commands/pocompendium.txt
-docs/_build/html/_sources/commands/pocompile.txt
-docs/_build/html/_sources/commands/poconflicts.txt
-docs/_build/html/_sources/commands/pocount.txt
-docs/_build/html/_sources/commands/podebug.txt
-docs/_build/html/_sources/commands/pofilter.txt
-docs/_build/html/_sources/commands/pofilter_tests.txt
-docs/_build/html/_sources/commands/pogrep.txt
-docs/_build/html/_sources/commands/pomerge.txt
-docs/_build/html/_sources/commands/pomigrate2.txt
-docs/_build/html/_sources/commands/popuretext.txt
-docs/_build/html/_sources/commands/poreencode.txt
-docs/_build/html/_sources/commands/porestructure.txt
-docs/_build/html/_sources/commands/posegment.txt
-docs/_build/html/_sources/commands/posplit.txt
-docs/_build/html/_sources/commands/poswap.txt
-docs/_build/html/_sources/commands/pot2po.txt
-docs/_build/html/_sources/commands/poterminology.txt
-docs/_build/html/_sources/commands/poterminology_stopword_file.txt
-docs/_build/html/_sources/commands/pretranslate.txt
-docs/_build/html/_sources/commands/prop2po.txt
-docs/_build/html/_sources/commands/rc2po.txt
-docs/_build/html/_sources/commands/sub2po.txt
-docs/_build/html/_sources/commands/symb2po.txt
-docs/_build/html/_sources/commands/tiki2po.txt
-docs/_build/html/_sources/commands/tmserver.txt
-docs/_build/html/_sources/commands/ts2po.txt
-docs/_build/html/_sources/commands/txt2po.txt
-docs/_build/html/_sources/commands/web2py2po.txt
-docs/_build/html/_sources/commands/xliff2po.txt
-docs/_build/html/_sources/developers/building.txt
-docs/_build/html/_sources/developers/contributing.txt
-docs/_build/html/_sources/developers/deprecation.txt
-docs/_build/html/_sources/developers/developers.txt
-docs/_build/html/_sources/developers/releasing.txt
-docs/_build/html/_sources/developers/styleguide.txt
-docs/_build/html/_sources/developers/testing.txt
-docs/_build/html/_sources/formats/android.txt
-docs/_build/html/_sources/formats/base_classes.txt
-docs/_build/html/_sources/formats/catkeys.txt
-docs/_build/html/_sources/formats/conformance.txt
-docs/_build/html/_sources/formats/csv.txt
-docs/_build/html/_sources/formats/dtd.txt
-docs/_build/html/_sources/formats/flex.txt
-docs/_build/html/_sources/formats/gsi.txt
-docs/_build/html/_sources/formats/html.txt
-docs/_build/html/_sources/formats/ical.txt
-docs/_build/html/_sources/formats/index.txt
-docs/_build/html/_sources/formats/ini.txt
-docs/_build/html/_sources/formats/json.txt
-docs/_build/html/_sources/formats/l20n.txt
-docs/_build/html/_sources/formats/mo.txt
-docs/_build/html/_sources/formats/odf.txt
-docs/_build/html/_sources/formats/omegat_glossary.txt
-docs/_build/html/_sources/formats/php.txt
-docs/_build/html/_sources/formats/po.txt
-docs/_build/html/_sources/formats/properties.txt
-docs/_build/html/_sources/formats/qm.txt
-docs/_build/html/_sources/formats/qt_phrase_book.txt
-docs/_build/html/_sources/formats/quoting_and_escaping.txt
-docs/_build/html/_sources/formats/rc.txt
-docs/_build/html/_sources/formats/strings.txt
-docs/_build/html/_sources/formats/subtitles.txt
-docs/_build/html/_sources/formats/tbx.txt
-docs/_build/html/_sources/formats/text.txt
-docs/_build/html/_sources/formats/tmx.txt
-docs/_build/html/_sources/formats/ts.txt
-docs/_build/html/_sources/formats/utx.txt
-docs/_build/html/_sources/formats/wiki.txt
-docs/_build/html/_sources/formats/wml.txt
-docs/_build/html/_sources/formats/wordfast.txt
-docs/_build/html/_sources/formats/xliff.txt
-docs/_build/html/_sources/guides/checking_for_inconsistencies.txt
-docs/_build/html/_sources/guides/cleanup_translator_comments.txt
-docs/_build/html/_sources/guides/creating_a_terminology_list_from_your_existing_translations.txt
-docs/_build/html/_sources/guides/creating_mozilla_pot_files.txt
-docs/_build/html/_sources/guides/document_translation.txt
-docs/_build/html/_sources/guides/index.txt
-docs/_build/html/_sources/guides/migrating_translations.txt
-docs/_build/html/_sources/guides/running_the_tools_on_microsoft_windows.txt
-docs/_build/html/_sources/guides/using_csv2po.txt
-docs/_build/html/_sources/guides/using_oo2po.txt
-docs/_build/html/_sources/guides/using_pofilter.txt
-docs/_build/html/_sources/releases/1.10.0.txt
-docs/_build/html/_sources/releases/1.11.0-rc1.txt
-docs/_build/html/_sources/releases/1.11.0.txt
-docs/_build/html/_sources/releases/1.12.0-rc1.txt
-docs/_build/html/_sources/releases/1.12.0.txt
-docs/_build/html/_sources/releases/1.8.1.txt
-docs/_build/html/_sources/releases/1.9.0.txt
-docs/_build/html/_sources/releases/dev.txt
-docs/_build/html/_sources/releases/index.txt
-docs/_build/html/_static/README.txt
-docs/_build/html/_static/ajax-loader.gif
-docs/_build/html/_static/basic.css
-docs/_build/html/_static/bootstrap-responsive.css
-docs/_build/html/_static/bootstrap-sphinx.css
-docs/_build/html/_static/bootstrap-sphinx.js
-docs/_build/html/_static/bootstrap.css
-docs/_build/html/_static/bootstrap.js
-docs/_build/html/_static/comment-bright.png
-docs/_build/html/_static/comment-close.png
-docs/_build/html/_static/comment.png
-docs/_build/html/_static/doctools.js
-docs/_build/html/_static/down-pressed.png
-docs/_build/html/_static/down.png
-docs/_build/html/_static/file.png
-docs/_build/html/_static/jquery.js
-docs/_build/html/_static/minus.png
-docs/_build/html/_static/plus.png
-docs/_build/html/_static/pygments.css
-docs/_build/html/_static/searchtools.js
-docs/_build/html/_static/underscore.js
-docs/_build/html/_static/up-pressed.png
-docs/_build/html/_static/up.png
-docs/_build/html/_static/websupport.js
-docs/_build/html/_static/font/fontawesome-webfont.eot
-docs/_build/html/_static/font/fontawesome-webfont.svg
-docs/_build/html/_static/font/fontawesome-webfont.ttf
-docs/_build/html/_static/font/fontawesome-webfont.woff
-docs/_build/html/_static/less/font-awesome.less
-docs/_build/html/_static/less/theme.less
-docs/_build/html/_static/less/variables.less
-docs/_build/html/api/convert.html
-docs/_build/html/api/filters.html
-docs/_build/html/api/index.html
-docs/_build/html/api/lang.html
-docs/_build/html/api/misc.html
-docs/_build/html/api/search.html
-docs/_build/html/api/services.html
-docs/_build/html/api/storage.html
-docs/_build/html/api/tools.html
-docs/_build/html/commands/csv2po.html
-docs/_build/html/commands/csv2tbx.html
-docs/_build/html/commands/general_usage.html
-docs/_build/html/commands/html2po.html
-docs/_build/html/commands/ical2po.html
-docs/_build/html/commands/index.html
-docs/_build/html/commands/ini2po.html
-docs/_build/html/commands/json2po.html
-docs/_build/html/commands/junitmsgfmt.html
-docs/_build/html/commands/levenshtein_distance.html
-docs/_build/html/commands/moz-l10n-builder.html
-docs/_build/html/commands/moz2po.html
-docs/_build/html/commands/mozilla_l10n_scripts.html
-docs/_build/html/commands/odf2xliff.html
-docs/_build/html/commands/oo2po.html
-docs/_build/html/commands/option_accelerator.html
-docs/_build/html/commands/option_duplicates.html
-docs/_build/html/commands/option_errorlevel.html
-docs/_build/html/commands/option_filteraction.html
-docs/_build/html/commands/option_multifile.html
-docs/_build/html/commands/option_personality.html
-docs/_build/html/commands/option_progress.html
-docs/_build/html/commands/option_rewrite.html
-docs/_build/html/commands/phase.html
-docs/_build/html/commands/php2po.html
-docs/_build/html/commands/po2tmx.html
-docs/_build/html/commands/po2wordfast.html
-docs/_build/html/commands/poclean.html
-docs/_build/html/commands/pocommentclean.html
-docs/_build/html/commands/pocompendium.html
-docs/_build/html/commands/pocompile.html
-docs/_build/html/commands/poconflicts.html
-docs/_build/html/commands/pocount.html
-docs/_build/html/commands/podebug.html
-docs/_build/html/commands/pofilter.html
-docs/_build/html/commands/pofilter_tests.html
-docs/_build/html/commands/pogrep.html
-docs/_build/html/commands/pomerge.html
-docs/_build/html/commands/pomigrate2.html
-docs/_build/html/commands/popuretext.html
-docs/_build/html/commands/poreencode.html
-docs/_build/html/commands/porestructure.html
-docs/_build/html/commands/posegment.html
-docs/_build/html/commands/posplit.html
-docs/_build/html/commands/poswap.html
-docs/_build/html/commands/pot2po.html
-docs/_build/html/commands/poterminology.html
-docs/_build/html/commands/poterminology_stopword_file.html
-docs/_build/html/commands/pretranslate.html
-docs/_build/html/commands/prop2po.html
-docs/_build/html/commands/rc2po.html
-docs/_build/html/commands/sub2po.html
-docs/_build/html/commands/symb2po.html
-docs/_build/html/commands/tiki2po.html
-docs/_build/html/commands/tmserver.html
-docs/_build/html/commands/ts2po.html
-docs/_build/html/commands/txt2po.html
-docs/_build/html/commands/web2py2po.html
-docs/_build/html/commands/xliff2po.html
-docs/_build/html/developers/building.html
-docs/_build/html/developers/contributing.html
-docs/_build/html/developers/deprecation.html
-docs/_build/html/developers/developers.html
-docs/_build/html/developers/releasing.html
-docs/_build/html/developers/styleguide.html
-docs/_build/html/developers/testing.html
-docs/_build/html/formats/android.html
-docs/_build/html/formats/base_classes.html
-docs/_build/html/formats/catkeys.html
-docs/_build/html/formats/conformance.html
-docs/_build/html/formats/csv.html
-docs/_build/html/formats/dtd.html
-docs/_build/html/formats/flex.html
-docs/_build/html/formats/gsi.html
-docs/_build/html/formats/html.html
-docs/_build/html/formats/ical.html
-docs/_build/html/formats/index.html
-docs/_build/html/formats/ini.html
-docs/_build/html/formats/json.html
-docs/_build/html/formats/l20n.html
-docs/_build/html/formats/mo.html
-docs/_build/html/formats/odf.html
-docs/_build/html/formats/omegat_glossary.html
-docs/_build/html/formats/php.html
-docs/_build/html/formats/po.html
-docs/_build/html/formats/properties.html
-docs/_build/html/formats/qm.html
-docs/_build/html/formats/qt_phrase_book.html
-docs/_build/html/formats/quoting_and_escaping.html
-docs/_build/html/formats/rc.html
-docs/_build/html/formats/strings.html
-docs/_build/html/formats/subtitles.html
-docs/_build/html/formats/tbx.html
-docs/_build/html/formats/text.html
-docs/_build/html/formats/tmx.html
-docs/_build/html/formats/ts.html
-docs/_build/html/formats/utx.html
-docs/_build/html/formats/wiki.html
-docs/_build/html/formats/wml.html
-docs/_build/html/formats/wordfast.html
-docs/_build/html/formats/xliff.html
-docs/_build/html/guides/checking_for_inconsistencies.html
-docs/_build/html/guides/cleanup_translator_comments.html
-docs/_build/html/guides/creating_a_terminology_list_from_your_existing_translations.html
-docs/_build/html/guides/creating_mozilla_pot_files.html
-docs/_build/html/guides/document_translation.html
-docs/_build/html/guides/index.html
-docs/_build/html/guides/migrating_translations.html
-docs/_build/html/guides/running_the_tools_on_microsoft_windows.html
-docs/_build/html/guides/using_csv2po.html
-docs/_build/html/guides/using_oo2po.html
-docs/_build/html/guides/using_pofilter.html
-docs/_build/html/releases/1.10.0.html
-docs/_build/html/releases/1.11.0-rc1.html
-docs/_build/html/releases/1.11.0.html
-docs/_build/html/releases/1.12.0-rc1.html
-docs/_build/html/releases/1.12.0.html
-docs/_build/html/releases/1.8.1.html
-docs/_build/html/releases/1.9.0.html
-docs/_build/html/releases/dev.html
-docs/_build/html/releases/index.html
-docs/_ext/translate_docs.py
-docs/_ext/translate_docs.pyc
-docs/_static/README.txt
-docs/_themes/.git
-docs/_themes/.gitignore
-docs/_themes/README.rst
-docs/_themes/sphinx-bootstrap/globaltoc.html
-docs/_themes/sphinx-bootstrap/layout.html
-docs/_themes/sphinx-bootstrap/localtoc.html
-docs/_themes/sphinx-bootstrap/relations.html
-docs/_themes/sphinx-bootstrap/search.html
-docs/_themes/sphinx-bootstrap/searchbox.html
-docs/_themes/sphinx-bootstrap/sourcelink.html
-docs/_themes/sphinx-bootstrap/theme.conf
-docs/_themes/sphinx-bootstrap/static/bootstrap-responsive.css
-docs/_themes/sphinx-bootstrap/static/bootstrap-sphinx.css_t
-docs/_themes/sphinx-bootstrap/static/bootstrap-sphinx.js
-docs/_themes/sphinx-bootstrap/static/bootstrap.css
-docs/_themes/sphinx-bootstrap/static/bootstrap.js
-docs/_themes/sphinx-bootstrap/static/jquery.js
-docs/_themes/sphinx-bootstrap/static/font/fontawesome-webfont.eot
-docs/_themes/sphinx-bootstrap/static/font/fontawesome-webfont.svg
-docs/_themes/sphinx-bootstrap/static/font/fontawesome-webfont.ttf
-docs/_themes/sphinx-bootstrap/static/font/fontawesome-webfont.woff
-docs/_themes/sphinx-bootstrap/static/less/font-awesome.less
-docs/_themes/sphinx-bootstrap/static/less/theme.less
-docs/_themes/sphinx-bootstrap/static/less/variables.less
-docs/api/convert.rst
-docs/api/filters.rst
-docs/api/index.rst
-docs/api/lang.rst
-docs/api/misc.rst
-docs/api/search.rst
-docs/api/services.rst
-docs/api/storage.rst
-docs/api/tools.rst
-docs/commands/csv2po.rst
-docs/commands/csv2tbx.rst
-docs/commands/general_usage.rst
-docs/commands/html2po.rst
-docs/commands/ical2po.rst
-docs/commands/index.rst
-docs/commands/ini2po.rst
-docs/commands/json2po.rst
-docs/commands/junitmsgfmt.rst
-docs/commands/levenshtein_distance.rst
-docs/commands/moz-l10n-builder.rst
-docs/commands/moz2po.rst
-docs/commands/mozilla_l10n_scripts.rst
-docs/commands/odf2xliff.rst
-docs/commands/oo2po.rst
-docs/commands/option_accelerator.rst
-docs/commands/option_duplicates.rst
-docs/commands/option_errorlevel.rst
-docs/commands/option_filteraction.rst
-docs/commands/option_multifile.rst
-docs/commands/option_personality.rst
-docs/commands/option_progress.rst
-docs/commands/option_rewrite.rst
-docs/commands/phase.rst
-docs/commands/php2po.rst
-docs/commands/po2tmx.rst
-docs/commands/po2wordfast.rst
-docs/commands/poclean.rst
-docs/commands/pocommentclean.rst
-docs/commands/pocompendium.rst
-docs/commands/pocompile.rst
-docs/commands/poconflicts.rst
-docs/commands/pocount.rst
-docs/commands/podebug.rst
-docs/commands/pofilter.rst
-docs/commands/pofilter_tests.rst
-docs/commands/pogrep.rst
-docs/commands/pomerge.rst
-docs/commands/pomigrate2.rst
-docs/commands/popuretext.rst
-docs/commands/poreencode.rst
-docs/commands/porestructure.rst
-docs/commands/posegment.rst
-docs/commands/posplit.rst
-docs/commands/poswap.rst
-docs/commands/pot2po.rst
-docs/commands/poterminology.rst
-docs/commands/poterminology_stopword_file.rst
-docs/commands/pretranslate.rst
-docs/commands/prop2po.rst
-docs/commands/rc2po.rst
-docs/commands/sub2po.rst
-docs/commands/symb2po.rst
-docs/commands/tiki2po.rst
-docs/commands/tmserver.rst
-docs/commands/ts2po.rst
-docs/commands/txt2po.rst
-docs/commands/web2py2po.rst
-docs/commands/xliff2po.rst
-docs/developers/building.rst
-docs/developers/contributing.rst
-docs/developers/deprecation.rst
-docs/developers/developers.rst
-docs/developers/releasing.rst
-docs/developers/styleguide.rst
-docs/developers/testing.rst
-docs/formats/android.rst
-docs/formats/base_classes.rst
-docs/formats/catkeys.rst
-docs/formats/conformance.rst
-docs/formats/csv.rst
-docs/formats/dtd.rst
-docs/formats/flex.rst
-docs/formats/gsi.rst
-docs/formats/html.rst
-docs/formats/ical.rst
-docs/formats/index.rst
-docs/formats/ini.rst
-docs/formats/json.rst
-docs/formats/l20n.rst
-docs/formats/mo.rst
-docs/formats/odf.rst
-docs/formats/omegat_glossary.rst
-docs/formats/php.rst
-docs/formats/po.rst
-docs/formats/properties.rst
-docs/formats/qm.rst
-docs/formats/qt_phrase_book.rst
-docs/formats/quoting_and_escaping.rst
-docs/formats/rc.rst
-docs/formats/strings.rst
-docs/formats/subtitles.rst
-docs/formats/tbx.rst
-docs/formats/text.rst
-docs/formats/tmx.rst
-docs/formats/ts.rst
-docs/formats/utx.rst
-docs/formats/wiki.rst
-docs/formats/wml.rst
-docs/formats/wordfast.rst
-docs/formats/xliff.rst
-docs/guides/checking_for_inconsistencies.rst
-docs/guides/cleanup_translator_comments.rst
-docs/guides/creating_a_terminology_list_from_your_existing_translations.rst
-docs/guides/creating_mozilla_pot_files.rst
-docs/guides/document_translation.rst
-docs/guides/index.rst
-docs/guides/migrating_translations.rst
-docs/guides/running_the_tools_on_microsoft_windows.rst
-docs/guides/using_csv2po.rst
-docs/guides/using_oo2po.rst
-docs/guides/using_pofilter.rst
-docs/releases/1.10.0.rst
-docs/releases/1.11.0-rc1.rst
-docs/releases/1.11.0.rst
-docs/releases/1.12.0-rc1.rst
-docs/releases/1.12.0.rst
-docs/releases/1.8.1.rst
-docs/releases/1.9.0.rst
-docs/releases/README.rst
-docs/releases/dev.rst
-docs/releases/index.rst
-requirements/dev.txt
-requirements/optional.txt
-requirements/recommended.txt
-requirements/required.txt
-share/stoplist-en
-share/langmodels/Ndebele.lm
-share/langmodels/NorthernSotho.lm
-share/langmodels/README
-share/langmodels/Sotho.lm
-share/langmodels/Swati.lm
-share/langmodels/Tsonga.lm
-share/langmodels/Tswana.lm
-share/langmodels/Venda.lm
-share/langmodels/Xhosa.lm
-share/langmodels/Zulu.lm
-share/langmodels/afrikaans.lm
-share/langmodels/albanian.lm
-share/langmodels/arabic.lm
-share/langmodels/basque.lm
-share/langmodels/belarus.lm
-share/langmodels/bosnian.lm
-share/langmodels/breton.lm
-share/langmodels/catalan.lm
-share/langmodels/chinese_simplified.lm
-share/langmodels/chinese_traditional.lm
-share/langmodels/croatian.lm
-share/langmodels/czech.lm
-share/langmodels/danish.lm
-share/langmodels/dutch.lm
-share/langmodels/english.lm
-share/langmodels/esperanto.lm
-share/langmodels/estonian.lm
-share/langmodels/finnish.lm
-share/langmodels/fpdb.conf
-share/langmodels/french.lm
-share/langmodels/frisian.lm
-share/langmodels/german.lm
-share/langmodels/greek.lm
-share/langmodels/hebrew.lm
-share/langmodels/hungarian.lm
-share/langmodels/icelandic.lm
-share/langmodels/indonesian.lm
-share/langmodels/irish_gaelic.lm
-share/langmodels/italian.lm
-share/langmodels/japanese.lm
-share/langmodels/latin.lm
-share/langmodels/latvian.lm
-share/langmodels/lithuanian.lm
-share/langmodels/malay.lm
-share/langmodels/manx_gaelic.lm
-share/langmodels/norwegian.lm
-share/langmodels/polish.lm
-share/langmodels/portuguese.lm
-share/langmodels/quechua.lm
-share/langmodels/romanian.lm
-share/langmodels/romansh.lm
-share/langmodels/russian.lm
-share/langmodels/scots.lm
-share/langmodels/scots_gaelic.lm
-share/langmodels/serbian_ascii.lm
-share/langmodels/slovak_ascii.lm
-share/langmodels/slovenian.lm
-share/langmodels/spanish.lm
-share/langmodels/swahili.lm
-share/langmodels/swedish.lm
-share/langmodels/tagalog.lm
-share/langmodels/turkish.lm
-share/langmodels/ukrainian.lm
-share/langmodels/vietnamese.lm
-share/langmodels/welsh.lm
-tests/cli/data/test_pocount/stderr.txt
-tests/cli/data/test_pocount_help/stdout.txt
-tests/cli/data/test_pocount_mutually_exclusive/stderr.txt
-tests/cli/data/test_pocount_nonexistant/stderr.txt
-tests/cli/data/test_pocount_po_file/stdout.txt
-tests/cli/data/test_pofilter_listfilters/stdout.txt
-tests/cli/data/test_pofilter_manpage/stdout.txt
-tests/cli/data/test_prop2po/stderr.txt
-tests/cli/data/test_prop2po_dirs/stderr.txt
-tools/junitmsgfmt
-tools/pocommentclean
-tools/pocompendium
-tools/pomigrate2
-tools/popuretext
-tools/poreencode
-tools/posplit
-tools/mozilla/build_firefox.sh
-tools/mozilla/buildxpi.py
-tools/mozilla/get_moz_enUS.py
-translate/__init__.py
-translate/__version__.py
-translate/convert/__init__.py
-translate/convert/accesskey.py
-translate/convert/convert.py
-translate/convert/csv2po
-translate/convert/csv2po.py
-translate/convert/csv2tbx
-translate/convert/csv2tbx.py
-translate/convert/dtd2po.py
-translate/convert/factory.py
-translate/convert/html2po
-translate/convert/html2po.py
-translate/convert/ical2po
-translate/convert/ical2po.py
-translate/convert/ini2po
-translate/convert/ini2po.py
-translate/convert/json2po
-translate/convert/json2po.py
-translate/convert/moz2po
-translate/convert/moz2po.py
-translate/convert/mozfunny2prop.py
-translate/convert/mozlang2po.py
-translate/convert/odf2xliff
-translate/convert/odf2xliff.py
-translate/convert/oo2po
-translate/convert/oo2po.py
-translate/convert/oo2xliff
-translate/convert/oo2xliff.py
-translate/convert/php2po
-translate/convert/php2po.py
-translate/convert/po2csv
-translate/convert/po2csv.py
-translate/convert/po2dtd.py
-translate/convert/po2html
-translate/convert/po2html.py
-translate/convert/po2ical
-translate/convert/po2ical.py
-translate/convert/po2ini
-translate/convert/po2ini.py
-translate/convert/po2json
-translate/convert/po2json.py
-translate/convert/po2moz
-translate/convert/po2moz.py
-translate/convert/po2mozlang.py
-translate/convert/po2oo
-translate/convert/po2oo.py
-translate/convert/po2php
-translate/convert/po2php.py
-translate/convert/po2prop
-translate/convert/po2prop.py
-translate/convert/po2rc
-translate/convert/po2rc.py
-translate/convert/po2sub
-translate/convert/po2sub.py
-translate/convert/po2symb
-translate/convert/po2symb.py
-translate/convert/po2tiki
-translate/convert/po2tiki.py
-translate/convert/po2tmx
-translate/convert/po2tmx.py
-translate/convert/po2ts
-translate/convert/po2ts.py
-translate/convert/po2txt
-translate/convert/po2txt.py
-translate/convert/po2web2py
-translate/convert/po2web2py.py
-translate/convert/po2wordfast
-translate/convert/po2wordfast.py
-translate/convert/po2xliff
-translate/convert/po2xliff.py
-translate/convert/poreplace.py
-translate/convert/pot2po
-translate/convert/pot2po.py
-translate/convert/prop2mozfunny.py
-translate/convert/prop2po
-translate/convert/prop2po.py
-translate/convert/rc2po
-translate/convert/rc2po.py
-translate/convert/sub2po
-translate/convert/sub2po.py
-translate/convert/symb2po
-translate/convert/symb2po.py
-translate/convert/test_accesskey.py
-translate/convert/test_convert.py
-translate/convert/test_csv2po.py
-translate/convert/test_dtd2po.py
-translate/convert/test_html2po.py
-translate/convert/test_json2po.py
-translate/convert/test_moz2po.py
-translate/convert/test_mozfunny2prop.py
-translate/convert/test_mozlang2po.py
-translate/convert/test_oo2po.py
-translate/convert/test_oo2xliff.py
-translate/convert/test_php2po.py
-translate/convert/test_po2csv.py
-translate/convert/test_po2dtd.py
-translate/convert/test_po2html.py
-translate/convert/test_po2ical.py
-translate/convert/test_po2ini.py
-translate/convert/test_po2moz.py
-translate/convert/test_po2mozlang.py
-translate/convert/test_po2oo.py
-translate/convert/test_po2php.py
-translate/convert/test_po2prop.py
-translate/convert/test_po2sub.py
-translate/convert/test_po2tiki.py
-translate/convert/test_po2tmx.py
-translate/convert/test_po2ts.py
-translate/convert/test_po2txt.py
-translate/convert/test_po2xliff.py
-translate/convert/test_pot2po.py
-translate/convert/test_prop2mozfunny.py
-translate/convert/test_prop2po.py
-translate/convert/test_tiki2po.py
-translate/convert/test_ts2po.py
-translate/convert/test_txt2po.py
-translate/convert/test_xliff2po.py
-translate/convert/tiki2po
-translate/convert/tiki2po.py
-translate/convert/ts2po
-translate/convert/ts2po.py
-translate/convert/txt2po
-translate/convert/txt2po.py
-translate/convert/web2py2po
-translate/convert/web2py2po.py
-translate/convert/xliff2odf
-translate/convert/xliff2odf.py
-translate/convert/xliff2oo
-translate/convert/xliff2oo.py
-translate/convert/xliff2po
-translate/convert/xliff2po.py
-translate/filters/__init__.py
-translate/filters/autocorrect.py
-translate/filters/checks.py
-translate/filters/decoration.py
-translate/filters/decorators.py
-translate/filters/helpers.py
-translate/filters/pofilter
-translate/filters/pofilter.py
-translate/filters/prefilters.py
-translate/filters/spelling.py
-translate/filters/test_autocorrect.py
-translate/filters/test_checks.py
-translate/filters/test_decoration.py
-translate/filters/test_pofilter.py
-translate/filters/test_prefilters.py
-translate/lang/__init__.py
-translate/lang/af.py
-translate/lang/ak.py
-translate/lang/am.py
-translate/lang/ar.py
-translate/lang/az.py
-translate/lang/bn.py
-translate/lang/code_or.py
-translate/lang/common.py
-translate/lang/data.py
-translate/lang/de.py
-translate/lang/dz.py
-translate/lang/el.py
-translate/lang/es.py
-translate/lang/fa.py
-translate/lang/factory.py
-translate/lang/fi.py
-translate/lang/fr.py
-translate/lang/gd.py
-translate/lang/gu.py
-translate/lang/he.py
-translate/lang/hi.py
-translate/lang/hy.py
-translate/lang/identify.py
-translate/lang/ja.py
-translate/lang/km.py
-translate/lang/kn.py
-translate/lang/ko.py
-translate/lang/kw.py
-translate/lang/lo.py
-translate/lang/ml.py
-translate/lang/mr.py
-translate/lang/ms.py
-translate/lang/my.py
-translate/lang/ne.py
-translate/lang/ngram.py
-translate/lang/nqo.py
-translate/lang/nso.py
-translate/lang/pa.py
-translate/lang/poedit.py
-translate/lang/si.py
-translate/lang/son.py
-translate/lang/st.py
-translate/lang/su.py
-translate/lang/sv.py
-translate/lang/ta.py
-translate/lang/te.py
-translate/lang/team.py
-translate/lang/test_af.py
-translate/lang/test_am.py
-translate/lang/test_ar.py
-translate/lang/test_common.py
-translate/lang/test_data.py
-translate/lang/test_el.py
-translate/lang/test_es.py
-translate/lang/test_fa.py
-translate/lang/test_factory.py
-translate/lang/test_fr.py
-translate/lang/test_hy.py
-translate/lang/test_identify.py
-translate/lang/test_km.py
-translate/lang/test_ko.py
-translate/lang/test_ne.py
-translate/lang/test_nqo.py
-translate/lang/test_or.py
-translate/lang/test_poedit.py
-translate/lang/test_team.py
-translate/lang/test_th.py
-translate/lang/test_tr.py
-translate/lang/test_uk.py
-translate/lang/test_vi.py
-translate/lang/test_zh.py
-translate/lang/th.py
-translate/lang/tr.py
-translate/lang/ug.py
-translate/lang/ur.py
-translate/lang/ve.py
-translate/lang/vi.py
-translate/lang/wo.py
-translate/lang/zh.py
-translate/lang/zh_cn.py
-translate/lang/zh_hk.py
-translate/lang/zh_tw.py
-translate/misc/__init__.py
-translate/misc/autoencode.py
-translate/misc/deprecation.py
-translate/misc/dictutils.py
-translate/misc/diff_match_patch.py
-translate/misc/file_discovery.py
-translate/misc/lru.py
-translate/misc/multistring.py
-translate/misc/optrecurse.py
-translate/misc/ourdom.py
-translate/misc/progressbar.py
-translate/misc/quote.py
-translate/misc/selector.py
-translate/misc/sparse.py
-translate/misc/stdiotell.py
-translate/misc/test_autoencode.py
-translate/misc/test_dictutils.py
-translate/misc/test_multistring.py
-translate/misc/test_optrecurse.py
-translate/misc/test_progressbar.py
-translate/misc/test_quote.py
-translate/misc/wStringIO.py
-translate/misc/wsgi.py
-translate/misc/xml_helpers.py
-translate/misc/wsgiserver/LICENSE.txt
-translate/misc/wsgiserver/__init__.py
-translate/misc/wsgiserver/ssl_builtin.py
-translate/misc/wsgiserver/ssl_pyopenssl.py
-translate/misc/wsgiserver/wsgiserver2.py
-translate/misc/wsgiserver/wsgiserver3.py
-translate/search/__init__.py
-translate/search/lshtein.py
-translate/search/match.py
-translate/search/segment.py
-translate/search/terminology.py
-translate/search/test_lshtein.py
-translate/search/test_match.py
-translate/search/test_terminology.py
-translate/search/indexing/CommonIndexer.py
-translate/search/indexing/PyLuceneIndexer.py
-translate/search/indexing/PyLuceneIndexer1.py
-translate/search/indexing/XapianIndexer.py
-translate/search/indexing/__init__.py
-translate/search/indexing/test_indexers.py
-translate/services/__init__.py
-translate/services/tmserver
-translate/services/tmserver.py
-translate/storage/__init__.py
-translate/storage/_factory_classes.py
-translate/storage/aresource.py
-translate/storage/base.py
-translate/storage/benchmark.py
-translate/storage/bundleprojstore.py
-translate/storage/catkeys.py
-translate/storage/cpo.py
-translate/storage/csvl10n.py
-translate/storage/directory.py
-translate/storage/dtd.py
-translate/storage/factory.py
-translate/storage/fpo.py
-translate/storage/html.py
-translate/storage/ical.py
-translate/storage/ini.py
-translate/storage/jsonl10n.py
-translate/storage/lisa.py
-translate/storage/mo.py
-translate/storage/mozilla_lang.py
-translate/storage/odf_io.py
-translate/storage/odf_shared.py
-translate/storage/omegat.py
-translate/storage/oo.py
-translate/storage/php.py
-translate/storage/po.py
-translate/storage/pocommon.py
-translate/storage/poheader.py
-translate/storage/poparser.py
-translate/storage/poxliff.py
-translate/storage/project.py
-translate/storage/projstore.py
-translate/storage/properties.py
-translate/storage/pypo.py
-translate/storage/qm.py
-translate/storage/qph.py
-translate/storage/rc.py
-translate/storage/statistics.py
-translate/storage/statsdb.py
-translate/storage/subtitles.py
-translate/storage/symbian.py
-translate/storage/tbx.py
-translate/storage/test_aresource.py
-translate/storage/test_base.py
-translate/storage/test_catkeys.py
-translate/storage/test_cpo.py
-translate/storage/test_csvl10n.py
-translate/storage/test_directory.py
-translate/storage/test_dtd.py
-translate/storage/test_factory.py
-translate/storage/test_html.py
-translate/storage/test_mo.py
-translate/storage/test_monolingual.py
-translate/storage/test_mozilla_lang.py
-translate/storage/test_omegat.py
-translate/storage/test_oo.py
-translate/storage/test_php.py
-translate/storage/test_po.py
-translate/storage/test_pocommon.py
-translate/storage/test_poheader.py
-translate/storage/test_poxliff.py
-translate/storage/test_properties.py
-translate/storage/test_pypo.py
-translate/storage/test_qm.py
-translate/storage/test_qph.py
-translate/storage/test_rc.py
-translate/storage/test_statsdb.py
-translate/storage/test_tbx.py
-translate/storage/test_tiki.py
-translate/storage/test_tmx.py
-translate/storage/test_trados.py
-translate/storage/test_ts.py
-translate/storage/test_ts2.py
-translate/storage/test_txt.py
-translate/storage/test_utx.py
-translate/storage/test_wordfast.py
-translate/storage/test_xliff.py
-translate/storage/test_zip.py
-translate/storage/tiki.py
-translate/storage/tmdb.py
-translate/storage/tmx.py
-translate/storage/trados.py
-translate/storage/ts.py
-translate/storage/ts2.py
-translate/storage/txt.py
-translate/storage/utx.py
-translate/storage/wordfast.py
-translate/storage/workflow.py
-translate/storage/xliff.py
-translate/storage/xml_name.py
-translate/storage/zip.py
-translate/storage/placeables/__init__.py
-translate/storage/placeables/base.py
-translate/storage/placeables/general.py
-translate/storage/placeables/interfaces.py
-translate/storage/placeables/lisa.py
-translate/storage/placeables/parse.py
-translate/storage/placeables/strelem.py
-translate/storage/placeables/terminology.py
-translate/storage/placeables/test_base.py
-translate/storage/placeables/test_general.py
-translate/storage/placeables/test_lisa.py
-translate/storage/placeables/test_terminology.py
-translate/storage/placeables/xliff.py
-translate/storage/versioncontrol/__init__.py
-translate/storage/versioncontrol/bzr.py
-translate/storage/versioncontrol/cvs.py
-translate/storage/versioncontrol/darcs.py
-translate/storage/versioncontrol/git.py
-translate/storage/versioncontrol/hg.py
-translate/storage/versioncontrol/svn.py
-translate/storage/versioncontrol/test_helper.py
-translate/storage/versioncontrol/test_svn.py
-translate/storage/xml_extract/__init__.py
-translate/storage/xml_extract/extract.py
-translate/storage/xml_extract/generate.py
-translate/storage/xml_extract/misc.py
-translate/storage/xml_extract/test_misc.py
-translate/storage/xml_extract/test_unit_tree.py
-translate/storage/xml_extract/test_xpath_breadcrumb.py
-translate/storage/xml_extract/unit_tree.py
-translate/storage/xml_extract/xpath_breadcrumb.py
-translate/tools/__init__.py
-translate/tools/build_tmdb
-translate/tools/build_tmdb.py
-translate/tools/phppo2pypo.py
-translate/tools/poclean
-translate/tools/poclean.py
-translate/tools/pocompile
-translate/tools/pocompile.py
-translate/tools/poconflicts
-translate/tools/poconflicts.py
-translate/tools/pocount
-translate/tools/pocount.py
-translate/tools/podebug
-translate/tools/podebug.py
-translate/tools/pogrep
-translate/tools/pogrep.py
-translate/tools/pomerge
-translate/tools/pomerge.py
-translate/tools/porestructure
-translate/tools/porestructure.py
-translate/tools/posegment
-translate/tools/posegment.py
-translate/tools/poswap
-translate/tools/poswap.py
-translate/tools/poterminology
-translate/tools/poterminology.py
-translate/tools/pretranslate
-translate/tools/pretranslate.py
-translate/tools/pydiff.py
-translate/tools/pypo2phppo.py
-translate/tools/test_phppo2pypo.py
-translate/tools/test_pocount.py
-translate/tools/test_podebug.py
-translate/tools/test_pogrep.py
-translate/tools/test_pomerge.py
-translate/tools/test_pretranslate.py
-translate/tools/test_pypo2phppo.py
-translate_toolkit.egg-info/PKG-INFO
-translate_toolkit.egg-info/SOURCES.txt
-translate_toolkit.egg-info/dependency_links.txt
-translate_toolkit.egg-info/requires.txt
-translate_toolkit.egg-info/top_level.txt
\ No newline at end of file
diff --git a/translate_toolkit.egg-info/dependency_links.txt b/translate_toolkit.egg-info/dependency_links.txt
deleted file mode 100644
index 8b13789..0000000
--- a/translate_toolkit.egg-info/dependency_links.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/translate_toolkit.egg-info/requires.txt b/translate_toolkit.egg-info/requires.txt
deleted file mode 100644
index b68c603..0000000
--- a/translate_toolkit.egg-info/requires.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-argparse
-six
-diff-match-patch
\ No newline at end of file
diff --git a/translate_toolkit.egg-info/top_level.txt b/translate_toolkit.egg-info/top_level.txt
deleted file mode 100644
index 0671813..0000000
--- a/translate_toolkit.egg-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-translate
-----------------------------------------------------------------------


hooks/post-receive
-- 
translate-toolkit



More information about the Debian-l10n-commits mailing list