| Index: grit/tclib.py
 | 
| ===================================================================
 | 
| --- grit/tclib.py	(revision 0)
 | 
| +++ grit/tclib.py	(revision 0)
 | 
| @@ -0,0 +1,216 @@
 | 
| +#!/usr/bin/python2.4
 | 
| +# Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
 | 
| +# Use of this source code is governed by a BSD-style license that can be
 | 
| +# found in the LICENSE file.
 | 
| +
 | 
| +'''Adaptation of the extern.tclib classes for our needs.
 | 
| +'''
 | 
| +
 | 
| +
 | 
| +import re
 | 
| +import types
 | 
| +
 | 
| +from grit import exception
 | 
| +import grit.extern.tclib
 | 
| +
 | 
| +def Identity(i):
 | 
| +  return i
 | 
| +
 | 
| +
 | 
| +class BaseMessage(object):
 | 
| +  '''Base class with methods shared by Message and Translation.
 | 
| +  '''
 | 
| +
 | 
| +  def __init__(self, text='', placeholders=[], description='', meaning=''):
 | 
| +    self.parts = []
 | 
| +    self.placeholders = []
 | 
| +    self.description = description
 | 
| +    self.meaning = meaning
 | 
| +    self.dirty = True  # True if self.id is (or might be) wrong
 | 
| +    self.id = 0
 | 
| +
 | 
| +    if text != '':
 | 
| +      if not placeholders or placeholders == []:
 | 
| +        self.AppendText(text)
 | 
| +      else:
 | 
| +        tag_map = {}
 | 
| +        for placeholder in placeholders:
 | 
| +          tag_map[placeholder.GetPresentation()] = [placeholder, 0]
 | 
| +        tag_re = '(' + '|'.join(tag_map.keys()) + ')'
 | 
| +        # This creates a regexp like '(TAG1|TAG2|TAG3)'
 | 
| +        chunked_text = re.split(tag_re, text)
 | 
| +        for chunk in chunked_text:
 | 
| +          if chunk: # ignore empty chunk
 | 
| +            if tag_map.has_key(chunk):
 | 
| +              self.AppendPlaceholder(tag_map[chunk][0])
 | 
| +              tag_map[chunk][1] += 1 # increase placeholder use count
 | 
| +            else:
 | 
| +              self.AppendText(chunk)
 | 
| +        for key in tag_map.keys():
 | 
| +          assert tag_map[key][1] != 0
 | 
| +
 | 
| +  def GetRealContent(self, escaping_function=Identity):
 | 
| +    '''Returns the original content, i.e. what your application and users
 | 
| +    will see.
 | 
| +
 | 
| +    Specify a function to escape each translateable bit, if you like.
 | 
| +    '''
 | 
| +    bits = []
 | 
| +    for item in self.parts:
 | 
| +      if isinstance(item, types.StringTypes):
 | 
| +        bits.append(escaping_function(item))
 | 
| +      else:
 | 
| +        bits.append(item.GetOriginal())
 | 
| +    return ''.join(bits)
 | 
| +
 | 
| +  def GetPresentableContent(self):
 | 
| +    presentable_content = []
 | 
| +    for part in self.parts:
 | 
| +      if isinstance(part, Placeholder):
 | 
| +        presentable_content.append(part.GetPresentation())
 | 
| +      else:
 | 
| +        presentable_content.append(part)
 | 
| +    return ''.join(presentable_content)
 | 
| +
 | 
| +  def AppendPlaceholder(self, placeholder):
 | 
| +    assert isinstance(placeholder, Placeholder)
 | 
| +    dup = False
 | 
| +    for other in self.GetPlaceholders():
 | 
| +      if other.presentation == placeholder.presentation:
 | 
| +        assert other.original == placeholder.original
 | 
| +        dup = True
 | 
| +
 | 
| +    if not dup:
 | 
| +      self.placeholders.append(placeholder)
 | 
| +    self.parts.append(placeholder)
 | 
| +    self.dirty = True
 | 
| +
 | 
| +  def AppendText(self, text):
 | 
| +    assert isinstance(text, types.StringTypes)
 | 
| +    assert text != ''
 | 
| +
 | 
| +    self.parts.append(text)
 | 
| +    self.dirty = True
 | 
| +
 | 
| +  def GetContent(self):
 | 
| +    '''Returns the parts of the message.  You may modify parts if you wish.
 | 
| +    Note that you must not call GetId() on this object until you have finished
 | 
| +    modifying the contents.
 | 
| +    '''
 | 
| +    self.dirty = True  # user might modify content
 | 
| +    return self.parts
 | 
| +
 | 
| +  def GetDescription(self):
 | 
| +    return self.description
 | 
| +
 | 
| +  def SetDescription(self, description):
 | 
| +    self.description = description
 | 
| +
 | 
| +  def GetMeaning(self):
 | 
| +    return self.meaning
 | 
| +
 | 
| +  def GetId(self):
 | 
| +    if self.dirty:
 | 
| +      self.id = self.GenerateId()
 | 
| +      self.dirty = False
 | 
| +    return self.id
 | 
| +
 | 
| +  def GenerateId(self):
 | 
| +    # Must use a UTF-8 encoded version of the presentable content, along with
 | 
| +    # the meaning attribute, to match the TC.
 | 
| +    return grit.extern.tclib.GenerateMessageId(
 | 
| +      self.GetPresentableContent().encode('utf-8'), self.meaning)
 | 
| +
 | 
| +  def GetPlaceholders(self):
 | 
| +    return self.placeholders
 | 
| +
 | 
| +  def FillTclibBaseMessage(self, msg):
 | 
| +    msg.SetDescription(self.description.encode('utf-8'))
 | 
| +
 | 
| +    for part in self.parts:
 | 
| +      if isinstance(part, Placeholder):
 | 
| +        ph = grit.extern.tclib.Placeholder(
 | 
| +          part.presentation.encode('utf-8'),
 | 
| +          part.original.encode('utf-8'),
 | 
| +          part.example.encode('utf-8'))
 | 
| +        msg.AppendPlaceholder(ph)
 | 
| +      else:
 | 
| +        msg.AppendText(part.encode('utf-8'))
 | 
| +
 | 
| +
 | 
| +class Message(BaseMessage):
 | 
| +  '''A message.'''
 | 
| +
 | 
| +  def __init__(self, text='', placeholders=[], description='', meaning='',
 | 
| +               assigned_id=None):
 | 
| +    BaseMessage.__init__(self, text, placeholders, description, meaning)
 | 
| +    self.assigned_id = assigned_id
 | 
| +
 | 
| +  def ToTclibMessage(self):
 | 
| +    msg = grit.extern.tclib.Message('utf-8', meaning=self.meaning)
 | 
| +    self.FillTclibBaseMessage(msg)
 | 
| +    return msg
 | 
| +
 | 
| +  def GetId(self):
 | 
| +    '''Use the assigned id if we have one.'''
 | 
| +    if self.assigned_id:
 | 
| +      return self.assigned_id
 | 
| +
 | 
| +    return BaseMessage.GetId(self)
 | 
| +
 | 
| +
 | 
| +class Translation(BaseMessage):
 | 
| +  '''A translation.'''
 | 
| +
 | 
| +  def __init__(self, text='', id='', placeholders=[], description='', meaning=''):
 | 
| +    BaseMessage.__init__(self, text, placeholders, description, meaning)
 | 
| +    self.id = id
 | 
| +
 | 
| +  def GetId(self):
 | 
| +    assert id != '', "ID has not been set."
 | 
| +    return self.id
 | 
| +
 | 
| +  def SetId(self, id):
 | 
| +    self.id = id
 | 
| +
 | 
| +  def ToTclibMessage(self):
 | 
| +    msg = grit.extern.tclib.Message(
 | 
| +      'utf-8', id=self.id, meaning=self.meaning)
 | 
| +    self.FillTclibBaseMessage(msg)
 | 
| +    return msg
 | 
| +
 | 
| +
 | 
| +class Placeholder(grit.extern.tclib.Placeholder):
 | 
| +  '''Modifies constructor to accept a Unicode string
 | 
| +  '''
 | 
| +
 | 
| +  # Must match placeholder presentation names
 | 
| +  _NAME_RE = re.compile('^[A-Za-z0-9_]+$')
 | 
| +
 | 
| +  def __init__(self, presentation, original, example):
 | 
| +    '''Creates a new placeholder.
 | 
| +
 | 
| +    Args:
 | 
| +      presentation: 'USERNAME'
 | 
| +      original: '%s'
 | 
| +      example: 'Joi'
 | 
| +    '''
 | 
| +    assert presentation != ''
 | 
| +    assert original != ''
 | 
| +    assert example != ''
 | 
| +    if not self._NAME_RE.match(presentation):
 | 
| +      raise exception.InvalidPlaceholderName(presentation)
 | 
| +    self.presentation = presentation
 | 
| +    self.original = original
 | 
| +    self.example = example
 | 
| +
 | 
| +  def GetPresentation(self):
 | 
| +    return self.presentation
 | 
| +
 | 
| +  def GetOriginal(self):
 | 
| +    return self.original
 | 
| +
 | 
| +  def GetExample(self):
 | 
| +    return self.example
 | 
| +
 | 
| +
 | 
| 
 | 
| Property changes on: grit/tclib.py
 | 
| ___________________________________________________________________
 | 
| Added: svn:eol-style
 | 
|    + LF
 | 
| 
 | 
| 
 |