From: Eileen McNaughton Date: Tue, 28 Jun 2022 04:39:07 +0000 (-0700) Subject: Translations - if a message_template has been translated then get/render the translat... X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=5ea3ea091d05ececb9ad62803f8c6376de3e503c;p=civicrm-core.git Translations - if a message_template has been translated then get/render the translated version --- diff --git a/CRM/Core/BAO/MessageTemplate.php b/CRM/Core/BAO/MessageTemplate.php index 5f63cb1520..10d357e86b 100644 --- a/CRM/Core/BAO/MessageTemplate.php +++ b/CRM/Core/BAO/MessageTemplate.php @@ -341,9 +341,18 @@ class CRM_Core_BAO_MessageTemplate extends CRM_Core_DAO_MessageTemplate implemen self::synchronizeLegacyParameters($params); $params = array_merge($modelDefaults, $viewDefaults, $envelopeDefaults, $params); - + $language = $params['language'] ?? (!empty($params['contactId']) ? Civi\Api4\Contact::get(FALSE)->addWhere('id', '=', $params['contactId'])->addSelect('preferred_language')->execute()->first()['preferred_language'] : NULL); CRM_Utils_Hook::alterMailParams($params, 'messageTemplate'); - $mailContent = self::loadTemplate((string) $params['workflow'], $params['isTest'], $params['messageTemplateID'] ?? NULL, $params['groupName'] ?? '', $params['messageTemplate'], $params['subject'] ?? NULL); + [$mailContent, $translatedLanguage] = self::loadTemplate((string) $params['workflow'], $params['isTest'], $params['messageTemplateID'] ?? NULL, $params['groupName'] ?? '', $params['messageTemplate'], $params['subject'] ?? NULL, $language); + global $moneyFormatLocale; + $originalValue = $moneyFormatLocale; + if ($translatedLanguage) { + // If the template has been translated then set the moneyFormatLocale to match the translation. + // Note that in future if we do the same for dates we are likely to want to set it to match + // the preferred_language rather than the translation language - a long discussion is on the + // property in AbstractAction + $moneyFormatLocale = $translatedLanguage; + } self::synchronizeLegacyParameters($params); $rendered = CRM_Core_TokenSmarty::render(CRM_Utils_Array::subset($mailContent, ['text', 'html', 'subject']), $params['tokenContext'], $params['tplParams']); @@ -352,6 +361,7 @@ class CRM_Core_BAO_MessageTemplate extends CRM_Core_DAO_MessageTemplate implemen } $nullSet = ['subject' => NULL, 'text' => NULL, 'html' => NULL]; $mailContent = array_merge($nullSet, $mailContent, $rendered); + $moneyFormatLocale = $originalValue; return [$mailContent, $params]; } @@ -459,18 +469,20 @@ class CRM_Core_BAO_MessageTemplate extends CRM_Core_DAO_MessageTemplate implemen * If omitted, the record will be loaded from workflowName/messageTemplateID. * @param string|null $subjectOverride * This option is the older, wonkier version of $messageTemplate['msg_subject']... + * @param string|null $language * * @return array * @throws \API_Exception * @throws \CRM_Core_Exception */ - protected static function loadTemplate(string $workflowName, bool $isTest, int $messageTemplateID = NULL, $groupName = NULL, ?array $messageTemplateOverride = NULL, ?string $subjectOverride = NULL): array { + protected static function loadTemplate(string $workflowName, bool $isTest, int $messageTemplateID = NULL, $groupName = NULL, ?array $messageTemplateOverride = NULL, ?string $subjectOverride = NULL, ?string $language = NULL): array { $base = ['msg_subject' => NULL, 'msg_text' => NULL, 'msg_html' => NULL, 'pdf_format_id' => NULL]; if (!$workflowName && !$messageTemplateID) { throw new CRM_Core_Exception(ts("Message template's option value or ID missing.")); } $apiCall = MessageTemplate::get(FALSE) + ->setLanguage($language) ->addSelect('msg_subject', 'msg_text', 'msg_html', 'pdf_format_id', 'id') ->addWhere('is_default', '=', 1); @@ -480,7 +492,8 @@ class CRM_Core_BAO_MessageTemplate extends CRM_Core_DAO_MessageTemplate implemen else { $apiCall->addWhere('workflow_name', '=', $workflowName); } - $messageTemplate = array_merge($base, $apiCall->execute()->first() ?: [], $messageTemplateOverride ?: []); + $result = $apiCall->execute(); + $messageTemplate = array_merge($base, $result->first() ?: [], $messageTemplateOverride ?: []); if (empty($messageTemplate['id']) && empty($messageTemplateOverride)) { if ($messageTemplateID) { throw new CRM_Core_Exception(ts('No such message template: id=%1.', [1 => $messageTemplateID])); diff --git a/tests/events/hook_civicrm_alterMailParams.evch.php b/tests/events/hook_civicrm_alterMailParams.evch.php index cc331f1aa2..c41e9ee78a 100644 --- a/tests/events/hook_civicrm_alterMailParams.evch.php +++ b/tests/events/hook_civicrm_alterMailParams.evch.php @@ -40,6 +40,9 @@ return new class() extends EventCheck implements HookInterface { 'Precedence' => ['type' => 'string|NULL', 'for' => ['civimail', 'flexmailer'], 'regex' => '/(bulk|first-class|list)/'], 'job_id' => ['type' => 'int|NULL', 'for' => ['civimail', 'flexmailer']], + // ## Language + 'language' => ['type' => 'string|NULL', 'for' => ['messageTemplate']], + // ## Content 'subject' => ['for' => ['messageTemplate', 'singleEmail'], 'type' => 'string'], diff --git a/tests/phpunit/CRM/Core/BAO/MessageTemplateTest.php b/tests/phpunit/CRM/Core/BAO/MessageTemplateTest.php index 7b87397f88..4172795d99 100644 --- a/tests/phpunit/CRM/Core/BAO/MessageTemplateTest.php +++ b/tests/phpunit/CRM/Core/BAO/MessageTemplateTest.php @@ -46,6 +46,94 @@ class CRM_Core_BAO_MessageTemplateTest extends CiviUnitTestCase { $this->assertStringContainsString('

Hello testRenderTemplate Abba Baab!

', $rendered['html']); } + /** + * Test that translated strings are rendered for templates where they exist. + * + * @throws \API_Exception|\CRM_Core_Exception + */ + public function testRenderTranslatedTemplate(): void { + $this->individualCreate(['preferred_language' => 'fr_FR']); + $contributionID = $this->contributionCreate(['contact_id' => $this->ids['Contact']['individual_0']]); + $messageTemplateID = MessageTemplate::get() + ->addWhere('is_default', '=', 1) + ->addWhere('workflow_name', '=', 'contribution_online_receipt') + ->addSelect('id') + ->execute()->first()['id']; + + Translation::save()->setRecords([ + ['entity_field' => 'msg_subject', 'string' => 'Bonjour'], + ['entity_field' => 'msg_html', 'string' => 'Voila!'], + ['entity_field' => 'msg_text', 'string' => '{contribution.total_amount}'], + ])->setDefaults([ + 'entity_table' => 'civicrm_msg_template', + 'entity_id' => $messageTemplateID, + 'status_id:name' => 'active', + 'language' => 'fr_FR', + ])->execute(); + + $messageTemplateFrench = MessageTemplate::get() + ->addWhere('is_default', '=', 1) + ->addWhere('workflow_name', '=', 'contribution_online_receipt') + ->addSelect('id', 'msg_subject', 'msg_html') + ->setLanguage('fr_FR') + ->execute()->first(); + + $this->assertEquals('Bonjour', $messageTemplateFrench['msg_subject']); + $this->assertEquals('Voila!', $messageTemplateFrench['msg_html']); + + $rendered = CRM_Core_BAO_MessageTemplate::renderTemplate([ + 'workflow' => 'contribution_online_receipt', + 'tokenContext' => [ + 'contactId' => $this->ids['Contact']['individual_0'], + 'contributionId' => $contributionID, + ], + ]); + $this->assertEquals('Bonjour', $rendered['subject']); + $this->assertEquals('Voila!', $rendered['html']); + $this->assertEquals('100,00 $US', $rendered['text']); + + // French Canadian should ALSO pick up French if there + //is no specific French Canadian. + $rendered = CRM_Core_BAO_MessageTemplate::renderTemplate([ + 'workflow' => 'contribution_online_receipt', + 'tokenContext' => [ + 'contactId' => $this->ids['Contact']['individual_0'], + 'contributionId' => $contributionID, + ], + 'language' => 'fr_CA', + ]); + $this->assertEquals('Bonjour', $rendered['subject']); + $this->assertEquals('Voila!', $rendered['html']); + // Money is formatted per fr_FR locale as that is the found-template-locale. + $this->assertEquals('100,00 $US', $rendered['text']); + + Translation::save()->setRecords([ + ['entity_field' => 'msg_subject', 'string' => 'Bonjour Canada'], + ['entity_field' => 'msg_html', 'string' => 'Voila! Canada'], + ['entity_field' => 'msg_text', 'string' => '{contribution.total_amount}'], + ])->setDefaults([ + 'entity_table' => 'civicrm_msg_template', + 'entity_id' => $messageTemplateID, + 'status_id:name' => 'active', + 'language' => 'fr_CA', + ])->execute(); + + // But, prefer French Canadian where both exist. + $rendered = CRM_Core_BAO_MessageTemplate::renderTemplate([ + 'workflow' => 'contribution_online_receipt', + 'tokenContext' => [ + 'contactId' => $this->ids['Contact']['individual_0'], + 'contributionId' => $contributionID, + ], + 'language' => 'fr_CA', + ]); + $this->assertEquals('Bonjour Canada', $rendered['subject']); + $this->assertEquals('Voila! Canada', $rendered['html']); + // Note that as there was a native-Canada format the money-formatting is + // also subtly different. + $this->assertEquals('100,00 $ US', $rendered['text']); + } + /** * @throws \API_Exception * @throws \CRM_Core_Exception