Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(69)

Delta Between Two Patch Sets: translate/storage/cpo.py

Issue 81: Fix CPO memory leak SVN Base: https://translate.svn.sourceforge.net/svnroot/translate/src/trunk/
Left Patch Set: Added tests Created 1 year, 4 months ago
Right Patch Set: Added some tests workarounds Created 1 year, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: View regular side by side diff
Right: View regular side by side diff
LEFTRIGHT
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*- 2 # -*- coding: utf-8 -*-
3 # 3 #
4 # Copyright 2002-2007 Zuza Software Foundation 4 # Copyright 2002-2007 Zuza Software Foundation
5 # 5 #
6 # This file is part of translate. 6 # This file is part of translate.
7 # 7 #
8 # translate is free software; you can redistribute it and/or modify 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 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 10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version. 11 # (at your option) any later version.
12 # 12 #
13 # translate is distributed in the hope that it will be useful, 13 # translate is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details. 16 # GNU General Public License for more details.
17 # 17 #
18 # You should have received a copy of the GNU General Public License 18 # You should have received a copy of the GNU General Public License
19 # along with translate; if not, write to the Free Software 19 # along with translate; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 21
22 """Classes that hold units of .po files (pounit) or entire files (pofile). 22 """Classes that hold units of .po files (pounit) or entire files (pofile).
23 23
24 Gettext-style .po (or .pot) files are used in translations for KDE, GNOME and 24 Gettext-style .po (or .pot) files are used in translations for KDE, GNOME and
25 many other projects. 25 many other projects.
26 26
27 This uses libgettextpo from the gettext package. Any version before 0.17 will 27 This uses libgettextpo from the gettext package. Any version before 0.17 will
28 at least cause some subtle bugs or may not work at all. Developers might want 28 at least cause some subtle bugs or may not work at all. Developers might want
29 to have a look at gettext-tools/libgettextpo/gettext-po.h from the gettext 29 to have a look at gettext-tools/libgettextpo/gettext-po.h from the gettext
30 package for the public API of the library. 30 package for the public API of the library.
31 """ 31 """
32 32
33 from translate.misc.multistring import multistring 33 from translate.misc.multistring import multistring
34 from translate.storage import pocommon 34 from translate.storage import pocommon
35 from translate.misc import quote 35 from translate.misc import quote
36 from translate.lang import data 36 from translate.lang import data
37 from ctypes import * 37 from ctypes import *
38 import ctypes.util 38 import ctypes.util
39 try: 39 try:
40 import cStringIO as StringIO 40 import cStringIO as StringIO
41 except ImportError: 41 except ImportError:
42 import StringIO 42 import StringIO
43 import os 43 import os
44 import pypo 44 import pypo
45 import re 45 import re
46 import sys 46 import sys
47 import tempfile 47 import tempfile
48 48
49 lsep = " " 49 lsep = " "
50 """Seperator for #: entries""" 50 """Seperator for #: entries"""
(...skipping 290 matching lines...) Show 10 above Show 10 below
341 if position == "append": 341 if position == "append":
342 newnotes = oldnotes + "\n" + text 342 newnotes = oldnotes + "\n" + text
343 elif position == "merge": 343 elif position == "merge":
344 if oldnotes != text: 344 if oldnotes != text:
345 oldnoteslist = oldnotes.split("\n") 345 oldnoteslist = oldnotes.split("\n")
346 for newline in text.split("\n"): 346 for newline in text.split("\n"):
347 newline = newline.rstrip() 347 newline = newline.rstrip()
348 # avoid duplicate comment lines (this might cause some p roblems) 348 # avoid duplicate comment lines (this might cause some p roblems)
349 if newline not in oldnotes or len(newline) < 5: 349 if newline not in oldnotes or len(newline) < 5:
350 oldnoteslist.append(newline) 350 oldnoteslist.append(newline)
351 newnotes = "\n".join(oldnoteslist) 351 newnotes = "\n".join(oldnoteslist)
352 else: 352 else:
353 newnotes = text + '\n' + oldnotes 353 newnotes = text + '\n' + oldnotes
354 else: 354 else:
355 newnotes = "\n".join([line.rstrip() for line in text.split("\n")]) 355 newnotes = "\n".join([line.rstrip() for line in text.split("\n")])
356 356
357 if newnotes: 357 if newnotes:
358 newlines = [] 358 newlines = []
359 needs_space = get_libgettextpo_version() < (0, 17, 0) 359 needs_space = get_libgettextpo_version() < (0, 17, 0)
360 for line in newnotes.split("\n"): 360 for line in newnotes.split("\n"):
361 if line and needs_space: 361 if line and needs_space:
362 newlines.append(" " + line) 362 newlines.append(" " + line)
363 else: 363 else:
364 newlines.append(line) 364 newlines.append(line)
365 newnotes = "\n".join(newlines) 365 newnotes = "\n".join(newlines)
366 if origin in ["programmer", "developer", "source code"]: 366 if origin in ["programmer", "developer", "source code"]:
367 gpo.po_message_set_extracted_comments(self._gpo_message, newnote s) 367 gpo.po_message_set_extracted_comments(self._gpo_message, newnote s)
368 else: 368 else:
369 gpo.po_message_set_comments(self._gpo_message, newnotes) 369 gpo.po_message_set_comments(self._gpo_message, newnotes)
370 370
371 def removenotes(self): 371 def removenotes(self):
372 gpo.po_message_set_comments(self._gpo_message, "") 372 gpo.po_message_set_comments(self._gpo_message, "")
373 373
374 def copy(self): 374 def copy(self):
375 """Returns a copy of the this unit that can be used independently. 375 """Returns a copy of the this unit that can be used independently.
376 """ 376 """
377 unit = pounit() 377 unit = pounit()
378 unit.source = self.source 378 unit.source = self.source
379 unit.target = self.target 379 unit.target = self.target
380 unit.markfuzzy(self.isfuzzy()) 380 unit.markfuzzy(self.isfuzzy())
381 if self.isobsolete(): 381 if self.isobsolete():
382 unit.makeobsolete() 382 unit.makeobsolete()
383 for location in self.getlocations(): 383 for location in self.getlocations():
384 unit.addlocation(location) 384 unit.addlocation(location)
385 notes = [] 385 notes = []
386 origins = ['translator', 'developer', 'programmer', 'source code'] 386 origins = ['translator', 'developer', 'programmer', 'source code']
387 for origin in origins: 387 for origin in origins:
388 note = self.getnotes(origin=origin) 388 note = self.getnotes(origin=origin)
389 if note in notes: 389 if note in notes:
390 continue 390 continue
391 else: 391 if note:
392 unit.addnote(note, origin=origin) 392 unit.addnote(note, origin=origin)
393 notes.append(note) 393 notes.append(note)
394 context = gpo.po_message_msgctxt(self._gpo_message) 394 context = gpo.po_message_msgctxt(self._gpo_message)
395 if context: 395 if context:
396 unit.setcontext(context) 396 unit.setcontext(context)
397 comments = self._extract_msgidcomments() 397 comments = self._extract_msgidcomments()
398 if comments: 398 if comments:
399 unit.setmsgidcomment(comments) 399 unit.setmsgidcomment(comments)
400 for typecomment in self.gettypecomments(): 400 for typecomment in self.gettypecomments():
401 unit.addtypecomment(typecomment) 401 unit.addtypecomment(typecomment)
402 return unit 402 return unit
403 403
404 def merge(self, otherpo, overwrite=False, comments=True, authoritative=False ): 404 def merge(self, otherpo, overwrite=False, comments=True, authoritative=False ):
405 """Merges the otherpo (with the same msgid) into this one. 405 """Merges the otherpo (with the same msgid) into this one.
406 406
407 Overwrite non-blank self.msgstr only if overwrite is True 407 Overwrite non-blank self.msgstr only if overwrite is True
408 merge comments only if comments is True 408 merge comments only if comments is True
409 409
410 """ 410 """
411 411
412 if not isinstance(otherpo, pounit): 412 if not isinstance(otherpo, pounit):
413 super(pounit, self).merge(otherpo, overwrite, comments) 413 super(pounit, self).merge(otherpo, overwrite, comments)
414 return 414 return
415 if comments: 415 if comments:
416 self.addnote(otherpo.getnotes("translator"), origin="translator", po sition="merge") 416 self.addnote(otherpo.getnotes("translator"), origin="translator", po sition="merge")
417 # FIXME mergelists(self.typecomments, otherpo.typecomments) 417 # FIXME mergelists(self.typecomments, otherpo.typecomments)
418 if not authoritative: 418 if not authoritative:
419 # We don't bring across otherpo.automaticcomments as we consider ourself 419 # We don't bring across otherpo.automaticcomments as we consider ourself
420 # to be the the authority. Same applies to otherpo.msgidcomment s 420 # to be the the authority. Same applies to otherpo.msgidcomment s
421 self.addnote(otherpo.getnotes("developer"), origin="developer", position="merge") 421 self.addnote(otherpo.getnotes("developer"), origin="developer", position="merge")
422 self.msgidcomment = otherpo._extract_msgidcomments() or None 422 self.msgidcomment = otherpo._extract_msgidcomments() or None
423 self.addlocations(otherpo.getlocations()) 423 self.addlocations(otherpo.getlocations())
424 if not self.istranslated() or overwrite: 424 if not self.istranslated() or overwrite:
425 # Remove kde-style comments from the translation (if any). 425 # Remove kde-style comments from the translation (if any).
426 if self._extract_msgidcomments(otherpo.target): 426 if self._extract_msgidcomments(otherpo.target):
427 otherpo.target = otherpo.target.replace('_: ' + otherpo._extract _msgidcomments()+ '\n', '') 427 otherpo.target = otherpo.target.replace('_: ' + otherpo._extract _msgidcomments()+ '\n', '')
428 self.target = otherpo.target 428 self.target = otherpo.target
429 if self.source != otherpo.source: 429 if self.source != otherpo.source:
430 self.markfuzzy() 430 self.markfuzzy()
431 else: 431 else:
432 self.markfuzzy(otherpo.isfuzzy()) 432 self.markfuzzy(otherpo.isfuzzy())
433 elif not otherpo.istranslated(): 433 elif not otherpo.istranslated():
434 if self.source != otherpo.source: 434 if self.source != otherpo.source:
435 self.markfuzzy() 435 self.markfuzzy()
436 else: 436 else:
437 if self.target != otherpo.target: 437 if self.target != otherpo.target:
438 self.markfuzzy() 438 self.markfuzzy()
439 439
440 def isheader(self): 440 def isheader(self):
441 #return self.source == u"" and self.target != u"" 441 #return self.source == u"" and self.target != u""
442 # we really want to make sure that there is no msgidcomment or msgctxt 442 # we really want to make sure that there is no msgidcomment or msgctxt
443 return self.getid() == "" and len(self.target) > 0 443 return self.getid() == "" and len(self.target) > 0
444 444
445 def isblank(self): 445 def isblank(self):
446 return len(self.source) == 0 and len(self.target) == 0 446 return len(self.source) == 0 and len(self.target) == 0
447 447
448 def hastypecomment(self, typecomment): 448 def hastypecomment(self, typecomment):
449 return gpo.po_message_is_format(self._gpo_message, typecomment) 449 return gpo.po_message_is_format(self._gpo_message, typecomment)
450 450
451 def gettypecomments(self): 451 def gettypecomments(self):
452 """Returns the type comments of a unit, if any. 452 #XXX: brute force hack
453
454 @return: a list containing the type comments of the unit
455 """
456 #XXX: brute force
457 formats = [ 453 formats = [
458 "c", "objc", "sh", "python", "lisp", "elisp", "librep", "scheme", 454 "c", "objc", "sh", "python", "lisp", "elisp", "librep", "scheme",
459 "smalltalk", "java", "csharp", "awk", "object-pascal", "ycp", "tcl", 455 "smalltalk", "java", "csharp", "awk", "object-pascal", "ycp", "tcl",
460 "perl", "perl-brace", "php", "gcc-internal", "qt", "kde", "boost", 456 "perl", "perl-brace", "php", "gcc-internal", "qt", "kde", "boost",
461 ] 457 ]
462 comments = [] 458 comments = []
463 for format in formats: 459 for format in formats:
464 format += '-format' 460 format += '-format'
465 if self.hastypecomment(format): 461 if self.hastypecomment(format):
466 comments.append(format) 462 comments.append(format)
467 return comments 463 return comments
468 464
469 def addtypecomment(self, typecomment): 465 def addtypecomment(self, typecomment):
470 """Adds a type comment to the unit
471
472 @oaram typecomment: the type comment to be added, for example
473 "c-format".
474 """
475 gpo.po_message_set_format(self._gpo_message, typecomment, 1) 466 gpo.po_message_set_format(self._gpo_message, typecomment, 1)
476 467
477 def hasmarkedcomment(self, commentmarker): 468 def hasmarkedcomment(self, commentmarker):
478 commentmarker = "(%s)" % commentmarker 469 commentmarker = "(%s)" % commentmarker
479 for comment in self.getnotes("translator").split("\n"): 470 for comment in self.getnotes("translator").split("\n"):
480 if comment.startswith(commentmarker): 471 if comment.startswith(commentmarker):
481 return True 472 return True
482 return False 473 return False
483 474
484 def istranslated(self): 475 def istranslated(self):
485 return super(pounit, self).istranslated() and not self.isobsolete() 476 return super(pounit, self).istranslated() and not self.isobsolete()
486 477
487 def istranslatable(self): 478 def istranslatable(self):
488 return not (self.isheader() or self.isblank() or self.isobsolete()) 479 return not (self.isheader() or self.isblank() or self.isobsolete())
489 480
490 def isfuzzy(self): 481 def isfuzzy(self):
491 return gpo.po_message_is_fuzzy(self._gpo_message) 482 return gpo.po_message_is_fuzzy(self._gpo_message)
492 483
493 def markfuzzy(self, present=True): 484 def markfuzzy(self, present=True):
494 gpo.po_message_set_fuzzy(self._gpo_message, present) 485 gpo.po_message_set_fuzzy(self._gpo_message, present)
495 486
496 def isreview(self): 487 def isreview(self):
497 return self.hasmarkedcomment("review") or self.hasmarkedcomment("pofilte r") 488 return self.hasmarkedcomment("review") or self.hasmarkedcomment("pofilte r")
498 489
499 def isobsolete(self): 490 def isobsolete(self):
500 return gpo.po_message_is_obsolete(self._gpo_message) 491 return gpo.po_message_is_obsolete(self._gpo_message)
501 492
502 def makeobsolete(self): 493 def makeobsolete(self):
503 # FIXME: libgettexpo currently does not reset other data, we probably wa nt to do that 494 # FIXME: libgettexpo currently does not reset other data, we probably wa nt to do that
504 # but a better solution would be for libgettextpo to output correct data on serialisation 495 # but a better solution would be for libgettextpo to output correct data on serialisation
505 gpo.po_message_set_obsolete(self._gpo_message, True) 496 gpo.po_message_set_obsolete(self._gpo_message, True)
506 497
507 def resurrect(self): 498 def resurrect(self):
508 gpo.po_message_set_obsolete(self._gpo_message, False) 499 gpo.po_message_set_obsolete(self._gpo_message, False)
509 500
510 def hasplural(self): 501 def hasplural(self):
511 return gpo.po_message_msgid_plural(self._gpo_message) is not None 502 return gpo.po_message_msgid_plural(self._gpo_message) is not None
512 503
513 def _extract_msgidcomments(self, text=None): 504 def _extract_msgidcomments(self, text=None):
514 """Extract KDE style msgid comments from the unit. 505 """Extract KDE style msgid comments from the unit.
515 506
516 @rtype: String 507 @rtype: String
517 @return: Returns the extracted msgidcomments found in this unit's msgid. 508 @return: Returns the extracted msgidcomments found in this unit's msgid.
518 509
519 """ 510 """
520 511
521 if not text: 512 if not text:
522 text = gpo.po_message_msgid(self._gpo_message) 513 text = gpo.po_message_msgid(self._gpo_message)
523 if text: 514 if text:
524 msgidcomment = re.search("_: (.*)\n", text) 515 msgidcomment = re.search("_: (.*)\n", text)
525 if msgidcomment: 516 if msgidcomment:
526 return msgidcomment.group(1).decode(self._encoding) 517 return msgidcomment.group(1).decode(self._encoding)
527 return u"" 518 return u""
528 519
529 def __str__(self): 520 def __str__(self):
530 pf = pofile() 521 pf = pofile()
531 unit = self.copy() 522 unit = self.copy()
532 pf.addunit(unit) 523 pf.addunit(unit)
533 return str(pf) 524 return str(pf)
534 525
535 def getlocations(self): 526 def getlocations(self):
536 locations = [] 527 locations = []
537 i = 0 528 i = 0
538 location = gpo.po_message_filepos(self._gpo_message, i) 529 location = gpo.po_message_filepos(self._gpo_message, i)
539 while location: 530 while location:
540 locname = gpo.po_filepos_file(location) 531 locname = gpo.po_filepos_file(location)
541 locline = gpo.po_filepos_start_line(location) 532 locline = gpo.po_filepos_start_line(location)
542 if locline == -1: 533 if locline == -1:
543 locstring = locname 534 locstring = locname
544 else: 535 else:
545 locstring = locname + ":" + str(locline) 536 locstring = locname + ":" + str(locline)
546 locations.append(locstring) 537 locations.append(locstring)
547 i += 1 538 i += 1
548 location = gpo.po_message_filepos(self._gpo_message, i) 539 location = gpo.po_message_filepos(self._gpo_message, i)
549 return locations 540 return locations
550 541
551 def addlocation(self, location): 542 def addlocation(self, location):
552 for loc in location.split(): 543 for loc in location.split():
553 parts = loc.split(":") 544 parts = loc.split(":")
554 file = parts[0] 545 file = parts[0]
555 if len(parts) == 2: 546 if len(parts) == 2:
556 line = int(parts[1]) 547 line = int(parts[1])
557 else: 548 else:
558 line = -1 549 line = -1
559 gpo.po_message_add_filepos(self._gpo_message, file, line) 550 gpo.po_message_add_filepos(self._gpo_message, file, line)
560 551
561 def setcontext(self, context): 552 def setcontext(self, context):
562 """Sets the context message""" 553 """Sets the context message"""
554 #FIXME: not complete
563 gpo.po_message_set_msgctxt(self._gpo_message, context) 555 gpo.po_message_set_msgctxt(self._gpo_message, context)
564 556
565 def getcontext(self): 557 def getcontext(self):
566 msgctxt = gpo.po_message_msgctxt(self._gpo_message) 558 msgctxt = gpo.po_message_msgctxt(self._gpo_message)
567 msgidcomment = self._extract_msgidcomments() 559 msgidcomment = self._extract_msgidcomments()
568 if msgctxt: 560 if msgctxt:
569 return msgctxt + msgidcomment 561 return msgctxt + msgidcomment
570 else: 562 else:
571 return msgidcomment 563 return msgidcomment
572 564
573 class pofile(pocommon.pofile): 565 class pofile(pocommon.pofile):
574 UnitClass = pounit 566 UnitClass = pounit
575 def __init__(self, inputfile=None, encoding=None, unitclass=pounit): 567 def __init__(self, inputfile=None, encoding=None, unitclass=pounit):
576 self.UnitClass = unitclass 568 self.UnitClass = unitclass
577 pocommon.pofile.__init__(self, unitclass=unitclass) 569 pocommon.pofile.__init__(self, unitclass=unitclass)
578 self._gpo_memory_file = None 570 self._gpo_memory_file = None
579 self._gpo_message_iterator = None 571 self._gpo_message_iterator = None
580 self._encoding = encodingToUse(encoding) 572 self._encoding = encodingToUse(encoding)
581 if inputfile is not None: 573 if inputfile is not None:
582 self.parse(inputfile) 574 self.parse(inputfile)
583 else: 575 else:
584 self._gpo_memory_file = gpo.po_file_create() 576 self._gpo_memory_file = gpo.po_file_create()
585 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memor y_file, None) 577 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memor y_file, None)
586 578
587 def addunit(self, unit): 579 def addunit(self, unit):
588 unitcopy = unit.copy() 580 unitcopy = unit.copy()
589 gpo.po_message_insert(self._gpo_message_iterator, unitcopy._gpo_message) 581 gpo.po_message_insert(self._gpo_message_iterator, unitcopy._gpo_message)
590 self.units.append(unitcopy) 582 self.units.append(unitcopy)
591
592 def addsourceunit(self, source):
593 self.addunit(self.UnitClass(source))
594 unit = self.findunit(source)
595 return unit
596 583
597 def removeduplicates(self, duplicatestyle="merge"): 584 def removeduplicates(self, duplicatestyle="merge"):
598 """make sure each msgid is unique ; merge comments etc from duplicates i nto original""" 585 """make sure each msgid is unique ; merge comments etc from duplicates i nto original"""
599 msgiddict = {} 586 msgiddict = {}
600 uniqueunits = [] 587 uniqueunits = []
601 # we sometimes need to keep track of what has been marked 588 # we sometimes need to keep track of what has been marked
602 # TODO: this is using a list as the pos aren't hashable, but this is slo w... 589 # TODO: this is using a list as the pos aren't hashable, but this is slo w...
603 markedpos = [] 590 markedpos = []
604 def addcomment(thepo): 591 def addcomment(thepo):
605 thepo.msgidcomment = " ".join(thepo.getlocations()) 592 thepo.msgidcomment = " ".join(thepo.getlocations())
606 markedpos.append(thepo) 593 markedpos.append(thepo)
607 for thepo in self.units: 594 for thepo in self.units:
608 if thepo.isheader(): 595 if thepo.isheader():
609 uniqueunits.append(thepo) 596 uniqueunits.append(thepo)
610 continue 597 continue
611 if duplicatestyle.startswith("msgid_comment"): 598 if duplicatestyle.startswith("msgid_comment"):
612 msgid = thepo._extract_msgidcomments() + thepo.source 599 msgid = thepo._extract_msgidcomments() + thepo.source
613 else: 600 else:
614 msgid = thepo.source 601 msgid = thepo.source
615 if duplicatestyle == "msgid_comment_all": 602 if duplicatestyle == "msgid_comment_all":
616 addcomment(thepo) 603 addcomment(thepo)
617 uniqueunits.append(thepo) 604 uniqueunits.append(thepo)
618 elif msgid in msgiddict: 605 elif msgid in msgiddict:
619 if duplicatestyle == "merge": 606 if duplicatestyle == "merge":
620 if msgid: 607 if msgid:
621 msgiddict[msgid].merge(thepo) 608 msgiddict[msgid].merge(thepo)
622 else: 609 else:
623 addcomment(thepo) 610 addcomment(thepo)
624 uniqueunits.append(thepo) 611 uniqueunits.append(thepo)
625 elif duplicatestyle == "keep": 612 elif duplicatestyle == "keep":
626 uniqueunits.append(thepo) 613 uniqueunits.append(thepo)
627 elif duplicatestyle == "msgid_comment": 614 elif duplicatestyle == "msgid_comment":
628 origpo = msgiddict[msgid] 615 origpo = msgiddict[msgid]
629 if origpo not in markedpos: 616 if origpo not in markedpos:
630 addcomment(origpo) 617 addcomment(origpo)
631 addcomment(thepo) 618 addcomment(thepo)
632 uniqueunits.append(thepo) 619 uniqueunits.append(thepo)
633 elif duplicatestyle == "msgctxt": 620 elif duplicatestyle == "msgctxt":
634 origpo = msgiddict[msgid] 621 origpo = msgiddict[msgid]
635 if origpo not in markedpos: 622 if origpo not in markedpos:
636 gpo.po_message_set_msgctxt(origpo._gpo_message, " ".join (origpo.getlocations())) 623 gpo.po_message_set_msgctxt(origpo._gpo_message, " ".join (origpo.getlocations()))
637 markedpos.append(thepo) 624 markedpos.append(thepo)
638 gpo.po_message_set_msgctxt(thepo._gpo_message, " ".join(thep o.getlocations())) 625 gpo.po_message_set_msgctxt(thepo._gpo_message, " ".join(thep o.getlocations()))
639 uniqueunits.append(thepo) 626 uniqueunits.append(thepo)
640 else: 627 else:
641 if not msgid and duplicatestyle != "keep": 628 if not msgid and duplicatestyle != "keep":
642 addcomment(thepo) 629 addcomment(thepo)
643 msgiddict[msgid] = thepo 630 msgiddict[msgid] = thepo
644 uniqueunits.append(thepo) 631 uniqueunits.append(thepo)
645 new_gpo_memory_file = gpo.po_file_create() 632 new_gpo_memory_file = gpo.po_file_create()
646 new_gpo_message_iterator = gpo.po_message_iterator(new_gpo_memory_file, None) 633 new_gpo_message_iterator = gpo.po_message_iterator(new_gpo_memory_file, None)
647 for unit in uniqueunits: 634 for unit in uniqueunits:
648 gpo.po_message_insert(new_gpo_message_iterator, unit._gpo_message) 635 gpo.po_message_insert(new_gpo_message_iterator, unit._gpo_message)
649 gpo.po_message_iterator_free(self._gpo_message_iterator) 636 gpo.po_message_iterator_free(self._gpo_message_iterator)
650 self._gpo_message_iterator = new_gpo_message_iterator 637 self._gpo_message_iterator = new_gpo_message_iterator
651 self._gpo_memory_file = new_gpo_memory_file 638 self._gpo_memory_file = new_gpo_memory_file
652 self.units = uniqueunits 639 self.units = uniqueunits
653 640
654 def __str__(self): 641 def __str__(self):
655 def obsolete_workaround(): 642 def obsolete_workaround():
656 # Remove all items that are not output by msgmerge when a unit is ob solete. This is a work 643 # Remove all items that are not output by msgmerge when a unit is ob solete. This is a work
657 # around for bug in libgettextpo 644 # around for bug in libgettextpo
658 # FIXME Do version test in case they fix this bug 645 # FIXME Do version test in case they fix this bug
659 for unit in self.units: 646 for unit in self.units:
660 if unit.isobsolete(): 647 if unit.isobsolete():
661 gpo.po_message_set_extracted_comments(unit._gpo_message, "") 648 gpo.po_message_set_extracted_comments(unit._gpo_message, "")
662 location = gpo.po_message_filepos(unit._gpo_message, 0) 649 location = gpo.po_message_filepos(unit._gpo_message, 0)
663 while location: 650 while location:
664 gpo.po_message_remove_filepos(unit._gpo_message, 0) 651 gpo.po_message_remove_filepos(unit._gpo_message, 0)
665 location = gpo.po_message_filepos(unit._gpo_message, 0) 652 location = gpo.po_message_filepos(unit._gpo_message, 0)
666
667 outputstring = "" 653 outputstring = ""
668 if self._gpo_memory_file: 654 if self._gpo_memory_file:
669 obsolete_workaround() 655 obsolete_workaround()
670 f = tempfile.NamedTemporaryFile(prefix='translate', suffix='.po') 656 f = tempfile.NamedTemporaryFile(prefix='translate', suffix='.po')
671 self._gpo_memory_file = gpo.po_file_write_v2(self._gpo_memory_file, f.name, xerror_handler) 657 self._gpo_memory_file = gpo.po_file_write_v2(self._gpo_memory_file, f.name, xerror_handler)
672 f.seek(0) 658 f.seek(0)
673 outputstring = f.read() 659 outputstring = f.read()
674 f.close() 660 f.close()
675 return outputstring 661 return outputstring
676 662
677 def isempty(self): 663 def isempty(self):
678 """Returns True if the object doesn't contain any translation units.""" 664 """Returns True if the object doesn't contain any translation units."""
679 if len(self.units) == 0: 665 if len(self.units) == 0:
680 return True 666 return True
681 # Skip the first unit if it is a header. 667 # Skip the first unit if it is a header.
682 if self.units[0].isheader(): 668 if self.units[0].isheader():
683 units = self.units[1:] 669 units = self.units[1:]
684 else: 670 else:
685 units = self.units 671 units = self.units
686 672
687 for unit in units: 673 for unit in units:
688 if not unit.isblank() and not unit.isobsolete(): 674 if not unit.isblank() and not unit.isobsolete():
689 return False 675 return False
690 return True 676 return True
691 677
692 def parse(self, input): 678 def parse(self, input):
693 if hasattr(input, 'name'): 679 if hasattr(input, 'name'):
694 self.filename = input.name 680 self.filename = input.name
695 elif not getattr(self, 'filename', ''): 681 elif not getattr(self, 'filename', ''):
696 self.filename = '' 682 self.filename = ''
697 683
698 if hasattr(input, "read"): 684 if hasattr(input, "read"):
699 posrc = input.read() 685 posrc = input.read()
700 input.close() 686 input.close()
701 input = posrc 687 input = posrc
702 688
703 needtmpfile = not os.path.isfile(input) 689 needtmpfile = not os.path.isfile(input)
704 if needtmpfile: 690 if needtmpfile:
705 # This is not a file - we write the string to a temporary file 691 # This is not a file - we write the string to a temporary file
706 fd, fname = tempfile.mkstemp(prefix='translate', suffix='.po') 692 fd, fname = tempfile.mkstemp(prefix='translate', suffix='.po')
707 os.write(fd, input) 693 os.write(fd, input)
708 input = fname 694 input = fname
709 os.close(fd) 695 os.close(fd)
710 696
711 self._gpo_memory_file = gpo.po_file_read_v3(input, xerror_handler) 697 self._gpo_memory_file = gpo.po_file_read_v3(input, xerror_handler)
712 if self._gpo_memory_file is None: 698 if self._gpo_memory_file is None:
713 print >> sys.stderr, "Error:" 699 print >> sys.stderr, "Error:"
714 700
715 if needtmpfile: 701 if needtmpfile:
716 os.remove(input) 702 os.remove(input)
717 703
718 # Handle xerrors here 704 # Handle xerrors here
719 self._header = gpo.po_file_domain_header(self._gpo_memory_file, None) 705 self._header = gpo.po_file_domain_header(self._gpo_memory_file, None)
720 if self._header: 706 if self._header:
721 charset = gpo.po_header_field(self._header, "Content-Type") 707 charset = gpo.po_header_field(self._header, "Content-Type")
722 if charset: 708 if charset:
723 charset = re.search("charset=([^\\s]+)", charset).group(1) 709 charset = re.search("charset=([^\\s]+)", charset).group(1)
724 self._encoding = encodingToUse(charset) 710 self._encoding = encodingToUse(charset)
725 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memory_fi le, None) 711 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memory_fi le, None)
726 newmessage = gpo.po_next_message(self._gpo_message_iterator) 712 newmessage = gpo.po_next_message(self._gpo_message_iterator)
727 while newmessage: 713 while newmessage:
728 newunit = pounit(gpo_message=newmessage) 714 newunit = pounit(gpo_message=newmessage)
729 self.units.append(newunit) 715 self.units.append(newunit)
730 newmessage = gpo.po_next_message(self._gpo_message_iterator) 716 newmessage = gpo.po_next_message(self._gpo_message_iterator)
731 717
732 def __del__(self): 718 def __del__(self):
733 # We currently disable this while we still get segmentation faults. 719 # We currently disable this while we still get segmentation faults.
734 # Note that this is definitely leaking memory because of this. 720 # Note that this is definitely leaking memory because of this.
735 self._free_iterator() 721 self._free_iterator()
736 if self._gpo_memory_file is not None: 722 if self._gpo_memory_file is not None:
737 gpo.po_file_free(self._gpo_memory_file) 723 gpo.po_file_free(self._gpo_memory_file)
738 self._gpo_memory_file = None 724 self._gpo_memory_file = None
739 725
740 def _free_iterator(self): 726 def _free_iterator(self):
741 # We currently disable this while we still get segmentation faults. 727 # We currently disable this while we still get segmentation faults.
742 # Note that this is definitely leaking memory because of this. 728 # Note that this is definitely leaking memory because of this.
743 if self._gpo_message_iterator is not None: 729 if self._gpo_message_iterator is not None:
744 gpo.po_message_iterator_free(self._gpo_message_iterator) 730 gpo.po_message_iterator_free(self._gpo_message_iterator)
745 self._gpo_message_iterator = None 731 self._gpo_message_iterator = None
LEFTRIGHT

Powered by Google App Engine
This is Rietveld r159