Repository: python-babel/babel
Pull request #392 (2016-04-18 16:34:56)

jslexer.py: Change jsx_tag regex
A less greedy jsx_tag regex. Can handle both translatable strings as
children or as props to a component.

Also made a test case with the kind of JSX syntax variants we're using.


Patch:
diff --git a/babel/messages/jslexer.py b/babel/messages/jslexer.py
index aed39f3..665a86f 100644
--- a/babel/messages/jslexer.py
+++ b/babel/messages/jslexer.py
@@ -45,7 +45,7 @@ _rules = [
         ([eE][-+]?\d+)? |
         (0x[a-fA-F0-9]+)
     )''')),
-    ('jsx_tag', re.compile(r'<(?:/?)\w+.+?>', re.I)),  # May be mangled in `get_rules`
+    ('jsx_tag', re.compile(r'</?[^> ]+', re.I)),  # May be mangled in `get_rules`
     ('operator', re.compile(r'(%s)' % '|'.join(map(re.escape, operators)))),
     ('template_string', re.compile(r'''`(?:[^`\\]*(?:\\.[^`\\]*)*)`''', re.UNICODE)),
     ('string', re.compile(r'''(?xs)(


Test patch:
diff --git a/tests/messages/test_jslexer.py b/tests/messages/test_jslexer.py
index 84221a1..e125fec 100644
--- a/tests/messages/test_jslexer.py
+++ b/tests/messages/test_jslexer.py
@@ -32,3 +32,63 @@ def test_template_string():
         ('name', 'gettext', 1),
         ('template_string', '`foo"bar"p`', 1)
     ]
+
+
+def test_jsx():
+    assert list(jslexer.tokenize("""
+         <option value="val1">{ i18n._('String1') }</option>
+         <option value="val2">{ i18n._('String 2') }</option>
+         <option value="val3">{ i18n._('String 3') }</option>
+         <component value={i18n._('String 4')} />
+    """, jsx=True)) == [
+         ('jsx_tag', '<option', 2),
+         ('name', 'value', 2),
+         ('operator', '=', 2),
+         ('string', '"val1"', 2),
+         ('operator', '>', 2),
+         ('operator', '{', 2),
+         ('name', 'i18n._', 2),
+         ('operator', '(', 2),
+         ('string', "'String1'", 2),
+         ('operator', ')', 2),
+         ('operator', '}', 2),
+         ('jsx_tag', '</option', 2),
+         ('operator', '>', 2),
+         ('jsx_tag', '<option', 3),
+         ('name', 'value', 3),
+         ('operator', '=', 3),
+         ('string', '"val2"', 3),
+         ('operator', '>', 3),
+         ('operator', '{', 3),
+         ('name', 'i18n._', 3),
+         ('operator', '(', 3),
+         ('string', "'String 2'", 3),
+         ('operator', ')', 3),
+         ('operator', '}', 3),
+         ('jsx_tag', '</option', 3),
+         ('operator', '>', 3),
+         ('jsx_tag', '<option', 4),
+         ('name', 'value', 4),
+         ('operator', '=', 4),
+         ('string', '"val3"', 4),
+         ('operator', '>', 4),
+         ('operator', '{', 4),
+         ('name', 'i18n._', 4),
+         ('operator', '(', 4),
+         ('string', "'String 3'", 4),
+         ('operator', ')', 4),
+         ('operator', '}', 4),
+         ('jsx_tag', '</option', 4),
+         ('operator', '>', 4),
+         ('jsx_tag', '<component', 5),
+         ('name', 'value', 5),
+         ('operator', '=', 5),
+         ('operator', '{', 5),
+         ('name', 'i18n._', 5),
+         ('operator', '(', 5),
+         ('string', "'String 4'", 5),
+         ('operator', ')', 5),
+         ('operator', '}', 5),
+         ('operator', '/', 5),
+         ('operator', '>', 5)
+     ]