Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiline strings #9

Closed
wants to merge 13 commits into from
114 changes: 106 additions & 8 deletions babel_godot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@


_godot_node = re.compile(r'^\[node name="([^"]+)" (?:type="([^"]+)")?')
_godot_property_str = re.compile(r'^([A-Za-z0-9_]+)\s*=\s*(".+)$')
_godot_property_str = re.compile(r'^([A-Za-z0-9_]+)\s*=\s*([\[|"].+)$')
_godot_escaped_tr = re.compile(r'^.*[^A-Za-z0-9_]tr\(\\"([^\\"]+)\\"\)?')


def _godot_unquote(string):
Expand All @@ -30,6 +31,43 @@ def _godot_unquote(string):
result.append(c)
return ''.join(result)

def _assemble_multiline_string(line, multiline):
to_yield = []

if '", "' in line:
# Multiline string ends within an array of strings
line_parts = line.split('", "')
multiline['value'] += line_parts[0]

value = _godot_unquote('"' + multiline['value'] + '"')
if value is not None:
to_yield.append([multiline['keyword'], value])

# Take care of intermediate strings in array (not multiline)
for line_part in line_parts[1:-1]:
value = _godot_unquote('"' + line_part + '"')
if value is not None:
to_yield.append([multiline['keyword'], value])

# Continue with the last array item normally
multiline['value'] = ''
line = line_parts[-1]

if not line.endswith('"\n') and not line.endswith(']\n'):
# Continuation of multiline string
multiline['value'] += line
else:
# Multiline string ends
multiline['value'] += line.strip('"]\n')

value = _godot_unquote('"' + multiline['value'] + '"')
if value is not None:
to_yield.append([multiline['keyword'], value])

multiline['keyword'] = ''
multiline['value'] = ''

return to_yield

def extract_godot_scene(fileobj, keywords, comment_tags, options):
"""Extract messages from Godot scene files (.tscn).
Expand All @@ -48,6 +86,10 @@ def extract_godot_scene(fileobj, keywords, comment_tags, options):

current_node_type = None

multiline = {'keyword': '', 'value': ''}

look_for_builtin_tr = 'tr' in keywords

properties_to_translate = {}
for keyword in keywords:
if '/' in keyword:
Expand All @@ -63,6 +105,15 @@ def check_translate_property(property):

for lineno, line in enumerate(fileobj, start=1):
line = line.decode(encoding)

# Handle multiline strings
if multiline['keyword']:
to_yield = _assemble_multiline_string(line, multiline)
for item in to_yield:
yield (lineno, item[0], [item[1]], [])

continue

match = _godot_node.match(line)
if match:
# Store which kind of node we're in
Expand All @@ -82,10 +133,30 @@ def check_translate_property(property):
value = match.group(2)
keyword = check_translate_property(property)
if keyword:
value = _godot_unquote(value)
if value is not None:
yield (lineno, keyword, [value], [])

# Beginning of multiline string
if not value.endswith('"') and not value.endswith(']'):
multiline['keyword'] = keyword
multiline['value'] = value.strip('[ "') + '\n'
continue

# Handle array of strings
if value.startswith('[ "'):
values = value.strip('[ "]').split('", "')
for value in values:
value = _godot_unquote('"' + value + '"')
if value is not None:
yield (lineno, keyword, [value], [])
else:
value = _godot_unquote(value)
if value is not None:
yield (lineno, keyword, [value], [])
elif look_for_builtin_tr:
# Handle Godot's tr() for built-in scripts
match = _godot_escaped_tr.match(line)
if match:
value = _godot_unquote('"' + match.group(1) + '"')
if value is not None:
yield (lineno, keyword, [value], [])

def extract_godot_resource(fileobj, keywords, comment_tags, options):
"""Extract messages from Godot resource files (.res, .tres).
Expand All @@ -102,10 +173,15 @@ def extract_godot_resource(fileobj, keywords, comment_tags, options):
"""
encoding = options.get('encoding', 'utf-8')

multiline = {'keyword': '', 'value': ''}

properties_to_translate = {}
for keyword in keywords:
if keyword.startswith('Resource/'):
properties_to_translate[keyword[9:]] = keyword
else:
# Without this else-case, any '<name>' properties (not starting with 'Resource/') would be ignored
properties_to_translate[keyword] = keyword

def check_translate_property(property):
return properties_to_translate.get(property)
Expand All @@ -115,12 +191,34 @@ def check_translate_property(property):
if line.startswith('['):
continue

# Handle multiline strings
if multiline['keyword']:
to_yield = _assemble_multiline_string(line, multiline)
for item in to_yield:
yield (lineno, item[0], [item[1]], [])

continue

match = _godot_property_str.match(line)
if match:
property = match.group(1)
value = match.group(2)
keyword = check_translate_property(property)
if keyword:
value = _godot_unquote(value)
if value is not None:
yield (lineno, keyword, [value], [])
# Beginning of multiline string
if not value.endswith('"') and not value.endswith(']'):
multiline['keyword'] = keyword
multiline['value'] = value.strip('[ "') + '\n'
continue

# Handle array of strings
if value.startswith('[ "'):
values = value.strip('[ "]').split('", "')
for value in values:
value = _godot_unquote('"' + value + '"')
if value is not None:
yield (lineno, keyword, [value], [])
else:
value = _godot_unquote(value)
if value is not None:
yield (lineno, keyword, [value], [])