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

Side by Side Diff: grit/node/misc.py

Issue 9965022: Allow substitution of messages as variables in other messages. (Closed) Base URL: https://grit-i18n.googlecode.com/svn/trunk
Patch Set: Fix unit tests for policy writers. Created 8 years, 8 months 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « grit/node/message.py ('k') | grit/node/misc_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 '''Miscellaneous node types. 6 '''Miscellaneous node types.
7 ''' 7 '''
8 8
9 import os.path 9 import os.path
10 import re 10 import re
11 import sys 11 import sys
12 12
13 from grit.node import base 13 from grit.node import base
14 from grit.node import message 14 from grit.node import message
15 15
16 from grit import exception 16 from grit import exception
17 from grit import constants 17 from grit import constants
18 from grit import util 18 from grit import util
19 19
20 import grit.format.rc_header 20 import grit.format.rc_header
21 21
22 22
23 # RTL languages
24 # TODO(jennyz): remove this fixed set of RTL language array
25 # now that generic expand_variable code exists.
26 _RTL_LANGS = (
27 'ar', # Arabic
28 'fa', # Farsi
29 'iw', # Hebrew
30 'ks', # Kashmiri
31 'ku', # Kurdish
32 'ps', # Pashto
33 'ur', # Urdu
34 'yi', # Yiddish
35 )
36
37
23 def _ReadFirstIdsFromFile(filename, defines): 38 def _ReadFirstIdsFromFile(filename, defines):
24 '''Read the starting resource id values from |filename|. We also 39 '''Read the starting resource id values from |filename|. We also
25 expand variables of the form <(FOO) based on defines passed in on 40 expand variables of the form <(FOO) based on defines passed in on
26 the command line. 41 the command line.
27 42
28 Returns a tuple, the absolute path of SRCDIR followed by the 43 Returns a tuple, the absolute path of SRCDIR followed by the
29 first_ids dictionary. 44 first_ids dictionary.
30 ''' 45 '''
31 first_ids_dict = eval(open(filename).read()) 46 first_ids_dict = eval(open(filename).read())
32 src_root_dir = os.path.abspath(os.path.join(os.path.dirname(filename), 47 src_root_dir = os.path.abspath(os.path.join(os.path.dirname(filename),
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 96
82 def MandatoryAttributes(self): 97 def MandatoryAttributes(self):
83 return ['expr'] 98 return ['expr']
84 99
85 def IsConditionSatisfied(self): 100 def IsConditionSatisfied(self):
86 '''Returns true if and only if the Python expression stored in attribute 101 '''Returns true if and only if the Python expression stored in attribute
87 'expr' evaluates to true. 102 'expr' evaluates to true.
88 ''' 103 '''
89 return self.EvaluateCondition(self.attrs['expr']) 104 return self.EvaluateCondition(self.attrs['expr'])
90 105
106 def SatisfiesOutputCondition(self):
107 '''Returns true if its condition is satisfied, including on ancestors.'''
108 if not self.IsConditionSatisfied():
109 return False
110 else:
111 return base.Node.SatisfiesOutputCondition(self)
112
91 113
92 class ReleaseNode(base.Node): 114 class ReleaseNode(base.Node):
93 '''The <release> element.''' 115 '''The <release> element.'''
94 116
95 def _IsValidChild(self, child): 117 def _IsValidChild(self, child):
96 from grit.node import empty 118 from grit.node import empty
97 return isinstance(child, (empty.IncludesNode, empty.MessagesNode, 119 return isinstance(child, (empty.IncludesNode, empty.MessagesNode,
98 empty.StructuresNode, empty.IdentifiersNode)) 120 empty.StructuresNode, empty.IdentifiersNode))
99 121
100 def _IsValidAttribute(self, name, value): 122 def _IsValidAttribute(self, name, value):
(...skipping 19 matching lines...) Expand all
120 else: 142 else:
121 return super(type(self), self).ItemFormatter(t) 143 return super(type(self), self).ItemFormatter(t)
122 144
123 class GritNode(base.Node): 145 class GritNode(base.Node):
124 '''The <grit> root element.''' 146 '''The <grit> root element.'''
125 147
126 def __init__(self): 148 def __init__(self):
127 base.Node.__init__(self) 149 base.Node.__init__(self)
128 self.output_language = '' 150 self.output_language = ''
129 self.defines = {} 151 self.defines = {}
152 self.substituter = util.Substituter()
130 153
131 def _IsValidChild(self, child): 154 def _IsValidChild(self, child):
132 from grit.node import empty 155 from grit.node import empty
133 return isinstance(child, (ReleaseNode, empty.TranslationsNode, 156 return isinstance(child, (ReleaseNode, empty.TranslationsNode,
134 empty.OutputsNode)) 157 empty.OutputsNode))
135 158
136 def _IsValidAttribute(self, name, value): 159 def _IsValidAttribute(self, name, value):
137 if name not in ['base_dir', 'first_ids_file', 'source_lang_id', 160 if name not in ['base_dir', 'first_ids_file', 'source_lang_id',
138 'latest_public_release', 'current_release', 161 'latest_public_release', 'current_release',
139 'enc_check', 'tc_project']: 162 'enc_check', 'tc_project', 'grit_version']:
140 return False 163 return False
141 if name in ['latest_public_release', 'current_release'] and value.strip( 164 if name in ['latest_public_release', 'current_release'] and value.strip(
142 '0123456789') != '': 165 '0123456789') != '':
143 return False 166 return False
144 return True 167 return True
145 168
146 def MandatoryAttributes(self): 169 def MandatoryAttributes(self):
147 return ['latest_public_release', 'current_release'] 170 return ['latest_public_release', 'current_release']
148 171
149 def DefaultAttributes(self): 172 def DefaultAttributes(self):
150 return { 173 return {
151 'base_dir' : '.', 174 'base_dir' : '.',
152 'first_ids_file': '', 175 'first_ids_file': '',
176 'grit_version': 1,
153 'source_lang_id' : 'en', 177 'source_lang_id' : 'en',
154 'enc_check' : constants.ENCODING_CHECK, 178 'enc_check' : constants.ENCODING_CHECK,
155 'tc_project' : 'NEED_TO_SET_tc_project_ATTRIBUTE', 179 'tc_project' : 'NEED_TO_SET_tc_project_ATTRIBUTE',
156 } 180 }
157 181
158 def EndParsing(self): 182 def EndParsing(self):
159 base.Node.EndParsing(self) 183 base.Node.EndParsing(self)
160 if (int(self.attrs['latest_public_release']) 184 if (int(self.attrs['latest_public_release'])
161 > int(self.attrs['current_release'])): 185 > int(self.attrs['current_release'])):
162 raise exception.Parsing('latest_public_release cannot have a greater ' 186 raise exception.Parsing('latest_public_release cannot have a greater '
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 '''Returns the list of <output> nodes that are descendants of this node's 308 '''Returns the list of <output> nodes that are descendants of this node's
285 <outputs> child and are not enclosed by unsatisfied <if> conditionals. 309 <outputs> child and are not enclosed by unsatisfied <if> conditionals.
286 ''' 310 '''
287 for child in self.children: 311 for child in self.children:
288 if child.name == 'outputs': 312 if child.name == 'outputs':
289 output_files = [] 313 output_files = []
290 self._CollectOutputFiles(child.children, output_files) 314 self._CollectOutputFiles(child.children, output_files)
291 return output_files 315 return output_files
292 raise exception.MissingElement() 316 raise exception.MissingElement()
293 317
318 def GetSubstitutionMessages(self):
319 '''Returns the list of <message sub_variable="true"> nodes.'''
320 msg_nodes = self.GetChildrenOfType(message.MessageNode)
321 return [n for n in msg_nodes if
322 n.attrs['sub_variable'] == 'true' and n.SatisfiesOutputCondition()]
323
294 def ItemFormatter(self, t): 324 def ItemFormatter(self, t):
295 if t == 'rc_header': 325 if t == 'rc_header':
296 from grit.format import rc_header # import here to avoid circular dep 326 from grit.format import rc_header # import here to avoid circular dep
297 return rc_header.TopLevel() 327 return rc_header.TopLevel()
298 elif t in ['rc_all', 'rc_translateable', 'rc_nontranslateable']: 328 elif t in ['rc_all', 'rc_translateable', 'rc_nontranslateable']:
299 from grit.format import rc # avoid circular dep 329 from grit.format import rc # avoid circular dep
300 return rc.TopLevel() 330 return rc.TopLevel()
301 elif t == 'c_format': 331 elif t == 'c_format':
302 from grit.format import c_format 332 from grit.format import c_format
303 return c_format.TopLevel() 333 return c_format.TopLevel()
304 elif t == 'resource_map_header': 334 elif t == 'resource_map_header':
305 from grit.format import resource_map 335 from grit.format import resource_map
306 return resource_map.HeaderTopLevel() 336 return resource_map.HeaderTopLevel()
307 elif t in ('resource_map_source', 'resource_file_map_source'): 337 elif t in ('resource_map_source', 'resource_file_map_source'):
308 from grit.format import resource_map 338 from grit.format import resource_map
309 return resource_map.SourceTopLevel() 339 return resource_map.SourceTopLevel()
310 elif t == 'js_map_format': 340 elif t == 'js_map_format':
311 from grit.format import js_map_format 341 from grit.format import js_map_format
312 return js_map_format.TopLevel() 342 return js_map_format.TopLevel()
313 elif t in ('adm', 'plist', 'plist_strings', 'admx', 'adml', 'doc', 'json', 343 elif t in ('adm', 'plist', 'plist_strings', 'admx', 'adml', 'doc', 'json',
314 'reg'): 344 'reg'):
315 from grit.format.policy_templates import template_formatter 345 from grit.format.policy_templates import template_formatter
316 return template_formatter.TemplateFormatter(t) 346 return template_formatter.TemplateFormatter(t)
317 else: 347 else:
318 return super(type(self), self).ItemFormatter(t) 348 return super(type(self), self).ItemFormatter(t)
319 349
320 def SetOutputContext(self, output_language, defines): 350 def SetOutputContext(self, output_language, defines):
351 '''Set the output context: language and defines. Prepares substitutions.
352
353 The substitutions are reset every time the OutputContext is changed.
354 They include messages designated as variables, and language codes for html
355 and rc files.
356
357 Args:
358 output_language: a two-letter language code (eg: 'en', 'ar'...)
359 defines: a map of names to values (strings or booleans.)
360 '''
361 output_language = output_language or self.GetSourceLanguage()
321 self.output_language = output_language 362 self.output_language = output_language
322 self.defines = defines 363 self.defines = defines
364 self.substituter.AddMessages(self.GetSubstitutionMessages(),
365 output_language)
366 if output_language in _RTL_LANGS:
367 direction = 'dir="RTL"'
368 else:
369 direction = 'dir="LTR"'
370 self.substituter.AddSubstitutions({
371 'GRITLANGCODE': output_language,
372 'GRITDIR': direction,
373 })
374 from grit.format import rc # avoid circular dep
375 rc.RcSubstitutions(self.substituter, output_language)
323 376
324 def SetDefines(self, defines): 377 def SetDefines(self, defines):
325 self.defines = defines 378 self.defines = defines
326 379
327 def AssignFirstIds(self, filename_or_stream, defines): 380 def AssignFirstIds(self, filename_or_stream, defines):
328 '''Assign first ids to each grouping node based on values from the 381 '''Assign first ids to each grouping node based on values from the
329 first_ids file (if specified on the <grit> node). 382 first_ids file (if specified on the <grit> node).
330 ''' 383 '''
331 # If the input is a stream, then we're probably in a unit test and 384 # If the input is a stream, then we're probably in a unit test and
332 # should skip this step. 385 # should skip this step.
(...skipping 30 matching lines...) Expand all
363 'update that file.' % (first_ids_filename, filename)) 416 'update that file.' % (first_ids_filename, filename))
364 print '-' * 78 417 print '-' * 78
365 raise e 418 raise e
366 419
367 try: 420 try:
368 node.attrs['first_id'] = str(id_list.pop(0)) 421 node.attrs['first_id'] = str(id_list.pop(0))
369 except IndexError, e: 422 except IndexError, e:
370 raise Exception('Please update %s and add a first id for %s (%s).' 423 raise Exception('Please update %s and add a first id for %s (%s).'
371 % (first_ids_filename, filename, node.name)) 424 % (first_ids_filename, filename, node.name))
372 425
426 def RunGatherers(self, recursive=0, debug=False):
427 '''Gathers information for the structure nodes, then apply substitutions.
428
429 The substitutions step requires that the OutputContext has been set.
430 Locally, get the Substitution messages
431 and add them to the substituter. Also add substitutions for language codes
432 in the Rc.
433
434 Args:
435 recursive: will call RunGatherers() recursively on all child nodes first.
436 debug: will print information while running gatherers.
437 '''
438 base.Node.RunGatherers(self, recursive, False)
439 assert self.output_language
440 self.SubstituteMessages(self.substituter)
441
373 442
374 class IdentifierNode(base.Node): 443 class IdentifierNode(base.Node):
375 '''A node for specifying identifiers that should appear in the resource 444 '''A node for specifying identifiers that should appear in the resource
376 header file, and be unique amongst all other resource identifiers, but don't 445 header file, and be unique amongst all other resource identifiers, but don't
377 have any other attributes or reference any resources. 446 have any other attributes or reference any resources.
378 ''' 447 '''
379 448
380 def MandatoryAttributes(self): 449 def MandatoryAttributes(self):
381 return ['name'] 450 return ['name']
382 451
(...skipping 17 matching lines...) Expand all
400 by parameters of the same name. 469 by parameters of the same name.
401 ''' 470 '''
402 node = IdentifierNode() 471 node = IdentifierNode()
403 node.StartParsing('identifier', parent) 472 node.StartParsing('identifier', parent)
404 node.HandleAttribute('name', name) 473 node.HandleAttribute('name', name)
405 node.HandleAttribute('id', id) 474 node.HandleAttribute('id', id)
406 node.HandleAttribute('comment', comment) 475 node.HandleAttribute('comment', comment)
407 node.EndParsing() 476 node.EndParsing()
408 return node 477 return node
409 Construct = staticmethod(Construct) 478 Construct = staticmethod(Construct)
OLDNEW
« no previous file with comments | « grit/node/message.py ('k') | grit/node/misc_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698