Chromium Code Reviews| 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 """Produces localized strings.xml files for Android. | 6 """Produces localized strings.xml files for Android. |
| 7 | 7 |
| 8 In cases where an "android" type output file is requested in a grd, the classes | 8 In cases where an "android" type output file is requested in a grd, the classes |
| 9 in android_xml will process the messages and translations to produce a valid | 9 in android_xml will process the messages and translations to produce a valid |
| 10 strings.xml that is properly localized with the specified language. | 10 strings.xml that is properly localized with the specified language. |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 89 | 89 |
| 90 | 90 |
| 91 # In most cases we only need a name attribute and string value. | 91 # In most cases we only need a name attribute and string value. |
| 92 _SIMPLE_TEMPLATE = u'<string name="%s">%s</string>\n' | 92 _SIMPLE_TEMPLATE = u'<string name="%s">%s</string>\n' |
| 93 | 93 |
| 94 | 94 |
| 95 # In a few cases a product attribute is needed. | 95 # In a few cases a product attribute is needed. |
| 96 _PRODUCT_TEMPLATE = u'<string name="%s" product="%s">%s</string>\n' | 96 _PRODUCT_TEMPLATE = u'<string name="%s" product="%s">%s</string>\n' |
| 97 | 97 |
| 98 | 98 |
| 99 # Some strings have a plural equivalent | |
| 100 _PLURALS_TEMPLATE = '<plurals name="%s">\n%s</plurals>\n' | |
| 101 _PLURALS_ITEM_TEMPLATE = ' <item quantity="%s">%s</item>\n' | |
| 102 | |
| 103 | |
| 99 def Format(root, lang='en', output_dir='.'): | 104 def Format(root, lang='en', output_dir='.'): |
| 105 import sys | |
| 106 sys.stderr.write('outputting to %s\n' % output_dir) | |
|
newt (away)
2015/08/03 23:06:40
Looks like debugging code. Remove this?
conleyo
2015/08/04 00:27:52
Done.
| |
| 100 yield ('<?xml version="1.0" encoding="utf-8"?>\n' | 107 yield ('<?xml version="1.0" encoding="utf-8"?>\n' |
| 101 '<resources ' | 108 '<resources ' |
| 102 'xmlns:android="http://schemas.android.com/apk/res/android">\n') | 109 'xmlns:android="http://schemas.android.com/apk/res/android">\n') |
| 103 | 110 |
| 104 tagged_only = _TAGGED_ONLY_DEFAULT | 111 tagged_only = _TAGGED_ONLY_DEFAULT |
| 105 if _TAGGED_ONLY_ENV_VAR in os.environ: | 112 if _TAGGED_ONLY_ENV_VAR in os.environ: |
| 106 tagged_only = os.environ[_TAGGED_ONLY_ENV_VAR].lower() | 113 tagged_only = os.environ[_TAGGED_ONLY_ENV_VAR].lower() |
| 107 if tagged_only == 'true': | 114 if tagged_only == 'true': |
| 108 tagged_only = True | 115 tagged_only = True |
| 109 elif tagged_only == 'false': | 116 elif tagged_only == 'false': |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 124 """Returns true if node should be outputted. | 131 """Returns true if node should be outputted. |
| 125 | 132 |
| 126 Args: | 133 Args: |
| 127 node: a Node from the grd dom | 134 node: a Node from the grd dom |
| 128 tagged_only: true, if only tagged messages should be outputted | 135 tagged_only: true, if only tagged messages should be outputted |
| 129 """ | 136 """ |
| 130 return (isinstance(node, message.MessageNode) and | 137 return (isinstance(node, message.MessageNode) and |
| 131 (not tagged_only or _EMIT_TAG in node.formatter_data)) | 138 (not tagged_only or _EMIT_TAG in node.formatter_data)) |
| 132 | 139 |
| 133 | 140 |
| 141 def _LoadPluralMessage(message): | |
|
newt (away)
2015/08/03 23:06:40
Please add a docstring comment. This method is far
conleyo
2015/08/04 00:27:52
Done.
| |
| 142 import re | |
|
newt (away)
2015/08/03 23:06:40
move import to top of file
conleyo
2015/08/04 00:27:52
Done.
| |
| 143 ret = {} | |
| 144 plural_match = re.match(r'\{[A-Z_]+,\s*plural,(.*)\}$', message, re.S) | |
|
newt (away)
2015/08/03 23:06:40
Pre-compile these patterns, since they're used so
conleyo
2015/08/04 00:27:52
Done.
| |
| 145 if not plural_match: | |
| 146 return None | |
| 147 body = plural_match.group(1).strip() | |
|
newt (away)
2015/08/03 23:06:40
To make this more readable, I'd suggest naming the
conleyo
2015/08/04 00:27:53
Done.
| |
| 148 for item_match in re.finditer(r'(.*)\s*\{(.*?)\}', body): | |
|
newt (away)
2015/08/03 23:06:40
I'd replace the initial .* with \S+ since you want
conleyo
2015/08/04 00:27:52
Done.
| |
| 149 quantity = item_match.group(1) | |
| 150 value = item_match.group(2).replace('#', '%d') | |
| 151 number_match = re.match(r'=(.*)', quantity) | |
|
newt (away)
2015/08/03 23:06:40
Explicit checks here would be better, e.g.
if q
conleyo
2015/08/04 00:27:52
Done.
| |
| 152 if number_match: | |
| 153 number = number_match.group(1).strip() | |
| 154 if number == '0': | |
| 155 ret['zero'] = value | |
| 156 elif number == '1': | |
| 157 ret['one'] = value | |
| 158 elif number == '2': | |
| 159 ret['two'] = value | |
| 160 else: | |
| 161 ret[number] = value | |
| 162 else: | |
| 163 ret['other'] = value | |
| 164 return ret | |
| 165 | |
| 166 | |
| 134 def _FormatMessage(item, lang): | 167 def _FormatMessage(item, lang): |
| 135 """Writes out a single string as a <resource/> element.""" | 168 """Writes out a single string as a <resource/> element.""" |
| 136 | 169 |
| 137 value = item.ws_at_start + item.Translate(lang) + item.ws_at_end | 170 value = item.ws_at_start + item.Translate(lang) + item.ws_at_end |
| 171 plurals = _LoadPluralMessage(value) | |
|
newt (away)
2015/08/03 23:06:40
How about calling this _FormatPluralMessage() and
conleyo
2015/08/04 00:27:52
Done.
| |
| 138 # Replace < > & with < > & to ensure we generate valid XML and | 172 # Replace < > & with < > & to ensure we generate valid XML and |
| 139 # replace ' " with \' \" to conform to Android's string formatting rules. | 173 # replace ' " with \' \" to conform to Android's string formatting rules. |
| 140 value = xml.sax.saxutils.escape(value, {"'": "\\'", '"': '\\"'}) | 174 value = xml.sax.saxutils.escape(value, {"'": "\\'", '"': '\\"'}) |
|
newt (away)
2015/08/03 23:06:40
these replacements need to happen even for plural
conleyo
2015/08/04 00:27:52
Done.
| |
| 141 # Wrap the string in double quotes to preserve whitespace. | 175 # Wrap the string in double quotes to preserve whitespace. |
| 142 value = '"' + value + '"' | 176 value = '"' + value + '"' |
| 143 | 177 |
| 144 mangled_name = item.GetTextualIds()[0] | 178 mangled_name = item.GetTextualIds()[0] |
| 145 match = _NAME_PATTERN.match(mangled_name) | 179 match = _NAME_PATTERN.match(mangled_name) |
| 146 if not match: | 180 if not match: |
| 147 raise Exception('Unexpected resource name: %s' % mangled_name) | 181 raise Exception('Unexpected resource name: %s' % mangled_name) |
| 148 name = match.group('name').lower() | 182 name = match.group('name').lower() |
| 149 product = match.group('product') | 183 product = match.group('product') |
| 150 | 184 |
| 151 # Override product or name with values in formatter_data, if any. | 185 # Override product or name with values in formatter_data, if any. |
| 152 product = item.formatter_data.get(_PRODUCT_TAG, product) | 186 product = item.formatter_data.get(_PRODUCT_TAG, product) |
| 153 name = item.formatter_data.get(_NAME_TAG, name) | 187 name = item.formatter_data.get(_NAME_TAG, name) |
| 154 | 188 |
| 155 if product: | 189 |
| 190 if plurals: | |
| 191 items = '' | |
| 192 for quantity, item_value in plurals.items(): | |
| 193 items += _PLURALS_ITEM_TEMPLATE % (quantity, item_value) | |
| 194 return _PLURALS_TEMPLATE % (name, items) | |
| 195 elif product: | |
| 156 return _PRODUCT_TEMPLATE % (name, product, value) | 196 return _PRODUCT_TEMPLATE % (name, product, value) |
| 157 else: | 197 else: |
| 158 return _SIMPLE_TEMPLATE % (name, value) | 198 return _SIMPLE_TEMPLATE % (name, value) |
| OLD | NEW |