diff --git a/addons/mail/models/mail_render_mixin.py b/addons/mail/models/mail_render_mixin.py index cbb70d3aacf..5804481f15c 100644 --- a/addons/mail/models/mail_render_mixin.py +++ b/addons/mail/models/mail_render_mixin.py @@ -80,6 +80,13 @@ class MailRenderMixin(models.AbstractModel): _name = 'mail.render.mixin' _description = 'Mail Render Mixin' + # language for rendering + lang = fields.Char( + 'Language', placeholder="${object.partner_id.lang}", + help="Optional translation language (ISO code) to select when sending out an email. " + "If not set, the english version will be used. This should usually be a placeholder expression " + "that provides the appropriate language, e.g. ${object.partner_id.lang}.") + # expression builder model_object_field = fields.Many2one( 'ir.model.fields', string="Field", store=False, help="Select target field from the related document model.\n" @@ -250,3 +257,74 @@ class MailRenderMixin(models.AbstractModel): rendered = self._render_template_postprocess(rendered) return rendered + + def _render_lang(self, res_ids): + """ Given some record ids, return the lang for each record based on + lang field of template or through specific context-based key. + + :param list res_ids: list of ids of records (all belonging to same model + defined by self.model) + + :return dict: {res_id: lang code (i.e. en_US)} + """ + self.ensure_one() + if not isinstance(res_ids, (list, tuple)): + raise ValueError(_('Template rendering for language should be called with a list of IDs.')) + + if self.env.context.get('template_preview_lang'): + return dict((res_id, self.env.context['template_preview_lang']) for res_id in res_ids) + else: + rendered_langs = self._render_template(self.lang, self.model, res_ids) + return dict((res_id, lang) + for res_id, lang in rendered_langs.items()) + + def _classify_per_lang(self, res_ids): + """ Given some record ids, return for computed each lang a contextualized + template and its subset of res_ids. + + :param list res_ids: list of ids of records (all belonging to same model + defined by self.model) + + :return dict: {lang: (template with lang=lang_code if specific lang computed + or template, res_ids targeted by that language} + """ + self.ensure_one() + + lang_to_res_ids = {} + for res_id, lang in self._render_lang(res_ids).items(): + lang_to_res_ids.setdefault(lang, []).append(res_id) + + return dict( + (lang, (self.with_context(lang=lang) if lang else self, lang_res_ids)) + for lang, lang_res_ids in lang_to_res_ids.items() + ) + + def _render_field(self, field, res_ids, compute_lang=False, set_lang=False, post_process=False): + """ Given some record ids, render a given field of template rendered on + all records. + + :param list res_ids: list of ids of records (all belonging to same model + defined by self.model) + :param compute_lang: compute rendering language based on template.lang + :param set_lang: force language + :param post_process: perform rendered str / html post processing (see + ``_render_template_postprocess``) + + :return dict: {res_id: string of rendered template based on record} + """ + self.ensure_one() + if compute_lang: + templates_res_ids = self._classify_per_lang(res_ids) + elif set_lang: + templates_res_ids = {set_lang: (self.with_context(lang=set_lang), res_ids)} + else: + templates_res_ids = {self._context.get('lang'): (self, res_ids)} + + return dict( + (res_id, rendered) + for lang, (template, tpl_res_ids) in templates_res_ids.items() + for res_id, rendered in template._render_template( + template[field], template.model, tpl_res_ids, + post_process=post_process + ).items() + ) diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index 72183aabf01..3fbe4b03e68 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -29,13 +29,6 @@ class MailTemplate(models.Model): name = fields.Char('Name') model_id = fields.Many2one('ir.model', 'Applies to', help="The type of document this template can be used with") model = fields.Char('Related Document Model', related='model_id.model', index=True, store=True, readonly=True) - lang = fields.Char('Language', - help="Optional translation language (ISO code) to select when sending out an email. " - "If not set, the english version will be used. " - "This should usually be a placeholder expression " - "that provides the appropriate language, e.g. " - "${object.partner_id.lang}.", - placeholder="${object.partner_id.lang}") subject = fields.Char('Subject', translate=True, help="Subject (placeholders may be used here)") email_from = fields.Char('From', help="Sender address (placeholders may be used here). If not set, the default " @@ -110,81 +103,6 @@ class MailTemplate(models.Model): return True - # ------------------------------------------------------------ - # RENDERING - # ------------------------------------------------------------ - - def _render_lang(self, res_ids): - """ Given some record ids, return the lang for each record based on - lang field of template or through specific context-based key. - - :param list res_ids: list of ids of records (all belonging to same model - defined by self.model) - - :return dict: {res_id: lang code (i.e. en_US)} - """ - self.ensure_one() - if not isinstance(res_ids, (list, tuple)): - raise ValueError(_('Template rendering for language should be called with a list of IDs.')) - - if self.env.context.get('template_preview_lang'): - return dict((res_id, self.env.context['template_preview_lang']) for res_id in res_ids) - else: - rendered_langs = self._render_template(self.lang, self.model, res_ids) - return dict((res_id, lang) - for res_id, lang in rendered_langs.items()) - - def _classify_per_lang(self, res_ids): - """ Given some record ids, return for computed each lang a contextualized - template and its subset of res_ids. - - :param list res_ids: list of ids of records (all belonging to same model - defined by self.model) - - :return dict: {lang: (template with lang=lang_code if specific lang computed - or template, res_ids targeted by that language} - """ - self.ensure_one() - - lang_to_res_ids = {} - for res_id, lang in self._render_lang(res_ids).items(): - lang_to_res_ids.setdefault(lang, []).append(res_id) - - return dict( - (lang, (self.with_context(lang=lang) if lang else self, lang_res_ids)) - for lang, lang_res_ids in lang_to_res_ids.items() - ) - - def _render_field(self, field, res_ids, compute_lang=False, set_lang=False, post_process=False): - """ Given some record ids, render a given field of template rendered on - all records. - - :param list res_ids: list of ids of records (all belonging to same model - defined by self.model) - :param compute_lang: compute rendering language based on template.lang - :param set_lang: force language - :param post_process: perform rendered str / html post processing (see - ``_render_template_postprocess``) - - :return dict: {res_id: string of rendered template based on record} - """ - self.ensure_one() - if compute_lang: - templates_res_ids = self._classify_per_lang(res_ids) - elif set_lang: - templates_res_ids = {set_lang: (self.with_context(lang=set_lang), res_ids)} - else: - templates_res_ids = {self._context.get('lang'): (self, res_ids)} - - return dict( - (res_id, rendered) - for lang, (template, tpl_res_ids) in templates_res_ids.items() - for res_id, rendered in template._render_template( - template[field], template.model, tpl_res_ids, - post_process=post_process - ).items() - ) - # ------------------------------------------------------------ # MESSAGE/EMAIL VALUES GENERATION # ------------------------------------------------------------ diff --git a/addons/sms/models/mail_thread.py b/addons/sms/models/mail_thread.py index 86713fddc24..820c5230cfe 100644 --- a/addons/sms/models/mail_thread.py +++ b/addons/sms/models/mail_thread.py @@ -180,8 +180,7 @@ class MailThread(models.AbstractModel): if not template and template_xmlid: template = self.env.ref(template_xmlid, raise_if_not_found=False) if template: - template_w_lang = template._get_context_lang_per_id(self.ids)[self.id] - body = template._render_template(template_w_lang.body, self._name, self.ids)[self.id] + body = template._render_field('body', self.ids, compute_lang=True)[self.id] else: body = self.env['sms.template']._render_template(template_fallback, self._name, self.ids)[self.id] return self._message_sms(body, partner_ids=partner_ids, **kwargs) diff --git a/addons/sms/models/sms_template.py b/addons/sms/models/sms_template.py index a2b2300051b..fb5b8877e87 100644 --- a/addons/sms/models/sms_template.py +++ b/addons/sms/models/sms_template.py @@ -24,9 +24,6 @@ class SMSTemplate(models.Model): help="The type of document this template can be used with", ondelete='cascade') model = fields.Char('Related Document Model', related='model_id.model', index=True, store=True, readonly=True) body = fields.Char('Body', translate=True, required=True) - lang = fields.Char('Language', help="Use this field to either force a specific language (ISO code) or dynamically " - "detect the language of your recipient by a placeholder expression " - "(e.g. ${object.partner_id.lang})") # Use to create contextual action (same as for email template) sidebar_action_id = fields.Many2one('ir.actions.act_window', 'Sidebar action', readonly=True, copy=False, help="Sidebar action to make this template available on records " @@ -67,43 +64,3 @@ class SMSTemplate(models.Model): if template.sidebar_action_id: template.sidebar_action_id.unlink() return True - - # ------------------------------------------------------------ - # RENDERING - # ------------------------------------------------------------ - - def _get_context_lang_per_id(self, res_ids): - self.ensure_one() - if res_ids is None: - return {None: self} - - if self.env.context.get('template_preview_lang'): - lang = self.env.context.get('template_preview_lang') - results = dict((res_id, self.with_context(lang=lang)) for res_id in res_ids) - else: - rendered_langs = self._render_template(self.lang, self.model, res_ids) - results = dict( - (res_id, self.with_context(lang=lang) if lang else self) - for res_id, lang in rendered_langs.items()) - - return results - - def _get_ids_per_lang(self, res_ids): - self.ensure_one() - - rids_to_tpl = self._get_context_lang_per_id(res_ids) - tpl_to_rids = {} - for res_id, template in rids_to_tpl.items(): - tpl_to_rids.setdefault(template._context.get('lang', self.env.user.lang), []).append(res_id) - - return tpl_to_rids - - def _get_translated_bodies(self, res_ids): - """ return sms translated bodies into a dict {'res_id':'body'} """ - self.ensure_one() - lang_to_rids = self._get_ids_per_lang(res_ids) - all_bodies = {} - for lang, rids in lang_to_rids.items(): - template = self.with_context(lang=lang) - all_bodies.update(template._render_template(template.body, self.model, rids)) - return all_bodies diff --git a/addons/sms/wizard/sms_composer.py b/addons/sms/wizard/sms_composer.py index 60c915d8172..7d5cbc9bfd2 100644 --- a/addons/sms/wizard/sms_composer.py +++ b/addons/sms/wizard/sms_composer.py @@ -168,7 +168,7 @@ class SendSMS(models.TransientModel): @api.onchange('composition_mode', 'res_model', 'res_id', 'template_id') def _onchange_template_id(self): if self.template_id and self.composition_mode == 'comment' and self.res_id: - self.body = self.template_id._get_translated_bodies([self.res_id])[self.res_id] + self.body = self.template_id._render_field('body', [self.res_id], compute_lang=True)[self.res_id] elif self.template_id: self.body = self.template_id.body @@ -279,7 +279,7 @@ class SendSMS(models.TransientModel): def _prepare_body_values(self, records): if self.template_id and self.body == self.template_id.body: - all_bodies = self.template_id._get_translated_bodies(records.ids) + all_bodies = self.template_id._render_field('body', records.ids, compute_lang=True) else: all_bodies = self.env['mail.render.mixin']._render_template(self.body, records._name, records.ids) return all_bodies diff --git a/addons/sms/wizard/sms_template_preview.py b/addons/sms/wizard/sms_template_preview.py index 9d00185ee2e..837c0b821b8 100644 --- a/addons/sms/wizard/sms_template_preview.py +++ b/addons/sms/wizard/sms_template_preview.py @@ -45,6 +45,7 @@ class SMSTemplatePreview(models.TransientModel): @api.depends('lang', 'resource_ref') def _compute_sms_template_fields(self): for wizard in self: - # Update body depending of the resource_ref - sms_template = wizard.sms_template_id.with_context(lang=wizard.lang) - wizard.body = sms_template._render_template(sms_template.body, sms_template.model, wizard.resource_ref.id) if wizard.resource_ref else sms_template.body + if wizard.sms_template_id and wizard.resource_ref: + wizard.body = wizard.sms_template_id._render_field('body', [wizard.resource_ref.id], set_lang=wizard.lang)[wizard.resource_ref.id] + else: + wizard.body = wizard.sms_template_id.body diff --git a/addons/test_mail_full/tests/test_sms_template.py b/addons/test_mail_full/tests/test_sms_template.py index a39edf8545f..d688b30d0f7 100644 --- a/addons/test_mail_full/tests/test_sms_template.py +++ b/addons/test_mail_full/tests/test_sms_template.py @@ -50,18 +50,20 @@ class TestSmsTemplate(test_mail_full_common.TestSMSCommon, test_mail_full_common self.assertEqual(self.sms_template.body, self.body_en) self.assertEqual(self.sms_template.with_context(lang='fr_FR').body, self.body_fr) - rid_to_tpl = self.sms_template._get_context_lang_per_id((self.test_record | test_record_2).ids) - self.assertEqual(set(rid_to_tpl.keys()), set((self.test_record | test_record_2).ids)) - for rid, tpl in rid_to_tpl.items(): + rid_to_lang = self.sms_template._render_lang((self.test_record | test_record_2).ids) + self.assertEqual(set(rid_to_lang.keys()), set((self.test_record | test_record_2).ids)) + for rid, lang in rid_to_lang.items(): + # TDE FIXME: False or en_US ? if rid == self.test_record.id: - self.assertEqual(tpl._context.get('lang'), 'en_US') + self.assertEqual(lang, 'en_US') elif rid == test_record_2.id: - self.assertEqual(tpl._context.get('lang'), 'fr_FR') + self.assertEqual(lang, 'fr_FR') else: self.assertTrue(False) - lang_to_rids = self.sms_template._get_ids_per_lang((self.test_record | test_record_2).ids) - for lang, rids in lang_to_rids.items(): + tpl_to_rids = self.sms_template._classify_per_lang((self.test_record | test_record_2).ids) + for lang, (tpl, rids) in tpl_to_rids.items(): + # TDE FIXME: False or en_US ? if lang == 'en_US': self.assertEqual(rids, self.test_record.ids) elif lang == 'fr_FR': @@ -87,4 +89,3 @@ class TestSmsTemplate(test_mail_full_common.TestSMSCommon, test_mail_full_common self.sms_template.unlink() self.assertEqual(ActWindow.search_count([('id', '=', action_id)]), 0) -