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