[arch-commits] Commit in gimp-help/trunk (PKGBUILD gimp-help-2.10.0-python3.patch)
Fabio Castelli
muflone at archlinux.org
Sun Jun 27 18:38:56 UTC 2021
Date: Sunday, June 27, 2021 @ 18:38:55
Author: muflone
Revision: 967605
upgpkg: gimp-help 2.10.0-4
Added:
gimp-help/trunk/gimp-help-2.10.0-python3.patch
Modified:
gimp-help/trunk/PKGBUILD
--------------------------------+
PKGBUILD | 12
gimp-help-2.10.0-python3.patch | 975 +++++++++++++++++++++++++++++++++++++++
2 files changed, 983 insertions(+), 4 deletions(-)
Modified: PKGBUILD
===================================================================
--- PKGBUILD 2021-06-27 18:34:04 UTC (rev 967604)
+++ PKGBUILD 2021-06-27 18:38:55 UTC (rev 967605)
@@ -3,14 +3,16 @@
pkgbase=gimp-help
pkgver=2.10.0
-pkgrel=3
+pkgrel=4
arch=('any')
url='https://docs.gimp.org/'
license=('GPL' 'LGPL')
-makedepends=('python2' 'docbook-xsl')
+makedepends=('python' 'docbook-xsl')
options=(!strip !zipman)
-source=("https://ftp.gimp.org/pub/gimp/help/${pkgbase}-${pkgver}.tar.bz2")
-sha256sums=('03804fed071b49e5810edd8327868659dfd9932fbf34d34189d56bd0ad539118')
+source=("https://ftp.gimp.org/pub/gimp/help/${pkgbase}-${pkgver}.tar.bz2"
+ "gimp-help-2.10.0-python3.patch")
+sha256sums=('03804fed071b49e5810edd8327868659dfd9932fbf34d34189d56bd0ad539118'
+ '955a8599f6908b989252a63ea3227198ff9880f30fc254fccc5128a6a745d599')
_languages=(
'ca "Catalan"'
@@ -45,6 +47,8 @@
prepare() {
cd "${pkgbase}-${pkgver}"
sed -e '1s/python$/python2/' -i "tools/xml2po.py"
+ # Python 3 (FS#70078 https://bugs.archlinux.org/task/70078 )
+ patch -Np1 -i "${srcdir}/gimp-help-2.10.0-python3.patch"
}
build(){
Added: gimp-help-2.10.0-python3.patch
===================================================================
--- gimp-help-2.10.0-python3.patch (rev 0)
+++ gimp-help-2.10.0-python3.patch 2021-06-27 18:38:55 UTC (rev 967605)
@@ -0,0 +1,975 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jacob Boerema <jgboerema at gmail.com>
+Date: Thu, 4 Feb 2021 15:31:12 -0500
+Subject: [PATCH 1/3] tools: start migration to python3 by running 2to3
+
+(cherry picked from commit c5079e972d62858eead44c9029d276d456daf90d)
+---
+ tools/xml2po.py | 14 ++++++------
+ tools/xml2po/__init__.py | 40 +++++++++++++++++-----------------
+ tools/xml2po/modes/docbook.py | 20 ++++++++---------
+ tools/xml2po/modes/gimphelp.py | 14 ++++++------
+ 4 files changed, 44 insertions(+), 44 deletions(-)
+
+diff --git a/tools/xml2po.py b/tools/xml2po.py
+index 037e61f27..b3e110dc3 100755
+--- a/tools/xml2po.py
++++ b/tools/xml2po.py
+@@ -41,9 +41,9 @@ NULL_STRING = '/dev/null'
+ if not os.path.exists('/dev/null'): NULL_STRING = 'NUL'
+
+ def usage (with_help = False):
+- print >> sys.stderr, "Usage: %s [OPTIONS] [XMLFILE]..." % (sys.argv[0])
++ print("Usage: %s [OPTIONS] [XMLFILE]..." % (sys.argv[0]), file=sys.stderr)
+ if with_help:
+- print >> sys.stderr, """
++ print("""
+ OPTIONS may be some of:
+ -a --automatic-tags Automatically decides if tags are to be considered
+ "final" or not
+@@ -72,7 +72,7 @@ EXAMPLES:
+ using -p option for each XML file:
+ %(command)s -p de.po chapter1.xml > chapter1.de.xml
+ %(command)s -p de.po chapter2.xml > chapter2.de.xml
+-""" % {'command': sys.argv[0]}
++""" % {'command': sys.argv[0]}, file=sys.stderr)
+
+
+ def main(argv):
+@@ -148,7 +148,7 @@ def main(argv):
+ sys.exit(0)
+
+ if operation == 'update' and output != "-":
+- print >> sys.stderr, "Option '-o' is not yet supported when updating translations directly. Ignoring this option."
++ print("Option '-o' is not yet supported when updating translations directly. Ignoring this option.", file=sys.stderr)
+
+ # Treat remaining arguments as XML files
+ filenames = []
+@@ -158,16 +158,16 @@ def main(argv):
+ try:
+ xml2po_main = Main(default_mode, operation, output, options)
+ except IOError:
+- print >> sys.stderr, "Error: cannot open file %s for writing." % (output)
++ print("Error: cannot open file %s for writing." % (output), file=sys.stderr)
+ sys.exit(5)
+
+ if operation == 'merge':
+ if len(filenames) > 1:
+- print >> sys.stderr, "Error: You can merge translations with only one XML file at a time."
++ print("Error: You can merge translations with only one XML file at a time.", file=sys.stderr)
+ sys.exit(2)
+
+ if not mofile:
+- print >> sys.stderr, "Error: You must specify MO file when merging translations."
++ print("Error: You must specify MO file when merging translations.", file=sys.stderr)
+ sys.exit(3)
+
+ xml2po_main.merge(mofile, filenames[0])
+diff --git a/tools/xml2po/__init__.py b/tools/xml2po/__init__.py
+index eec197947..7a07eb226 100644
+--- a/tools/xml2po/__init__.py
++++ b/tools/xml2po/__init__.py
+@@ -86,14 +86,14 @@ class MessageOutput:
+ self.messages.append(t)
+ if spacepreserve:
+ self.nowrap[t] = True
+- if t in self.linenos.keys():
++ if t in list(self.linenos.keys()):
+ self.linenos[t].append((self.filename, tag, lineno))
+ else:
+ self.linenos[t] = [ (self.filename, tag, lineno) ]
+ if (not self.do_translations) and comment and not t in self.comments:
+ self.comments[t] = comment
+ else:
+- if t in self.linenos.keys():
++ if t in list(self.linenos.keys()):
+ self.linenos[t].append((self.filename, tag, lineno))
+ else:
+ self.linenos[t] = [ (self.filename, tag, lineno) ]
+@@ -166,7 +166,7 @@ class XMLDocument(object):
+ elif node.isText():
+ if node.isBlankNode():
+ if self.app.options.get('expand_entities') or \
+- (not (node.prev and not node.prev.isBlankNode() and node.next and not node.next.isBlankNode()) ):
++ (not (node.prev and not node.prev.isBlankNode() and node.__next__ and not node.next.isBlankNode()) ):
+ #print >>sys.stderr, "BLANK"
+ node.setContent('')
+ else:
+@@ -176,7 +176,7 @@ class XMLDocument(object):
+ child = node.children
+ while child:
+ self.normalizeNode(child)
+- child = child.next
++ child = child.__next__
+
+ def normalizeString(self, text, spacepreserve = False):
+ """Normalizes string to be used as key for gettext lookup.
+@@ -200,7 +200,7 @@ class XMLDocument(object):
+ tree = ctxt.doc()
+ newnode = tree.getRootElement()
+ except:
+- print >> sys.stderr, """Error while normalizing string as XML:\n"%s"\n""" % (text)
++ print("""Error while normalizing string as XML:\n"%s"\n""" % (text), file=sys.stderr)
+ return text
+
+ self.normalizeNode(newnode)
+@@ -209,7 +209,7 @@ class XMLDocument(object):
+ child = newnode.children
+ while child:
+ result += child.serialize('utf-8')
+- child = child.next
++ child = child.__next__
+
+ result = re.sub('^ ','', result)
+ result = re.sub(' $','', result)
+@@ -235,7 +235,7 @@ class XMLDocument(object):
+ ctxt.parseDocument()
+ tree = ctxt.doc()
+ if next:
+- newnode = tree.children.next
++ newnode = tree.children.__next__
+ else:
+ newnode = tree.children
+
+@@ -243,7 +243,7 @@ class XMLDocument(object):
+ child = newnode.children
+ while child:
+ result += child.serialize('utf-8')
+- child = child.next
++ child = child.__next__
+ tree.freeDoc()
+ return result
+
+@@ -262,7 +262,7 @@ class XMLDocument(object):
+ result += child.content.decode('utf-8')
+ else:
+ result += self.myAttributeSerialize(child)
+- child = child.next
++ child = child.__next__
+ else:
+ result = node.serialize('utf-8')
+ return result
+@@ -338,7 +338,7 @@ class XMLDocument(object):
+ pass
+
+ if not newnode:
+- print >> sys.stderr, """Error while parsing translation as XML:\n"%s"\n""" % (text.encode('utf-8'))
++ print("""Error while parsing translation as XML:\n"%s"\n""" % (text.encode('utf-8')), file=sys.stderr)
+ return
+
+ newelem = newnode.getRootElement()
+@@ -346,13 +346,13 @@ class XMLDocument(object):
+ if newelem and newelem.children:
+ free = node.children
+ while free:
+- next = free.next
++ next = free.__next__
+ free.unlinkNode()
+ free = next
+
+ if node:
+ copy = newelem.copyNodeList()
+- next = node.next
++ next = node.__next__
+ node.replaceNode(newelem.copyNodeList())
+ node.next = next
+
+@@ -377,7 +377,7 @@ class XMLDocument(object):
+ if child.isText() and child.content.strip() != '':
+ return True
+ else:
+- child = child.next
++ child = child.__next__
+ return False
+
+
+@@ -441,7 +441,7 @@ class XMLDocument(object):
+ outtxt += '<%s>%s</%s>' % (starttag, content, endtag)
+ else:
+ outtxt += self.doSerialize(child)
+- child = child.next
++ child = child.__next__
+
+ if self.app.operation == 'merge':
+ norm_outtxt = self.normalizeString(outtxt, self.app.isSpacePreserveNode(node))
+@@ -521,7 +521,7 @@ class XMLDocument(object):
+ outtxt = ''
+ while child:
+ outtxt += self.doSerialize(child)
+- child = child.next
++ child = child.__next__
+ return outtxt
+
+ def xml_error_handler(arg, ctxt):
+@@ -565,7 +565,7 @@ class Main(object):
+ try:
+ doc = XMLDocument(xmlfile, self)
+ except Exception as e:
+- print >> sys.stderr, "Unable to parse XML file '%s': %s" % (xmlfile, str(e))
++ print("Unable to parse XML file '%s': %s" % (xmlfile, str(e)), file=sys.stderr)
+ sys.exit(1)
+ self.current_mode.preProcessXml(doc.doc, self.msg)
+ doc.generate_messages()
+@@ -578,13 +578,13 @@ class Main(object):
+ try:
+ doc = XMLDocument(xmlfile, self)
+ except Exception as e:
+- print >> sys.stderr, str(e)
++ print(str(e), file=sys.stderr)
+ sys.exit(1)
+
+ try:
+ mfile = open(mofile, "rb")
+ except:
+- print >> sys.stderr, "Can't open MO file '%s'." % (mofile)
++ print("Can't open MO file '%s'." % (mofile), file=sys.stderr)
+ self.gt = gettext.GNUTranslations(mfile)
+ self.gt.add_fallback(NoneTranslations())
+ # Has preProcessXml use cases for merge?
+@@ -607,7 +607,7 @@ class Main(object):
+ try:
+ doc = XMLDocument(xmlfile, self)
+ except Exception as e:
+- print >> sys.stderr, str(e)
++ print(str(e), file=sys.stderr)
+ sys.exit(1)
+ doc.generate_messages()
+
+@@ -615,7 +615,7 @@ class Main(object):
+ try:
+ doc = XMLDocument(origxml, self)
+ except Exception as e:
+- print >> sys.stderr, str(e)
++ print(str(e), file=sys.stderr)
+ sys.exit(1)
+ doc.generate_messages()
+ self.output_po()
+diff --git a/tools/xml2po/modes/docbook.py b/tools/xml2po/modes/docbook.py
+index 276a9d9bb..5658ffc1a 100644
+--- a/tools/xml2po/modes/docbook.py
++++ b/tools/xml2po/modes/docbook.py
+@@ -43,7 +43,7 @@ try:
+ except ImportError:
+ from md5 import new as md5_new
+
+-from basic import basicXmlMode
++from .basic import basicXmlMode
+
+ class docbookXmlMode(basicXmlMode):
+ """Class for special handling of DocBook document types.
+@@ -95,7 +95,7 @@ class docbookXmlMode(basicXmlMode):
+ ret = self._find_articleinfo(child)
+ if ret:
+ return ret
+- child = child.next
++ child = child.__next__
+ return None
+
+ def _find_lastcopyright(self, node):
+@@ -131,7 +131,7 @@ class docbookXmlMode(basicXmlMode):
+ hash = self._md5_for_file(fullpath)
+ else:
+ hash = "THIS FILE DOESN'T EXIST"
+- print >>sys.stderr, "Warning: image file '%s' not found." % fullpath
++ print("Warning: image file '%s' not found." % fullpath, file=sys.stderr)
+
+ msg.outputMessage("@@image: '%s'; md5=%s" % (attr, hash), node.lineNo(),
+ "When image changes, this message will be marked fuzzy or untranslated for you.\n"+
+@@ -140,7 +140,7 @@ class docbookXmlMode(basicXmlMode):
+ child = node.children
+ while child:
+ self._output_images(child,msg)
+- child = child.next
++ child = child.__next__
+
+
+ def preProcessXml(self, doc, msg):
+@@ -157,7 +157,7 @@ class docbookXmlMode(basicXmlMode):
+ root = doc.getRootElement()
+ # DocBook documents can be something other than article, handle that as well in the future
+ while root and root.name != 'article' and root.name != 'book':
+- root = root.next
++ root = root.__next__
+ if root and (root.name == 'article' or root.name == 'book'):
+ root.setProp('lang', language)
+ else:
+@@ -198,10 +198,10 @@ class docbookXmlMode(basicXmlMode):
+ # Perform some tests when ran standalone
+ if __name__ == '__main__':
+ test = docbookXmlMode()
+- print "Ignored tags : " + repr(test.getIgnoredTags())
+- print "Final tags : " + repr(test.getFinalTags())
+- print "Space-preserve tags: " + repr(test.getSpacePreserveTags())
++ print("Ignored tags : " + repr(test.getIgnoredTags()))
++ print("Final tags : " + repr(test.getFinalTags()))
++ print("Space-preserve tags: " + repr(test.getSpacePreserveTags()))
+
+- print "Credits from string: '%s'" % test.getStringForTranslators()
+- print "Explanation for credits:\n\t'%s'" % test.getCommentForTranslators()
++ print("Credits from string: '%s'" % test.getStringForTranslators())
++ print("Explanation for credits:\n\t'%s'" % test.getCommentForTranslators())
+
+diff --git a/tools/xml2po/modes/gimphelp.py b/tools/xml2po/modes/gimphelp.py
+index 24d4154e6..d72f518ee 100644
+--- a/tools/xml2po/modes/gimphelp.py
++++ b/tools/xml2po/modes/gimphelp.py
+@@ -31,7 +31,7 @@ try:
+ except ImportError:
+ from md5 import new as md5_new
+
+-from docbook import docbookXmlMode
++from .docbook import docbookXmlMode
+
+ class gimphelpXmlMode(docbookXmlMode):
+ """Class for special handling of gimp-help DocBook document types.
+@@ -81,7 +81,7 @@ class gimphelpXmlMode(docbookXmlMode):
+ child = node.children
+ while child:
+ self._output_images(child,msg)
+- child = child.next
++ child = child.__next__
+
+ def preProcessXml(self, doc, msg):
+ """Add additional messages of interest here."""
+@@ -91,10 +91,10 @@ class gimphelpXmlMode(docbookXmlMode):
+ # Perform some tests when ran standalone
+ if __name__ == '__main__':
+ test = gimphelpXmlMode()
+- print "Ignored tags : " + repr(test.getIgnoredTags())
+- print "Final tags : " + repr(test.getFinalTags())
+- print "Space-preserve tags: " + repr(test.getSpacePreserveTags())
++ print("Ignored tags : " + repr(test.getIgnoredTags()))
++ print("Final tags : " + repr(test.getFinalTags()))
++ print("Space-preserve tags: " + repr(test.getSpacePreserveTags()))
+
+- print "Credits from string: '%s'" % test.getStringForTranslators()
+- print "Explanation for credits:\n\t'%s'" % test.getCommentForTranslators()
++ print("Credits from string: '%s'" % test.getStringForTranslators())
++ print("Explanation for credits:\n\t'%s'" % test.getCommentForTranslators())
+
+--
+2.29.2
+
+
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jacob Boerema <jgboerema at gmail.com>
+Date: Mon, 29 Mar 2021 17:51:48 -0400
+Subject: [PATCH 2/3] tools: complete port of xml2po to python3
+
+Also:
+- Let it work correctly on Windows by setting encoding for
+ stdout and stderr to utf-8.
+- Fix setting correct timezone in po files.
+- Better error handling.
+- Detect errors in tags in the translated xml text.
+
+(cherry picked from commit 299cfb7150857f0045ae42978d8ed917b4b0e4ff)
+---
+ tools/xml2po.py | 19 +++-
+ tools/xml2po/__init__.py | 189 +++++++++++++++++++++++++--------
+ tools/xml2po/modes/gimphelp.py | 2 +-
+ 3 files changed, 163 insertions(+), 47 deletions(-)
+
+diff --git a/tools/xml2po.py b/tools/xml2po.py
+index b3e110dc3..ef8d725da 100755
+--- a/tools/xml2po.py
++++ b/tools/xml2po.py
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env python2
++#!/usr/bin/env python3
+ # -*- encoding: utf-8 -*-
+ # Copyright (c) 2004, 2005, 2006 Danilo Šegan <danilo at gnome.org>.
+ # Copyright (c) 2009 Claude Paroz <claude at 2xlibre.net>.
+@@ -21,7 +21,7 @@
+ #
+
+ # xml2po -- translate XML documents
+-VERSION = "0.18.0 (patched by GIMP Documentation Team)"
++VERSION = "0.19.0 (patched by GIMP Documentation Team)"
+
+ # Versioning system (I use this for a long time, so lets explain it to
+ # those Linux-versioning-scheme addicts):
+@@ -37,11 +37,13 @@ import os
+ import getopt
+ import tempfile
+
++DEBUG_VERBOSITY = 0
++
+ NULL_STRING = '/dev/null'
+ if not os.path.exists('/dev/null'): NULL_STRING = 'NUL'
+
+ def usage (with_help = False):
+- print("Usage: %s [OPTIONS] [XMLFILE]..." % (sys.argv[0]), file=sys.stderr)
++ print(f"Usage: {sys.argv[0]} [OPTIONS] [XMLFILE]...", file=sys.stderr)
+ if with_help:
+ print("""
+ OPTIONS may be some of:
+@@ -86,6 +88,11 @@ def main(argv):
+
+ from xml2po import Main
+
++
++ # Make sure stdout and stderr output utf-8 even on Windows where it's not the default
++ sys.stdout = open(sys.stdout.fileno(), 'w', encoding='utf-8', closefd=False)
++ sys.stderr = open(sys.stderr.fileno(), 'w', encoding='utf-8', closefd=False)
++
+ # Default parameters
+ default_mode = 'docbook'
+ operation = 'pot' # 'pot', 'merge', 'update'
+@@ -136,6 +143,8 @@ def main(argv):
+ operation = 'merge'
+ if 'translationlanguage' not in options:
+ options['translationlanguage'] = os.path.split(os.path.splitext(pofile)[0])[1]
++ if DEBUG_VERBOSITY > 0:
++ print(f"Converting {pofile} to {mofile_tmppath} using msgfmt")
+ os.system("msgfmt -o %s %s >%s" % (mofile_tmppath, pofile, NULL_STRING)) and sys.exit(7)
+ mofile = mofile_tmppath
+ elif opt in ('-o', '--output'):
+@@ -170,6 +179,10 @@ def main(argv):
+ print("Error: You must specify MO file when merging translations.", file=sys.stderr)
+ sys.exit(3)
+
++ if DEBUG_VERBOSITY > 0:
++ print(f"Merge mo file {mofile} with {filenames[0]}")
++ if pofile:
++ xml2po_main.pofile = pofile
+ xml2po_main.merge(mofile, filenames[0])
+
+ elif operation == 'update':
+diff --git a/tools/xml2po/__init__.py b/tools/xml2po/__init__.py
+index 7a07eb226..42fa81f39 100644
+--- a/tools/xml2po/__init__.py
++++ b/tools/xml2po/__init__.py
+@@ -26,6 +26,7 @@ import tempfile
+ import gettext
+ import libxml2
+
++DEBUG_VERBOSITY = 0
+ NULL_STRING = '/dev/null'
+ if not os.path.exists('/dev/null'): NULL_STRING = 'NUL'
+
+@@ -86,14 +87,14 @@ class MessageOutput:
+ self.messages.append(t)
+ if spacepreserve:
+ self.nowrap[t] = True
+- if t in list(self.linenos.keys()):
++ if t in self.linenos.keys():
+ self.linenos[t].append((self.filename, tag, lineno))
+ else:
+ self.linenos[t] = [ (self.filename, tag, lineno) ]
+ if (not self.do_translations) and comment and not t in self.comments:
+ self.comments[t] = comment
+ else:
+- if t in list(self.linenos.keys()):
++ if t in self.linenos.keys():
+ self.linenos[t].append((self.filename, tag, lineno))
+ else:
+ self.linenos[t] = [ (self.filename, tag, lineno) ]
+@@ -101,7 +102,11 @@ class MessageOutput:
+ self.comments[t] = comment
+
+ def outputHeader(self, out):
+- import time
++ from datetime import datetime
++ # Using time.strftime was not working correctly for me: instead of a
++ # timezone offset a timezone name was added. This fixes it.
++ dt = datetime.now()
++ tz = dt.astimezone().tzinfo
+ out.write("""msgid ""
+ msgstr ""
+ "Project-Id-Version: PACKAGE VERSION\\n"
+@@ -113,7 +118,7 @@ msgstr ""
+ "Content-Type: text/plain; charset=UTF-8\\n"
+ "Content-Transfer-Encoding: 8bit\\n"
+
+-""" % (time.strftime("%Y-%m-%d %H:%M%z")))
++""" % (dt.astimezone(tz).strftime("%Y-%m-%d %H:%M%z")))
+
+ def outputAll(self, out):
+ self.outputHeader(out)
+@@ -138,6 +143,7 @@ msgstr ""
+
+ class XMLDocument(object):
+ def __init__(self, filename, app):
++ self.filename = filename
+ self.app = app
+ self.expand_entities = self.app.options.get('expand_entities')
+ self.ignored_tags = self.app.current_mode.getIgnoredTags()
+@@ -145,7 +151,13 @@ class XMLDocument(object):
+ ctxt.lineNumbers(1)
+ if self.app.options.get('expand_all_entities'):
+ ctxt.replaceEntities(1)
+- ctxt.parseDocument()
++
++ try:
++ ctxt.parseDocument()
++ except Exception as e:
++ print("Error parsing XML file '%s': %s" % (filename, str(e)), file=sys.stderr)
++ sys.exit(1)
++
+ self.doc = ctxt.doc()
+ if self.doc.name != filename:
+ raise Exception("Error: I tried to open '%s' but got '%s' -- how did that happen?" % (filename, self.doc.name))
+@@ -166,22 +178,23 @@ class XMLDocument(object):
+ elif node.isText():
+ if node.isBlankNode():
+ if self.app.options.get('expand_entities') or \
+- (not (node.prev and not node.prev.isBlankNode() and node.__next__ and not node.next.isBlankNode()) ):
+- #print >>sys.stderr, "BLANK"
++ (not (node.prev and not node.prev.isBlankNode() and node.next and not node.next.isBlankNode()) ):
+ node.setContent('')
+ else:
+- node.setContent(re.sub('\s+',' ', node.content))
++ node.setContent(re.sub(r'\s+',' ', node.content))
+
+ elif node.children and node.type == 'element':
+ child = node.children
+ while child:
++ nextchild = child.next
+ self.normalizeNode(child)
+- child = child.__next__
++ child = nextchild
+
+ def normalizeString(self, text, spacepreserve = False):
+ """Normalizes string to be used as key for gettext lookup.
+
+ Removes all unnecessary whitespace."""
++ mytext = text
+ if spacepreserve:
+ return text
+ try:
+@@ -203,13 +216,20 @@ class XMLDocument(object):
+ print("""Error while normalizing string as XML:\n"%s"\n""" % (text), file=sys.stderr)
+ return text
+
++ # Not sure if saving the doc here is really necessary. It was one of the
++ # things done in debugging and don't want to spend time now to check if
++ # we can remove it.
++ save_doc = self.doc
++ self.doc = ctxt.doc()
+ self.normalizeNode(newnode)
++ self.doc = save_doc
+
+ result = ''
+ child = newnode.children
+ while child:
++ nextchild = child.next
+ result += child.serialize('utf-8')
+- child = child.__next__
++ child = nextchild
+
+ result = re.sub('^ ','', result)
+ result = re.sub(' $','', result)
+@@ -235,15 +255,16 @@ class XMLDocument(object):
+ ctxt.parseDocument()
+ tree = ctxt.doc()
+ if next:
+- newnode = tree.children.__next__
++ newnode = tree.children.next
+ else:
+ newnode = tree.children
+
+ result = ''
+ child = newnode.children
+ while child:
++ nextchild = child.next
+ result += child.serialize('utf-8')
+- child = child.__next__
++ child = nextchild
+ tree.freeDoc()
+ return result
+
+@@ -252,6 +273,7 @@ class XMLDocument(object):
+ result = ''
+ if node.children:
+ child = node.children
++ nextchild = child.next
+ while child:
+ if child.type=='text':
+ result += self.doc.encodeEntitiesReentrant(child.content)
+@@ -262,7 +284,7 @@ class XMLDocument(object):
+ result += child.content.decode('utf-8')
+ else:
+ result += self.myAttributeSerialize(child)
+- child = child.__next__
++ child = nextchild
+ else:
+ result = node.serialize('utf-8')
+ return result
+@@ -308,11 +330,81 @@ class XMLDocument(object):
+ return None
+
+ def replaceAttributeContentsWithText(self, node, text):
+- node.setContent(text)
++ try:
++ node.setContent(text.decode('utf-8'))
++ except TypeError:
++ sys.stderr.write("--> replaceAttributeContentsWithText: Failed to decode text to utf-8.")
++ sys.exit(1)
++
++ def CheckMatchedTags(self, text):
++ stack = []
++ textblock = text
++
++ log=sys.stdout
++
++ # It might be even better to do the below with regex, see e.g.
++ # https://datadependence.com/2016/03/find-unclosed-tags-using-stacks/
++ # However I'm not sure it really matters that much since the text
++ # blocks usually are fairly small and most don't have a lot of tags.
++ start_tag = textblock.find('<')
++ while start_tag > -1:
++ textblock = textblock[start_tag+1:]
++ end_tag = textblock.find('>')
++ if end_tag > -1:
++ # Found left and right brackets: grab tag
++ tag = textblock[: end_tag]
++ # Check that it's not a tag that closes itself and comment tags starting with <!
++ if textblock[end_tag-1] != '/' and textblock[0] != '!':
++ # Tag can have multiple elements inside, watch for first space
++ space = tag.find(' ')
++ if space > -1:
++ tag = tag[: space]
++
++ open_tag = (len(tag) > 0 and tag[0] != '/')
++ if open_tag:
++ # Add tag to stack
++ stack.append(tag)
++ else:
++ tag = tag[1:]
++ if len(stack) == 0:
++ pass
++ else:
++ if stack[-1] == tag:
++ # Close the block
++ stack.pop()
++ else:
++ print(f"\n========================", file=log)
++ print(f"Source xml: {self.filename}", file=log)
++ print(f"Source po : {self.app.pofile}", file=log)
++ print(f"Translated msgstr:\n{text}\n", file=log)
++ print(f"WARNING: Found closing tag [{tag}], however we expected [{stack[0]}].", file=log)
++ print(f"Remaining tags: {str(stack)}", file=log)
++ if tag in stack:
++ stack.remove(tag)
++ print(" Assuming incorrect tag order, found and removed tag from the stack", file=log)
++ print(f"========================\n", file=log)
++ textblock = textblock[end_tag+1:]
++ start_tag = textblock.find('<')
++ else:
++ start_tag = -1
++
++
++ if len(stack):
++ print(f"\n========================", file=log)
++ print(f"Source xml: {self.filename}", file=log)
++ print(f"Source po : {self.app.pofile}", file=log)
++ print(f"ERROR: Found unmatched tags in po msgstr:\n{text}\n", file=log)
++ print(f"Tags not matched: {str(stack)}", file=log)
++ print(f"========================\n", file=log)
++ return False
++ return True
+
+ def replaceNodeContentsWithText(self, node, text):
+ """Replaces all subnodes of a node with contents of text treated as XML."""
+
++ if not self.CheckMatchedTags(text):
++ return
++
+ if node.children:
+ starttag = self.startTagForNode(node)
+ endtag = self.endTagForNode(node)
+@@ -326,7 +418,7 @@ class XMLDocument(object):
+ pass
+
+ content = '<%s>%s</%s>' % (starttag, text, endtag)
+- tmp = tmp + content.encode('utf-8')
++ tmp = tmp + content
+
+ newnode = None
+ try:
+@@ -338,7 +430,9 @@ class XMLDocument(object):
+ pass
+
+ if not newnode:
+- print("""Error while parsing translation as XML:\n"%s"\n""" % (text.encode('utf-8')), file=sys.stderr)
++ print(f"\n--> Error parsing translation as XML:\n{text}")
++ # See: https://gitlab.gnome.org/GNOME/libxml2/-/issues/64
++ print("--> Note: this might be caused by a bug in libxml2.\n")
+ return
+
+ newelem = newnode.getRootElement()
+@@ -346,15 +440,14 @@ class XMLDocument(object):
+ if newelem and newelem.children:
+ free = node.children
+ while free:
+- next = free.__next__
++ nextchild = free.next
+ free.unlinkNode()
+- free = next
++ free = nextchild
+
+ if node:
+- copy = newelem.copyNodeList()
+- next = node.__next__
++ nextnode = node.next
+ node.replaceNode(newelem.copyNodeList())
+- node.next = next
++ node.__next__ = nextnode
+
+ else:
+ # In practice, this happens with tags such as "<para> </para>" (only whitespace in between)
+@@ -374,10 +467,11 @@ class XMLDocument(object):
+ return True
+ child = node.children
+ while child:
++ nextchild = child.next
+ if child.isText() and child.content.strip() != '':
+ return True
+ else:
+- child = child.__next__
++ child = nextchild
+ return False
+
+
+@@ -432,6 +526,10 @@ class XMLDocument(object):
+
+ child = node.children
+ while child:
++ # Although I do not know why, child or child.next gets changed inside the if part below.
++ # This makes child.next fail when it shouldn't. That's why we store nextchild here
++ # before going into the if and use that at the end of the loop
++ nextchild = child.next
+ if (self.isFinalNode(child)) or (child.type == 'element' and self.worthOutputting(child)):
+ myrepl.append(self.processElementTag(child, myrepl, True))
+ outtxt += '<placeholder-%d/>' % (len(myrepl))
+@@ -441,20 +539,20 @@ class XMLDocument(object):
+ outtxt += '<%s>%s</%s>' % (starttag, content, endtag)
+ else:
+ outtxt += self.doSerialize(child)
+- child = child.__next__
++ child = nextchild
+
+ if self.app.operation == 'merge':
+ norm_outtxt = self.normalizeString(outtxt, self.app.isSpacePreserveNode(node))
+ translation = self.app.getTranslation(norm_outtxt)
+ else:
+- translation = outtxt.decode('utf-8')
++ translation = outtxt
+
+ starttag = self.startTagForNode(node)
+ endtag = self.endTagForNode(node)
+
+ worth = self.worthOutputting(node)
+ if not translation:
+- translation = outtxt.decode('utf-8')
++ translation = outtxt
+ if worth and self.app.options.get('mark_untranslated'):
+ node.setLang('C')
+
+@@ -463,7 +561,7 @@ class XMLDocument(object):
+ # repl[0] may contain translated attributes with
+ # non-ASCII chars, so implicit conversion to <str> may fail
+ replacement = '<%s>%s</%s>' % \
+- (repl[0].decode('utf-8'), repl[3], repl[2])
++ (repl[0], repl[3], repl[2])
+ translation = translation.replace('<placeholder-%d/>' % (i+1), replacement)
+
+ if worth:
+@@ -479,7 +577,7 @@ class XMLDocument(object):
+ def isExternalGeneralParsedEntity(self, node):
+ try:
+ # it would be nice if debugDumpNode could use StringIO, but it apparently cannot
+- tmp = tempfile.TemporaryFile()
++ tmp = tempfile.TemporaryFile(encoding='utf-8')
+ node.debugDumpNode(tmp,0)
+ tmp.seek(0)
+ tmpstr = tmp.read()
+@@ -507,25 +605,31 @@ class XMLDocument(object):
+ if self.isExternalGeneralParsedEntity(node):
+ return node.serialize('utf-8')
+ else:
+- return self.stringForEntity(node) #content #content #serialize("utf-8")
+- elif node.type == 'entity_decl':
++ return self.stringForEntity(node)
++ elif node.type == 'entity_decl --> serialize':
+ return node.serialize('utf-8') #'<%s>%s</%s>' % (startTagForNode(node), node.content, node.name)
+ elif node.type == 'text':
+- return node.serialize('utf-8')
++ nodetext = node.serialize('utf-8')
++ return nodetext
+ elif node.type == 'element':
+ repl = []
+ (starttag, content, endtag, translation) = self.processElementTag(node, repl, True)
+- return '<%s>%s</%s>' % (starttag, content, endtag)
++ return '<%s>%s</%s>' % (starttag, content.encode('utf-8'), endtag)
+ else:
+ child = node.children
+ outtxt = ''
+ while child:
++ # Not sure if the same problem with using next.child happens here too
++ # but we will use nextchild here too just to be sure
++ nextchild = child.next
+ outtxt += self.doSerialize(child)
+- child = child.__next__
++ child = nextchild
+ return outtxt
+
+-def xml_error_handler(arg, ctxt):
++def xml_error_handler(ctxt, error):
+ #deactivate error messages from the validation
++ if DEBUG_VERBOSITY > 0:
++ print(f"--> xml_error_handler: {error}")
+ pass
+
+ class Main(object):
+@@ -538,11 +642,11 @@ class Main(object):
+ self.current_mode = self.load_mode(mode)()
+ # Prepare output
+ if operation == 'update':
+- self.out = tempfile.TemporaryFile()
++ self.out = tempfile.TemporaryFile(encoding='utf-8')
+ elif output == '-':
+ self.out = sys.stdout
+ else:
+- self.out = file(output, 'w')
++ self.out = open(output, 'w', encoding='utf-8', buffering=1)
+
+ def load_mode(self, modename):
+ try:
+@@ -565,7 +669,7 @@ class Main(object):
+ try:
+ doc = XMLDocument(xmlfile, self)
+ except Exception as e:
+- print("Unable to parse XML file '%s': %s" % (xmlfile, str(e)), file=sys.stderr)
++ print("Error parsing XML file '%s': %s" % (xmlfile, str(e)), file=sys.stderr)
+ sys.exit(1)
+ self.current_mode.preProcessXml(doc.doc, self.msg)
+ doc.generate_messages()
+@@ -578,13 +682,13 @@ class Main(object):
+ try:
+ doc = XMLDocument(xmlfile, self)
+ except Exception as e:
+- print(str(e), file=sys.stderr)
++ print("Error parsing XML file '%s': %s" % (xmlfile, str(e)), file=sys.stderr)
+ sys.exit(1)
+-
+ try:
+ mfile = open(mofile, "rb")
+ except:
+- print("Can't open MO file '%s'." % (mofile), file=sys.stderr)
++ print("Error opening MO file '%s': %s." % (mofile, str(e)), file=sys.stderr)
++ sys.exit(1)
+ self.gt = gettext.GNUTranslations(mfile)
+ self.gt.add_fallback(NoneTranslations())
+ # Has preProcessXml use cases for merge?
+@@ -607,7 +711,7 @@ class Main(object):
+ try:
+ doc = XMLDocument(xmlfile, self)
+ except Exception as e:
+- print(str(e), file=sys.stderr)
++ print("Error parsing XML file '%s': %s" % (xmlfile, str(e)), file=sys.stderr)
+ sys.exit(1)
+ doc.generate_messages()
+
+@@ -615,7 +719,7 @@ class Main(object):
+ try:
+ doc = XMLDocument(origxml, self)
+ except Exception as e:
+- print(str(e), file=sys.stderr)
++ print("Error parsing XML file '%s': %s" % (origxml, str(e)), file=sys.stderr)
+ sys.exit(1)
+ doc.generate_messages()
+ self.output_po()
+@@ -646,11 +750,10 @@ class Main(object):
+
+ text should be a string to look for.
+ """
+- #print >>sys.stderr,"getTranslation('%s')" % (text.encode('utf-8'))
+ if not text or text.strip() == '':
+ return text
+ if self.gt:
+- res = self.gt.ugettext(text.decode('utf-8'))
++ res = self.gt.gettext(text)
+ return res
+
+ return text
+diff --git a/tools/xml2po/modes/gimphelp.py b/tools/xml2po/modes/gimphelp.py
+index d72f518ee..0e7e31c73 100644
+--- a/tools/xml2po/modes/gimphelp.py
++++ b/tools/xml2po/modes/gimphelp.py
+@@ -81,7 +81,7 @@ class gimphelpXmlMode(docbookXmlMode):
+ child = node.children
+ while child:
+ self._output_images(child,msg)
+- child = child.__next__
++ child = child.next
+
+ def preProcessXml(self, doc, msg):
+ """Add additional messages of interest here."""
+--
+2.29.2
+
+
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jacob Boerema <jgboerema at gmail.com>
+Date: Mon, 29 Mar 2021 17:55:35 -0400
+Subject: [PATCH 3/3] tools: also update docbook.py to python3.
+
+(cherry picked from commit b2d8952713245cbec4fef5b613b984549ca2b2fd)
+---
+ tools/xml2po/modes/docbook.py | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/tools/xml2po/modes/docbook.py b/tools/xml2po/modes/docbook.py
+index 5658ffc1a..ed395080e 100644
+--- a/tools/xml2po/modes/docbook.py
++++ b/tools/xml2po/modes/docbook.py
+@@ -95,7 +95,7 @@ class docbookXmlMode(basicXmlMode):
+ ret = self._find_articleinfo(child)
+ if ret:
+ return ret
+- child = child.__next__
++ child = child.next
+ return None
+
+ def _find_lastcopyright(self, node):
+@@ -140,7 +140,7 @@ class docbookXmlMode(basicXmlMode):
+ child = node.children
+ while child:
+ self._output_images(child,msg)
+- child = child.__next__
++ child = child.next
+
+
+ def preProcessXml(self, doc, msg):
+@@ -157,7 +157,7 @@ class docbookXmlMode(basicXmlMode):
+ root = doc.getRootElement()
+ # DocBook documents can be something other than article, handle that as well in the future
+ while root and root.name != 'article' and root.name != 'book':
+- root = root.__next__
++ root = root.next
+ if root and (root.name == 'article' or root.name == 'book'):
+ root.setProp('lang', language)
+ else:
+@@ -184,7 +184,7 @@ class docbookXmlMode(basicXmlMode):
+ else:
+ ai.addChild(copy)
+ if match.group(3):
+- copy.newChild(None, "year", match.group(3).encode('utf-8'))
++ copy.newChild(None, "year", match.group(3))
+ if match.group(1) and match.group(2):
+ holder = match.group(1)+"(%s)" % match.group(2)
+ elif match.group(1):
+@@ -193,7 +193,7 @@ class docbookXmlMode(basicXmlMode):
+ holder = match.group(2)
+ else:
+ holder = "???"
+- copy.newChild(None, "holder", holder.encode('utf-8'))
++ copy.newChild(None, "holder", holder)
+
+ # Perform some tests when ran standalone
+ if __name__ == '__main__':
+--
+2.31.1
+
More information about the arch-commits
mailing list