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

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: 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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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 &lt; &gt; &amp; to ensure we generate valid XML and 172 # Replace < > & with &lt; &gt; &amp; 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)
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