blob: 79ed8390c84c4e0c38c1d06f2e72307a1096d873 [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2012 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.
'''Support for ALL_ALL.xml format used by Igoogle plug-ins in Google Desktop.'''
import StringIO
import re
import xml.sax
import xml.sax.handler
import xml.sax.saxutils
from grit.gather import regexp
from grit import util
from grit import tclib
# Placeholders can be defined in strings.xml files by putting the name of the
# placeholder between [![ and ]!] e.g. <MSG>Hello [![USER]!] how are you<MSG>
PLACEHOLDER_RE = re.compile('(\[!\[|\]!\])')
class IgoogleStringsContentHandler(xml.sax.handler.ContentHandler):
'''A very dumb parser for splitting the strings.xml file into translateable
and nontranslateable chunks.'''
def __init__(self, parent):
self.curr_elem = ''
self.curr_text = ''
self.parent = parent
self.resource_name = ''
self.meaning = ''
self.translateable = True
def startElement(self, name, attrs):
if (name != 'messagebundle'):
self.curr_elem = name
attr_names = attrs.getQNames()
if 'name' in attr_names:
self.resource_name = attrs.getValueByQName('name')
att_text = []
for attr_name in attr_names:
att_text.append(' ')
att_text.append(attr_name)
att_text.append('=')
att_text.append(
xml.sax.saxutils.quoteattr(attrs.getValueByQName(attr_name)))
self.parent._AddNontranslateableChunk("<%s%s>" %
(name, ''.join(att_text)))
def characters(self, content):
if self.curr_elem != '':
self.curr_text += content
def endElement(self, name):
if name != 'messagebundle':
self.parent.AddMessage(self.curr_text, self.resource_name,
self.meaning, self.translateable)
self.parent._AddNontranslateableChunk("</%s>\n" % name)
self.curr_elem = ''
self.curr_text = ''
self.resource_name = ''
self.meaning = ''
self.translateable = True
def ignorableWhitespace(self, whitespace):
pass
class IgoogleStrings(regexp.RegexpGatherer):
'''Supports the ALL_ALL.xml format used by Igoogle gadgets.'''
def AddMessage(self, msgtext, description, meaning, translateable):
if msgtext == '':
return
msg = tclib.Message(description=description, meaning=meaning)
unescaped_text = self.UnEscape(msgtext)
parts = PLACEHOLDER_RE.split(unescaped_text)
in_placeholder = False
for part in parts:
if part == '':
continue
elif part == '[![':
in_placeholder = True
elif part == ']!]':
in_placeholder = False
else:
if in_placeholder:
msg.AppendPlaceholder(tclib.Placeholder(part, '[![%s]!]' % part,
'(placeholder)'))
else:
msg.AppendText(part)
self.skeleton_.append(
self.uberclique.MakeClique(msg, translateable=translateable))
# if statement needed because this is supposed to be idempotent (so never
# set back to false)
if translateable:
self.translatable_chunk_ = True
# Although we use the RegexpGatherer base class, we do not use the
# _RegExpParse method of that class to implement Parse(). Instead, we
# parse using a SAX parser.
def Parse(self):
if self.have_parsed_:
return
self.have_parsed_ = True
self.text_ = self._LoadInputFile().strip()
self._AddNontranslateableChunk(u'<messagebundle>\n')
stream = StringIO.StringIO(self.text_)
handler = IgoogleStringsContentHandler(self)
xml.sax.parse(stream, handler)
self._AddNontranslateableChunk(u'</messagebundle>\n')
def Escape(self, text):
return util.EncodeCdata(text)