@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Send Differential e-mails in user's language

Summary:
Works this way:

- Select users' language with multiplexing.
- Select default language otherwise (it can be different from current user's language).
- Build body and subject for each user individually.
- Set the original language after sending the mails.

Test Plan:
- Comment on a diff of user with custom translation.
- Set default to a custom translation. Comment on a diff of user with default translation.
- Set default to a default translation. Comment on a diff of user with default translation.

Repeat with/without multiplexing.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin

Maniphest Tasks: T1139

Differential Revision: https://secure.phabricator.com/D2774

vrana e84f9f9e 112acf11

+165 -57
+1 -3
src/applications/base/controller/PhabricatorController.php
··· 62 62 63 63 $translation = $user->getTranslation(); 64 64 if ($translation && 65 - $translation != PhabricatorEnv::getEnvConfig('translation.provider') && 66 - class_exists($translation) && 67 - is_subclass_of($translation, 'PhabricatorTranslation')) { 65 + $translation != PhabricatorEnv::getEnvConfig('translation.provider')) { 68 66 $translation = newv($translation, array()); 69 67 PhutilTranslator::getInstance() 70 68 ->setLanguage($translation->getLanguage())
+28 -18
src/applications/differential/mail/DifferentialCommentMail.php
··· 20 20 21 21 protected $changedByCommit; 22 22 23 + private $addedReviewers; 24 + private $addedCCs; 25 + 23 26 public function setChangedByCommit($changed_by_commit) { 24 27 $this->changedByCommit = $changed_by_commit; 25 28 return $this; ··· 87 90 return $verb; 88 91 } 89 92 90 - protected function renderBody() { 91 - 92 - $comment = $this->getComment(); 93 - 94 - $actor = $this->getActorName(); 95 - $name = $this->getRevision()->getTitle(); 96 - $verb = $this->getVerb(); 97 - 98 - $body = array(); 99 - 100 - $body[] = "{$actor} has {$verb} the revision \"{$name}\"."; 93 + protected function prepareBody() { 94 + parent::prepareBody(); 101 95 102 96 // If the commented added reviewers or CCs, list them explicitly. 103 - $meta = $comment->getMetadata(); 97 + $meta = $this->getComment()->getMetadata(); 104 98 $m_reviewers = idx( 105 99 $meta, 106 100 DifferentialComment::METADATA_ADDED_REVIEWERS, ··· 113 107 if ($load) { 114 108 $handles = id(new PhabricatorObjectHandleData($load))->loadHandles(); 115 109 if ($m_reviewers) { 116 - $body[] = 'Added Reviewers: '.$this->renderHandleList( 117 - $handles, 118 - $m_reviewers); 110 + $this->addedReviewers = $this->renderHandleList($handles, $m_reviewers); 119 111 } 120 112 if ($m_cc) { 121 - $body[] = 'Added CCs: '.$this->renderHandleList( 122 - $handles, 123 - $m_cc); 113 + $this->addedCCs = $this->renderHandleList($handles, $m_cc); 124 114 } 115 + } 116 + } 117 + 118 + protected function renderBody() { 119 + 120 + $comment = $this->getComment(); 121 + 122 + $actor = $this->getActorName(); 123 + $name = $this->getRevision()->getTitle(); 124 + $verb = $this->getVerb(); 125 + 126 + $body = array(); 127 + 128 + $body[] = "{$actor} has {$verb} the revision \"{$name}\"."; 129 + 130 + if ($this->addedReviewers) { 131 + $body[] = 'Added Reviewers: '.$this->addedReviewers; 132 + } 133 + if ($this->addedCCs) { 134 + $body[] = 'Added CCs: '.$this->addedCCs; 125 135 } 126 136 127 137 $body[] = null;
+64 -19
src/applications/differential/mail/DifferentialMail.php
··· 78 78 } 79 79 80 80 $cc_phids = $this->getCCPHIDs(); 81 - $body = $this->buildBody(); 82 81 $attachments = $this->buildAttachments(); 83 82 84 83 $template = new PhabricatorMetaMTAMail(); ··· 90 89 } 91 90 92 91 $template 93 - ->setSubject($this->renderSubject()) 94 - ->setSubjectPrefix($this->getSubjectPrefix()) 95 - ->setVarySubjectPrefix($this->renderVaryPrefix()) 96 - ->setBody($body) 97 92 ->setIsHTML($this->shouldMarkMailAsHTML()) 98 93 ->setParentMessageID($this->parentMessageID) 99 94 ->addHeader('Thread-Topic', $this->getThreadTopic()); ··· 172 167 $phids = array_keys($phids); 173 168 174 169 $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); 170 + $objects = id(new PhabricatorObjectHandleData($phids))->loadObjects(); 175 171 176 - $event = new PhabricatorEvent( 177 - PhabricatorEventType::TYPE_DIFFERENTIAL_WILLSENDMAIL, 178 - array( 179 - 'mail' => $template, 180 - ) 181 - ); 182 - PhutilEventEngine::dispatchEvent($event); 172 + $to_handles = array_select_keys($handles, $to_phids); 173 + $cc_handles = array_select_keys($handles, $cc_phids); 174 + 175 + $this->prepareBody(); 176 + 177 + $mails = $reply_handler->multiplexMail($template, $to_handles, $cc_handles); 178 + 179 + $original_translator = PhutilTranslator::getInstance(); 180 + if (!PhabricatorMetaMTAMail::shouldMultiplexAllMail()) { 181 + $translation = PhabricatorEnv::newObjectFromConfig( 182 + 'translation.provider'); 183 + $translator = id(new PhutilTranslator()) 184 + ->setLanguage($translation->getLanguage()) 185 + ->addTranslations($translation->getTranslations()); 186 + } 187 + 188 + try { 189 + foreach ($mails as $mail) { 190 + if (PhabricatorMetaMTAMail::shouldMultiplexAllMail()) { 191 + $translation = newv($mail->getTranslation($objects), array()); 192 + $translator = id(new PhutilTranslator()) 193 + ->setLanguage($translation->getLanguage()) 194 + ->addTranslations($translation->getTranslations()); 195 + PhutilTranslator::setInstance($translator); 196 + } 197 + 198 + $body = 199 + $this->buildBody()."\n". 200 + $reply_handler->getRecipientsSummary($to_handles, $cc_handles); 201 + 202 + $mail 203 + ->setSubject($this->renderSubject()) 204 + ->setSubjectPrefix($this->getSubjectPrefix()) 205 + ->setVarySubjectPrefix($this->renderVaryPrefix()) 206 + ->setBody($body); 183 207 184 - $template = $event->getValue('mail'); 208 + $event = new PhabricatorEvent( 209 + PhabricatorEventType::TYPE_DIFFERENTIAL_WILLSENDMAIL, 210 + array( 211 + 'mail' => $mail, 212 + ) 213 + ); 214 + PhutilEventEngine::dispatchEvent($event); 215 + $mail = $event->getValue('mail'); 185 216 186 - $mails = $reply_handler->multiplexMail( 187 - $template, 188 - array_select_keys($handles, $to_phids), 189 - array_select_keys($handles, $cc_phids)); 217 + $mail->saveAndSend(); 218 + } 190 219 191 - foreach ($mails as $mail) { 192 - $mail->saveAndSend(); 220 + } catch (Exception $ex) { 221 + PhutilTranslator::setInstance($original_translator); 222 + throw $ex; 193 223 } 224 + 225 + PhutilTranslator::setInstance($original_translator); 194 226 } 195 227 196 228 protected function getMailTags() { ··· 203 235 204 236 protected function shouldMarkMailAsHTML() { 205 237 return false; 238 + } 239 + 240 + /** 241 + * @{method:buildBody} is called once for each e-mail recipient to allow 242 + * translating text to his language. This method can be used to load data that 243 + * don't need translation and use them later in @{method:buildBody}. 244 + * 245 + * @param 246 + * @return 247 + */ 248 + protected function prepareBody() { 206 249 } 207 250 208 251 protected function buildBody() { ··· 369 412 $body = array(); 370 413 foreach ($aux_fields as $field) { 371 414 $field->setRevision($this->getRevision()); 415 + // TODO: Introduce and use getRequiredHandlePHIDsForMail() and load all 416 + // handles in prepareBody(). 372 417 $text = $field->renderValueForMail($phase); 373 418 if ($text !== null) { 374 419 $body[] = $text;
+20 -15
src/applications/differential/mail/DifferentialReviewRequestMail.php
··· 20 20 21 21 protected $comments; 22 22 23 + private $patch; 24 + 23 25 public function setComments($comments) { 24 26 $this->comments = $comments; 25 27 return $this; ··· 40 42 $this->setChangesets($changesets); 41 43 } 42 44 45 + protected function prepareBody() { 46 + parent::prepareBody(); 47 + 48 + $inline_max_length = PhabricatorEnv::getEnvConfig( 49 + 'metamta.differential.inline-patches'); 50 + if ($inline_max_length) { 51 + $patch = $this->buildPatch(); 52 + if (count(explode("\n", $patch)) <= $inline_max_length) { 53 + $this->patch = $patch; 54 + } 55 + } 56 + } 57 + 43 58 protected function renderReviewRequestBody() { 44 59 $revision = $this->getRevision(); 45 60 ··· 65 80 $body[] = null; 66 81 } 67 82 68 - $inline_key = 'metamta.differential.inline-patches'; 69 - $inline_max_length = PhabricatorEnv::getEnvConfig($inline_key); 70 - if ($inline_max_length) { 71 - $patch = $this->buildPatch(); 72 - if (count(explode("\n", $patch)) <= $inline_max_length) { 73 - $body[] = 'CHANGE DETAILS'; 74 - $body[] = $patch; 75 - } 83 + if ($this->patch) { 84 + $body[] = 'CHANGE DETAILS'; 85 + $body[] = $this->patch; 76 86 } 77 87 78 88 return implode("\n", $body); ··· 110 120 } 111 121 112 122 private function buildPatch() { 113 - $revision = $this->getRevision(); 114 - $revision_id = $revision->getID(); 123 + $diff = new DifferentialDiff(); 115 124 116 - $diffs = $revision->loadDiffs(); 117 - $diff_number = count($diffs); 118 - $diff = array_pop($diffs); 119 - 120 - $diff->attachChangesets($diff->loadChangesets()); 125 + $diff->attachChangesets($this->getChangesets()); 121 126 // TODO: We could batch this to improve performance. 122 127 foreach ($diff->getChangesets() as $changeset) { 123 128 $changeset->attachHunks($changeset->loadHunks());
+17 -2
src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php
··· 71 71 return null; 72 72 } 73 73 74 + final public function getRecipientsSummary( 75 + array $to_handles, 76 + array $cc_handles) { 77 + assert_instances_of($to_handles, 'PhabricatorObjectHandle'); 78 + assert_instances_of($cc_handles, 'PhabricatorObjectHandle'); 79 + 80 + $body = ''; 81 + if ($to_handles) { 82 + $body .= "To: ".implode(', ', mpull($to_handles, 'getName'))."\n"; 83 + } 84 + if ($cc_handles) { 85 + $body .= "Cc: ".implode(', ', mpull($cc_handles, 'getName'))."\n"; 86 + } 87 + return $body; 88 + } 89 + 74 90 final public function multiplexMail( 75 91 PhabricatorMetaMTAMail $mail_template, 76 92 array $to_handles, ··· 115 131 $body = $mail_template->getBody(); 116 132 $body .= "\n"; 117 133 if ($to_handles) { 118 - $body .= "To: ".implode(', ', mpull($to_handles, 'getName'))."\n"; 119 134 $add_headers['X-Phabricator-To'] = $this->formatPHIDList($to_handles); 120 135 } 121 136 if ($cc_handles) { 122 - $body .= "Cc: ".implode(', ', mpull($cc_handles, 'getName'))."\n"; 123 137 $add_headers['X-Phabricator-Cc'] = $this->formatPHIDList($cc_handles); 124 138 } 139 + $body .= $this->getRecipientsSummary($to_handles, $cc_handles); 125 140 126 141 foreach ($recipients as $recipient) { 127 142 $mail = clone $mail_template;
+22
src/applications/metamta/storage/PhabricatorMetaMTAMail.php
··· 119 119 return $this; 120 120 } 121 121 122 + public function getTranslation(array $objects) { 123 + $default_translation = PhabricatorEnv::getEnvConfig('translation.provider'); 124 + $return = null; 125 + $recipients = array_merge( 126 + idx($this->parameters, 'to', array()), 127 + idx($this->parameters, 'cc', array())); 128 + foreach (array_select_keys($objects, $recipients) as $object) { 129 + $translation = null; 130 + if ($object instanceof PhabricatorUser) { 131 + $translation = $object->getTranslation(); 132 + } 133 + if (!$translation) { 134 + $translation = $default_translation; 135 + } 136 + if ($return && $translation != $return) { 137 + return $default_translation; 138 + } 139 + $return = $translation; 140 + } 141 + return $return; 142 + } 143 + 122 144 public function addHeader($name, $value) { 123 145 $this->parameters['headers'][$name] = $value; 124 146 return $this;
+13
src/applications/people/storage/PhabricatorUser.php
··· 96 96 return $this->sex; 97 97 } 98 98 99 + public function getTranslation() { 100 + try { 101 + if ($this->translation && 102 + class_exists($this->translation) && 103 + is_subclass_of($this->translation, 'PhabricatorTranslation')) { 104 + return $this->translation; 105 + } 106 + } catch (PhutilMissingSymbolException $ex) { 107 + return null; 108 + } 109 + return null; 110 + } 111 + 99 112 public function isLoggedIn() { 100 113 return !($this->getPHID() === null); 101 114 }