From: Tim Otten Date: Tue, 10 Aug 2021 03:55:44 +0000 (-0700) Subject: TokenProcessor - If there is a `locale`, then use it X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=4b7b899badc1312040384e15ffdf23bab7425814;p=civicrm-core.git TokenProcessor - If there is a `locale`, then use it There are two likely ways in which a tokenized email winds up with localized strings - either the Smarty `{ts}...{/ts}` tags define it, or a custom/hook-based tag uses `ts()`. This ensures that the locale is set in both cases. It's hypothetically possible that some other `civi.token.eval` listeners need to use the `row->context['locale']`. However, I grepped universe and couldn't find anything that would be affected. (There were two contrib listeners for `civi.token.eval` and neither seemed to be affected.) --- diff --git a/Civi/Token/TokenCompatSubscriber.php b/Civi/Token/TokenCompatSubscriber.php index d957c3cb9d..c2d6c5b6e1 100644 --- a/Civi/Token/TokenCompatSubscriber.php +++ b/Civi/Token/TokenCompatSubscriber.php @@ -51,6 +51,10 @@ class TokenCompatSubscriber implements EventSubscriberInterface { if (empty($row->context['contactId'])) { continue; } + + unset($swapLocale); + $swapLocale = empty($row->context['locale']) ? NULL : \CRM_Utils_AutoClean::swapLocale($row->context['locale']); + /** @var int $contactId */ $contactId = $row->context['contactId']; if (empty($row->context['contact'])) { diff --git a/Civi/Token/TokenProcessor.php b/Civi/Token/TokenProcessor.php index e8ee1b8f73..7ad2ec7b58 100644 --- a/Civi/Token/TokenProcessor.php +++ b/Civi/Token/TokenProcessor.php @@ -55,6 +55,7 @@ class TokenProcessor { * automatically from contactId.) * - actionSchedule: DAO, the rule which triggered the mailing * [for CRM_Core_BAO_ActionScheduler]. + * - locale: string, the name of a locale (eg 'fr_CA') to use for {ts} strings in the view. * - schema: array, a list of fields that will be provided for each row. * This is automatically populated with any general context * keys, but you may need to add extra keys for token-row data. @@ -351,6 +352,8 @@ class TokenProcessor { $row = $this->getRow($row); } + $swapLocale = empty($row->context['locale']) ? NULL : \CRM_Utils_AutoClean::swapLocale($row->context['locale']); + $message = $this->getMessage($name); $row->fill($message['format']); $useSmarty = !empty($row->context['smarty']); diff --git a/tests/phpunit/Civi/Token/TokenProcessorTest.php b/tests/phpunit/Civi/Token/TokenProcessorTest.php index cd8dba1cf2..ce6037d071 100644 --- a/tests/phpunit/Civi/Token/TokenProcessorTest.php +++ b/tests/phpunit/Civi/Token/TokenProcessorTest.php @@ -139,6 +139,75 @@ class TokenProcessorTest extends \CiviUnitTestCase { } } + public function testRenderLocalizedSmarty() { + $this->dispatcher->addSubscriber(new TokenCompatSubscriber()); + $p = new TokenProcessor($this->dispatcher, [ + 'controller' => __CLASS__, + 'smarty' => TRUE, + ]); + $p->addMessage('text', '{ts}Yes{/ts} {ts}No{/ts}', 'text/plain'); + $p->addRow([]); + $p->addRow(['locale' => 'fr_FR']); + $p->addRow(['locale' => 'es_MX']); + + $expectText = [ + 'Yes No', + 'Oui Non', + 'Sí No', + ]; + + $rowCount = 0; + foreach ($p->evaluate()->getRows() as $key => $row) { + /** @var TokenRow */ + $this->assertTrue($row instanceof TokenRow); + $this->assertEquals($expectText[$key], $row->render('text')); + $rowCount++; + } + $this->assertEquals(3, $rowCount); + } + + public function testRenderLocalizedHookToken() { + $cid = $this->individualCreate(); + + $this->dispatcher->addSubscriber(new TokenCompatSubscriber()); + \Civi::dispatcher()->addListener('hook_civicrm_tokens', function($e) { + $e->tokens['trans'] = [ + 'trans.affirm' => ts('Translated affirmation'), + ]; + }); + \Civi::dispatcher()->addListener('hook_civicrm_tokenValues', function($e) { + if (in_array('affirm', $e->tokens['trans'])) { + foreach ($e->contactIDs as $cid) { + $e->details[$cid]['trans.affirm'] = ts('Yes'); + } + } + }); + + $p = new TokenProcessor($this->dispatcher, [ + 'controller' => __CLASS__, + 'smarty' => FALSE, + ]); + $p->addMessage('text', '!!{trans.affirm}!!', 'text/plain'); + $p->addRow(['contactId' => $cid]); + $p->addRow(['contactId' => $cid, 'locale' => 'fr_FR']); + $p->addRow(['contactId' => $cid, 'locale' => 'es_MX']); + + $expectText = [ + '!!Yes!!', + '!!Oui!!', + '!!Sí!!', + ]; + + $rowCount = 0; + foreach ($p->evaluate()->getRows() as $key => $row) { + /** @var TokenRow */ + $this->assertTrue($row instanceof TokenRow); + $this->assertEquals($expectText[$key], $row->render('text')); + $rowCount++; + } + $this->assertEquals(3, $rowCount); + } + public function testGetMessageTokens() { $p = new TokenProcessor($this->dispatcher, [ 'controller' => __CLASS__,