| #!/usr/bin/env python |
| |
| # Copyright 2020 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| '''Enforces message text style. |
| |
| Expects one argument to be the path of the .grd(p). |
| |
| Sample usage: |
| |
| ./fix_grd.py some_messages.grd |
| git diff |
| # Audit changes (e.g. formatting, quotes, etc). |
| ''' |
| |
| import path_helpers |
| import optparse |
| import os |
| import re |
| import sys |
| import xml.etree.ElementTree as ET |
| |
| def Die(message): |
| '''Prints an error message and exit the program.''' |
| sys.stderr.write(message + '\n') |
| sys.exit(1) |
| |
| def Process(xml_file): |
| xml = ET.parse(xml_file) |
| root = xml.getroot() |
| messages = root.findall('message') |
| modified = False |
| removed_so_far = set() |
| for message in messages: |
| modified |= MaybeRemoveTrailingPeriods(message) |
| modified |= MaybeRemoveUnusedMessage(root, message, removed_so_far) |
| |
| if modified: |
| xml.write(xml_file, encoding='UTF-8') |
| |
| def MaybeRemoveTrailingPeriods(message): |
| modified = False |
| # Re-write messages containing a period at the end (excluding whitespace) |
| # and no other periods. This excludes phrases that have multiple sentences |
| # which should retain periods. |
| text = message.text.rstrip() |
| if text.endswith('.') and text.find('.') == text.rfind('.'): |
| modified = True |
| message.text = message.text.replace('.', '') |
| return modified |
| |
| def MaybeRemoveUnusedMessage(root, message, removed_so_far): |
| found = False |
| |
| # Always strip IDS_ and lowercase the message id. |
| base_message_id = re.sub('^ids_', '', message.get('name').lower()) |
| |
| # Get the unprefixed message id. This is used by various extensions like |
| # ChromeVox and STS. |
| message_id = re.sub( |
| '^(chromevox_|select_to_speak_|switch_access_|enhanced_network_tts_)', |
| '', base_message_id) |
| |
| # This message is needed by the extension system. |
| if message_id == 'locale': |
| return False |
| |
| # Explicitly skip these messages in ChromeVox since they get programmatically |
| # constructed. If the non _brl counterpart was removed though, also remove it. |
| if message_id.endswith('_brl'): |
| if message_id[:-4] in removed_so_far: |
| sys.stdout.write('Removing ' + message_id + '\n') |
| root.remove(message) |
| return True |
| else: |
| return False |
| |
| # Explicitly skip messages referencing ARIA; these strings should be used by |
| # ChromeVox. |
| if message.get('desc').find('ARIA') != -1: |
| return False |
| |
| # Explicitly skip messages starting with tag_. |
| if message_id.startswith('tag_'): |
| return False |
| |
| for dir_name, subdir_list, file_list in os.walk( |
| path_helpers.AccessibilityPath()): |
| for fname in file_list: |
| if not fname.endswith('.js') and not fname.endswith('.html'): |
| continue |
| with open(os.path.join(dir_name, fname), 'r') as f: |
| for line in f: |
| index = line.find(base_message_id) |
| if index == -1: |
| index = line.find(message_id) |
| |
| # Eliminate partial matches (e.g. for bar, foo_bar). |
| if index > 0 and line[index - 1] == '_': |
| continue |
| |
| if index != -1: |
| found = True |
| break |
| |
| if not found: |
| sys.stdout.write('Removing ' + message_id + '\n') |
| removed_so_far.add(message_id) |
| root.remove(message) |
| |
| return not found |
| |
| if __name__ == '__main__': |
| options, args = optparse.OptionParser().parse_args() |
| if len(args) != 1: |
| Die('Expected one .grd file') |
| Process(args[0]) |