Commits

Seraphim Mellos committed 076e039

More work on Qt files escapes/unescapes.

Comments (0)

Files changed (3)

transifex/resources/formats/qt.py

         It just does a search and replace inside `text` and replaces all
         occurrences of `original` with `replacement`.
         """
-        return re.sub(re.escape(original), xml_escape(replacement), text)
-
+        return re.sub(re.escape(original), xml_escape(replacement,
+            {"'": "'", '"': '"'}), text)
     def _post_compile(self, *args, **kwargs):
         """
         """
                 message.setAttribute('numerus', 'yes')
                 for key in plural_keys.keys():
                     e = doc.createElement("numerusform")
-                    e.appendChild(doc.createTextNode(plural_keys[key]))
+                    e.appendChild(doc.createTextNode(xml_escape(plural_keys[key],
+                        {"'": "'", '"': '"'})))
                     translation.appendChild(e)
 
-        self.compiled_template = doc.toxml()
+        template_text = doc.toxml()
+        esc_template_text = re.sub("'(?=(?:(?!>).)*<\/source>)",
+            r"&apos;", template_text)
+        esc_template_text = re.sub("'(?=(?:(?!>).)*<\/translation>)",
+            r"&apos;", esc_template_text)
+        self.compiled_template = esc_template_text
 
     @need_language
     @need_file
                                 context_name]).encode('utf-8')).hexdigest()})))
 
             if is_source:
-                self.template = str(doc.toxml().encode('utf-8'))
+                # Ugly fix to revert single quotes back to the escaped version
+                template_text = doc.toxml().encode('utf-8')
+                esc_template_text = re.sub("'(?=(?:(?!>).)*<\/source>)",
+                    r"&apos;", template_text)
+                self.template = str(esc_template_text)
 
             self.suggestions = suggestions
             self.stringset=stringset

transifex/resources/migrations/0008_escape_ts_special_chars.py

             template = Template.objects.get(resource=r)
             for s in SourceEntity.objects.filter(resource=r):
                 old_hash = s.string_hash
-                s.string = unescape(s.string)
+                s.string = unescape(s.string, {"&apos;": "'", "&quot;": '"'})
                 s.save()
                 for t in Translation.objects.filter(source_entity=s):
-                    t.string = unescape(t.string)
+                    t.string = unescape(t.string,
+                        {"&apos;": "'", "&quot;":'"'})
                     t.save()
 
 
             template = Template.objects.get(resource=r)
             for s in SourceEntity.objects.filter(resource=r):
                 old_hash = s.string_hash
-                s.string = escape(s.string)
+                s.string = escape(s.string,  {"'": "&apos;", '"': '&quot;'})
                 s.save()
                 for t in Translation.objects.filter(source_entity=s):
-                    t.string = escape(t.string)
+                    t.string = escape(t.string,  {"'": "&apos;", '"': '&quot;'})
                     t.save()
 
                 new_hash = s.string_hash

transifex/resources/tests/lib/qt/__init__.py

         # Make sure one string is now untranslated
         self.assertEqual(Translation.objects.filter(source_entity__in=
             SourceEntity.objects.filter(resource=self.resource).values('id')).count(), 4)
+
+    def test_special_characters(self):
+        """Test that escaping/unescaping happens correctly"""
+
+        unescaped_string = "& < > \" '"
+        escaped_string = "&amp; &lt; &gt; &quot; &apos;"
+
+        # Empty our resource
+        SourceEntity.objects.filter(resource=self.resource).delete()
+
+        # Make sure that we have no suggestions to begin with
+        self.assertEqual(Suggestion.objects.filter(source_entity__in=
+            SourceEntity.objects.filter(resource=self.resource).values('id')).count(), 0)
+
+        # Import file with two senteces
+        handler = LinguistHandler('%s/special_characters/en.ts' %
+            os.path.split(__file__)[0])
+        handler.bind_resource(self.resource)
+        handler.set_language(self.resource.source_language)
+        handler.parse_file(is_source=True)
+        handler.save2db(is_source=True)
+
+        # Make sure that we have all sources in the db
+        self.assertEqual(SourceEntity.objects.filter(
+            resource=self.resource).values('id').count(), 1)
+
+        # Make sure that we have all translations in the db
+        self.assertEqual(Translation.objects.filter(source_entity__in=
+            SourceEntity.objects.filter(resource=self.resource).values('id')).count(),1)
+
+        source = SourceEntity.objects.filter(resource=self.resource)[0]
+        translation = Translation.objects.get(source_entity=source)
+
+        self.assertEqual(source.string, unescaped_string)
+        self.assertEqual(translation.string, unescaped_string)
+
+        handler.compile()
+
+        self.assertTrue(escaped_string in handler.compiled_template)
+        self.assertFalse(unescaped_string in handler.compiled_template)
+
+