2 # -*- coding: utf-8 -*-
4 # Copyright 2004-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 """classes that hold units of .properties files (propunit) or entire files
23 (propfile) these files are used in translating Mozilla and other software
25 @note: The following {.properties file
26 description<http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html>}
27 and {example <http://www.exampledepot.com/egs/java.util/Props.html>} give some
28 good references to the .properties specification. A simple summary of what is
35 b = a string with escape sequences \t \n \r \\ \" \' \ (space) \u0123
36 c = a string with a continuation line \
38 d.e.f = another string
42 from translate
.storage
import base
43 from translate
.misc
import quote
46 # the rstripeols convert dos <-> unix nicely as well
47 # output will be appropriate for the platform
51 class propunit(base
.TranslationUnit
):
52 """an element of a properties file i.e. a name and value, and any comments
54 def __init__(self
, source
=""):
55 """construct a blank propunit"""
56 super(propunit
, self
).__init
__(source
)
62 def setsource(self
, source
):
63 """Sets the source AND the target to be equal"""
64 self
.value
= quote
.mozillapropertiesencode(source
or "")
67 value
= quote
.mozillapropertiesdecode(self
.value
)
68 value
= value
.lstrip(" ")
69 rstriped
= value
.rstrip(" ")
70 if rstriped
and rstriped
[-1] != "\\":
73 value
= re
.sub("\\\\ ", " ", value
)
76 source
= property(getsource
, setsource
)
78 def settarget(self
, target
):
79 """Note: this also sets the .source attribute!"""
80 # TODO: shouldn't this just call the .source property? no quoting done here...
85 target
= property(gettarget
, settarget
)
88 """convert to a string. double check that unicode is handled somehow here"""
89 source
= self
.getoutput()
90 if isinstance(source
, unicode):
91 return source
.encode(getattr(self
, "encoding", "UTF-8"))
95 """convert the element back into formatted lines for a .properties file"""
97 return "".join(self
.comments
+ ["\n"])
99 if "\\u" in self
.value
:
100 self
.value
= quote
.mozillapropertiesencode(quote
.mozillapropertiesdecode(self
.value
))
101 return "".join(self
.comments
+ ["%s=%s\n" % (self
.name
, self
.value
)])
103 def getlocations(self
):
106 def addnote(self
, note
, origin
=None):
107 self
.comments
.append(note
)
109 def getnotes(self
, origin
=None):
110 return '\n'.join(self
.comments
)
112 def removenotes(self
):
116 """returns whether this is a blank element, containing only comments..."""
117 return not (self
.name
or self
.value
)
119 class propfile(base
.TranslationStore
):
120 """this class represents a .properties file, made up of propunits"""
122 def __init__(self
, inputfile
=None):
123 """construct a propfile, optionally reading in from inputfile"""
124 super(propfile
, self
).__init
__(unitclass
= self
.UnitClass
)
125 self
.filename
= getattr(inputfile
, 'name', '')
126 if inputfile
is not None:
127 propsrc
= inputfile
.read()
131 def parse(self
, propsrc
):
132 """read the source of a properties file in and include them as units"""
134 inmultilinevalue
= False
135 for line
in propsrc
.split("\n"):
136 # handle multiline value if we're in one
137 line
= quote
.rstripeol(line
)
139 newunit
.value
+= line
.lstrip()
140 # see if there's more
141 inmultilinevalue
= (newunit
.value
[-1:] == '\\')
142 # if we're still waiting for more...
144 # strip the backslash
145 newunit
.value
= newunit
.value
[:-1]
146 if not inmultilinevalue
:
147 # we're finished, add it to the list...
148 self
.addunit(newunit
)
150 # otherwise, this could be a comment
151 elif line
.strip()[:1] == '#':
153 line
= quote
.escapecontrols(line
)
154 newunit
.comments
.append(line
+"\n")
155 elif not line
.strip():
156 # this is a blank line...
157 if str(newunit
).strip():
158 self
.addunit(newunit
)
161 equalspos
= line
.find('=')
162 # if no equals, just ignore it
165 # otherwise, this is a definition
167 newunit
.name
= line
[:equalspos
].strip()
168 newunit
.value
= line
[equalspos
+1:].lstrip()
169 # backslash at end means carry string on to next line
170 if newunit
.value
[-1:] == '\\':
171 inmultilinevalue
= True
172 newunit
.value
= newunit
.value
[:-1]
174 self
.addunit(newunit
)
176 # see if there is a leftover one...
177 if inmultilinevalue
or len(newunit
.comments
) > 0:
178 self
.addunit(newunit
)
181 """convert the units back to lines"""
183 for unit
in self
.units
:
184 lines
.append(str(unit
))
185 return "".join(lines
)
187 if __name__
== '__main__':
189 pf
= propfile(sys
.stdin
)
190 sys
.stdout
.write(str(pf
))