@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.

Use pht()

Summary:
This is the first step in Phabricator internationalization.
It adds a translation selector and calls it at startup.
Installations can add custom selectors to override some texts.
We can add official translations in future.

Next step is to allow user to choose his translation which will override the global one.

This is currently used only for English plurals.

Test Plan: Displayed a diff with unit test error, verified that it says 'Detail' or 'Details' and not 'Detail(s)'.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin

Maniphest Tasks: T1139

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

vrana 0acb7734 35730550

+154 -68
+7
conf/default.conf.php
··· 65 65 'phabricator.custom.logo' => null, 66 66 67 67 68 + // -- Internationalization -------------------------------------------------- // 69 + 70 + // This allows customizing texts used in Phabricator. The class must extend 71 + // PhabricatorTranslation. 72 + 'translation.provider' => 'PhabricatorEnglishTranslation', 73 + 74 + 68 75 // -- Access Policies ------------------------------------------------------- // 69 76 70 77 // Phabricator allows you to set the visibility of objects (like repositories
+5
scripts/__init_script__.php
··· 60 60 61 61 PhabricatorEnv::setEnvConfig($conf); 62 62 63 + $translation = PhabricatorEnv::newObjectFromConfig('translation.provider'); 64 + PhutilTranslator::getInstance() 65 + ->setLanguage($translation->getLanguage()) 66 + ->addTranslations($translation->getTranslations()); 67 + 63 68 phutil_load_library('arcanist/src'); 64 69 65 70 foreach (PhabricatorEnv::getEnvConfig('load-libraries') as $library) {
+3
src/__phutil_library_map__.php
··· 614 614 'PhabricatorEmailLoginController' => 'applications/auth/controller/PhabricatorEmailLoginController.php', 615 615 'PhabricatorEmailTokenController' => 'applications/auth/controller/PhabricatorEmailTokenController.php', 616 616 'PhabricatorEmailVerificationController' => 'applications/people/controller/PhabricatorEmailVerificationController.php', 617 + 'PhabricatorEnglishTranslation' => 'infrastructure/internationalization/PhabricatorEnglishTranslation.php', 617 618 'PhabricatorEnv' => 'infrastructure/PhabricatorEnv.php', 618 619 'PhabricatorEnvTestCase' => 'infrastructure/__tests__/PhabricatorEnvTestCase.php', 619 620 'PhabricatorErrorExample' => 'applications/uiexample/examples/PhabricatorErrorExample.php', ··· 959 960 'PhabricatorTimer' => 'applications/countdown/storage/PhabricatorTimer.php', 960 961 'PhabricatorTransactionView' => 'view/layout/PhabricatorTransactionView.php', 961 962 'PhabricatorTransformedFile' => 'applications/files/storage/PhabricatorTransformedFile.php', 963 + 'PhabricatorTranslation' => 'infrastructure/internationalization/PhabricatorTranslation.php', 962 964 'PhabricatorTrivialTestCase' => 'infrastructure/testing/__tests__/PhabricatorTrivialTestCase.php', 963 965 'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadCommonDatasourceController.php', 964 966 'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadDatasourceController.php', ··· 1609 1611 'PhabricatorEmailLoginController' => 'PhabricatorAuthController', 1610 1612 'PhabricatorEmailTokenController' => 'PhabricatorAuthController', 1611 1613 'PhabricatorEmailVerificationController' => 'PhabricatorPeopleController', 1614 + 'PhabricatorEnglishTranslation' => 'PhabricatorTranslation', 1612 1615 'PhabricatorEnvTestCase' => 'PhabricatorTestCase', 1613 1616 'PhabricatorErrorExample' => 'PhabricatorUIExample', 1614 1617 'PhabricatorEvent' => 'PhutilEvent',
+1 -8
src/applications/differential/field/specification/DifferentialCommitsFieldSpecification.php
··· 64 64 65 65 $body = array(); 66 66 $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); 67 - if (count($handles) == 1) { 68 - $body[] = "COMMIT"; 69 - } else { 70 - // This is unlikely to ever happen since we'll send this mail the 71 - // first time we discover a commit, but it's not impossible if data 72 - // was migrated, etc. 73 - $body[] = "COMMITS"; 74 - } 67 + $body[] = pht('COMMIT(S)', count($handles)); 75 68 76 69 foreach ($handles as $handle) { 77 70 $body[] = ' '.PhabricatorEnv::getProductionURI($handle->getURI());
+19 -20
src/applications/differential/field/specification/DifferentialLintFieldSpecification.php
··· 167 167 'details', 168 168 )) + $hidden; 169 169 170 - $singular = array( 171 - ArcanistLintSeverity::SEVERITY_ERROR => 'Error', 172 - ArcanistLintSeverity::SEVERITY_WARNING => 'Warning', 173 - ArcanistLintSeverity::SEVERITY_AUTOFIX => 'Auto-Fix', 174 - ArcanistLintSeverity::SEVERITY_ADVICE => 'Advice', 175 - 'details' => 'Detail', 176 - ); 177 - 178 - $plural = array( 179 - ArcanistLintSeverity::SEVERITY_ERROR => 'Errors', 180 - ArcanistLintSeverity::SEVERITY_WARNING => 'Warnings', 181 - ArcanistLintSeverity::SEVERITY_AUTOFIX => 'Auto-Fixes', 182 - ArcanistLintSeverity::SEVERITY_ADVICE => 'Advice', 183 - 'details' => 'Details', 184 - ); 185 - 186 170 $show = array(); 187 171 foreach ($hidden as $key => $value) { 188 - if ($value == 1) { 189 - $show[] = $value.' '.idx($singular, $key); 190 - } else { 191 - $show[] = $value.' '.idx($plural, $key); 172 + switch ($key) { 173 + case ArcanistLintSeverity::SEVERITY_ERROR: 174 + $show[] = pht('%d Error(s)', $value); 175 + break; 176 + case ArcanistLintSeverity::SEVERITY_WARNING: 177 + $show[] = pht('%d Warning(s)', $value); 178 + break; 179 + case ArcanistLintSeverity::SEVERITY_AUTOFIX: 180 + $show[] = pht('%d Auto-Fix(es)', $value); 181 + break; 182 + case ArcanistLintSeverity::SEVERITY_ADVICE: 183 + $show[] = pht('%d Advice(s)', $value); 184 + break; 185 + case 'details': 186 + $show[] = pht('%d Detail(s)', $value); 187 + break; 188 + default: 189 + $show[] = $value; 190 + break; 192 191 } 193 192 } 194 193
+5 -2
src/applications/differential/field/specification/DifferentialUnitFieldSpecification.php
··· 171 171 ArcanistUnitTestResult::RESULT_SKIP => 'Skipped', 172 172 ArcanistUnitTestResult::RESULT_POSTPONED => 'Postponed', 173 173 ArcanistUnitTestResult::RESULT_PASS => 'Passed', 174 - 'details' => 'Details', 175 174 ); 176 175 177 176 $show = array(); 178 177 foreach ($hidden as $key => $value) { 179 - $show[] = $value.' '.idx($noun, $key); 178 + if ($key == 'details') { 179 + $show[] = pht('%d Detail(s)', $value); 180 + } else { 181 + $show[] = $value.' '.idx($noun, $key); 182 + } 180 183 } 181 184 182 185 return "Show Full Unit Results (".implode(', ', $show).")";
+1 -1
src/applications/differential/mail/DifferentialNewDiffMail.php
··· 21 21 protected function renderVaryPrefix() { 22 22 $revision = $this->getRevision(); 23 23 $line_count = $revision->getLineCount(); 24 - $lines = ($line_count == 1 ? "1 line" : "{$line_count} lines"); 24 + $lines = pht('%d line(s)', $line_count); 25 25 26 26 if ($this->isFirstMailToRecipients()) { 27 27 $verb = 'Request';
+1 -3
src/applications/differential/view/DifferentialDiffTableOfContentsView.php
··· 137 137 $line_count = $changeset->getAffectedLineCount(); 138 138 if ($line_count == 0) { 139 139 $lines = null; 140 - } else if ($line_count == 1) { 141 - $lines = ' (1 line)'; 142 140 } else { 143 - $lines = ' ('.$line_count.' lines)'; 141 + $lines = ' '.pht('(%d line(s))', $line_count); 144 142 } 145 143 146 144 $char = DifferentialChangeType::getSummaryCharacterForChangeType($type);
+21 -29
src/applications/maniphest/view/ManiphestTransactionDetailView.php
··· 407 407 if (count($removed) == 1) { 408 408 $desc = 'removed project '.$this->renderHandles($removed); 409 409 } else { 410 - $desc = 'removed projectss: '.$this->renderHandles($removed); 410 + $desc = 'removed projects: '.$this->renderHandles($removed); 411 411 } 412 412 } else { 413 413 $verb = 'Changed Projects'; ··· 488 488 $add_desc = $this->renderHandles($added); 489 489 $rem_desc = $this->renderHandles($removed); 490 490 491 - switch ($attach_type) { 492 - case PhabricatorPHIDConstants::PHID_TYPE_DREV: 493 - $singular = 'Differential Revision'; 494 - $plural = 'Differential Revisions'; 495 - break; 496 - case PhabricatorPHIDConstants::PHID_TYPE_FILE: 497 - $singular = 'file'; 498 - $plural = 'files'; 499 - break; 500 - case PhabricatorPHIDConstants::PHID_TYPE_TASK: 501 - $singular = 'Maniphest Task'; 502 - $plural = 'Maniphest Tasks'; 503 - $dependency = true; 504 - break; 505 - } 506 - 507 491 if ($added && !$removed) { 508 492 $verb = 'Attached'; 509 - if (count($added) == 1) { 510 - $desc = 'attached '.$singular.': '.$add_desc; 511 - } else { 512 - $desc = 'attached '.$plural.': '.$add_desc; 513 - } 493 + $desc = 'attached '.$this->getAttachName($attach_type, count($added)); 514 494 } else if ($removed && !$added) { 515 495 $verb = 'Detached'; 516 - if (count($removed) == 1) { 517 - $desc = 'detached '.$singular.': '.$rem_desc; 518 - } else { 519 - $desc = 'detached '.$plural.': '.$rem_desc; 520 - } 496 + $desc = 497 + 'detached '. 498 + $this->getAttachName($attach_type, count($removed)); 521 499 } else { 522 500 $verb = 'Changed Attached'; 523 - $desc = 'changed attached '.$plural.', added: '.$add_desc.'; '. 524 - 'removed: '.$rem_desc; 501 + $desc = 502 + 'changed attached '. 503 + $this->getAttachName($attach_type, count($added) + count($removed)). 504 + ', added: '.$add_desc.'; '. 505 + 'removed: '.$rem_desc; 525 506 } 526 507 break; 527 508 case ManiphestTransactionType::TYPE_AUXILIARY: ··· 563 544 } 564 545 565 546 return array($verb, $desc, $classes); 547 + } 548 + 549 + private function getAttachName($attach_type, $count) { 550 + switch ($attach_type) { 551 + case PhabricatorPHIDConstants::PHID_TYPE_DREV: 552 + return pht('Differential Revision(s)', $count); 553 + case PhabricatorPHIDConstants::PHID_TYPE_FILE: 554 + return pht('file(s)', $count); 555 + case PhabricatorPHIDConstants::PHID_TYPE_TASK: 556 + return pht('Maniphest Task(s)', $count); 557 + } 566 558 } 567 559 568 560 private function renderFullSummary($transaction) {
+3 -5
src/applications/phortune/stripe/controller/PhortuneStripeTestPaymentFormController.php
··· 144 144 } 145 145 146 146 // append a helpful "fix this" to the messages to be displayed to the user 147 - if (count($messages) == 1) { 148 - $messages[] = 'Please fix this error and try again.'; 149 - } else { 150 - $messages[] = 'Please fix these errors and try again.'; 151 - } 147 + $messages[] = pht( 148 + 'Please fix these errors and try again.', 149 + count($messages)); 152 150 153 151 return array( 154 152 $card_number_error,
+1
src/infrastructure/PhabricatorEnv.php
··· 299 299 */ 300 300 public static function getRequiredClasses() { 301 301 return array( 302 + 'translation.provider' => 'PhabricatorTranslation', 302 303 'metamta.mail-adapter' => 'PhabricatorMailImplementationAdapter', 303 304 'metamta.maniphest.reply-handler' => 'PhabricatorMailReplyHandler', 304 305 'metamta.differential.reply-handler' => 'PhabricatorMailReplyHandler',
+57
src/infrastructure/internationalization/PhabricatorEnglishTranslation.php
··· 1 + <?php 2 + 3 + /* 4 + * Copyright 2012 Facebook, Inc. 5 + * 6 + * Licensed under the Apache License, Version 2.0 (the "License"); 7 + * you may not use this file except in compliance with the License. 8 + * You may obtain a copy of the License at 9 + * 10 + * http://www.apache.org/licenses/LICENSE-2.0 11 + * 12 + * Unless required by applicable law or agreed to in writing, software 13 + * distributed under the License is distributed on an "AS IS" BASIS, 14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 + * See the License for the specific language governing permissions and 16 + * limitations under the License. 17 + */ 18 + 19 + final class PhabricatorEnglishTranslation extends PhabricatorTranslation { 20 + 21 + public function getLanguage() { 22 + return 'en'; 23 + } 24 + 25 + public function getName() { 26 + return 'English'; 27 + } 28 + 29 + public function getTranslations() { 30 + return array( 31 + 'Differential Revision(s)' => array( 32 + 'Differential Revision', 33 + 'Differential Revisions', 34 + ), 35 + 'file(s)' => array('file', 'files'), 36 + 'Maniphest Task(s)' => array('Maniphest Task', 'Maniphest Tasks'), 37 + 38 + 'Please fix these errors and try again.' => array( 39 + 'Please fix this error and try again.', 40 + 'Please fix these errors and try again.', 41 + ), 42 + 43 + '%d Error(s)' => array('%d Error', '%d Errors'), 44 + '%d Warning(s)' => array('%d Warning', '%d Warnings'), 45 + '%d Auto-Fix(es)' => array('%d Auto-Fix', '%d Auto-Fixes'), 46 + '%d Advice(s)' => array('%d Advice', '%d Pieces of Advice'), 47 + '%d Detail(s)' => array('%d Detail', '%d Details'), 48 + 49 + '(%d line(s))' => array('(%d line)', '(%d lines)'), 50 + 51 + 'COMMIT(S)' => array('COMMIT', 'COMMITS'), 52 + 53 + '%d line(s)' => array('%d line', '%d lines'), 54 + ); 55 + } 56 + 57 + }
+25
src/infrastructure/internationalization/PhabricatorTranslation.php
··· 1 + <?php 2 + 3 + /* 4 + * Copyright 2012 Facebook, Inc. 5 + * 6 + * Licensed under the Apache License, Version 2.0 (the "License"); 7 + * you may not use this file except in compliance with the License. 8 + * You may obtain a copy of the License at 9 + * 10 + * http://www.apache.org/licenses/LICENSE-2.0 11 + * 12 + * Unless required by applicable law or agreed to in writing, software 13 + * distributed under the License is distributed on an "AS IS" BASIS, 14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 + * See the License for the specific language governing permissions and 16 + * limitations under the License. 17 + */ 18 + 19 + abstract class PhabricatorTranslation { 20 + 21 + abstract public function getLanguage(); 22 + abstract public function getName(); 23 + abstract public function getTranslations(); 24 + 25 + }
+5
webroot/index.php
··· 122 122 123 123 phabricator_detect_bad_base_uri(); 124 124 125 + $translation = PhabricatorEnv::newObjectFromConfig('translation.provider'); 126 + PhutilTranslator::getInstance() 127 + ->setLanguage($translation->getLanguage()) 128 + ->addTranslations($translation->getTranslations()); 129 + 125 130 $host = $_SERVER['HTTP_HOST']; 126 131 $path = $_REQUEST['__path__']; 127 132