fix git support for v1.5.3 (or higher) by setting "--work-tree"
[translate_toolkit.git] / storage / php.py
blob29389fdd3aee7f516e3063e7eca6d40a581bd9fe
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright 2004-2008 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 php localisation files (phpunit) or entire files
23 (phpfile) these files are used in translating many PHP based applications
25 """
27 from translate.storage import base
28 from translate.misc import quote
29 import re
31 def phpencode(text, quotechar="'"):
32 """convert Python string to PHP escaping"""
33 if not text:
34 return text
35 return text.replace("%s" % quotechar, "\\%s" % quotechar).replace("\n", "\\n")
37 def phpdecode(text):
38 """convert PHP escaped string to a Python string"""
39 if not text:
40 return text
41 return text.replace("\\'", "'").replace('\\"', '"').replace("\\n", "\n")
43 class phpunit(base.TranslationUnit):
44 """a unit of a PHP file i.e. a name and value, and any comments
45 associated"""
46 def __init__(self, source=""):
47 """construct a blank phpunit"""
48 super(phpunit, self).__init__(source)
49 self.name = ""
50 self.value = ""
51 self._comments = []
52 self.source = source
54 def setsource(self, source):
55 """Sets the source AND the target to be equal"""
56 self.value = phpencode(source)
58 def getsource(self):
59 return phpdecode(self.value)
60 source = property(getsource, setsource)
62 def settarget(self, target):
63 """Note: this also sets the .source attribute!"""
64 # TODO: shouldn't this just call the .source property? no quoting done here...
65 self.source = target
67 def gettarget(self):
68 return self.source
69 target = property(gettarget, settarget)
71 def __str__(self):
72 """convert to a string. double check that unicode is handled somehow here"""
73 source = self.getoutput()
74 if isinstance(source, unicode):
75 return source.encode(getattr(self, "encoding", "UTF-8"))
76 return source
78 def getoutput(self):
79 """convert the unit back into formatted lines for a php file"""
80 return "".join(self._comments + ["%s='%s';\n" % (self.name, self.value)])
82 def addlocation(self, location):
83 self.name = location
85 def getlocations(self):
86 return [self.name]
88 def addnote(self, note, origin=None):
89 self._comments.append(note)
91 def getnotes(self, origin=None):
92 return '\n'.join(self._comments)
94 def removenotes(self):
95 self._comments = []
97 def isblank(self):
98 """returns whether this is a blank element, containing only comments..."""
99 return not (self.name or self.value)
101 class phpfile(base.TranslationStore):
102 """this class represents a php file, made up of phpunits"""
103 UnitClass = phpunit
104 def __init__(self, inputfile=None, encoding='utf-8'):
105 """construct a phpfile, optionally reading in from inputfile"""
106 super(phpfile, self).__init__(unitclass = self.UnitClass)
107 self.filename = getattr(inputfile, 'name', '')
108 self._encoding = encoding
109 if inputfile is not None:
110 phpsrc = inputfile.read()
111 inputfile.close()
112 self.parse(phpsrc)
114 def parse(self, phpsrc):
115 """read the source of a php file in and include them as units"""
116 newunit = phpunit()
117 lastvalue = ""
118 value = ""
119 comment = []
120 invalue = False
121 incomment = False
122 valuequote = "" # either ' or "
123 for line in phpsrc.decode(self._encoding).split("\n"):
124 # Assuming /* comments */ are started and stopped on lines
125 commentstartpos = line.find("/*")
126 commentendpos = line.rfind("*/")
127 if commentstartpos != -1:
128 incomment = True
129 if commentendpos != -1:
130 newunit.addnote(line[commentstartpos+2:commentendpos].strip(), "developer")
131 incomment = False
132 if incomment:
133 newunit.addnote(line[commentstartpos+2:].strip(), "developer")
134 if commentendpos != -1 and incomment:
135 newunit.addnote(line[:commentendpos].strip(), "developer")
136 incomment = False
137 if commentstartpos == -1 and incomment:
138 newunit.addnote(line.strip(), "developer")
139 equalpos = line.find("=")
140 if equalpos != -1 and not invalue:
141 newunit.addlocation(line[:equalpos].strip().replace(" ", ""))
142 value = line[equalpos+1:].lstrip()[1:]
143 valuequote = line[equalpos+1:].lstrip()[0]
144 lastvalue = ""
145 invalue = True
146 else:
147 if invalue:
148 value = line
149 colonpos = value.rfind(";")
150 while colonpos != -1:
151 if value[colonpos-1] == valuequote:
152 newunit.value = lastvalue + value[:colonpos-1]
153 lastvalue = ""
154 invalue = False
155 if not invalue and colonpos != len(value)-1:
156 commentinlinepos = value.find("//", colonpos)
157 if commentinlinepos != -1:
158 newunit.addnote(value[commentinlinepos+2:].strip(), "developer")
159 if not invalue:
160 self.addunit(newunit)
161 value = ""
162 newunit = phpunit()
163 colonpos = value.rfind(";", 0, colonpos)
164 if invalue:
165 lastvalue = lastvalue + value
167 def __str__(self):
168 """convert the units back to lines"""
169 lines = []
170 for unit in self.units:
171 lines.append(str(unit))
172 return "".join(lines)
174 if __name__ == '__main__':
175 import sys
176 pf = phpfile(sys.stdin)
177 sys.stdout.write(str(pf))