1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """script to convert a mozilla .dtd UTF-8 localization format to a
23 gettext .po localization file using the po and dtd modules, and the
24 dtd2po convertor class which is in this module
25 You can convert back to .dtd using po2dtd.py"""
26
27 from translate.storage import po
28 from translate.storage import dtd
29 from translate.misc import quote
30 from translate.convert import accesskey as accesskeyfn
31
33 """Says if the given entity is likely to contain CSS that should not be
34 translated."""
35 if '.' in entity:
36 prefix, suffix = entity.rsplit('.', 1)
37 if suffix in ["height", "width", "unixWidth", "macWidth", "size"] or suffix.startswith("style"):
38 return True
39 return False
40
42 - def __init__(self, blankmsgstr=False, duplicatestyle="msgctxt"):
43 self.currentgroup = None
44 self.blankmsgstr = blankmsgstr
45 self.duplicatestyle = duplicatestyle
46
70
72
73 unquoted = dtd.unquotefromdtd(thedtd.definition).replace("\r", "")
74
75
76
77 lines = unquoted.split('\n')
78 while lines and not lines[0].strip():
79 del lines[0]
80 while lines and not lines[-1].strip():
81 del lines[-1]
82
83 if len(lines) > 1:
84 thepo.source = "\n".join([lines[0].rstrip() + ' '] + \
85 [line.strip() + ' ' for line in lines[1:-1]] + \
86 [lines[-1].lstrip()])
87 elif lines:
88 thepo.source = lines[0]
89 else:
90 thepo.source = ""
91 thepo.target = ""
92
94 """converts a dtd unit to a po unit, returns None if empty or not for translation"""
95 if thedtd is None:
96 return None
97 if getattr(thedtd, "entityparameter", None) == "SYSTEM":
98 return None
99 thepo = po.pounit(encoding="UTF-8")
100
101 for commentnum in range(len(thedtd.comments)):
102 commenttype, locnote = thedtd.comments[commentnum]
103
104 if commenttype == 'locnote':
105
106 typeend = quote.findend(locnote,'LOCALIZATION NOTE')
107
108 idstart = locnote.find('(', typeend)
109 if idstart == -1: continue
110 idend = locnote.find(')', idstart+1)
111 entity = locnote[idstart+1:idend].strip()
112
113 actualnotestart = locnote.find(':', idend+1)
114 actualnoteend = locnote.find('-->', idend)
115 actualnote = locnote[actualnotestart+1:actualnoteend].strip()
116
117 if thedtd.entity == entity:
118
119 if actualnote.startswith("DONT_TRANSLATE"):
120
121 thedtd.entity = ""
122 thedtd.definition = ""
123 del thedtd.comments[commentnum]
124
125 break
126 else:
127
128 thedtd.comments[commentnum] = ("automaticcomment", actualnote)
129
130 self.convertcomments(thedtd, thepo)
131 self.convertstrings(thedtd, thepo)
132 if thepo.isblank() and not thepo.getlocations():
133 return None
134 else:
135 return thepo
136
162
164 """creates self.mixedentities from the dtd file..."""
165 self.mixedentities = {}
166 for entity in thedtdfile.index.keys():
167 for labelsuffix in dtd.labelsuffixes:
168 if entity.endswith(labelsuffix):
169 entitybase = entity[:entity.rfind(labelsuffix)]
170
171
172 for akeytype in dtd.accesskeysuffixes:
173 if thedtdfile.index.has_key(entitybase + akeytype):
174
175 self.mixedentities[entity] = {}
176 self.mixedentities[entitybase+akeytype] = {}
177
178
180 """converts a dtd unit from thedtdfile to a po unit, handling mixed entities along the way..."""
181
182 if thedtd.entity in self.mixedentities:
183
184
185 alreadymixed = self.mixedentities[thedtd.entity].get(mixbucket, None)
186 if alreadymixed:
187
188 return None
189 elif alreadymixed is None:
190
191 labeldtd, accesskeydtd = None, None
192 labelentity, accesskeyentity = None, None
193 for labelsuffix in dtd.labelsuffixes:
194 if thedtd.entity.endswith(labelsuffix):
195 entitybase = thedtd.entity[:thedtd.entity.rfind(labelsuffix)]
196 for akeytype in dtd.accesskeysuffixes:
197 if thedtdfile.index.has_key(entitybase + akeytype):
198 labelentity, labeldtd = thedtd.entity, thedtd
199 accesskeyentity = labelentity[:labelentity.rfind(labelsuffix)]+akeytype
200 accesskeydtd = thedtdfile.index[accesskeyentity]
201 break
202 else:
203 for akeytype in dtd.accesskeysuffixes:
204 if thedtd.entity.endswith(akeytype):
205 accesskeyentity, accesskeydtd = thedtd.entity, thedtd
206 for labelsuffix in dtd.labelsuffixes:
207 labelentity = accesskeyentity[:accesskeyentity.rfind(akeytype)]+labelsuffix
208 if thedtdfile.index.has_key(labelentity):
209 labeldtd = thedtdfile.index[labelentity]
210 break
211 else:
212 labelentity = None
213 accesskeyentity = None
214 thepo = self.convertmixedunit(labeldtd, accesskeydtd)
215 if thepo is not None:
216 if accesskeyentity is not None:
217 self.mixedentities[accesskeyentity][mixbucket] = True
218 if labelentity is not None:
219 self.mixedentities[labelentity][mixbucket] = True
220 return thepo
221 else:
222
223 if accesskeyentity is not None:
224 self.mixedentities[accesskeyentity][mixbucket] = False
225 if labelentity is not None:
226 self.mixedentities[labelentity][mixbucket] = False
227 return self.convertunit(thedtd)
228
230 thetargetfile = po.pofile()
231 targetheader = thetargetfile.init_headers(charset="UTF-8", encoding="8bit", x_accelerator_marker="&")
232 targetheader.addnote("extracted from %s" % thedtdfile.filename, "developer")
233
234 thedtdfile.makeindex()
235 self.findmixedentities(thedtdfile)
236
237 for thedtd in thedtdfile.units:
238 if thedtd.isnull():
239 continue
240 thepo = self.convertdtdunit(thedtdfile, thedtd)
241 if thepo is not None:
242 thetargetfile.addunit(thepo)
243 thetargetfile.removeduplicates(self.duplicatestyle)
244 return thetargetfile
245
246 - def mergestore(self, origdtdfile, translateddtdfile):
247 thetargetfile = po.pofile()
248 targetheader = thetargetfile.init_headers(charset="UTF-8", encoding="8bit")
249 targetheader.addnote("extracted from %s, %s" % (origdtdfile.filename, translateddtdfile.filename), "developer")
250
251 origdtdfile.makeindex()
252 self.findmixedentities(origdtdfile)
253 translateddtdfile.makeindex()
254 self.findmixedentities(translateddtdfile)
255
256 for origdtd in origdtdfile.units:
257 if origdtd.isnull():
258 continue
259 origpo = self.convertdtdunit(origdtdfile, origdtd, mixbucket="orig")
260 if origdtd.entity in self.mixedentities:
261 mixedentitydict = self.mixedentities[origdtd.entity]
262 if "orig" not in mixedentitydict:
263
264 mixbucket = "orig"
265 del self.mixedentities[origdtd.entity]
266 elif mixedentitydict["orig"]:
267
268 mixbucket = "translate"
269 else:
270
271 mixbucket = "orig"
272 else:
273 mixbucket = "translate"
274 if origpo is None:
275
276 continue
277 if origdtd.entity in translateddtdfile.index:
278 translateddtd = translateddtdfile.index[origdtd.entity]
279 translatedpo = self.convertdtdunit(translateddtdfile, translateddtd, mixbucket=mixbucket)
280 else:
281 translatedpo = None
282 if origpo is not None:
283 if translatedpo is not None and not self.blankmsgstr:
284 origpo.target = translatedpo.source
285 thetargetfile.addunit(origpo)
286 thetargetfile.removeduplicates(self.duplicatestyle)
287 return thetargetfile
288
289 -def convertdtd(inputfile, outputfile, templatefile, pot=False, duplicatestyle="msgctxt"):
290 """reads in inputfile and templatefile using dtd, converts using dtd2po, writes to outputfile"""
291 inputstore = dtd.dtdfile(inputfile)
292 convertor = dtd2po(blankmsgstr=pot, duplicatestyle=duplicatestyle)
293 if templatefile is None:
294 outputstore = convertor.convertstore(inputstore)
295 else:
296 templatestore = dtd.dtdfile(templatefile)
297 outputstore = convertor.mergestore(templatestore, inputstore)
298 if outputstore.isempty():
299 return 0
300 outputfile.write(str(outputstore))
301 return 1
302
303 -def main(argv=None):
304 from translate.convert import convert
305 formats = {"dtd": ("po", convertdtd), ("dtd", "dtd"): ("po", convertdtd)}
306 parser = convert.ConvertOptionParser(formats, usetemplates=True, usepots=True, description=__doc__)
307 parser.add_duplicates_option()
308 parser.passthrough.append("pot")
309 parser.run(argv)
310
311 if __name__ == '__main__':
312 main()
313