Move workflow method in ModelWorkflow Move workflow service in workflow module Remove Service and LocalService Remove web_service and use a dispatcher in protocols New netrpc/xmlrpc syntax to be easier to introspect
1121 lines
43 KiB
Python
1121 lines
43 KiB
Python
#This file is part of Tryton. The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms.
|
|
"Translation"
|
|
import base64
|
|
try:
|
|
import cStringIO as StringIO
|
|
except ImportError:
|
|
import StringIO
|
|
import zipfile
|
|
from xml import dom
|
|
from xml.dom import minidom
|
|
from difflib import SequenceMatcher
|
|
import csv
|
|
from trytond.osv import fields, OSV, Cacheable
|
|
from trytond.wizard import Wizard, WizardOSV
|
|
from trytond import tools
|
|
|
|
TRANSLATION_TYPE = [
|
|
('field', 'Field'),
|
|
('model', 'Model'),
|
|
('odt', 'ODT'),
|
|
('selection', 'Selection'),
|
|
('view', 'View'),
|
|
('wizard_button', 'Wizard Button'),
|
|
('help', 'Help'),
|
|
('error', 'Error'),
|
|
]
|
|
|
|
HEADER = ['type', 'name', 'res_id', 'src', 'value', 'fuzzy']
|
|
|
|
|
|
class TRYTON(csv.excel):
|
|
lineterminator = '\n'
|
|
|
|
csv.register_dialect("TRYTON", TRYTON)
|
|
|
|
|
|
class Translation(OSV, Cacheable):
|
|
"Translation"
|
|
_name = "ir.translation"
|
|
_description = __doc__
|
|
name = fields.Char('Field Name', required=True)
|
|
res_id = fields.Integer('Resource ID', select=1)
|
|
lang = fields.Selection('get_language', string='Language')
|
|
type = fields.Selection(TRANSLATION_TYPE, string='Type',
|
|
required=True)
|
|
src = fields.Text('Source')
|
|
value = fields.Text('Translation Value')
|
|
module = fields.Char('Module', readonly=True)
|
|
fuzzy = fields.Boolean('Fuzzy')
|
|
model = fields.Function('get_model', fnct_search='model_search',
|
|
type='char', string='Model')
|
|
|
|
def __init__(self):
|
|
super(Translation, self).__init__()
|
|
self._sql_constraints += [
|
|
('translation_uniq',
|
|
'UNIQUE (name, res_id, lang, type, src, module)',
|
|
'Translation must be unique'),
|
|
]
|
|
self._max_len = 10240
|
|
|
|
def init(self, cursor, module_name):
|
|
super(Translation, self).init(cursor, module_name)
|
|
|
|
cursor.execute('SELECT indexname FROM pg_indexes ' \
|
|
'WHERE indexname = ' \
|
|
'\'ir_translation_lang_type_name_index\'')
|
|
if not cursor.rowcount:
|
|
cursor.execute('CREATE INDEX ' \
|
|
'ir_translation_lang_type_name_index ' \
|
|
'ON ir_translation (lang, type, name)')
|
|
cursor.execute('SELECT indexname FROM pg_indexes ' \
|
|
'WHERE indexname = ' \
|
|
'\'ir_translation_lang_type_name_src_index\'')
|
|
if not cursor.rowcount:
|
|
cursor.execute('CREATE INDEX ' \
|
|
'ir_translation_lang_type_name_src_index ' \
|
|
'ON ir_translation (lang, type, name, src)')
|
|
|
|
def default_fuzzy(self, cursor, user, context=None):
|
|
return False
|
|
|
|
def get_model(self, cursor, user, ids, name, arg, context=None):
|
|
res = {}
|
|
for translation in self.browse(cursor, user, ids, context=context):
|
|
res[translation.id] = translation.name.split(',')[0]
|
|
return res
|
|
|
|
def model_search(self, cursor, user, name, args, context=None):
|
|
args2 = []
|
|
i = 0
|
|
while i < len(args):
|
|
cursor.execute('SELECT id FROM ir_translation ' \
|
|
'WHERE split_part(name, \',\', 1) ' + args[i][1] + ' %s',
|
|
(args[i][2],))
|
|
args2.append(('id', 'in', [x[0] for x in cursor.fetchall()]))
|
|
i += 1
|
|
return args2
|
|
|
|
def get_language(self, cursor, user, context):
|
|
lang_obj = self.pool.get('ir.lang')
|
|
lang_ids = lang_obj.search(cursor, user, [], context=context)
|
|
langs = lang_obj.browse(cursor, user, lang_ids, context=context)
|
|
res = [(lang.code, lang.name) for lang in langs]
|
|
return res
|
|
|
|
def _get_ids(self, cursor, name, ttype, lang, ids):
|
|
model_fields_obj = self.pool.get('ir.model.field')
|
|
model_obj = self.pool.get('ir.model')
|
|
|
|
translations, to_fetch = {}, []
|
|
name = unicode(name)
|
|
ttype = unicode(ttype)
|
|
lang = unicode(lang)
|
|
if name.split(',')[0] in ('ir.model.field', 'ir.model'):
|
|
field_name = name.split(',')[1]
|
|
if name.split(',')[0] == 'ir.model.field':
|
|
if field_name == 'field_description':
|
|
ttype = u'field'
|
|
else:
|
|
ttype = u'help'
|
|
records = model_fields_obj.browse(cursor, 0, ids)
|
|
else:
|
|
ttype = u'model'
|
|
records = model_obj.browse(cursor, 0, ids)
|
|
|
|
trans_args = []
|
|
for record in records:
|
|
if ttype in ('field', 'help'):
|
|
name = record.model.model + ',' + record.name
|
|
else:
|
|
name = record.model + ',' + field_name
|
|
trans_args.append((name, ttype, lang, None))
|
|
self._get_sources(cursor, trans_args)
|
|
|
|
for record in records:
|
|
if ttype in ('field', 'help'):
|
|
name = record.model.model + ',' + record.name
|
|
else:
|
|
name = record.model + ',' + field_name
|
|
translations[record.id] = self._get_source(cursor,
|
|
name, ttype, lang)
|
|
return translations
|
|
for obj_id in ids:
|
|
trans = self.get(cursor, (lang, ttype, name, obj_id))
|
|
if trans is not None:
|
|
translations[obj_id] = trans
|
|
else:
|
|
to_fetch.append(obj_id)
|
|
if to_fetch:
|
|
cursor.execute('SELECT res_id, value ' \
|
|
'FROM ir_translation ' \
|
|
'WHERE lang = %s ' \
|
|
'AND type = %s ' \
|
|
'AND name = %s ' \
|
|
'AND value != \'\' ' \
|
|
'AND value IS NOT NULL ' \
|
|
'AND fuzzy = false ' \
|
|
'AND res_id in (' + \
|
|
','.join([str(x) for x in to_fetch]) + ')',
|
|
(lang, ttype, name))
|
|
for res_id, value in cursor.fetchall():
|
|
self.add(cursor, (lang, ttype, name, res_id), value)
|
|
translations[res_id] = value
|
|
for res_id in ids:
|
|
if res_id not in translations:
|
|
self.add(cursor, (lang, ttype, name, res_id), False)
|
|
translations[res_id] = False
|
|
return translations
|
|
|
|
def _set_ids(self, cursor, user, name, ttype, lang, ids, value):
|
|
model_fields_obj = self.pool.get('ir.model.field')
|
|
model_obj = self.pool.get('ir.model')
|
|
|
|
model_name, field_name = name.split(',')
|
|
if model_name in ('ir.model.field', 'ir.model'):
|
|
if model_name == 'ir.model.field':
|
|
if field_name == 'field_description':
|
|
ttype = 'field'
|
|
else:
|
|
ttype = 'help'
|
|
records = model_fields_obj.browse(cursor, user, ids)
|
|
else:
|
|
ttype = 'model'
|
|
records = model_obj.browse(cursor, user, ids)
|
|
for record in records:
|
|
if ttype in ('field', 'help'):
|
|
name = record.model + ',' + record.name
|
|
ids2 = self.search(cursor, user, [
|
|
('lang', '=', lang),
|
|
('type', '=', ttype),
|
|
('name', '=', name),
|
|
])
|
|
if not ids2:
|
|
self.create(cursor, user, {
|
|
'name': name,
|
|
'lang': lang,
|
|
'type': ttype,
|
|
'src': record[field_name],
|
|
'value': value,
|
|
'fuzzy': False,
|
|
})
|
|
else:
|
|
self.write(cursor, user, ids, {
|
|
'src': record[field_name],
|
|
'value': value,
|
|
'fuzzy': False,
|
|
})
|
|
return len(ids)
|
|
model_obj = self.pool.get(model_name)
|
|
for record in model_obj.browse(cursor, user, ids):
|
|
ids2 = self.search(cursor, user, [
|
|
('lang', '=', lang),
|
|
('type', '=', ttype),
|
|
('name', '=', name),
|
|
('res_id', '=', record.id),
|
|
])
|
|
if not ids2:
|
|
self.create(cursor, user, {
|
|
'name': name,
|
|
'lang': lang,
|
|
'type': ttype,
|
|
'res_id': record.id,
|
|
'value': value,
|
|
'src': record[field_name],
|
|
'fuzzy': False,
|
|
})
|
|
else:
|
|
self.write(cursor, user, ids2, {
|
|
'value': value,
|
|
'src': record[field_name],
|
|
'fuzzy': False,
|
|
})
|
|
return len(ids)
|
|
|
|
def _get_source(self, cursor, name, ttype, lang, source=None):
|
|
name = unicode(name)
|
|
ttype = unicode(ttype)
|
|
lang = unicode(lang)
|
|
if source is not None:
|
|
source = unicode(source)
|
|
trans = self.get(cursor, (lang, ttype, name, source))
|
|
if trans is not None:
|
|
return trans
|
|
|
|
if source:
|
|
cursor.execute('SELECT value ' \
|
|
'FROM ir_translation ' \
|
|
'WHERE lang = %s ' \
|
|
'AND type = %s ' \
|
|
'AND name = %s ' \
|
|
'AND src = %s ' \
|
|
'AND value != \'\' ' \
|
|
'AND value IS NOT NULL ' \
|
|
'AND fuzzy = false ' \
|
|
'AND res_id = 0',
|
|
(lang, ttype, str(name), source))
|
|
else:
|
|
cursor.execute('SELECT value ' \
|
|
'FROM ir_translation ' \
|
|
'WHERE lang = %s ' \
|
|
'AND type = %s ' \
|
|
'AND name = %s ' \
|
|
'AND value != \'\' ' \
|
|
'AND value IS NOT NULL ' \
|
|
'AND fuzzy = false ' \
|
|
'AND res_id = 0',
|
|
(lang, ttype, str(name)))
|
|
res = cursor.fetchone()
|
|
if res:
|
|
self.add(cursor, (lang, ttype, name, source), res[0])
|
|
return res[0]
|
|
else:
|
|
self.add(cursor, (lang, ttype, name, source), False)
|
|
return False
|
|
|
|
def _get_sources(self, cursor, args):
|
|
'''
|
|
Take a list of (name, ttype, lang, source).
|
|
Add the translations to the cache.
|
|
Return a dict with the translations.
|
|
'''
|
|
res = {}
|
|
clause = ''
|
|
value = []
|
|
if len(args) > cursor.IN_MAX:
|
|
for i in range(0, len(args), cursor.IN_MAX):
|
|
sub_args = args[i:i + cursor.IN_MAX]
|
|
res.update(self._get_sources(cursor, sub_args))
|
|
return res
|
|
for name, ttype, lang, source in args:
|
|
name = unicode(name)
|
|
ttype = unicode(ttype)
|
|
lang = unicode(lang)
|
|
if source is not None:
|
|
source = unicode(source)
|
|
trans = self.get(cursor, (lang, ttype, name, source))
|
|
if trans is not None:
|
|
res[(name, ttype, lang, source)] = trans
|
|
else:
|
|
res[(name, ttype, lang, source)] = False
|
|
self.add(cursor, (lang, ttype, name, source), False)
|
|
if clause:
|
|
clause += ' OR '
|
|
if source:
|
|
clause += '(lang = %s ' \
|
|
'AND type = %s ' \
|
|
'AND name = %s ' \
|
|
'AND src = %s ' \
|
|
'AND value != \'\' ' \
|
|
'AND value IS NOT NULL ' \
|
|
'AND fuzzy = false ' \
|
|
'AND res_id = 0)'
|
|
value.extend((lang, ttype, str(name), source))
|
|
else:
|
|
clause += '(lang = %s ' \
|
|
'AND type = %s ' \
|
|
'AND name = %s ' \
|
|
'AND value != \'\' ' \
|
|
'AND value IS NOT NULL ' \
|
|
'AND fuzzy = false ' \
|
|
'AND res_id = 0)'
|
|
value.extend((lang, ttype, str(name)))
|
|
if clause:
|
|
cursor.execute('SELECT lang, type, name, src, value ' \
|
|
'FROM ir_translation ' \
|
|
'WHERE ' + clause, value)
|
|
for lang, ttype, name, source, value in cursor.fetchall():
|
|
if (name, ttype, lang, source) not in args:
|
|
source = None
|
|
res[(name, ttype, lang, source)] = value
|
|
self.add(cursor, (lang, ttype, name, source), value)
|
|
return res
|
|
|
|
def delete(self, cursor, user, ids, context=None):
|
|
self.clear(cursor)
|
|
self.fields_view_get(cursor.dbname)
|
|
return super(Translation, self).delete(cursor, user, ids,
|
|
context=context)
|
|
|
|
def create(self, cursor, user, vals, context=None):
|
|
self.clear(cursor)
|
|
self.fields_view_get(cursor.dbname)
|
|
if not vals.get('module'):
|
|
if vals.get('type', '') in ('odt', 'view', 'wizard_button',
|
|
'selection', 'error'):
|
|
cursor.execute('SELECT module FROM ir_translation ' \
|
|
'WHERE name = %s ' \
|
|
'AND res_id = %s ' \
|
|
'AND lang = %s ' \
|
|
'AND type = %s ' \
|
|
'AND src = %s ',
|
|
(vals.get('name', ''), vals.get('res_id', 0), 'en_US',
|
|
vals.get('type', ''), vals.get('src', '')))
|
|
if cursor.rowcount:
|
|
vals = vals.copy()
|
|
vals['module'] = cursor.fetchone()[0]
|
|
else:
|
|
cursor.execute('SELECT module, src FROM ir_translation ' \
|
|
'WHERE name = %s ' \
|
|
'AND res_id = %s ' \
|
|
'AND lang = %s ' \
|
|
'AND type = %s',
|
|
(vals.get('name', ''), vals.get('res_id', 0), 'en_US',
|
|
vals.get('type', '')))
|
|
if cursor.rowcount:
|
|
vals = vals.copy()
|
|
vals['module'], vals['src'] = cursor.fetchone()
|
|
return super(Translation, self).create(cursor, user, vals,
|
|
context=context)
|
|
|
|
def write(self, cursor, user, ids, vals, context=None):
|
|
self.clear(cursor)
|
|
self.fields_view_get(cursor.dbname)
|
|
return super(Translation, self).write(cursor, user, ids, vals,
|
|
context=context)
|
|
|
|
def translation_import(self, cursor, user, lang, module, datas,
|
|
context=None):
|
|
if context is None:
|
|
context = {}
|
|
ctx = context.copy()
|
|
ctx['module'] = module
|
|
model_data_obj = self.pool.get('ir.model.data')
|
|
model_data_ids = model_data_obj.search(cursor, user, [
|
|
('module', '=', module),
|
|
], context=context)
|
|
fs_id2db_id = {}
|
|
for model_data in model_data_obj.browse(cursor, user, model_data_ids,
|
|
context=context):
|
|
fs_id2db_id.setdefault(model_data.model, {})
|
|
fs_id2db_id[model_data.model][model_data.fs_id] = model_data.db_id
|
|
|
|
translation_ids = []
|
|
reader = csv.reader(datas)
|
|
for row in reader:
|
|
break
|
|
|
|
id2translation = {}
|
|
key2ids = {}
|
|
module_translation_ids = self.search(cursor, user, [
|
|
('lang', '=', lang),
|
|
('module', '=', module),
|
|
], context=context)
|
|
for translation in self.browse(cursor, user, module_translation_ids,
|
|
context=context):
|
|
if translation.type in ('odt', 'view', 'wizard_button',
|
|
'selection', 'error'):
|
|
key = (translation.name, translation.res_id, translation.type,
|
|
translation.src)
|
|
elif translation.type in ('field', 'model','help'):
|
|
key = (translation.name, translation.res_id, translation.type)
|
|
else:
|
|
raise Exception('Unknow translation type: %s' % translation.type)
|
|
key2ids.setdefault(key, []).append(translation.id)
|
|
id2translation[translation.id] = translation
|
|
|
|
for row in reader:
|
|
ttype = row[0].decode('utf-8')
|
|
name = row[1].decode('utf-8')
|
|
res_id = row[2].decode('utf-8')
|
|
src = row[3].decode('utf-8')
|
|
value = row[4].decode('utf-8')
|
|
fuzzy = int(row[5])
|
|
|
|
model = name.split(',')[0]
|
|
if model in fs_id2db_id:
|
|
res_id = fs_id2db_id[model].get(res_id, res_id)
|
|
|
|
try:
|
|
res_id = int(res_id)
|
|
except ValueError:
|
|
continue
|
|
|
|
if ttype in ('odt', 'view', 'wizard_button', 'selection', 'error'):
|
|
key = (name, res_id, ttype, src)
|
|
elif ttype in('field', 'model','help'):
|
|
key = (name, res_id, ttype)
|
|
else:
|
|
raise Exception('Unknow translation type: %s' % ttype)
|
|
ids = key2ids.get(key, [])
|
|
|
|
if not ids:
|
|
translation_ids.append(self.create(cursor, user, {
|
|
'name': name,
|
|
'res_id': res_id,
|
|
'lang': lang,
|
|
'type': ttype,
|
|
'src': src,
|
|
'value': value,
|
|
'fuzzy': fuzzy,
|
|
'module': module,
|
|
}, context=ctx))
|
|
else:
|
|
ids2 = []
|
|
for translation_id in ids:
|
|
translation = id2translation[translation_id]
|
|
if not translation.write_uid and not translation.write_uid \
|
|
and (translation.value != value \
|
|
or translation.fuzzy != fuzzy):
|
|
ids2.append(translation.id)
|
|
if ids2:
|
|
self.write(cursor, user, ids2, {
|
|
'value': value,
|
|
'fuzzy': fuzzy,
|
|
}, context=ctx)
|
|
translation_ids += ids
|
|
|
|
if translation_ids:
|
|
cursor.execute('DELETE FROM ir_translation ' \
|
|
'WHERE module = %s ' \
|
|
'AND lang = %s ' \
|
|
'AND id NOT IN ' \
|
|
'(' + ','.join(['%s' for x in translation_ids]) + ')',
|
|
(module, lang) + tuple(translation_ids))
|
|
return len(translation_ids)
|
|
|
|
def translation_export(self, cursor, user, lang, module, context=None):
|
|
model_data_obj = self.pool.get('ir.model.data')
|
|
|
|
if context is None:
|
|
context = {}
|
|
|
|
model_data_ids = model_data_obj.search(cursor, user, [
|
|
('module', '=', module),
|
|
], context=context)
|
|
db_id2fs_id = {}
|
|
for model_data in model_data_obj.browse(cursor, user, model_data_ids,
|
|
context=context):
|
|
db_id2fs_id.setdefault(model_data.model, {})
|
|
db_id2fs_id[model_data.model][model_data.db_id] = model_data.fs_id
|
|
|
|
buf = StringIO.StringIO()
|
|
writer = csv.writer(buf, 'TRYTON')
|
|
writer.writerow(HEADER)
|
|
|
|
ctx = context.copy()
|
|
ctx['language'] = 'en_US'
|
|
translation_ids = self.search(cursor, user, [
|
|
('lang', '=', lang),
|
|
('module', '=', module),
|
|
], order=[
|
|
('type', 'ASC'),
|
|
('name', 'ASC'),
|
|
('src', 'ASC'),
|
|
('res_id', 'ASC'),
|
|
], context=ctx)
|
|
for translation in self.browse(cursor, user, translation_ids,
|
|
context=context):
|
|
row = []
|
|
for field in HEADER:
|
|
if field == 'res_id':
|
|
res_id = translation[field]
|
|
if res_id:
|
|
model = translation.name.split(',')[0]
|
|
if model in db_id2fs_id:
|
|
res_id = db_id2fs_id[model].get(res_id)
|
|
try:
|
|
val = int(res_id)
|
|
if val != 0:
|
|
continue
|
|
except (ValueError, TypeError):
|
|
pass
|
|
row.append(res_id)
|
|
elif field == 'fuzzy':
|
|
row.append(int(translation[field]))
|
|
else:
|
|
value = translation[field] or ''
|
|
value = value.encode('utf-8')
|
|
row.append(value)
|
|
writer.writerow(row)
|
|
|
|
file_data = buf.getvalue()
|
|
buf.close()
|
|
return file_data
|
|
|
|
Translation()
|
|
|
|
|
|
class ReportTranslationSetInit(WizardOSV):
|
|
"Update Report Translation"
|
|
_name = 'ir.translation.set_report.init'
|
|
_description = __doc__
|
|
|
|
ReportTranslationSetInit()
|
|
|
|
|
|
class ReportTranslationSetStart(WizardOSV):
|
|
"Update Report Translation"
|
|
_name = 'ir.translation.set_report.start'
|
|
_description = __doc__
|
|
|
|
ReportTranslationSetStart()
|
|
|
|
|
|
class ReportTranslationSet(Wizard):
|
|
"Update report translation"
|
|
_name = "ir.translation.set_report"
|
|
|
|
states = {
|
|
'init': {
|
|
'actions': [],
|
|
'result': {
|
|
'type': 'form',
|
|
'object': 'ir.translation.set_report.init',
|
|
'state': [
|
|
('end', 'Cancel', 'tryton-cancel'),
|
|
('start', 'Start Update', 'tryton-ok', True),
|
|
],
|
|
},
|
|
},
|
|
'start': {
|
|
'actions': ['_set_report_translation'],
|
|
'result': {
|
|
'type': 'form',
|
|
'object': 'ir.translation.set_report.start',
|
|
'state': [
|
|
('end', 'Ok', 'tryton-ok', True),
|
|
],
|
|
},
|
|
},
|
|
}
|
|
|
|
def _translate_report(self, node):
|
|
strings = []
|
|
|
|
if node.nodeType in (node.CDATA_SECTION_NODE, node.TEXT_NODE):
|
|
if node.parentNode \
|
|
and node.parentNode.tagName == 'text:placeholder':
|
|
return strings
|
|
|
|
if node.nodeValue:
|
|
txt = node.nodeValue.strip()
|
|
if txt:
|
|
strings.append(txt)
|
|
|
|
for child in [x for x in node.childNodes]:
|
|
strings.extend(self._translate_report(child))
|
|
return strings
|
|
|
|
def _set_report_translation(self, cursor, user, data, context):
|
|
report_obj = self.pool.get('ir.action.report')
|
|
|
|
ctx = context.copy()
|
|
ctx['active_test'] = False
|
|
|
|
report_ids = report_obj.search(cursor, user, [], context=ctx)
|
|
|
|
if not report_ids:
|
|
return {}
|
|
|
|
reports = report_obj.browse(cursor, user, report_ids, context=context)
|
|
|
|
for report in reports:
|
|
cursor.execute('SELECT id, name, src FROM ir_translation ' \
|
|
'WHERE lang = %s ' \
|
|
'AND type = %s ' \
|
|
'AND name = %s ' \
|
|
'AND module = %s',
|
|
('en_US', 'odt', report.report_name, report.module))
|
|
trans_reports = {}
|
|
for trans in cursor.dictfetchall():
|
|
trans_reports[trans['src']] = trans
|
|
|
|
try:
|
|
content = report.report_content
|
|
except:
|
|
continue
|
|
if not content:
|
|
continue
|
|
|
|
content_io = StringIO.StringIO(report.report_content)
|
|
content_z = zipfile.ZipFile(content_io, mode='r')
|
|
|
|
content_xml = content_z.read('content.xml')
|
|
document = dom.minidom.parseString(content_xml)
|
|
strings = self._translate_report(document.documentElement)
|
|
|
|
style_xml = content_z.read('styles.xml')
|
|
document = dom.minidom.parseString(style_xml)
|
|
strings += self._translate_report(document.documentElement)
|
|
|
|
style_content = None
|
|
try:
|
|
style_content = report.style_content
|
|
except:
|
|
pass
|
|
|
|
if style_content:
|
|
style_io = StringIO.StringIO(style_content)
|
|
style_z = zipfile.ZipFile(style_io, mode='r')
|
|
style_xml = style_z.read('styles.xml')
|
|
|
|
document = dom.minidom.parseString(style_xml)
|
|
|
|
strings += self._translate_report(document.documentElement)
|
|
|
|
for string in {}.fromkeys(strings).keys():
|
|
done = False
|
|
if string in trans_reports:
|
|
del trans_reports[string]
|
|
continue
|
|
for string_trans in trans_reports:
|
|
if string_trans in strings:
|
|
continue
|
|
seqmatch = SequenceMatcher(lambda x: x == ' ',
|
|
string, string_trans)
|
|
if seqmatch.ratio() == 1.0:
|
|
del trans_reports[report.report_name][string_trans]
|
|
done = True
|
|
break
|
|
if seqmatch.ratio() > 0.6:
|
|
cursor.execute('UPDATE ir_translation ' \
|
|
'SET src = %s, ' \
|
|
'fuzzy = True ' \
|
|
'WHERE name = %s ' \
|
|
'AND type = %s ' \
|
|
'AND src = %s ' \
|
|
'AND module = %s',
|
|
(string, report.report_name, 'odt', string_trans,
|
|
report.module))
|
|
del trans_reports[string_trans]
|
|
done = True
|
|
break
|
|
if not done:
|
|
cursor.execute('INSERT INTO ir_translation ' \
|
|
'(name, lang, type, src, value, module, fuzzy)' \
|
|
'VALUES (%s, %s, %s, %s, %s, %s, False)',
|
|
(report.report_name, 'en_US', 'odt', string, '',
|
|
report.module))
|
|
if strings:
|
|
cursor.execute('DELETE FROM ir_translation ' \
|
|
'WHERE name = %s ' \
|
|
'AND type = %s ' \
|
|
'AND src NOT IN ' \
|
|
'(' + ','.join(['%s' for x in strings]) + ')',
|
|
(report.report_name, 'odt') + tuple(strings))
|
|
return {}
|
|
|
|
ReportTranslationSet()
|
|
|
|
|
|
class TranslationCleanInit(WizardOSV):
|
|
'Clean translation init'
|
|
_name = 'ir.translation.clean.init'
|
|
_description = __doc__
|
|
|
|
TranslationCleanInit()
|
|
|
|
|
|
class TranslationCleanStart(WizardOSV):
|
|
'Clean translation start'
|
|
_name = 'ir.translation.clean.start'
|
|
_description = __doc__
|
|
|
|
TranslationCleanStart()
|
|
|
|
|
|
class TranslationClean(Wizard):
|
|
"Clean translation"
|
|
_name = 'ir.translation.clean'
|
|
|
|
states = {
|
|
'init': {
|
|
'actions': [],
|
|
'result': {
|
|
'type': 'form',
|
|
'object': 'ir.translation.clean.init',
|
|
'state': [
|
|
('end', 'Cancel', 'tryton-cancel'),
|
|
('start', 'Start', 'tryton-ok', True),
|
|
],
|
|
},
|
|
},
|
|
'start': {
|
|
'actions': ['_clean_translation'],
|
|
'result': {
|
|
'type': 'form',
|
|
'object': 'ir.translation.clean.start',
|
|
'state': [
|
|
('end', 'Ok', 'tryton-ok', True),
|
|
],
|
|
},
|
|
},
|
|
}
|
|
|
|
def _clean_translation(self, cursor, user, data, context):
|
|
translation_obj = self.pool.get('ir.translation')
|
|
model_data_obj = self.pool.get('ir.model.data')
|
|
report_obj = self.pool.get('ir.action.report')
|
|
|
|
ctx = context.copy()
|
|
ctx['active_test'] = False
|
|
|
|
offset = 0
|
|
limit = cursor.IN_MAX
|
|
while True:
|
|
to_delete = []
|
|
translation_ids = translation_obj.search(cursor, user, [],
|
|
offset=offset, limit=limit, context=context)
|
|
if not translation_ids:
|
|
break
|
|
offset += limit
|
|
for translation in translation_obj.browse(cursor, user,
|
|
translation_ids, context=context):
|
|
if translation.type == 'field':
|
|
try:
|
|
model_name, field_name = translation.name.split(',', 1)
|
|
except ValueError:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
if model_name not in self.pool.object_name_list():
|
|
to_delete.append(translation.id)
|
|
continue
|
|
model_obj = self.pool.get(model_name)
|
|
if field_name not in model_obj._columns:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
elif translation.type == 'model':
|
|
try:
|
|
model_name, field_name = translation.name.split(',', 1)
|
|
except ValueError:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
if model_name not in self.pool.object_name_list():
|
|
to_delete.append(translation.id)
|
|
continue
|
|
if translation.res_id:
|
|
model_obj = self.pool.get(model_name)
|
|
if field_name not in model_obj._columns:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
field = model_obj._columns[field_name]
|
|
if not hasattr(field, 'translate') or \
|
|
not field.translate:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
elif field_name not in ('name'):
|
|
to_delete.append(translation.id)
|
|
continue
|
|
elif translation.type == 'odt':
|
|
if not report_obj.search(cursor, user, [
|
|
('report_name', '=', translation.name),
|
|
], context=ctx):
|
|
to_delete.append(translation.id)
|
|
continue
|
|
elif translation.type == 'selection':
|
|
try:
|
|
model_name, field_name = translation.name.split(',', 1)
|
|
except ValueError:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
if model_name not in self.pool.object_name_list():
|
|
to_delete.append(translation.id)
|
|
continue
|
|
model_obj = self.pool.get(model_name)
|
|
if field_name not in model_obj._columns:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
field = model_obj._columns[field_name]
|
|
if not hasattr(field, 'selection') or not field.selection \
|
|
or not ((hasattr(field, 'translate_selection') and \
|
|
field.translate_selection) or True):
|
|
to_delete.append(translation.id)
|
|
continue
|
|
if isinstance(field.selection, (tuple, list)) \
|
|
and translation.src not in \
|
|
dict(field.selection).values():
|
|
to_delete.append(translation.id)
|
|
continue
|
|
elif translation.type == 'view':
|
|
model_name = translation.name
|
|
if model_name not in self.pool.object_name_list():
|
|
to_delete.append(translation.id)
|
|
continue
|
|
elif translation.type == 'wizard_button':
|
|
try:
|
|
wizard_name, state_name, button_name = \
|
|
translation.name.split(',', 2)
|
|
except ValueError:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
wizard = self.pool.get(wizard_name, type='wizard')
|
|
if not wizard:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
state = wizard.states.get(state_name)
|
|
if not state:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
find = False
|
|
for but in state['result']['state']:
|
|
if but[0] == button_name:
|
|
find = True
|
|
if not find:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
elif translation.type == 'help':
|
|
try:
|
|
model_name, field_name = translation.name.split(',', 1)
|
|
except ValueError:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
if model_name not in self.pool.object_name_list():
|
|
to_delete.append(translation.id)
|
|
continue
|
|
model_obj = self.pool.get(model_name)
|
|
if field_name not in model_obj._columns:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
field = model_obj._columns[field_name]
|
|
if not field.help:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
elif translation.type == 'error':
|
|
model_name = translation.name
|
|
if model_name in (
|
|
'delete_xml_record',
|
|
'xml_record_desc',
|
|
'write_xml_record',
|
|
'delete_workflow_record',
|
|
'domain_validation_record',
|
|
'required_validation_record',
|
|
):
|
|
continue
|
|
if model_name in self.pool.object_name_list():
|
|
model_obj = self.pool.get(model_name)
|
|
errors = model_obj._error_messages.values() + \
|
|
model_obj._sql_error_messages.values()
|
|
for _, _, error in model_obj._sql_constraints:
|
|
errors.append(error)
|
|
if translation.src not in errors:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
elif model_name in self.pool.object_name_list(type='wizard'):
|
|
wizard_obj = self.pool.get(model_name, type='wizard')
|
|
errors = wizard_obj._error_messages.values()
|
|
if translation.src not in errors:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
else:
|
|
to_delete.append(translation.id)
|
|
continue
|
|
# skip translation handled in ir.model.data
|
|
mdata_ids = model_data_obj.search(
|
|
cursor, user,
|
|
[('db_id', 'in', to_delete), ('model', '=', 'ir.translation')],
|
|
context=context)
|
|
for mdata in model_data_obj.browse(cursor, user, mdata_ids,
|
|
context=context):
|
|
if mdata.db_id in to_delete:
|
|
to_delete.remove(mdata.db_id)
|
|
|
|
translation_obj.delete(cursor, user, to_delete, context=context)
|
|
return {}
|
|
|
|
TranslationClean()
|
|
|
|
|
|
class TranslationUpdateInit(WizardOSV):
|
|
"Update translation - language"
|
|
_name = 'ir.translation.update.init'
|
|
_description = __doc__
|
|
lang = fields.Selection('get_language', string='Language',
|
|
required=True)
|
|
|
|
def get_language(self, cursor, user, context):
|
|
lang_obj = self.pool.get('ir.lang')
|
|
lang_ids = lang_obj.search(cursor, user, [('translatable', '=', True)],
|
|
context=context)
|
|
langs = lang_obj.browse(cursor, user, lang_ids, context=context)
|
|
res = [(lang.code, lang.name) for lang in langs if lang.code != 'en_US']
|
|
return res
|
|
|
|
TranslationUpdateInit()
|
|
|
|
|
|
class TranslationUpdate(Wizard):
|
|
"Update translation"
|
|
_name = "ir.translation.update"
|
|
|
|
def _update_translation(self, cursor, user, data, context):
|
|
translation_obj = self.pool.get('ir.translation')
|
|
cursor.execute('SELECT name, res_id, type, src, module ' \
|
|
'FROM ir_translation ' \
|
|
'WHERE lang=\'en_US\' ' \
|
|
'AND type in (\'odt\', \'view\', \'wizard_button\', ' \
|
|
' \'selection\', \'error\') ' \
|
|
'EXCEPT SELECT name, res_id, type, src, module ' \
|
|
'FROM ir_translation ' \
|
|
'WHERE lang=%s ' \
|
|
'AND type in (\'odt\', \'view\', \'wizard_button\', ' \
|
|
' \'selection\', \'error\')',
|
|
(data['form']['lang'],))
|
|
for row in cursor.dictfetchall():
|
|
translation_obj.create(cursor, user, {
|
|
'name': row['name'],
|
|
'res_id': row['res_id'],
|
|
'lang': data['form']['lang'],
|
|
'type': row['type'],
|
|
'src': row['src'],
|
|
'module': row['module'],
|
|
})
|
|
cursor.execute('SELECT name, res_id, type, module ' \
|
|
'FROM ir_translation ' \
|
|
'WHERE lang=\'en_US\' ' \
|
|
'AND type in (\'field\', \'model\', \'help\') ' \
|
|
'EXCEPT SELECT name, res_id, type, module ' \
|
|
'FROM ir_translation ' \
|
|
'WHERE lang=%s ' \
|
|
'AND type in (\'field\', \'model\', \'help\')',
|
|
(data['form']['lang'],))
|
|
for row in cursor.dictfetchall():
|
|
translation_obj.create(cursor, user, {
|
|
'name': row['name'],
|
|
'res_id': row['res_id'],
|
|
'lang': data['form']['lang'],
|
|
'type': row['type'],
|
|
'module': row['module'],
|
|
})
|
|
cursor.execute('SELECT name, res_id, type, src ' \
|
|
'FROM ir_translation ' \
|
|
'WHERE lang=\'en_US\' ' \
|
|
'AND type in (\'field\', \'model\', \'selection\', ' \
|
|
'\'help\') ' \
|
|
'EXCEPT SELECT name, res_id, type, src ' \
|
|
'FROM ir_translation ' \
|
|
'WHERE lang=%s ' \
|
|
'AND type in (\'field\', \'model\', \'selection\', ' \
|
|
'\'help\')',
|
|
(data['form']['lang'],))
|
|
for row in cursor.dictfetchall():
|
|
cursor.execute('UPDATE ir_translation ' \
|
|
'SET fuzzy = True, ' \
|
|
'src = %s ' \
|
|
'WHERE name = %s ' \
|
|
'AND res_id = %s ' \
|
|
'AND type = %s ' \
|
|
'AND lang = %s',
|
|
(row['src'], row['name'], row['res_id'], row['type'],
|
|
data['form']['lang']))
|
|
cursor.execute('UPDATE ir_translation ' \
|
|
'SET fuzzy = False ' \
|
|
'WHERE (value = \'\' OR value IS NULL) ' \
|
|
'AND lang = %s', (data['form']['lang'],))
|
|
return {}
|
|
|
|
def _action_translation_open(self, cursor, user, data, context):
|
|
model_data_obj = self.pool.get('ir.model.data')
|
|
act_window_obj = self.pool.get('ir.action.act_window')
|
|
|
|
model_data_ids = model_data_obj.search(cursor, user, [
|
|
('fs_id', '=', 'act_translation_form'),
|
|
('module', '=', 'ir'),
|
|
('inherit', '=', False),
|
|
], limit=1, context=context)
|
|
model_data = model_data_obj.browse(cursor, user, model_data_ids[0],
|
|
context=context)
|
|
res = act_window_obj.read(cursor, user, model_data.db_id, context=context)
|
|
res['domain'] = res['domain'][:-1] + ',' + \
|
|
str(('lang', '=', data['form']['lang'])) + res['domain'][-1:]
|
|
return res
|
|
|
|
states = {
|
|
'init': {
|
|
'actions': [],
|
|
'result': {
|
|
'type': 'form',
|
|
'object': 'ir.translation.update.init',
|
|
'state': [
|
|
('end', 'Cancel', 'tryton-cancel'),
|
|
('start', 'Start Update','tryton-ok', True),
|
|
],
|
|
},
|
|
},
|
|
'start': {
|
|
'actions': ['_update_translation'],
|
|
'result': {
|
|
'type': 'action',
|
|
'action': '_action_translation_open',
|
|
'state': 'end',
|
|
},
|
|
},
|
|
}
|
|
|
|
TranslationUpdate()
|
|
|
|
|
|
class TranslationExportInit(WizardOSV):
|
|
"Export translation - language and module"
|
|
_name = 'ir.translation.export.init'
|
|
_description = __doc__
|
|
lang = fields.Selection('get_language', string='Language',
|
|
required=True)
|
|
module = fields.Selection('get_module', string='Module',
|
|
required=True)
|
|
|
|
def get_language(self, cursor, user, context):
|
|
lang_obj = self.pool.get('ir.lang')
|
|
lang_ids = lang_obj.search(cursor, user, [], context=context)
|
|
langs = lang_obj.browse(cursor, user, lang_ids, context=context)
|
|
res = [(lang.code, lang.name) for lang in langs]
|
|
return res
|
|
|
|
def get_module(self, cursor, user, context):
|
|
module_obj = self.pool.get('ir.module.module')
|
|
module_ids = module_obj.search(cursor, user, [], context=context)
|
|
modules = module_obj.browse(cursor, user, module_ids, context=context)
|
|
res = [(module.name, module.name) for module in modules]
|
|
return res
|
|
|
|
TranslationExportInit()
|
|
|
|
|
|
class TranslationExportStart(WizardOSV):
|
|
"Export translation - file"
|
|
_description = __doc__
|
|
_name = 'ir.translation.export.start'
|
|
file = fields.Binary('File', readonly=True)
|
|
|
|
TranslationExportStart()
|
|
|
|
|
|
class TranslationExport(Wizard):
|
|
"Export translation"
|
|
_name = "ir.translation.export"
|
|
|
|
def _export_translation(self, cursor, user, data, context):
|
|
translation_obj = self.pool.get('ir.translation')
|
|
file_data = translation_obj.translation_export(cursor, user,
|
|
data['form']['lang'], data['form']['module'], context=context)
|
|
return {
|
|
'file': base64.encodestring(file_data),
|
|
}
|
|
|
|
states = {
|
|
'init': {
|
|
'actions': [],
|
|
'result': {
|
|
'type': 'form',
|
|
'object': 'ir.translation.export.init',
|
|
'state': [
|
|
('end', 'Cancel', 'tryton-cancel'),
|
|
('start', 'Start Export', 'tryton-ok', True),
|
|
],
|
|
},
|
|
},
|
|
'start': {
|
|
'actions': ['_export_translation'],
|
|
'result': {
|
|
'type': 'form',
|
|
'object': 'ir.translation.export.start',
|
|
'state': [
|
|
('end', 'Close', 'tryton-close'),
|
|
],
|
|
},
|
|
},
|
|
}
|
|
|
|
TranslationExport()
|