Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(732)

Unified Diff: tools/grit/grit/node/message.py

Issue 1410853008: Move grit from DEPS into src. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: webview licenses Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/grit/grit/node/mapping.py ('k') | tools/grit/grit/node/message_unittest.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/grit/grit/node/message.py
diff --git a/tools/grit/grit/node/message.py b/tools/grit/grit/node/message.py
new file mode 100755
index 0000000000000000000000000000000000000000..48cd1c79519bfe87a294eef03074b10526341ac5
--- /dev/null
+++ b/tools/grit/grit/node/message.py
@@ -0,0 +1,301 @@
+#!/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.
+
+'''Handling of the <message> element.
+'''
+
+import re
+import types
+
+from grit.node import base
+
+import grit.format.rc_header
+import grit.format.rc
+
+from grit import clique
+from grit import exception
+from grit import lazy_re
+from grit import tclib
+from grit import util
+
+# Finds whitespace at the start and end of a string which can be multiline.
+_WHITESPACE = lazy_re.compile('(?P<start>\s*)(?P<body>.+?)(?P<end>\s*)\Z',
+ re.DOTALL | re.MULTILINE)
+
+
+class MessageNode(base.ContentNode):
+ '''A <message> element.'''
+
+ # For splitting a list of things that can be separated by commas or
+ # whitespace
+ _SPLIT_RE = lazy_re.compile('\s*,\s*|\s+')
+
+ def __init__(self):
+ super(MessageNode, self).__init__()
+ # Valid after EndParsing, this is the MessageClique that contains the
+ # source message and any translations of it that have been loaded.
+ self.clique = None
+
+ # We don't send leading and trailing whitespace into the translation
+ # console, but rather tack it onto the source message and any
+ # translations when formatting them into RC files or what have you.
+ self.ws_at_start = '' # Any whitespace characters at the start of the text
+ self.ws_at_end = '' # --"-- at the end of the text
+
+ # A list of "shortcut groups" this message is in. We check to make sure
+ # that shortcut keys (e.g. &J) within each shortcut group are unique.
+ self.shortcut_groups_ = []
+
+ # Formatter-specific data used to control the output of individual strings.
+ # formatter_data is a space separated list of C preprocessor-style
+ # definitions. Names without values are given the empty string value.
+ # Example: "foo=5 bar baz=100"
+ self.formatter_data = {}
+
+ def _IsValidChild(self, child):
+ return isinstance(child, (PhNode))
+
+ def _IsValidAttribute(self, name, value):
+ if name not in ['name', 'offset', 'translateable', 'desc', 'meaning',
+ 'internal_comment', 'shortcut_groups', 'custom_type',
+ 'validation_expr', 'use_name_for_id', 'sub_variable',
+ 'formatter_data']:
+ return False
+ if (name in ('translateable', 'sub_variable') and
+ value not in ['true', 'false']):
+ return False
+ return True
+
+ def MandatoryAttributes(self):
+ return ['name|offset']
+
+ def DefaultAttributes(self):
+ return {
+ 'custom_type' : '',
+ 'desc' : '',
+ 'formatter_data' : '',
+ 'internal_comment' : '',
+ 'meaning' : '',
+ 'shortcut_groups' : '',
+ 'sub_variable' : 'false',
+ 'translateable' : 'true',
+ 'use_name_for_id' : 'false',
+ 'validation_expr' : '',
+ }
+
+ def HandleAttribute(self, attrib, value):
+ base.ContentNode.HandleAttribute(self, attrib, value)
+ if attrib == 'formatter_data':
+ # Parse value, a space-separated list of defines, into a dict.
+ # Example: "foo=5 bar" -> {'foo':'5', 'bar':''}
+ for item in value.split():
+ name, sep, val = item.partition('=')
+ self.formatter_data[name] = val
+
+ def GetTextualIds(self):
+ '''
+ Returns the concatenation of the parent's node first_id and
+ this node's offset if it has one, otherwise just call the
+ superclass' implementation
+ '''
+ if 'offset' in self.attrs:
+ # we search for the first grouping node in the parents' list
+ # to take care of the case where the first parent is an <if> node
+ grouping_parent = self.parent
+ import grit.node.empty
+ while grouping_parent and not isinstance(grouping_parent,
+ grit.node.empty.GroupingNode):
+ grouping_parent = grouping_parent.parent
+
+ assert 'first_id' in grouping_parent.attrs
+ return [grouping_parent.attrs['first_id'] + '_' + self.attrs['offset']]
+ else:
+ return super(MessageNode, self).GetTextualIds()
+
+ def IsTranslateable(self):
+ return self.attrs['translateable'] == 'true'
+
+ def EndParsing(self):
+ super(MessageNode, self).EndParsing()
+
+ # Make the text (including placeholder references) and list of placeholders,
+ # then strip and store leading and trailing whitespace and create the
+ # tclib.Message() and a clique to contain it.
+
+ text = ''
+ placeholders = []
+ for item in self.mixed_content:
+ if isinstance(item, types.StringTypes):
+ text += item
+ else:
+ presentation = item.attrs['name'].upper()
+ text += presentation
+ ex = ' '
+ if len(item.children):
+ ex = item.children[0].GetCdata()
+ original = item.GetCdata()
+ placeholders.append(tclib.Placeholder(presentation, original, ex))
+
+ m = _WHITESPACE.match(text)
+ if m:
+ self.ws_at_start = m.group('start')
+ self.ws_at_end = m.group('end')
+ text = m.group('body')
+
+ self.shortcut_groups_ = self._SPLIT_RE.split(self.attrs['shortcut_groups'])
+ self.shortcut_groups_ = [i for i in self.shortcut_groups_ if i != '']
+
+ description_or_id = self.attrs['desc']
+ if description_or_id == '' and 'name' in self.attrs:
+ description_or_id = 'ID: %s' % self.attrs['name']
+
+ assigned_id = None
+ if self.attrs['use_name_for_id'] == 'true':
+ assigned_id = self.attrs['name']
+ message = tclib.Message(text=text, placeholders=placeholders,
+ description=description_or_id,
+ meaning=self.attrs['meaning'],
+ assigned_id=assigned_id)
+ self.InstallMessage(message)
+
+ def InstallMessage(self, message):
+ '''Sets this node's clique from a tclib.Message instance.
+
+ Args:
+ message: A tclib.Message.
+ '''
+ self.clique = self.UberClique().MakeClique(message, self.IsTranslateable())
+ for group in self.shortcut_groups_:
+ self.clique.AddToShortcutGroup(group)
+ if self.attrs['custom_type'] != '':
+ self.clique.SetCustomType(util.NewClassInstance(self.attrs['custom_type'],
+ clique.CustomType))
+ elif self.attrs['validation_expr'] != '':
+ self.clique.SetCustomType(
+ clique.OneOffCustomType(self.attrs['validation_expr']))
+
+ def SubstituteMessages(self, substituter):
+ '''Applies substitution to this message.
+
+ Args:
+ substituter: a grit.util.Substituter object.
+ '''
+ message = substituter.SubstituteMessage(self.clique.GetMessage())
+ if message is not self.clique.GetMessage():
+ self.InstallMessage(message)
+
+ def GetCliques(self):
+ if self.clique:
+ return [self.clique]
+ else:
+ return []
+
+ def Translate(self, lang):
+ '''Returns a translated version of this message.
+ '''
+ assert self.clique
+ msg = self.clique.MessageForLanguage(lang,
+ self.PseudoIsAllowed(),
+ self.ShouldFallbackToEnglish()
+ ).GetRealContent()
+ return msg.replace('[GRITLANGCODE]', lang)
+
+ def NameOrOffset(self):
+ if 'name' in self.attrs:
+ return self.attrs['name']
+ else:
+ return self.attrs['offset']
+
+ def ExpandVariables(self):
+ '''We always expand variables on Messages.'''
+ return True
+
+ def GetDataPackPair(self, lang, encoding):
+ '''Returns a (id, string) pair that represents the string id and the string
+ in the specified encoding, where |encoding| is one of the encoding values
+ accepted by util.Encode. This is used to generate the data pack data file.
+ '''
+ from grit.format import rc_header
+ id_map = rc_header.GetIds(self.GetRoot())
+ id = id_map[self.GetTextualIds()[0]]
+
+ message = self.ws_at_start + self.Translate(lang) + self.ws_at_end
+ return id, util.Encode(message, encoding)
+
+ def IsResourceMapSource(self):
+ return True
+
+ def GeneratesResourceMapEntry(self, output_all_resource_defines,
+ is_active_descendant):
+ return is_active_descendant
+
+ @staticmethod
+ def Construct(parent, message, name, desc='', meaning='', translateable=True):
+ '''Constructs a new message node that is a child of 'parent', with the
+ name, desc, meaning and translateable attributes set using the same-named
+ parameters and the text of the message and any placeholders taken from
+ 'message', which must be a tclib.Message() object.'''
+ # Convert type to appropriate string
+ translateable = 'true' if translateable else 'false'
+
+ node = MessageNode()
+ node.StartParsing('message', parent)
+ node.HandleAttribute('name', name)
+ node.HandleAttribute('desc', desc)
+ node.HandleAttribute('meaning', meaning)
+ node.HandleAttribute('translateable', translateable)
+
+ items = message.GetContent()
+ for ix, item in enumerate(items):
+ if isinstance(item, types.StringTypes):
+ # Ensure whitespace at front and back of message is correctly handled.
+ if ix == 0:
+ item = "'''" + item
+ if ix == len(items) - 1:
+ item = item + "'''"
+
+ node.AppendContent(item)
+ else:
+ phnode = PhNode()
+ phnode.StartParsing('ph', node)
+ phnode.HandleAttribute('name', item.GetPresentation())
+ phnode.AppendContent(item.GetOriginal())
+
+ if len(item.GetExample()) and item.GetExample() != ' ':
+ exnode = ExNode()
+ exnode.StartParsing('ex', phnode)
+ exnode.AppendContent(item.GetExample())
+ exnode.EndParsing()
+ phnode.AddChild(exnode)
+
+ phnode.EndParsing()
+ node.AddChild(phnode)
+
+ node.EndParsing()
+ return node
+
+class PhNode(base.ContentNode):
+ '''A <ph> element.'''
+
+ def _IsValidChild(self, child):
+ return isinstance(child, ExNode)
+
+ def MandatoryAttributes(self):
+ return ['name']
+
+ def EndParsing(self):
+ super(PhNode, self).EndParsing()
+ # We only allow a single example for each placeholder
+ if len(self.children) > 1:
+ raise exception.TooManyExamples()
+
+ def GetTextualIds(self):
+ # The 'name' attribute is not an ID.
+ return []
+
+
+class ExNode(base.ContentNode):
+ '''An <ex> element.'''
+ pass
« no previous file with comments | « tools/grit/grit/node/mapping.py ('k') | tools/grit/grit/node/message_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698