Package translate :: Package convert :: Module prop2po

[hide private]
[frames] | no frames]

# Source Code for Module translate.convert.prop2po

      1  #!/usr/bin/env python
      2  # -*- coding: utf-8 -*-
      3  #
      4  # Copyright 2002-2006 Zuza Software Foundation
      5  #
      6  # This file is part of translate.
      7  #
      8  # translate is free software; you can redistribute it and/or modify
      9  # it under the terms of the GNU General Public License as published by
     10  # the Free Software Foundation; either version 2 of the License, or
     11  # (at your option) any later version.
     12  #
     13  # translate is distributed in the hope that it will be useful,
     14  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  # GNU General Public License for more details.
     17  #
     18  # You should have received a copy of the GNU General Public License
     19  # along with translate; if not, write to the Free Software
     20  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     21
     22  """convert Java/Mozilla .properties files to Gettext PO localization files
     23
     24  See: http://translate.sourceforge.net/wiki/toolkit/prop2po for examples and
     25  usage instructions
     26  """
     27
     28  import sys
     29  from translate.storage import po
     30  from translate.storage import properties
     31
     32
     33 -class prop2po:
     34      """convert a .properties file to a .po file for handling the
     35      translation."""
     36
     37 -    def convertstore(self, thepropfile, personality="java",
     38                       duplicatestyle="msgctxt"):
     39          """converts a .properties file to a .po file..."""
     40          self.personality = personality
     41          thetargetfile = po.pofile()
     42          if self.personality == "mozilla" or self.personality == "skype":
     43              targetheader = thetargetfile.init_headers(charset="UTF-8",
     44                                                        encoding="8bit",
     45                                                        x_accelerator_marker="&")
     46          else:
     47              targetheader = thetargetfile.init_headers(charset="UTF-8",
     48                                                        encoding="8bit")
     49          targetheader.addnote("extracted from %s" % thepropfile.filename,
     50                               "developer")
     51          # we try and merge the header po with any comments at the start of the
     52          # properties file
     53          appendedheader = False
     54          waitingcomments = []
     55          for propunit in thepropfile.units:
     56              pounit = self.convertunit(propunit, "developer")
     57              if pounit is None:
     58                  waitingcomments.extend(propunit.comments)
     59              # FIXME the storage class should not be creating blank units
     60              if pounit is "discard":
     61                  continue
     62              if not appendedheader:
     63                  if propunit.isblank():
     64                      targetheader.addnote("\n".join(waitingcomments).rstrip(),
     65                                           "developer", position="prepend")
     66                      waitingcomments = []
     67                      pounit = None
     68                  appendedheader = True
     69              if pounit is not None:
     70                  pounit.addnote("\n".join(waitingcomments).rstrip(),
     71                                 "developer", position="prepend")
     72                  waitingcomments = []
     73                  thetargetfile.addunit(pounit)
     74          thetargetfile.removeduplicates(duplicatestyle)
     75          return thetargetfile
     76
     77 -    def mergestore(self, origpropfile, translatedpropfile, personality="java",
     78                     blankmsgstr=False, duplicatestyle="msgctxt"):
     79          """converts two .properties files to a .po file..."""
     80          self.personality = personality
     81          thetargetfile = po.pofile()
     82          if self.personality == "mozilla" or self.personality == "skype":
     83              targetheader = thetargetfile.init_headers(charset="UTF-8",
     84                                                        encoding="8bit",
     85                                                        x_accelerator_marker="&")
     86          else:
     87              targetheader = thetargetfile.init_headers(charset="UTF-8",
     88                                                        encoding="8bit")
     89          targetheader.addnote("extracted from %s, %s" % (origpropfile.filename, translatedpropfile.filename),
     90                               "developer")
     91          translatedpropfile.makeindex()
     92          # we try and merge the header po with any comments at the start of
     93          # the properties file
     94          appendedheader = False
     95          waitingcomments = []
     96          # loop through the original file, looking at units one by one
     97          for origprop in origpropfile.units:
     98              origpo = self.convertunit(origprop, "developer")
     99              if origpo is None:
    100                  waitingcomments.extend(origprop.comments)
    101              # FIXME the storage class should not be creating blank units
    102              if origpo is "discard":
    103                  continue
    104              # handle the header case specially...
    105              if not appendedheader:
    106                  if origprop.isblank():
    107                      targetheader.addnote(u"".join(waitingcomments).rstrip(),
    108                                           "developer", position="prepend")
    109                      waitingcomments = []
    110                      origpo = None
    111                  appendedheader = True
    112              # try and find a translation of the same name...
    113              if origprop.name in translatedpropfile.locationindex:
    114                  translatedprop = translatedpropfile.locationindex[origprop.name]
    115                  # Need to check that this comment is not a copy of the
    116                  # developer comments
    117                  translatedpo = self.convertunit(translatedprop, "translator")
    118                  if translatedpo is "discard":
    119                      continue
    120              else:
    121                  translatedpo = None
    122              # if we have a valid po unit, get the translation and add it...
    123              if origpo is not None:
    124                  if translatedpo is not None and not blankmsgstr:
    125                      origpo.target = translatedpo.source
    126                  origpo.addnote(u"".join(waitingcomments).rstrip(),
    127                                 "developer", position="prepend")
    128                  waitingcomments = []
    129                  thetargetfile.addunit(origpo)
    130              elif translatedpo is not None:
    131                  print >> sys.stderr, "error converting original properties definition %s" % origprop.name
    132          thetargetfile.removeduplicates(duplicatestyle)
    133          return thetargetfile
    134
    135 -    def convertunit(self, propunit, commenttype):
    136          """Converts a .properties unit to a .po unit. Returns None if empty
    137          or not for translation."""
    138          if propunit is None:
    139              return None
    140          # escape unicode
    141          pounit = po.pounit(encoding="UTF-8")
    142          if hasattr(propunit, "comments"):
    143              for comment in propunit.comments:
    144                  if "DONT_TRANSLATE" in comment:
    145                      return "discard"
    146              pounit.addnote(u"".join(propunit.getnotes()).rstrip(), commenttype)
    147          # TODO: handle multiline msgid
    148          if propunit.isblank():
    149              return None
    150          pounit.addlocation(propunit.name)
    151          pounit.source = propunit.source
    152          pounit.target = u""
    153          return pounit
    154
    155
    156 -def convertstrings(inputfile, outputfile, templatefile, personality="strings",
    157                     pot=False, duplicatestyle="msgctxt", encoding=None):
    158      """.strings specific convertor function"""
    159      return convertprop(inputfile, outputfile, templatefile,
    160                         personality="strings", pot=pot,
    161                         duplicatestyle=duplicatestyle, encoding=encoding)
    162
    163
    164 -def convertmozillaprop(inputfile, outputfile, templatefile, pot=False,
    165                         duplicatestyle="msgctxt"):
    166      """Mozilla specific convertor function"""
    167      return convertprop(inputfile, outputfile, templatefile,
    168                         personality="mozilla", pot=pot,
    169                         duplicatestyle=duplicatestyle)
    170
    171
    172 -def convertprop(inputfile, outputfile, templatefile, personality="java",
    173                  pot=False, duplicatestyle="msgctxt", encoding=None):
    174      """reads in inputfile using properties, converts using prop2po, writes
    175      to outputfile"""
    176      inputstore = properties.propfile(inputfile, personality, encoding)
    177      convertor = prop2po()
    178      if templatefile is None:
    179          outputstore = convertor.convertstore(inputstore, personality,
    180                                               duplicatestyle=duplicatestyle)
    181      else:
    182          templatestore = properties.propfile(templatefile, personality, encoding)
    183          outputstore = convertor.mergestore(templatestore, inputstore,
    184                                             personality, blankmsgstr=pot,
    185                                             duplicatestyle=duplicatestyle)
    186      if outputstore.isempty():
    187          return 0
    188      outputfile.write(str(outputstore))
    189      return 1
    190
    191  formats = {
    192      "properties": ("po", convertprop),
    193      ("properties", "properties"): ("po", convertprop),
    194      "lang": ("po", convertprop),
    195      ("lang", "lang"): ("po", convertprop),
    196      "strings": ("po", convertstrings),
    197      ("strings", "strings"): ("po", convertstrings),
    198  }
    199
    200
    201 -def main(argv=None):
    202      from translate.convert import convert
    203      parser = convert.ConvertOptionParser(formats, usetemplates=True,
    204                                           usepots=True,
    205                                           description=__doc__)
    206      parser.add_option("", "--personality", dest="personality",
    207              default=properties.default_dialect,
    208              type="choice",
    209              choices=properties.dialects.keys(),
    210              help="override the input file format: %s (for .properties files, default: %s)" %
    211                   (", ".join(properties.dialects.iterkeys()),
    212                    properties.default_dialect),
    213              metavar="TYPE")
    214      parser.add_option("", "--encoding", dest="encoding", default=None,
    215              help="override the encoding set by the personality",
    216              metavar="ENCODING")
    217      parser.add_duplicates_option()
    218      parser.passthrough.append("pot")
    219      parser.passthrough.append("personality")
    220      parser.passthrough.append("encoding")
    221      parser.run(argv)
    222
    223  if __name__ == '__main__':
    224      main()
    225