lims_report_html: add template translation

This commit is contained in:
Adrián Bernardi 2020-05-23 11:19:07 -03:00
parent 0da7240d70
commit cdaa89b076
14 changed files with 463 additions and 23 deletions

View File

@ -102,13 +102,13 @@ class ResultReport(metaclass=PoolMeta):
@classmethod
def get_results_report_template(cls, action, detail_id):
content = super(ResultReport, cls).get_results_report_template(
action, detail_id)
content, template_id = super(ResultReport,
cls).get_results_report_template(action, detail_id)
signature = 'show_diagnosis_content'
diagnosis_content = (
'{%% macro %s(sample) %%}\n%s\n{%% endmacro %%}' % (
signature, '{{ sample.diagnosis }}'))
return '%s\n\n%s' % (diagnosis_content, content)
return '%s\n\n%s' % (diagnosis_content, content), template_id
@classmethod
def get_context(cls, records, data):

View File

@ -13,6 +13,7 @@ def register():
Pool.register(
action.ActionReport,
html_template.ReportTemplate,
html_template.ReportTemplateTranslation,
sample.Sample,
sample.CreateSampleStart,
results_report.ResultsReportVersionDetail,

View File

@ -3,8 +3,11 @@
# the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields
from trytond.pool import Pool
from trytond.transaction import Transaction
from trytond.cache import Cache
__all__ = ['ReportTemplate']
__all__ = ['ReportTemplate', 'ReportTemplateTranslation']
class ReportTemplate(ModelSQL, ModelView):
@ -13,3 +16,73 @@ class ReportTemplate(ModelSQL, ModelView):
name = fields.Char('Name', required=True)
content = fields.Text('Content', required=True)
translations = fields.One2Many('lims.result_report.template.translation',
'template', 'Translations')
_translation_cache = Cache('lims.result_report.template.translation',
size_limit=10240, context=False)
@classmethod
def gettext(cls, *args, **variables):
ReportTemplateTranslation = Pool().get(
'lims.result_report.template.translation')
template, src, lang = args
key = (template, src, lang)
text = cls._translation_cache.get(key)
if text is None:
translations = ReportTemplateTranslation.search([
('template', '=', template),
('src', '=', src),
('lang', '=', lang),
], limit=1)
if translations:
text = translations[0].value
else:
text = src
cls._translation_cache.set(key, text)
return text if not variables else text % variables
class ReportTemplateTranslation(ModelSQL, ModelView):
'Results Report Template Translation'
__name__ = 'lims.result_report.template.translation'
_order_name = 'src'
template = fields.Many2One('lims.result_report.template', 'Template',
ondelete='CASCADE', select=True, required=True)
src = fields.Text('Source', required=True)
value = fields.Text('Translation Value', required=True)
lang = fields.Selection('get_language', string='Language', required=True)
_get_language_cache = Cache(
'lims.result_report.template.translation.get_language')
@staticmethod
def default_lang():
return Transaction().language
@classmethod
def get_language(cls):
result = cls._get_language_cache.get(None)
if result is not None:
return result
langs = Pool().get('ir.lang').search([('translatable', '=', True)])
result = [(lang.code, lang.name) for lang in langs]
cls._get_language_cache.set(None, result)
return result
@classmethod
def create(cls, vlist):
Template = Pool().get('lims.result_report.template')
Template._translation_cache.clear()
return super(ReportTemplateTranslation, cls).create(vlist)
@classmethod
def write(cls, *args):
Template = Pool().get('lims.result_report.template')
Template._translation_cache.clear()
return super(ReportTemplateTranslation, cls).write(*args)
@classmethod
def delete(cls, translations):
Template = Pool().get('lims.result_report.template')
Template._translation_cache.clear()
return super(ReportTemplateTranslation, cls).delete(translations)

View File

@ -34,5 +34,18 @@
id="menu_html_template_list"
parent="lims.lims_config_report" sequence="10"/>
<!-- Results Report Template Translation -->
<record model="ir.ui.view" id="template_translation_view_form">
<field name="model">lims.result_report.template.translation</field>
<field name="type">form</field>
<field name="name">template_translation_form</field>
</record>
<record model="ir.ui.view" id="template_translation_view_list">
<field name="model">lims.result_report.template.translation</field>
<field name="type">tree</field>
<field name="name">template_translation_list</field>
</record>
</data>
</tryton>

View File

@ -18,6 +18,26 @@ msgctxt "field:lims.result_report.template,name:"
msgid "Name"
msgstr "Nombre"
msgctxt "field:lims.result_report.template,translations:"
msgid "Translations"
msgstr "Traducciones"
msgctxt "field:lims.result_report.template.translation,lang:"
msgid "Language"
msgstr "Idioma"
msgctxt "field:lims.result_report.template.translation,src:"
msgid "Source"
msgstr "Original"
msgctxt "field:lims.result_report.template.translation,template:"
msgid "Template"
msgstr "Plantilla"
msgctxt "field:lims.result_report.template.translation,value:"
msgid "Translation Value"
msgstr "Traducción"
msgctxt "field:lims.results_report.version.detail,template:"
msgid "Report Template"
msgstr "Plantilla de Informe"
@ -50,6 +70,14 @@ msgctxt "model:lims.result_report.template,name:"
msgid "Results Report Template"
msgstr "Plantilla de Informe de resultados"
msgctxt "model:lims.result_report.template.translation,name:"
msgid "Results Report Template Translation"
msgstr "Traducción de Plantilla de Informe de resultados"
msgctxt "view:lims.result_report.template:"
msgid "Content"
msgstr "Contenido"
msgctxt "view:lims.result_report.template:"
msgid "Translations"
msgstr "Traducciones"

View File

@ -981,7 +981,7 @@
{% if stp_polisample_project == 'True' and fraction.stp_variety %}
<tr>
<td colspan="2" style="width:100%;">
<p>{{ _('CUSTOMER VARIETY') }}: {{ fraction.stp_variety }}</p>
<p>{{ _('VARIETY') }}: {{ fraction.stp_variety }}</p>
</td>
</tr>
{% endif %}
@ -1216,7 +1216,7 @@
<table style="width:100%;">
<tr>
<td style="width:100%;">
<p class="text-center">The results only refer to the analyzed samples. This report must not be partially reproduced without the written approval of {{ company.party.rec_name }}.</p>
<p class="text-center">{{ _('The results only refer to the analyzed samples. This report must not be partially reproduced without the written approval of') }} {{ company.party.rec_name }}.</p>
</td>
</tr>
</table>

View File

@ -0,0 +1,2 @@
[jinja2: **.html]
extensions=jinja2.ext.i18n,jinja2.ext.autoescape,jinja2.ext.with_

View File

@ -0,0 +1,115 @@
msgid "ACTIVE INGREDIENT"
msgstr "PRINCIPIO ACTIVO"
msgid "ADDRESS"
msgstr "DIRECCIÓN"
msgid "APPLICATION DATES"
msgstr "FECHA/S DE APLICACIÓN"
msgid "Analysis"
msgstr "Análisis"
msgid "BEGINNING OF THE ANALYSIS"
msgstr "FECHA INICIO DE ANÁLISIS"
msgid "CODE OF THE SAMPLE"
msgstr "CÓDIGO DE LA MUESTRA"
msgid "CONFIRMATION SAMPLE RECEPTION"
msgstr "CONFIRMACIÓN INGRESO DE LA MUESTRA"
msgid "CONTAINER"
msgstr "ENVASE"
msgid "CUSTOMER DESCRIPTION"
msgstr "DESCRIPCIÓN DEL CLIENTE"
msgid "DAYS AFTER TREATMENT (DAT)"
msgstr "DÍAS DESPUÉS DE APLICADO"
msgid "DOSE"
msgstr "DOSIS"
msgid "Date"
msgstr "Fecha"
msgid "Detection Limit"
msgstr "Límite de Detección"
msgid "END OF ANALYSIS"
msgstr "FECHA FINALIZACIÓN DE ANÁLISIS"
msgid "FORMULATION TYPES"
msgstr "TIPO DE FORMULACIÓN ARMONIZADA"
msgid "For the SAT NRO"
msgstr "Correspondiente al SAT NRO"
msgid "LABEL"
msgstr "RÓTULO"
msgid "METHODS"
msgstr "MÉTODOS"
msgid "Method"
msgstr "Método"
msgid "OBSERVATIONS"
msgstr "OBSERVACIONES"
msgid "PRODUCER COMPANY"
msgstr "EMPRESA PRODUCTORA"
msgid "RECEIVED SAMPLE"
msgstr "MUESTRA RECIBIDA"
msgid "REPETITION"
msgstr "REPETICIÓN"
msgid "REPORT Nº"
msgstr "INFORME Nº"
msgid "REQUESTED BY"
msgstr "SOLICITADO POR"
msgid "RESULTS"
msgstr "RESULTADOS"
msgid "Result"
msgstr "Resultado"
msgid "Results Report"
msgstr "Informe de resultados"
msgid "SAMPLE PRESENTATION"
msgstr "PRESENTACIÓN DE LA MUESTRA"
msgid "SAMPLING DATE"
msgstr "FECHA DE MUESTREO"
msgid "SENASA PROTOCOL N°"
msgstr "PROTOCOLO SENASA N°"
msgid "STUDY PLAN N°"
msgstr "PLAN DE ESTUDIO N°"
msgid "TREATMENT"
msgstr "TRATAMIENTO"
msgid ""
"The results only refer to the analyzed samples. This report must not be "
"partially reproduced without the written approval of"
msgstr ""
"Los resultados corresponden exclusivamente a las muestras analizadas. El "
"informe no debe reproducirse parcialmente sin la aprobación escrita de"
msgid "Unit"
msgstr "Unidad"
msgid "VARIETY"
msgstr "VARIEDAD"
msgid "ZONE"
msgstr "ZONA"

View File

@ -0,0 +1,113 @@
msgid "ACTIVE INGREDIENT"
msgstr ""
msgid "ADDRESS"
msgstr ""
msgid "APPLICATION DATES"
msgstr ""
msgid "Analysis"
msgstr ""
msgid "BEGINNING OF THE ANALYSIS"
msgstr ""
msgid "CODE OF THE SAMPLE"
msgstr ""
msgid "CONFIRMATION SAMPLE RECEPTION"
msgstr ""
msgid "CONTAINER"
msgstr ""
msgid "CUSTOMER DESCRIPTION"
msgstr ""
msgid "DAYS AFTER TREATMENT (DAT)"
msgstr ""
msgid "DOSE"
msgstr ""
msgid "Date"
msgstr ""
msgid "Detection Limit"
msgstr ""
msgid "END OF ANALYSIS"
msgstr ""
msgid "FORMULATION TYPES"
msgstr ""
msgid "For the SAT NRO"
msgstr ""
msgid "LABEL"
msgstr ""
msgid "METHODS"
msgstr ""
msgid "Method"
msgstr ""
msgid "OBSERVATIONS"
msgstr ""
msgid "PRODUCER COMPANY"
msgstr ""
msgid "RECEIVED SAMPLE"
msgstr ""
msgid "REPETITION"
msgstr ""
msgid "REPORT Nº"
msgstr ""
msgid "REQUESTED BY"
msgstr ""
msgid "RESULTS"
msgstr ""
msgid "Result"
msgstr ""
msgid "Results Report"
msgstr ""
msgid "SAMPLE PRESENTATION"
msgstr ""
msgid "SAMPLING DATE"
msgstr ""
msgid "SENASA PROTOCOL N°"
msgstr ""
msgid "STUDY PLAN N°"
msgstr ""
msgid "TREATMENT"
msgstr ""
msgid ""
"The results only refer to the analyzed samples. This report must not be "
"partially reproduced without the written approval of"
msgstr ""
msgid "Unit"
msgstr ""
msgid "VARIETY"
msgstr ""
msgid "ZONE"
msgstr ""

View File

@ -1,8 +1,10 @@
# This file is part of lims_report_html module for Tryton.
# The COPYRIGHT file at the top level of this repository contains
# the full copyright notices and license terms.
import os
from lxml import html as lxml_html
from base64 import b64encode
from babel.support import Translations as BabelTranslations
from trytond.model import fields
from trytond.pool import Pool, PoolMeta
@ -93,16 +95,12 @@ class ResultReport(metaclass=PoolMeta):
cls.check_access()
action, model = cls.get_action(data)
with Transaction().set_context(html_report=action.id):
records = []
if model:
records = cls._get_records(ids, model, data)
#records = cls._get_dual_records(ids, model, data)
oext, content = cls._execute_html_results_report(records, data,
action)
if not isinstance(content, str):
content = bytearray(content) if bytes == str else bytes(
content)
records = []
if model:
records = cls._get_records(ids, model, data)
oext, content = cls._execute_html_results_report(records, data, action)
if not isinstance(content, str):
content = bytearray(content) if bytes == str else bytes(content)
return oext, content, cls.get_direct_print(action), cls.get_name(
action)
@ -111,9 +109,17 @@ class ResultReport(metaclass=PoolMeta):
def _execute_html_results_report(cls, records, data, action):
documents = []
for record in records:
template = cls.get_results_report_template(action, record.id)
content = cls.render_results_report_template(action, template,
record=record, records=[record], data=data)
template_content, template_id = cls.get_results_report_template(
action, record.id)
context = Transaction().context
context['template'] = template_id
if not template_id:
context['default_translations'] = os.path.join(
os.path.dirname(__file__), 'report', 'translations')
with Transaction().set_context(**context):
content = cls.render_results_report_template(action,
template_content, record=record, records=[record],
data=data)
if action.extension == 'pdf':
documents.append(PdfGenerator(content, side_margin=1,
extra_vertical_margin=30).render_html())
@ -130,19 +136,33 @@ class ResultReport(metaclass=PoolMeta):
@classmethod
def get_results_report_template(cls, action, detail_id):
ResultsDetail = Pool().get('lims.results_report.version.detail')
content, template_id = None, None
detail = ResultsDetail(detail_id)
content = detail.template and detail.template.content
if detail.template:
content = detail.template.content
template_id = detail.template
if not content:
content = (action.report_content and
action.report_content.decode('utf-8'))
if not content:
raise UserError(gettext('lims_report_html.msg_no_template'))
return content
return content, template_id
@classmethod
def render_results_report_template(cls, action, template_string,
record=None, records=None, data=None):
env = cls.get_environment()
User = Pool().get('res.user')
user = User(Transaction().user)
if data and data.get('alt_lang'):
locale = data['alt_lang']
elif user.language:
locale = user.language.code
else:
locale = Transaction().language
with Transaction().set_context(locale=locale):
env = cls.get_results_report_environment()
report_template = env.from_string(template_string)
context = cls.get_context(records, data)
context.update({
@ -154,6 +174,16 @@ class ResultReport(metaclass=PoolMeta):
# print('TEMPLATE:\n', res)
return res
@classmethod
def get_results_report_environment(cls):
env = cls.get_environment()
context = Transaction().context
locale = context.get('locale').split('_')[0]
translations = TemplateTranslations(locale)
env.install_gettext_translations(translations)
return env
@classmethod
def parse_images(cls, template_string):
Attachment = Pool().get('ir.attachment')
@ -179,3 +209,47 @@ class ResultReport(metaclass=PoolMeta):
return ''
b64_image = b64encode(image).decode()
return 'data:image/png;base64,%s' % b64_image
class TemplateTranslations:
def __init__(self, lang='en'):
self.cache = {}
self.env = None
self.current = None
self.language = lang
self.template = None
self.set_language(lang)
def set_language(self, lang='en'):
self.language = lang
if lang in self.cache:
self.current = self.cache[lang]
return
context = Transaction().context
if context.get('default_translations'):
default_translations = context['default_translations']
if os.path.isdir(default_translations):
self.current = BabelTranslations.load(
dirname=default_translations, locales=[lang])
self.cache[lang] = self.current
else:
self.template = context.get('template', -1)
def ugettext(self, message):
ReportTemplate = Pool().get('lims.result_report.template')
if self.current:
return self.current.ugettext(message)
elif self.template:
return ReportTemplate.gettext(self.template, message,
self.language)
return message
def ngettext(self, singular, plural, n):
ReportTemplate = Pool().get('lims.result_report.template')
if self.current:
return self.current.ugettext(singular, plural, n)
elif self.template:
return ReportTemplate.gettext(self.template, singular,
self.language)
return singular

View File

@ -6,5 +6,8 @@
<field name="content" colspan="4" widget="html"/>
<field name="content" colspan="4"/>
</page>
<page id="translations" string="Translations">
<field name="translations" colspan="4"/>
</page>
</notebook>
</form>

View File

@ -0,0 +1,12 @@
<form>
<label name="template"/>
<field name="template"/>
<label name="lang"/>
<field name="lang"/>
<group id="src_value" colspan="4" col="2" yexpand="1" yfill="1">
<separator name="src"/>
<separator name="value"/>
<field name="src"/>
<field name="value"/>
</group>
</form>

View File

@ -0,0 +1,6 @@
<tree editable="top">
<field name="template"/>
<field name="lang"/>
<field name="src"/>
<field name="value"/>
</tree>

View File

@ -87,7 +87,7 @@ for name in os.listdir('.'):
for data_pattern in (info.get('xml', []) + ['tryton.cfg', 'view/*.xml',
'locale/*.po', 'locale/override/*.po', 'report/*.fodt',
'report/*.fods', 'report/*.html', 'report/stylesheet/*.css',
'icons/*.svg', 'tests/*.rst']):
'report/translations/*/*/*.po', 'icons/*.svg', 'tests/*.rst']):
data.append(data_pattern)
if data:
package_data[subpackage] = data