Salome HOME
bug
[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 __future__ import absolute_import
26 try : 
27   from builtins import zip
28   from builtins import map
29   from builtins import range
30 except : 
31   pass
32 from .eficas_exception import EficasException
33 #from Extensions.eficas_exception import EficasException
34 import re
35 from six.moves import map
36 import six
37 from six.moves import range
38 from six.moves import zip
39 regex=re.compile(r"% *[0-9]+")
40
41
42
43
44 def _reformat_qstring_from_tuple(qstring, params):
45     """
46     _reformat_qstring_from_tuple(string, tuple) -> string
47
48     Module-internal method.
49     Returns a formatted string from an unformatted string
50     and a tuple specifying the parameters of the string.
51     """
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)))):
55         try:
56             i += 1 + qstring[i + 1:].indexOf("%")
57         except NameError:
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]))
67         else:
68             qstring = qstring[:i + 1].replace("%", "%" + six.text_type(1 + j)) + \
69                       qstring[i + 2:]
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]).\
76                 #                                         split('.')[1])))
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]))
85             else:
86                 raise EficasException("TypeError: i18n.translation: \
87                                       Unicode, list or number expected!")
88     return qstring
89
90 def _reformat_qstring_from_dict(qstring, params):
91     """
92     _reformat_qstring_from_dict(string, dict) -> string
93
94     Module-internal method.
95     Returns a formatted string from an unformatted string
96     and a dictionary specifying the parameters of the string.
97     """
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)
102         if p_index != -1:
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]), \
107             #                                             'f', \
108             #                                             int(precision)))
109             qstring = qstring.replace("%(" + p + ")." + precision + "f","%" + six.text_type(1 + j))
110             qstring=regex.sub("{}",qstring)
111             qstring = qstring.format(float(params[p]))
112         else:
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]))
129             else:
130                 raise EficasException("TypeError: i18n.translation: \
131                                       Improper string parameter type.")
132     return qstring
133
134 def _reformat_qstring_from_atom(qstring, params):
135     """
136     _reformat_qstring_from_atom(string, int-or-float) -> string
137
138     Module-internal method.
139     Returns a formatted string from an unformatted string
140     and an integer or a float specifying the parameter of 
141     the string.
142     """
143     from PyQt5.QtCore import QRegExp
144     reg = QRegExp("\%\.[1-9]{1,2}f")
145     if qstring.count("%") == 0:
146         qstring.append("%1")
147         try:
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',\
163             #                                     int(precision)))
164         else:
165             qstring = qstring[:i + 1].replace("%", "%1") + \
166                       qstring[i + 2:]
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).\
172                 #                                         split('.')[1])))
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)
178             else:
179                 raise EficasException("TypeError: i18n.translation: Unicode, \
180                                       string or number expected!")
181     return qstring
182
183 def _reformat_qstring_from_list(qstring, params):
184     """
185     _reformat_qstring_from_list(string, tuple) -> string
186
187     Module-internal method.
188     Returns a formatted string from an unformatted string
189     and a list whose concatenation specifies the parameter 
190     of the string.
191     """
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:
200         qstring.append("%1")
201         qstring=regex.sub("{}",qstring)
202         qstring = qstring.format(u' '.join(map(six.text_type, params)))
203     else:
204         raise EficasException("ValueError: i18n.translation: \
205                               At most one '%' expected!")
206     return qstring
207
208 def _preprocess_atom(string):
209     """
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.
215     """
216     if isinstance(string, (six.text_type, int, float, complex)):
217         return string
218     elif isinstance(string, str):
219         return _str_toUnicode(string)
220     else:
221         raise EficasException("TypeError: Expected number, string or\
222                               Unicode object!")
223
224 def _str_toUnicode(string):
225     """
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 
229     Latin-9 encoded.
230     """
231     try:
232         string = six.text_type(string, "utf-8")
233     except UnicodeDecodeError:
234         try:
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")
239     return string
240
241 def tr(string, *args):
242     """tr(string-or-unicode, iterable-or-float-or-int) -> unicode
243        tr(string-or-unicode) -> unicode
244        
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)
251     if len(args) == 0:
252         r = six.text_type(QApplication.translate("@default", string))
253     elif len(args) == 1:
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])
262             else:
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])
269             else:
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]))
276             else:
277                 r = (six.text_type(QApplication.translate("@default", string)), args[0])
278
279         else:
280             raise EficasException("ValueError: i18n.translation.tr: \
281                                   Wrong type for formatted string \
282                                   arguments: %s" % type(args[0]))
283     else:
284         raise EficasException("ValueError: i18n.translation.tr: \
285                               Wrong formatted string arguments")
286     return r
287
288
289 def tr_qt(string, *args):
290     """tr_qt(string, iterable-or-float-or-int) -> unicode
291        t_qtr(string) -> unicode
292        
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
301     if len(args) == 0:
302         r = QApplication.translate("@default", string)
303     elif len(args) == 1:
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])))
315             else:
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])))
324         else:
325             raise EficasException("ValueError: i18n.translation.tr_qt: \
326                                   Wrong string formatting parameter types")
327     else:
328         raise EficasException("ValueError: i18n.translation.tr_qt: \
329                               Improper formatted string parameter set")
330     return six.text_type(r)
331
332
333 if __name__ == "__main__":
334     import sys
335     tr(sys.argv[1], *args)
336     tr_qt(sys.argv[1], *args)