home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / share / xml2po / docbook.py next >
Encoding:
Python Source  |  2007-04-09  |  7.7 KB  |  206 lines

  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) 2004, 2005, 2006 Danilo Segan <danilo@gnome.org>.
  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 getTreatedAttributes(self):
  77.         "Returns array of tag attributes which content is to be translated"
  78.         return []
  79.  
  80.     def getStringForTranslators(self):
  81.         """Returns string which will be used to credit translators."""
  82.         return "translator-credits"
  83.  
  84.     def getCommentForTranslators(self):
  85.         """Returns a comment to be added next to string for crediting translators."""
  86.         return """Put one translator per line, in the form of NAME <EMAIL>, YEAR1, YEAR2."""
  87.  
  88.     def _find_articleinfo(self, node):
  89.         if node.name == 'articleinfo' or node.name == 'bookinfo':
  90.             return node
  91.         child = node.children
  92.         while child:
  93.             ret = self._find_articleinfo(child)
  94.             if ret:
  95.                 return ret
  96.             child = child.next
  97.         return None
  98.  
  99.     def _find_lastcopyright(self, node):
  100.         if not node.children:
  101.             return None
  102.         last = node.lastChild()
  103.         tmp = last
  104.         while tmp:
  105.             if tmp.name == "copyright":
  106.                 last = tmp
  107.                 break
  108.             tmp = tmp.prev
  109.         return last
  110.  
  111.     def _md5_for_file(self, filename):
  112.         hash = md5.new()
  113.         input = open(filename, "rb")
  114.         read = input.read(4096)
  115.         while read:
  116.             hash.update(read)
  117.             read = input.read(4096)
  118.         input.close()
  119.         return hash.hexdigest()
  120.  
  121.     def _output_images(self, node, msg):
  122.         if node and node.type=='element' and node.name=='imagedata':
  123.             # Use .fileref to construct new message
  124.             attr = node.prop("fileref")
  125.             if attr:
  126.                 dir = os.path.dirname(msg.filename)
  127.                 fullpath = os.path.join(dir, attr)
  128.                 if os.path.exists(fullpath):
  129.                     hash = self._md5_for_file(fullpath)
  130.                 else:
  131.                     hash = "THIS FILE DOESN'T EXIST"
  132.                     print >>sys.stderr, "Warning: image file '%s' not found." % fullpath
  133.                     
  134.                 msg.outputMessage("@@image: '%s'; md5=%s" % (attr, hash), node.lineNo(),
  135.                                   "When image changes, this message will be marked fuzzy or untranslated for you.\n"+
  136.                                   "It doesn't matter what you translate it to: it's not used at all.")
  137.         elif node and node.children:
  138.             child = node.children
  139.             while child:
  140.                 self._output_images(child,msg)
  141.                 child = child.next
  142.  
  143.  
  144.     def preProcessXml(self, doc, msg):
  145.         """Add additional messages of interest here."""
  146.         root = doc.getRootElement()
  147.         self._output_images(root,msg)
  148.  
  149.     def postProcessXmlTranslation(self, doc, language, translators):
  150.         """Sets a language and translators in "doc" tree.
  151.         
  152.         "translators" is a string consisted of "Name <email>, years" pairs
  153.         of each translator, separated by newlines."""
  154.  
  155.         root = doc.getRootElement()
  156.         # DocBook documents can be something other than article, handle that as well in the future
  157.         while root and root.name != 'article' and root.name != 'book':
  158.             root = root.next
  159.         if root and (root.name == 'article' or root.name == 'book'):
  160.             root.setProp('lang', language)
  161.         else:
  162.             return
  163.         
  164.         if translators == self.getStringForTranslators():
  165.             return
  166.         elif translators:
  167.             # Now, lets find 'articleinfo' (it can be something else, but this goes along with 'article')
  168.             ai = self._find_articleinfo(root)
  169.             if not ai:
  170.                 return
  171.  
  172.             # Now, lets do one translator at a time
  173.             lines = translators.split("\n")
  174.             for line in lines:
  175.                 line = line.strip()
  176.                 match = re.match(r"^([^<,]+)\s*(?:<([^>,]+)>)?,\s*(.*)$", line)
  177.                 if match:
  178.                     last = self._find_lastcopyright(ai)
  179.                     copy = libxml2.newNode("copyright")
  180.                     if last:
  181.                         copy = last.addNextSibling(copy)
  182.                     else:
  183.                         ai.addChild(copy)
  184.                     if match.group(3):
  185.                         copy.newChild(None, "year", match.group(3).encode('utf-8'))
  186.                     if match.group(1) and match.group(2):
  187.                         holder = match.group(1)+"(%s)" % match.group(2)
  188.                     elif match.group(1):
  189.                         holder = match.group(1)
  190.                     elif match.group(2):
  191.                         holder = match.group(2)
  192.                     else:
  193.                         holder = "???"
  194.                     copy.newChild(None, "holder", holder.encode('utf-8'))
  195.  
  196. # Perform some tests when ran standalone
  197. if __name__ == '__main__':
  198.     test = docbookXmlMode()
  199.     print "Ignored tags       : " + repr(test.getIgnoredTags())
  200.     print "Final tags         : " + repr(test.getFinalTags())
  201.     print "Space-preserve tags: " + repr(test.getSpacePreserveTags())
  202.  
  203.     print "Credits from string: '%s'" % test.getStringForTranslators()
  204.     print "Explanation for credits:\n\t'%s'" % test.getCommentForTranslators()
  205.     
  206.