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
27 regex=re.compile(r"% *[0-9]+")
32 def _reformat_qstring_from_tuple(qstring, params):
34 _reformat_qstring_from_tuple(string, tuple) -> string
36 Module-internal method.
37 Returns a formatted string from an unformatted string
38 and a tuple specifying the parameters of the string.
40 from PyQt5.QtCore import QRegExp
41 reg = QRegExp("\%\.[1-9]{1,2}f")
42 for p, j in zip(params, range(len(params))):
44 i += 1 + qstring[i + 1:].indexOf("%")
46 i = qstring.indexOf("%")
47 if i == reg.indexIn(qstring):
48 precision = reg.cap(0).split('.')[1].split('f')[0]
49 qstring = qstring[:i + 2 + len(precision)].\
50 replace("%." + precision, "%" + unicode(1 + j)) + \
51 qstring[i + 3 + len(precision):]
52 qstring=regex.sub("{}",qstring)
53 #qstring = qstring.format(QString.number(float(params[j]), 'f', int(precision)))
54 qstring = qstring.format(float(params[j]))
56 qstring = qstring[:i + 1].replace("%", "%" + unicode(1 + j)) + \
58 if isinstance(params[j], unicode):
59 qstring=regex.sub("{}",qstring)
60 qstring = qstring.format(params[j])
61 elif isinstance(params[j], float):
62 qstring=regex.sub("{}",qstring)
63 #qstring = qstring.format(QString.number(params[j], 'f',\ len(unicode(params[j]).\
65 qstring = qstring.format(params[j])
66 elif isinstance(params[j], int):
67 qstring=regex.sub("{}",qstring)
68 #qstring = qstring.format(QString.number(params[j], 10))
69 qstring = qstring.format(params[j])
70 elif isinstance(params[j], list):
71 qstring=regex.sub("{}",qstring)
72 qstring = qstring.format(repr(params[j]))
74 raise EficasException("TypeError: i18n.translation: \
75 Unicode, list or number expected!")
78 def _reformat_qstring_from_dict(qstring, params):
80 _reformat_qstring_from_dict(string, dict) -> string
82 Module-internal method.
83 Returns a formatted string from an unformatted string
84 and a dictionary specifying the parameters of the string.
86 from PyQt5.QtCore import QRegExp
87 for p, j in zip(params, range(len(params))):
88 p_reg = QRegExp("\%\("+ p + "\)\.[1-9]{1,2}f")
89 p_index = p_reg.indexIn(qstring)
91 precision = p_reg.cap(0).split('.')[1].split('f')[0]
92 #qstring = qstring.replace("%(" + p + ")." + precision + "f",\
93 # "%" + unicode(1 + j)).\
94 # arg(QString.number(float(params[p]), \
97 qstring = qstring.replace("%(" + p + ")." + precision + "f","%" + unicode(1 + j))
98 qstring=regex.sub("{}",qstring)
99 qstring = qstring.format(float(params[p]))
101 qstring.remove(QRegExp("\\)[sdf]{1}"))
102 qstring = qstring.replace("%(" + p, "%" + unicode(1 + j))
103 if isinstance(params[p], unicode):
104 qstring=regex.sub("{}",qstring)
105 qstring = qstring.format(params[p])
106 elif isinstance(params[p], float):
107 qstring=regex.sub("{}",qstring)
108 qstring = qstring.format(params[p])
109 #qstring = qstring.format(QString.number(params[p], 'f', \
110 # len(unicode(params[p]).split('.')[1])))
111 elif isinstance(params[p], int):
112 qstring=regex.sub("{}",qstring)
113 qstring = qstring.format(params[p])
114 elif isinstance(params[p], list):
115 qstring=regex.sub("{}",qstring)
116 qstring = qstring.format(repr(params[p]))
118 raise EficasException("TypeError: i18n.translation: \
119 Improper string parameter type.")
122 def _reformat_qstring_from_atom(qstring, params):
124 _reformat_qstring_from_atom(string, int-or-float) -> string
126 Module-internal method.
127 Returns a formatted string from an unformatted string
128 and an integer or a float specifying the parameter of
131 from PyQt5.QtCore import QRegExp
132 reg = QRegExp("\%\.[1-9]{1,2}f")
133 if qstring.count("%") == 0:
136 qstring=regex.sub("{}",qstring)
137 qstring = qstring.format(unicode(params))
138 except AttributeError:
139 qstring=regex.sub("{}",qstring)
140 qstring = qstring.format(params)
141 elif qstring.count("%") == 1:
142 i = qstring.indexOf("%")
143 if i == reg.indexIn(qstring):
144 precision = reg.cap(0).split('.')[1].split('f')[0]
145 qstring = qstring[: i + 2 + len(precision)].\
146 replace("%." + precision, "%1") + \
147 qstring[i + 3 + len(precision):]
148 qstring=regex.sub("{}",qstring)
149 qstring = qstring.format((params))
150 #qstring = qstring.format(QString.number(float(params), 'f',\
153 qstring = qstring[:i + 1].replace("%", "%1") + \
155 if isinstance(params, (unicode, str)):
156 qstring = qstring.format(_preprocess_atom(params))
157 elif isinstance(params, float):
158 #qstring = qstring.format(QString.number(params, 'f', \
159 # len(unicode(params).\
161 qstring = qstring.format(params)
162 elif isinstance(params, int):
163 qstring=regex.sub("{}",qstring)
164 #qstring = qstring.format(QString.number(params, 10))
165 qstring = qstring.format(params)
167 raise EficasException("TypeError: i18n.translation: Unicode, \
168 string or number expected!")
171 def _reformat_qstring_from_list(qstring, params):
173 _reformat_qstring_from_list(string, tuple) -> string
175 Module-internal method.
176 Returns a formatted string from an unformatted string
177 and a list whose concatenation specifies the parameter
180 # XXX to add further functionality, e.g. list processing
181 # when ``%`` not at the end.
182 if qstring.count("%") == 1 and \
183 unicode(qstring).strip()[:-1].endswith("%"):
184 qstring = qstring[:qstring.indexOf("%") + 1].append("1")
185 qstring=regex.sub("{}",qstring)
186 qstring = qstring.format(u' '.join(map(unicode, params)))
187 elif qstring.count("%") == 0:
189 qstring=regex.sub("{}",qstring)
190 qstring = qstring.format(u' '.join(map(unicode, params)))
192 raise EficasException("ValueError: i18n.translation: \
193 At most one '%' expected!")
196 def _preprocess_atom(string):
198 _preprocess_atom(string-or-number-or-unicode) -> unicode
199 Test if input is a Unicode object or a number; if so, then return it;
200 otherwise, test if the input is a string; if so, then try to create
201 a Unicode object out of it. To this end, assume the string is encoded
202 in utf-8; if this fails, then assume the string is encoded in Latin-9.
204 if isinstance(string, (unicode, int, float, complex)):
206 elif isinstance(string, str):
207 return _str_to_unicode(string)
209 raise EficasException("TypeError: Expected number, string or\
212 def _str_to_unicode(string):
214 _str_to_unicode(string) -> unicode
215 Tries to create a Unicode object out of the input string; assumes
216 the string is UTF-8 encoded; if not, then assume the string is
220 string = unicode(string, "utf-8")
221 except UnicodeDecodeError:
223 string = unicode(string, "iso-8859-15")
224 except UnicodeDecodeError:
225 raise EficasException("UnicodeDecodeError: UTF-8, Latin-1 \
226 or Latin-9 expected")
229 def tr(string, *args):
230 """tr(string-or-unicode, iterable-or-float-or-int) -> unicode
231 tr(string-or-unicode) -> unicode
233 Returns a formatted Unicode object from an unformatted
234 string or Unicode object with formatting specifications, and,
235 optionally, an iterable or an int or float.
236 Lets Python do the string formatting."""
237 from PyQt5.QtWidgets import QApplication
238 string = _preprocess_atom(string)
240 r = unicode(QApplication.translate("@default", string))
242 if isinstance(args[0], (dict, tuple)):
243 if string.count("%") == len(args[0]):
244 r = unicode(QApplication.translate("@default", string)) % args[0]
245 elif string.count("%") == 1 and string.count("%(") == 0:
246 r = unicode(QApplication.translate("@default", string))\
247 % _preprocess_atom(repr(args[0]))
248 elif string.count("%") == 0:
249 r = (unicode(QApplication.translate("@default", string)), args[0])
251 raise EficasException("ValueError: i18n.translate.tr: \
252 Improper input string formatting")
253 elif isinstance(args[0], (unicode, str, int, float, complex)):
254 if string.count("%") == 1:
255 r = unicode(QApplication.translate("@default", string))\
256 % _preprocess_atom(args[0])
258 r = unicode(QApplication.translate("@default", string)) +\
259 unicode(_preprocess_atom(args[0]))
260 elif isinstance(args[0], list) or args[0] is None:
261 if string.count("%") == 1:
262 r = unicode(QApplication.translate("@default", string))\
263 % _preprocess_atom(repr(args[0]))
265 r = (unicode(QApplication.translate("@default", string)), args[0])
268 raise EficasException("ValueError: i18n.translation.tr: \
269 Wrong type for formatted string \
270 arguments: %s" % type(args[0]))
272 raise EficasException("ValueError: i18n.translation.tr: \
273 Wrong formatted string arguments")
277 def tr_qt(string, *args):
278 """tr_qt(string, iterable-or-float-or-int) -> unicode
279 t_qtr(string) -> unicode
281 Returns a formatted string from an unformatted
282 Unicode string with formatting specifications, and,
283 optionally, an iterable or an int or float.
284 Lets PyQt4 do the string formatting. To this end,
285 a conversion from Python to Qt string formatting
286 syntax is performed."""
287 string = _preprocess_atom(string)
288 from PyQt5.QtWidgets import QApplication
290 r = QApplication.translate("@default", string)
292 r = QApplication.translate("@default", string)
293 if isinstance(args[0], (dict, tuple)):
294 if r.count("%") == len(args[0]):
295 if isinstance(args[0], dict):
296 r = _reformat_qstring_from_dict(r, args[0])
297 elif isinstance(args[0], tuple):
298 r = _reformat_qstring_from_tuple(r, args[0])
299 # XXX Pay attention to this: distinguish between tuple,
300 # dict and dict with key given in string.
301 elif r.count("%") in range(2) and r.count("%(") == 0:
302 r = _reformat_qstring_from_atom(r, _preproces_atom(repr(args[0])))
304 raise EficasException("ValueError: i18n.translation.tr_qt: \
305 Improper formatting string parameters")
306 elif isinstance(args[0], (unicode, str, int, float, complex)):
307 r = _reformat_qstring_from_atom(r, args[0])
308 elif isinstance(args[0], list):
309 r = _reformat_qstring_from_list(r, args[0])
310 elif args[0] is None:
311 r = _reformat_qstring_from_atom(r, _preprocess_string_from_atom(repr(args[0])))
313 raise EficasException("ValueError: i18n.translation.tr_qt: \
314 Wrong string formatting parameter types")
316 raise EficasException("ValueError: i18n.translation.tr_qt: \
317 Improper formatted string parameter set")
321 if __name__ == "__main__":
323 tr(sys.argv[1], *args)
324 tr_qt(sys.argv[1], *args)