Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(488)

Side by Side Diff: grit/format/android_xml.py

Issue 1258833004: Compile plural strings to android <plurals> elem (Closed) Base URL: https://chromium.googlesource.com/external/grit-i18n.git@master
Patch Set: Handled comments Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 <message name="IDS_FOO_DEFAULT" formatter_data="android_java_product=default 51 <message name="IDS_FOO_DEFAULT" formatter_data="android_java_product=default
52 android_java_name=foo">has card</message> 52 android_java_name=foo">has card</message>
53 53
54 would generate 54 would generate
55 55
56 <string name="foo" product="nosdcard">"no card"</string> 56 <string name="foo" product="nosdcard">"no card"</string>
57 <string name="foo" product="default">"has card"</string> 57 <string name="foo" product="default">"has card"</string>
58 """ 58 """
59 59
60 import os 60 import os
61 import re
61 import types 62 import types
62 import xml.sax.saxutils 63 import xml.sax.saxutils
63 64
64 from grit import lazy_re 65 from grit import lazy_re
65 from grit.node import message 66 from grit.node import message
66 67
67 68
68 # When this environmental variable has value "true", only tagged messages will 69 # When this environmental variable has value "true", only tagged messages will
69 # be outputted. 70 # be outputted.
70 _TAGGED_ONLY_ENV_VAR = 'ANDROID_JAVA_TAGGED_ONLY' 71 _TAGGED_ONLY_ENV_VAR = 'ANDROID_JAVA_TAGGED_ONLY'
(...skipping 18 matching lines...) Expand all
89 90
90 91
91 # In most cases we only need a name attribute and string value. 92 # In most cases we only need a name attribute and string value.
92 _SIMPLE_TEMPLATE = u'<string name="%s">%s</string>\n' 93 _SIMPLE_TEMPLATE = u'<string name="%s">%s</string>\n'
93 94
94 95
95 # In a few cases a product attribute is needed. 96 # In a few cases a product attribute is needed.
96 _PRODUCT_TEMPLATE = u'<string name="%s" product="%s">%s</string>\n' 97 _PRODUCT_TEMPLATE = u'<string name="%s" product="%s">%s</string>\n'
97 98
98 99
100 # Some strings have a plural equivalent
101 _PLURALS_TEMPLATE = '<plurals name="%s">\n%s</plurals>\n'
102 _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)
104 _PLURALS_ITEM_PATTERN = lazy_re.compile(r'(?P<quantity>\S+)\s*\{(?P<value>.*?)\} ')
105
106
99 def Format(root, lang='en', output_dir='.'): 107 def Format(root, lang='en', output_dir='.'):
100 yield ('<?xml version="1.0" encoding="utf-8"?>\n' 108 yield ('<?xml version="1.0" encoding="utf-8"?>\n'
101 '<resources ' 109 '<resources '
102 'xmlns:android="http://schemas.android.com/apk/res/android">\n') 110 'xmlns:android="http://schemas.android.com/apk/res/android">\n')
103 111
104 tagged_only = _TAGGED_ONLY_DEFAULT 112 tagged_only = _TAGGED_ONLY_DEFAULT
105 if _TAGGED_ONLY_ENV_VAR in os.environ: 113 if _TAGGED_ONLY_ENV_VAR in os.environ:
106 tagged_only = os.environ[_TAGGED_ONLY_ENV_VAR].lower() 114 tagged_only = os.environ[_TAGGED_ONLY_ENV_VAR].lower()
107 if tagged_only == 'true': 115 if tagged_only == 'true':
108 tagged_only = True 116 tagged_only = True
(...skipping 15 matching lines...) Expand all
124 """Returns true if node should be outputted. 132 """Returns true if node should be outputted.
125 133
126 Args: 134 Args:
127 node: a Node from the grd dom 135 node: a Node from the grd dom
128 tagged_only: true, if only tagged messages should be outputted 136 tagged_only: true, if only tagged messages should be outputted
129 """ 137 """
130 return (isinstance(node, message.MessageNode) and 138 return (isinstance(node, message.MessageNode) and
131 (not tagged_only or _EMIT_TAG in node.formatter_data)) 139 (not tagged_only or _EMIT_TAG in node.formatter_data))
132 140
133 141
142 def _FormatPluralMessage(message):
143 """Compile ICU plural syntax to the body of an Android <plurals> element.
newt (away) 2015/08/04 03:14:26 nit: "Compiles"
conleyo 2015/08/04 16:53:02 Done.
144
145 1. In a .grd file, we can write a plural string like this:
146
147 <message name="IDS_THINGS">
148 {NUM_THINGS, plural,
149 =1 {1 thing}
150 other {# things}}
151 </message>
152
153 2. The Android equivalent looks like this:
154
155 <plurals name="things">
156 <item quantity="one">1 thing</item>
157 <item quantity="other">%d things</item>
158 </plurals>
159
160 This method takes the body of (1) and converts it to the body of (2).
161
162 If the message is *not* a plural string, this function returns `None`.
163 If the message includes quantities without an equivalent format in Android,
164 it raises an exception.
165 """
166 ret = {}
167 plural_match = _PLURALS_PATTERN.match(message)
168 if not plural_match:
169 return None
170 body_in = plural_match.group('items').strip()
171 body_out = u''
newt (away) 2015/08/04 03:14:26 A better idiom for concatenating strings in python
conleyo 2015/08/04 16:53:02 Done.
172 for item_match in _PLURALS_ITEM_PATTERN.finditer(body_in):
173 quantity = item_match.group('quantity')
174 value = item_match.group('value').replace('#', '%d')
175 if quantity == '=0':
176 body_out += _PLURALS_ITEM_TEMPLATE % ('zero', value)
177 elif quantity == '=1':
178 body_out += _PLURALS_ITEM_TEMPLATE % ('one', value)
179 elif quantity == 'other':
180 body_out += _PLURALS_ITEM_TEMPLATE % ('other', value)
181 else:
newt (away) 2015/08/04 03:14:26 Why not handle "=2", "few" and "many"?
conleyo 2015/08/04 16:53:02 Done.
182 raise Exception('Unsupported plural quantity for android '
183 'strings.xml: %s' % quantity)
184 return body_out
185
186
134 def _FormatMessage(item, lang): 187 def _FormatMessage(item, lang):
135 """Writes out a single string as a <resource/> element.""" 188 """Writes out a single string as a <resource/> element."""
136 189
137 value = item.ws_at_start + item.Translate(lang) + item.ws_at_end 190 value = item.ws_at_start + item.Translate(lang) + item.ws_at_end
138 # Replace < > & with &lt; &gt; &amp; to ensure we generate valid XML and 191 # Replace < > & with &lt; &gt; &amp; to ensure we generate valid XML and
139 # replace ' " with \' \" to conform to Android's string formatting rules. 192 # replace ' " with \' \" to conform to Android's string formatting rules.
140 value = xml.sax.saxutils.escape(value, {"'": "\\'", '"': '\\"'}) 193 value = xml.sax.saxutils.escape(value, {"'": "\\'", '"': '\\"'})
194 plurals = _FormatPluralMessage(value)
141 # Wrap the string in double quotes to preserve whitespace. 195 # Wrap the string in double quotes to preserve whitespace.
142 value = '"' + value + '"' 196 value = '"' + value + '"'
143 197
144 mangled_name = item.GetTextualIds()[0] 198 mangled_name = item.GetTextualIds()[0]
145 match = _NAME_PATTERN.match(mangled_name) 199 match = _NAME_PATTERN.match(mangled_name)
146 if not match: 200 if not match:
147 raise Exception('Unexpected resource name: %s' % mangled_name) 201 raise Exception('Unexpected resource name: %s' % mangled_name)
148 name = match.group('name').lower() 202 name = match.group('name').lower()
149 product = match.group('product') 203 product = match.group('product')
150 204
151 # Override product or name with values in formatter_data, if any. 205 # Override product or name with values in formatter_data, if any.
152 product = item.formatter_data.get(_PRODUCT_TAG, product) 206 product = item.formatter_data.get(_PRODUCT_TAG, product)
153 name = item.formatter_data.get(_NAME_TAG, name) 207 name = item.formatter_data.get(_NAME_TAG, name)
154 208
155 if product: 209 if plurals:
210 return _PLURALS_TEMPLATE % (name, plurals)
211 elif product:
156 return _PRODUCT_TEMPLATE % (name, product, value) 212 return _PRODUCT_TEMPLATE % (name, product, value)
157 else: 213 else:
158 return _SIMPLE_TEMPLATE % (name, value) 214 return _SIMPLE_TEMPLATE % (name, value)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698