trytond-translate/translate.py

351 lines
13 KiB
Python

# This file is part of translate module for Tryton.
# The COPYRIGHT file at the top level of this repository contains
# the full copyright notices and license terms.
from lxml import etree
from trytond.model import ModelView, ModelSQL, fields, Unique
from trytond.pool import Pool
from trytond.pyson import Bool, Eval, Not, PYSONEncoder
from trytond.transaction import Transaction
from trytond.wizard import Wizard, StateView, StateTransition, Button
__all__ = ['Translate', 'TranslateFields', 'TranslateWizardStart',
'TranslateWizardTranslation', 'TranslateWizard']
class Translate(ModelSQL, ModelView):
'Translate'
__name__ = 'translate.translate'
_rec_name = 'model'
model = fields.Many2One('ir.model', 'Model', required=True)
field_domain = fields.Function(fields.One2Many('ir.model.field', None,
'Field Domain', depends=['model']),
'get_field_domain')
model_fields = fields.Many2Many('translate.translate-ir.model.field',
'translate', 'field', 'Fields',
domain=[
('id', 'in', Eval('field_domain')),
],
depends=['field_domain'])
keyword = fields.Many2One('ir.action.keyword', 'Keyword', readonly=True)
@classmethod
def __setup__(cls):
super(Translate, cls).__setup__()
t = cls.__table__()
cls._sql_constraints += [
('model_uniq', Unique(t, t.model),
'Translate must be unique per model.'),
]
cls._error_messages.update({
'not_modelsql': 'Model "%s" does not store information '
'to an SQL table.',
})
cls._buttons.update({
'create_keyword': {
'invisible': Eval('keyword'),
},
'remove_keyword': {
'invisible': ~Eval('keyword'),
},
})
@classmethod
def validate(cls, translates):
super(Translate, cls).validate(translates)
for translate in translates:
Model = Pool().get(translate.model.model)
if not issubclass(Model, ModelSQL):
cls.raise_user_error('not_modelsql',
(translate.model.rec_name,))
@classmethod
@ModelView.button
def create_keyword(cls, translates):
pool = Pool()
Action = pool.get('ir.action.wizard')
ModelData = pool.get('ir.model.data')
Keyword = pool.get('ir.action.keyword')
for translate in translates:
if translate.keyword:
continue
action = Action(ModelData.get_id('translate',
'wizard_translate'))
keyword = Keyword()
keyword.keyword = 'form_action'
keyword.model = '%s,-1' % translate.model.model
keyword.action = action.action
keyword.save()
translate.keyword = keyword
translate.save()
@classmethod
@ModelView.button
def remove_keyword(cls, translates):
pool = Pool()
Keyword = pool.get('ir.action.keyword')
Keyword.delete([x.keyword for x in translates if x.keyword])
@classmethod
def delete(cls, translates):
cls.remove_keyword(translates)
super(Translate, cls).delete(translates)
@classmethod
def get_field_domain(cls, translations, names):
pool = Pool()
ModelField = pool.get('ir.model.field')
res = {'field_domain': {}}
for translation in translations:
if translation.model:
Model = pool.get(translation.model.model)
translatable_fields = []
for f in Model._fields:
if getattr(Model._fields[f], 'translate', False):
translatable_fields.append(f)
if translatable_fields:
model_fields = ModelField.search([
('name', 'in', translatable_fields),
('model', '=', translation.model)
])
res['field_domain'].update({
translation.id: [f.id for f in model_fields]
})
return res
class TranslateFields(ModelSQL):
'Translate Fields'
__name__ = 'translate.translate-ir.model.field'
translate = fields.Many2One('translate.translate', 'Translate',
required=True)
field = fields.Many2One('ir.model.field', 'Field', required=True)
class TranslateWizardStart(ModelView):
'Translate Wizard Start'
__name__ = 'translate.wizard.start'
source_lang = fields.Selection('get_lang', 'Source Language',
required=True)
target_lang = fields.Selection('get_lang', 'Target Language',
required=True)
translator = fields.Selection([
(None, ''),
], 'Translator', required=True)
@staticmethod
def get_lang():
Language = Pool().get('ir.lang')
languages = Language.search([
('translatable', '=', True),
])
return [(l.code, l.name) for l in languages]
@staticmethod
def default_source_lang():
context = Transaction().context
return context['language']
@classmethod
def default_translator(cls):
translators = cls.translator.selection
if translators:
return translators[0][0]
return
class TranslateWizardTranslation(ModelView):
'Translate Wizard Translation'
__name__ = 'translate.wizard.translation'
@classmethod
def __setup__(cls):
super(TranslateWizardTranslation, cls).__setup__()
cls._error_messages.update({
'no_translation_found':
'No translation found for field %s.',
'original': 'Original',
'translation': 'Translation',
'translate': 'Translate',
})
@classmethod
def fields_view_get(cls, view_id=None, view_type='form'):
pool = Pool()
Translate = pool.get('translate.translate')
res = super(TranslateWizardTranslation, cls).fields_view_get(view_id,
view_type)
fields = res['fields']
context = Transaction().context
encoder = PYSONEncoder()
model = context.get('active_model', None)
if not model:
return res
Model = pool.get(model)
translates = Translate.search([('model.model', '=', model)],
limit=1)
if not translates:
return res
translate, = translates
root = etree.fromstring(res['arch'])
form = root.find('separator').getparent()
xml_group = etree.SubElement(form, 'group', {
'col': '3',
'colspan': '4',
})
etree.SubElement(xml_group, 'label', {
'id': 'label_original',
'string': cls.raise_user_error('original',
raise_exception=False),
'xalign': '0.0',
})
etree.SubElement(xml_group, 'label', {
'id': 'label_translation',
'string': cls.raise_user_error('translation',
raise_exception=False),
'xalign': '0.0',
})
etree.SubElement(xml_group, 'label', {
'id': 'label_translate',
'string': cls.raise_user_error('translate',
raise_exception=False),
'xexpand': '0',
'width': '25',
})
fields.update(Model.fields_get([f.name for f in
translate.model_fields]))
for field in translate.model_fields:
if fields[field.name].get('states'):
fields[field.name]['states'] = {
'readonly': True,
'invisible': {},
}
if fields[field.name].get('required'):
fields[field.name]['required'] = False
if fields[field.name].get('translate'):
fields[field.name]['translate'] = False
if fields[field.name].get('on_change'):
fields[field.name]['on_change'] = []
if fields[field.name].get('on_change_with'):
fields[field.name]['on_change_with'] = []
readonly = encoder.encode({"readonly": Not(Bool(Eval(
'translate_%s' % fields[field.name]['name'])))})
fields['translation_%s' % field.name] = {
'name': 'translation_%s' % fields[field.name],
'type': fields[field.name]['type'],
'string': 'Translation %s' % fields[field.name]['string'],
'states': readonly,
}
fields['translate_%s' % field.name] = {
'name': 'translate_%s' % fields[field.name],
'type': 'boolean',
'string': 'Translate %s' % fields[field.name]['string'],
}
etree.SubElement(xml_group, 'field', {
'name': field.name,
})
etree.SubElement(xml_group, 'field', {
'name': 'translation_%s' % field.name,
})
etree.SubElement(xml_group, 'field', {
'name': 'translate_%s' % field.name,
'xexpand': '0',
'width': '25',
})
res['arch'] = etree.tostring(root)
res['fields'] = fields
return res
@classmethod
def get_translation(cls, translator, text, source_lang, target_lang):
if translator:
translate = getattr(cls, 'get_translation_from_%s' % translator)
return translate(text, source_lang, target_lang)
@classmethod
def default_get(cls, fields, with_rec_name=True):
pool = Pool()
Translation = pool.get('ir.translation')
context = Transaction().context
source_lang = context.get('source_lang', None)
target_lang = context.get('target_lang', None)
active_id = context.get('active_id', None)
translator = context.get('translator', None)
model = context.get('active_model', None)
Model = pool.get(model)
res = {}
for field in fields:
if field == 'id':
continue
if not field.startswith('translat'):
resource = Translation.search([
('name', '=', '%s,%s' % (Model.__name__, field)),
('res_id', '=', active_id),
('lang', '=', source_lang),
], limit=1)
if not resource:
cls.raise_user_error('no_translation_found',
error_args=(field,))
res[field] = resource[0].value
res['translation_%s' % field] = cls.get_translation(
translator, res[field], source_lang, target_lang)
elif field.startswith('translate_'):
res[field] = False
return res
class TranslateWizard(Wizard):
'Translate Wizard'
__name__ = 'translate.wizard'
start = StateView(
'translate.wizard.start',
'translate.view_translate_wizard_start', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Translate', 'translate', 'tryton-ok', default=True),
])
translate = StateTransition()
translation = StateView(
'translate.wizard.translation',
'translate.view_translate_wizard_translation', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Apply', 'update', 'tryton-ok', default=True),
])
update = StateTransition()
def transition_translate(self):
context = Transaction().context
context['source_lang'] = self.start.source_lang
context['target_lang'] = self.start.target_lang
context['translator'] = self.start.translator
return 'translation'
def transition_update(self):
pool = Pool()
context = Transaction().context
model = context.get('active_model', None)
translates = Translate.search([('model.model', '=', model)], limit=1)
active_id = context.get('active_id', None)
Model = pool.get(model)
model = Model(active_id)
if translates:
translate, = translates
with Transaction().set_context(
language=self.start.target_lang):
data = {}
for f in translate.model_fields:
if getattr(self.translation, 'translate_%s' % f.name,
False):
data[f.name] = getattr(self.translation,
'translation_%s' % f.name)
Model.write([model], data)
return 'end'