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 __future__ import absolute_import
27 from builtins import zip
28 from builtins import map
29 from builtins import range
32 from .eficas_exception import EficasException
33 #from Extensions.eficas_exception import EficasException
35 from six.moves import map
37 from six.moves import range
38 from six.moves import zip
39 regex=re.compile(r"% *[0-9]+")
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_to_unicode(string)
221 raise EficasException("TypeError: Expected number, string or\
224 def _str_to_unicode(string):
226 _str_to_unicode(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."""
249 from PyQt5.QtWidgets import QApplication
250 string = _preprocess_atom(string)
252 r = six.text_type(QApplication.translate("@default", string))
254 if isinstance(args[0], (dict, tuple)):
255 if string.count("%") == len(args[0]):
256 r = six.text_type(QApplication.translate("@default", string)) % args[0]
257 elif string.count("%") == 1 and string.count("%(") == 0:
258 r = six.text_type(QApplication.translate("@default", string))\
259 % _preprocess_atom(repr(args[0]))
260 elif string.count("%") == 0:
261 r = (six.text_type(QApplication.translate("@default", string)), args[0])
263 raise EficasException("ValueError: i18n.translate.tr: \
264 Improper input string formatting")
265 elif isinstance(args[0], (six.text_type, str, int, float, complex)):
266 if string.count("%") == 1:
267 r = six.text_type(QApplication.translate("@default", string))\
268 % _preprocess_atom(args[0])
270 r = six.text_type(QApplication.translate("@default", string)) +\
271 six.text_type(_preprocess_atom(args[0]))
272 elif isinstance(args[0], list) or args[0] is None:
273 if string.count("%") == 1:
274 r = six.text_type(QApplication.translate("@default", string))\
275 % _preprocess_atom(repr(args[0]))
277 r = (six.text_type(QApplication.translate("@default", string)), args[0])
280 raise EficasException("ValueError: i18n.translation.tr: \
281 Wrong type for formatted string \
282 arguments: %s" % type(args[0]))
284 raise EficasException("ValueError: i18n.translation.tr: \
285 Wrong formatted string arguments")
289 def tr_qt(string, *args):
290 """tr_qt(string, iterable-or-float-or-int) -> unicode
291 t_qtr(string) -> unicode
293 Returns a formatted string from an unformatted
294 Unicode string with formatting specifications, and,
295 optionally, an iterable or an int or float.
296 Lets PyQt4 do the string formatting. To this end,
297 a conversion from Python to Qt string formatting
298 syntax is performed."""
299 string = _preprocess_atom(string)
300 from PyQt5.QtWidgets import QApplication
302 r = QApplication.translate("@default", string)
304 r = QApplication.translate("@default", string)
305 if isinstance(args[0], (dict, tuple)):
306 if r.count("%") == len(args[0]):
307 if isinstance(args[0], dict):
308 r = _reformat_qstring_from_dict(r, args[0])
309 elif isinstance(args[0], tuple):
310 r = _reformat_qstring_from_tuple(r, args[0])
311 # XXX Pay attention to this: distinguish between tuple,
312 # dict and dict with key given in string.
313 elif r.count("%") in range(2) and r.count("%(") == 0:
314 r = _reformat_qstring_from_atom(r, _preproces_atom(repr(args[0])))
316 raise EficasException("ValueError: i18n.translation.tr_qt: \
317 Improper formatting string parameters")
318 elif isinstance(args[0], (six.text_type, str, int, float, complex)):
319 r = _reformat_qstring_from_atom(r, args[0])
320 elif isinstance(args[0], list):
321 r = _reformat_qstring_from_list(r, args[0])
322 elif args[0] is None:
323 r = _reformat_qstring_from_atom(r, _preprocess_string_from_atom(repr(args[0])))
325 raise EficasException("ValueError: i18n.translation.tr_qt: \
326 Wrong string formatting parameter types")
328 raise EficasException("ValueError: i18n.translation.tr_qt: \
329 Improper formatted string parameter set")
330 return six.text_type(r)
333 if __name__ == "__main__":
335 tr(sys.argv[1], *args)
336 tr_qt(sys.argv[1], *args)