Merge lp:~mathieu-julius/aeroo/openerp7.0.x into lp:~anybox/aeroo/openerp7.0.x

Proposed by Mathieu Vatel - Julius Network Solutions
Status: Merged
Merged at revision: 10
Proposed branch: lp:~mathieu-julius/aeroo/openerp7.0.x
Merge into: lp:~anybox/aeroo/openerp7.0.x
Diff against target: 353 lines (+113/-102)
1 file modified
report_aeroo/translate.py (+113/-102)
To merge this branch: bzr merge lp:~mathieu-julius/aeroo/openerp7.0.x
Reviewer Review Type Date Requested Status
Jean-Sébastien SUZANNE Approve
Review via email: mp+152150@code.launchpad.net

Description of the change

Change the translation method to fit the v7.0 translation process

To post a comment you must log in.
Revision history for this message
Jean-Sébastien SUZANNE (jssuzanne) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'report_aeroo/translate.py'
2--- report_aeroo/translate.py 2012-12-17 14:37:23 +0000
3+++ report_aeroo/translate.py 2013-03-07 11:12:20 +0000
4@@ -20,28 +20,44 @@
5 #
6 ##############################################################################
7
8+#import itertools
9+#import codecs
10+#import csv
11+#import inspect
12+#import locale
13+#import openerp.sql_db as sql_db
14+#import re
15+#import tarfile
16+#import tempfile
17+#import threading
18+#from datetime import datetime
19+#from openerp import SUPERUSER_ID
20+
21 import netsvc
22+import tools
23+from openerp.tools.translate import trans_parse_rml, trans_parse_xsl, extract_translatable_view_strings, WEB_TRANSLATION_COMMENT
24+import fnmatch
25 import os
26+import openerp.pooler as pooler
27 import logging
28-import pooler
29-import re
30-import tools
31-from tools.translate import trans_parse_rml, trans_parse_xsl, trans_parse_view
32-import itertools
33-import fnmatch
34+from babel.messages import extract
35 from os.path import join
36 from lxml import etree
37-from tools.misc import UpdateableStr
38+from openerp.tools.config import config
39+import tools.misc
40+from tools.misc import UpdateableStr, SKIPPED_ELEMENT_TYPES
41+import openerp.tools.osutil as osutil
42+
43+_logger = logging.getLogger(__name__)
44
45 def extend_trans_generate(lang, modules, cr):
46- logger = logging.getLogger('i18n')
47 dbname = cr.dbname
48
49 pool = pooler.get_pool(dbname)
50 trans_obj = pool.get('ir.translation')
51 model_data_obj = pool.get('ir.model.data')
52 uid = 1
53- l = pool.obj_list()
54+ l = pool.models.items()
55 l.sort()
56
57 query = 'SELECT name, model, res_id, module' \
58@@ -65,9 +81,14 @@
59 cr.execute(query, query_param)
60
61 _to_translate = []
62- def push_translation(module, type, name, id, source):
63- tuple = (module, source, name, id, type)
64- if source and tuple not in _to_translate:
65+ def push_translation(module, type, name, id, source, comments=None):
66+ tuple = (module, source, name, id, type, comments or [])
67+ # empty and one-letter terms are ignored, they probably are not meant to be
68+ # translated, and would be very hard to translate anyway.
69+ if not source or len(source.strip()) <= 1:
70+ _logger.debug("Ignoring empty or 1-letter source term: %r", tuple)
71+ return
72+ if tuple not in _to_translate:
73 _to_translate.append(tuple)
74
75 def encode(s):
76@@ -81,21 +102,22 @@
77 xml_name = "%s.%s" % (module, encode(xml_name))
78
79 if not pool.get(model):
80- logger.error("Unable to find object %r", model)
81+ _logger.error("Unable to find object %r", model)
82 continue
83
84 exists = pool.get(model).exists(cr, uid, res_id)
85 if not exists:
86- logger.warning("Unable to find object %r with id %d", model, res_id)
87+ _logger.warning("Unable to find object %r with id %d", model, res_id)
88 continue
89 obj = pool.get(model).browse(cr, uid, res_id)
90
91 if model=='ir.ui.view':
92 d = etree.XML(encode(obj.arch))
93- for t in trans_parse_view(d):
94+ for t in extract_translatable_view_strings(d):
95 push_translation(module, 'view', encode(obj.model), 0, t)
96 elif model=='ir.actions.wizard':
97 service_name = 'wizard.'+encode(obj.wiz_name)
98+ import openerp.netsvc as netsvc
99 if netsvc.Service._services.get(service_name):
100 obj2 = netsvc.Service._services[service_name]
101 for state_name, state_def in obj2.states.iteritems():
102@@ -113,7 +135,7 @@
103
104 # export fields
105 if not result.has_key('fields'):
106- logger.warning("res has no fields: %r", result)
107+ _logger.warning("res has no fields: %r", result)
108 continue
109 for field_name, field_def in result['fields'].iteritems():
110 res_name = name + ',' + field_name
111@@ -128,7 +150,7 @@
112 arch = result['arch']
113 if arch and not isinstance(arch, UpdateableStr):
114 d = etree.XML(arch)
115- for t in trans_parse_view(d):
116+ for t in extract_translatable_view_strings(d):
117 push_translation(module, 'wizard_view', name, 0, t)
118
119 # export button labels
120@@ -142,7 +164,7 @@
121 try:
122 field_name = encode(obj.name)
123 except AttributeError, exc:
124- logger.error("name error in %s: %s", xml_name, str(exc))
125+ _logger.error("name error in %s: %s", xml_name, str(exc))
126 continue
127 objmodel = pool.get(obj.model)
128 if not objmodel or not field_name in objmodel._columns:
129@@ -180,7 +202,7 @@
130 if obj.report_type == 'aeroo':
131 trans_ids = trans_obj.search(cr, uid, [('type', '=', 'report'),('res_id', '=', obj.id)])
132 for t in trans_obj.read(cr, uid, trans_ids, ['name','src']):
133- push_translation(module, "report", t['name'], xml_name, t['src'])
134+ push_translation(module, "report", t['name'], xml_name, encode(t['src']))
135 ##############################
136 else:
137 if obj.report_rml:
138@@ -193,7 +215,7 @@
139 report_type = "xsl"
140 if fname and obj.report_type in ('pdf', 'xsl'):
141 try:
142- report_file = tools.file_open(fname)
143+ report_file = misc.file_open(fname)
144 try:
145 d = etree.parse(report_file)
146 for t in parse_func(d.iter()):
147@@ -201,7 +223,7 @@
148 finally:
149 report_file.close()
150 except (IOError, etree.XMLSyntaxError):
151- logger.exception("couldn't export translation for report %s %s %s", name, report_type, fname)
152+ _logger.exception("couldn't export translation for report %s %s %s", name, report_type, fname)
153
154 for field_name,field_def in obj._table._columns.items():
155 if field_def.translate:
156@@ -217,33 +239,39 @@
157 cr.execute(query_models, query_param)
158
159 def push_constraint_msg(module, term_type, model, msg):
160- # Check presence of __call__ directly instead of using
161- # callable() because it will be deprecated as of Python 3.0
162 if not hasattr(msg, '__call__'):
163- push_translation(module, term_type, model, 0, encode(msg))
164-
165- for (model_id, model, module) in cr.fetchall():
166- module = encode(module)
167- model = encode(model)
168-
169+ push_translation(encode(module), term_type, encode(model), 0, encode(msg))
170+
171+ def push_local_constraints(module, model, cons_type='sql_constraints'):
172+ """Climb up the class hierarchy and ignore inherited constraints
173+ from other modules"""
174+ term_type = 'sql_constraint' if cons_type == 'sql_constraints' else 'constraint'
175+ msg_pos = 2 if cons_type == 'sql_constraints' else 1
176+ for cls in model.__class__.__mro__:
177+ if getattr(cls, '_module', None) != module:
178+ continue
179+ constraints = getattr(cls, '_local_' + cons_type, [])
180+ for constraint in constraints:
181+ push_constraint_msg(module, term_type, model._name, constraint[msg_pos])
182+
183+ for (_, model, module) in cr.fetchall():
184 model_obj = pool.get(model)
185
186 if not model_obj:
187- logging.getLogger("i18n").error("Unable to find object %r", model)
188+ _logger.error("Unable to find object %r", model)
189 continue
190
191- for constraint in getattr(model_obj, '_constraints', []):
192- push_constraint_msg(module, 'constraint', model, constraint[1])
193-
194- for constraint in getattr(model_obj, '_sql_constraints', []):
195- push_constraint_msg(module, 'sql_constraint', model, constraint[2])
196-
197- # parse source code for _() calls
198+ if model_obj._constraints:
199+ push_local_constraints(module, model_obj, 'constraints')
200+
201+ if model_obj._sql_constraints:
202+ push_local_constraints(module, model_obj, 'sql_constraints')
203+
204 def get_module_from_path(path, mod_paths=None):
205 if not mod_paths:
206 # First, construct a list of possible paths
207- def_path = os.path.abspath(os.path.join(tools.config['root_path'], 'addons')) # default addons path (base)
208- ad_paths= map(lambda m: os.path.abspath(m.strip()),tools.config['addons_path'].split(','))
209+ def_path = os.path.abspath(os.path.join(config['root_path'], 'addons')) # default addons path (base)
210+ ad_paths= map(lambda m: os.path.abspath(m.strip()),config['addons_path'].split(','))
211 mod_paths=[def_path]
212 for adp in ad_paths:
213 mod_paths.append(adp)
214@@ -261,9 +289,9 @@
215 installed_modids = modobj.search(cr, uid, [('state', '=', 'installed')])
216 installed_modules = map(lambda m: m['name'], modobj.read(cr, uid, installed_modids, ['name']))
217
218- root_path = os.path.join(tools.config['root_path'], 'addons')
219+ root_path = os.path.join(config['root_path'], 'addons')
220
221- apaths = map(os.path.abspath, map(str.strip, tools.config['addons_path'].split(',')))
222+ apaths = map(os.path.abspath, map(str.strip, config['addons_path'].split(',')))
223 if root_path in apaths:
224 path_list = apaths
225 else :
226@@ -271,83 +299,66 @@
227
228 # Also scan these non-addon paths
229 for bin_path in ['osv', 'report' ]:
230- path_list.append(os.path.join(tools.config['root_path'], bin_path))
231+ path_list.append(os.path.join(config['root_path'], bin_path))
232
233- logger.debug("Scanning modules at paths: ", path_list)
234+ _logger.debug("Scanning modules at paths: ", path_list)
235
236 mod_paths = []
237- join_dquotes = re.compile(r'([^\\])"[\s\\]*"', re.DOTALL)
238- join_quotes = re.compile(r'([^\\])\'[\s\\]*\'', re.DOTALL)
239- re_dquotes = re.compile(r'[^a-zA-Z0-9_]_\([\s]*"(.+?)"[\s]*?\)', re.DOTALL)
240- re_quotes = re.compile(r'[^a-zA-Z0-9_]_\([\s]*\'(.+?)\'[\s]*?\)', re.DOTALL)
241
242- def export_code_terms_from_file(fname, path, root, terms_type):
243+ def verified_module_filepaths(fname, path, root):
244 fabsolutepath = join(root, fname)
245 frelativepath = fabsolutepath[len(path):]
246+ display_path = "addons%s" % frelativepath
247 module = get_module_from_path(fabsolutepath, mod_paths=mod_paths)
248- is_mod_installed = module in installed_modules
249- if (('all' in modules) or (module in modules)) and is_mod_installed:
250- logger.debug("Scanning code of %s at module: %s", frelativepath, module)
251- src_file = tools.file_open(fabsolutepath, subdir='')
252+ if ('all' in modules or module in modules) and module in installed_modules:
253+ return module, fabsolutepath, frelativepath, display_path
254+ return None, None, None, None
255+
256+ def babel_extract_terms(fname, path, root, extract_method="python", trans_type='code',
257+ extra_comments=None, extract_keywords={'_': None}):
258+ module, fabsolutepath, _, display_path = verified_module_filepaths(fname, path, root)
259+ extra_comments = extra_comments or []
260+ if module:
261+ src_file = open(fabsolutepath, 'r')
262 try:
263- code_string = src_file.read()
264+ for lineno, message, comments in extract.extract(extract_method, src_file,
265+ keywords=extract_keywords):
266+ push_translation(module, trans_type, display_path, lineno,
267+ encode(message), comments + extra_comments)
268+ except Exception:
269+ _logger.exception("Failed to extract terms from %s", fabsolutepath)
270 finally:
271 src_file.close()
272- if module in installed_modules:
273- frelativepath = str("addons" + frelativepath)
274- ite = re_dquotes.finditer(code_string)
275- code_offset = 0
276- code_line = 1
277- for i in ite:
278- src = i.group(1)
279- if src.startswith('""'):
280- assert src.endswith('""'), "Incorrect usage of _(..) function (should contain only literal strings!) in file %s near: %s" % (frelativepath, src[:30])
281- src = src[2:-2]
282- else:
283- src = join_dquotes.sub(r'\1', src)
284- # try to count the lines from the last pos to our place:
285- code_line += code_string[code_offset:i.start(1)].count('\n')
286- # now, since we did a binary read of a python source file, we
287- # have to expand pythonic escapes like the interpreter does.
288- src = src.decode('string_escape')
289- push_translation(module, terms_type, frelativepath, code_line, encode(src))
290- code_line += i.group(1).count('\n')
291- code_offset = i.end() # we have counted newlines up to the match end
292-
293- ite = re_quotes.finditer(code_string)
294- code_offset = 0 #reset counters
295- code_line = 1
296- for i in ite:
297- src = i.group(1)
298- if src.startswith("''"):
299- assert src.endswith("''"), "Incorrect usage of _(..) function (should contain only literal strings!) in file %s near: %s" % (frelativepath, src[:30])
300- src = src[2:-2]
301- else:
302- src = join_quotes.sub(r'\1', src)
303- code_line += code_string[code_offset:i.start(1)].count('\n')
304- src = src.decode('string_escape')
305- push_translation(module, terms_type, frelativepath, code_line, encode(src))
306- code_line += i.group(1).count('\n')
307- code_offset = i.end() # we have counted newlines up to the match end
308
309 for path in path_list:
310- logger.debug("Scanning files of modules at %s", path)
311- for root, dummy, files in tools.osutil.walksymlinks(path):
312- for fname in itertools.chain(fnmatch.filter(files, '*.py')):
313- export_code_terms_from_file(fname, path, root, 'code')
314- for fname in itertools.chain(fnmatch.filter(files, '*.mako')):
315- export_code_terms_from_file(fname, path, root, 'report')
316-
317-
318- out = [["module","type","name","res_id","src","value"]] # header
319+ _logger.debug("Scanning files of modules at %s", path)
320+ for root, dummy, files in osutil.walksymlinks(path):
321+ for fname in fnmatch.filter(files, '*.py'):
322+ babel_extract_terms(fname, path, root)
323+ # mako provides a babel extractor: http://docs.makotemplates.org/en/latest/usage.html#babel
324+ for fname in fnmatch.filter(files, '*.mako'):
325+ babel_extract_terms(fname, path, root, 'mako', trans_type='report')
326+ # Javascript source files in the static/src/js directory, rest is ignored (libs)
327+ if fnmatch.fnmatch(root, '*/static/src/js*'):
328+ for fname in fnmatch.filter(files, '*.js'):
329+ babel_extract_terms(fname, path, root, 'javascript',
330+ extra_comments=[WEB_TRANSLATION_COMMENT],
331+ extract_keywords={'_t': None, '_lt': None})
332+ # QWeb template files
333+ if fnmatch.fnmatch(root, '*/static/src/xml*'):
334+ for fname in fnmatch.filter(files, '*.xml'):
335+ babel_extract_terms(fname, path, root, 'openerp.tools.translate:babel_extract_qweb',
336+ extra_comments=[WEB_TRANSLATION_COMMENT])
337+
338+ out = []
339 _to_translate.sort()
340 # translate strings marked as to be translated
341- for module, source, name, id, type in _to_translate:
342- trans = trans_obj._get_source(cr, uid, name, type, lang, source)
343- out.append([module, type, name, id, source, encode(trans) or ''])
344-
345+ for module, source, name, id, type, comments in _to_translate:
346+ trans = '' if not lang else trans_obj._get_source(cr, uid, name, type, lang, source)
347+ out.append([module, type, name, id, source, encode(trans) or '', comments])
348 return out
349
350 import sys
351 sys.modules['tools.translate'].trans_generate = extend_trans_generate
352
353+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

Subscribers

People subscribed via source and target branches