We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
csv2po new line
Hi there, i have CSV with:

```csv
"yellow pencil","żółty\nołówek"
"photo description","opis zdjęcia"
```

And converted with csv2po:

```po
msgid "yellow pencil"
msgstr "żółtynołówek"

msgid "photo description"
msgstr "opis zdjęcia"
```

How to convert with save format "\n", script delete \ from string.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `translate/storage/csvl10n.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright 2002-2006 Zuza Software Foundation
4 #
5 # This file is part of translate.
6 #
7 # translate is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11 #
12 # translate is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, see <http://www.gnu.org/licenses/>.
19 
20 """classes that hold units of comma-separated values (.csv) files (csvunit)
21 or entire files (csvfile) for use with localisation
22 """
23 
24 from __future__ import unicode_literals
25 
26 import six
27 if six.PY2:
28     from backports import csv
29 else:
30     import csv
31 
32 from translate.storage import base
33 
34 
35 class DefaultDialect(csv.excel):
36     skipinitialspace = True
37     quoting = csv.QUOTE_ALL
38     escapechar = '\\'
39 
40 
41 csv.register_dialect('default', DefaultDialect)
42 
43 
44 @six.python_2_unicode_compatible
45 class csvunit(base.TranslationUnit):
46     spreadsheetescapes = [("+", "\\+"), ("-", "\\-"), ("=", "\\="), ("'", "\\'")]
47 
48     def __init__(self, source=None):
49         super(csvunit, self).__init__(source)
50         self.location = ""
51         self.source = source or ""
52         self.target = ""
53         self.id = ""
54         self.fuzzy = 'False'
55         self.developer_comments = ""
56         self.translator_comments = ""
57         self.context = ""
58 
59     def getid(self):
60         if self.id:
61             return self.id
62 
63         result = self.source
64         context = self.context
65         if context:
66             result = u"%s\04%s" % (context, result)
67 
68         return result
69 
70     def setid(self, value):
71         self.id = value
72 
73     def getlocations(self):
74         #FIXME: do we need to support more than one location
75         return [self.location]
76 
77     def addlocation(self, location):
78         self.location = location
79 
80     def getcontext(self):
81         return self.context
82 
83     def setcontext(self, value):
84         self.context = value
85 
86     def getnotes(self, origin=None):
87         if origin is None:
88             result = self.translator_comments
89             if self.developer_comments:
90                 if result:
91                     result += '\n' + self.developer_comments
92                 else:
93                     result = self.developer_comments
94             return result
95         elif origin == "translator":
96             return self.translator_comments
97         elif origin in ('programmer', 'developer', 'source code'):
98             return self.developer_comments
99         else:
100             raise ValueError("Comment type not valid")
101 
102     def addnote(self, text, origin=None, position="append"):
103         if origin in ('programmer', 'developer', 'source code'):
104             if position == 'append' and self.developer_comments:
105                 self.developer_comments += '\n' + text
106             elif position == 'prepend' and self.developer_comments:
107                 self.developer_comments = text + '\n' + self.developer_comments
108             else:
109                 self.developer_comments = text
110         else:
111             if position == 'append' and self.translator_comments:
112                 self.translator_comments += '\n' + text
113             elif position == 'prepend' and self.translator_comments:
114                 self.translator_comments = self.translator_comments + '\n' + text
115             else:
116                 self.translator_comments = text
117 
118     def removenotes(self):
119         self.translator_comments = u''
120 
121     def isfuzzy(self):
122         if self.fuzzy.lower() in ('1', 'x', 'true', 'yes', 'fuzzy'):
123             return True
124         return False
125 
126     def markfuzzy(self, value=True):
127         if value:
128             self.fuzzy = 'True'
129         else:
130             self.fuzzy = 'False'
131 
132     def match_header(self):
133         """see if unit might be a header"""
134         some_value = False
135         for key, value in six.iteritems(self.todict()):
136             if value:
137                 some_value = True
138             if key.lower() != 'fuzzy' and value and key.lower() != value.lower():
139                 return False
140         return some_value
141 
142     def add_spreadsheet_escapes(self, source, target):
143         """add common spreadsheet escapes to two strings"""
144         for unescaped, escaped in self.spreadsheetescapes:
145             if source.startswith(unescaped):
146                 source = source.replace(unescaped, escaped, 1)
147             if target.startswith(unescaped):
148                 target = target.replace(unescaped, escaped, 1)
149         return source, target
150 
151     def remove_spreadsheet_escapes(self, source, target):
152         """remove common spreadsheet escapes from two strings"""
153         for unescaped, escaped in self.spreadsheetescapes:
154             if source.startswith(escaped):
155                 source = source.replace(escaped, unescaped, 1)
156             if target.startswith(escaped):
157                 target = target.replace(escaped, unescaped, 1)
158         return source, target
159 
160     def fromdict(self, cedict, encoding='utf-8'):
161         for key, value in six.iteritems(cedict):
162             rkey = fieldname_map.get(key, key)
163             if value is None or key is None or key == EXTRA_KEY:
164                 continue
165             if rkey == "id":
166                 self.id = value
167             elif rkey == "source":
168                 self.source = value
169             elif rkey == "target":
170                 self.target = value
171             elif rkey == "location":
172                 self.location = value
173             elif rkey == "fuzzy":
174                 self.fuzzy = value
175             elif rkey == "context":
176                 self.context = value
177             elif rkey == "translator_comments":
178                 self.translator_comments = value
179             elif rkey == "developer_comments":
180                 self.developer_comments = value
181 
182         #self.source, self.target = self.remove_spreadsheet_escapes(self.source, self.target)
183 
184     def todict(self, **kwargs):
185         #FIXME: use apis?
186         #source, target = self.add_spreadsheet_escapes(self.source, self.target)
187         source = self.source
188         target = self.target
189         output = {
190             'location': self.location,
191             'source': source,
192             'target': target,
193             'id': self.id,
194             'fuzzy': str(self.fuzzy),
195             'context': self.context,
196             'translator_comments': self.translator_comments,
197             'developer_comments': self.developer_comments,
198         }
199 
200         return output
201 
202     def __str__(self):
203         return str(self.todict())
204 
205 
206 fieldname_map = {
207     'original': 'source',
208     'untranslated': 'source',
209     'translated': 'target',
210     'translation': 'target',
211     'identified': 'id',
212     'key': 'id',
213     'label': 'id',
214     'translator comments': 'translator_comments',
215     'notes': 'translator_comments',
216     'developer comments': 'developer_comments',
217     'state': 'fuzzy',
218 }
219 
220 
221 EXTRA_KEY = '__CSVL10N__EXTRA__'
222 
223 
224 def try_dialects(inputfile, fieldnames, dialect):
225     #FIXME: does it verify at all if we don't actually step through the file?
226     try:
227         inputfile.seek(0)
228         reader = csv.DictReader(inputfile, fieldnames=fieldnames, dialect=dialect, restkey=EXTRA_KEY)
229     except csv.Error:
230         try:
231             inputfile.seek(0)
232             reader = csv.DictReader(inputfile, fieldnames=fieldnames, dialect='default', restkey=EXTRA_KEY)
233         except csv.Error:
234             inputfile.seek(0)
235             reader = csv.DictReader(inputfile, fieldnames=fieldnames, dialect='excel', restkey=EXTRA_KEY)
236     return reader
237 
238 
239 def valid_fieldnames(fieldnames):
240     """Check if fieldnames are valid, that is at least one field is identified
241     as the source.
242     """
243     for fieldname in fieldnames:
244         if fieldname == 'source':
245             return True
246         elif fieldname in fieldname_map and fieldname_map[fieldname] == 'source':
247             return True
248     return False
249 
250 
251 def detect_header(sample, dialect, fieldnames):
252     """Test if file has a header or not, also returns number of columns in first row"""
253     inputfile = csv.StringIO(sample)
254     try:
255         reader = csv.reader(inputfile, dialect)
256     except csv.Error:
257         try:
258             inputfile.seek(0)
259             reader = csv.reader(inputfile, 'default')
260         except csv.Error:
261             inputfile.seek(0)
262             reader = csv.reader(inputfile, 'excel')
263 
264     header = next(reader)
265     columncount = max(len(header), 3)
266     if valid_fieldnames(header):
267         return header
268     return fieldnames[:columncount]
269 
270 
271 class csvfile(base.TranslationStore):
272     """This class represents a .csv file with various lines.  The default
273     format contains three columns: location, source, target
274     """
275 
276     UnitClass = csvunit
277     Name = "Comma Separated Value"
278     Mimetypes = ['text/comma-separated-values', 'text/csv']
279     Extensions = ["csv"]
280 
281     def __init__(self, inputfile=None, fieldnames=None, encoding='auto'):
282         super(csvfile, self).__init__(encoding=encoding)
283         if not fieldnames:
284             self.fieldnames = ['location', 'source', 'target', 'id', 'fuzzy', 'context', 'translator_comments', 'developer_comments']
285         else:
286             self.fieldnames = fieldnames
287         self.filename = getattr(inputfile, 'name', '')
288         self.dialect = 'default'
289         if inputfile is not None:
290             csvsrc = inputfile.read()
291             inputfile.close()
292             self.parse(csvsrc)
293 
294     def parse(self, csvsrc):
295         text, encoding = self.detect_encoding(csvsrc, default_encodings=['utf-8', 'utf-16'])
296         #FIXME: raise parse error if encoding detection fails?
297         self.encoding = encoding or 'utf-8'
298 
299         sniffer = csv.Sniffer()
300         sample = text[:1024]
301 
302         try:
303             self.dialect = sniffer.sniff(sample)
304             if not self.dialect.escapechar:
305                 self.dialect.escapechar = '\\'
306                 if self.dialect.quoting == csv.QUOTE_MINIMAL:
307                     #HACKISH: most probably a default, not real detection
308                     self.dialect.quoting = csv.QUOTE_ALL
309                     self.dialect.doublequote = True
310         except csv.Error:
311             self.dialect = 'default'
312 
313         try:
314             fieldnames = detect_header(sample, self.dialect, self.fieldnames)
315             self.fieldnames = fieldnames
316         except csv.Error:
317             pass
318 
319         inputfile = csv.StringIO(text)
320         reader = try_dialects(inputfile, self.fieldnames, self.dialect)
321 
322         first_row = True
323         for row in reader:
324             newce = self.UnitClass()
325             newce.fromdict(row)
326             if not first_row or not newce.match_header():
327                 self.addunit(newce)
328             first_row = False
329 
330     def serialize(self, out):
331         """Write to file"""
332         source = self.getoutput()
333         if isinstance(source, six.text_type):
334             # Python 3
335             out.write(source.encode(self.encoding))
336         else:
337             out.write(source)
338 
339     def getoutput(self):
340         output = csv.StringIO()
341         writer = csv.DictWriter(output, self.fieldnames,
342                                 extrasaction='ignore',
343                                 dialect=self.dialect)
344         writer.writeheader()
345         for ce in self.units:
346             writer.writerow(ce.todict())
347         return output.getvalue()
348
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/translate/storage/csvl10n.py b/translate/storage/csvl10n.py
--- a/translate/storage/csvl10n.py
+++ b/translate/storage/csvl10n.py
@@ -301,12 +301,10 @@
 
         try:
             self.dialect = sniffer.sniff(sample)
-            if not self.dialect.escapechar:
-                self.dialect.escapechar = '\\'
-                if self.dialect.quoting == csv.QUOTE_MINIMAL:
-                    #HACKISH: most probably a default, not real detection
-                    self.dialect.quoting = csv.QUOTE_ALL
-                    self.dialect.doublequote = True
+            if self.dialect.quoting == csv.QUOTE_MINIMAL:
+                #HACKISH: most probably a default, not real detection
+                self.dialect.quoting = csv.QUOTE_ALL
+                self.dialect.doublequote = True
         except csv.Error:
             self.dialect = 'default'

{"golden_diff": "diff --git a/translate/storage/csvl10n.py b/translate/storage/csvl10n.py\n--- a/translate/storage/csvl10n.py\n+++ b/translate/storage/csvl10n.py\n@@ -301,12 +301,10 @@\n \n         try:\n             self.dialect = sniffer.sniff(sample)\n-            if not self.dialect.escapechar:\n-                self.dialect.escapechar = '\\\\'\n-                if self.dialect.quoting == csv.QUOTE_MINIMAL:\n-                    #HACKISH: most probably a default, not real detection\n-                    self.dialect.quoting = csv.QUOTE_ALL\n-                    self.dialect.doublequote = True\n+            if self.dialect.quoting == csv.QUOTE_MINIMAL:\n+                #HACKISH: most probably a default, not real detection\n+                self.dialect.quoting = csv.QUOTE_ALL\n+                self.dialect.doublequote = True\n         except csv.Error:\n             self.dialect = 'default'\n", "issue": "csv2po new line\nHi there, i have CSV with:\r\n\r\n```csv\r\n\"yellow pencil\",\"\u017c\u00f3\u0142ty\\no\u0142\u00f3wek\"\r\n\"photo description\",\"opis zdj\u0119cia\"\r\n```\r\n\r\nAnd converted with csv2po:\r\n\r\n```po\r\nmsgid \"yellow pencil\"\r\nmsgstr \"\u017c\u00f3\u0142tyno\u0142\u00f3wek\"\r\n\r\nmsgid \"photo description\"\r\nmsgstr \"opis zdj\u0119cia\"\r\n```\r\n\r\nHow to convert with save format \"\\n\", script delete \\ from string.\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2002-2006 Zuza Software Foundation\n#\n# This file is part of translate.\n#\n# translate is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# translate is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"classes that hold units of comma-separated values (.csv) files (csvunit)\nor entire files (csvfile) for use with localisation\n\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport six\nif six.PY2:\n    from backports import csv\nelse:\n    import csv\n\nfrom translate.storage import base\n\n\nclass DefaultDialect(csv.excel):\n    skipinitialspace = True\n    quoting = csv.QUOTE_ALL\n    escapechar = '\\\\'\n\n\ncsv.register_dialect('default', DefaultDialect)\n\n\n@six.python_2_unicode_compatible\nclass csvunit(base.TranslationUnit):\n    spreadsheetescapes = [(\"+\", \"\\\\+\"), (\"-\", \"\\\\-\"), (\"=\", \"\\\\=\"), (\"'\", \"\\\\'\")]\n\n    def __init__(self, source=None):\n        super(csvunit, self).__init__(source)\n        self.location = \"\"\n        self.source = source or \"\"\n        self.target = \"\"\n        self.id = \"\"\n        self.fuzzy = 'False'\n        self.developer_comments = \"\"\n        self.translator_comments = \"\"\n        self.context = \"\"\n\n    def getid(self):\n        if self.id:\n            return self.id\n\n        result = self.source\n        context = self.context\n        if context:\n            result = u\"%s\\04%s\" % (context, result)\n\n        return result\n\n    def setid(self, value):\n        self.id = value\n\n    def getlocations(self):\n        #FIXME: do we need to support more than one location\n        return [self.location]\n\n    def addlocation(self, location):\n        self.location = location\n\n    def getcontext(self):\n        return self.context\n\n    def setcontext(self, value):\n        self.context = value\n\n    def getnotes(self, origin=None):\n        if origin is None:\n            result = self.translator_comments\n            if self.developer_comments:\n                if result:\n                    result += '\\n' + self.developer_comments\n                else:\n                    result = self.developer_comments\n            return result\n        elif origin == \"translator\":\n            return self.translator_comments\n        elif origin in ('programmer', 'developer', 'source code'):\n            return self.developer_comments\n        else:\n            raise ValueError(\"Comment type not valid\")\n\n    def addnote(self, text, origin=None, position=\"append\"):\n        if origin in ('programmer', 'developer', 'source code'):\n            if position == 'append' and self.developer_comments:\n                self.developer_comments += '\\n' + text\n            elif position == 'prepend' and self.developer_comments:\n                self.developer_comments = text + '\\n' + self.developer_comments\n            else:\n                self.developer_comments = text\n        else:\n            if position == 'append' and self.translator_comments:\n                self.translator_comments += '\\n' + text\n            elif position == 'prepend' and self.translator_comments:\n                self.translator_comments = self.translator_comments + '\\n' + text\n            else:\n                self.translator_comments = text\n\n    def removenotes(self):\n        self.translator_comments = u''\n\n    def isfuzzy(self):\n        if self.fuzzy.lower() in ('1', 'x', 'true', 'yes', 'fuzzy'):\n            return True\n        return False\n\n    def markfuzzy(self, value=True):\n        if value:\n            self.fuzzy = 'True'\n        else:\n            self.fuzzy = 'False'\n\n    def match_header(self):\n        \"\"\"see if unit might be a header\"\"\"\n        some_value = False\n        for key, value in six.iteritems(self.todict()):\n            if value:\n                some_value = True\n            if key.lower() != 'fuzzy' and value and key.lower() != value.lower():\n                return False\n        return some_value\n\n    def add_spreadsheet_escapes(self, source, target):\n        \"\"\"add common spreadsheet escapes to two strings\"\"\"\n        for unescaped, escaped in self.spreadsheetescapes:\n            if source.startswith(unescaped):\n                source = source.replace(unescaped, escaped, 1)\n            if target.startswith(unescaped):\n                target = target.replace(unescaped, escaped, 1)\n        return source, target\n\n    def remove_spreadsheet_escapes(self, source, target):\n        \"\"\"remove common spreadsheet escapes from two strings\"\"\"\n        for unescaped, escaped in self.spreadsheetescapes:\n            if source.startswith(escaped):\n                source = source.replace(escaped, unescaped, 1)\n            if target.startswith(escaped):\n                target = target.replace(escaped, unescaped, 1)\n        return source, target\n\n    def fromdict(self, cedict, encoding='utf-8'):\n        for key, value in six.iteritems(cedict):\n            rkey = fieldname_map.get(key, key)\n            if value is None or key is None or key == EXTRA_KEY:\n                continue\n            if rkey == \"id\":\n                self.id = value\n            elif rkey == \"source\":\n                self.source = value\n            elif rkey == \"target\":\n                self.target = value\n            elif rkey == \"location\":\n                self.location = value\n            elif rkey == \"fuzzy\":\n                self.fuzzy = value\n            elif rkey == \"context\":\n                self.context = value\n            elif rkey == \"translator_comments\":\n                self.translator_comments = value\n            elif rkey == \"developer_comments\":\n                self.developer_comments = value\n\n        #self.source, self.target = self.remove_spreadsheet_escapes(self.source, self.target)\n\n    def todict(self, **kwargs):\n        #FIXME: use apis?\n        #source, target = self.add_spreadsheet_escapes(self.source, self.target)\n        source = self.source\n        target = self.target\n        output = {\n            'location': self.location,\n            'source': source,\n            'target': target,\n            'id': self.id,\n            'fuzzy': str(self.fuzzy),\n            'context': self.context,\n            'translator_comments': self.translator_comments,\n            'developer_comments': self.developer_comments,\n        }\n\n        return output\n\n    def __str__(self):\n        return str(self.todict())\n\n\nfieldname_map = {\n    'original': 'source',\n    'untranslated': 'source',\n    'translated': 'target',\n    'translation': 'target',\n    'identified': 'id',\n    'key': 'id',\n    'label': 'id',\n    'translator comments': 'translator_comments',\n    'notes': 'translator_comments',\n    'developer comments': 'developer_comments',\n    'state': 'fuzzy',\n}\n\n\nEXTRA_KEY = '__CSVL10N__EXTRA__'\n\n\ndef try_dialects(inputfile, fieldnames, dialect):\n    #FIXME: does it verify at all if we don't actually step through the file?\n    try:\n        inputfile.seek(0)\n        reader = csv.DictReader(inputfile, fieldnames=fieldnames, dialect=dialect, restkey=EXTRA_KEY)\n    except csv.Error:\n        try:\n            inputfile.seek(0)\n            reader = csv.DictReader(inputfile, fieldnames=fieldnames, dialect='default', restkey=EXTRA_KEY)\n        except csv.Error:\n            inputfile.seek(0)\n            reader = csv.DictReader(inputfile, fieldnames=fieldnames, dialect='excel', restkey=EXTRA_KEY)\n    return reader\n\n\ndef valid_fieldnames(fieldnames):\n    \"\"\"Check if fieldnames are valid, that is at least one field is identified\n    as the source.\n    \"\"\"\n    for fieldname in fieldnames:\n        if fieldname == 'source':\n            return True\n        elif fieldname in fieldname_map and fieldname_map[fieldname] == 'source':\n            return True\n    return False\n\n\ndef detect_header(sample, dialect, fieldnames):\n    \"\"\"Test if file has a header or not, also returns number of columns in first row\"\"\"\n    inputfile = csv.StringIO(sample)\n    try:\n        reader = csv.reader(inputfile, dialect)\n    except csv.Error:\n        try:\n            inputfile.seek(0)\n            reader = csv.reader(inputfile, 'default')\n        except csv.Error:\n            inputfile.seek(0)\n            reader = csv.reader(inputfile, 'excel')\n\n    header = next(reader)\n    columncount = max(len(header), 3)\n    if valid_fieldnames(header):\n        return header\n    return fieldnames[:columncount]\n\n\nclass csvfile(base.TranslationStore):\n    \"\"\"This class represents a .csv file with various lines.  The default\n    format contains three columns: location, source, target\n    \"\"\"\n\n    UnitClass = csvunit\n    Name = \"Comma Separated Value\"\n    Mimetypes = ['text/comma-separated-values', 'text/csv']\n    Extensions = [\"csv\"]\n\n    def __init__(self, inputfile=None, fieldnames=None, encoding='auto'):\n        super(csvfile, self).__init__(encoding=encoding)\n        if not fieldnames:\n            self.fieldnames = ['location', 'source', 'target', 'id', 'fuzzy', 'context', 'translator_comments', 'developer_comments']\n        else:\n            self.fieldnames = fieldnames\n        self.filename = getattr(inputfile, 'name', '')\n        self.dialect = 'default'\n        if inputfile is not None:\n            csvsrc = inputfile.read()\n            inputfile.close()\n            self.parse(csvsrc)\n\n    def parse(self, csvsrc):\n        text, encoding = self.detect_encoding(csvsrc, default_encodings=['utf-8', 'utf-16'])\n        #FIXME: raise parse error if encoding detection fails?\n        self.encoding = encoding or 'utf-8'\n\n        sniffer = csv.Sniffer()\n        sample = text[:1024]\n\n        try:\n            self.dialect = sniffer.sniff(sample)\n            if not self.dialect.escapechar:\n                self.dialect.escapechar = '\\\\'\n                if self.dialect.quoting == csv.QUOTE_MINIMAL:\n                    #HACKISH: most probably a default, not real detection\n                    self.dialect.quoting = csv.QUOTE_ALL\n                    self.dialect.doublequote = True\n        except csv.Error:\n            self.dialect = 'default'\n\n        try:\n            fieldnames = detect_header(sample, self.dialect, self.fieldnames)\n            self.fieldnames = fieldnames\n        except csv.Error:\n            pass\n\n        inputfile = csv.StringIO(text)\n        reader = try_dialects(inputfile, self.fieldnames, self.dialect)\n\n        first_row = True\n        for row in reader:\n            newce = self.UnitClass()\n            newce.fromdict(row)\n            if not first_row or not newce.match_header():\n                self.addunit(newce)\n            first_row = False\n\n    def serialize(self, out):\n        \"\"\"Write to file\"\"\"\n        source = self.getoutput()\n        if isinstance(source, six.text_type):\n            # Python 3\n            out.write(source.encode(self.encoding))\n        else:\n            out.write(source)\n\n    def getoutput(self):\n        output = csv.StringIO()\n        writer = csv.DictWriter(output, self.fieldnames,\n                                extrasaction='ignore',\n                                dialect=self.dialect)\n        writer.writeheader()\n        for ce in self.units:\n            writer.writerow(ce.todict())\n        return output.getvalue()\n", "path": "translate/storage/csvl10n.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n#\n# Copyright 2002-2006 Zuza Software Foundation\n#\n# This file is part of translate.\n#\n# translate is free software; you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation; either version 2 of the License, or\n# (at your option) any later version.\n#\n# translate is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with this program; if not, see <http://www.gnu.org/licenses/>.\n\n\"\"\"classes that hold units of comma-separated values (.csv) files (csvunit)\nor entire files (csvfile) for use with localisation\n\"\"\"\n\nfrom __future__ import unicode_literals\n\nimport six\nif six.PY2:\n    from backports import csv\nelse:\n    import csv\n\nfrom translate.storage import base\n\n\nclass DefaultDialect(csv.excel):\n    skipinitialspace = True\n    quoting = csv.QUOTE_ALL\n    escapechar = '\\\\'\n\n\ncsv.register_dialect('default', DefaultDialect)\n\n\n@six.python_2_unicode_compatible\nclass csvunit(base.TranslationUnit):\n    spreadsheetescapes = [(\"+\", \"\\\\+\"), (\"-\", \"\\\\-\"), (\"=\", \"\\\\=\"), (\"'\", \"\\\\'\")]\n\n    def __init__(self, source=None):\n        super(csvunit, self).__init__(source)\n        self.location = \"\"\n        self.source = source or \"\"\n        self.target = \"\"\n        self.id = \"\"\n        self.fuzzy = 'False'\n        self.developer_comments = \"\"\n        self.translator_comments = \"\"\n        self.context = \"\"\n\n    def getid(self):\n        if self.id:\n            return self.id\n\n        result = self.source\n        context = self.context\n        if context:\n            result = u\"%s\\04%s\" % (context, result)\n\n        return result\n\n    def setid(self, value):\n        self.id = value\n\n    def getlocations(self):\n        #FIXME: do we need to support more than one location\n        return [self.location]\n\n    def addlocation(self, location):\n        self.location = location\n\n    def getcontext(self):\n        return self.context\n\n    def setcontext(self, value):\n        self.context = value\n\n    def getnotes(self, origin=None):\n        if origin is None:\n            result = self.translator_comments\n            if self.developer_comments:\n                if result:\n                    result += '\\n' + self.developer_comments\n                else:\n                    result = self.developer_comments\n            return result\n        elif origin == \"translator\":\n            return self.translator_comments\n        elif origin in ('programmer', 'developer', 'source code'):\n            return self.developer_comments\n        else:\n            raise ValueError(\"Comment type not valid\")\n\n    def addnote(self, text, origin=None, position=\"append\"):\n        if origin in ('programmer', 'developer', 'source code'):\n            if position == 'append' and self.developer_comments:\n                self.developer_comments += '\\n' + text\n            elif position == 'prepend' and self.developer_comments:\n                self.developer_comments = text + '\\n' + self.developer_comments\n            else:\n                self.developer_comments = text\n        else:\n            if position == 'append' and self.translator_comments:\n                self.translator_comments += '\\n' + text\n            elif position == 'prepend' and self.translator_comments:\n                self.translator_comments = self.translator_comments + '\\n' + text\n            else:\n                self.translator_comments = text\n\n    def removenotes(self):\n        self.translator_comments = u''\n\n    def isfuzzy(self):\n        if self.fuzzy.lower() in ('1', 'x', 'true', 'yes', 'fuzzy'):\n            return True\n        return False\n\n    def markfuzzy(self, value=True):\n        if value:\n            self.fuzzy = 'True'\n        else:\n            self.fuzzy = 'False'\n\n    def match_header(self):\n        \"\"\"see if unit might be a header\"\"\"\n        some_value = False\n        for key, value in six.iteritems(self.todict()):\n            if value:\n                some_value = True\n            if key.lower() != 'fuzzy' and value and key.lower() != value.lower():\n                return False\n        return some_value\n\n    def add_spreadsheet_escapes(self, source, target):\n        \"\"\"add common spreadsheet escapes to two strings\"\"\"\n        for unescaped, escaped in self.spreadsheetescapes:\n            if source.startswith(unescaped):\n                source = source.replace(unescaped, escaped, 1)\n            if target.startswith(unescaped):\n                target = target.replace(unescaped, escaped, 1)\n        return source, target\n\n    def remove_spreadsheet_escapes(self, source, target):\n        \"\"\"remove common spreadsheet escapes from two strings\"\"\"\n        for unescaped, escaped in self.spreadsheetescapes:\n            if source.startswith(escaped):\n                source = source.replace(escaped, unescaped, 1)\n            if target.startswith(escaped):\n                target = target.replace(escaped, unescaped, 1)\n        return source, target\n\n    def fromdict(self, cedict, encoding='utf-8'):\n        for key, value in six.iteritems(cedict):\n            rkey = fieldname_map.get(key, key)\n            if value is None or key is None or key == EXTRA_KEY:\n                continue\n            if rkey == \"id\":\n                self.id = value\n            elif rkey == \"source\":\n                self.source = value\n            elif rkey == \"target\":\n                self.target = value\n            elif rkey == \"location\":\n                self.location = value\n            elif rkey == \"fuzzy\":\n                self.fuzzy = value\n            elif rkey == \"context\":\n                self.context = value\n            elif rkey == \"translator_comments\":\n                self.translator_comments = value\n            elif rkey == \"developer_comments\":\n                self.developer_comments = value\n\n        #self.source, self.target = self.remove_spreadsheet_escapes(self.source, self.target)\n\n    def todict(self, **kwargs):\n        #FIXME: use apis?\n        #source, target = self.add_spreadsheet_escapes(self.source, self.target)\n        source = self.source\n        target = self.target\n        output = {\n            'location': self.location,\n            'source': source,\n            'target': target,\n            'id': self.id,\n            'fuzzy': str(self.fuzzy),\n            'context': self.context,\n            'translator_comments': self.translator_comments,\n            'developer_comments': self.developer_comments,\n        }\n\n        return output\n\n    def __str__(self):\n        return str(self.todict())\n\n\nfieldname_map = {\n    'original': 'source',\n    'untranslated': 'source',\n    'translated': 'target',\n    'translation': 'target',\n    'identified': 'id',\n    'key': 'id',\n    'label': 'id',\n    'translator comments': 'translator_comments',\n    'notes': 'translator_comments',\n    'developer comments': 'developer_comments',\n    'state': 'fuzzy',\n}\n\n\nEXTRA_KEY = '__CSVL10N__EXTRA__'\n\n\ndef try_dialects(inputfile, fieldnames, dialect):\n    #FIXME: does it verify at all if we don't actually step through the file?\n    try:\n        inputfile.seek(0)\n        reader = csv.DictReader(inputfile, fieldnames=fieldnames, dialect=dialect, restkey=EXTRA_KEY)\n    except csv.Error:\n        try:\n            inputfile.seek(0)\n            reader = csv.DictReader(inputfile, fieldnames=fieldnames, dialect='default', restkey=EXTRA_KEY)\n        except csv.Error:\n            inputfile.seek(0)\n            reader = csv.DictReader(inputfile, fieldnames=fieldnames, dialect='excel', restkey=EXTRA_KEY)\n    return reader\n\n\ndef valid_fieldnames(fieldnames):\n    \"\"\"Check if fieldnames are valid, that is at least one field is identified\n    as the source.\n    \"\"\"\n    for fieldname in fieldnames:\n        if fieldname == 'source':\n            return True\n        elif fieldname in fieldname_map and fieldname_map[fieldname] == 'source':\n            return True\n    return False\n\n\ndef detect_header(sample, dialect, fieldnames):\n    \"\"\"Test if file has a header or not, also returns number of columns in first row\"\"\"\n    inputfile = csv.StringIO(sample)\n    try:\n        reader = csv.reader(inputfile, dialect)\n    except csv.Error:\n        try:\n            inputfile.seek(0)\n            reader = csv.reader(inputfile, 'default')\n        except csv.Error:\n            inputfile.seek(0)\n            reader = csv.reader(inputfile, 'excel')\n\n    header = next(reader)\n    columncount = max(len(header), 3)\n    if valid_fieldnames(header):\n        return header\n    return fieldnames[:columncount]\n\n\nclass csvfile(base.TranslationStore):\n    \"\"\"This class represents a .csv file with various lines.  The default\n    format contains three columns: location, source, target\n    \"\"\"\n\n    UnitClass = csvunit\n    Name = \"Comma Separated Value\"\n    Mimetypes = ['text/comma-separated-values', 'text/csv']\n    Extensions = [\"csv\"]\n\n    def __init__(self, inputfile=None, fieldnames=None, encoding='auto'):\n        super(csvfile, self).__init__(encoding=encoding)\n        if not fieldnames:\n            self.fieldnames = ['location', 'source', 'target', 'id', 'fuzzy', 'context', 'translator_comments', 'developer_comments']\n        else:\n            self.fieldnames = fieldnames\n        self.filename = getattr(inputfile, 'name', '')\n        self.dialect = 'default'\n        if inputfile is not None:\n            csvsrc = inputfile.read()\n            inputfile.close()\n            self.parse(csvsrc)\n\n    def parse(self, csvsrc):\n        text, encoding = self.detect_encoding(csvsrc, default_encodings=['utf-8', 'utf-16'])\n        #FIXME: raise parse error if encoding detection fails?\n        self.encoding = encoding or 'utf-8'\n\n        sniffer = csv.Sniffer()\n        sample = text[:1024]\n\n        try:\n            self.dialect = sniffer.sniff(sample)\n            if self.dialect.quoting == csv.QUOTE_MINIMAL:\n                #HACKISH: most probably a default, not real detection\n                self.dialect.quoting = csv.QUOTE_ALL\n                self.dialect.doublequote = True\n        except csv.Error:\n            self.dialect = 'default'\n\n        try:\n            fieldnames = detect_header(sample, self.dialect, self.fieldnames)\n            self.fieldnames = fieldnames\n        except csv.Error:\n            pass\n\n        inputfile = csv.StringIO(text)\n        reader = try_dialects(inputfile, self.fieldnames, self.dialect)\n\n        first_row = True\n        for row in reader:\n            newce = self.UnitClass()\n            newce.fromdict(row)\n            if not first_row or not newce.match_header():\n                self.addunit(newce)\n            first_row = False\n\n    def serialize(self, out):\n        \"\"\"Write to file\"\"\"\n        source = self.getoutput()\n        if isinstance(source, six.text_type):\n            # Python 3\n            out.write(source.encode(self.encoding))\n        else:\n            out.write(source)\n\n    def getoutput(self):\n        output = csv.StringIO()\n        writer = csv.DictWriter(output, self.fieldnames,\n                                extrasaction='ignore',\n                                dialect=self.dialect)\n        writer.writeheader()\n        for ce in self.units:\n            writer.writerow(ce.todict())\n        return output.getvalue()\n", "path": "translate/storage/csvl10n.py"}]}