gimp-help-2 r2588 - in branches/xml2po-support: . tools
- From: ulfehlert svn gnome org
- To: svn-commits-list gnome org
- Subject: gimp-help-2 r2588 - in branches/xml2po-support: . tools
- Date: Thu, 23 Oct 2008 19:30:08 +0000 (UTC)
Author: ulfehlert
Date: Thu Oct 23 19:30:08 2008
New Revision: 2588
URL: http://svn.gnome.org/viewvc/gimp-help-2?rev=2588&view=rev
Log:
2008-10-23 Ulf-D. Ehlert <ulfehlert svn gnome org>
* Makefile.GNU: set width of pot files to 80; removed debugging code
* Makefile.am: set width of pot files to 80; minor simplification
* configure.ac: added gettext tools "msguniq" and "msgcat"
* tools/xmllang2en.sh: removed
* tools/migrate.sh: applied some changes
* tools/xml2po_for_gimp-help.patch1
* tools/xml2po: added script from gnome-doc-utils with above patch
applied to fix a placeholder bug; this patch is a slightly modified
version of the patch attached to bugreport #545478
Added:
branches/xml2po-support/tools/xml2po (contents, props changed)
branches/xml2po-support/tools/xml2po_for_gimp-help.patch1
Removed:
branches/xml2po-support/tools/xmllang2en.sh
Modified:
branches/xml2po-support/ChangeLog
branches/xml2po-support/Makefile.GNU
branches/xml2po-support/Makefile.am
branches/xml2po-support/configure.ac
branches/xml2po-support/tools/migrate.sh
Modified: branches/xml2po-support/Makefile.GNU
==============================================================================
--- branches/xml2po-support/Makefile.GNU (original)
+++ branches/xml2po-support/Makefile.GNU Thu Oct 23 19:30:08 2008
@@ -16,19 +16,23 @@
PO_LANGS = $(filter-out $(XML_LANG), $(LANGUAGES))
# Essential external programs and their default options
-XSLTPROC = $(fake) xsltproc
+XSLTPROC = xsltproc
XSLTFLAGS = --nonet
-XMLLINT = $(fake) xmllint
+XMLLINT = xmllint
XMLLINTFLAGS = --nonet -noout
-XML2PO = $(fake) xml2po
+XML2PO = tools/xml2po
-MSGINIT = $(fake) msginit
-MSGFMT = $(fake) msgfmt
-MSGMERGE = $(fake) msgmerge
+MSGUNIQ = msguniq
+MSGUNIQFLAGS =
+MSGCAT = msgcat
+MSGCATFLAGS = --width=80
+MSGINIT = msginit
MSGINITFLAGS = --no-translator
+MSGFMT = msgfmt
MSGFMTFLAGS = --check --use-fuzzy --statistics
+MSGMERGE = msgmerge
MSGMERGEFLAGS = --quiet --backup=none --update
# Simple commands
@@ -103,13 +107,6 @@
endif
endif
-# Testing & debugging
-ifeq ($(DEBUG),)
-fake =
-else
-fake = echo
-endif
-
#--------------------------------------------------------------#
# The main functions used to transform #
@@ -118,15 +115,20 @@
# (c) XML and PO files to XML files #
#--------------------------------------------------------------#
-# Create a PO-template
+# Create a PO-template (POT)
#
# Usage:
# $(call xml2pot,xml-file,pot-file)
# Parameters:
# $1 - original (untranslated) XML file
# $2 - POT template file containing translatable tags
-xml2pot = $(XML2PO) --output="$(2)" $(1) 2>&1 \
- | sed -e '/Warning: image file .* not found./d'
+#
+# Hint: Better don't use 'grep' for filtering-out the warning
+# messages, since grep's exit status is 1 if there is no match.
+xml2pot = ($(XML2PO) --output='-' "$(1)" \
+ | $(MSGUNIQ) $(MSGUNIQFLAGS) \
+ | $(MSGCAT) $(MSGCATFLAGS) - > "$(2)") 2>&1 \
+ | sed -e '/image file .* not found/d'
# Merge template (pot) and message catalog (po) or create a new catalog
#
@@ -263,8 +265,8 @@
$(xmlpodir)/en: $(XML_FILES)
$(cmd) src_dir=$$(cd $(srcdir)/$(xmldir) && pwd); \
poxml_dir=$(builddir)/$(xmlpodir); \
- test -d $${poxml_dir} || $(fake) $(mkdir_p) $${poxml_dir}; \
- test -d $${poxml_dir}/en || $(fake) $(ln_s) $${src_dir} $${poxml_dir}/en; \
+ test -d $${poxml_dir} || $(mkdir_p) $${poxml_dir}; \
+ test -d $${poxml_dir}/en || $(ln_s) $${src_dir} $${poxml_dir}/en; \
touch $@
Modified: branches/xml2po-support/Makefile.am
==============================================================================
--- branches/xml2po-support/Makefile.am (original)
+++ branches/xml2po-support/Makefile.am Thu Oct 23 19:30:08 2008
@@ -94,8 +94,10 @@
#### POT directories
-xml2pot = $(XML2PO) --output="$(2)" $(1) 2>&1 \
- | sed -e '/Warning: image file .* not found./d'
+xml2pot = ($(XML2PO) --output='-' "$(1)" \
+ | $(MSGUNIQ) $(MSGUNIQFLAGS) \
+ | $(MSGCAT) $(MSGCATFLAGS) - > "$(2)") 2>&1 \
+ | sed -e '/image file .* not found/d'
$(POT_FILES): $(potdir)/%.pot : $(xmldir)/%.xml
@@ -173,9 +175,7 @@
# Special case: en
en_XML_FILES = $(XML_FILES:$(xmldir)/%=$(xmlpodir)/en/%)
-$(en_XML_FILES): xmldir-en
-
-xmldir-en: $(xmlpodir)/en ;
+$(en_XML_FILES): $(xmlpodir)/en
# TODO: make relative link rather than absolute link(?)
$(xmlpodir)/en: $(XML_FILES)
@@ -187,8 +187,9 @@
# Targets suitable for command line
+
# Special case: en
-xml-en: xmldir-en
+xml-en: $(xmlpodir)/en ;
#### XML profiling
Modified: branches/xml2po-support/configure.ac
==============================================================================
--- branches/xml2po-support/configure.ac (original)
+++ branches/xml2po-support/configure.ac Thu Oct 23 19:30:08 2008
@@ -143,7 +143,7 @@
AM_CONDITIONAL(HAVE_XML2PO, test -n "$XML2PO")
-# Search for msgfmt, msginit, msgmerge
+# Search for gettext tools
AC_PATH_PROG(MSGFMT, msgfmt)
if test -z "$MSGFMT" && test "x$enable_build" = "xyes"; then
@@ -177,6 +177,23 @@
MSGMERGEFLAGS="--quiet --backup=none --update"
AC_SUBST(MSGMERGEFLAGS)
+
+AC_PATH_PROG(MSGUNIQ, msguniq)
+if test -z "$MSGUNIQ" && test "x$enable_build" = "xyes"; then
+ AC_MSG_ERROR([
+** Couldn't find msguniq(1). You will need it to build the help files.
+** See the file 'INSTALL' for more help.])
+fi
+
+
+AC_PATH_PROG(MSGCAT, msgcat)
+if test -z "$MSGCAT" && test "x$enable_build" = "xyes"; then
+ AC_MSG_ERROR([
+** Couldn't find msgcat(1). You will need it to build the help files.
+** See the file 'INSTALL' for more help.])
+fi
+
+
# Optionally allow xsltproc to access DTDs over the network
AC_ARG_ENABLE(network,
Modified: branches/xml2po-support/tools/migrate.sh
==============================================================================
--- branches/xml2po-support/tools/migrate.sh (original)
+++ branches/xml2po-support/tools/migrate.sh Thu Oct 23 19:30:08 2008
@@ -1,37 +1,37 @@
#!/bin/bash
-# This file is part of the gimp-help-2 project and is
-# Copyright 2008, Ulf-D. Ehlert, Roman Joost
-#
-# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
+# this script migrates the content from DocBook XML files to PO/GETTEXT
+# supported XML files ??!?!
+
+#LINGUAS="de en es fr it ko nl no pl ru sv"
+LINGUAS="de fr"
srcdir="src"
+oldsrcdir="oldsrc"
xmldir="xml"
potdir="pot"
podir="po"
-LINGUAS="de"
-SPLIT="/opt/python2.4/bin/python tools/split_xml_multi_lang.py"
+
+SPLIT="python tools/split_xml_multi_lang.py"
XML2PO="python tools/xml2po" # patched version!!
-XMLLANG2EN="tools/xmllang2en.sh -v"
-echo "Creating en_US ..."
-$XMLLANG2EN --srcdir=$srcdir --dstdir=en_US
+exclude_patterns='.svn key-reference* glossary dictionary'
+exclude=$(echo "$exclude_patterns" | \
+ sed -e 's/[^ ]\+/"&"/g; s/ / -o -name /g; s/^/\\( -name /; s/$/ \\) -prune /')
+
+# clean-up
+if [ -d "$oldsrcdir" ]; then
+ echo >&2 Removing $srcdir, $potdir, $podir, $xmldir, ...
+ test -L $xmldir/en && rm $xmldir/en
+ test -d $srcdir && rm -rf $srcdir
+ test -d $potdir && rm -rf $potdir
+ test -d $podir && rm -rf $podir
+ test -d $xmldir && rm -rf $xmldir
+ mv $oldsrcdir $srcdir
+fi
echo "Splitting the source XML"
time \
-find $srcdir -name .svn -prune -o -name '*.xml' -print |
+eval find $srcdir $exclude -o -name '*.xml' -print |
while read srcfile
do
base=${srcfile%/*}
@@ -41,7 +41,7 @@
done
echo
-srcdir=$xmldir/en
+mv -vi "$srcdir" "$oldsrcdir" && mv -vi "$xmldir"/en "$srcdir"
echo
@@ -55,7 +55,8 @@
dest=${potfile%/*}
test -d "$dest" || mkdir -p "$dest"
echo >&2 $potfile
- $XML2PO --output="$potfile" "$srcfile" 2>&1 | grep -vE 'image file .* not found'
+ #$XML2PO --output="$potfile" "$srcfile" 2>&1 | grep -vE 'image file .* not found'
+ ($XML2PO --output='-' "$srcfile" | msguniq | msgcat -w80 - > "$potfile") 2>&1 | grep -vE 'image file .* not found'
done
echo
@@ -72,8 +73,11 @@
dest=${pofile%/*}
test -d "$dest" || mkdir -p "$dest"
echo >&2 $pofile
- $XML2PO --language $lang --reuse=$xmlfile --output="$pofile" \
- "$srcfile" 2>&1 | grep -vE 'image file .* not found'
+ #$XML2PO --language $lang --reuse=$xmlfile --output="$pofile" \
+ # "$srcfile" 2>&1 | grep -vE 'image file .* not found'
+ ($XML2PO --language $lang --reuse=$xmlfile --output='-' \
+ "$srcfile" | msguniq | msgcat -w80 - > "$pofile") 2>&1 \
+ | grep -vE 'image file .* not found'
done
done
echo
Added: branches/xml2po-support/tools/xml2po
==============================================================================
--- (empty file)
+++ branches/xml2po-support/tools/xml2po Thu Oct 23 19:30:08 2008
@@ -0,0 +1,874 @@
+#!/usr/bin/python
+# -*- encoding: utf-8 -*-
+# Copyright (c) 2004, 2005, 2006 Danilo Åegan <danilo gnome org>.
+#
+# This file is part of xml2po.
+#
+# xml2po 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.
+#
+# xml2po 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 xml2po; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+# xml2po -- translate XML documents
+VERSION = "0.14.0"
+
+# Versioning system (I use this for a long time, so lets explain it to
+# those Linux-versioning-scheme addicts):
+# 1.0.* are unstable, development versions
+# 1.1 will be first stable release (release 1), and 1.1.* bugfix releases
+# 2.0.* will be unstable-feature-development stage (milestone 1)
+# 2.1.* unstable development betas (milestone 2)
+# 2.2 second stable release (release 2), and 2.2.* bugfix releases
+# ...
+#
+import sys
+import libxml2
+import gettext
+import os
+import re
+
+class NoneTranslations:
+ def gettext(self, message):
+ return None
+
+ def lgettext(self, message):
+ return None
+
+ def ngettext(self, msgid1, msgid2, n):
+ return None
+
+ def lngettext(self, msgid1, msgid2, n):
+ return None
+
+ def ugettext(self, message):
+ return None
+
+ def ungettext(self, msgid1, msgid2, n):
+ return None
+
+
+
+class MessageOutput:
+ def __init__(self, with_translations = 0):
+ self.messages = []
+ self.comments = {}
+ self.linenos = {}
+ self.nowrap = {}
+ if with_translations:
+ self.translations = []
+ self.do_translations = with_translations
+ self.output_msgstr = 0 # this is msgid mode for outputMessage; 1 is for msgstr mode
+
+ def translationsFollow(self):
+ """Indicate that what follows are translations."""
+ self.output_msgstr = 1
+
+ def setFilename(self, filename):
+ self.filename = filename
+
+ def outputMessage(self, text, lineno = 0, comment = None, spacepreserve = 0, tag = None):
+ """Adds a string to the list of messages."""
+ if (text.strip() != ''):
+ t = escapePoString(normalizeString(text, not spacepreserve))
+ if self.output_msgstr:
+ self.translations.append(t)
+ return
+
+ if self.do_translations or (not t in self.messages):
+ self.messages.append(t)
+ if spacepreserve:
+ self.nowrap[t] = 1
+ 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 self.linenos.keys():
+ self.linenos[t].append((self.filename, tag, lineno))
+ else:
+ self.linenos[t] = [ (self.filename, tag, lineno) ]
+ if comment and not t in self.comments:
+ self.comments[t] = comment
+
+ def outputHeader(self, out):
+ import time
+ out.write("""msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"POT-Creation-Date: %s\\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
+"Last-Translator: FULL NAME <EMAIL ADDRESS>\\n"
+"Language-Team: LANGUAGE <LL li org>\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+
+""" % (time.strftime("%Y-%m-%d %H:%M%z")))
+
+ def outputAll(self, out):
+ self.outputHeader(out)
+
+ for k in self.messages:
+ if k in self.comments:
+ out.write("#. %s\n" % (self.comments[k].replace("\n","\n#. ")))
+ references = ""
+ for reference in self.linenos[k]:
+ references += "%s:%d(%s) " % (reference[0], reference[2], reference[1])
+ out.write("#: %s\n" % (references))
+ if k in self.nowrap and self.nowrap[k]:
+ out.write("#, no-wrap\n")
+ out.write("msgid \"%s\"\n" % (k))
+ translation = ""
+ if self.do_translations:
+ if len(self.translations)>0:
+ translation = self.translations.pop(0)
+ if translation == k:
+ translation = ""
+ out.write("msgstr \"%s\"\n\n" % (translation))
+
+
+def normalizeNode(node):
+ #print >>sys.stderr, "<%s> (%s) [%s]" % (node.name, node.type, node.serialize('utf-8'))
+ if not node:
+ return
+ elif isSpacePreserveNode(node):
+ return
+ elif node.isText():
+ if node.isBlankNode():
+ if expand_entities or ( not (node.prev and not node.prev.isBlankNode()
+ and node.next and not node.next.isBlankNode()) ):
+ #print >>sys.stderr, "BLANK"
+ node.setContent('')
+ else:
+ node.setContent(re.sub('\s+',' ', node.content))
+
+ elif node.children and node.type == 'element':
+ child = node.children
+ while child:
+ normalizeNode(child)
+ child = child.next
+
+def normalizeString(text, ignorewhitespace = 1):
+ """Normalizes string to be used as key for gettext lookup.
+
+ Removes all unnecessary whitespace."""
+ if not ignorewhitespace:
+ return text
+ try:
+ # Lets add document DTD so entities are resolved
+ dtd = doc.intSubset()
+ tmp = dtd.serialize('utf-8')
+ tmp = tmp + '<norm>%s</norm>' % text
+ except:
+ tmp = '<norm>%s</norm>' % text
+
+ try:
+ ctxt = libxml2.createDocParserCtxt(tmp)
+ if expand_entities:
+ ctxt.replaceEntities(1)
+ ctxt.parseDocument()
+ tree = ctxt.doc()
+ newnode = tree.getRootElement()
+ except:
+ print >> sys.stderr, """Error while normalizing string as XML:\n"%s"\n""" % (text)
+ return text
+
+ normalizeNode(newnode)
+
+ result = ''
+ child = newnode.children
+ while child:
+ result += child.serialize('utf-8')
+ child = child.next
+
+ result = re.sub('^ ','', result)
+ result = re.sub(' $','', result)
+
+ return result
+
+def stringForEntity(node):
+ """Replaces entities in the node."""
+ text = node.serialize('utf-8')
+ try:
+ # Lets add document DTD so entities are resolved
+ dtd = node.doc.intSubset()
+ tmp = dtd.serialize('utf-8') + '<norm>%s</norm>' % text
+ next = 1
+ except:
+ tmp = '<norm>%s</norm>' % text
+ next = 0
+
+ ctxt = libxml2.createDocParserCtxt(tmp)
+ if expand_entities:
+ ctxt.replaceEntities(1)
+ ctxt.parseDocument()
+ tree = ctxt.doc()
+ if next:
+ newnode = tree.children.next
+ else:
+ newnode = tree.children
+
+ result = ''
+ child = newnode.children
+ while child:
+ result += child.serialize('utf-8')
+ child = child.next
+
+ return result
+
+
+def escapePoString(text):
+ return text.replace('\\','\\\\').replace('"', "\\\"").replace("\n","\\n").replace("\t","\\t")
+
+def unEscapePoString(text):
+ return text.replace('\\"', '"').replace('\\\\','\\')
+
+def getTranslation(text, spacepreserve = 0):
+ """Returns a translation via gettext for specified snippet.
+
+ text should be a string to look for, spacepreserve set to 1
+ when spaces should be preserved.
+ """
+ #print >>sys.stderr,"getTranslation('%s')" % (text.encode('utf-8'))
+ text = normalizeString(text, not spacepreserve)
+ if (text.strip() == ''):
+ return text
+ global gt
+ if gt:
+ res = gt.ugettext(text.decode('utf-8'))
+ return res
+
+ return text
+
+def myAttributeSerialize(node):
+ result = ''
+ if node.children:
+ child = node.children
+ while child:
+ if child.type=='text':
+ result += doc.encodeEntitiesReentrant(child.content)
+ elif child.type=='entity_ref':
+ if not expand_entities:
+ result += '&' + child.name + ';'
+ else:
+ result += child.content.decode('utf-8')
+ else:
+ result += myAttributeSerialize(child)
+ child = child.next
+ else:
+ result = node.serialize('utf-8')
+ return result
+
+def startTagForNode(node):
+ if not node:
+ return 0
+
+ result = node.name
+ params = ''
+ if node.properties:
+ for p in node.properties:
+ if p.type == 'attribute':
+ try:
+ nsprop = p.ns().name + ":" + p.name
+ except:
+ nsprop = p.name
+ params += " %s=\"%s\"" % (nsprop, myAttributeSerialize(p))
+ return result+params
+
+def endTagForNode(node):
+ if not node:
+ return 0
+
+ result = node.name
+ return result
+
+def isFinalNode(node):
+ if automatic:
+ auto = autoNodeIsFinal(node)
+ # Check if any of the parents is also autoNodeIsFinal,
+ # and if it is, don't consider this node a final one
+ parent = node.parent
+ while parent and auto:
+ auto = not autoNodeIsFinal(parent)
+ parent = parent.parent
+ return auto
+ #node.type =='text' or not node.children or
+ if node.type == 'element' and node.name in ultimate_tags:
+ return 1
+ elif node.children:
+ final_children = 1
+ child = node.children
+ while child and final_children:
+ if not child.isBlankNode() and child.type != 'comment' and not isFinalNode(child):
+ final_children = 0
+ child = child.next
+ if final_children:
+ return 1
+ return 0
+
+def ignoreNode(node):
+ if automatic:
+ if node.type in ('dtd', 'comment'):
+ return 1
+ else:
+ return 0
+ else:
+ if isFinalNode(node):
+ return 0
+ if node.name in ignored_tags or node.type in ('dtd', 'comment'):
+ return 1
+ return 0
+
+def isSpacePreserveNode(node):
+ pres = node.getSpacePreserve()
+ if pres == 1:
+ return 1
+ else:
+ if CurrentXmlMode and (node.name in CurrentXmlMode.getSpacePreserveTags()):
+ return 1
+ else:
+ return 0
+
+def getCommentForNode(node):
+ """Walk through previous siblings until a comment is found, or other element.
+
+ Only whitespace is allowed between comment and current node."""
+ prev = node.prev
+ while prev and prev.type == 'text' and prev.content.strip() == '':
+ prev = prev.prev
+ if prev and prev.type == 'comment':
+ return prev.content.strip()
+ else:
+ return None
+
+def replaceAttributeContentsWithText(node,text):
+ node.setContent(text)
+
+def replaceNodeContentsWithText(node,text):
+ """Replaces all subnodes of a node with contents of text treated as XML."""
+
+ if node.children:
+ starttag = startTagForNode(node)
+ endtag = endTagForNode(node)
+
+ # Lets add document DTD so entities are resolved
+ tmp = '<?xml version="1.0" encoding="utf-8" ?>'
+ try:
+ dtd = doc.intSubset()
+ tmp = tmp + dtd.serialize('utf-8')
+ except libxml2.treeError:
+ pass
+
+ content = '<%s>%s</%s>' % (starttag, text, endtag)
+ tmp = tmp + content.encode('utf-8')
+
+ newnode = None
+ try:
+ ctxt = libxml2.createDocParserCtxt(tmp)
+ ctxt.replaceEntities(0)
+ ctxt.parseDocument()
+ newnode = ctxt.doc()
+ except:
+ pass
+
+ if not newnode:
+ print >> sys.stderr, """Error while parsing translation as XML:\n"%s"\n""" % (text.encode('utf-8'))
+ return
+
+ newelem = newnode.getRootElement()
+
+ if newelem and newelem.children:
+ free = node.children
+ while free:
+ next = free.next
+ free.unlinkNode()
+ free = next
+
+ if node:
+ copy = newelem.copyNodeList()
+ next = node.next
+ node.replaceNode(newelem.copyNodeList())
+ node.next = next
+
+ else:
+ # In practice, this happens with tags such as "<para> </para>" (only whitespace in between)
+ pass
+ else:
+ node.setContent(text)
+
+def autoNodeIsFinal(node):
+ """Returns 1 if node is text node, contains non-whitespace text nodes or entities."""
+ if hasattr(node, '__autofinal__'):
+ return node.__autofinal__
+ if node.name in ignored_tags:
+ node.__autofinal__ = 0
+ return 0
+ if node.isText() and node.content.strip()!='':
+ node.__autofinal__ = 1
+ return 1
+ final = 0
+ child = node.children
+ while child:
+ if child.type in ['text'] and child.content.strip()!='':
+ final = 1
+ break
+ child = child.next
+
+ node.__autofinal__ = final
+ return final
+
+
+def worthOutputting(node):
+ """Whether or not a node is worth outputting
+
+ A node is "worth outputting", if the node itself or one of its
+ children is a text node -- unless the node is not final and there
+ is a parent node which is already worth outputting.
+
+ """
+ # TODO: rename "autoNodeIsFinal()"!
+ worth = autoNodeIsFinal(node) # is or has non-empty text node
+
+ # XXX: IMHO test for "ignored tags" should go to 'isFinalNode()'
+ if not (isFinalNode(node) or node.get_name() in ignored_tags):
+ parent = node.get_parent()
+ while worth and parent:
+ if worthOutputting(parent):
+ worth = False
+ else:
+ parent = parent.get_parent()
+
+ return worth
+
+def processAttribute(node, attr):
+ if not node or not attr or not worthOutputting(node):
+ return
+
+ outtxt = attr.content
+ if mode=='merge':
+ translation = getTranslation(outtxt, 0)
+ replaceAttributeContentsWithText(attr, translation.encode('utf-8'))
+ else:
+ msg.outputMessage(outtxt, node.lineNo(), "", 0,
+ node.name + ":" + attr.name)
+
+def processElementTag(node, replacements, restart = 0):
+ """Process node with node.type == 'element'."""
+ if node.type == 'element':
+ # Translate attributes if needed
+ if node.properties and len(treated_attributes):
+ for p in node.properties:
+ if p.name in treated_attributes:
+ processAttribute(node, p)
+
+ outtxt = ''
+ if restart:
+ myrepl = []
+ else:
+ myrepl = replacements
+
+ submsgs = []
+
+ child = node.children
+ while child:
+ if (isFinalNode(child)) or (child.type == 'element' and worthOutputting(child)):
+ myrepl.append(processElementTag(child, myrepl, 1))
+ outtxt += '<placeholder-%d/>' % (len(myrepl))
+ else:
+ if child.type == 'element':
+ (starttag, content, endtag, translation) = processElementTag(child, myrepl, 0)
+ outtxt += '<%s>%s</%s>' % (starttag, content, endtag)
+ else:
+ outtxt += doSerialize(child)
+
+ child = child.next
+
+ if mode == 'merge':
+ translation = getTranslation(outtxt, isSpacePreserveNode(node))
+ else:
+ translation = outtxt.decode('utf-8')
+
+ starttag = startTagForNode(node)
+ endtag = endTagForNode(node)
+
+ worth = worthOutputting(node)
+ if not translation:
+ translation = outtxt.decode('utf-8')
+ if worth and mark_untranslated: node.setLang('C')
+
+ if restart or worth:
+ i = 0
+ while i < len(myrepl):
+ replacement = '<%s>%s</%s>' % (myrepl[i][0], myrepl[i][3], myrepl[i][2])
+ i += 1
+ translation = translation.replace('<placeholder-%d/>' % (i), replacement)
+
+ if worth:
+ if mode == 'merge':
+ replaceNodeContentsWithText(node, translation)
+ else:
+ msg.outputMessage(outtxt, node.lineNo(), getCommentForNode(node), isSpacePreserveNode(node), tag = node.name)
+
+ return (starttag, outtxt, endtag, translation)
+ else:
+ raise Exception("You must pass node with node.type=='element'.")
+
+
+def isExternalGeneralParsedEntity(node):
+ if (node and node.type=='entity_ref'):
+ try:
+ # it would be nice if debugDumpNode could use StringIO, but it apparently cannot
+ tmp = file(".xml2po-entitychecking","w+")
+ node.debugDumpNode(tmp,0)
+ tmp.seek(0)
+ tmpstr = tmp.read()
+ tmp.close()
+ os.remove(".xml2po-entitychecking")
+ except:
+ # We fail silently, and replace all entities if we cannot
+ # write .xml2po-entitychecking
+ # !!! This is not very nice thing to do, but I don't know if
+ # raising an exception is any better
+ return 0
+ if tmpstr.find('EXTERNAL_GENERAL_PARSED_ENTITY') != -1:
+ return 1
+ else:
+ return 0
+ else:
+ return 0
+
+def doSerialize(node):
+ """Serializes a node and its children, emitting PO messages along the way.
+
+ node is the node to serialize, first indicates whether surrounding
+ tags should be emitted as well.
+ """
+
+ if ignoreNode(node):
+ return ''
+ elif not node.children:
+ return node.serialize("utf-8")
+ elif node.type == 'entity_ref':
+ if isExternalGeneralParsedEntity(node):
+ return node.serialize('utf-8')
+ else:
+ return stringForEntity(node) #content #content #serialize("utf-8")
+ elif node.type == 'entity_decl':
+ return node.serialize('utf-8') #'<%s>%s</%s>' % (startTagForNode(node), node.content, node.name)
+ elif node.type == 'text':
+ return node.serialize('utf-8')
+ elif node.type == 'element':
+ repl = []
+ (starttag, content, endtag, translation) = processElementTag(node, repl, 1)
+ return '<%s>%s</%s>' % (starttag, content, endtag)
+ else:
+ child = node.children
+ outtxt = ''
+ while child:
+ outtxt += doSerialize(child)
+ child = child.next
+ return outtxt
+
+
+def read_finaltags(filelist):
+ if CurrentXmlMode:
+ return CurrentXmlMode.getFinalTags()
+ else:
+ defaults = ['para', 'title', 'releaseinfo', 'revnumber',
+ 'date', 'itemizedlist', 'orderedlist',
+ 'variablelist', 'varlistentry', 'term' ]
+ return defaults
+
+def read_ignoredtags(filelist):
+ if CurrentXmlMode:
+ return CurrentXmlMode.getIgnoredTags()
+ else:
+ defaults = ['itemizedlist', 'orderedlist', 'variablelist',
+ 'varlistentry' ]
+ return defaults
+
+def read_treatedattributes(filelist):
+ if CurrentXmlMode:
+ return CurrentXmlMode.getTreatedAttributes()
+ else:
+ return []
+
+
+def tryToUpdate(allargs, lang):
+ # Remove "-u" and "--update-translation"
+ print >>sys.stderr, "OVDI!"
+ command = allargs[0]
+ args = allargs[1:]
+ opts, args = getopt.getopt(args, 'avhm:ket:o:p:u:',
+ ['automatic-tags','version', 'help', 'keep-entities', 'extract-all-entities', 'merge', 'translation=',
+ 'output=', 'po-file=', 'update-translation=' ])
+ for opt, arg in opts:
+ if opt in ('-a', '--automatic-tags'):
+ command += " -a"
+ elif opt in ('-k', '--keep-entities'):
+ command += " -k"
+ elif opt in ('-e', '--extract-all-entities'):
+ command += " -e"
+ elif opt in ('-m', '--mode'):
+ command += " -m %s" % arg
+ elif opt in ('-o', '--output'):
+ sys.stderr.write("Error: Option '-o' is not yet supported when updating translations directly.\n")
+ sys.exit(8)
+ elif opt in ('-v', '--version'):
+ print VERSION + " (patched by GIMP Documentation Team 2008-10-23)"
+ sys.exit(0)
+ elif opt in ('-h', '--help'):
+ sys.stderr.write("Error: If you want help, please use `%s --help' without '-u' option.\n" % (allargs[0]))
+ sys.exit(9)
+ elif opt in ('-u', '--update-translation'):
+ pass
+ else:
+ sys.stderr.write("Error: Option `%s' is not supported with option `-u'.\n" % (opt))
+ sys.exit(9)
+
+ while args:
+ command += " " + args.pop()
+
+ file = lang
+
+ sys.stderr.write("Merging translations for %s: " % (lang))
+ result = os.system("%s | msgmerge -o .tmp.%s.po %s -" % (command, lang, file))
+ if result:
+ sys.exit(10)
+ else:
+ result = os.system("mv .tmp.%s.po %s" % (lang, file))
+ if result:
+ sys.stderr.write("Error: cannot rename file.\n")
+ sys.exit(11)
+ else:
+ os.system("msgfmt -cv -o %s %s" % (NULL_STRING, file))
+ sys.exit(0)
+
+def load_mode(modename):
+ #import imp
+ #found = imp.find_module(modename, submodes_path)
+ #module = imp.load_module(modename, found[0], found[1], found[2])
+ try:
+ sys.path.append(submodes_path)
+ module = __import__(modename)
+ modeModule = '%sXmlMode' % modename
+ return getattr(module, modeModule)
+ except:
+ return None
+
+def xml_error_handler(arg, ctxt):
+ pass
+
+libxml2.registerErrorHandler(xml_error_handler, None)
+
+
+# Main program start
+if __name__ != '__main__': raise NotImplementedError
+
+# Parameters
+submodes_path = "/usr/share/xml2po"
+default_mode = 'docbook'
+
+filename = ''
+origxml = ''
+mofile = ''
+gt = None
+ultimate = [ ]
+ignored = [ ]
+filenames = [ ]
+translationlanguage = ''
+
+mode = 'pot' # 'pot' or 'merge'
+automatic = 0
+expand_entities = 1
+mark_untranslated = 0
+expand_all_entities = 0
+
+output = '-' # this means to stdout
+
+NULL_STRING = '/dev/null'
+if not os.path.exists('/dev/null'): NULL_STRING = 'NUL'
+
+import getopt, fileinput
+
+def usage (with_help = False):
+ print >> sys.stderr, "Usage: %s [OPTIONS] [XMLFILE]..." % (sys.argv[0])
+ if (with_help):
+ print >> sys.stderr, """
+OPTIONS may be some of:
+ -a --automatic-tags Automatically decides if tags are to be considered
+ "final" or not
+ -k --keep-entities Don't expand entities
+ -e --expand-all-entities Expand ALL entities (including SYSTEM ones)
+ -m --mode=TYPE Treat tags as type TYPE (default: docbook)
+ -o --output=FILE Print resulting text (XML or POT) to FILE
+ -p --po-file=FILE Specify PO file containing translation, and merge
+ Overwrites temporary file .xml2po.mo.
+ -r --reuse=FILE Specify translated XML file with the same structure
+ -t --translation=FILE Specify MO file containing translation, and merge
+ -u --update-translation=LANG.po Updates a PO file using msgmerge program
+
+ -l --language=LANG Set language of the translation to LANG
+ --mark-untranslated Set 'xml:lang="C"' on untranslated tags
+
+ -v --version Output version of the xml2po program
+
+ -h --help Output this message
+
+EXAMPLES:
+ To create a POTemplate book.pot from input files chapter1.xml and
+ chapter2.xml, run the following:
+ %s -o book.pot chapter1.xml chapter2.xml
+
+ After translating book.pot into de.po, merge the translations back,
+ using -p option for each XML file:
+ %s -p de.po chapter1.xml > chapter1.de.xml
+ %s -p de.po chapter2.xml > chapter2.de.xml
+""" % (sys.argv[0], sys.argv[0], sys.argv[0])
+ sys.exit(0)
+
+if len(sys.argv) < 2: usage()
+
+args = sys.argv[1:]
+try: opts, args = getopt.getopt(args, 'avhkem:t:o:p:u:r:l:',
+ ['automatic-tags','version', 'help', 'keep-entities', 'expand-all-entities', 'mode=', 'translation=',
+ 'output=', 'po-file=', 'update-translation=', 'reuse=', 'language=', 'mark-untranslated' ])
+except getopt.GetoptError: usage(True)
+
+for opt, arg in opts:
+ if opt in ('-m', '--mode'):
+ default_mode = arg
+ if opt in ('-a', '--automatic-tags'):
+ automatic = 1
+ elif opt in ('-k', '--keep-entities'):
+ expand_entities = 0
+ elif opt in ('--mark-untranslated',):
+ mark_untranslated = 1
+ elif opt in ('-e', '--expand-all-entities'):
+ expand_all_entities = 1
+ elif opt in ('-l', '--language'):
+ translationlanguage = arg
+ elif opt in ('-t', '--translation'):
+ mofile = arg
+ mode = 'merge'
+ if translationlanguage == '': translationlanguage = os.path.split(os.path.splitext(mofile)[0])[1]
+ elif opt in ('-r', '--reuse'):
+ origxml = arg
+ elif opt in ('-u', '--update-translation'):
+ tryToUpdate(sys.argv, arg)
+ elif opt in ('-p', '--po-file'):
+ mofile = ".xml2po.mo"
+ pofile = arg
+ if translationlanguage == '': translationlanguage = os.path.split(os.path.splitext(pofile)[0])[1]
+ os.system("msgfmt -o %s %s >%s" % (mofile, pofile, NULL_STRING)) and sys.exit(7)
+ mode = 'merge'
+ elif opt in ('-o', '--output'):
+ output = arg
+ elif opt in ('-v', '--version'):
+ print VERSION
+ sys.exit(0)
+ elif opt in ('-h', '--help'):
+ usage(True)
+
+# Treat remaining arguments as XML files
+while args:
+ filenames.append(args.pop())
+
+if len(filenames) > 1 and mode=='merge':
+ print >> sys.stderr, "Error: You can merge translations with only one XML file at a time."
+ sys.exit(2)
+
+try:
+ CurrentXmlMode = load_mode(default_mode)()
+except:
+ CurrentXmlMode = None
+ print >> sys.stderr, "Warning: cannot load module '%s', using automatic detection (-a)." % (default_mode)
+ automatic = 1
+
+if mode=='merge' and mofile=='':
+ print >> sys.stderr, "Error: You must specify MO file when merging translations."
+ sys.exit(3)
+
+if mofile:
+ try:
+ mfile = open(mofile, "rb")
+
+ gt = gettext.GNUTranslations(mfile)
+ gt.add_fallback(NoneTranslations())
+ except:
+ print >> sys.stderr, "Can't open MO file '%s'." % (mofile)
+
+ultimate_tags = read_finaltags(ultimate)
+ignored_tags = read_ignoredtags(ignored)
+treated_attributes = read_treatedattributes(ignored)
+
+# I'm not particularly happy about making any of these global,
+# but I don't want to bother too much with it right now
+semitrans = {}
+PlaceHolder = 0
+if origxml == '':
+ msg = MessageOutput()
+else:
+ filenames.append(origxml)
+ msg = MessageOutput(1)
+
+for filename in filenames:
+ try:
+ if filename == origxml:
+ msg.translationsFollow()
+ ctxt = libxml2.createFileParserCtxt(filename)
+ ctxt.lineNumbers(1)
+ if expand_all_entities:
+ ctxt.replaceEntities(1)
+ ctxt.parseDocument()
+ doc = ctxt.doc()
+ if doc.name != filename:
+ print >> sys.stderr, "Error: I tried to open '%s' but got '%s' -- how did that happen?" % (filename, doc.name)
+ sys.exit(4)
+ except:
+ print >> sys.stderr, "Error: cannot open file '%s'." % (filename)
+ sys.exit(1)
+
+ msg.setFilename(filename)
+ if CurrentXmlMode and origxml=='':
+ CurrentXmlMode.preProcessXml(doc,msg)
+ doSerialize(doc)
+
+if output == '-':
+ out = sys.stdout
+else:
+ try:
+ out = file(output, 'w')
+ except:
+ print >> sys.stderr, "Error: cannot open file %s for writing." % (output)
+ sys.exit(5)
+
+if mode != 'merge':
+ if CurrentXmlMode:
+ tcmsg = CurrentXmlMode.getStringForTranslators()
+ tccom = CurrentXmlMode.getCommentForTranslators()
+ if tcmsg:
+ msg.outputMessage(tcmsg, 0, tccom)
+
+ msg.outputAll(out)
+else:
+ if CurrentXmlMode:
+ tcmsg = CurrentXmlMode.getStringForTranslators()
+ if tcmsg:
+ outtxt = getTranslation(tcmsg)
+ else:
+ outtxt = ''
+ CurrentXmlMode.postProcessXmlTranslation(doc, translationlanguage, outtxt)
+ out.write(doc.serialize('utf-8', 1))
Added: branches/xml2po-support/tools/xml2po_for_gimp-help.patch1
==============================================================================
--- (empty file)
+++ branches/xml2po-support/tools/xml2po_for_gimp-help.patch1 Thu Oct 23 19:30:08 2008
@@ -0,0 +1,70 @@
+--- xml2po 2008-10-11 14:10:16.000000000 +0200
++++ xml2po 2008-10-23 20:00:00.000000000 +0200
+@@ -430,39 +430,30 @@
+ return final
+
+
+-def worthOutputting(node, noauto = 0):
+- """Returns 1 if node is "worth outputting", otherwise 0.
++def worthOutputting(node):
++ """Whether or not a node is worth outputting
++
++ A node is "worth outputting", if the node itself or one of its
++ children is a text node -- unless the node is not final and there
++ is a parent node which is already worth outputting.
+
+- Node is "worth outputting", if none of the parents
+- isFinalNode, and it contains non-blank text and entities.
+ """
+- if noauto and hasattr(node, '__worth__'):
+- return node.__worth__
+- elif not noauto and hasattr(node, '__autoworth__'):
+- return node.__autoworth__
+- worth = 1
+- parent = node.parent
+- final = isFinalNode(node) and node.name not in ignored_tags
+- while not final and parent:
+- if isFinalNode(parent):
+- final = 1 # reset if we've got to one final tag
+- if final and (parent.name not in ignored_tags) and worthOutputting(parent):
+- worth = 0
+- break
+- parent = parent.parent
+- if not worth:
+- node.__worth__ = 0
+- return 0
++ # TODO: rename "autoNodeIsFinal()"!
++ worth = autoNodeIsFinal(node) # is or has non-empty text node
+
+- if noauto:
+- node.__worth__ = worth
+- return worth
+- else:
+- node.__autoworth__ = autoNodeIsFinal(node)
+- return node.__autoworth__
++ # XXX: IMHO test for "ignored tags" should go to 'isFinalNode()'
++ if not (isFinalNode(node) or node.get_name() in ignored_tags):
++ parent = node.get_parent()
++ while worth and parent:
++ if worthOutputting(parent):
++ worth = False
++ else:
++ parent = parent.get_parent()
++
++ return worth
+
+ def processAttribute(node, attr):
+- if not node or not attr or not worthOutputting(node=node, noauto=1):
++ if not node or not attr or not worthOutputting(node):
+ return
+
+ outtxt = attr.content
+@@ -636,7 +627,7 @@
+ sys.stderr.write("Error: Option '-o' is not yet supported when updating translations directly.\n")
+ sys.exit(8)
+ elif opt in ('-v', '--version'):
+- print VERSION
++ print VERSION + " (patched by GIMP Documentation Team 2008-10-23)"
+ sys.exit(0)
+ elif opt in ('-h', '--help'):
+ sys.stderr.write("Error: If you want help, please use `%s --help' without '-u' option.\n" % (allargs[0]))
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]