home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / share / xml2po / docbook.py next >
Encoding:
Python Source  |  2006-08-07  |  7.6 KB  |  202 lines

  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) 2004 Danilo Segan <danilo@kvota.net>.
  3. #
  4. # This file is part of xml2po.
  5. #
  6. # xml2po is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # xml2po is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with xml2po; if not, write to the Free Software Foundation, Inc.,
  18. # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19. #
  20.  
  21. # This implements special instructions for handling DocBook XML documents
  22. # in a better way.
  23. #
  24. #  This means:
  25. #   ΓÇö better handling of nested complicated tags (i.e. definitions of
  26. #     ignored-tags and final-tags)
  27. #   ΓÇö support for merging translator-credits back into DocBook articles
  28. #   ΓÇö support for setting a language
  29. #
  30.  
  31. # We use "currentXmlMode" class name for all modes
  32. #  -- it might be better to have it named docbookXmlMode, but it will make loading harder;
  33. #     it is also not necessary until we start supporting extracting strings from more
  34. #     than one document type at the same time
  35. #
  36. import re
  37. import libxml2
  38. import os
  39. import md5
  40. import sys
  41.  
  42. class docbookXmlMode:
  43.     """Class for special handling of DocBook document types.
  44.  
  45.     It sets lang attribute on article elements, and adds translators
  46.     to articleinfo/copyright."""
  47.     def __init__(self):
  48.         self.lists = ['itemizedlist', 'orderedlist', 'variablelist',
  49.                       'segmentedlist', 'simplelist', 'calloutlist', 'varlistentry' ]
  50.         self.objects = [ 'figure', 'textobject', 'imageobject', 'mediaobject',
  51.                          'screenshot' ]
  52.         
  53.     def getIgnoredTags(self):
  54.         "Returns array of tags to be ignored."
  55.         return  self.objects + self.lists
  56.  
  57.     def getFinalTags(self):
  58.         "Returns array of tags to be considered 'final'."
  59.         return ['para', 'formalpara', 'simpara',
  60.                 'releaseinfo', 'revnumber', 'title',
  61.                 'date', 'term', 'programlisting'] + self.objects + self.lists
  62.  
  63.     def getSpacePreserveTags(self):
  64.         "Returns array of tags in which spaces are to be preserved."
  65.         return [
  66.             'classsynopsisinfo',
  67.             'computeroutput',
  68.             'funcsynopsisinfo',
  69.             'literallayout',
  70.             'programlisting',
  71.             'screen',
  72.             'synopsis',
  73.             'userinput'
  74.             ]
  75.  
  76.     def getStringForTranslators(self):
  77.         """Returns string which will be used to credit translators."""
  78.         return "translator-credits"
  79.  
  80.     def getCommentForTranslators(self):
  81.         """Returns a comment to be added next to string for crediting translators."""
  82.         return """Put one translator per line, in the form of NAME <EMAIL>, YEAR1, YEAR2."""
  83.  
  84.     def _find_articleinfo(self, node):
  85.         if node.name == 'articleinfo' or node.name == 'bookinfo':
  86.             return node
  87.         child = node.children
  88.         while child:
  89.             ret = self._find_articleinfo(child)
  90.             if ret:
  91.                 return ret
  92.             child = child.next
  93.         return None
  94.  
  95.     def _find_lastcopyright(self, node):
  96.         if not node.children:
  97.             return None
  98.         last = node.lastChild()
  99.         tmp = last
  100.         while tmp:
  101.             if tmp.name == "copyright":
  102.                 last = tmp
  103.                 break
  104.             tmp = tmp.prev
  105.         return last
  106.  
  107.     def _md5_for_file(self, filename):
  108.         hash = md5.new()
  109.         input = open(filename, "rb")
  110.         read = input.read(4096)
  111.         while read:
  112.             hash.update(read)
  113.             read = input.read(4096)
  114.         input.close()
  115.         return hash.hexdigest()
  116.  
  117.     def _output_images(self, node, msg):
  118.         if node and node.type=='element' and node.name=='imagedata':
  119.             # Use .fileref to construct new message
  120.             attr = node.prop("fileref")
  121.             if attr:
  122.                 dir = os.path.dirname(msg.filename)
  123.                 fullpath = os.path.join(dir, attr)
  124.                 if os.path.exists(fullpath):
  125.                     hash = self._md5_for_file(fullpath)
  126.                 else:
  127.                     hash = "THIS FILE DOESN'T EXIST"
  128.                     print >>sys.stderr, "Warning: image file '%s' not found." % fullpath
  129.                     
  130.                 msg.outputMessage("@@image: '%s'; md5=%s" % (attr, hash), node.lineNo(),
  131.                                   "When image changes, this message will be marked fuzzy or untranslated for you.\n"+
  132.                                   "It doesn't matter what you translate it to: it's not used at all.")
  133.         elif node and node.children:
  134.             child = node.children
  135.             while child:
  136.                 self._output_images(child,msg)
  137.                 child = child.next
  138.  
  139.  
  140.     def preProcessXml(self, doc, msg):
  141.         """Add additional messages of interest here."""
  142.         root = doc.getRootElement()
  143.         self._output_images(root,msg)
  144.  
  145.     def postProcessXmlTranslation(self, doc, language, translators):
  146.         """Sets a language and translators in "doc" tree.
  147.         
  148.         "translators" is a string consisted of "Name <email>, years" pairs
  149.         of each translator, separated by newlines."""
  150.  
  151.         root = doc.getRootElement()
  152.         # DocBook documents can be something other than article, handle that as well in the future
  153.         while root and root.name != 'article' and root.name != 'book':
  154.             root = root.next
  155.         if root and (root.name == 'article' or root.name == 'book'):
  156.             root.setProp('lang', language)
  157.         else:
  158.             return
  159.         
  160.         if translators == self.getStringForTranslators():
  161.             return
  162.         elif translators:
  163.             # Now, lets find 'articleinfo' (it can be something else, but this goes along with 'article')
  164.             ai = self._find_articleinfo(root)
  165.             if not ai:
  166.                 return
  167.  
  168.             # Now, lets do one translator at a time
  169.             lines = translators.split("\n")
  170.             for line in lines:
  171.                 line = line.strip()
  172.                 match = re.match(r"^([^<,]+)\s*(?:<([^>,]+)>)?,\s*(.*)$", line)
  173.                 if match:
  174.                     last = self._find_lastcopyright(ai)
  175.                     copy = libxml2.newNode("copyright")
  176.                     if last:
  177.                         copy = last.addNextSibling(copy)
  178.                     else:
  179.                         ai.addChild(copy)
  180.                     if match.group(3):
  181.                         copy.newChild(None, "year", match.group(3).encode('utf-8'))
  182.                     if match.group(1) and match.group(2):
  183.                         holder = match.group(1)+"(%s)" % match.group(2)
  184.                     elif match.group(1):
  185.                         holder = match.group(1)
  186.                     elif match.group(2):
  187.                         holder = match.group(2)
  188.                     else:
  189.                         holder = "???"
  190.                     copy.newChild(None, "holder", holder.encode('utf-8'))
  191.  
  192. # Perform some tests when ran standalone
  193. if __name__ == '__main__':
  194.     test = docbookXmlMode()
  195.     print "Ignored tags       : " + repr(test.getIgnoredTags())
  196.     print "Final tags         : " + repr(test.getFinalTags())
  197.     print "Space-preserve tags: " + repr(test.getSpacePreserveTags())
  198.  
  199.     print "Credits from string: '%s'" % test.getStringForTranslators()
  200.     print "Explanation for credits:\n\t'%s'" % test.getCommentForTranslators()
  201.     
  202.