fix git support for v1.5.3 (or higher) by setting "--work-tree"
[translate_toolkit.git] / storage / properties.py
blob73d06db88bfb1742a55cc6c773554780afb8e2af
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright 2004-2006 Zuza Software Foundation
5 #
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
29 permissible follows.
31 # a comment
32 ! a comment
34 a = a string
35 b = a string with escape sequences \t \n \r \\ \" \' \ (space) \u0123
36 c = a string with a continuation line \
37 continuation line
38 d.e.f = another string
40 """
42 from translate.storage import base
43 from translate.misc import quote
44 import re
46 # the rstripeols convert dos <-> unix nicely as well
47 # output will be appropriate for the platform
49 eol = "\n"
51 class propunit(base.TranslationUnit):
52 """an element of a properties file i.e. a name and value, and any comments
53 associated"""
54 def __init__(self, source=""):
55 """construct a blank propunit"""
56 super(propunit, self).__init__(source)
57 self.name = ""
58 self.value = ""
59 self.comments = []
60 self.source = source
62 def setsource(self, source):
63 """Sets the source AND the target to be equal"""
64 self.value = quote.mozillapropertiesencode(source or "")
66 def getsource(self):
67 value = quote.mozillapropertiesdecode(self.value)
68 value = value.lstrip(" ")
69 rstriped = value.rstrip(" ")
70 if rstriped and rstriped[-1] != "\\":
71 value = rstriped
73 value = re.sub("\\\\ ", " ", value)
74 return 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...
81 self.source = target
83 def gettarget(self):
84 return self.source
85 target = property(gettarget, settarget)
87 def __str__(self):
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"))
92 return source
94 def getoutput(self):
95 """convert the element back into formatted lines for a .properties file"""
96 if self.isblank():
97 return "".join(self.comments + ["\n"])
98 else:
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):
104 return [self.name]
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):
113 self.comments = []
115 def isblank(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"""
121 UnitClass = propunit
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()
128 inputfile.close()
129 self.parse(propsrc)
131 def parse(self, propsrc):
132 """read the source of a properties file in and include them as units"""
133 newunit = propunit()
134 inmultilinevalue = False
135 for line in propsrc.split("\n"):
136 # handle multiline value if we're in one
137 line = quote.rstripeol(line)
138 if inmultilinevalue:
139 newunit.value += line.lstrip()
140 # see if there's more
141 inmultilinevalue = (newunit.value[-1:] == '\\')
142 # if we're still waiting for more...
143 if inmultilinevalue:
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)
149 newunit = propunit()
150 # otherwise, this could be a comment
151 elif line.strip()[:1] == '#':
152 # add a comment
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)
159 newunit = propunit()
160 else:
161 equalspos = line.find('=')
162 # if no equals, just ignore it
163 if equalspos == -1:
164 continue
165 # otherwise, this is a definition
166 else:
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]
173 else:
174 self.addunit(newunit)
175 newunit = propunit()
176 # see if there is a leftover one...
177 if inmultilinevalue or len(newunit.comments) > 0:
178 self.addunit(newunit)
180 def __str__(self):
181 """convert the units back to lines"""
182 lines = []
183 for unit in self.units:
184 lines.append(str(unit))
185 return "".join(lines)
187 if __name__ == '__main__':
188 import sys
189 pf = propfile(sys.stdin)
190 sys.stdout.write(str(pf))