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 '''Support for "strings.xml" format used by Muppet plug-ins in Google Desktop.''
' |
| 7 |
| 8 import StringIO |
| 9 import types |
| 10 import re |
| 11 import xml.sax |
| 12 import xml.sax.handler |
| 13 import xml.sax.saxutils |
| 14 |
| 15 from grit.gather import regexp |
| 16 from grit import util |
| 17 from grit import tclib |
| 18 |
| 19 # Placeholders can be defined in strings.xml files by putting the name of the |
| 20 # placeholder between [![ and ]!] e.g. <MSG>Hello [![USER]!] how are you<MSG> |
| 21 PLACEHOLDER_RE = re.compile('(\[!\[|\]!\])') |
| 22 |
| 23 |
| 24 class MuppetStringsContentHandler(xml.sax.handler.ContentHandler): |
| 25 '''A very dumb parser for splitting the strings.xml file into translateable |
| 26 and nontranslateable chunks.''' |
| 27 |
| 28 def __init__(self, parent): |
| 29 self.curr_elem = '' |
| 30 self.curr_text = '' |
| 31 self.parent = parent |
| 32 self.description = '' |
| 33 self.meaning = '' |
| 34 self.translateable = True |
| 35 |
| 36 def startElement(self, name, attrs): |
| 37 if (name != 'strings'): |
| 38 self.curr_elem = name |
| 39 |
| 40 attr_names = attrs.getQNames() |
| 41 if 'desc' in attr_names: |
| 42 self.description = attrs.getValueByQName('desc') |
| 43 if 'meaning' in attr_names: |
| 44 self.meaning = attrs.getValueByQName('meaning') |
| 45 if 'translateable' in attr_names: |
| 46 value = attrs.getValueByQName('translateable') |
| 47 if value.lower() not in ['true', 'yes']: |
| 48 self.translateable = False |
| 49 |
| 50 att_text = [] |
| 51 for attr_name in attr_names: |
| 52 att_text.append(' ') |
| 53 att_text.append(attr_name) |
| 54 att_text.append('=') |
| 55 att_text.append( |
| 56 xml.sax.saxutils.quoteattr(attrs.getValueByQName(attr_name))) |
| 57 |
| 58 self.parent._AddNontranslateableChunk("<%s%s>" % |
| 59 (name, ''.join(att_text))) |
| 60 |
| 61 def characters(self, content): |
| 62 if self.curr_elem != '': |
| 63 self.curr_text += content |
| 64 |
| 65 def endElement(self, name): |
| 66 if name != 'strings': |
| 67 self.parent.AddMessage(self.curr_text, self.description, |
| 68 self.meaning, self.translateable) |
| 69 self.parent._AddNontranslateableChunk("</%s>\n" % name) |
| 70 self.curr_elem = '' |
| 71 self.curr_text = '' |
| 72 self.description = '' |
| 73 self.meaning = '' |
| 74 self.translateable = True |
| 75 |
| 76 def ignorableWhitespace(self, whitespace): |
| 77 pass |
| 78 |
| 79 class MuppetStrings(regexp.RegexpGatherer): |
| 80 '''Supports the strings.xml format used by Muppet gadgets.''' |
| 81 |
| 82 def __init__(self, text): |
| 83 if util.IsExtraVerbose(): |
| 84 print text |
| 85 regexp.RegexpGatherer.__init__(self, text) |
| 86 |
| 87 def AddMessage(self, msgtext, description, meaning, translateable): |
| 88 if msgtext == '': |
| 89 return |
| 90 |
| 91 msg = tclib.Message(description=description, meaning=meaning) |
| 92 |
| 93 unescaped_text = self.UnEscape(msgtext) |
| 94 parts = PLACEHOLDER_RE.split(unescaped_text) |
| 95 in_placeholder = False |
| 96 for part in parts: |
| 97 if part == '': |
| 98 continue |
| 99 elif part == '[![': |
| 100 in_placeholder = True |
| 101 elif part == ']!]': |
| 102 in_placeholder = False |
| 103 else: |
| 104 if in_placeholder: |
| 105 msg.AppendPlaceholder(tclib.Placeholder(part, '[![%s]!]' % part, |
| 106 '(placeholder)')) |
| 107 else: |
| 108 msg.AppendText(part) |
| 109 |
| 110 self.skeleton_.append( |
| 111 self.uberclique.MakeClique(msg, translateable=translateable)) |
| 112 |
| 113 # if statement needed because this is supposed to be idempotent (so never |
| 114 # set back to false) |
| 115 if translateable: |
| 116 self.translatable_chunk_ = True |
| 117 |
| 118 # Although we use the RegexpGatherer base class, we do not use the |
| 119 # _RegExpParse method of that class to implement Parse(). Instead, we |
| 120 # parse using a SAX parser. |
| 121 def Parse(self): |
| 122 if (self.have_parsed_): |
| 123 return |
| 124 self.have_parsed_ = True |
| 125 self._AddNontranslateableChunk(u'<strings>\n') |
| 126 stream = StringIO.StringIO(self.text_) |
| 127 handler = MuppetStringsContentHandler(self) |
| 128 xml.sax.parse(stream, handler) |
| 129 self._AddNontranslateableChunk(u'</strings>\n') |
| 130 |
| 131 def Escape(self, text): |
| 132 return util.EncodeCdata(text) |
| 133 |
| 134 def FromFile(filename_or_stream, extkey=None, encoding='cp1252'): |
| 135 if isinstance(filename_or_stream, types.StringTypes): |
| 136 if util.IsVerbose(): |
| 137 print "MuppetStrings reading file %s, encoding %s" % ( |
| 138 filename_or_stream, encoding) |
| 139 filename_or_stream = util.WrapInputStream(file(filename_or_stream, 'r'), e
ncoding) |
| 140 return MuppetStrings(filename_or_stream.read()) |
| 141 FromFile = staticmethod(FromFile) |
| 142 |
OLD | NEW |