| LEFT | RIGHT |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # -*- coding: utf-8 -*- | 2 # -*- coding: utf-8 -*- |
| 3 # | 3 # |
| 4 # Copyright 2006-2008 Zuza Software Foundation | 4 # Copyright 2006-2008 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 """Base classes for storage interfaces. | 22 """Base classes for storage interfaces. |
| 23 | 23 |
| 24 @organization: Zuza Software Foundation | 24 @organization: Zuza Software Foundation |
| 25 @copyright: 2006-2007 Zuza Software Foundation | 25 @copyright: 2006-2007 Zuza Software Foundation |
| 26 @license: U{GPL <http://www.fsf.org/licensing/licenses/gpl.html>} | 26 @license: U{GPL <http://www.fsf.org/licensing/licenses/gpl.html>} |
| 27 """ | 27 """ |
| 28 | 28 |
| 29 try: | 29 try: |
| 30 import cPickle as pickle | 30 import cPickle as pickle |
| 31 except: | 31 except: |
| 32 import pickle | 32 import pickle |
| 33 from exceptions import NotImplementedError | 33 from exceptions import NotImplementedError |
| 34 | 34 |
| 35 def force_override(method, baseclass): | 35 def force_override(method, baseclass): |
| 36 """Forces derived classes to override method.""" | 36 """Forces derived classes to override method.""" |
| 37 | 37 |
| 38 if type(method.im_self) == type(baseclass): | 38 if type(method.im_self) == type(baseclass): |
| 39 # then this is a classmethod and im_self is the actual class | 39 # then this is a classmethod and im_self is the actual class |
| 40 actualclass = method.im_self | 40 actualclass = method.im_self |
| 41 else: | 41 else: |
| 42 actualclass = method.im_class | 42 actualclass = method.im_class |
| 43 if actualclass != baseclass: | 43 if actualclass != baseclass: |
| 44 raise NotImplementedError("%s does not reimplement %s as required by %s"
% (actualclass.__name__, method.__name__, baseclass.__name__)) | 44 raise NotImplementedError("%s does not reimplement %s as required by %s"
% (actualclass.__name__, method.__name__, baseclass.__name__)) |
| 45 | 45 |
| 46 class ParseError(Exception): | 46 class ParseError(Exception): |
| 47 pass | 47 pass |
| 48 | 48 |
| 49 class TranslationUnit(object): | 49 class TranslationUnit(object): |
| 50 """Base class for translation units. | 50 """Base class for translation units. |
| (...skipping 203 matching lines...) Show 10 above Show 10 below |
| 254 def isheader(self): | 254 def isheader(self): |
| 255 """Indicates whether this unit is a header.""" | 255 """Indicates whether this unit is a header.""" |
| 256 | 256 |
| 257 return False | 257 return False |
| 258 | 258 |
| 259 def isreview(self): | 259 def isreview(self): |
| 260 """Indicates whether this unit needs review.""" | 260 """Indicates whether this unit needs review.""" |
| 261 return False | 261 return False |
| 262 | 262 |
| 263 | 263 |
| 264 def isblank(self): | 264 def isblank(self): |
| 265 """Used to see if this unit has no source or target string. | 265 """Used to see if this unit has no source or target string. |
| 266 | 266 |
| 267 @note: This is probably used more to find translatable units, | 267 @note: This is probably used more to find translatable units, |
| 268 and we might want to move in that direction rather and get rid of this. | 268 and we might want to move in that direction rather and get rid of this. |
| 269 | 269 |
| 270 """ | 270 """ |
| 271 | 271 |
| 272 return not (self.source or self.target) | 272 return not (self.source or self.target) |
| 273 | 273 |
| 274 def hasplural(self): | 274 def hasplural(self): |
| 275 """Tells whether or not this specific unit has plural strings.""" | 275 """Tells whether or not this specific unit has plural strings.""" |
| 276 | 276 |
| 277 #TODO: Reconsider | 277 #TODO: Reconsider |
| 278 return False | 278 return False |
| 279 | 279 |
| 280 def getsourcelanguage(self): | 280 def getsourcelanguage(self): |
| 281 return getattr(self._store, "sourcelanguage", "en") | 281 return getattr(self._store, "sourcelanguage", "en") |
| 282 | 282 |
| 283 def gettargetlanguage(self): | 283 def gettargetlanguage(self): |
| 284 return getattr(self._store, "targetlanguage", None) | 284 return getattr(self._store, "targetlanguage", None) |
| 285 | 285 |
| 286 def merge(self, otherunit, overwrite=False, comments=True): | 286 def merge(self, otherunit, overwrite=False, comments=True): |
| 287 """Do basic format agnostic merging.""" | 287 """Do basic format agnostic merging.""" |
| 288 | 288 |
| 289 if self.target == "" or overwrite: | 289 if self.target == "" or overwrite: |
| 290 self.target = otherunit.target | 290 self.target = otherunit.target |
| 291 | 291 |
| 292 def unit_iter(self): | 292 def unit_iter(self): |
| 293 """Iterator that only returns this unit.""" | 293 """Iterator that only returns this unit.""" |
| 294 yield self | 294 yield self |
| 295 | 295 |
| 296 def getunits(self): | 296 def getunits(self): |
| 297 """This unit in a list.""" | 297 """This unit in a list.""" |
| 298 return [self] | 298 return [self] |
| 299 | 299 |
| 300 def buildfromunit(cls, unit): | 300 def buildfromunit(cls, unit): |
| 301 """Build a native unit from a foreign unit, preserving as much | 301 """Build a native unit from a foreign unit, preserving as much |
| 302 information as possible.""" | 302 information as possible.""" |
| 303 | 303 |
| 304 if type(unit) == cls and hasattr(unit, "copy") and callable(unit.copy): | 304 #if type(unit) == cls and hasattr(unit, "copy") and callable(unit.copy): |
| 305 return unit.copy() | 305 # return unit.copy() |
| 306 newunit = cls(unit.source) | 306 newunit = cls(unit.source) |
| 307 newunit.target = unit.target | 307 newunit.target = unit.target |
| 308 newunit.markfuzzy(unit.isfuzzy()) | 308 newunit.markfuzzy(unit.isfuzzy()) |
| 309 locations = unit.getlocations() | 309 locations = unit.getlocations() |
| 310 if locations: | 310 if locations: |
| 311 newunit.addlocations(locations) | 311 newunit.addlocations(locations) |
| 312 notes = unit.getnotes() | 312 notes = unit.getnotes() |
| 313 if notes: | 313 if notes: |
| 314 newunit.addnote(notes) | 314 newunit.addnote(notes) |
| 315 return newunit | 315 return newunit |
| 316 buildfromunit = classmethod(buildfromunit) | 316 buildfromunit = classmethod(buildfromunit) |
| 317 | 317 |
| 318 class TranslationStore(object): | 318 class TranslationStore(object): |
| 319 """Base class for stores for multiple translation units of type UnitClass.""
" | 319 """Base class for stores for multiple translation units of type UnitClass.""
" |
| 320 | 320 |
| 321 UnitClass = TranslationUnit | 321 UnitClass = TranslationUnit |
| 322 Mimetypes = None | 322 Mimetypes = None |
| 323 Extensions = None | 323 Extensions = None |
| 324 | 324 |
| 325 def __init__(self, unitclass=None): | 325 def __init__(self, unitclass=None): |
| 326 """Constructs a blank TranslationStore.""" | 326 """Constructs a blank TranslationStore.""" |
| 327 | 327 |
| 328 self.units = [] | 328 self.units = [] |
| 329 self.filepath = None | 329 self.filepath = None |
| 330 self.translator = "" | 330 self.translator = "" |
| 331 self.date = "" | 331 self.date = "" |
| 332 self.sourcelanguage = None | 332 self.sourcelanguage = None |
| 333 self.targetlanguage = None | 333 self.targetlanguage = None |
| 334 if unitclass: | 334 if unitclass: |
| 335 self.UnitClass = unitclass | 335 self.UnitClass = unitclass |
| 336 super(TranslationStore, self).__init__() | 336 super(TranslationStore, self).__init__() |
| 337 | 337 |
| 338 def setsourcelanguage(self, sourcelanguage): | 338 def setsourcelanguage(self, sourcelanguage): |
| 339 """Sets the source language for this store""" | 339 """Sets the source language for this store""" |
| 340 self.sourcelanguage = sourcelanguage | 340 self.sourcelanguage = sourcelanguage |
| 341 | 341 |
| 342 def settargetlanguage(self, targetlanguage): | 342 def settargetlanguage(self, targetlanguage): |
| 343 """Sets the target language for this store""" | 343 """Sets the target language for this store""" |
| 344 self.targetlanguage = targetlanguage | 344 self.targetlanguage = targetlanguage |
| 345 | 345 |
| 346 def unit_iter(self): | 346 def unit_iter(self): |
| 347 """Iterator over all the units in this store.""" | 347 """Iterator over all the units in this store.""" |
| 348 for unit in self.units: | 348 for unit in self.units: |
| 349 yield unit | 349 yield unit |
| 350 | 350 |
| 351 def getunits(self): | 351 def getunits(self): |
| 352 """Return a list of all units in this store.""" | 352 """Return a list of all units in this store.""" |
| 353 return [unit for unit in self.unit_iter()] | 353 return [unit for unit in self.unit_iter()] |
| 354 | 354 |
| 355 def addunit(self, unit): | 355 def addunit(self, unit): |
| (...skipping 104 matching lines...) Show 10 above Show 10 below |
| 460 return newstore | 460 return newstore |
| 461 parsestring = classmethod(parsestring) | 461 parsestring = classmethod(parsestring) |
| 462 | 462 |
| 463 def parse(self, data): | 463 def parse(self, data): |
| 464 """parser to process the given source string""" | 464 """parser to process the given source string""" |
| 465 self.units = pickle.loads(data).units | 465 self.units = pickle.loads(data).units |
| 466 | 466 |
| 467 def savefile(self, storefile): | 467 def savefile(self, storefile): |
| 468 """Writes the string representation to the given file (or filename).""" | 468 """Writes the string representation to the given file (or filename).""" |
| 469 if isinstance(storefile, basestring): | 469 if isinstance(storefile, basestring): |
| 470 storefile = open(storefile, "w") | 470 storefile = open(storefile, "w") |
| 471 self.fileobj = storefile | 471 self.fileobj = storefile |
| 472 self._assignname() | 472 self._assignname() |
| 473 storestring = str(self) | 473 storestring = str(self) |
| 474 storefile.write(storestring) | 474 storefile.write(storestring) |
| 475 storefile.close() | 475 storefile.close() |
| 476 | 476 |
| 477 def save(self): | 477 def save(self): |
| 478 """Save to the file that data was originally read from, if available.""" | 478 """Save to the file that data was originally read from, if available.""" |
| 479 fileobj = getattr(self, "fileobj", None) | 479 fileobj = getattr(self, "fileobj", None) |
| 480 if not fileobj: | 480 if not fileobj: |
| 481 filename = getattr(self, "filename", None) | 481 filename = getattr(self, "filename", None) |
| 482 if filename: | 482 if filename: |
| 483 fileobj = file(filename, "w") | 483 fileobj = file(filename, "w") |
| 484 else: | 484 else: |
| 485 fileobj.close() | 485 fileobj.close() |
| 486 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non
e)) | 486 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non
e)) |
| 487 if not filename: | 487 if not filename: |
| 488 raise ValueError("No file or filename to save to") | 488 raise ValueError("No file or filename to save to") |
| 489 fileobj = fileobj.__class__(filename, "w") | 489 fileobj = fileobj.__class__(filename, "w") |
| 490 self.savefile(fileobj) | 490 self.savefile(fileobj) |
| 491 | 491 |
| 492 def parsefile(cls, storefile): | 492 def parsefile(cls, storefile): |
| 493 """Reads the given file (or opens the given filename) and parses back to
an object.""" | 493 """Reads the given file (or opens the given filename) and parses back to
an object.""" |
| 494 | 494 |
| 495 if isinstance(storefile, basestring): | 495 if isinstance(storefile, basestring): |
| 496 storefile = open(storefile, "r") | 496 storefile = open(storefile, "r") |
| 497 mode = getattr(storefile, "mode", "r") | 497 mode = getattr(storefile, "mode", "r") |
| 498 #For some reason GzipFile returns 1, so we have to test for that here | 498 #For some reason GzipFile returns 1, so we have to test for that here |
| 499 if mode == 1 or "r" in mode: | 499 if mode == 1 or "r" in mode: |
| 500 storestring = storefile.read() | 500 storestring = storefile.read() |
| 501 storefile.close() | 501 storefile.close() |
| 502 else: | 502 else: |
| 503 storestring = "" | 503 storestring = "" |
| 504 newstore = cls.parsestring(storestring) | 504 newstore = cls.parsestring(storestring) |
| 505 newstore.fileobj = storefile | 505 newstore.fileobj = storefile |
| 506 newstore._assignname() | 506 newstore._assignname() |
| 507 return newstore | 507 return newstore |
| 508 parsefile = classmethod(parsefile) | 508 parsefile = classmethod(parsefile) |
| 509 | 509 |
| LEFT | RIGHT |