2 # -*- coding: utf-8 -*-
4 # Copyright 2002-2006 Zuza Software Foundation
6 # This file is part of translate.
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.
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.
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
22 """convert Java/Mozilla .properties files to Gettext PO localization files
24 See: http://translate.sourceforge.net/wiki/toolkit/prop2po for examples and
29 from translate
.storage
import po
30 from translate
.storage
import properties
33 """convert a .properties file to a .po file for handling the translation..."""
34 def convertstore(self
, thepropfile
, duplicatestyle
="msgctxt"):
35 """converts a .properties file to a .po file..."""
36 thetargetfile
= po
.pofile()
37 targetheader
= thetargetfile
.makeheader(charset
="UTF-8", encoding
="8bit", x_accelerator_marker
="&")
38 targetheader
.addnote("extracted from %s" % thepropfile
.filename
, "developer")
39 # we try and merge the header po with any comments at the start of the properties file
42 for propunit
in thepropfile
.units
:
43 pounit
= self
.convertunit(propunit
, "developer")
45 waitingcomments
.extend(propunit
.comments
)
46 # FIXME the storage class should not be creating blank units
47 if pounit
is "discard":
49 if not appendedheader
:
50 if propunit
.isblank():
53 thetargetfile
.addunit(targetheader
)
55 if pounit
is not None:
56 pounit
.addnote("".join(waitingcomments
).rstrip(), "developer", position
="prepend")
58 thetargetfile
.addunit(pounit
)
59 thetargetfile
.removeduplicates(duplicatestyle
)
62 def mergestore(self
, origpropfile
, translatedpropfile
, blankmsgstr
=False, duplicatestyle
="msgctxt"):
63 """converts two .properties files to a .po file..."""
64 thetargetfile
= po
.pofile()
65 targetheader
= thetargetfile
.makeheader(charset
="UTF-8", encoding
="8bit")
66 targetheader
.addnote("extracted from %s, %s" % (origpropfile
.filename
, translatedpropfile
.filename
), "developer")
67 translatedpropfile
.makeindex()
68 # we try and merge the header po with any comments at the start of the properties file
71 # loop through the original file, looking at units one by one
72 for origprop
in origpropfile
.units
:
73 origpo
= self
.convertunit(origprop
, "developer")
75 waitingcomments
.extend(origprop
.comments
)
76 # FIXME the storage class should not be creating blank units
77 if origpo
is "discard":
79 # handle the header case specially...
80 if not appendedheader
:
81 if origprop
.isblank():
84 thetargetfile
.addunit(targetheader
)
86 # try and find a translation of the same name...
87 if origprop
.name
in translatedpropfile
.locationindex
:
88 translatedprop
= translatedpropfile
.locationindex
[origprop
.name
]
89 # Need to check that this comment is not a copy of the developer comments
90 translatedpo
= self
.convertunit(translatedprop
, "translator")
93 # if we have a valid po unit, get the translation and add it...
94 if origpo
is not None:
95 if translatedpo
is not None and not blankmsgstr
:
96 origpo
.target
= translatedpo
.source
97 origpo
.addnote("".join(waitingcomments
).rstrip(), "developer", position
="prepend")
99 thetargetfile
.addunit(origpo
)
100 elif translatedpo
is not None:
101 print >> sys
.stderr
, "error converting original properties definition %s" % origprop
.name
102 thetargetfile
.removeduplicates(duplicatestyle
)
105 def convertunit(self
, propunit
, commenttype
):
106 """Converts a .properties unit to a .po unit. Returns None if empty
107 or not for translation."""
111 pounit
= po
.pounit(encoding
="UTF-8")
112 if hasattr(propunit
, "comments"):
113 for comment
in propunit
.comments
:
114 if "DONT_TRANSLATE" in comment
:
116 pounit
.addnote("".join(propunit
.comments
).rstrip(), commenttype
)
117 # TODO: handle multiline msgid
118 if propunit
.isblank():
120 pounit
.addlocation(propunit
.name
)
121 pounit
.source
= propunit
.source
125 def convertprop(inputfile
, outputfile
, templatefile
, pot
=False, duplicatestyle
="msgctxt"):
126 """reads in inputfile using properties, converts using prop2po, writes to outputfile"""
127 inputstore
= properties
.propfile(inputfile
)
128 convertor
= prop2po()
129 if templatefile
is None:
130 outputstore
= convertor
.convertstore(inputstore
, duplicatestyle
=duplicatestyle
)
132 templatestore
= properties
.propfile(templatefile
)
133 outputstore
= convertor
.mergestore(templatestore
, inputstore
, blankmsgstr
=pot
, duplicatestyle
=duplicatestyle
)
134 if outputstore
.isempty():
136 outputfile
.write(str(outputstore
))
140 from translate
.convert
import convert
141 formats
= {"properties": ("po", convertprop
), ("properties", "properties"): ("po", convertprop
)}
142 parser
= convert
.ConvertOptionParser(formats
, usetemplates
=True, usepots
=True, description
=__doc__
)
143 parser
.add_duplicates_option()
144 parser
.passthrough
.append("pot")
147 if __name__
== '__main__':