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

Side by Side Diff: translate/storage/cpo.py

Issue 65: xliff2po & po2xliff should handle context SVN Base: https://translate.svn.sourceforge.net/svnroot/translate/src/trunk/
Patch Set: 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:
View unified diff
OLDNEW
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 414 matching lines...) Show 10 above Show 10 below
465 @return: Returns the extracted msgidcomments found in this unit's msgid. 465 @return: Returns the extracted msgidcomments found in this unit's msgid.
466 466
467 """ 467 """
468 468
469 if not text: 469 if not text:
470 text = gpo.po_message_msgid(self._gpo_message) 470 text = gpo.po_message_msgid(self._gpo_message)
471 if text: 471 if text:
472 msgidcomment = re.search("_: (.*)\n", text) 472 msgidcomment = re.search("_: (.*)\n", text)
473 if msgidcomment: 473 if msgidcomment:
474 return msgidcomment.group(1).decode(self._encoding) 474 return msgidcomment.group(1).decode(self._encoding)
475 return u"" 475 return u""
476 476
477 def __str__(self): 477 def __str__(self):
478 pf = pofile() 478 pf = pofile()
479 pf.addunit(self) 479 pf.addunit(self)
480 return str(pf) 480 return str(pf)
481 481
482 def getlocations(self): 482 def getlocations(self):
483 locations = [] 483 locations = []
484 i = 0 484 i = 0
485 location = gpo.po_message_filepos(self._gpo_message, i) 485 location = gpo.po_message_filepos(self._gpo_message, i)
486 while location: 486 while location:
487 locname = gpo.po_filepos_file(location) 487 locname = gpo.po_filepos_file(location)
488 locline = gpo.po_filepos_start_line(location) 488 locline = gpo.po_filepos_start_line(location)
489 if locline == -1: 489 if locline == -1:
490 locstring = locname 490 locstring = locname
491 else: 491 else:
492 locstring = locname + ":" + str(locline) 492 locstring = locname + ":" + str(locline)
493 locations.append(locstring) 493 locations.append(locstring)
494 i += 1 494 i += 1
495 location = gpo.po_message_filepos(self._gpo_message, i) 495 location = gpo.po_message_filepos(self._gpo_message, i)
496 return locations 496 return locations
497 497
498 def addlocation(self, location): 498 def addlocation(self, location):
499 for loc in location.split(): 499 for loc in location.split():
500 parts = loc.split(":") 500 parts = loc.split(":")
501 file = parts[0] 501 file = parts[0]
502 if len(parts) == 2: 502 if len(parts) == 2:
503 line = int(parts[1]) 503 line = int(parts[1])
504 else: 504 else:
505 line = -1 505 line = -1
506 gpo.po_message_add_filepos(self._gpo_message, file, line) 506 gpo.po_message_add_filepos(self._gpo_message, file, line)
507 507
508 def getcontext(self): 508 def getcontext(self):
509 msgctxt = gpo.po_message_msgctxt(self._gpo_message) 509 msgctxt = gpo.po_message_msgctxt(self._gpo_message)
510 msgidcomment = self._extract_msgidcomments() 510 msgidcomment = self._extract_msgidcomments()
511 if msgctxt: 511 if msgctxt:
512 return msgctxt + msgidcomment 512 return msgctxt + msgidcomment
513 else: 513 else:
514 return msgidcomment 514 return msgidcomment
515
516 def setcontext(self, context):
517 """Sets the current context for this unit"""
georgeyk 2008/07/24 05:14:28 Should I care about the getcontext() ? The getcont
518 # TODO: inspect what behavior this should really have
519 gpo.po_message_set_msgctxt(self._gpo_message, context)
515 520
516 class pofile(pocommon.pofile): 521 class pofile(pocommon.pofile):
517 UnitClass = pounit 522 UnitClass = pounit
518 def __init__(self, inputfile=None, encoding=None, unitclass=pounit): 523 def __init__(self, inputfile=None, encoding=None, unitclass=pounit):
519 self.UnitClass = unitclass 524 self.UnitClass = unitclass
520 pocommon.pofile.__init__(self, unitclass=unitclass) 525 pocommon.pofile.__init__(self, unitclass=unitclass)
521 self._gpo_memory_file = None 526 self._gpo_memory_file = None
522 self._gpo_message_iterator = None 527 self._gpo_message_iterator = None
523 self._encoding = encodingToUse(encoding) 528 self._encoding = encodingToUse(encoding)
524 if inputfile is not None: 529 if inputfile is not None:
525 self.parse(inputfile) 530 self.parse(inputfile)
526 else: 531 else:
527 self._gpo_memory_file = gpo.po_file_create() 532 self._gpo_memory_file = gpo.po_file_create()
528 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memor y_file, None) 533 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memor y_file, None)
529 534
530 def addunit(self, unit): 535 def addunit(self, unit):
531 gpo.po_message_insert(self._gpo_message_iterator, unit._gpo_message) 536 gpo.po_message_insert(self._gpo_message_iterator, unit._gpo_message)
532 self.units.append(unit) 537 self.units.append(unit)
533 538
534 def removeduplicates(self, duplicatestyle="merge"): 539 def removeduplicates(self, duplicatestyle="merge"):
535 """make sure each msgid is unique ; merge comments etc from duplicates i nto original""" 540 """make sure each msgid is unique ; merge comments etc from duplicates i nto original"""
536 msgiddict = {} 541 msgiddict = {}
537 uniqueunits = [] 542 uniqueunits = []
538 # we sometimes need to keep track of what has been marked 543 # we sometimes need to keep track of what has been marked
539 # TODO: this is using a list as the pos aren't hashable, but this is slo w... 544 # TODO: this is using a list as the pos aren't hashable, but this is slo w...
540 markedpos = [] 545 markedpos = []
541 def addcomment(thepo): 546 def addcomment(thepo):
542 thepo.msgidcomment = " ".join(thepo.getlocations()) 547 thepo.msgidcomment = " ".join(thepo.getlocations())
543 markedpos.append(thepo) 548 markedpos.append(thepo)
544 for thepo in self.units: 549 for thepo in self.units:
545 if thepo.isheader(): 550 if thepo.isheader():
546 uniqueunits.append(thepo) 551 uniqueunits.append(thepo)
547 continue 552 continue
548 if duplicatestyle.startswith("msgid_comment"): 553 if duplicatestyle.startswith("msgid_comment"):
549 msgid = thepo._extract_msgidcomments() + thepo.source 554 msgid = thepo._extract_msgidcomments() + thepo.source
550 else: 555 else:
551 msgid = thepo.source 556 msgid = thepo.source
552 if duplicatestyle == "msgid_comment_all": 557 if duplicatestyle == "msgid_comment_all":
553 addcomment(thepo) 558 addcomment(thepo)
554 uniqueunits.append(thepo) 559 uniqueunits.append(thepo)
555 elif msgid in msgiddict: 560 elif msgid in msgiddict:
556 if duplicatestyle == "merge": 561 if duplicatestyle == "merge":
557 if msgid: 562 if msgid:
558 msgiddict[msgid].merge(thepo) 563 msgiddict[msgid].merge(thepo)
559 else: 564 else:
560 addcomment(thepo) 565 addcomment(thepo)
561 uniqueunits.append(thepo) 566 uniqueunits.append(thepo)
562 elif duplicatestyle == "keep": 567 elif duplicatestyle == "keep":
563 uniqueunits.append(thepo) 568 uniqueunits.append(thepo)
564 elif duplicatestyle == "msgid_comment": 569 elif duplicatestyle == "msgid_comment":
(...skipping 70 matching lines...) Show 10 above Show 10 below
635 posrc = input.read() 640 posrc = input.read()
636 input.close() 641 input.close()
637 input = posrc 642 input = posrc
638 643
639 needtmpfile = not os.path.isfile(input) 644 needtmpfile = not os.path.isfile(input)
640 if needtmpfile: 645 if needtmpfile:
641 # This is not a file - we write the string to a temporary file 646 # This is not a file - we write the string to a temporary file
642 fd, fname = tempfile.mkstemp(prefix='translate', suffix='.po') 647 fd, fname = tempfile.mkstemp(prefix='translate', suffix='.po')
643 os.write(fd, input) 648 os.write(fd, input)
644 input = fname 649 input = fname
645 os.close(fd) 650 os.close(fd)
646 651
647 self._gpo_memory_file = gpo.po_file_read_v3(input, xerror_handler) 652 self._gpo_memory_file = gpo.po_file_read_v3(input, xerror_handler)
648 if self._gpo_memory_file is None: 653 if self._gpo_memory_file is None:
649 print >> sys.stderr, "Error:" 654 print >> sys.stderr, "Error:"
650 655
651 if needtmpfile: 656 if needtmpfile:
652 os.remove(input) 657 os.remove(input)
653 658
654 # Handle xerrors here 659 # Handle xerrors here
655 self._header = gpo.po_file_domain_header(self._gpo_memory_file, None) 660 self._header = gpo.po_file_domain_header(self._gpo_memory_file, None)
656 if self._header: 661 if self._header:
657 charset = gpo.po_header_field(self._header, "Content-Type") 662 charset = gpo.po_header_field(self._header, "Content-Type")
658 if charset: 663 if charset:
659 charset = re.search("charset=([^\\s]+)", charset).group(1) 664 charset = re.search("charset=([^\\s]+)", charset).group(1)
660 self._encoding = encodingToUse(charset) 665 self._encoding = encodingToUse(charset)
661 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memory_fi le, None) 666 self._gpo_message_iterator = gpo.po_message_iterator(self._gpo_memory_fi le, None)
662 newmessage = gpo.po_next_message(self._gpo_message_iterator) 667 newmessage = gpo.po_next_message(self._gpo_message_iterator)
663 while newmessage: 668 while newmessage:
664 newunit = pounit(gpo_message=newmessage) 669 newunit = pounit(gpo_message=newmessage)
665 self.units.append(newunit) 670 self.units.append(newunit)
666 newmessage = gpo.po_next_message(self._gpo_message_iterator) 671 newmessage = gpo.po_next_message(self._gpo_message_iterator)
667 self._free_iterator() 672 self._free_iterator()
668 673
669 def __del__(self): 674 def __del__(self):
670 # We currently disable this while we still get segmentation faults. 675 # We currently disable this while we still get segmentation faults.
671 # Note that this is definitely leaking memory because of this. 676 # Note that this is definitely leaking memory because of this.
672 return 677 return
673 self._free_iterator() 678 self._free_iterator()
674 if self._gpo_memory_file is not None: 679 if self._gpo_memory_file is not None:
675 gpo.po_file_free(self._gpo_memory_file) 680 gpo.po_file_free(self._gpo_memory_file)
676 self._gpo_memory_file = None 681 self._gpo_memory_file = None
677 682
678 def _free_iterator(self): 683 def _free_iterator(self):
679 # We currently disable this while we still get segmentation faults. 684 # We currently disable this while we still get segmentation faults.
680 # Note that this is definitely leaking memory because of this. 685 # Note that this is definitely leaking memory because of this.
681 return 686 return
682 if self._gpo_message_iterator is not None: 687 if self._gpo_message_iterator is not None:
683 gpo.po_message_iterator_free(self._gpo_message_iterator) 688 gpo.po_message_iterator_free(self._gpo_message_iterator)
684 self._gpo_message_iterator = None 689 self._gpo_message_iterator = None
OLDNEW

Powered by Google App Engine
This is Rietveld r159