1 # -*- coding: utf-8 -*-
2 # copyright 2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
3 # contact http://www.logilab.fr -- mailto:contact@logilab.fr
5 # This program is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU Lesser General Public License as published by the Free
7 # Software Foundation, either version 2.1 of the License, or (at your option)
10 # This program is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15 # You should have received a copy of the GNU Lesser General Public License along
16 # with this program. If not, see <http://www.gnu.org/licenses/>.
18 Main module of the ``i18n`` package, for internationalizing strings via the Qt
19 mechanism, in the ``Eficas`` application of EDF. Handles unformatted and
20 formatted strings, according to all formatting schemes: via dictionaries,
23 ``PyQt4`` is currently supported.
25 from Extensions.eficas_exception import EficasException
26 def _reformat_qstring_from_tuple(qstring, params):
28 _reformat_qstring_from_tuple(QString, tuple) -> QString
30 Module-internal method.
31 Returns a formatted QString from an unformatted QString
32 and a tuple specifying the parameters of the QString.
34 from PyQt4.QtCore import QRegExp, QString
35 reg = QRegExp("\%\.[1-9]{1,2}f")
36 for p, j in zip(params, range(len(params))):
38 i += 1 + qstring[i + 1:].indexOf("%")
40 i = qstring.indexOf("%")
41 if i == reg.indexIn(qstring):
42 precision = reg.cap(0).split('.')[1].split('f')[0]
43 qstring = qstring[:i + 2 + len(precision)].\
44 replace("%." + precision, "%" + unicode(1 + j)) + \
45 qstring[i + 3 + len(precision):]
46 qstring = qstring.arg(QString.number(float(params[j]), 'f',\
49 qstring = qstring[:i + 1].replace("%", "%" + unicode(1 + j)) + \
51 if isinstance(params[j], unicode):
52 qstring = qstring.arg(params[j])
53 elif isinstance(params[j], float):
54 qstring = qstring.arg(QString.number(params[j], 'f',\
55 len(unicode(params[j]).\
57 elif isinstance(params[j], int):
58 qstring = qstring.arg(QString.number(params[j], 10))
59 elif isinstance(params[j], list):
60 qstring = qstring.arg(repr(params[j]))
62 raise EficasException("TypeError: i18n.translation: \
63 Unicode, list or number expected!")
66 def _reformat_qstring_from_dict(qstring, params):
68 _reformat_qstring_from_dict(QString, dict) -> QString
70 Module-internal method.
71 Returns a formatted QString from an unformatted QString
72 and a dictionary specifying the parameters of the QString.
74 from PyQt4.QtCore import QRegExp, QString
75 for p, j in zip(params, range(len(params))):
76 p_reg = QRegExp("\%\("+ p + "\)\.[1-9]{1,2}f")
77 p_index = p_reg.indexIn(qstring)
79 precision = p_reg.cap(0).split('.')[1].split('f')[0]
80 qstring = qstring.replace("%(" + p + ")." + precision + "f",\
81 "%" + unicode(1 + j)).\
82 arg(QString.number(float(params[p]), \
86 qstring.remove(QRegExp("\\)[sdf]{1}"))
87 qstring = qstring.replace("%(" + p, "%" + unicode(1 + j))
88 if isinstance(params[p], unicode):
89 qstring = qstring.arg(params[p])
90 elif isinstance(params[p], float):
91 qstring = qstring.arg(QString.number(params[p], 'f', \
92 len(unicode(params[p]).split('.')[1])))
93 elif isinstance(params[p], int):
94 qstring = qstring.arg(QString.number(params[p], 10))
95 elif isinstance(params[p], list):
96 qstring = qstring.arg(repr(params[p]))
98 raise EficasException("TypeError: i18n.translation: \
99 Improper string parameter type.")
102 def _reformat_qstring_from_atom(qstring, params):
104 _reformat_qstring_from_atom(QString, int-or-float) -> QString
106 Module-internal method.
107 Returns a formatted QString from an unformatted QString
108 and an integer or a float specifying the parameter of
111 from PyQt4.QtCore import QRegExp, QString
112 reg = QRegExp("\%\.[1-9]{1,2}f")
113 if qstring.count("%") == 0:
116 qstring = qstring.arg(unicode(params))
117 except AttributeError:
118 qstring = qstring.arg(params)
119 elif qstring.count("%") == 1:
120 i = qstring.indexOf("%")
121 if i == reg.indexIn(qstring):
122 precision = reg.cap(0).split('.')[1].split('f')[0]
123 qstring = qstring[: i + 2 + len(precision)].\
124 replace("%." + precision, "%1") + \
125 qstring[i + 3 + len(precision):]
126 qstring = qstring.arg(QString.number(float(params), 'f',\
129 qstring = qstring[:i + 1].replace("%", "%1") + \
131 if isinstance(params, (unicode, str)):
132 qstring = qstring.arg(_preprocess_atom(params))
133 elif isinstance(params, float):
134 qstring = qstring.arg(QString.number(params, 'f', \
135 len(unicode(params).\
137 elif isinstance(params, int):
138 qstring = qstring.arg(QString.number(params, 10))
140 raise EficasException("TypeError: i18n.translation: Unicode, \
141 string or number expected!")
144 def _reformat_qstring_from_list(qstring, params):
146 _reformat_qstring_from_list(QString, tuple) -> QString
148 Module-internal method.
149 Returns a formatted QString from an unformatted QString
150 and a list whose concatenation specifies the parameter
153 # XXX to add further functionality, e.g. list processing
154 # when ``%`` not at the end.
155 if qstring.count("%") == 1 and \
156 unicode(qstring).strip()[:-1].endswith("%"):
157 qstring = qstring[:qstring.indexOf("%") + 1].append("1")
158 qstring = qstring.arg(u' '.join(map(unicode, params)))
159 elif qstring.count("%") == 0:
161 qstring = qstring.arg(u' '.join(map(unicode, params)))
163 raise EficasException("ValueError: i18n.translation: \
164 At most one '%' expected!")
167 def _preprocess_atom(string):
169 _preprocess_atom(string-or-number-or-unicode) -> unicode
170 Test if input is a Unicode object or a number; if so, then return it;
171 otherwise, test if the input is a string; if so, then try to create
172 a Unicode object out of it. To this end, assume the string is encoded
173 in utf-8; if this fails, then assume the string is encoded in Latin-9.
175 if isinstance(string, (unicode, int, float, complex)):
177 elif isinstance(string, str):
178 return _str_to_unicode(string)
180 raise EficasException("TypeError: Expected number, string or\
183 def _str_to_unicode(string):
185 _str_to_unicode(string) -> unicode
186 Tries to create a Unicode object out of the input string; assumes
187 the string is UTF-8 encoded; if not, then assume the string is
191 string = unicode(string, "utf-8")
192 except UnicodeDecodeError:
194 string = unicode(string, "iso-8859-15")
195 except UnicodeDecodeError:
196 raise EficasException("UnicodeDecodeError: UTF-8, Latin-1 \
197 or Latin-9 expected")
200 def tr(string, *args):
201 """tr(string-or-unicode, iterable-or-float-or-int) -> unicode
202 tr(string-or-unicode) -> unicode
204 Returns a formatted Unicode object from an unformatted
205 string or Unicode object with formatting specifications, and,
206 optionally, an iterable or an int or float.
207 Lets Python do the string formatting."""
208 from PyQt4.QtGui import QApplication
209 string = _preprocess_atom(string)
211 r = unicode(QApplication.translate("@default", string))
213 if isinstance(args[0], (dict, tuple)):
214 if string.count("%") == len(args[0]):
215 r = unicode(QApplication.translate("@default", string)) % args[0]
216 elif string.count("%") == 1 and string.count("%(") == 0:
217 r = unicode(QApplication.translate("@default", string))\
218 % _preprocess_atom(repr(args[0]))
219 elif string.count("%") == 0:
220 r = (unicode(QApplication.translate("@default", string)), args[0])
222 raise EficasException("ValueError: i18n.translate.tr: \
223 Improper input string formatting")
224 elif isinstance(args[0], (unicode, str, int, float, complex)):
225 if string.count("%") == 1:
226 r = unicode(QApplication.translate("@default", string))\
227 % _preprocess_atom(args[0])
229 r = unicode(QApplication.translate("@default", string)) +\
230 unicode(_preprocess_atom(args[0]))
231 elif isinstance(args[0], list) or args[0] is None:
232 if string.count("%") == 1:
233 r = unicode(QApplication.translate("@default", string))\
234 % _preprocess_atom(repr(args[0]))
236 r = (unicode(QApplication.translate("@default", string)), args[0])
239 raise EficasException("ValueError: i18n.translation.tr: \
240 Wrong type for formatted string \
241 arguments: %s" % type(args[0]))
243 raise EficasException("ValueError: i18n.translation.tr: \
244 Wrong formatted string arguments")
248 def tr_qt(string, *args):
249 """tr_qt(string, iterable-or-float-or-int) -> unicode
250 t_qtr(string) -> unicode
252 Returns a formatted string from an unformatted
253 Unicode string with formatting specifications, and,
254 optionally, an iterable or an int or float.
255 Lets PyQt4 do the string formatting. To this end,
256 a conversion from Python to Qt string formatting
257 syntax is performed."""
258 string = _preprocess_atom(string)
259 from PyQt4.QtGui import QApplication
261 r = QApplication.translate("@default", string)
263 r = QApplication.translate("@default", string)
264 if isinstance(args[0], (dict, tuple)):
265 if r.count("%") == len(args[0]):
266 if isinstance(args[0], dict):
267 r = _reformat_qstring_from_dict(r, args[0])
268 elif isinstance(args[0], tuple):
269 r = _reformat_qstring_from_tuple(r, args[0])
270 # XXX Pay attention to this: distinguish between tuple,
271 # dict and dict with key given in string.
272 elif r.count("%") in range(2) and r.count("%(") == 0:
273 r = _reformat_qstring_from_atom(r, _preproces_atom(repr(args[0])))
275 raise EficasException("ValueError: i18n.translation.tr_qt: \
276 Improper formatting string parameters")
277 elif isinstance(args[0], (unicode, str, int, float, complex)):
278 r = _reformat_qstring_from_atom(r, args[0])
279 elif isinstance(args[0], list):
280 r = _reformat_qstring_from_list(r, args[0])
281 elif args[0] is None:
282 r = _reformat_qstring_from_atom(r, _preprocess_string_from_atom(repr(args[0])))
284 raise EficasException("ValueError: i18n.translation.tr_qt: \
285 Wrong string formatting parameter types")
287 raise EficasException("ValueError: i18n.translation.tr_qt: \
288 Improper formatted string parameter set")
292 if __name__ == "__main__":
294 tr(sys.argv[1], *args)
295 tr_qt(sys.argv[1], *args)