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