Mailinglist Archive: opensuse-commit (1029 mails)

< Previous Next >
commit itstool for openSUSE:Factory

Hello community,

here is the log from the commit of package itstool for openSUSE:Factory
checked in at Tue Jul 26 09:22:59 CEST 2011.



--------
--- itstool/itstool.changes 2011-05-24 09:56:38.000000000 +0200
+++ /mounts/work_src_done/STABLE/itstool/itstool.changes 2011-06-28
11:26:52.000000000 +0200
@@ -1,0 +2,15 @@
+Tue Jun 28 11:22:55 CEST 2011 - dimstar@xxxxxxxxxxxx
+
+- Update to version 1.1.0:
+ + Added itst:context to set msgctxt
+ + Added itst:drop to drop context from translations
+ + Allow XML attribute to be translated
+ + Allow locNotePointer to return a string
+ + Allow localization notes to be space-preserving
+ + Allow both XLink and child rules on its:rules
+ + Fixed Unicode encoding/decoding errors
+ + Added automated test suite
+ + Added a man page
+ + Python 3 fixes
+
+-------------------------------------------------------------------

calling whatdependson for head-i586


Old:
----
itstool-1.0.1.tar.bz2

New:
----
itstool-1.1.0.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ itstool.spec ++++++
--- /var/tmp/diff_new_pack.VmAeeR/_old 2011-07-26 09:19:22.000000000 +0200
+++ /var/tmp/diff_new_pack.VmAeeR/_new 2011-07-26 09:19:22.000000000 +0200
@@ -18,7 +18,7 @@


Name: itstool
-Version: 1.0.1
+Version: 1.1.0
Release: 1
License: GPLv3+
Summary: Tool to translate XML documents using PO files
@@ -57,5 +57,6 @@
%doc ChangeLog COPYING COPYING.GPL3 NEWS
%{_bindir}/%{name}
%{_datadir}/%{name}/
+%{_mandir}/man1/itstool.1%{?ext_man}

%changelog

++++++ itstool-1.0.1.tar.bz2 -> itstool-1.1.0.tar.bz2 ++++++
++++ 1885 lines of diff (skipped)
++++ retrying with extended exclude list
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh
old/itstool-1.0.1/ChangeLog new/itstool-1.1.0/ChangeLog
--- old/itstool-1.0.1/ChangeLog 2011-05-06 23:02:08.000000000 +0200
+++ new/itstool-1.1.0/ChangeLog 2011-06-27 20:58:10.000000000 +0200
@@ -1,3 +1,309 @@
+commit 187fcbe585560f128c7436e66f6b8e3a789a73b0
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Sun Jun 26 12:28:10 2011 -0400
+
+ mallard.its: Set msgctxt on info titles
+
+ its/mallard.its | 3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+commit b57dfa4327da4d889dbfc5d26d824482fd7b2f54
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Sun Jun 26 12:27:46 2011 -0400
+
+ Don't bomb if a locNotePointer returns a string
+
+ itstool.in | 22 +++++++++++++---------
+ 1 files changed, 13 insertions(+), 9 deletions(-)
+
+commit 8d97758ac43f2079d252fedf2a9666b33a751fd0
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Sat Jun 25 14:49:53 2011 -0400
+
+ Added itst:context to specify a msgctxt for a node
+
+ itstool.in | 35 ++++++++++++++++++++++++++++++++++-
+ tests/Context.ll.po | 35 +++++++++++++++++++++++++++++++++++
+ tests/Context.ll.xml | 15 +++++++++++++++
+ tests/Context.pot | 35 +++++++++++++++++++++++++++++++++++
+ tests/Context.xml | 14 ++++++++++++++
+ tests/run_tests.py | 3 +++
+ 6 files changed, 136 insertions(+), 1 deletions(-)
+
+commit e84f296dd21de75b9244896be9d2acc6aeed4dea
+Author: Claude Paroz <claude@xxxxxxxxxxx>
+Date: Fri Jun 24 12:25:17 2011 -0400
+
+ Fixes for Python 3
+
+ itstool.in | 2 +-
+ tests/run_tests.py | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+commit b13436f2a75ffded500e5f26028237d337510394
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Fri Jun 24 11:21:38 2011 -0400
+
+ Use #!/usr/bin/python -s for shebang, RH bug #702989
+
+ itstool.in | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+commit d8b399ae628e822ee9a9762657969361c5aebc93
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Fri Jun 24 10:19:54 2011 -0400
+
+ Make itst:drop work on non-inline nodes
+
+ itstool.in | 15 ++++++++++++++-
+ tests/Droprule.xml | 2 ++
+ 2 files changed, 16 insertions(+), 1 deletions(-)
+
+commit 56cd8382ae979fab1a4a4a25f052d93d1070fc6d
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Thu Jun 23 17:51:40 2011 -0400
+
+ Made dropRule take a drop attribute, like other rules
+
+ itstool.in | 6 +++---
+ tests/Droprule.ll.xml | 2 +-
+ tests/Droprule.xml | 2 +-
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+commit 333218d4978a7b203252d35e7979f64cfb3b0c1c
+Author: Claude Paroz <claude@xxxxxxxxxxx>
+Date: Tue May 31 22:46:29 2011 +0200
+
+ Add itst drop rule
+
+ The itst Droprule is a rule allowing to ignore completely a tag from
+ the translation, including its content. The resulting xml will not
+ have the tag either.
+
+ itstool.in | 7 ++++++-
+ tests/Droprule.ll.po | 15 +++++++++++++++
+ tests/Droprule.ll.xml | 11 +++++++++++
+ tests/Droprule.pot | 15 +++++++++++++++
+ tests/Droprule.xml | 10 ++++++++++
+ tests/run_tests.py | 4 ++++
+ 6 files changed, 61 insertions(+), 1 deletions(-)
+
+commit 7cda8e16e2281e0e6c42f1e47bfc98ee5e4fe4ae
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Thu Jun 23 17:45:16 2011 -0400
+
+ Renamed attribute test files
+
+ tests/Attributes1.ll.po | 19 +++++++++++++++++++
+ tests/Attributes1.ll.xml | 10 ++++++++++
+ tests/Attributes1.pot | 19 +++++++++++++++++++
+ tests/Attributes1.xml | 10 ++++++++++
+ tests/README | 2 --
+ tests/run_tests.py | 4 ++--
+ tests/x-attr1.ll.po | 19 -------------------
+ tests/x-attr1.ll.xml | 10 ----------
+ tests/x-attr1.pot | 19 -------------------
+ tests/x-attr1.xml | 10 ----------
+ 10 files changed, 60 insertions(+), 62 deletions(-)
+
+commit 4334f863ae6ab636b3e7c905e15693a188e4bee1
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Thu Jun 23 16:11:42 2011 -0400
+
+ Handled translatable attributes in non-translatable elements
+
+ itstool.in | 25 +++++++++++++++----------
+ tests/README | 4 +++-
+ tests/run_tests.py | 3 +++
+ tests/x-attr1.ll.po | 19 +++++++++++++++++++
+ tests/x-attr1.ll.xml | 10 ++++++++++
+ tests/x-attr1.pot | 19 +++++++++++++++++++
+ tests/x-attr1.xml | 10 ++++++++++
+ 7 files changed, 79 insertions(+), 11 deletions(-)
+
+commit 7ecd70b27d5cc22f8d6b35fc68aa9fe9cd3a7def
+Author: Claude Paroz <claude@xxxxxxxxxxx>
+Date: Sun Jun 12 21:40:36 2011 +0200
+
+ Extract and translate node attributes
+
+ itstool.in | 41 ++++++++++++++++++++++++++++++++++++-----
+ tests/Translate1.ll.po | 4 ++++
+ tests/Translate1.ll.xml | 2 +-
+ tests/Translate1.pot | 4 ++++
+ tests/Translate2.ll.po | 4 ++++
+ tests/Translate2.ll.xml | 2 +-
+ tests/Translate2.pot | 4 ++++
+ tests/TranslateGlobal.ll.po | 23 +++++++++++++++++++++++
+ tests/TranslateGlobal.ll.xml | 13 +++++++++++++
+ tests/TranslateGlobal.pot | 23 +++++++++++++++++++++++
+ tests/run_tests.py | 7 +++----
+ 11 files changed, 116 insertions(+), 11 deletions(-)
+
+commit fadb43fc37dbe18d9b1204bb13fb5ccea492b649
+Merge: 43a518a 1ebcc2a
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Wed Jun 1 09:22:03 2011 -0400
+
+ Merge branch 'testsuite'
+
+commit 1ebcc2af7fa4d6e12687199e173720b44eb823a3
+Author: Claude Paroz <claude@xxxxxxxxxxx>
+Date: Wed Jun 1 15:11:51 2011 +0200
+
+ Fix LocNote2 test and add README in tests
+
+ tests/LocNote2.pot | 25 +++++++++++++++++++++++++
+ tests/README | 5 +++++
+ tests/run_tests.py | 4 ++--
+ 3 files changed, 32 insertions(+), 2 deletions(-)
+
+commit 43a518a2da4eb11f78b23cbca6291f9cd7c2f4ab
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Wed Jun 1 08:59:26 2011 -0400
+
+ Adding copyright and license info to itstool
+
+ itstool.in | 17 +++++++++++++++++
+ 1 files changed, 17 insertions(+), 0 deletions(-)
+
+commit 480a2531c9b8ba0249f9326e8d043de309486e5b
+Author: Claude Paroz <claude@xxxxxxxxxxx>
+Date: Wed Jun 1 13:45:51 2011 +0200
+
+ Add remaining tests
+
+ itstool.in | 5 ++-
+ tests/EX-locNotePointer-attribute-1.pot | 21 +++++++++++
+ tests/EX-locNoteRefPointer-attribute-1.pot | 21 +++++++++++
+ tests/LocNote1.pot | 25 +++++++++++++
+ tests/LocNote3.pot | 29 ++++++++++++++++
+ tests/LocNote4.pot | 30 ++++++++++++++++
+ tests/WithinText1.ll.po | 23 ++++++++++++
+ tests/WithinText1.ll.xml | 14 ++++++++
+ tests/WithinText1.pot | 23 ++++++++++++
+ tests/WithinText2.ll.po | 51 ++++++++++++++++++++++++++++
+ tests/WithinText2.ll.xml | 21 +++++++++++
+ tests/WithinText2.pot | 51 ++++++++++++++++++++++++++++
+ tests/run_tests.py | 40 ++++++++++++++++++++-
+ 13 files changed, 350 insertions(+), 4 deletions(-)
+
+commit 66f3fdd0d678bfffefef4b26e0c6812e3a9b8bb8
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Wed Jun 1 08:07:42 2011 -0400
+
+ itstool: Allow both XLink and child rules on its:rules
+
+ We weren't handling tests/WithinText2.xml correctly
+
+ itstool.in | 3 +--
+ 1 files changed, 1 insertions(+), 2 deletions(-)
+
+commit 2ffe1d30ea1d5925a75955bc9b88c3d4c14b7b46
+Author: Claude Paroz <claude@xxxxxxxxxxx>
+Date: Tue May 31 22:05:00 2011 +0200
+
+ Add tests for the Translate* series
+
+ tests/Translate2.ll.po | 15 +++++++++++++++
+ tests/Translate2.ll.xml | 10 ++++++++++
+ tests/Translate2.pot | 15 +++++++++++++++
+ tests/Translate3.ll.po | 19 +++++++++++++++++++
+ tests/Translate3.ll.xml | 10 ++++++++++
+ tests/Translate4.ll.po | 19 +++++++++++++++++++
+ tests/Translate4.ll.xml | 10 ++++++++++
+ tests/Translate5.ll.po | 19 +++++++++++++++++++
+ tests/Translate5.ll.xml | 19 +++++++++++++++++++
+ tests/Translate5.pot | 19 +++++++++++++++++++
+ tests/Translate6.ll.po | 31 +++++++++++++++++++++++++++++++
+ tests/Translate6.ll.xml | 19 +++++++++++++++++++
+ tests/Translate7.ll.po | 19 +++++++++++++++++++
+ tests/Translate7.ll.xml | 29 +++++++++++++++++++++++++++++
+ tests/Translate7.pot | 19 +++++++++++++++++++
+ tests/run_tests.py | 41 +++++++++++++++++++++++++++++++++++------
+ 16 files changed, 307 insertions(+), 6 deletions(-)
+
+commit d3177444660bac67265ba9cf17d586fd1b0b2907
+Author: Claude Paroz <claude@xxxxxxxxxxx>
+Date: Tue May 31 20:41:13 2011 +0200
+
+ Fix xml iteration when constructing translated subnodes
+
+ itstool.in | 3 ++-
+ tests/Translate1.ll.xml | 2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+commit 6c7b6bb9db8e77ec142fac2c9b514ec1769df65b
+Author: Claude Paroz <claude@xxxxxxxxxxx>
+Date: Tue May 31 16:33:48 2011 +0200
+
+ Use unicode strings inside of Message class
+
+ itstool.in | 40 +++++++++++++++++++++-------------------
+ 1 files changed, 21 insertions(+), 19 deletions(-)
+
+commit f4635d084d93212af73221de5165c3fa92f834cd
+Author: Claude Paroz <claude@xxxxxxxxxxx>
+Date: Mon May 30 21:23:15 2011 +0200
+
+ Initial test infrastructure
+
+ tests/Translate1.ll.po | 35 +++++++++++++++++++++++++
+ tests/Translate1.ll.xml | 39 +++++++++++++++++++++++++++
+ tests/Translate1.pot | 35 +++++++++++++++++++++++++
+ tests/run_tests.py | 66 +++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 175 insertions(+), 0 deletions(-)
+
+commit 00a8df54545a66aa70c20ceecb19709ca0b811a7
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Fri May 27 12:09:10 2011 -0400
+
+ Include installation dir in search path if XDG_DATA_DIRS not set
+
+ configure.ac | 9 +++++++++
+ itstool.in | 5 ++++-
+ 2 files changed, 13 insertions(+), 1 deletions(-)
+
+commit abd3afc9bd7066658d295de3a39c5c0b287d0644
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Mon May 9 21:26:42 2011 -0400
+
+ itstool: Allow localization notes to be space-preserving
+
+ itstool.in | 32 ++++++++++++++++++++++----------
+ 1 files changed, 22 insertions(+), 10 deletions(-)
+
+commit 04a706ae1057d0a9ed4b36c7e20292d44e97ad80
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Mon May 9 16:32:25 2011 -0400
+
+ itstool.1: Added a man page
+
+ .gitignore | 1 +
+ Makefile.am | 10 +++++++-
+ configure.ac | 1 +
+ itstool.1.in | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 88 insertions(+), 1 deletions(-)
+
+commit 69db1ded268af460d31b6ab2d86172873468890f
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Mon May 9 11:15:02 2011 -0400
+
+ Catch XPath exceptions and warn
+
+ itstool.in | 30 +++++++++++++++++++-----------
+ 1 files changed, 19 insertions(+), 11 deletions(-)
+
+commit 6fdaea81bf70023612202cadcd7d9995e571f23e
+Author: Shaun McCance <shaunm@xxxxxxxxx>
+Date: Fri May 6 17:02:13 2011 -0400
+
+ Version 1.0.1
+
+ NEWS | 7 +++++++
+ configure.ac | 2 +-
+ 2 files changed, 8 insertions(+), 1 deletions(-)
+
commit e9344508508112ecd177232ba49b5664e860bc9f
Author: Shaun McCance <shaunm@xxxxxxxxx>
Date: Tue May 3 12:48:53 2011 -0400
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh
old/itstool-1.0.1/Makefile.am new/itstool-1.1.0/Makefile.am
--- old/itstool-1.0.1/Makefile.am 2011-04-30 20:47:14.000000000 +0200
+++ new/itstool-1.1.0/Makefile.am 2011-06-24 19:30:25.000000000 +0200
@@ -2,7 +2,15 @@

bin_SCRIPTS = itstool

-EXTRA_DIST = ChangeLog COPYING.GPL3 $(bin_SCRIPTS) itstool.in
+man_MANS = itstool.1
+
+EXTRA_DIST = \
+ ChangeLog \
+ COPYING.GPL3 \
+ $(bin_SCRIPTS) \
+ itstool.in \
+ $(man_MANS) \
+ itstool.1.in

ChangeLog:
@if test -f $(top_srcdir)/.git/HEAD; then \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh
old/itstool-1.0.1/NEWS new/itstool-1.1.0/NEWS
--- old/itstool-1.0.1/NEWS 2011-05-06 23:01:51.000000000 +0200
+++ new/itstool-1.1.0/NEWS 2011-06-27 20:57:50.000000000 +0200
@@ -1,3 +1,17 @@
+1.1.0
+=====
+* Added itst:context to set msgctxt
+* Added itst:drop to drop context from translations
+* Allow XML attribute to be translated
+* Allow locNotePointer to return a string
+* Allow localization notes to be space-preserving
+* Allow both XLink and child rules on its:rules
+* Fixed Unicode encoding/decoding errors
+* Added automated test suite
+* Added a man page
+* Python 3 fixes
+* Commits by Shaun McCance, Claude Paroz
+
1.0.1
=====
* Convert POSIX-style locales to BCP47
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh
old/itstool-1.0.1/configure.ac new/itstool-1.1.0/configure.ac
--- old/itstool-1.0.1/configure.ac 2011-05-06 23:00:41.000000000 +0200
+++ new/itstool-1.1.0/configure.ac 2011-06-27 20:53:05.000000000 +0200
@@ -1,9 +1,19 @@
-AC_INIT([itstool], [1.0.1], [])
+AC_INIT([itstool], [1.1.0], [])
AM_INIT_AUTOMAKE([1.9 no-dist-gzip dist-bzip2])

+DATADIR=`(
+ case $prefix in
+ NONE) prefix=$ac_default_prefix ;;
+ *) ;;
+ esac
+ eval echo $(eval echo $datadir)
+)`
+AC_SUBST([DATADIR])
+
AC_CONFIG_FILES([
Makefile
itstool
+itstool.1
its/Makefile
])

diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh
old/itstool-1.0.1/its/mallard.its new/itstool-1.1.0/its/mallard.its
--- old/itstool-1.0.1/its/mallard.its 2011-04-26 02:05:18.000000000 +0200
+++ new/itstool-1.1.0/its/mallard.its 2011-06-25 21:10:22.000000000 +0200
@@ -36,4 +36,7 @@
<its:translateRule translate="no" selector="//mal:credit/mal:email"/>

<itst:externalRefRule selector="//mal:media" refPointer="@src"/>
+
+ <itst:contextRule selector="//mal:info/mal:title[@type]"
contextPointer="@type"/>
+ <itst:contextRule selector="//mal:info/mal:title[@type and @role]"
contextPointer="concat(@type, ':', @role)"/>
</its:rules>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh
old/itstool-1.0.1/itstool new/itstool-1.1.0/itstool
--- old/itstool-1.0.1/itstool 2011-05-06 23:02:08.000000000 +0200
+++ new/itstool-1.1.0/itstool 2011-06-27 20:58:10.000000000 +0200
@@ -1,6 +1,24 @@
-#!/usr/bin/env python
+#!/usr/bin/python -s
+#
+# Copyright (c) 2010-2011 Shaun McCance <shaunm@xxxxxxxxx>
+#
+# ITS Tool 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 3 of the License, or (at your
+# option) any later version.
+#
+# ITS Tool 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 ITS Tool; if not, write to the Free Software Foundation, 59 Temple
+# Place, Suite 330, Boston, MA 0211-1307 USA.
+#

-VERSION="1.0.1"
+VERSION="1.1.0"
+DATADIR="/usr/local/share"

import gettext
import hashlib
@@ -91,7 +109,7 @@
out.write('"Content-Transfer-Encoding: 8bit\\n"\n')
out.write('\n')
for msg in msgs:
- out.write(msg.format())
+ out.write(msg.format().encode('utf-8'))
out.write('\n')


@@ -105,10 +123,15 @@
self._comments = []
self._preserve = False

+ def __repr__(self):
+ if self._empty:
+ return "Empty message"
+ return self.get_string()
+
class Placeholder (object):
def __init__ (self, node):
self.node = node
- self.name = node.name
+ self.name = unicode(node.name, 'utf-8')

def escape (self, text):
return text.replace('\\','\\\\').replace('"',
"\\\"").replace("\n","\\n").replace("\t","\\t")
@@ -116,6 +139,8 @@
def add_text (self, text):
if len(self._message) == 0 or not(isinstance(self._message[-1],
basestring)):
self._message.append('')
+ if not isinstance(text, unicode):
+ text = unicode(text, 'utf-8')
self._message[-1] += text.replace('&', '&amp;').replace('<',
'&lt;').replace('>', '&gt;')
if re.sub('\s+', ' ', text).strip() != '':
self._empty = False
@@ -128,8 +153,8 @@
def get_placeholder (self, name):
placeholder = 1
for holder in self._placeholders:
- holdername = '%s-%i' % (holder.name, placeholder)
- if holdername == name:
+ holdername = u'%s-%i' % (holder.name, placeholder)
+ if holdername == unicode(name, 'utf-8'):
return holder
placeholder += 1

@@ -155,7 +180,7 @@
if node.children is not None:
if len(self._message) == 0 or not(isinstance(self._message[-1],
basestring)):
self._message.append('')
- self._message[-1] += ('</%s>' % node.name)
+ self._message[-1] += (u'</%s>' % unicode(node.name, 'utf-8'))

def is_empty (self):
return self._empty
@@ -167,25 +192,28 @@
self._ctxt = ctxt

def add_source (self, source):
+ if not isinstance(source, unicode):
+ source = unicode(source, 'utf-8')
self._sources.append(source)

def get_sources (self):
return self._sources

def add_comment (self, comment):
- self._comments.append(comment)
+ if comment is not None:
+ self._comments.append(comment)

def get_comments (self):
return self._comments

def get_string (self):
- message = ''
+ message = u''
placeholder = 1
for msg in self._message:
if isinstance(msg, basestring):
message += msg
elif isinstance(msg, Message.Placeholder):
- message += '<_:%s-%i/>' % (msg.name, placeholder)
+ message += u'<_:%s-%i/>' % (msg.name, placeholder)
placeholder += 1
if not self._preserve:
message = re.sub('\s+', ' ', message).strip()
@@ -198,38 +226,47 @@
self._preserve = preserve

def format (self):
- ret = ''
+ ret = u''
for i in range(len(self._comments)):
if i != 0:
ret += '#.\n'
comment = self._comments[i]
- while len(comment) > 72:
- j = comment.rfind(' ', 0, 72)
- if j == -1:
- j = comment.find(' ')
- if j == -1:
- break
- ret += '#. %s\n' % comment[:j]
- comment = comment[j+1:]
- ret += '#. %s\n' % comment
+ if '\n' in comment:
+ doadd = False
+ for line in comment.split('\n'):
+ if line != '':
+ doadd = True
+ if not doadd:
+ continue
+ ret += u'#. %s\n' % line
+ else:
+ while len(comment) > 72:
+ j = comment.rfind(' ', 0, 72)
+ if j == -1:
+ j = comment.find(' ')
+ if j == -1:
+ break
+ ret += u'#. %s\n' % comment[:j]
+ comment = comment[j+1:]
+ ret += '#. %s\n' % comment
for source in self._sources:
- ret += '#: %s\n' % source
+ ret += u'#: %s\n' % source
if self._preserve:
- ret += '#, no-wrap\n'
+ ret += u'#, no-wrap\n'
if self._ctxt is not None:
- ret += 'msgctxt "%s"\n' % self._ctxt
+ ret += u'msgctxt "%s"\n' % self._ctxt
message = self.get_string()
if self._preserve:
- ret += 'msgid ""\n'
+ ret += u'msgid ""\n'
lines = message.split('\n')
for line, no in zip(lines, range(len(lines))):
if no == len(lines) - 1:
- ret += '"%s"\n' % self.escape(line)
+ ret += u'"%s"\n' % self.escape(line)
else:
- ret += '"%s\\n"\n' % self.escape(line)
+ ret += u'"%s\\n"\n' % self.escape(line)
else:
- ret += 'msgid "%s"\n' % self.escape(message)
- ret += 'msgstr ""\n'
+ ret += u'msgid "%s"\n' % self.escape(message)
+ ret += u'msgstr ""\n'
return ret


@@ -239,6 +276,12 @@
yield child
child = child.next

+def xml_attr_iter (node):
+ attr = node.get_properties()
+ while attr is not None:
+ yield attr
+ attr = attr.next
+
def xml_is_ns_name (node, ns, name):
if node.type != 'element':
return False
@@ -267,8 +310,7 @@
hctxt.replaceEntities(1)
hctxt.parseDocument()
self._localrules.append(hctxt.doc().getRootElement())
- else:
- self._localrules.append(child)
+ self._localrules.append(child)
pre_process(child)
pre_process(self._doc)
self._msgs = messages
@@ -276,6 +318,8 @@
self._its_within_text_nodes = {}
self._its_loc_notes = {}
self._itst_preserve_space_nodes = {}
+ self._itst_drop_nodes = {}
+ self._itst_contexts = {}
self._its_lang = {}
self._itst_lang_attr = {}
self._itst_credits = None
@@ -286,16 +330,39 @@
return
if xml_is_ns_name(rule, NS_ITS, 'translateRule'):
if rule.prop('selector') is not None:
- for node in xpath.xpathEval(rule.prop('selector')):
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
self._its_translate_nodes[node] = rule.prop('translate')
elif xml_is_ns_name(rule, NS_ITS, 'withinTextRule'):
if rule.prop('selector') is not None:
- for node in xpath.xpathEval(rule.prop('selector')):
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
self._its_within_text_nodes[node] = rule.prop('withinText')
elif xml_is_ns_name(rule, NS_ITST, 'preserveSpaceRule'):
if rule.prop('selector') is not None:
- for node in xpath.xpathEval(rule.prop('selector')):
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
self._itst_preserve_space_nodes[node] =
rule.prop('preserveSpace')
+ elif xml_is_ns_name(rule, NS_ITST, 'dropRule'):
+ if rule.prop('selector') is not None:
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
+ self._itst_drop_nodes[node] = rule.prop('drop')
+ elif xml_is_ns_name(rule, NS_ITST, 'contextRule'):
+ if rule.prop('selector') is not None:
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
+ if rule.hasProp('context'):
+ self._itst_contexts[node] = rule.prop('context')
+ elif rule.hasProp('contextPointer'):
+ try:
+ oldnode = xpath.contextNode()
+ except:
+ oldnode = None
+ xpath.setContextNode(node)
+ ctxt = self._try_xpath_eval(xpath,
rule.prop('contextPointer'))
+ if isinstance(ctxt, basestring):
+ self._itst_contexts[node] = ctxt
+ else:
+ for ctxt in ctxt:
+ self._itst_contexts[node] = ctxt.content
+ break
+ xpath.setContextNode(oldnode)
elif xml_is_ns_name(rule, NS_ITS, 'locNoteRule'):
locnote = None
for child in xml_child_iter(rule):
@@ -306,7 +373,7 @@
if rule.hasProp('locNoteRef'):
locnote = 'SEE: ' + re.sub('\s+', ' ',
rule.prop('locNoteRef')).strip()
if rule.prop('selector') is not None:
- for node in xpath.xpathEval(rule.prop('selector')):
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
if locnote is not None:
self._its_loc_notes[node] = locnote
else:
@@ -323,22 +390,29 @@
except:
oldnode = None
xpath.setContextNode(node)
- for note in xpath.xpathEval(sel):
- cont = re.sub('\s+', ' ', note.content).strip()
- if ref:
- cont = 'SEE: ' + cont
- self._its_loc_notes[node] = cont
- break
+ note = self._try_xpath_eval(xpath, sel)
+ if isinstance(note, basestring):
+ self._its_loc_notes[node] = note
+ else:
+ for note in note:
+ if self.get_preserve_space(note):
+ cont = note.content
+ else:
+ cont = re.sub('\s+', ' ',
note.content).strip()
+ if ref:
+ cont = 'SEE: ' + cont
+ self._its_loc_notes[node] = cont
+ break
xpath.setContextNode(oldnode)
elif xml_is_ns_name(rule, NS_ITS, 'langRule'):
if rule.prop('selector') is not None and rule.prop('langPointer')
is not None:
- for node in xpath.xpathEval(rule.prop('selector')):
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
try:
oldnode = xpath.contextNode()
except:
oldnode = None
xpath.setContextNode(node)
- res = xpath.xpathEval(rule.prop('langPointer'))
+ res = self._try_xpath_eval(xpath, rule.prop('langPointer'))
if len(res) > 0:
self._its_lang[node] = res[0].content
# We need to construct language attributes, not just read
@@ -350,18 +424,18 @@
xpath.setContextNode(oldnode)
elif xml_is_ns_name(rule, NS_ITST, 'credits'):
if rule.prop('appendTo') is not None:
- for node in xpath.xpathEval(rule.prop('appendTo')):
+ for node in self._try_xpath_eval(xpath, rule.prop('appendTo')):
self._itst_credits = (node, rule)
break
elif xml_is_ns_name(rule, NS_ITST, 'externalRefRule'):
if rule.prop('selector') is not None and rule.prop('refPointer')
is not None:
- for node in xpath.xpathEval(rule.prop('selector')):
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
try:
oldnode = xpath.contextNode()
except:
oldnode = None
xpath.setContextNode(node)
- res = xpath.xpathEval(rule.prop('refPointer'))
+ res = self._try_xpath_eval(xpath, rule.prop('refPointer'))
if len(res) > 0:
self._itst_externals.append((node, res[0].content))
xpath.setContextNode(oldnode)
@@ -374,7 +448,9 @@
dirs.append(ddir)
ddir = os.getenv('XDG_DATA_DIRS', '')
if ddir == '':
- ddir = '/usr/local/share:/usr/share'
+ if DATADIR not in ('/usr/local/share', '/usr/share'):
+ ddir += DATADIR + ':'
+ ddir += '/usr/local/share:/usr/share'
dirs.extend(ddir.split(':'))
ddone = {}
for ddir in dirs:
@@ -410,7 +486,7 @@
nsdef = nsdef.next
par = par.parent
if match.hasProp('selector'):
- if len(xpath.xpathEval(match.prop('selector'))) > 0:
+ if len(self._try_xpath_eval(xpath,
match.prop('selector'))) > 0:
matched = True
break
if matched == False:
@@ -443,6 +519,8 @@
xpath = self._doc.xpathNewContext()
reg_ns(xpath, rules)
for rule in xml_child_iter(rules):
+ if rule.type != 'element':
+ continue
if rule.nsDefs() is not None:
rule_xpath = self._doc.xpathNewContent()
reg_ns(rule_xpath, rule)
@@ -503,16 +581,27 @@
node = self._doc.getRootElement()
if node is None or node.type != 'element':
return
+ if ((node.hasNsProp('drop', NS_ITST) and node.nsProp('drop', NS_ITST)
== 'yes') or
+ self._itst_drop_nodes.get(node, 'no') == 'yes'):
+ prev = node.prev
+ node.unlinkNode()
+ node.freeNode()
+ if prev.isBlankNode():
+ prev.unlinkNode()
+ prev.freeNode()
+ return
if is_root:
self.merge_credits(translations, language, node)
msg = self._msgs.get_message_by_node(node)
if msg is None:
+ self.translate_attrs(node, node)
children = [child for child in xml_child_iter(node)]
for child in children:
self.merge_translations(translations, language, node=child)
else:
newnode = self.get_translated(node, translations)
if newnode != node:
+ self.translate_attrs(node, newnode)
node.replaceNode(newnode)
if is_root:
# Apply language attributes to untranslated nodes. We don't do
@@ -556,11 +645,24 @@
fix_node_ns(child, childnsdefs)
fix_node_ns(node, {})

+ def translate_attrs(self, oldnode, newnode):
+ trans_attrs = [attr for attr in xml_attr_iter(oldnode) if
self._its_translate_nodes.get(attr, 'no') == 'yes']
+ for attr in trans_attrs:
+ newcontent = translations.ugettext(attr.get_content())
+ if newcontent:
+ newnode.setProp(attr.name,
translations.ugettext(attr.get_content()))
+
def get_translated (self, node, translations):
msg = self._msgs.get_message_by_node(node)
if msg is None:
return node
- trans = translations.ugettext(msg.get_string())
+ msgstr = msg.get_string()
+ # Dear Python, please implement pgettext.
+ # http://bugs.python.org/issue2504
+ # Sincerely, Shaun
+ if msg.get_context() is not None:
+ msgstr = msg.get_context() + '\x04' + msgstr
+ trans = translations.ugettext(msgstr)
if trans is None:
return node
nss = {}
@@ -585,7 +687,8 @@
ctxt.parseDocument()
trnode = ctxt.doc().getRootElement()
def scan_node(node):
- for child in xml_child_iter(node):
+ children = [child for child in xml_child_iter(node)]
+ for child in children:
if child.type != 'element':
continue
if child.ns() is not None and child.ns().content == NS_BLANK:
@@ -632,12 +735,17 @@
return
if node.type != 'element':
return
+ if node.hasNsProp('drop', NS_ITST) and node.nsProp('drop', NS_ITST) ==
'yes':
+ return
+ if self._itst_drop_nodes.get(node, 'no') == 'yes':
+ return
translate = self.get_its_translate(node)
if translate is None:
if self._in_translatable:
translate = 'yes'
else:
translate = 'no'
+ withinText = False
if translate == 'no':
if msg is not None:
msg.add_placeholder(node)
@@ -649,16 +757,35 @@
if msg is not None:
msg.add_placeholder(node)
msg = Message()
+ ctxt = None
+ if node.hasNsProp('context', NS_ITST):
+ ctxt = node.nsProp('context', NS_ITST)
+ if ctxt is None:
+ ctxt = self._itst_contexts.get(node)
+ if ctxt is not None:
+ msg.set_context(ctxt)
if self.get_preserve_space(node):
msg.set_preserve_space()
msg.add_source('%s:%i(%s/%s)' % (self._doc.name,
node.lineNo(), node.parent.name, node.name))
else:
+ withinText = True
msg.add_start_tag(node)

+ if not withinText:
+ # Add msg for translatable node attributes
+ for attr in xml_attr_iter(node):
+ if self._its_translate_nodes.get(attr, 'no') == 'yes':
+ attr_msg = Message()
+ attr_msg.add_source('%s:%i(%s/%s@%s)' % (
+ self._doc.name, node.lineNo(), node.parent.name,
node.name, attr.name))
+ attr_msg.add_text(attr.content)
+ if comments:
+ attr_msg.add_comment(self.get_its_loc_note(attr))
+ self._msgs.add_message(attr_msg, attr)
+
+
if comments and msg is not None:
- comment = self.get_its_loc_note(node)
- if comment is not None:
- msg.add_comment(comment)
+ msg.add_comment(self.get_its_loc_note(node))

in_translatable = self._in_translatable
self._in_translatable = (translate == 'yes')
@@ -710,6 +837,14 @@
return 'SEE: ' + re.sub('\s+', ' ',
node.prop('locNoteRef')).strip()
return self._its_loc_notes.get(node, None)

+ @staticmethod
+ def _try_xpath_eval (xpath, expr):
+ try:
+ return xpath.xpathEval(expr)
+ except:
+ sys.stderr.write('Warning: Invalid XPath: %s\n' % expr)
+ return []
+

_locale_pattern =
re.compile('([a-zA-Z0-9-]+)(_[A-Za-z0-9]+)?(@[A-Za-z0-9]+)?(\.[A-Za-z0-9]+)?')
def convert_locale (locale):
@@ -768,7 +903,7 @@
(opts, args) = options.parse_args(sys.argv)

if opts.version:
- print 'itstool ' + VERSION
+ print('itstool %s' % VERSION)
sys.exit(0)

if opts.merge is None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh
old/itstool-1.0.1/itstool.1 new/itstool-1.1.0/itstool.1
--- old/itstool-1.0.1/itstool.1 1970-01-01 01:00:00.000000000 +0100
+++ new/itstool-1.1.0/itstool.1 2011-06-27 20:58:10.000000000 +0200
@@ -0,0 +1,77 @@
+.TH ITSTOOL "1" "May 2011" "itstool 1.1.0"
+.SH NAME
+itstool \- convert between XML and PO using ITS
+
+.SH SYNOPSIS
+itstool [OPTIONS] [XMLFILES]
+.br
+itstool \fB\-m\fR <MOFILE> [OPTIONS] [XMLFILES]
+
+.SH DESCRIPTION
+.BR itstool
+extracts messages from XML files and outputs PO template files, then merges
+translations from MO files to create translated XML files. It determines what
+to translate and how to chunk it into messages using the W3C
Internationalization
+Tag Set (ITS).
+
+To extract messages from XML files \fBFILES\fR and output them to
\fBOUT.pot\fR:
+
+\fBitstool -o OUT.pot FILES\fR
+
+After merging with existing translations or translating strings, generate an
+MO file with \fBmsgfmt(1)\fR, then output translated files to the directory
+\fBDIR\fR:
+
+\fBitstool -m OUT.mo -o DIR FILES\fR
+
+ITS definitions are loaded from the built-in rules, rules embedded in the
source
+XML files, files passed with the \fB-i\fR option, and ITS attributes in the
source
+XML files. Later definitions take precedence.
+
+.SH OPTIONS
+.SS "Extracting"
+.IP "\fB\-o \fIFILE\fR" 4
+.PD 0
+.IP "\fB\-\-out=\fIFILE \fR" 4
+.PD
+output PO template to the file
+.BR OUT
+.SS "Merging"
+.IP "\fB\-m \fIFILE\fR" 4
+.PD 0
+.IP "\fB\-\-merge=\fIFILE \fR" 4
+.PD
+merge from an MO file
+.BR FILE
+and output XML files
+.TP
+.IP "\fB\-l \fILANG\fR" 4
+.PD 0
+.IP "\fB\-\-lang=\fILANG \fR" 4
+.PD
+explicitly set the language code output to XML
+.TP
+.IP "\fB\-o \fIFILE\fR" 4
+.PD 0
+.IP "\fB\-\-out=\fIFILE \fR" 4
+.PD
+output XML files in the directory
+.BR OUT
+.SS "Common"
+.IP "\fB\-i \fIITS\fR" 4
+.PD 0
+.IP "\fB\-\-its=\fIITS \fR" 4
+.PD
+load the ITS rules in the file ITS (can specify
+multiple times)
+
+.SH AUTHOR
+Shaun McCance <shaunm@xxxxxxxxx>
+
+.SH "SEE ALSO"
+More documentation for
+.B itstool
+is maintained online. For more information, see:
+.IP
+.B http://itstool.org/documentation/
+.PP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh
old/itstool-1.0.1/itstool.1.in new/itstool-1.1.0/itstool.1.in
--- old/itstool-1.0.1/itstool.1.in 1970-01-01 01:00:00.000000000 +0100
+++ new/itstool-1.1.0/itstool.1.in 2011-05-09 22:24:10.000000000 +0200
@@ -0,0 +1,77 @@
+.TH ITSTOOL "1" "May 2011" "itstool @VERSION@"
+.SH NAME
+itstool \- convert between XML and PO using ITS
+
+.SH SYNOPSIS
+itstool [OPTIONS] [XMLFILES]
+.br
+itstool \fB\-m\fR <MOFILE> [OPTIONS] [XMLFILES]
+
+.SH DESCRIPTION
+.BR itstool
+extracts messages from XML files and outputs PO template files, then merges
+translations from MO files to create translated XML files. It determines what
+to translate and how to chunk it into messages using the W3C
Internationalization
+Tag Set (ITS).
+
+To extract messages from XML files \fBFILES\fR and output them to
\fBOUT.pot\fR:
+
+\fBitstool -o OUT.pot FILES\fR
+
+After merging with existing translations or translating strings, generate an
+MO file with \fBmsgfmt(1)\fR, then output translated files to the directory
+\fBDIR\fR:
+
+\fBitstool -m OUT.mo -o DIR FILES\fR
+
+ITS definitions are loaded from the built-in rules, rules embedded in the
source
+XML files, files passed with the \fB-i\fR option, and ITS attributes in the
source
+XML files. Later definitions take precedence.
+
+.SH OPTIONS
+.SS "Extracting"
+.IP "\fB\-o \fIFILE\fR" 4
+.PD 0
+.IP "\fB\-\-out=\fIFILE \fR" 4
+.PD
+output PO template to the file
+.BR OUT
+.SS "Merging"
+.IP "\fB\-m \fIFILE\fR" 4
+.PD 0
+.IP "\fB\-\-merge=\fIFILE \fR" 4
+.PD
+merge from an MO file
+.BR FILE
+and output XML files
+.TP
+.IP "\fB\-l \fILANG\fR" 4
+.PD 0
+.IP "\fB\-\-lang=\fILANG \fR" 4
+.PD
+explicitly set the language code output to XML
+.TP
+.IP "\fB\-o \fIFILE\fR" 4
+.PD 0
+.IP "\fB\-\-out=\fIFILE \fR" 4
+.PD
+output XML files in the directory
+.BR OUT
+.SS "Common"
+.IP "\fB\-i \fIITS\fR" 4
+.PD 0
+.IP "\fB\-\-its=\fIITS \fR" 4
+.PD
+load the ITS rules in the file ITS (can specify
+multiple times)
+
+.SH AUTHOR
+Shaun McCance <shaunm@xxxxxxxxx>
+
+.SH "SEE ALSO"
+More documentation for
+.B itstool
+is maintained online. For more information, see:
+.IP
+.B http://itstool.org/documentation/
+.PP
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh
old/itstool-1.0.1/itstool.in new/itstool-1.1.0/itstool.in
--- old/itstool-1.0.1/itstool.in 2011-05-03 18:48:24.000000000 +0200
+++ new/itstool-1.1.0/itstool.in 2011-06-26 18:25:36.000000000 +0200
@@ -1,6 +1,24 @@
-#!/usr/bin/env python
+#!/usr/bin/python -s
+#
+# Copyright (c) 2010-2011 Shaun McCance <shaunm@xxxxxxxxx>
+#
+# ITS Tool 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 3 of the License, or (at your
+# option) any later version.
+#
+# ITS Tool 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 ITS Tool; if not, write to the Free Software Foundation, 59 Temple
+# Place, Suite 330, Boston, MA 0211-1307 USA.
+#

VERSION="@VERSION@"
+DATADIR="@DATADIR@"

import gettext
import hashlib
@@ -91,7 +109,7 @@
out.write('"Content-Transfer-Encoding: 8bit\\n"\n')
out.write('\n')
for msg in msgs:
- out.write(msg.format())
+ out.write(msg.format().encode('utf-8'))
out.write('\n')


@@ -105,10 +123,15 @@
self._comments = []
self._preserve = False

+ def __repr__(self):
+ if self._empty:
+ return "Empty message"
+ return self.get_string()
+
class Placeholder (object):
def __init__ (self, node):
self.node = node
- self.name = node.name
+ self.name = unicode(node.name, 'utf-8')

def escape (self, text):
return text.replace('\\','\\\\').replace('"',
"\\\"").replace("\n","\\n").replace("\t","\\t")
@@ -116,6 +139,8 @@
def add_text (self, text):
if len(self._message) == 0 or not(isinstance(self._message[-1],
basestring)):
self._message.append('')
+ if not isinstance(text, unicode):
+ text = unicode(text, 'utf-8')
self._message[-1] += text.replace('&', '&amp;').replace('<',
'&lt;').replace('>', '&gt;')
if re.sub('\s+', ' ', text).strip() != '':
self._empty = False
@@ -128,8 +153,8 @@
def get_placeholder (self, name):
placeholder = 1
for holder in self._placeholders:
- holdername = '%s-%i' % (holder.name, placeholder)
- if holdername == name:
+ holdername = u'%s-%i' % (holder.name, placeholder)
+ if holdername == unicode(name, 'utf-8'):
return holder
placeholder += 1

@@ -155,7 +180,7 @@
if node.children is not None:
if len(self._message) == 0 or not(isinstance(self._message[-1],
basestring)):
self._message.append('')
- self._message[-1] += ('</%s>' % node.name)
+ self._message[-1] += (u'</%s>' % unicode(node.name, 'utf-8'))

def is_empty (self):
return self._empty
@@ -167,25 +192,28 @@
self._ctxt = ctxt

def add_source (self, source):
+ if not isinstance(source, unicode):
+ source = unicode(source, 'utf-8')
self._sources.append(source)

def get_sources (self):
return self._sources

def add_comment (self, comment):
- self._comments.append(comment)
+ if comment is not None:
+ self._comments.append(comment)

def get_comments (self):
return self._comments

def get_string (self):
- message = ''
+ message = u''
placeholder = 1
for msg in self._message:
if isinstance(msg, basestring):
message += msg
elif isinstance(msg, Message.Placeholder):
- message += '<_:%s-%i/>' % (msg.name, placeholder)
+ message += u'<_:%s-%i/>' % (msg.name, placeholder)
placeholder += 1
if not self._preserve:
message = re.sub('\s+', ' ', message).strip()
@@ -198,38 +226,47 @@
self._preserve = preserve

def format (self):
- ret = ''
+ ret = u''
for i in range(len(self._comments)):
if i != 0:
ret += '#.\n'
comment = self._comments[i]
- while len(comment) > 72:
- j = comment.rfind(' ', 0, 72)
- if j == -1:
- j = comment.find(' ')
- if j == -1:
- break
- ret += '#. %s\n' % comment[:j]
- comment = comment[j+1:]
- ret += '#. %s\n' % comment
+ if '\n' in comment:
+ doadd = False
+ for line in comment.split('\n'):
+ if line != '':
+ doadd = True
+ if not doadd:
+ continue
+ ret += u'#. %s\n' % line
+ else:
+ while len(comment) > 72:
+ j = comment.rfind(' ', 0, 72)
+ if j == -1:
+ j = comment.find(' ')
+ if j == -1:
+ break
+ ret += u'#. %s\n' % comment[:j]
+ comment = comment[j+1:]
+ ret += '#. %s\n' % comment
for source in self._sources:
- ret += '#: %s\n' % source
+ ret += u'#: %s\n' % source
if self._preserve:
- ret += '#, no-wrap\n'
+ ret += u'#, no-wrap\n'
if self._ctxt is not None:
- ret += 'msgctxt "%s"\n' % self._ctxt
+ ret += u'msgctxt "%s"\n' % self._ctxt
message = self.get_string()
if self._preserve:
- ret += 'msgid ""\n'
+ ret += u'msgid ""\n'
lines = message.split('\n')
for line, no in zip(lines, range(len(lines))):
if no == len(lines) - 1:
- ret += '"%s"\n' % self.escape(line)
+ ret += u'"%s"\n' % self.escape(line)
else:
- ret += '"%s\\n"\n' % self.escape(line)
+ ret += u'"%s\\n"\n' % self.escape(line)
else:
- ret += 'msgid "%s"\n' % self.escape(message)
- ret += 'msgstr ""\n'
+ ret += u'msgid "%s"\n' % self.escape(message)
+ ret += u'msgstr ""\n'
return ret


@@ -239,6 +276,12 @@
yield child
child = child.next

+def xml_attr_iter (node):
+ attr = node.get_properties()
+ while attr is not None:
+ yield attr
+ attr = attr.next
+
def xml_is_ns_name (node, ns, name):
if node.type != 'element':
return False
@@ -267,8 +310,7 @@
hctxt.replaceEntities(1)
hctxt.parseDocument()
self._localrules.append(hctxt.doc().getRootElement())
- else:
- self._localrules.append(child)
+ self._localrules.append(child)
pre_process(child)
pre_process(self._doc)
self._msgs = messages
@@ -276,6 +318,8 @@
self._its_within_text_nodes = {}
self._its_loc_notes = {}
self._itst_preserve_space_nodes = {}
+ self._itst_drop_nodes = {}
+ self._itst_contexts = {}
self._its_lang = {}
self._itst_lang_attr = {}
self._itst_credits = None
@@ -286,16 +330,39 @@
return
if xml_is_ns_name(rule, NS_ITS, 'translateRule'):
if rule.prop('selector') is not None:
- for node in xpath.xpathEval(rule.prop('selector')):
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
self._its_translate_nodes[node] = rule.prop('translate')
elif xml_is_ns_name(rule, NS_ITS, 'withinTextRule'):
if rule.prop('selector') is not None:
- for node in xpath.xpathEval(rule.prop('selector')):
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
self._its_within_text_nodes[node] = rule.prop('withinText')
elif xml_is_ns_name(rule, NS_ITST, 'preserveSpaceRule'):
if rule.prop('selector') is not None:
- for node in xpath.xpathEval(rule.prop('selector')):
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
self._itst_preserve_space_nodes[node] =
rule.prop('preserveSpace')
+ elif xml_is_ns_name(rule, NS_ITST, 'dropRule'):
+ if rule.prop('selector') is not None:
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
+ self._itst_drop_nodes[node] = rule.prop('drop')
+ elif xml_is_ns_name(rule, NS_ITST, 'contextRule'):
+ if rule.prop('selector') is not None:
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
+ if rule.hasProp('context'):
+ self._itst_contexts[node] = rule.prop('context')
+ elif rule.hasProp('contextPointer'):
+ try:
+ oldnode = xpath.contextNode()
+ except:
+ oldnode = None
+ xpath.setContextNode(node)
+ ctxt = self._try_xpath_eval(xpath,
rule.prop('contextPointer'))
+ if isinstance(ctxt, basestring):
+ self._itst_contexts[node] = ctxt
+ else:
+ for ctxt in ctxt:
+ self._itst_contexts[node] = ctxt.content
+ break
+ xpath.setContextNode(oldnode)
elif xml_is_ns_name(rule, NS_ITS, 'locNoteRule'):
locnote = None
for child in xml_child_iter(rule):
@@ -306,7 +373,7 @@
if rule.hasProp('locNoteRef'):
locnote = 'SEE: ' + re.sub('\s+', ' ',
rule.prop('locNoteRef')).strip()
if rule.prop('selector') is not None:
- for node in xpath.xpathEval(rule.prop('selector')):
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
if locnote is not None:
self._its_loc_notes[node] = locnote
else:
@@ -323,22 +390,29 @@
except:
oldnode = None
xpath.setContextNode(node)
- for note in xpath.xpathEval(sel):
- cont = re.sub('\s+', ' ', note.content).strip()
- if ref:
- cont = 'SEE: ' + cont
- self._its_loc_notes[node] = cont
- break
+ note = self._try_xpath_eval(xpath, sel)
+ if isinstance(note, basestring):
+ self._its_loc_notes[node] = note
+ else:
+ for note in note:
+ if self.get_preserve_space(note):
+ cont = note.content
+ else:
+ cont = re.sub('\s+', ' ',
note.content).strip()
+ if ref:
+ cont = 'SEE: ' + cont
+ self._its_loc_notes[node] = cont
+ break
xpath.setContextNode(oldnode)
elif xml_is_ns_name(rule, NS_ITS, 'langRule'):
if rule.prop('selector') is not None and rule.prop('langPointer')
is not None:
- for node in xpath.xpathEval(rule.prop('selector')):
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
try:
oldnode = xpath.contextNode()
except:
oldnode = None
xpath.setContextNode(node)
- res = xpath.xpathEval(rule.prop('langPointer'))
+ res = self._try_xpath_eval(xpath, rule.prop('langPointer'))
if len(res) > 0:
self._its_lang[node] = res[0].content
# We need to construct language attributes, not just read
@@ -350,18 +424,18 @@
xpath.setContextNode(oldnode)
elif xml_is_ns_name(rule, NS_ITST, 'credits'):
if rule.prop('appendTo') is not None:
- for node in xpath.xpathEval(rule.prop('appendTo')):
+ for node in self._try_xpath_eval(xpath, rule.prop('appendTo')):
self._itst_credits = (node, rule)
break
elif xml_is_ns_name(rule, NS_ITST, 'externalRefRule'):
if rule.prop('selector') is not None and rule.prop('refPointer')
is not None:
- for node in xpath.xpathEval(rule.prop('selector')):
+ for node in self._try_xpath_eval(xpath, rule.prop('selector')):
try:
oldnode = xpath.contextNode()
except:
oldnode = None
xpath.setContextNode(node)
- res = xpath.xpathEval(rule.prop('refPointer'))
+ res = self._try_xpath_eval(xpath, rule.prop('refPointer'))
if len(res) > 0:
self._itst_externals.append((node, res[0].content))
xpath.setContextNode(oldnode)
@@ -374,7 +448,9 @@
dirs.append(ddir)
ddir = os.getenv('XDG_DATA_DIRS', '')
if ddir == '':
- ddir = '/usr/local/share:/usr/share'
+ if DATADIR not in ('/usr/local/share', '/usr/share'):
+ ddir += DATADIR + ':'
+ ddir += '/usr/local/share:/usr/share'
dirs.extend(ddir.split(':'))
ddone = {}
for ddir in dirs:
@@ -410,7 +486,7 @@
nsdef = nsdef.next
par = par.parent
if match.hasProp('selector'):
- if len(xpath.xpathEval(match.prop('selector'))) > 0:
+ if len(self._try_xpath_eval(xpath,
match.prop('selector'))) > 0:
matched = True
break
if matched == False:
@@ -443,6 +519,8 @@
xpath = self._doc.xpathNewContext()
reg_ns(xpath, rules)
for rule in xml_child_iter(rules):
+ if rule.type != 'element':
+ continue
if rule.nsDefs() is not None:
rule_xpath = self._doc.xpathNewContent()
reg_ns(rule_xpath, rule)
@@ -503,16 +581,27 @@
node = self._doc.getRootElement()
if node is None or node.type != 'element':
return
+ if ((node.hasNsProp('drop', NS_ITST) and node.nsProp('drop', NS_ITST)
== 'yes') or
+ self._itst_drop_nodes.get(node, 'no') == 'yes'):
+ prev = node.prev
+ node.unlinkNode()
+ node.freeNode()
+ if prev.isBlankNode():
+ prev.unlinkNode()
+ prev.freeNode()
+ return
if is_root:
self.merge_credits(translations, language, node)
msg = self._msgs.get_message_by_node(node)
if msg is None:
+ self.translate_attrs(node, node)
children = [child for child in xml_child_iter(node)]
for child in children:
self.merge_translations(translations, language, node=child)
else:
newnode = self.get_translated(node, translations)
if newnode != node:
+ self.translate_attrs(node, newnode)
node.replaceNode(newnode)
if is_root:
# Apply language attributes to untranslated nodes. We don't do
@@ -556,11 +645,24 @@
fix_node_ns(child, childnsdefs)
fix_node_ns(node, {})

+ def translate_attrs(self, oldnode, newnode):
+ trans_attrs = [attr for attr in xml_attr_iter(oldnode) if
self._its_translate_nodes.get(attr, 'no') == 'yes']
+ for attr in trans_attrs:
+ newcontent = translations.ugettext(attr.get_content())
+ if newcontent:
+ newnode.setProp(attr.name,
translations.ugettext(attr.get_content()))
+
def get_translated (self, node, translations):
msg = self._msgs.get_message_by_node(node)
if msg is None:
return node
- trans = translations.ugettext(msg.get_string())
+ msgstr = msg.get_string()
+ # Dear Python, please implement pgettext.
+ # http://bugs.python.org/issue2504
+ # Sincerely, Shaun
+ if msg.get_context() is not None:
+ msgstr = msg.get_context() + '\x04' + msgstr
+ trans = translations.ugettext(msgstr)
if trans is None:
return node
nss = {}
@@ -585,7 +687,8 @@
ctxt.parseDocument()
trnode = ctxt.doc().getRootElement()
def scan_node(node):
- for child in xml_child_iter(node):
+ children = [child for child in xml_child_iter(node)]
+ for child in children:
if child.type != 'element':
continue
if child.ns() is not None and child.ns().content == NS_BLANK:
@@ -632,12 +735,17 @@
return
if node.type != 'element':
return
+ if node.hasNsProp('drop', NS_ITST) and node.nsProp('drop', NS_ITST) ==
'yes':
+ return
+ if self._itst_drop_nodes.get(node, 'no') == 'yes':
+ return
translate = self.get_its_translate(node)
if translate is None:
if self._in_translatable:
translate = 'yes'
else:
translate = 'no'
+ withinText = False
if translate == 'no':
if msg is not None:
msg.add_placeholder(node)
@@ -649,16 +757,35 @@
if msg is not None:
msg.add_placeholder(node)
msg = Message()
+ ctxt = None
+ if node.hasNsProp('context', NS_ITST):
+ ctxt = node.nsProp('context', NS_ITST)
+ if ctxt is None:
+ ctxt = self._itst_contexts.get(node)
+ if ctxt is not None:
+ msg.set_context(ctxt)
if self.get_preserve_space(node):
msg.set_preserve_space()
msg.add_source('%s:%i(%s/%s)' % (self._doc.name,
node.lineNo(), node.parent.name, node.name))
else:
+ withinText = True
msg.add_start_tag(node)

+ if not withinText:
+ # Add msg for translatable node attributes
+ for attr in xml_attr_iter(node):
+ if self._its_translate_nodes.get(attr, 'no') == 'yes':
+ attr_msg = Message()
+ attr_msg.add_source('%s:%i(%s/%s@%s)' % (
+ self._doc.name, node.lineNo(), node.parent.name,
node.name, attr.name))
+ attr_msg.add_text(attr.content)
+ if comments:
+ attr_msg.add_comment(self.get_its_loc_note(attr))
+ self._msgs.add_message(attr_msg, attr)
+
+
if comments and msg is not None:
- comment = self.get_its_loc_note(node)
- if comment is not None:
- msg.add_comment(comment)
+ msg.add_comment(self.get_its_loc_note(node))

in_translatable = self._in_translatable
self._in_translatable = (translate == 'yes')
@@ -710,6 +837,14 @@
return 'SEE: ' + re.sub('\s+', ' ',
node.prop('locNoteRef')).strip()
return self._its_loc_notes.get(node, None)

+ @staticmethod
+ def _try_xpath_eval (xpath, expr):
+ try:
+ return xpath.xpathEval(expr)
+ except:
+ sys.stderr.write('Warning: Invalid XPath: %s\n' % expr)
+ return []
+

_locale_pattern =
re.compile('([a-zA-Z0-9-]+)(_[A-Za-z0-9]+)?(@[A-Za-z0-9]+)?(\.[A-Za-z0-9]+)?')
def convert_locale (locale):
@@ -768,7 +903,7 @@
(opts, args) = options.parse_args(sys.argv)

if opts.version:
- print 'itstool ' + VERSION
+ print('itstool %s' % VERSION)
sys.exit(0)

if opts.merge is None:


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



Remember to have fun...

--
To unsubscribe, e-mail: opensuse-commit+unsubscribe@xxxxxxxxxxxx
For additional commands, e-mail: opensuse-commit+help@xxxxxxxxxxxx

< Previous Next >
This Thread
  • No further messages