Skip to content

Commit

Permalink
(Update) Translations - if a message_template has been translated the…
Browse files Browse the repository at this point in the history
…n get/render the translated version

* Updates for APIv4 calls
  * Set `$language` and `#ranslationMode()` instead of `$preferredLanguage`
  * Read 'actual_language' instead of `getTranslationLanguage()`
* Updates for tracking global locale properties
  * Use `$loacleObj->moneyFormat` instead of `$GLOBALS['moneyFormatLocale']` and `IGNORE_SEPARATOR_CONFIG`
  * Use `$tokenContext['locale']` instead of `$GLOBALS['moneyFormatLocale']` and `IGNORE_SEPARATOR_CONFIG`
* Split `testRenderTranslatedTemplate()` in two (for different configurations)
  • Loading branch information
totten committed Aug 29, 2022
1 parent bfa373d commit c941fa2
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 25 deletions.
14 changes: 3 additions & 11 deletions CRM/Core/BAO/MessageTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -344,15 +344,7 @@ protected static function renderTemplateRaw($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, $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;
}
$params['tokenContext']['locale'] = $translatedLanguage ?? $params['language'] ?? NULL;

self::synchronizeLegacyParameters($params);
$rendered = CRM_Core_TokenSmarty::render(CRM_Utils_Array::subset($mailContent, ['text', 'html', 'subject']), $params['tokenContext'], $params['tplParams']);
Expand All @@ -361,7 +353,6 @@ protected static function renderTemplateRaw($params) {
}
$nullSet = ['subject' => NULL, 'text' => NULL, 'html' => NULL];
$mailContent = array_merge($nullSet, $mailContent, $rendered);
$moneyFormatLocale = $originalValue;
return [$mailContent, $params];
}

Expand Down Expand Up @@ -483,6 +474,7 @@ protected static function loadTemplate(string $workflowName, bool $isTest, int $

$apiCall = MessageTemplate::get(FALSE)
->setLanguage($language)
->setTranslationMode('fuzzy')
->addSelect('msg_subject', 'msg_text', 'msg_html', 'pdf_format_id', 'id')
->addWhere('is_default', '=', 1);

Expand Down Expand Up @@ -540,7 +532,7 @@ protected static function loadTemplate(string $workflowName, bool $isTest, int $
$mailContent['subject'] = $subjectOverride;
}

return [$mailContent, $apiCall->getTranslationLanguage()];
return [$mailContent, $messageTemplate['actual_language'] ?? NULL];
}

/**
Expand Down
14 changes: 1 addition & 13 deletions Civi/Api4/Action/WorkflowMessage/Render.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,24 +75,12 @@ class Render extends \Civi\Api4\Generic\AbstractAction {

public function _run(\Civi\Api4\Generic\Result $result) {
$this->validateValues();
global $moneyFormatLocale;
$separatorConfig = \CRM_Utils_Constant::value('IGNORE_SEPARATOR_CONFIG');
$originalValue = $moneyFormatLocale;

if ($this->getTranslationLanguage()) {
// Passing in translation language forces money formatting, useful when the
// template is previewed before being saved.
$moneyFormatLocale = $this->getTranslationLanguage();
putenv('IGNORE_SEPARATOR_CONFIG=' . 1);
}
$r = \CRM_Core_BAO_MessageTemplate::renderTemplate([
'model' => $this->_model,
'messageTemplate' => $this->getMessageTemplate(),
'messageTemplateId' => $this->getMessageTemplateId(),
'language' => $this->getPreferredLanguage(),
'language' => $this->getLanguage(),
]);
$moneyFormatLocale = $originalValue;
putenv('IGNORE_SEPARATOR_CONFIG=' . $separatorConfig);
$result[] = \CRM_Utils_Array::subset($r, ['subject', 'html', 'text']);
}

Expand Down
66 changes: 65 additions & 1 deletion tests/phpunit/CRM/Core/BAO/MessageTemplateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use Civi\Api4\Address;
use Civi\Api4\Contact;
use Civi\Api4\MessageTemplate;
use Civi\Api4\Translation;
use Civi\Token\TokenProcessor;

/**
Expand Down Expand Up @@ -49,9 +50,16 @@ public function testRenderTemplate(): void {
/**
* Test that translated strings are rendered for templates where they exist.
*
* This system has a relatively open localization policy where any translation can be used,
* even if the system doesn't allow it in the web UI. Ex: The sysadmin has configured 'fr_FR'
* strings. The user has requested 'fr_CA', and we'll fallback to 'fr_CA'.
*
* @throws \API_Exception|\CRM_Core_Exception
* @group locale
*/
public function testRenderTranslatedTemplate(): void {
public function testRenderTranslatedTemplate_AllowPartialLocales(): void {
$cleanup = \CRM_Utils_AutoClean::swapSettings(['partial_locales' => TRUE, 'uiLanguages' => ['en_US']]);

$this->individualCreate(['preferred_language' => 'fr_FR']);
$contributionID = $this->contributionCreate(['contact_id' => $this->ids['Contact']['individual_0']]);
$messageTemplateID = MessageTemplate::get()
Expand All @@ -76,6 +84,7 @@ public function testRenderTranslatedTemplate(): void {
->addWhere('workflow_name', '=', 'contribution_online_receipt')
->addSelect('id', 'msg_subject', 'msg_html')
->setLanguage('fr_FR')
->setTranslationMode('fuzzy')
->execute()->first();

$this->assertEquals('Bonjour', $messageTemplateFrench['msg_subject']);
Expand Down Expand Up @@ -134,6 +143,61 @@ public function testRenderTranslatedTemplate(): void {
$this->assertEquals('100,00 $ US', $rendered['text']);
}

/**
* Test that translated strings are rendered for templates where they exist.
*
* This system has a relatively closed localization policy where translations will only be
* used if the locale is fully supported by the app. Ex: Even though there are some strings
* for 'fr_FR', the language in "Admin=>Localizaton", so we don't use it.
*
* @throws \API_Exception|\CRM_Core_Exception
* @group locale
*/
public function testRenderTranslatedTemplate_OnlyFullLocales(): void {
$cleanup = \CRM_Utils_AutoClean::swapSettings(['partial_locales' => FALSE, 'uiLanguages' => ['en_US']]);

$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')
->setTranslationMode('fuzzy')
->execute()->first();

$this->assertStringNotContainsString('Bonjour', $messageTemplateFrench['msg_subject']);
$this->assertStringNotContainsString('Voila!', $messageTemplateFrench['msg_html']);

$rendered = CRM_Core_BAO_MessageTemplate::renderTemplate([
'workflow' => 'contribution_online_receipt',
'tokenContext' => [
'contactId' => $this->ids['Contact']['individual_0'],
'contributionId' => $contributionID,
],
]);
$this->assertStringNotContainsString('Bonjour', $rendered['subject']);
$this->assertStringNotContainsString('Voila!', $rendered['html']);
$this->assertStringNotContainsString('100,00', $rendered['text']);
}

/**
* @throws \API_Exception
* @throws \CRM_Core_Exception
Expand Down

0 comments on commit c941fa2

Please sign in to comment.