Skip to content

Commit

Permalink
Merge pull request #326 from mathjazz/bug-1193860
Browse files Browse the repository at this point in the history
Fix bug 1193860: escape quotes in some DTD files
  • Loading branch information
mathjazz committed Jan 14, 2016
2 parents 9c53c7c + 8f2f091 commit ef2925b
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 2 deletions.
33 changes: 31 additions & 2 deletions pontoon/sync/formats/silme.py
Expand Up @@ -4,10 +4,11 @@
"""
import codecs
import os
import silme

from collections import OrderedDict
from copy import copy

import silme
from silme.format.dtd import FormatParser as DTDParser
from silme.format.ini import FormatParser as IniParser
from silme.format.inc import FormatParser as IncParser
Expand Down Expand Up @@ -78,6 +79,9 @@ def __init__(self, parser, path, source_resource=None):
self.source_resource = source_resource
self.entities = OrderedDict() # Preserve entity order.

# Bug 1193860: unescape quotes in some files
self.escape_quotes_on = 'mobile/android/base' in path and parser is DTDParser

# Copy entities from the source_resource if it's available.
if source_resource:
for key, entity in source_resource.entities.items():
Expand All @@ -103,6 +107,10 @@ def __init__(self, parser, path, source_resource=None):
current_order = 0
for obj in self.structure:
if isinstance(obj, silme.core.entity.Entity):

if self.escape_quotes_on:
obj.value = self.unescape_quotes(obj.value)

entity = SilmeEntity(obj, comments, current_order)
self.entities[entity.key] = entity
current_order += 1
Expand All @@ -118,6 +126,22 @@ def __init__(self, parser, path, source_resource=None):
def translations(self):
return self.entities.values()

def escape_quotes(self, value):
"""
DTD files can use single or double quotes for identifying strings,
so " and ' are the safe bet that will work in both cases.
"""
value = value.replace('"', '\\"')
value = value.replace("'", '\\'')
return value

def unescape_quotes(self, value):
value = value.replace('\\"', '"')
value = value.replace('\\"', '"')
value = value.replace('\\'', "'")
value = value.replace("\\'", "'")
return value

def save(self, locale):
"""
Load the source resource, modify it with changes made to this
Expand All @@ -144,7 +168,12 @@ def save(self, locale):

translated_entity = self.entities.get(key)
if translated_entity and None in translated_entity.strings:
new_structure.modify_entity(key, translated_entity.strings[None])
translation = translated_entity.strings[None]

if self.escape_quotes_on:
translation = self.escape_quotes(translation)

new_structure.modify_entity(key, translation)
else:
# Remove untranslated entity and following newline
pos = new_structure.entity_pos(key)
Expand Down
41 changes: 41 additions & 0 deletions pontoon/sync/tests/formats/test_silme.py
Expand Up @@ -185,6 +185,47 @@ def test_save_translation_identical(self):

self.run_save_translation_identical(source_string, input_string, expected_string)

def test_quotes(self):
input_strings = dedent("""
<!ENTITY SingleQuote "\'">
<!ENTITY SingleQuoteEntity "\&apos;">
<!ENTITY DoubleQuote '\"'>
<!ENTITY DoubleQuoteEntity "\&quot;">
""")

# Make sure path contains 'mobile/android/base'
dirname = os.path.join(tempfile.mkdtemp(), 'mobile', 'android', 'base')
os.makedirs(dirname)

fd, path = tempfile.mkstemp(dir=dirname)
with os.fdopen(fd, 'w') as f:
f.write(input_strings)

resource = self.parse(path)

# Unescape quotes when parsing
assert_attributes_equal(resource.translations[0], strings={None: "'"})
assert_attributes_equal(resource.translations[1], strings={None: "'"})
assert_attributes_equal(resource.translations[2], strings={None: '"'})
assert_attributes_equal(resource.translations[3], strings={None: '"'})

# Escape quotes when saving
translated_resource = silme.SilmeResource(
DTDParser, path, source_resource=resource
)
translated_resource.translations[0].strings[None] = "Single Quote '"
translated_resource.translations[1].strings[None] = 'Double Quote "'

translated_resource.save(self.locale)

expected_string = dedent("""
<!ENTITY SingleQuote "Single Quote \&apos;">
<!ENTITY SingleQuoteEntity "Double Quote \&quot;">
<!ENTITY DoubleQuote '\&quot;'>
<!ENTITY DoubleQuoteEntity "\&quot;">
""")
self.assert_file_content(path, expected_string)


BASE_PROPERTIES_FILE = """
# Sample comment
Expand Down

0 comments on commit ef2925b

Please sign in to comment.