Salome HOME
1er mise en coherence avec la 7_6
[tools/eficas.git] / Extensions / translation.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 def _reformat_qstring_from_tuple(qstring, params):
27     """
28     _reformat_qstring_from_tuple(QString, tuple) -> QString
29
30     Module-internal method.
31     Returns a formatted QString from an unformatted QString
32     and a tuple specifying the parameters of the QString.
33     """
34     from PyQt4.QtCore import QRegExp, QString
35     reg = QRegExp("\%\.[1-9]{1,2}f")
36     for p, j in zip(params, range(len(params))):
37         try:
38             i += 1 + qstring[i + 1:].indexOf("%")
39         except NameError:
40             i = qstring.indexOf("%")
41         if i == reg.indexIn(qstring):
42             precision = reg.cap(0).split('.')[1].split('f')[0]
43             qstring = qstring[:i + 2 + len(precision)].\
44                       replace("%." + precision, "%" + unicode(1 + j)) + \
45                       qstring[i + 3 + len(precision):]
46             qstring = qstring.arg(QString.number(float(params[j]), 'f',\
47                                                  int(precision)))
48         else:
49             qstring = qstring[:i + 1].replace("%", "%" + unicode(1 + j)) + \
50                       qstring[i + 2:]
51             if isinstance(params[j], unicode):
52                 qstring = qstring.arg(params[j])
53             elif isinstance(params[j], float):
54                 qstring = qstring.arg(QString.number(params[j], 'f',\
55                                                      len(unicode(params[j]).\
56                                                          split('.')[1])))
57             elif isinstance(params[j], int):
58                 qstring = qstring.arg(QString.number(params[j], 10))
59             elif isinstance(params[j], list):
60                 qstring = qstring.arg(repr(params[j]))
61             else:
62                 raise EficasException("TypeError: i18n.translation: \
63                                       Unicode, list or number expected!")
64     return qstring
65
66 def _reformat_qstring_from_dict(qstring, params):
67     """
68     _reformat_qstring_from_dict(QString, dict) -> QString
69
70     Module-internal method.
71     Returns a formatted QString from an unformatted QString
72     and a dictionary specifying the parameters of the QString.
73     """
74     from PyQt4.QtCore import QRegExp, QString
75     for p, j in zip(params, range(len(params))):
76         p_reg = QRegExp("\%\("+ p + "\)\.[1-9]{1,2}f")
77         p_index = p_reg.indexIn(qstring)
78         if p_index != -1:
79             precision = p_reg.cap(0).split('.')[1].split('f')[0]
80             qstring = qstring.replace("%(" + p + ")." + precision + "f",\
81                                       "%" + unicode(1 + j)).\
82                                       arg(QString.number(float(params[p]), \
83                                                          'f', \
84                                                          int(precision)))
85         else:
86             qstring.remove(QRegExp("\\)[sdf]{1}"))
87             qstring = qstring.replace("%(" + p, "%" + unicode(1 + j))
88             if isinstance(params[p], unicode):
89                 qstring = qstring.arg(params[p])
90             elif isinstance(params[p], float):
91                 qstring = qstring.arg(QString.number(params[p], 'f', \
92                           len(unicode(params[p]).split('.')[1])))
93             elif isinstance(params[p], int):
94                 qstring = qstring.arg(QString.number(params[p], 10))
95             elif isinstance(params[p], list):
96                 qstring = qstring.arg(repr(params[p]))
97             else:
98                 raise EficasException("TypeError: i18n.translation: \
99                                       Improper string parameter type.")
100     return qstring
101
102 def _reformat_qstring_from_atom(qstring, params):
103     """
104     _reformat_qstring_from_atom(QString, int-or-float) -> QString
105
106     Module-internal method.
107     Returns a formatted QString from an unformatted QString
108     and an integer or a float specifying the parameter of 
109     the QString.
110     """
111     from PyQt4.QtCore import QRegExp, QString
112     reg = QRegExp("\%\.[1-9]{1,2}f")
113     if qstring.count("%") == 0:
114         qstring.append("%1")
115         try:
116             qstring = qstring.arg(unicode(params))
117         except AttributeError:
118             qstring = qstring.arg(params)
119     elif qstring.count("%") == 1:
120         i = qstring.indexOf("%")
121         if i == reg.indexIn(qstring):
122             precision = reg.cap(0).split('.')[1].split('f')[0]
123             qstring = qstring[: i + 2 + len(precision)].\
124                       replace("%." + precision, "%1") + \
125                       qstring[i + 3 + len(precision):]
126             qstring = qstring.arg(QString.number(float(params), 'f',\
127                                                  int(precision)))
128         else:
129             qstring = qstring[:i + 1].replace("%", "%1") + \
130                       qstring[i + 2:]
131             if isinstance(params, (unicode, str)):
132                 qstring = qstring.arg(_preprocess_atom(params))
133             elif isinstance(params, float):
134                 qstring = qstring.arg(QString.number(params, 'f', \
135                                                      len(unicode(params).\
136                                                          split('.')[1])))
137             elif isinstance(params, int):
138                 qstring = qstring.arg(QString.number(params, 10))
139             else:
140                 raise EficasException("TypeError: i18n.translation: Unicode, \
141                                       string or number expected!")
142     return qstring
143
144 def _reformat_qstring_from_list(qstring, params):
145     """
146     _reformat_qstring_from_list(QString, tuple) -> QString
147
148     Module-internal method.
149     Returns a formatted QString from an unformatted QString
150     and a list whose concatenation specifies the parameter 
151     of the QString.
152     """
153     # XXX to add further functionality, e.g. list processing
154     # when ``%`` not at the end.
155     if qstring.count("%") == 1 and \
156        unicode(qstring).strip()[:-1].endswith("%"):
157         qstring = qstring[:qstring.indexOf("%") + 1].append("1")
158         qstring = qstring.arg(u' '.join(map(unicode, params)))
159     elif qstring.count("%") == 0:
160         qstring.append("%1")
161         qstring = qstring.arg(u' '.join(map(unicode, params)))
162     else:
163         raise EficasException("ValueError: i18n.translation: \
164                               At most one '%' expected!")
165     return qstring
166
167 def _preprocess_atom(string):
168     """
169     _preprocess_atom(string-or-number-or-unicode) -> unicode
170     Test if input is a Unicode object or a number; if so, then return it; 
171     otherwise, test if the input is a string; if so, then try to create 
172     a Unicode object out of it. To this end, assume the string is encoded 
173     in utf-8; if this fails, then assume the string is encoded in Latin-9.
174     """
175     if isinstance(string, (unicode, int, float, complex)):
176         return string
177     elif isinstance(string, str):
178         return _str_to_unicode(string)
179     else:
180         raise EficasException("TypeError: Expected number, string or\
181                               Unicode object!")
182
183 def _str_to_unicode(string):
184     """
185     _str_to_unicode(string) -> unicode
186     Tries to create a Unicode object out of the input string; assumes 
187     the string is UTF-8 encoded; if not, then assume the string is 
188     Latin-9 encoded.
189     """
190     try:
191         string = unicode(string, "utf-8")
192     except UnicodeDecodeError:
193         try:
194             string = unicode(string, "iso-8859-15")
195         except UnicodeDecodeError:
196             raise EficasException("UnicodeDecodeError: UTF-8, Latin-1 \
197                                   or Latin-9 expected")
198     return string
199
200 def tr(string, *args):
201     """tr(string-or-unicode, iterable-or-float-or-int) -> unicode
202        tr(string-or-unicode) -> unicode
203        
204        Returns a formatted Unicode object from an unformatted 
205        string or Unicode object with formatting specifications, and, 
206        optionally, an iterable or an int or float.
207        Lets Python do the string formatting."""
208     from PyQt4.QtGui import QApplication
209     string = _preprocess_atom(string)
210     if len(args) == 0:
211         r = unicode(QApplication.translate("@default", string))
212     elif len(args) == 1:
213         if isinstance(args[0], (dict, tuple)):
214             if string.count("%") == len(args[0]):
215                 r = unicode(QApplication.translate("@default", string)) % args[0]
216             elif string.count("%") == 1 and string.count("%(") == 0:
217                 r = unicode(QApplication.translate("@default", string))\
218                     % _preprocess_atom(repr(args[0]))
219             elif string.count("%") == 0:
220                 r = (unicode(QApplication.translate("@default", string)), args[0])
221             else:
222                 raise EficasException("ValueError: i18n.translate.tr: \
223                                       Improper input string formatting")
224         elif isinstance(args[0], (unicode, str, int, float, complex)):
225             if string.count("%") == 1:
226                 r = unicode(QApplication.translate("@default", string))\
227                     % _preprocess_atom(args[0])
228             else:
229                 r = unicode(QApplication.translate("@default", string)) +\
230                     unicode(_preprocess_atom(args[0]))
231         elif isinstance(args[0], list) or args[0] is None:
232             if string.count("%") == 1:
233                 r = unicode(QApplication.translate("@default", string))\
234                     % _preprocess_atom(repr(args[0]))
235             else:
236                 r = (unicode(QApplication.translate("@default", string)), args[0])
237
238         else:
239             raise EficasException("ValueError: i18n.translation.tr: \
240                                   Wrong type for formatted string \
241                                   arguments: %s" % type(args[0]))
242     else:
243         raise EficasException("ValueError: i18n.translation.tr: \
244                               Wrong formatted string arguments")
245     return r
246
247
248 def tr_qt(string, *args):
249     """tr_qt(string, iterable-or-float-or-int) -> unicode
250        t_qtr(string) -> unicode
251        
252        Returns a formatted string from an unformatted 
253        Unicode string with formatting specifications, and, 
254        optionally, an iterable or an int or float.
255        Lets PyQt4 do the string formatting. To this end,
256        a conversion from Python to Qt string formatting
257        syntax is performed."""
258     string = _preprocess_atom(string)
259     from PyQt4.QtGui import QApplication
260     if len(args) == 0:
261         r = QApplication.translate("@default", string)
262     elif len(args) == 1:
263         r = QApplication.translate("@default", string)
264         if isinstance(args[0], (dict, tuple)):
265             if r.count("%") == len(args[0]):
266                 if isinstance(args[0], dict):
267                     r = _reformat_qstring_from_dict(r, args[0])
268                 elif isinstance(args[0], tuple):
269                     r = _reformat_qstring_from_tuple(r, args[0])
270             # XXX Pay attention to this: distinguish between tuple, 
271             # dict and dict with key given in string.
272             elif r.count("%") in range(2) and r.count("%(") == 0:
273                 r = _reformat_qstring_from_atom(r, _preproces_atom(repr(args[0])))
274             else:
275                 raise EficasException("ValueError: i18n.translation.tr_qt: \
276                                       Improper formatting string parameters")
277         elif isinstance(args[0], (unicode, str, int, float, complex)):
278             r = _reformat_qstring_from_atom(r, args[0])
279         elif isinstance(args[0], list):
280             r = _reformat_qstring_from_list(r, args[0])
281         elif args[0] is None:
282             r = _reformat_qstring_from_atom(r, _preprocess_string_from_atom(repr(args[0])))
283         else:
284             raise EficasException("ValueError: i18n.translation.tr_qt: \
285                                   Wrong string formatting parameter types")
286     else:
287         raise EficasException("ValueError: i18n.translation.tr_qt: \
288                               Improper formatted string parameter set")
289 #    print r
290     return unicode(r)
291
292
293 if __name__ == "__main__":
294     import sys
295     tr(sys.argv[1], *args)
296     tr_qt(sys.argv[1], *args)