Index: grit/node/message.py |
diff --git a/grit/node/message.py b/grit/node/message.py |
deleted file mode 100644 |
index 48cd1c79519bfe87a294eef03074b10526341ac5..0000000000000000000000000000000000000000 |
--- a/grit/node/message.py |
+++ /dev/null |
@@ -1,301 +0,0 @@ |
-#!/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 |