blob: 38b504c38122a2d4be946f410285f5d207c8fc9a [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.
'''A baseclass for simple gatherers that store their gathered resource in a
list.
'''
import types
from grit.gather import interface
from grit import clique
from grit import tclib
class SkeletonGatherer(interface.GathererBase):
'''Common functionality of gatherers that parse their input as a skeleton of
translatable and nontranslatable chunks.
'''
def __init__(self, *args, **kwargs):
super(SkeletonGatherer, self).__init__(*args, **kwargs)
# List of parts of the document. Translateable parts are
# clique.MessageClique objects, nontranslateable parts are plain strings.
# Translated messages are inserted back into the skeleton using the quoting
# rules defined by self.Escape()
self.skeleton_ = []
# A list of the names of IDs that need to be defined for this resource
# section to compile correctly.
self.ids_ = []
# True if Parse() has already been called.
self.have_parsed_ = False
# True if a translatable chunk has been added
self.translatable_chunk_ = False
# If not None, all parts of the document will be put into this single
# message; otherwise the normal skeleton approach is used.
self.single_message_ = None
# Number to use for the next placeholder name. Used only if single_message
# is not None
self.ph_counter_ = 1
def GetText(self):
'''Returns the original text of the section'''
return self.text_
def Escape(self, text):
'''Subclasses can override. Base impl is identity.
'''
return text
def UnEscape(self, text):
'''Subclasses can override. Base impl is identity.
'''
return text
def GetTextualIds(self):
'''Returns the list of textual IDs that need to be defined for this
resource section to compile correctly.'''
return self.ids_
def _AddTextualId(self, id):
self.ids_.append(id)
def GetCliques(self):
'''Returns the message cliques for each translateable message in the
resource section.'''
return [x for x in self.skeleton_ if isinstance(x, clique.MessageClique)]
def Translate(self, lang, pseudo_if_not_available=True,
skeleton_gatherer=None, fallback_to_english=False):
if len(self.skeleton_) == 0:
raise exception.NotReady()
if skeleton_gatherer:
assert len(skeleton_gatherer.skeleton_) == len(self.skeleton_)
out = []
for ix in range(len(self.skeleton_)):
if isinstance(self.skeleton_[ix], types.StringTypes):
if skeleton_gatherer:
# Make sure the skeleton is like the original
assert(isinstance(skeleton_gatherer.skeleton_[ix], types.StringTypes))
out.append(skeleton_gatherer.skeleton_[ix])
else:
out.append(self.skeleton_[ix])
else:
if skeleton_gatherer: # Make sure the skeleton is like the original
assert(not isinstance(skeleton_gatherer.skeleton_[ix],
types.StringTypes))
msg = self.skeleton_[ix].MessageForLanguage(lang,
pseudo_if_not_available,
fallback_to_english)
def MyEscape(text):
return self.Escape(text)
text = msg.GetRealContent(escaping_function=MyEscape)
out.append(text)
return ''.join(out)
def Parse(self):
'''Parses the section. Implemented by subclasses. Idempotent.'''
raise NotImplementedError()
def _AddNontranslateableChunk(self, chunk):
'''Adds a nontranslateable chunk.'''
if self.single_message_:
ph = tclib.Placeholder('XX%02dXX' % self.ph_counter_, chunk, chunk)
self.ph_counter_ += 1
self.single_message_.AppendPlaceholder(ph)
else:
self.skeleton_.append(chunk)
def _AddTranslateableChunk(self, chunk):
'''Adds a translateable chunk. It will be unescaped before being added.'''
# We don't want empty messages since they are redundant and the TC
# doesn't allow them.
if chunk == '':
return
unescaped_text = self.UnEscape(chunk)
if self.single_message_:
self.single_message_.AppendText(unescaped_text)
else:
self.skeleton_.append(self.uberclique.MakeClique(
tclib.Message(text=unescaped_text)))
self.translatable_chunk_ = True
def SubstituteMessages(self, substituter):
'''Applies substitutions to all messages in the tree.
Goes through the skeleton and finds all MessageCliques.
Args:
substituter: a grit.util.Substituter object.
'''
if self.single_message_:
self.single_message_ = substituter.SubstituteMessage(self.single_message_)
new_skel = []
for chunk in self.skeleton_:
if isinstance(chunk, clique.MessageClique):
old_message = chunk.GetMessage()
new_message = substituter.SubstituteMessage(old_message)
if new_message is not old_message:
new_skel.append(self.uberclique.MakeClique(new_message))
continue
new_skel.append(chunk)
self.skeleton_ = new_skel