Salome HOME
except and print
[tools/eficas.git] / Extensions / translationQT5.py
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
4 #
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)
8 # any later version.
9 #
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
13 # details.
14 #
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/>.
17 """
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,
21 tuples, or atoms.
22
23 ``PyQt4`` is currently supported.
24 """
25 from Extensions.eficas_exception import EficasException
26 import re
27 regex=re.compile(r"% *[0-9]+")
28
29
30
31
32 def _reformat_qstring_from_tuple(qstring, params):
33     """
34     _reformat_qstring_from_tuple(string, tuple) -> string
35
36     Module-internal method.
37     Returns a formatted string from an unformatted string
38     and a tuple specifying the parameters of the string.
39     """
40     from PyQt5.QtCore import QRegExp
41     reg = QRegExp("\%\.[1-9]{1,2}f")
42     for p, j in zip(params, range(len(params))):
43         try:
44             i += 1 + qstring[i + 1:].indexOf("%")
45         except NameError:
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]))
55         else:
56             qstring = qstring[:i + 1].replace("%", "%" + unicode(1 + j)) + \
57                       qstring[i + 2:]
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]).\
64                 #                                         split('.')[1])))
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]))
73             else:
74                 raise EficasException("TypeError: i18n.translation: \
75                                       Unicode, list or number expected!")
76     return qstring
77
78 def _reformat_qstring_from_dict(qstring, params):
79     """
80     _reformat_qstring_from_dict(string, dict) -> string
81
82     Module-internal method.
83     Returns a formatted string from an unformatted string
84     and a dictionary specifying the parameters of the string.
85     """
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)
90         if p_index != -1:
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]), \
95             #                                             'f', \
96             #                                             int(precision)))
97             qstring = qstring.replace("%(" + p + ")." + precision + "f","%" + unicode(1 + j))
98             qstring=regex.sub("{}",qstring)
99             qstring = qstring.format(float(params[p]))
100         else:
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]))
117             else:
118                 raise EficasException("TypeError: i18n.translation: \
119                                       Improper string parameter type.")
120     return qstring
121
122 def _reformat_qstring_from_atom(qstring, params):
123     """
124     _reformat_qstring_from_atom(string, int-or-float) -> string
125
126     Module-internal method.
127     Returns a formatted string from an unformatted string
128     and an integer or a float specifying the parameter of 
129     the string.
130     """
131     from PyQt5.QtCore import QRegExp
132     reg = QRegExp("\%\.[1-9]{1,2}f")
133     if qstring.count("%") == 0:
134         qstring.append("%1")
135         try:
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',\
151             #                                     int(precision)))
152         else:
153             qstring = qstring[:i + 1].replace("%", "%1") + \
154                       qstring[i + 2:]
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).\
160                 #                                         split('.')[1])))
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)
166             else:
167                 raise EficasException("TypeError: i18n.translation: Unicode, \
168                                       string or number expected!")
169     return qstring
170
171 def _reformat_qstring_from_list(qstring, params):
172     """
173     _reformat_qstring_from_list(string, tuple) -> string
174
175     Module-internal method.
176     Returns a formatted string from an unformatted string
177     and a list whose concatenation specifies the parameter 
178     of the string.
179     """
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:
188         qstring.append("%1")
189         qstring=regex.sub("{}",qstring)
190         qstring = qstring.format(u' '.join(map(unicode, params)))
191     else:
192         raise EficasException("ValueError: i18n.translation: \
193                               At most one '%' expected!")
194     return qstring
195
196 def _preprocess_atom(string):
197     """
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.
203     """
204     if isinstance(string, (unicode, int, float, complex)):
205         return string
206     elif isinstance(string, str):
207         return _str_to_unicode(string)
208     else:
209         raise EficasException("TypeError: Expected number, string or\
210                               Unicode object!")
211
212 def _str_to_unicode(string):
213     """
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 
217     Latin-9 encoded.
218     """
219     try:
220         string = unicode(string, "utf-8")
221     except UnicodeDecodeError:
222         try:
223             string = unicode(string, "iso-8859-15")
224         except UnicodeDecodeError:
225             raise EficasException("UnicodeDecodeError: UTF-8, Latin-1 \
226                                   or Latin-9 expected")
227     return string
228
229 def tr(string, *args):
230     """tr(string-or-unicode, iterable-or-float-or-int) -> unicode
231        tr(string-or-unicode) -> unicode
232        
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)
239     if len(args) == 0:
240         r = unicode(QApplication.translate("@default", string))
241     elif len(args) == 1:
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])
250             else:
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])
257             else:
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]))
264             else:
265                 r = (unicode(QApplication.translate("@default", string)), args[0])
266
267         else:
268             raise EficasException("ValueError: i18n.translation.tr: \
269                                   Wrong type for formatted string \
270                                   arguments: %s" % type(args[0]))
271     else:
272         raise EficasException("ValueError: i18n.translation.tr: \
273                               Wrong formatted string arguments")
274     return r
275
276
277 def tr_qt(string, *args):
278     """tr_qt(string, iterable-or-float-or-int) -> unicode
279        t_qtr(string) -> unicode
280        
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
289     if len(args) == 0:
290         r = QApplication.translate("@default", string)
291     elif len(args) == 1:
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])))
303             else:
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])))
312         else:
313             raise EficasException("ValueError: i18n.translation.tr_qt: \
314                                   Wrong string formatting parameter types")
315     else:
316         raise EficasException("ValueError: i18n.translation.tr_qt: \
317                               Improper formatted string parameter set")
318     return unicode(r)
319
320
321 if __name__ == "__main__":
322     import sys
323     tr(sys.argv[1], *args)
324     tr_qt(sys.argv[1], *args)