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
     30  from translate.storage import po
     31  from translate.storage import properties
     32
     33
     34 -class prop2po:
     35      """convert a .properties file to a .po file for handling the
     36      translation."""
     37
     38 -    def convertstore(self, thepropfile, personality="java",
     39                       duplicatestyle="msgctxt"):
     40          """converts a .properties file to a .po file..."""
     41          self.personality = personality
     42          thetargetfile = po.pofile()
     43          if self.personality == "mozilla" or self.personality == "skype":
     44              targetheader = thetargetfile.init_headers(charset="UTF-8",
     45                                                        encoding="8bit",
     46                                                        x_accelerator_marker="&")
     47          else:
     48              targetheader = thetargetfile.init_headers(charset="UTF-8",
     49                                                        encoding="8bit")
     50          targetheader.addnote("extracted from %s" % thepropfile.filename,
     51                               "developer")
     52          # we try and merge the header po with any comments at the start of the
     53          # properties file
     54          appendedheader = False
     55          waitingcomments = []
     56          for propunit in thepropfile.units:
     57              pounit = self.convertunit(propunit, "developer")
     58              if pounit is None:
     59                  waitingcomments.extend(propunit.comments)
     60              # FIXME the storage class should not be creating blank units
     61              if pounit is "discard":
     62                  continue
     63              if not appendedheader:
     64                  if propunit.isblank():
     65                      targetheader.addnote("\n".join(waitingcomments).rstrip(),
     66                                           "developer", position="prepend")
     67                      waitingcomments = []
     68                      pounit = None
     69                  appendedheader = True
     70              if pounit is not None:
     71                  pounit.addnote("\n".join(waitingcomments).rstrip(),
     72                                 "developer", position="prepend")
     73                  waitingcomments = []
     74                  thetargetfile.addunit(pounit)
     75          thetargetfile.removeduplicates(duplicatestyle)
     76          return thetargetfile
     77
     78 -    def mergestore(self, origpropfile, translatedpropfile, personality="java",
     79                     blankmsgstr=False, duplicatestyle="msgctxt"):
     80          """converts two .properties files to a .po file..."""
     81          self.personality = personality
     82          thetargetfile = po.pofile()
     83          if self.personality == "mozilla" or self.personality == "skype":
     84              targetheader = thetargetfile.init_headers(charset="UTF-8",
     85                                                        encoding="8bit",
     86                                                        x_accelerator_marker="&")
     87          else:
     88              targetheader = thetargetfile.init_headers(charset="UTF-8",
     89                                                        encoding="8bit")
     90          targetheader.addnote("extracted from %s, %s" % (origpropfile.filename, translatedpropfile.filename),
     91                               "developer")
     92          translatedpropfile.makeindex()
     93          # we try and merge the header po with any comments at the start of
     94          # the properties file
     95          appendedheader = False
     96          waitingcomments = []
     97          # loop through the original file, looking at units one by one
     98          for origprop in origpropfile.units:
     99              origpo = self.convertunit(origprop, "developer")
    100              if origpo is None:
    101                  waitingcomments.extend(origprop.comments)
    102              # FIXME the storage class should not be creating blank units
    103              if origpo is "discard":
    104                  continue
    105              # handle the header case specially...
    106              if not appendedheader:
    107                  if origprop.isblank():
    108                      targetheader.addnote(u"".join(waitingcomments).rstrip(),
    109                                           "developer", position="prepend")
    110                      waitingcomments = []
    111                      origpo = None
    112                  appendedheader = True
    113              # try and find a translation of the same name...
    114              if origprop.name in translatedpropfile.locationindex:
    115                  translatedprop = translatedpropfile.locationindex[origprop.name]
    116                  # Need to check that this comment is not a copy of the
    117                  # developer comments
    118                  translatedpo = self.convertunit(translatedprop, "translator")
    119                  if translatedpo is "discard":
    120                      continue
    121              else:
    122                  translatedpo = None
    123              # if we have a valid po unit, get the translation and add it...
    124              if origpo is not None:
    125                  if translatedpo is not None and not blankmsgstr:
    126                      origpo.target = translatedpo.source
    127                  origpo.addnote(u"".join(waitingcomments).rstrip(),
    128                                 "developer", position="prepend")
    129                  waitingcomments = []
    130                  thetargetfile.addunit(origpo)
    131              elif translatedpo is not None:
    132                  print >> sys.stderr, "error converting original properties definition %s" % origprop.name
    133          thetargetfile.removeduplicates(duplicatestyle)
    134          return thetargetfile
    135
    136 -    def convertunit(self, propunit, commenttype):
    137          """Converts a .properties unit to a .po unit. Returns None if empty
    138          or not for translation."""
    139          if propunit is None:
    140              return None
    141          # escape unicode
    142          pounit = po.pounit(encoding="UTF-8")
    143          if hasattr(propunit, "comments"):
    144              for comment in propunit.comments:
    145                  if "DONT_TRANSLATE" in comment:
    146                      return "discard"
    147              pounit.addnote(u"".join(propunit.getnotes()).rstrip(), commenttype)
    148          # TODO: handle multiline msgid
    149          if propunit.isblank():
    150              return None
    151          pounit.addlocation(propunit.name)
    152          pounit.source = propunit.source
    153          pounit.target = u""
    154          return pounit
    155
    156
    157 -def convertstrings(inputfile, outputfile, templatefile, personality="strings",
    158                     pot=False, duplicatestyle="msgctxt", encoding=None):
    159      """.strings specific convertor function"""
    160      return convertprop(inputfile, outputfile, templatefile,
    161                         personality="strings", pot=pot,
    162                         duplicatestyle=duplicatestyle, encoding=encoding)
    163
    164
    165 -def convertmozillaprop(inputfile, outputfile, templatefile, pot=False,
    166                         duplicatestyle="msgctxt"):
    167      """Mozilla specific convertor function"""
    168      return convertprop(inputfile, outputfile, templatefile,
    169                         personality="mozilla", pot=pot,
    170                         duplicatestyle=duplicatestyle)
    171
    172
    173 -def convertprop(inputfile, outputfile, templatefile, personality="java",
    174                  pot=False, duplicatestyle="msgctxt", encoding=None):
    175      """reads in inputfile using properties, converts using prop2po, writes
    176      to outputfile"""
    177      inputstore = properties.propfile(inputfile, personality, encoding)
    178      convertor = prop2po()
    179      if templatefile is None:
    180          outputstore = convertor.convertstore(inputstore, personality,
    181                                               duplicatestyle=duplicatestyle)
    182      else:
    183          templatestore = properties.propfile(templatefile, personality, encoding)
    184          outputstore = convertor.mergestore(templatestore, inputstore,
    185                                             personality, blankmsgstr=pot,
    186                                             duplicatestyle=duplicatestyle)
    187      if outputstore.isempty():
    188          return 0
    189      outputfile.write(str(outputstore))
    190      return 1
    191
    192  formats = {
    193      "properties": ("po", convertprop),
    194      ("properties", "properties"): ("po", convertprop),
    195      "lang": ("po", convertprop),
    196      ("lang", "lang"): ("po", convertprop),
    197      "strings": ("po", convertstrings),
    198      ("strings", "strings"): ("po", convertstrings),
    199  }
    200
    201
    202 -def main(argv=None):
    203      from translate.convert import convert
    204      parser = convert.ConvertOptionParser(formats, usetemplates=True,
    205                                           usepots=True,
    206                                           description=__doc__)
    207      parser.add_option("", "--personality", dest="personality",
    208              default=properties.default_dialect,
    209              type="choice",
    210              choices=properties.dialects.keys(),
    211              help="override the input file format: %s (for .properties files, default: %s)" %
    212                   (", ".join(properties.dialects.iterkeys()),
    213                    properties.default_dialect),
    214              metavar="TYPE")
    215      parser.add_option("", "--encoding", dest="encoding", default=None,
    216              help="override the encoding set by the personality",
    217              metavar="ENCODING")
    218      parser.add_duplicates_option()
    219      parser.passthrough.append("pot")
    220      parser.passthrough.append("personality")
    221      parser.passthrough.append("encoding")
    222      parser.run(argv)
    223
    224  if __name__ == '__main__':
    225      main()
    226