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,
24 from __future__ import absolute_import
26 from builtins import zip
27 from builtins import map
28 from builtins import range
31 from .eficas_exception import EficasException
34 regex=re.compile(r"% *[0-9]+")
37 from six.moves import map
38 from six.moves import range
39 from six.moves import zip
44 def _reformat_qstring_from_tuple(qstring, params):
46 _reformat_qstring_from_tuple(string, tuple) -> string
48 Module-internal method.
49 Returns a formatted string from an unformatted string
50 and a tuple specifying the parameters of the string.
52 from PyQt5.QtCore import QRegExp
53 reg = QRegExp("\%\.[1-9]{1,2}f")
54 for p, j in zip(params, list(range(len(params)))):
56 i += 1 + qstring[i + 1:].indexOf("%")
58 i = qstring.indexOf("%")
59 if i == reg.indexIn(qstring):
60 precision = reg.cap(0).split('.')[1].split('f')[0]
61 qstring = qstring[:i + 2 + len(precision)].\
62 replace("%." + precision, "%" + six.text_type(1 + j)) + \
63 qstring[i + 3 + len(precision):]
64 qstring=regex.sub("{}",qstring)
65 #qstring = qstring.format(QString.number(float(params[j]), 'f', int(precision)))
66 qstring = qstring.format(float(params[j]))
68 qstring = qstring[:i + 1].replace("%", "%" + six.text_type(1 + j)) + \
70 if isinstance(params[j], six.text_type):
71 qstring=regex.sub("{}",qstring)
72 qstring = qstring.format(params[j])
73 elif isinstance(params[j], float):
74 qstring=regex.sub("{}",qstring)
75 #qstring = qstring.format(QString.number(params[j], 'f',\ len(unicode(params[j]).\
77 qstring = qstring.format(params[j])
78 elif isinstance(params[j], int):
79 qstring=regex.sub("{}",qstring)
80 #qstring = qstring.format(QString.number(params[j], 10))
81 qstring = qstring.format(params[j])
82 elif isinstance(params[j], list):
83 qstring=regex.sub("{}",qstring)
84 qstring = qstring.format(repr(params[j]))
86 raise EficasException("TypeError: i18n.translation: \
87 Unicode, list or number expected!")
90 def _reformat_qstring_from_dict(qstring, params):
92 _reformat_qstring_from_dict(string, dict) -> string
94 Module-internal method.
95 Returns a formatted string from an unformatted string
96 and a dictionary specifying the parameters of the string.
98 from PyQt5.QtCore import QRegExp
99 for p, j in zip(params, list(range(len(params)))):
100 p_reg = QRegExp("\%\("+ p + "\)\.[1-9]{1,2}f")
101 p_index = p_reg.indexIn(qstring)
103 precision = p_reg.cap(0).split('.')[1].split('f')[0]
104 #qstring = qstring.replace("%(" + p + ")." + precision + "f",\
105 # "%" + unicode(1 + j)).\
106 # arg(QString.number(float(params[p]), \
109 qstring = qstring.replace("%(" + p + ")." + precision + "f","%" + six.text_type(1 + j))
110 qstring=regex.sub("{}",qstring)
111 qstring = qstring.format(float(params[p]))
113 qstring.remove(QRegExp("\\)[sdf]{1}"))
114 qstring = qstring.replace("%(" + p, "%" + six.text_type(1 + j))
115 if isinstance(params[p], six.text_type):
116 qstring=regex.sub("{}",qstring)
117 qstring = qstring.format(params[p])
118 elif isinstance(params[p], float):
119 qstring=regex.sub("{}",qstring)
120 qstring = qstring.format(params[p])
121 #qstring = qstring.format(QString.number(params[p], 'f', \
122 # len(unicode(params[p]).split('.')[1])))
123 elif isinstance(params[p], int):
124 qstring=regex.sub("{}",qstring)
125 qstring = qstring.format(params[p])
126 elif isinstance(params[p], list):
127 qstring=regex.sub("{}",qstring)
128 qstring = qstring.format(repr(params[p]))
130 raise EficasException("TypeError: i18n.translation: \
131 Improper string parameter type.")
134 def _reformat_qstring_from_atom(qstring, params):
136 _reformat_qstring_from_atom(string, int-or-float) -> string
138 Module-internal method.
139 Returns a formatted string from an unformatted string
140 and an integer or a float specifying the parameter of
143 from PyQt5.QtCore import QRegExp
144 reg = QRegExp("\%\.[1-9]{1,2}f")
145 if qstring.count("%") == 0:
148 qstring=regex.sub("{}",qstring)
149 qstring = qstring.format(six.text_type(params))
150 except AttributeError:
151 qstring=regex.sub("{}",qstring)
152 qstring = qstring.format(params)
153 elif qstring.count("%") == 1:
154 i = qstring.indexOf("%")
155 if i == reg.indexIn(qstring):
156 precision = reg.cap(0).split('.')[1].split('f')[0]
157 qstring = qstring[: i + 2 + len(precision)].\
158 replace("%." + precision, "%1") + \
159 qstring[i + 3 + len(precision):]
160 qstring=regex.sub("{}",qstring)
161 qstring = qstring.format((params))
162 #qstring = qstring.format(QString.number(float(params), 'f',\
165 qstring = qstring[:i + 1].replace("%", "%1") + \
167 if isinstance(params, (six.text_type, str)):
168 qstring = qstring.format(_preprocess_atom(params))
169 elif isinstance(params, float):
170 #qstring = qstring.format(QString.number(params, 'f', \
171 # len(unicode(params).\
173 qstring = qstring.format(params)
174 elif isinstance(params, int):
175 qstring=regex.sub("{}",qstring)
176 #qstring = qstring.format(QString.number(params, 10))
177 qstring = qstring.format(params)
179 raise EficasException("TypeError: i18n.translation: Unicode, \
180 string or number expected!")
183 def _reformat_qstring_from_list(qstring, params):
185 _reformat_qstring_from_list(string, tuple) -> string
187 Module-internal method.
188 Returns a formatted string from an unformatted string
189 and a list whose concatenation specifies the parameter
192 # XXX to add further functionality, e.g. list processing
193 # when ``%`` not at the end.
194 if qstring.count("%") == 1 and \
195 six.text_type(qstring).strip()[:-1].endswith("%"):
196 qstring = qstring[:qstring.indexOf("%") + 1].append("1")
197 qstring=regex.sub("{}",qstring)
198 qstring = qstring.format(u' '.join(map(six.text_type, params)))
199 elif qstring.count("%") == 0:
201 qstring=regex.sub("{}",qstring)
202 qstring = qstring.format(u' '.join(map(six.text_type, params)))
204 raise EficasException("ValueError: i18n.translation: \
205 At most one '%' expected!")
208 def _preprocess_atom(string):
210 _preprocess_atom(string-or-number-or-unicode) -> unicode
211 Test if input is a Unicode object or a number; if so, then return it;
212 otherwise, test if the input is a string; if so, then try to create
213 a Unicode object out of it. To this end, assume the string is encoded
214 in utf-8; if this fails, then assume the string is encoded in Latin-9.
216 if isinstance(string, (six.text_type, int, float, complex)):
218 elif isinstance(string, str):
219 return _str_toUnicode(string)
221 raise EficasException("TypeError: Expected number, string or\
224 def _str_toUnicode(string):
226 _str_toUnicode(string) -> unicode
227 Tries to create a Unicode object out of the input string; assumes
228 the string is UTF-8 encoded; if not, then assume the string is
232 string = six.text_type(string, "utf-8")
233 except UnicodeDecodeError:
235 string = six.text_type(string, "iso-8859-15")
236 except UnicodeDecodeError:
237 raise EficasException("UnicodeDecodeError: UTF-8, Latin-1 \
238 or Latin-9 expected")
241 def tr(string, *args):
242 """tr(string-or-unicode, iterable-or-float-or-int) -> unicode
243 tr(string-or-unicode) -> unicode
245 Returns a formatted Unicode object from an unformatted
246 string or Unicode object with formatting specifications, and,
247 optionally, an iterable or an int or float.
248 Lets Python do the string formatting."""
250 from PyQt5.QtWidgets import QApplication
254 string = _preprocess_atom(string)
256 r = six.text_type(QApplication.translate("@default", string))
258 if isinstance(args[0], (dict, tuple)):
259 if string.count("%") == len(args[0]):
260 r = six.text_type(QApplication.translate("@default", string)) % args[0]
261 elif string.count("%") == 1 and string.count("%(") == 0:
262 r = six.text_type(QApplication.translate("@default", string))\
263 % _preprocess_atom(repr(args[0]))
264 elif string.count("%") == 0:
265 r = (six.text_type(QApplication.translate("@default", string)), args[0])
267 raise EficasException("ValueError: i18n.translate.tr: \
268 Improper input string formatting")
269 elif isinstance(args[0], (six.text_type, str, int, float, complex)):
270 if string.count("%") == 1:
271 r = six.text_type(QApplication.translate("@default", string))\
272 % _preprocess_atom(args[0])
274 r = six.text_type(QApplication.translate("@default", string)) +\
275 six.text_type(_preprocess_atom(args[0]))
276 elif isinstance(args[0], list) or args[0] is None:
277 if string.count("%") == 1:
278 r = six.text_type(QApplication.translate("@default", string))\
279 % _preprocess_atom(repr(args[0]))
281 r = (six.text_type(QApplication.translate("@default", string)), args[0])
284 raise EficasException("ValueError: i18n.translation.tr: \
285 Wrong type for formatted string \
286 arguments: %s" % type(args[0]))
288 raise EficasException("ValueError: i18n.translation.tr: \
289 Wrong formatted string arguments")
293 def tr_qt(string, *args):
294 """tr_qt(string, iterable-or-float-or-int) -> unicode
295 t_qtr(string) -> unicode
297 Returns a formatted string from an unformatted
298 Unicode string with formatting specifications, and,
299 optionally, an iterable or an int or float.
300 Lets PyQt4 do the string formatting. To this end,
301 a conversion from Python to Qt string formatting
302 syntax is performed."""
303 string = _preprocess_atom(string)
304 from PyQt5.QtWidgets import QApplication
306 r = QApplication.translate("@default", string)
308 r = QApplication.translate("@default", string)
309 if isinstance(args[0], (dict, tuple)):
310 if r.count("%") == len(args[0]):
311 if isinstance(args[0], dict):
312 r = _reformat_qstring_from_dict(r, args[0])
313 elif isinstance(args[0], tuple):
314 r = _reformat_qstring_from_tuple(r, args[0])
315 # XXX Pay attention to this: distinguish between tuple,
316 # dict and dict with key given in string.
317 elif r.count("%") in range(2) and r.count("%(") == 0:
318 r = _reformat_qstring_from_atom(r, _preproces_atom(repr(args[0])))
320 raise EficasException("ValueError: i18n.translation.tr_qt: \
321 Improper formatting string parameters")
322 elif isinstance(args[0], (six.text_type, str, int, float, complex)):
323 r = _reformat_qstring_from_atom(r, args[0])
324 elif isinstance(args[0], list):
325 r = _reformat_qstring_from_list(r, args[0])
326 elif args[0] is None:
327 r = _reformat_qstring_from_atom(r, _preprocess_string_from_atom(repr(args[0])))
329 raise EficasException("ValueError: i18n.translation.tr_qt: \
330 Wrong string formatting parameter types")
332 raise EficasException("ValueError: i18n.translation.tr_qt: \
333 Improper formatted string parameter set")
334 return six.text_type(r)
337 if __name__ == "__main__":
339 tr(sys.argv[1], *args)
340 tr_qt(sys.argv[1], *args)