| 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. |
| 51 | 51 |
| 52 Our concept of a I{translation unit} is influenced heavily by XLIFF: | 52 Our concept of a I{translation unit} is influenced heavily by XLIFF: |
| 53 U{http://www.oasis-open.org/committees/xliff/documents/xliff-specification.h tm} | 53 U{http://www.oasis-open.org/committees/xliff/documents/xliff-specification.h tm} |
| 54 | 54 |
| 55 As such most of the method- and variable names borrows from XLIFF terminolog y. | 55 As such most of the method- and variable names borrows from XLIFF terminolog y. |
| 56 | 56 |
| 57 A translation unit consists of the following: | 57 A translation unit consists of the following: |
| 58 - A I{source} string. This is the original translatable text. | 58 - A I{source} string. This is the original translatable text. |
| 59 - A I{target} string. This is the translation of the I{source}. | 59 - A I{target} string. This is the translation of the I{source}. |
| 60 - Zero or more I{notes} on the unit. Notes would typically be some | 60 - Zero or more I{notes} on the unit. Notes would typically be some |
| 61 comments from a translator on the unit, or some comments originating fro m | 61 comments from a translator on the unit, or some comments originating fro m |
| 62 the source code. | 62 the source code. |
| 63 - Zero or more I{locations}. Locations indicate where in the original | 63 - Zero or more I{locations}. Locations indicate where in the original |
| 64 source code this unit came from. | 64 source code this unit came from. |
| 65 - Zero or more I{errors}. Some tools (eg. L{pofilter <filters.pofilter>}) can run checks on | 65 - Zero or more I{errors}. Some tools (eg. L{pofilter <filters.pofilter>}) can run checks on |
| 66 translations and produce error messages. | 66 translations and produce error messages. |
| 67 - Zero or one I{prev_source} string, the old version of the translatable t ext. | |
| 68 - Zero or one I{prev_context} string, the old version of the message conte xt. | |
| 69 | 67 |
| 70 @group Source: *source* | 68 @group Source: *source* |
| 71 @group Target: *target* | 69 @group Target: *target* |
| 72 @group PrevSource: *PrevSource* | |
| 73 @group PrevContext: *PrevContext* | |
| 74 @group Notes: *note* | 70 @group Notes: *note* |
| 75 @group Locations: *location* | 71 @group Locations: *location* |
| 76 @group Errors: *error* | 72 @group Errors: *error* |
| 77 """ | 73 """ |
| 78 | 74 |
| 79 def __init__(self, source): | 75 def __init__(self, source): |
| 80 """Constructs a TranslationUnit containing the given source string.""" | 76 """Constructs a TranslationUnit containing the given source string.""" |
| 81 | 77 |
| 78 self._store = None | |
| 82 self.source = source | 79 self.source = source |
| 83 self.target = None | 80 self.target = None |
| 84 self.prev_source = None | |
| 85 self.prev_context = None | |
| 86 self.notes = "" | 81 self.notes = "" |
| 87 super(TranslationUnit, self).__init__() | 82 super(TranslationUnit, self).__init__() |
| 88 | 83 |
| 89 def __eq__(self, other): | 84 def __eq__(self, other): |
| 90 """Compares two TranslationUnits. | 85 """Compares two TranslationUnits. |
| 91 | 86 |
| 92 @type other: L{TranslationUnit} | 87 @type other: L{TranslationUnit} |
| 93 @param other: Another L{TranslationUnit} | 88 @param other: Another L{TranslationUnit} |
| 94 @rtype: Boolean | 89 @rtype: Boolean |
| 95 @return: Returns True if the supplied TranslationUnit equals this unit. | 90 @return: Returns True if the supplied TranslationUnit equals this unit. |
| 96 | 91 |
| 97 """ | 92 """ |
| 98 | 93 |
| 99 return self.source == other.source and self.target == other.target | 94 return self.source == other.source and self.target == other.target |
| 100 | 95 |
| 101 def settarget(self, target): | 96 def settarget(self, target): |
| 102 """Sets the target string to the given value.""" | 97 """Sets the target string to the given value.""" |
| 103 | 98 |
| 104 self.target = target | 99 self.target = target |
| 105 | 100 |
| 106 def gettargetlen(self): | 101 def gettargetlen(self): |
| 107 """Returns the length of the target string. | 102 """Returns the length of the target string. |
| 108 | 103 |
| 109 @note: Plural forms might be combined. | 104 @note: Plural forms might be combined. |
| 110 @rtype: Integer | 105 @rtype: Integer |
| 111 | 106 |
| 112 """ | 107 """ |
| 113 | 108 |
| 114 length = len(self.target or "") | 109 length = len(self.target or "") |
| 115 strings = getattr(self.target, "strings", []) | 110 strings = getattr(self.target, "strings", []) |
| 116 if strings: | 111 if strings: |
| 117 length += sum([len(pluralform) for pluralform in strings[1:]]) | 112 length += sum([len(pluralform) for pluralform in strings[1:]]) |
| 118 return length | 113 return length |
| 119 | 114 |
| 120 def getid(self): | 115 def getid(self): |
| 121 """A unique identifier for this unit. | 116 """A unique identifier for this unit. |
| 122 | 117 |
| 123 @rtype: string | 118 @rtype: string |
| 124 @return: an identifier for this unit that is unique in the store | 119 @return: an identifier for this unit that is unique in the store |
| 125 | 120 |
| 126 Derived classes should override this in a way that guarantees a unique | 121 Derived classes should override this in a way that guarantees a unique |
| 127 identifier for each unit in the store. | 122 identifier for each unit in the store. |
| 128 """ | 123 """ |
| 129 return self.source | 124 return self.source |
| 130 | 125 |
| 131 def getlocations(self): | 126 def getlocations(self): |
| 132 """A list of source code locations. | 127 """A list of source code locations. |
| 133 | 128 |
| 134 @note: Shouldn't be implemented if the format doesn't support it. | 129 @note: Shouldn't be implemented if the format doesn't support it. |
| 135 @rtype: List | 130 @rtype: List |
| (...skipping 99 matching lines...) Show 10 above Show 10 below | |
| 235 to ensure that other classes can implement more functionality | 230 to ensure that other classes can implement more functionality |
| 236 (as XLIFF does). | 231 (as XLIFF does). |
| 237 | 232 |
| 238 """ | 233 """ |
| 239 | 234 |
| 240 return bool(self.target) and not self.isfuzzy() | 235 return bool(self.target) and not self.isfuzzy() |
| 241 | 236 |
| 242 def istranslatable(self): | 237 def istranslatable(self): |
| 243 """Indicates whether this unit can be translated. | 238 """Indicates whether this unit can be translated. |
| 244 | 239 |
| 245 This should be used to distinguish real units for translation from | 240 This should be used to distinguish real units for translation from |
| 246 header, obsolete, binary or other blank units. | 241 header, obsolete, binary or other blank units. |
| 247 """ | 242 """ |
| 248 return True | 243 return True |
| 249 | 244 |
| 250 def isfuzzy(self): | 245 def isfuzzy(self): |
| 251 """Indicates whether this unit is fuzzy.""" | 246 """Indicates whether this unit is fuzzy.""" |
| 252 | 247 |
| 253 return False | 248 return False |
| 254 | 249 |
| 255 def markfuzzy(self, value=True): | 250 def markfuzzy(self, value=True): |
| 256 """Marks the unit as fuzzy or not.""" | 251 """Marks the unit as fuzzy or not.""" |
| 257 pass | 252 pass |
| 258 | 253 |
| 259 def isheader(self): | 254 def isheader(self): |
| 260 """Indicates whether this unit is a header.""" | 255 """Indicates whether this unit is a header.""" |
| 261 | 256 |
| 262 return False | 257 return False |
| 263 | 258 |
| 264 def isreview(self): | 259 def isreview(self): |
| 265 """Indicates whether this unit needs review.""" | 260 """Indicates whether this unit needs review.""" |
| 266 return False | 261 return False |
| 267 | 262 |
| 268 | 263 |
| 269 def isblank(self): | 264 def isblank(self): |
| 270 """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. |
| 271 | 266 |
| 272 @note: This is probably used more to find translatable units, | 267 @note: This is probably used more to find translatable units, |
| 273 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. |
| 274 | 269 |
| 275 """ | 270 """ |
| 276 | 271 |
| 277 return not (self.source or self.target) | 272 return not (self.source or self.target) |
| 278 | 273 |
| 279 def hasplural(self): | 274 def hasplural(self): |
| 280 """Tells whether or not this specific unit has plural strings.""" | 275 """Tells whether or not this specific unit has plural strings.""" |
| 281 | 276 |
| 282 #TODO: Reconsider | 277 #TODO: Reconsider |
| 283 return False | 278 return False |
| 284 | 279 |
| 280 def getsourcelanguage(self): | |
| 281 return getattr(self._store, "sourcelanguage", "en") | |
| 282 | |
| 283 def gettargetlanguage(self): | |
| 284 return getattr(self._store, "targetlanguage", None) | |
| 285 | |
| 285 def merge(self, otherunit, overwrite=False, comments=True): | 286 def merge(self, otherunit, overwrite=False, comments=True): |
| 286 """Do basic format agnostic merging.""" | 287 """Do basic format agnostic merging.""" |
| 287 | 288 |
| 288 if self.target == "" or overwrite: | 289 if self.target == "" or overwrite: |
| 289 self.target = otherunit.target | 290 self.target = otherunit.target |
| 290 | 291 |
| 291 def unit_iter(self): | 292 def unit_iter(self): |
| 292 """Iterator that only returns this unit.""" | 293 """Iterator that only returns this unit.""" |
| 293 yield self | 294 yield self |
| 294 | 295 |
| 295 def getunits(self): | 296 def getunits(self): |
| 296 """This unit in a list.""" | 297 """This unit in a list.""" |
| 297 return [self] | 298 return [self] |
| 298 | 299 |
| 299 def setprev_source(self, source): | 300 def setprev_source(self, source): |
| 300 """Sets the previous source message for this unit""" | 301 """Sets the previous source message for this unit""" |
| 301 self.prev_source = source | 302 pass |
| 302 | 303 |
| 303 def getprev_source(self): | 304 def getprev_source(self): |
| 304 """Gets the previous source message for this unit""" | 305 """Gets the previous source message for this unit""" |
| 305 return self.prev_source | 306 pass |
|
dwaynebailey
2008/07/17 12:59:27
Shouldn't the decorators be here for prev_source?
georgeyk
2008/07/18 05:15:49
On 2008/07/17 12:59:27, dwaynebailey wrote:
> Shou
| |
| 307 | |
| 308 prev_source = property(getprev_source, setprev_source) | |
| 306 | 309 |
| 307 def setprev_context(self, context): | 310 def setprev_context(self, context): |
| 308 """Sets the previous context of this unit""" | 311 """Sets the previous context of this unit""" |
| 309 self.prev_context = context | 312 pass |
| 310 | 313 |
| 311 def getprev_context(self): | 314 def getprev_context(self): |
| 312 """Gets the previous context of this unit""" | 315 """Gets the previous context of this unit""" |
| 313 return self.prev_context | 316 pass |
| 317 | |
| 318 prev_context = property(getprev_context, setprev_context) | |
| 314 | 319 |
| 315 def set_as_previous(self): | 320 def set_as_previous(self): |
| 316 """Sets this unit as a previous unit message""" | 321 """Sets this unit as a previous unit message""" |
| 317 if self.isfuzzy(): | 322 if self.isfuzzy(): |
| 318 return | 323 return |
| 319 self.setprev_context(self.getcontext()) | 324 self.setprev_context(self.getcontext()) |
| 320 self.setprev_source(self.source) | 325 self.setprev_source(self.source) |
| 321 self.markfuzzy() | 326 self.markfuzzy() |
| 322 | 327 |
| 323 def buildfromunit(cls, unit): | 328 def buildfromunit(cls, unit): |
| 324 """Build a native unit from a foreign unit, preserving as much | 329 """Build a native unit from a foreign unit, preserving as much |
| 325 information as possible.""" | 330 information as possible.""" |
| 326 | 331 |
| 327 if type(unit) == cls and hasattr(unit, "copy") and callable(unit.copy): | 332 if type(unit) == cls and hasattr(unit, "copy") and callable(unit.copy): |
| 328 return unit.copy() | 333 return unit.copy() |
| 329 newunit = cls(unit.source) | 334 newunit = cls(unit.source) |
| 330 newunit.target = unit.target | 335 newunit.target = unit.target |
| 331 newunit.markfuzzy(unit.isfuzzy()) | 336 newunit.markfuzzy(unit.isfuzzy()) |
| 332 locations = unit.getlocations() | 337 locations = unit.getlocations() |
| 333 if locations: | 338 if locations: |
| 334 newunit.addlocations(locations) | 339 newunit.addlocations(locations) |
| 335 notes = unit.getnotes() | 340 notes = unit.getnotes() |
| 336 if notes: | 341 if notes: |
| 337 newunit.addnote(notes) | 342 newunit.addnote(notes) |
| 338 return newunit | 343 return newunit |
| 339 buildfromunit = classmethod(buildfromunit) | 344 buildfromunit = classmethod(buildfromunit) |
| 340 | 345 |
| 341 class TranslationStore(object): | 346 class TranslationStore(object): |
| 342 """Base class for stores for multiple translation units of type UnitClass."" " | 347 """Base class for stores for multiple translation units of type UnitClass."" " |
| 343 | 348 |
| 344 UnitClass = TranslationUnit | 349 UnitClass = TranslationUnit |
| 345 Mimetypes = None | 350 Mimetypes = None |
| 346 Extensions = None | 351 Extensions = None |
| 347 | 352 |
| 348 def __init__(self, unitclass=None): | 353 def __init__(self, unitclass=None): |
| 349 """Constructs a blank TranslationStore.""" | 354 """Constructs a blank TranslationStore.""" |
| 350 | 355 |
| 351 self.units = [] | 356 self.units = [] |
| 352 self.filepath = None | 357 self.filepath = None |
| 353 self.translator = "" | 358 self.translator = "" |
| 354 self.date = "" | 359 self.date = "" |
| 355 self.sourcelanguage = None | 360 self.sourcelanguage = None |
| 356 self.targetlanguage = None | 361 self.targetlanguage = None |
| 357 if unitclass: | 362 if unitclass: |
| 358 self.UnitClass = unitclass | 363 self.UnitClass = unitclass |
| 359 super(TranslationStore, self).__init__() | 364 super(TranslationStore, self).__init__() |
| 360 | 365 |
| 361 def setsourcelanguage(self, sourcelanguage): | 366 def setsourcelanguage(self, sourcelanguage): |
| 362 """Sets the source language for this store""" | 367 """Sets the source language for this store""" |
| 363 self.sourcelanguage = sourcelanguage | 368 self.sourcelanguage = sourcelanguage |
| 364 | 369 |
| 365 def settargetlanguage(self, targetlanguage): | 370 def settargetlanguage(self, targetlanguage): |
| 366 """Sets the target language for this store""" | 371 """Sets the target language for this store""" |
| 367 self.targetlanguage = targetlanguage | 372 self.targetlanguage = targetlanguage |
| 368 | 373 |
| 369 def unit_iter(self): | 374 def unit_iter(self): |
| 370 """Iterator over all the units in this store.""" | 375 """Iterator over all the units in this store.""" |
| 371 for unit in self.units: | 376 for unit in self.units: |
| 372 yield unit | 377 yield unit |
| 373 | 378 |
| 374 def getunits(self): | 379 def getunits(self): |
| 375 """Return a list of all units in this store.""" | 380 """Return a list of all units in this store.""" |
| 376 return [unit for unit in self.unit_iter()] | 381 return [unit for unit in self.unit_iter()] |
| 377 | 382 |
| 378 def addunit(self, unit): | 383 def addunit(self, unit): |
| 379 """Appends the given unit to the object's list of units. | 384 """Appends the given unit to the object's list of units. |
| 380 | 385 |
| 381 This method should always be used rather than trying to modify the | 386 This method should always be used rather than trying to modify the |
| 382 list manually. | 387 list manually. |
| 383 | 388 |
| 384 @type unit: L{TranslationUnit} | 389 @type unit: L{TranslationUnit} |
| 385 @param unit: The unit that will be added. | 390 @param unit: The unit that will be added. |
| 386 | 391 |
| 387 """ | 392 """ |
| 388 | 393 unit._store = self |
| 389 self.units.append(unit) | 394 self.units.append(unit) |
| 390 | 395 |
| 391 def addsourceunit(self, source): | 396 def addsourceunit(self, source): |
| 392 """Adds and returns a new unit with the given source string. | 397 """Adds and returns a new unit with the given source string. |
| 393 | 398 |
| 394 @rtype: L{TranslationUnit} | 399 @rtype: L{TranslationUnit} |
| 395 | 400 |
| 396 """ | 401 """ |
| 397 | 402 |
| 398 unit = self.UnitClass(source) | 403 unit = self.UnitClass(source) |
| 399 self.addunit(unit) | 404 self.addunit(unit) |
| 400 return unit | 405 return unit |
| 401 | 406 |
| 402 def findunit(self, source): | 407 def findunit(self, source): |
| 403 """Finds the unit with the given source string. | 408 """Finds the unit with the given source string. |
| 404 | 409 |
| 405 @rtype: L{TranslationUnit} or None | 410 @rtype: L{TranslationUnit} or None |
| 406 | 411 |
| 407 """ | 412 """ |
| 408 | 413 |
| 409 if len(getattr(self, "sourceindex", [])): | 414 if len(getattr(self, "sourceindex", [])): |
| 410 if source in self.sourceindex: | 415 if source in self.sourceindex: |
| 411 return self.sourceindex[source] | 416 return self.sourceindex[source] |
| 412 else: | 417 else: |
| 413 for unit in self.units: | 418 for unit in self.units: |
| 414 if unit.source == source: | 419 if unit.source == source: |
| 415 return unit | 420 return unit |
| 416 return None | 421 return None |
| 417 | 422 |
| 418 def translate(self, source): | 423 def translate(self, source): |
| 419 """Returns the translated string for a given source string. | 424 """Returns the translated string for a given source string. |
| 420 | 425 |
| 421 @rtype: String or None | 426 @rtype: String or None |
| 422 | 427 |
| 423 """ | 428 """ |
| 424 | 429 |
| 425 unit = self.findunit(source) | 430 unit = self.findunit(source) |
| 426 if unit and unit.target: | 431 if unit and unit.target: |
| 427 return unit.target | 432 return unit.target |
| 428 else: | 433 else: |
| 429 return None | 434 return None |
| 430 | 435 |
| 431 def makeindex(self): | 436 def makeindex(self): |
| 432 """Indexes the items in this store. At least .sourceindex should be usef ull.""" | 437 """Indexes the items in this store. At least .sourceindex should be usef ull.""" |
| 433 | 438 |
| 434 self.locationindex = {} | 439 self.locationindex = {} |
| 435 self.sourceindex = {} | 440 self.sourceindex = {} |
| 436 for unit in self.units: | 441 for unit in self.units: |
| 437 # Do we need to test if unit.source exists? | 442 # Do we need to test if unit.source exists? |
| 438 self.sourceindex[unit.source] = unit | 443 self.sourceindex[unit.source] = unit |
| 439 if unit.hasplural(): | 444 if unit.hasplural(): |
| 440 for nounform in unit.source.strings[1:]: | 445 for nounform in unit.source.strings[1:]: |
| 441 self.sourceindex[nounform] = unit | 446 self.sourceindex[nounform] = unit |
| 442 for location in unit.getlocations(): | 447 for location in unit.getlocations(): |
| 443 if location in self.locationindex: | 448 if location in self.locationindex: |
| 444 # if sources aren't unique, don't use them | 449 # if sources aren't unique, don't use them |
| 445 self.locationindex[location] = None | 450 self.locationindex[location] = None |
| 446 else: | 451 else: |
| 447 self.locationindex[location] = unit | 452 self.locationindex[location] = unit |
| 448 | 453 |
| 449 def __str__(self): | 454 def __str__(self): |
| 450 """Converts to a string representation that can be parsed back using L{p arsestring()}.""" | 455 """Converts to a string representation that can be parsed back using L{p arsestring()}.""" |
| 451 | 456 |
| 452 # We can't pickle fileobj if it is there, so let's hide it for a while. | 457 # We can't pickle fileobj if it is there, so let's hide it for a while. |
| 453 fileobj = getattr(self, "fileobj", None) | 458 fileobj = getattr(self, "fileobj", None) |
| 454 self.fileobj = None | 459 self.fileobj = None |
| 455 dump = pickle.dumps(self) | 460 dump = pickle.dumps(self) |
| 456 self.fileobj = fileobj | 461 self.fileobj = fileobj |
| 457 return dump | 462 return dump |
| 458 | 463 |
| 459 def isempty(self): | 464 def isempty(self): |
| 460 """Returns True if the object doesn't contain any translation units.""" | 465 """Returns True if the object doesn't contain any translation units.""" |
| 461 | 466 |
| 462 if len(self.units) == 0: | 467 if len(self.units) == 0: |
| 463 return True | 468 return True |
| 464 for unit in self.units: | 469 for unit in self.units: |
| 465 if not (unit.isblank() or unit.isheader()): | 470 if not (unit.isblank() or unit.isheader()): |
| 466 return False | 471 return False |
| 467 return True | 472 return True |
| 468 | 473 |
| 469 def _assignname(self): | 474 def _assignname(self): |
| 470 """Tries to work out what the name of the filesystem file is and | 475 """Tries to work out what the name of the filesystem file is and |
| 471 assigns it to .filename.""" | 476 assigns it to .filename.""" |
| 472 fileobj = getattr(self, "fileobj", None) | 477 fileobj = getattr(self, "fileobj", None) |
| 473 if fileobj: | 478 if fileobj: |
| 474 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non e)) | 479 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non e)) |
| 475 if filename: | 480 if filename: |
| 476 self.filename = filename | 481 self.filename = filename |
| 477 | 482 |
| 478 def parsestring(cls, storestring): | 483 def parsestring(cls, storestring): |
| 479 """Converts the string representation back to an object.""" | 484 """Converts the string representation back to an object.""" |
| 480 newstore = cls() | 485 newstore = cls() |
| 481 if storestring: | 486 if storestring: |
| 482 newstore.parse(storestring) | 487 newstore.parse(storestring) |
| 483 return newstore | 488 return newstore |
| 484 parsestring = classmethod(parsestring) | 489 parsestring = classmethod(parsestring) |
| 485 | 490 |
| 486 def parse(self, data): | 491 def parse(self, data): |
| 487 """parser to process the given source string""" | 492 """parser to process the given source string""" |
| 488 self.units = pickle.loads(data).units | 493 self.units = pickle.loads(data).units |
| 489 | 494 |
| 490 def savefile(self, storefile): | 495 def savefile(self, storefile): |
| 491 """Writes the string representation to the given file (or filename).""" | 496 """Writes the string representation to the given file (or filename).""" |
| 492 if isinstance(storefile, basestring): | 497 if isinstance(storefile, basestring): |
| 493 storefile = open(storefile, "w") | 498 storefile = open(storefile, "w") |
| 494 self.fileobj = storefile | 499 self.fileobj = storefile |
| 495 self._assignname() | 500 self._assignname() |
| 496 storestring = str(self) | 501 storestring = str(self) |
| 497 storefile.write(storestring) | 502 storefile.write(storestring) |
| 498 storefile.close() | 503 storefile.close() |
| 499 | 504 |
| 500 def save(self): | 505 def save(self): |
| 501 """Save to the file that data was originally read from, if available.""" | 506 """Save to the file that data was originally read from, if available.""" |
| 502 fileobj = getattr(self, "fileobj", None) | 507 fileobj = getattr(self, "fileobj", None) |
| 503 if not fileobj: | 508 if not fileobj: |
| 504 filename = getattr(self, "filename", None) | 509 filename = getattr(self, "filename", None) |
| 505 if filename: | 510 if filename: |
| 506 fileobj = file(filename, "w") | 511 fileobj = file(filename, "w") |
| 507 else: | 512 else: |
| 508 fileobj.close() | 513 fileobj.close() |
| 509 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non e)) | 514 filename = getattr(fileobj, "name", getattr(fileobj, "filename", Non e)) |
| 510 if not filename: | 515 if not filename: |
| 511 raise ValueError("No file or filename to save to") | 516 raise ValueError("No file or filename to save to") |
| 512 fileobj = fileobj.__class__(filename, "w") | 517 fileobj = fileobj.__class__(filename, "w") |
| 513 self.savefile(fileobj) | 518 self.savefile(fileobj) |
| 514 | 519 |
| 515 def parsefile(cls, storefile): | 520 def parsefile(cls, storefile): |
| 516 """Reads the given file (or opens the given filename) and parses back to an object.""" | 521 """Reads the given file (or opens the given filename) and parses back to an object.""" |
| 517 | 522 |
| 518 if isinstance(storefile, basestring): | 523 if isinstance(storefile, basestring): |
| 519 storefile = open(storefile, "r") | 524 storefile = open(storefile, "r") |
| 520 mode = getattr(storefile, "mode", "r") | 525 mode = getattr(storefile, "mode", "r") |
| 521 #For some reason GzipFile returns 1, so we have to test for that here | 526 #For some reason GzipFile returns 1, so we have to test for that here |
| 522 if mode == 1 or "r" in mode: | 527 if mode == 1 or "r" in mode: |
| 523 storestring = storefile.read() | 528 storestring = storefile.read() |
| 524 storefile.close() | 529 storefile.close() |
| 525 else: | 530 else: |
| 526 storestring = "" | 531 storestring = "" |
| 527 newstore = cls.parsestring(storestring) | 532 newstore = cls.parsestring(storestring) |
| 528 newstore.fileobj = storefile | 533 newstore.fileobj = storefile |
| 529 newstore._assignname() | 534 newstore._assignname() |
| 530 return newstore | 535 return newstore |
| 531 parsefile = classmethod(parsefile) | 536 parsefile = classmethod(parsefile) |
| 532 | 537 |
| LEFT | RIGHT |