| Index: grit/format/android_xml.py
|
| diff --git a/grit/format/android_xml.py b/grit/format/android_xml.py
|
| index d960bf49ddb8f009575b36f3a146cd25edbef8f8..438ea622eaa66d4d154316eaa2af6dc9e9e41611 100644
|
| --- a/grit/format/android_xml.py
|
| +++ b/grit/format/android_xml.py
|
| @@ -58,6 +58,7 @@ would generate
|
| """
|
|
|
| import os
|
| +import re
|
| import types
|
| import xml.sax.saxutils
|
|
|
| @@ -96,6 +97,24 @@ _SIMPLE_TEMPLATE = u'<string name="%s">%s</string>\n'
|
| _PRODUCT_TEMPLATE = u'<string name="%s" product="%s">%s</string>\n'
|
|
|
|
|
| +# Some strings have a plural equivalent
|
| +_PLURALS_TEMPLATE = '<plurals name="%s">\n%s</plurals>\n'
|
| +_PLURALS_ITEM_TEMPLATE = ' <item quantity="%s">%s</item>\n'
|
| +_PLURALS_PATTERN = lazy_re.compile(r'\{[A-Z_]+,\s*plural,(?P<items>.*)\}$', flags=re.S)
|
| +_PLURALS_ITEM_PATTERN = lazy_re.compile(r'(?P<quantity>\S+)\s*\{(?P<value>.*?)\}')
|
| +_PLURALS_QUANTITY_MAP = {
|
| + '=0': 'zero',
|
| + 'zero': 'zero',
|
| + '=1': 'one',
|
| + 'one': 'one',
|
| + '=2': 'two',
|
| + 'two': 'two',
|
| + 'few': 'few',
|
| + 'many': 'many',
|
| + 'other': 'other',
|
| +}
|
| +
|
| +
|
| def Format(root, lang='en', output_dir='.'):
|
| yield ('<?xml version="1.0" encoding="utf-8"?>\n'
|
| '<resources '
|
| @@ -131,6 +150,49 @@ def ShouldOutputNode(node, tagged_only):
|
| (not tagged_only or _EMIT_TAG in node.formatter_data))
|
|
|
|
|
| +def _FormatPluralMessage(message):
|
| + """Compiles ICU plural syntax to the body of an Android <plurals> element.
|
| +
|
| + 1. In a .grd file, we can write a plural string like this:
|
| +
|
| + <message name="IDS_THINGS">
|
| + {NUM_THINGS, plural,
|
| + =1 {1 thing}
|
| + other {# things}}
|
| + </message>
|
| +
|
| + 2. The Android equivalent looks like this:
|
| +
|
| + <plurals name="things">
|
| + <item quantity="one">1 thing</item>
|
| + <item quantity="other">%d things</item>
|
| + </plurals>
|
| +
|
| + This method takes the body of (1) and converts it to the body of (2).
|
| +
|
| + If the message is *not* a plural string, this function returns `None`.
|
| + If the message includes quantities without an equivalent format in Android,
|
| + it raises an exception.
|
| + """
|
| + ret = {}
|
| + plural_match = _PLURALS_PATTERN.match(message)
|
| + if not plural_match:
|
| + return None
|
| + body_in = plural_match.group('items').strip()
|
| + lines = []
|
| + for item_match in _PLURALS_ITEM_PATTERN.finditer(body_in):
|
| + quantity_in = item_match.group('quantity')
|
| + quantity_out = _PLURALS_QUANTITY_MAP.get(quantity_in)
|
| + value_in = item_match.group('value')
|
| + value_out = '"' + value_in.replace('#', '%d') + '"'
|
| + if quantity_out:
|
| + lines.append(_PLURALS_ITEM_TEMPLATE % (quantity_out, value_out))
|
| + else:
|
| + raise Exception('Unsupported plural quantity for android '
|
| + 'strings.xml: %s' % quantity_in)
|
| + return ''.join(lines)
|
| +
|
| +
|
| def _FormatMessage(item, lang):
|
| """Writes out a single string as a <resource/> element."""
|
|
|
| @@ -138,6 +200,7 @@ def _FormatMessage(item, lang):
|
| # Replace < > & with < > & to ensure we generate valid XML and
|
| # replace ' " with \' \" to conform to Android's string formatting rules.
|
| value = xml.sax.saxutils.escape(value, {"'": "\\'", '"': '\\"'})
|
| + plurals = _FormatPluralMessage(value)
|
| # Wrap the string in double quotes to preserve whitespace.
|
| value = '"' + value + '"'
|
|
|
| @@ -152,7 +215,9 @@ def _FormatMessage(item, lang):
|
| product = item.formatter_data.get(_PRODUCT_TAG, product)
|
| name = item.formatter_data.get(_NAME_TAG, name)
|
|
|
| - if product:
|
| + if plurals:
|
| + return _PLURALS_TEMPLATE % (name, plurals)
|
| + elif product:
|
| return _PRODUCT_TEMPLATE % (name, product, value)
|
| else:
|
| return _SIMPLE_TEMPLATE % (name, value)
|
|
|