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 |