OLD | NEW |
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 '''Utilities used by GRIT. | 6 '''Utilities used by GRIT. |
7 ''' | 7 ''' |
8 | 8 |
9 import sys | 9 import sys |
10 import os.path | 10 import os.path |
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 def IsVerbose(): | 401 def IsVerbose(): |
402 return verbose | 402 return verbose |
403 | 403 |
404 def IsExtraVerbose(): | 404 def IsExtraVerbose(): |
405 return extra_verbose | 405 return extra_verbose |
406 | 406 |
407 def GetCurrentYear(): | 407 def GetCurrentYear(): |
408 '''Returns the current 4-digit year as an integer.''' | 408 '''Returns the current 4-digit year as an integer.''' |
409 return time.localtime()[0] | 409 return time.localtime()[0] |
410 | 410 |
| 411 def ParseDefine(define): |
| 412 '''Parses a define argument and returns the name and value. |
| 413 |
| 414 The format is either "NAME=VAL" or "NAME", using True as the default value. |
| 415 Values of "1" and "0" are transformed to True and False respectively. |
| 416 |
| 417 Args: |
| 418 define: a string of the form "NAME=VAL" or "NAME". |
| 419 |
| 420 Returns: |
| 421 A (name, value) pair. name is a string, value a string or boolean. |
| 422 ''' |
| 423 parts = [part.strip() for part in define.split('=')] |
| 424 assert len(parts) >= 1 |
| 425 name = parts[0] |
| 426 val = True |
| 427 if len(parts) > 1: |
| 428 val = parts[1] |
| 429 if val == "1": val = True |
| 430 elif val == "0": val = False |
| 431 return (name, val) |
| 432 |
| 433 |
| 434 class Substituter(object): |
| 435 '''Finds and substitutes variable names in text strings. |
| 436 |
| 437 Given a dictionary of variable names and values, prepares to |
| 438 search for patterns of the form [VAR_NAME] in a text. |
| 439 The value will be substituted back efficiently. |
| 440 Also applies to tclib.Message objects. |
| 441 ''' |
| 442 |
| 443 def __init__(self): |
| 444 '''Create an empty substituter.''' |
| 445 self.substitutions_ = {} |
| 446 self.dirty_ = True |
| 447 |
| 448 def AddSubstitutions(self, subs): |
| 449 '''Add new values to the substitutor. |
| 450 |
| 451 Args: |
| 452 subs: A dictionary of new substitutions. |
| 453 ''' |
| 454 self.substitutions_.update(subs) |
| 455 self.dirty_ = True |
| 456 |
| 457 def AddMessages(self, messages, lang): |
| 458 '''Adds substitutions extracted from node.Message objects. |
| 459 |
| 460 Args: |
| 461 messages: a list of node.Message objects. |
| 462 lang: The translation language to use in substitutions. |
| 463 ''' |
| 464 subs = [(str(msg.attrs['name']), msg.Translate(lang)) for msg in messages] |
| 465 self.AddSubstitutions(dict(subs)) |
| 466 self.dirty_ = True |
| 467 |
| 468 def GetExp(self): |
| 469 '''Obtain a regular expression that will find substitution keys in text. |
| 470 |
| 471 Create and cache if the substituter has been updated. Use the cached value |
| 472 otherwise. Keys will be enclosed in [square brackets] in text. |
| 473 |
| 474 Returns: |
| 475 A regular expression object. |
| 476 ''' |
| 477 if self.dirty_: |
| 478 components = ['\[%s\]' % (k,) for k in self.substitutions_.keys()] |
| 479 self.exp = re.compile("(%s)" % ('|'.join(components),)) |
| 480 self.dirty_ = False |
| 481 return self.exp |
| 482 |
| 483 def Substitute(self, text): |
| 484 '''Substitute the variable values in the given text. |
| 485 |
| 486 Text of the form [message_name] will be replaced by the message's value. |
| 487 |
| 488 Args: |
| 489 text: A string of text. |
| 490 |
| 491 Returns: |
| 492 A string of text with substitutions done. |
| 493 ''' |
| 494 return ''.join([self._SubFragment(f) for f in self.GetExp().split(text)]) |
| 495 |
| 496 def _SubFragment(self, fragment): |
| 497 '''Utility function for Substitute. |
| 498 |
| 499 Performs a simple substitution if the fragment is exactly of the form |
| 500 [message_name]. |
| 501 |
| 502 Args: |
| 503 fragment: A simple string. |
| 504 |
| 505 Returns: |
| 506 A string with the substitution done. |
| 507 ''' |
| 508 if len(fragment) > 2 and fragment[0] == '[' and fragment[-1] == ']': |
| 509 sub = self.substitutions_.get(fragment[1:-1], None) |
| 510 if sub is not None: |
| 511 return sub |
| 512 return fragment |
| 513 |
| 514 def SubstituteMessage(self, msg): |
| 515 '''Apply substitutions to a tclib.Message object. |
| 516 |
| 517 Text of the form [message_name] will be replaced by a new placeholder, |
| 518 whose presentation will take the form the message_name_{UsageCount}, and |
| 519 whose example will be the message's value. Existing placeholders are |
| 520 not affected. |
| 521 |
| 522 Args: |
| 523 msg: A tclib.Message object. |
| 524 |
| 525 Returns: |
| 526 A tclib.Message object, with substitutions done. |
| 527 ''' |
| 528 from grit import tclib # avoid circular import |
| 529 counts = {} |
| 530 text = msg.GetPresentableContent() |
| 531 placeholders = [] |
| 532 newtext = '' |
| 533 for f in self.GetExp().split(text): |
| 534 sub = self._SubFragment(f) |
| 535 if f != sub: |
| 536 f = str(f) |
| 537 count = counts.get(f, 0) + 1 |
| 538 counts[f] = count |
| 539 name = "%s_%d" % (f[1:-1], count) |
| 540 placeholders.append(tclib.Placeholder(name, f, sub)) |
| 541 newtext += name |
| 542 else: |
| 543 newtext += f |
| 544 if placeholders: |
| 545 return tclib.Message(newtext, msg.GetPlaceholders() + placeholders, |
| 546 msg.GetDescription(), msg.GetMeaning()) |
| 547 else: |
| 548 return msg |
OLD | NEW |