1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 """Manage the Haiku catkeys translation format
22
23 The Haiku catkeys format is the translation format used for localisation of
24 the U{Haiku<http://www.haiku-os.org/>} operating system.
25
26 It is a bilingual base class derived format with L{CatkeysFile} and
27 L{CatkeysUnit} providing file and unit level access. The file format is
28 described here:
29 http://www.haiku-os.org/blog/pulkomandy/2009-09-24_haiku_locale_kit_translator_handbook
30
31 Implementation
32 ==============
33 The implementation covers the full requirements of a catkeys file. The
34 files are simple Tab Separated Value (TSV) files that can be read
35 by Microsoft Excel and other spreadsheet programs. They use the .txt
36 extension which does make it more difficult to automatically identify
37 such files.
38
39 The dialect of the TSV files is specified by L{CatkeysDialect}.
40
41 Encoding
42 --------
43 The files are UTF-8 encoded.
44
45 Header
46 ------
47 L{CatkeysHeader} provides header management support.
48
49 Escaping
50 --------
51 catkeys seem to escape things like in C++ (strings are just extracted from
52 the source code unchanged, it seems.
53
54 Functions allow for L{escaping<_escape>} and L{unescaping<_unescape>}.
55 """
56
57 import csv
58 import sys
59 from translate.storage import base
60 from translate.lang.data import tr_lang
61
62 FIELDNAMES_HEADER = ["version", "language", "mimetype", "checksum"]
63 """Field names for the catkeys header"""
64
65 FIELDNAMES = ["source", "context", "comment", "target"]
66 """Field names for a catkeys TU"""
67
68 FIELDNAMES_HEADER_DEFAULTS = {
69 "version": "1",
70 "language": "",
71 "mimetype": "",
72 "checksum": "",
73 }
74 """Default or minimum header entries for a catkeys file"""
75
76 _unescape_map = {"\\r": "\r", "\\t": "\t", '\\n': '\n', '\\\\': '\\'}
77 _escape_map = dict([(value, key) for (key, value) in _unescape_map.items()])
78
79
80
81
83 if string:
84 string = string.replace(r"\n", r"\\n").replace("\n", "\\n").replace("\t", "\\t")
85 return string
86
88 if string:
89 string = string.replace("\\n", "\n").replace("\\t", "\t").replace(r"\n", r"\\n")
90 return string
91
92
106 csv.register_dialect("catkeys", CatkeysDialect)
107
109 """A catkeys translation memory header"""
116
121
123 """Set a human readable target language"""
124 self._header_dict['language'] = tr_lang('en')(newlang)
125 targetlang = property(None, settargetlang)
126
128 """A catkeys translation memory unit"""
134
136 """Get the dictionary of values for a catkeys line"""
137 return self._dict
138
140 """Set the dictionary of values for a catkeys line
141
142 @param newdict: a new dictionary with catkeys line elements
143 @type newdict: Dict
144 """
145
146 self._dict = newdict
147 dict = property(getdict, setdict)
148
150 if self._dict.get(key, None) is None:
151 return None
152 elif self._dict[key]:
153 return _unescape(self._dict[key]).decode('utf-8')
154 else:
155 return ""
156
158 if newvalue is None:
159 self._dict[key] = None
160 if isinstance(newvalue, unicode):
161 newvalue = newvalue.encode('utf-8')
162 newvalue = _escape(newvalue)
163 if not key in self._dict or newvalue != self._dict[key]:
164 self._dict[key] = newvalue
165
168
172 source = property(getsource, setsource)
173
176
180 target = property(gettarget, settarget)
181
183 if not origin or origin in ["programmer", "developer", "source code"]:
184 return self._dict["comment"].decode('utf-8')
185 return u""
186
187 - def getcontext(self):
188 return self._dict["context"].decode('utf-8')
189
199
201 if present:
202 self.target = u""
203
205 self._dict['target-lang'] = newlang
206 targetlang = property(None, settargetlang)
207
209 return str(self._dict)
210
212 if not self._dict.get('source', None):
213 return False
214 return bool(self._dict.get('target', None))
215
216 - def merge(self, otherunit, overwrite=False, comments=True,
217 authoritative=False):
224
225
227 """A catkeys translation memory file"""
228 Name = _("Haiku catkeys file")
229 Mimetypes = ["application/x-catkeys"]
230 Extensions = ["catkeys"]
232 """Construct a catkeys store, optionally reading in from inputfile."""
233 self.UnitClass = unitclass
234 base.TranslationStore.__init__(self, unitclass=unitclass)
235 self.filename = ''
236 self.header = CatkeysHeader()
237 self._encoding = 'utf-8'
238 if inputfile is not None:
239 self.parse(inputfile)
240
242 """parsse the given file or file source string"""
243 if hasattr(input, 'name'):
244 self.filename = input.name
245 elif not getattr(self, 'filename', ''):
246 self.filename = ''
247 if hasattr(input, "read"):
248 tmsrc = input.read()
249 input.close()
250 input = tmsrc
251 for header in csv.DictReader(input.split("\n")[:1], fieldnames=FIELDNAMES_HEADER, dialect="catkeys"):
252 self.header = CatkeysHeader(header)
253 lines = csv.DictReader(input.split("\n")[1:], fieldnames=FIELDNAMES, dialect="catkeys")
254 for line in lines:
255 newunit = CatkeysUnit()
256 newunit.dict = line
257 self.addunit(newunit)
258
260 output = csv.StringIO()
261 writer = csv.DictWriter(output, fieldnames=FIELDNAMES, dialect="catkeys")
262 writer.writerow(self.header._header_dict)
263 for unit in self.units:
264 writer.writerow(unit.dict)
265 return output.getvalue()
266