195640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org#!/usr/bin/env python 295640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org# Copyright (c) 2012 The Chromium Authors. All rights reserved. 301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# Use of this source code is governed by a BSD-style license that can be 401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# found in the LICENSE file. 501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# The tclib module contains tools for aggregating, verifying, and storing 701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# messages destined for the Translation Console, as well as for reading 801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# translations back and outputting them in some desired format. 901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# 1001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# This has been stripped down to include only the functionality needed by grit 1101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# for creating Windows .rc and .h files. These are the only parts needed by 1201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# the Chrome build process. 1301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgimport exceptions 1501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit.extern import FP 1701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 1801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# This module assumes that within a bundle no two messages can have the 1901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# same id unless they're identical. 2001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 2101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# The basic classes defined here for external use are Message and Translation, 2201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# where the former is used for English messages and the latter for 2301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# translations. These classes have a lot of common functionality, as expressed 2401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# by the common parent class BaseMessage. Perhaps the most important 2501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# distinction is that translated text is stored in UTF-8, whereas original text 2601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# is stored in whatever encoding the client uses (presumably Latin-1). 2701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 2801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# -------------------- 2901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# The public interface 3001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# -------------------- 3101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 3201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# Generate message id from message text and meaning string (optional), 3301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# both in utf-8 encoding 3401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# 3501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgdef GenerateMessageId(message, meaning=''): 3601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org fp = FP.FingerPrint(message) 3701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if meaning: 3801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # combine the fingerprints of message and meaning 3901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org fp2 = FP.FingerPrint(meaning) 4001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if fp < 0: 4101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org fp = fp2 + (fp << 1) + 1 4201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 4301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org fp = fp2 + (fp << 1) 4401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # To avoid negative ids we strip the high-order bit 4501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return str(fp & 0x7fffffffffffffffL) 4601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 4701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# ------------------------------------------------------------------------- 4801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# The MessageTranslationError class is used to signal tclib-specific errors. 4901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 5001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass MessageTranslationError(exceptions.Exception): 5101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def __init__(self, args = ''): 5201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.args = args 5301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 5401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 5501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# ----------------------------------------------------------- 5601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# The Placeholder class represents a placeholder in a message. 5701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 5801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass Placeholder(object): 5901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # String representation 6001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def __str__(self): 6101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return '%s, "%s", "%s"' % \ 6201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org (self.__presentation, self.__original, self.__example) 6301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 6401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Getters 6501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetOriginal(self): 6601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__original 6701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 6801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetPresentation(self): 6901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__presentation 7001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 7101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetExample(self): 7201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__example 7301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 7401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def __eq__(self, other): 7501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.EqualTo(other, strict=1, ignore_trailing_spaces=0) 7601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 7701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Equality test 7801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # 7901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # ignore_trailing_spaces: TC is using varchar to store the 8001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # phrwr fields, as a result of that, the trailing spaces 8101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # are removed by MySQL when the strings are stored into TC:-( 8201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # ignore_trailing_spaces parameter is used to ignore 8301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # trailing spaces during equivalence comparison. 8401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # 8501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def EqualTo(self, other, strict = 1, ignore_trailing_spaces = 1): 8601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if type(other) is not Placeholder: 8701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 8801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if StringEquals(self.__presentation, other.__presentation, 8901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ignore_trailing_spaces): 9001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not strict or (StringEquals(self.__original, other.__original, 9101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ignore_trailing_spaces) and 9201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org StringEquals(self.__example, other.__example, 9301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ignore_trailing_spaces)): 9401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 1 9501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 9601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 9701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 9801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# ----------------------------------------------------------------- 9901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# BaseMessage is the common parent class of Message and Translation. 10001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# It is not meant for direct use. 10101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 10201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass BaseMessage(object): 10301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Three types of message construction is supported. If the message text is a 10401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # simple string with no dynamic content, you can pass it to the constructor 10501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # as the "text" parameter. Otherwise, you can omit "text" and assemble the 10601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # message step by step using AppendText() and AppendPlaceholder(). Or, as an 10701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # alternative, you can give the constructor the "presentable" version of the 10801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # message and a list of placeholders; it will then parse the presentation and 10901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # build the message accordingly. For example: 11001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Message(text = "There are NUM_BUGS bugs in your code", 11101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # placeholders = [Placeholder("NUM_BUGS", "%d", "33")], 11201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # description = "Bla bla bla") 11301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def __eq__(self, other): 11401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # "source encoding" is nonsense, so ignore it 11501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return _ObjectEquals(self, other, ['_BaseMessage__source_encoding']) 11601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 11701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetName(self): 11801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__name 11901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 12001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetSourceEncoding(self): 12101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__source_encoding 12201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 12301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Append a placeholder to the message 12401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def AppendPlaceholder(self, placeholder): 12501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not isinstance(placeholder, Placeholder): 12601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org raise MessageTranslationError, ("Invalid message placeholder %s in " 12701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org "message %s" % (placeholder, self.GetId())) 12801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Are there other placeholders with the same presentation? 12901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # If so, they need to be the same. 13001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for other in self.GetPlaceholders(): 13101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if placeholder.GetPresentation() == other.GetPresentation(): 13201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not placeholder.EqualTo(other): 13301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org raise MessageTranslationError, \ 13401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org "Conflicting declarations of %s within message" % \ 13501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org placeholder.GetPresentation() 13601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # update placeholder list 13701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org dup = 0 13801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for item in self.__content: 13901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if isinstance(item, Placeholder) and placeholder.EqualTo(item): 14001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org dup = 1 14101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org break 14201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not dup: 14301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__placeholders.append(placeholder) 14401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 14501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # update content 14601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__content.append(placeholder) 14701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 14801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Strips leading and trailing whitespace, and returns a tuple 14901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # containing the leading and trailing space that was removed. 15001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Strip(self): 15101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org leading = trailing = '' 15201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if len(self.__content) > 0: 15301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s0 = self.__content[0] 15401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not isinstance(s0, Placeholder): 15501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s = s0.lstrip() 15601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org leading = s0[:-len(s)] 15701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__content[0] = s 15801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 15901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s0 = self.__content[-1] 16001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not isinstance(s0, Placeholder): 16101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s = s0.rstrip() 16201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org trailing = s0[len(s):] 16301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__content[-1] = s 16401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return leading, trailing 16501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 16601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Return the id of this message 16701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetId(self): 16801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if self.__id is None: 16901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.GenerateId() 17001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__id 17101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 17201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Set the id of this message 17301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def SetId(self, id): 17401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if id is None: 17501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__id = None 17601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 17701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__id = str(id) # Treat numerical ids as strings 17801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 17901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Return content of this message as a list (internal use only) 18001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetContent(self): 18101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__content 18201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 18301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Return a human-readable version of this message 18401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetPresentableContent(self): 18501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org presentable_content = "" 18601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for item in self.__content: 18701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if isinstance(item, Placeholder): 18801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org presentable_content += item.GetPresentation() 18901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 19001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org presentable_content += item 19101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 19201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return presentable_content 19301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 19401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Return a fragment of a message in escaped format 19501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def EscapeFragment(self, fragment): 19601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return fragment.replace('%', '%%') 19701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 19801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Return the "original" version of this message, doing %-escaping 19901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # properly. If source_msg is specified, the placeholder original 20001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # information inside source_msg will be used instead. 20101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetOriginalContent(self, source_msg = None): 20201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org original_content = "" 20301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for item in self.__content: 20401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if isinstance(item, Placeholder): 20501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if source_msg: 20601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ph = source_msg.GetPlaceholder(item.GetPresentation()) 20701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not ph: 20801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org raise MessageTranslationError, \ 20901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org "Placeholder %s doesn't exist in message: %s" % \ 21001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org (item.GetPresentation(), source_msg); 21101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org original_content += ph.GetOriginal() 21201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 21301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org original_content += item.GetOriginal() 21401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 21501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org original_content += self.EscapeFragment(item) 21601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return original_content 21701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 21801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Return the example of this message 21901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetExampleContent(self): 22001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org example_content = "" 22101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for item in self.__content: 22201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if isinstance(item, Placeholder): 22301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org example_content += item.GetExample() 22401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 22501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org example_content += item 22601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return example_content 22701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 22801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Return a list of all unique placeholders in this message 22901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetPlaceholders(self): 23001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__placeholders 23101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 23201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Return a placeholder in this message 23301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetPlaceholder(self, presentation): 23401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for item in self.__content: 23501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if (isinstance(item, Placeholder) and 23601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org item.GetPresentation() == presentation): 23701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return item 23801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return None 23901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 24001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Return this message's description 24101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetDescription(self): 24201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__description 24301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 24401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Add a message source 24501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def AddSource(self, source): 24601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__sources.append(source) 24701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 24801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Return this message's sources as a list 24901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetSources(self): 25001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__sources 25101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 25201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Return this message's sources as a string 25301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetSourcesAsText(self, delimiter = "; "): 25401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return delimiter.join(self.__sources) 25501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 25601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Set the obsolete flag for a message (internal use only) 25701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def SetObsolete(self): 25801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__obsolete = 1 25901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 26001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Get the obsolete flag for a message (internal use only) 26101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def IsObsolete(self): 26201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__obsolete 26301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 26401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Get the sequence number (0 by default) 26501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetSequenceNumber(self): 26601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__sequence_number 26701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 26801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Set the sequence number 26901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def SetSequenceNumber(self, number): 27001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__sequence_number = number 27101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 27201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Increment instance counter 27301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def AddInstance(self): 27401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__num_instances += 1 27501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 27601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Return instance count 27701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetNumInstances(self): 27801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__num_instances 27901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 28001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetErrors(self, from_tc=0): 28101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org """ 28201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org Returns a description of the problem if the message is not 28301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org syntactically valid, or None if everything is fine. 28401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 28501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org Args: 28601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org from_tc: indicates whether this message came from the TC. We let 28701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org the TC get away with some things we normally wouldn't allow for 28801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org historical reasons. 28901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org """ 29001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # check that placeholders are unambiguous 29101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org pos = 0 29201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org phs = {} 29301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for item in self.__content: 29401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if isinstance(item, Placeholder): 29501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org phs[pos] = item 29601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org pos += len(item.GetPresentation()) 29701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org else: 29801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org pos += len(item) 29901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org presentation = self.GetPresentableContent() 30001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for ph in self.GetPlaceholders(): 30101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for pos in FindOverlapping(presentation, ph.GetPresentation()): 30201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # message contains the same text as a placeholder presentation 30301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org other_ph = phs.get(pos) 30401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if ((not other_ph 30501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org and not IsSubstringInPlaceholder(pos, len(ph.GetPresentation()), phs)) 30601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org or 30701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org (other_ph and len(other_ph.GetPresentation()) < len(ph.GetPresentation()))): 30801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return "message contains placeholder name '%s':\n%s" % ( 30901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ph.GetPresentation(), presentation) 31001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return None 31101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 31201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 31301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def __CopyTo(self, other): 31401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org """ 31501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org Returns a copy of this BaseMessage. 31601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org """ 31701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org assert isinstance(other, self.__class__) or isinstance(self, other.__class__) 31801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org other.__source_encoding = self.__source_encoding 31901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org other.__content = self.__content[:] 32001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org other.__description = self.__description 32101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org other.__id = self.__id 32201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org other.__num_instances = self.__num_instances 32301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org other.__obsolete = self.__obsolete 32401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org other.__name = self.__name 32501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org other.__placeholders = self.__placeholders[:] 32601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org other.__sequence_number = self.__sequence_number 32701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org other.__sources = self.__sources[:] 32801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 32901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return other 33001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 33101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def HasText(self): 33201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org """Returns true iff this message has anything other than placeholders.""" 33301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for item in self.__content: 33401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not isinstance(item, Placeholder): 33501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return True 33601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return False 33701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 33801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# -------------------------------------------------------- 33901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# The Message class represents original (English) messages 34001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 34101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass Message(BaseMessage): 34201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # See BaseMessage constructor 34301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def __init__(self, source_encoding, text=None, id=None, 34401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org description=None, meaning="", placeholders=None, 34501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org source=None, sequence_number=0, clone_from=None, 34601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org time_created=0, name=None, is_hidden = 0): 34701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 34801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if clone_from is not None: 34901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org BaseMessage.__init__(self, None, clone_from=clone_from) 35001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__meaning = clone_from.__meaning 35101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__time_created = clone_from.__time_created 35201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__is_hidden = clone_from.__is_hidden 35301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 35401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 35501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org BaseMessage.__init__(self, source_encoding, text, id, description, 35601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org placeholders, source, sequence_number, 35701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org name=name) 35801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__meaning = meaning 35901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__time_created = time_created 36001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.SetIsHidden(is_hidden) 36101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 36201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # String representation 36301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def __str__(self): 36401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s = 'source: %s, id: %s, content: "%s", meaning: "%s", ' \ 36501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 'description: "%s"' % \ 36601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org (self.GetSourcesAsText(), self.GetId(), self.GetPresentableContent(), 36701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__meaning, self.GetDescription()) 36801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if self.GetName() is not None: 36901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s += ', name: "%s"' % self.GetName() 37001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org placeholders = self.GetPlaceholders() 37101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for i in range(len(placeholders)): 37201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s += ", placeholder[%d]: %s" % (i, placeholders[i]) 37301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return s 37401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 37501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Strips leading and trailing whitespace, and returns a tuple 37601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # containing the leading and trailing space that was removed. 37701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Strip(self): 37801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org leading = trailing = '' 37901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org content = self.GetContent() 38001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if len(content) > 0: 38101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s0 = content[0] 38201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not isinstance(s0, Placeholder): 38301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s = s0.lstrip() 38401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org leading = s0[:-len(s)] 38501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org content[0] = s 38601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 38701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s0 = content[-1] 38801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not isinstance(s0, Placeholder): 38901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s = s0.rstrip() 39001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org trailing = s0[len(s):] 39101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org content[-1] = s 39201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return leading, trailing 39301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 39401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Generate an id by hashing message content 39501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GenerateId(self): 39601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.SetId(GenerateMessageId(self.GetPresentableContent(), 39701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__meaning)) 39801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.GetId() 39901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 40001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetMeaning(self): 40101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__meaning 40201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 40301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def GetTimeCreated(self): 40401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__time_created 40501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 40601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Equality operator 40701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def EqualTo(self, other, strict = 1): 40801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Check id, meaning, content 40901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if self.GetId() != other.GetId(): 41001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 41101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if self.__meaning != other.__meaning: 41201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 41301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if self.GetPresentableContent() != other.GetPresentableContent(): 41401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 41501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Check descriptions if comparison is strict 41601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if (strict and 41701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.GetDescription() is not None and 41801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org other.GetDescription() is not None and 41901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.GetDescription() != other.GetDescription()): 42001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 42101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Check placeholders 42201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ph1 = self.GetPlaceholders() 42301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ph2 = other.GetPlaceholders() 42401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if len(ph1) != len(ph2): 42501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 42601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for i in range(len(ph1)): 42701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not ph1[i].EqualTo(ph2[i], strict): 42801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 42901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 43001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 1 43101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 43201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Copy(self): 43301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org """ 43401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org Returns a copy of this Message. 43501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org """ 43601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org assert isinstance(self, Message) 43701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return Message(None, clone_from=self) 43801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 43901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def SetIsHidden(self, is_hidden): 44001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org """Sets whether this message should be hidden. 44101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 44201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org Args: 44301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org is_hidden : 0 or 1 - if the message should be hidden, 0 otherwise 44401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org """ 44501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if is_hidden not in [0, 1]: 44601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org raise MessageTranslationError, "is_hidden must be 0 or 1, got %s" 44701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.__is_hidden = is_hidden 44801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 44901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def IsHidden(self): 45001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org """Returns 1 if this message is hidden, and 0 otherwise.""" 45101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return self.__is_hidden 45201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 45301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# ---------------------------------------------------- 45401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# The Translation class represents translated messages 45501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 45601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass Translation(BaseMessage): 45701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # See BaseMessage constructor 45801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def __init__(self, source_encoding, text=None, id=None, 45901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org description=None, placeholders=None, source=None, 46001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org sequence_number=0, clone_from=None, ignore_ph_errors=0, 46101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org name=None): 46201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if clone_from is not None: 46301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org BaseMessage.__init__(self, None, clone_from=clone_from) 46401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 46501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 46601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org BaseMessage.__init__(self, source_encoding, text, id, description, 46701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org placeholders, source, sequence_number, 46801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ignore_ph_errors=ignore_ph_errors, name=name) 46901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 47001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # String representation 47101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def __str__(self): 47201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s = 'source: %s, id: %s, content: "%s", description: "%s"' % \ 47301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org (self.GetSourcesAsText(), self.GetId(), self.GetPresentableContent(), 47401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org self.GetDescription()); 47501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org placeholders = self.GetPlaceholders() 47601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for i in range(len(placeholders)): 47701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org s += ", placeholder[%d]: %s" % (i, placeholders[i]) 47801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return s 47901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 48001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Equality operator 48101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def EqualTo(self, other, strict=1): 48201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Check id and content 48301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if self.GetId() != other.GetId(): 48401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 48501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if self.GetPresentableContent() != other.GetPresentableContent(): 48601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 48701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org # Check placeholders 48801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ph1 = self.GetPlaceholders() 48901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org ph2 = other.GetPlaceholders() 49001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if len(ph1) != len(ph2): 49101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 49201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org for i in range(len(ph1)): 49301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org if not ph1[i].EqualTo(ph2[i], strict): 49401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 0 49501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 49601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return 1 49701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 49801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org def Copy(self): 49901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org """ 50001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org Returns a copy of this Translation. 50101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org """ 50201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org return Translation(None, clone_from=self) 50301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org 504