OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python2.4 |
| 2 # Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 '''Adaptation of the extern.tclib classes for our needs. |
| 7 ''' |
| 8 |
| 9 |
| 10 import re |
| 11 import types |
| 12 |
| 13 from grit import exception |
| 14 import grit.extern.tclib |
| 15 |
| 16 def Identity(i): |
| 17 return i |
| 18 |
| 19 |
| 20 class BaseMessage(object): |
| 21 '''Base class with methods shared by Message and Translation. |
| 22 ''' |
| 23 |
| 24 def __init__(self, text='', placeholders=[], description='', meaning=''): |
| 25 self.parts = [] |
| 26 self.placeholders = [] |
| 27 self.description = description |
| 28 self.meaning = meaning |
| 29 self.dirty = True # True if self.id is (or might be) wrong |
| 30 self.id = 0 |
| 31 |
| 32 if text != '': |
| 33 if not placeholders or placeholders == []: |
| 34 self.AppendText(text) |
| 35 else: |
| 36 tag_map = {} |
| 37 for placeholder in placeholders: |
| 38 tag_map[placeholder.GetPresentation()] = [placeholder, 0] |
| 39 tag_re = '(' + '|'.join(tag_map.keys()) + ')' |
| 40 # This creates a regexp like '(TAG1|TAG2|TAG3)' |
| 41 chunked_text = re.split(tag_re, text) |
| 42 for chunk in chunked_text: |
| 43 if chunk: # ignore empty chunk |
| 44 if tag_map.has_key(chunk): |
| 45 self.AppendPlaceholder(tag_map[chunk][0]) |
| 46 tag_map[chunk][1] += 1 # increase placeholder use count |
| 47 else: |
| 48 self.AppendText(chunk) |
| 49 for key in tag_map.keys(): |
| 50 assert tag_map[key][1] != 0 |
| 51 |
| 52 def GetRealContent(self, escaping_function=Identity): |
| 53 '''Returns the original content, i.e. what your application and users |
| 54 will see. |
| 55 |
| 56 Specify a function to escape each translateable bit, if you like. |
| 57 ''' |
| 58 bits = [] |
| 59 for item in self.parts: |
| 60 if isinstance(item, types.StringTypes): |
| 61 bits.append(escaping_function(item)) |
| 62 else: |
| 63 bits.append(item.GetOriginal()) |
| 64 return ''.join(bits) |
| 65 |
| 66 def GetPresentableContent(self): |
| 67 presentable_content = [] |
| 68 for part in self.parts: |
| 69 if isinstance(part, Placeholder): |
| 70 presentable_content.append(part.GetPresentation()) |
| 71 else: |
| 72 presentable_content.append(part) |
| 73 return ''.join(presentable_content) |
| 74 |
| 75 def AppendPlaceholder(self, placeholder): |
| 76 assert isinstance(placeholder, Placeholder) |
| 77 dup = False |
| 78 for other in self.GetPlaceholders(): |
| 79 if other.presentation == placeholder.presentation: |
| 80 assert other.original == placeholder.original |
| 81 dup = True |
| 82 |
| 83 if not dup: |
| 84 self.placeholders.append(placeholder) |
| 85 self.parts.append(placeholder) |
| 86 self.dirty = True |
| 87 |
| 88 def AppendText(self, text): |
| 89 assert isinstance(text, types.StringTypes) |
| 90 assert text != '' |
| 91 |
| 92 self.parts.append(text) |
| 93 self.dirty = True |
| 94 |
| 95 def GetContent(self): |
| 96 '''Returns the parts of the message. You may modify parts if you wish. |
| 97 Note that you must not call GetId() on this object until you have finished |
| 98 modifying the contents. |
| 99 ''' |
| 100 self.dirty = True # user might modify content |
| 101 return self.parts |
| 102 |
| 103 def GetDescription(self): |
| 104 return self.description |
| 105 |
| 106 def SetDescription(self, description): |
| 107 self.description = description |
| 108 |
| 109 def GetMeaning(self): |
| 110 return self.meaning |
| 111 |
| 112 def GetId(self): |
| 113 if self.dirty: |
| 114 self.id = self.GenerateId() |
| 115 self.dirty = False |
| 116 return self.id |
| 117 |
| 118 def GenerateId(self): |
| 119 # Must use a UTF-8 encoded version of the presentable content, along with |
| 120 # the meaning attribute, to match the TC. |
| 121 return grit.extern.tclib.GenerateMessageId( |
| 122 self.GetPresentableContent().encode('utf-8'), self.meaning) |
| 123 |
| 124 def GetPlaceholders(self): |
| 125 return self.placeholders |
| 126 |
| 127 def FillTclibBaseMessage(self, msg): |
| 128 msg.SetDescription(self.description.encode('utf-8')) |
| 129 |
| 130 for part in self.parts: |
| 131 if isinstance(part, Placeholder): |
| 132 ph = grit.extern.tclib.Placeholder( |
| 133 part.presentation.encode('utf-8'), |
| 134 part.original.encode('utf-8'), |
| 135 part.example.encode('utf-8')) |
| 136 msg.AppendPlaceholder(ph) |
| 137 else: |
| 138 msg.AppendText(part.encode('utf-8')) |
| 139 |
| 140 |
| 141 class Message(BaseMessage): |
| 142 '''A message.''' |
| 143 |
| 144 def __init__(self, text='', placeholders=[], description='', meaning='', |
| 145 assigned_id=None): |
| 146 BaseMessage.__init__(self, text, placeholders, description, meaning) |
| 147 self.assigned_id = assigned_id |
| 148 |
| 149 def ToTclibMessage(self): |
| 150 msg = grit.extern.tclib.Message('utf-8', meaning=self.meaning) |
| 151 self.FillTclibBaseMessage(msg) |
| 152 return msg |
| 153 |
| 154 def GetId(self): |
| 155 '''Use the assigned id if we have one.''' |
| 156 if self.assigned_id: |
| 157 return self.assigned_id |
| 158 |
| 159 return BaseMessage.GetId(self) |
| 160 |
| 161 |
| 162 class Translation(BaseMessage): |
| 163 '''A translation.''' |
| 164 |
| 165 def __init__(self, text='', id='', placeholders=[], description='', meaning=''
): |
| 166 BaseMessage.__init__(self, text, placeholders, description, meaning) |
| 167 self.id = id |
| 168 |
| 169 def GetId(self): |
| 170 assert id != '', "ID has not been set." |
| 171 return self.id |
| 172 |
| 173 def SetId(self, id): |
| 174 self.id = id |
| 175 |
| 176 def ToTclibMessage(self): |
| 177 msg = grit.extern.tclib.Message( |
| 178 'utf-8', id=self.id, meaning=self.meaning) |
| 179 self.FillTclibBaseMessage(msg) |
| 180 return msg |
| 181 |
| 182 |
| 183 class Placeholder(grit.extern.tclib.Placeholder): |
| 184 '''Modifies constructor to accept a Unicode string |
| 185 ''' |
| 186 |
| 187 # Must match placeholder presentation names |
| 188 _NAME_RE = re.compile('^[A-Za-z0-9_]+$') |
| 189 |
| 190 def __init__(self, presentation, original, example): |
| 191 '''Creates a new placeholder. |
| 192 |
| 193 Args: |
| 194 presentation: 'USERNAME' |
| 195 original: '%s' |
| 196 example: 'Joi' |
| 197 ''' |
| 198 assert presentation != '' |
| 199 assert original != '' |
| 200 assert example != '' |
| 201 if not self._NAME_RE.match(presentation): |
| 202 raise exception.InvalidPlaceholderName(presentation) |
| 203 self.presentation = presentation |
| 204 self.original = original |
| 205 self.example = example |
| 206 |
| 207 def GetPresentation(self): |
| 208 return self.presentation |
| 209 |
| 210 def GetOriginal(self): |
| 211 return self.original |
| 212 |
| 213 def GetExample(self): |
| 214 return self.example |
| 215 |
| 216 |
OLD | NEW |