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 24 matching lines...) Expand all Loading... | |
| 35 | 35 |
| 36 Advanced usage | 36 Advanced usage |
| 37 -------------- | 37 -------------- |
| 38 | 38 |
| 39 To process only certain messages in a grd file, tag each desired message by | 39 To process only certain messages in a grd file, tag each desired message by |
| 40 adding "android_java" to formatter_data. Then set the environmental variable | 40 adding "android_java" to formatter_data. Then set the environmental variable |
| 41 ANDROID_JAVA_TAGGED_ONLY to "true" when building the grd file. For example: | 41 ANDROID_JAVA_TAGGED_ONLY to "true" when building the grd file. For example: |
| 42 | 42 |
| 43 <message name="IDS_HELLO" formatter_data="android_java">Hello</message> | 43 <message name="IDS_HELLO" formatter_data="android_java">Hello</message> |
| 44 | 44 |
| 45 To specify the product attribute to be added to a <string> element, add | 45 To generate Android plurals (aka "quantity strings"), use the ICU plural syntax |
| 46 "android_java_product" to formatter_data. "android_java_name" can be used to | 46 in the grd file. This will automatically be transformed into a <purals> element |
| 47 override the name in the <string> element. For example, | 47 in the output xml file. For example: |
|
Nico
2015/08/13 22:45:51
Aha, then say in the Cl description something like
| |
| 48 | 48 |
| 49 <message name="IDS_FOO_NOSDCARD" formatter_data="android_java_product=nosdcard | 49 <message name="IDS_CATS"> |
| 50 android_java_name=foo">no card</message> | 50 {NUM_CATS, plural, |
| 51 <message name="IDS_FOO_DEFAULT" formatter_data="android_java_product=default | 51 =1 {1 cat} |
| 52 android_java_name=foo">has card</message> | 52 other {# cats}} |
| 53 </message> | |
| 53 | 54 |
| 54 would generate | 55 will produce |
| 55 | 56 |
| 56 <string name="foo" product="nosdcard">"no card"</string> | 57 <plurals name="cats"> |
| 57 <string name="foo" product="default">"has card"</string> | 58 <item quantity="one">1 Katze</item> |
| 59 <item quantity="other">%d Katzen</item> | |
| 60 </plurals> | |
| 58 """ | 61 """ |
| 59 | 62 |
| 60 import os | 63 import os |
| 61 import re | 64 import re |
| 62 import types | 65 import types |
| 63 import xml.sax.saxutils | 66 import xml.sax.saxutils |
| 64 | 67 |
| 65 from grit import lazy_re | 68 from grit import lazy_re |
| 66 from grit.node import message | 69 from grit.node import message |
| 67 | 70 |
| 68 | 71 |
| 69 # When this environmental variable has value "true", only tagged messages will | 72 # When this environmental variable has value "true", only tagged messages will |
| 70 # be outputted. | 73 # be outputted. |
| 71 _TAGGED_ONLY_ENV_VAR = 'ANDROID_JAVA_TAGGED_ONLY' | 74 _TAGGED_ONLY_ENV_VAR = 'ANDROID_JAVA_TAGGED_ONLY' |
| 72 _TAGGED_ONLY_DEFAULT = False | 75 _TAGGED_ONLY_DEFAULT = False |
| 73 | 76 |
| 74 # In tagged-only mode, only messages with this tag will be ouputted. | 77 # In tagged-only mode, only messages with this tag will be ouputted. |
| 75 _EMIT_TAG = 'android_java' | 78 _EMIT_TAG = 'android_java' |
| 76 | 79 |
| 77 # This tag controls the product attribute of the generated <string> element. | 80 _NAME_PATTERN = lazy_re.compile('IDS_(?P<name>[A-Z0-9_]+)\Z') |
| 78 _PRODUCT_TAG = 'android_java_product' | |
| 79 | 81 |
| 80 # This tag controls the name attribute of the generated <string> element. | 82 # Most strings are output as a <string> element. Note the double quotes |
| 81 _NAME_TAG = 'android_java_name' | 83 # around the value to preserve whitespace. |
| 84 _STRING_TEMPLATE = u'<string name="%s">"%s"</string>\n' | |
| 82 | 85 |
| 83 # The Android resource name and optional product information are placed | 86 # Some strings are output as a <plurals> element. |
| 84 # in the grd string name because grd doesn't know about Android product | |
| 85 # information. | |
| 86 # TODO(newt): Don't allow product information in mangled names, since it can now | |
| 87 # be specified using "android_java_product" in formatter_data. | |
| 88 _NAME_PATTERN = lazy_re.compile( | |
| 89 'IDS_(?P<name>[A-Z0-9_]+)(_product_(?P<product>[a-z]+))?\Z') | |
| 90 | |
| 91 | |
| 92 # In most cases we only need a name attribute and string value. | |
| 93 _SIMPLE_TEMPLATE = u'<string name="%s">%s</string>\n' | |
| 94 | |
| 95 | |
| 96 # In a few cases a product attribute is needed. | |
| 97 _PRODUCT_TEMPLATE = u'<string name="%s" product="%s">%s</string>\n' | |
| 98 | |
| 99 | |
| 100 # Some strings have a plural equivalent | |
| 101 _PLURALS_TEMPLATE = '<plurals name="%s">\n%s</plurals>\n' | 87 _PLURALS_TEMPLATE = '<plurals name="%s">\n%s</plurals>\n' |
| 102 _PLURALS_ITEM_TEMPLATE = ' <item quantity="%s">%s</item>\n' | 88 _PLURALS_ITEM_TEMPLATE = ' <item quantity="%s">%s</item>\n' |
| 103 _PLURALS_PATTERN = lazy_re.compile(r'\{[A-Z_]+,\s*plural,(?P<items>.*)\}$', flag s=re.S) | 89 _PLURALS_PATTERN = lazy_re.compile(r'\{[A-Z_]+,\s*plural,(?P<items>.*)\}$', flag s=re.S) |
| 104 _PLURALS_ITEM_PATTERN = lazy_re.compile(r'(?P<quantity>\S+)\s*\{(?P<value>.*?)\} ') | 90 _PLURALS_ITEM_PATTERN = lazy_re.compile(r'(?P<quantity>\S+)\s*\{(?P<value>.*?)\} ') |
| 105 _PLURALS_QUANTITY_MAP = { | 91 _PLURALS_QUANTITY_MAP = { |
| 106 '=0': 'zero', | 92 '=0': 'zero', |
| 107 'zero': 'zero', | 93 'zero': 'zero', |
| 108 '=1': 'one', | 94 '=1': 'one', |
| 109 'one': 'one', | 95 'one': 'one', |
| 110 '=2': 'two', | 96 '=2': 'two', |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 189 lines.append(_PLURALS_ITEM_TEMPLATE % (quantity_out, value_out)) | 175 lines.append(_PLURALS_ITEM_TEMPLATE % (quantity_out, value_out)) |
| 190 else: | 176 else: |
| 191 raise Exception('Unsupported plural quantity for android ' | 177 raise Exception('Unsupported plural quantity for android ' |
| 192 'strings.xml: %s' % quantity_in) | 178 'strings.xml: %s' % quantity_in) |
| 193 return ''.join(lines) | 179 return ''.join(lines) |
| 194 | 180 |
| 195 | 181 |
| 196 def _FormatMessage(item, lang): | 182 def _FormatMessage(item, lang): |
| 197 """Writes out a single string as a <resource/> element.""" | 183 """Writes out a single string as a <resource/> element.""" |
| 198 | 184 |
| 199 value = item.ws_at_start + item.Translate(lang) + item.ws_at_end | |
| 200 # Replace < > & with < > & to ensure we generate valid XML and | |
| 201 # replace ' " with \' \" to conform to Android's string formatting rules. | |
| 202 value = xml.sax.saxutils.escape(value, {"'": "\\'", '"': '\\"'}) | |
| 203 plurals = _FormatPluralMessage(value) | |
| 204 # Wrap the string in double quotes to preserve whitespace. | |
| 205 value = '"' + value + '"' | |
| 206 | |
| 207 mangled_name = item.GetTextualIds()[0] | 185 mangled_name = item.GetTextualIds()[0] |
| 208 match = _NAME_PATTERN.match(mangled_name) | 186 match = _NAME_PATTERN.match(mangled_name) |
| 209 if not match: | 187 if not match: |
| 210 raise Exception('Unexpected resource name: %s' % mangled_name) | 188 raise Exception('Unexpected resource name: %s' % mangled_name) |
| 211 name = match.group('name').lower() | 189 name = match.group('name').lower() |
| 212 product = match.group('product') | |
| 213 | 190 |
| 214 # Override product or name with values in formatter_data, if any. | 191 value = item.ws_at_start + item.Translate(lang) + item.ws_at_end |
| 215 product = item.formatter_data.get(_PRODUCT_TAG, product) | 192 # Replace < > & with < > & to ensure we generate valid XML and |
| 216 name = item.formatter_data.get(_NAME_TAG, name) | 193 # replace ' " with \' \" to conform to Android's string formatting rules. |
| 194 value = xml.sax.saxutils.escape(value, {"'": "\\'", '"': '\\"'}) | |
| 217 | 195 |
| 196 plurals = _FormatPluralMessage(value) | |
| 218 if plurals: | 197 if plurals: |
| 219 return _PLURALS_TEMPLATE % (name, plurals) | 198 return _PLURALS_TEMPLATE % (name, plurals) |
| 220 elif product: | |
| 221 return _PRODUCT_TEMPLATE % (name, product, value) | |
| 222 else: | 199 else: |
| 223 return _SIMPLE_TEMPLATE % (name, value) | 200 return _STRING_TEMPLATE % (name, value) |
| OLD | NEW |