Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14070651
D11747.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
22 KB
Referenced Files
None
Subscribers
None
D11747.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1245,7 +1245,6 @@
'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php',
'PhabricatorActivitySettingsPanel' => 'applications/settings/panel/PhabricatorActivitySettingsPanel.php',
'PhabricatorAdministratorsPolicyRule' => 'applications/policy/rule/PhabricatorAdministratorsPolicyRule.php',
- 'PhabricatorAllCapsTranslation' => 'infrastructure/internationalization/translation/PhabricatorAllCapsTranslation.php',
'PhabricatorAlmanacApplication' => 'applications/almanac/application/PhabricatorAlmanacApplication.php',
'PhabricatorAmazonAuthProvider' => 'applications/auth/provider/PhabricatorAmazonAuthProvider.php',
'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php',
@@ -1414,7 +1413,6 @@
'PhabricatorAutoEventListener' => 'infrastructure/events/PhabricatorAutoEventListener.php',
'PhabricatorBarePageUIExample' => 'applications/uiexample/examples/PhabricatorBarePageUIExample.php',
'PhabricatorBarePageView' => 'view/page/PhabricatorBarePageView.php',
- 'PhabricatorBaseEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBaseEnglishTranslation.php',
'PhabricatorBaseProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorBaseProtocolAdapter.php',
'PhabricatorBaseURISetupCheck' => 'applications/config/check/PhabricatorBaseURISetupCheck.php',
'PhabricatorBcryptPasswordHasher' => 'infrastructure/util/password/PhabricatorBcryptPasswordHasher.php',
@@ -1435,6 +1433,7 @@
'PhabricatorBotTarget' => 'infrastructure/daemon/bot/target/PhabricatorBotTarget.php',
'PhabricatorBotUser' => 'infrastructure/daemon/bot/target/PhabricatorBotUser.php',
'PhabricatorBotWhatsNewHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotWhatsNewHandler.php',
+ 'PhabricatorBritishEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php',
'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php',
'PhabricatorBusyUIExample' => 'applications/uiexample/examples/PhabricatorBusyUIExample.php',
'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php',
@@ -1717,7 +1716,6 @@
'PhabricatorEmbedFileRemarkupRule' => 'applications/files/markup/PhabricatorEmbedFileRemarkupRule.php',
'PhabricatorEmojiRemarkupRule' => 'applications/macro/markup/PhabricatorEmojiRemarkupRule.php',
'PhabricatorEmptyQueryException' => 'infrastructure/query/PhabricatorEmptyQueryException.php',
- 'PhabricatorEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorEnglishTranslation.php',
'PhabricatorEnv' => 'infrastructure/env/PhabricatorEnv.php',
'PhabricatorEnvTestCase' => 'infrastructure/env/__tests__/PhabricatorEnvTestCase.php',
'PhabricatorEvent' => 'infrastructure/events/PhabricatorEvent.php',
@@ -2563,7 +2561,6 @@
'PhabricatorTransactions' => 'applications/transactions/constants/PhabricatorTransactions.php',
'PhabricatorTransactionsApplication' => 'applications/transactions/application/PhabricatorTransactionsApplication.php',
'PhabricatorTransformedFile' => 'applications/files/storage/PhabricatorTransformedFile.php',
- 'PhabricatorTranslation' => 'infrastructure/internationalization/translation/PhabricatorTranslation.php',
'PhabricatorTranslationsConfigOptions' => 'applications/config/option/PhabricatorTranslationsConfigOptions.php',
'PhabricatorTriggerAction' => 'infrastructure/daemon/workers/action/PhabricatorTriggerAction.php',
'PhabricatorTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorTriggerClock.php',
@@ -2587,6 +2584,7 @@
'PhabricatorUIExample' => 'applications/uiexample/examples/PhabricatorUIExample.php',
'PhabricatorUIExampleRenderController' => 'applications/uiexample/controller/PhabricatorUIExampleRenderController.php',
'PhabricatorUIExamplesApplication' => 'applications/uiexample/application/PhabricatorUIExamplesApplication.php',
+ 'PhabricatorUSEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php',
'PhabricatorUnitsTestCase' => 'view/__tests__/PhabricatorUnitsTestCase.php',
'PhabricatorUnsubscribedFromObjectEdgeType' => 'applications/transactions/edges/PhabricatorUnsubscribedFromObjectEdgeType.php',
'PhabricatorUser' => 'applications/people/storage/PhabricatorUser.php',
@@ -2618,6 +2616,7 @@
'PhabricatorUserTransaction' => 'applications/people/storage/PhabricatorUserTransaction.php',
'PhabricatorUsersPolicyRule' => 'applications/policy/rule/PhabricatorUsersPolicyRule.php',
'PhabricatorVCSResponse' => 'applications/repository/response/PhabricatorVCSResponse.php',
+ 'PhabricatorVeryWowEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorVeryWowEnglishTranslation.php',
'PhabricatorWatcherHasObjectEdgeType' => 'applications/transactions/edges/PhabricatorWatcherHasObjectEdgeType.php',
'PhabricatorWordPressAuthProvider' => 'applications/auth/provider/PhabricatorWordPressAuthProvider.php',
'PhabricatorWorker' => 'infrastructure/daemon/workers/PhabricatorWorker.php',
@@ -4472,7 +4471,6 @@
'PhabricatorActionView' => 'AphrontView',
'PhabricatorActivitySettingsPanel' => 'PhabricatorSettingsPanel',
'PhabricatorAdministratorsPolicyRule' => 'PhabricatorPolicyRule',
- 'PhabricatorAllCapsTranslation' => 'PhabricatorTranslation',
'PhabricatorAlmanacApplication' => 'PhabricatorApplication',
'PhabricatorAmazonAuthProvider' => 'PhabricatorOAuth2AuthProvider',
'PhabricatorAnchorView' => 'AphrontView',
@@ -4658,7 +4656,6 @@
'PhabricatorAutoEventListener' => 'PhabricatorEventListener',
'PhabricatorBarePageUIExample' => 'PhabricatorUIExample',
'PhabricatorBarePageView' => 'AphrontPageView',
- 'PhabricatorBaseEnglishTranslation' => 'PhabricatorTranslation',
'PhabricatorBaseURISetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorBcryptPasswordHasher' => 'PhabricatorPasswordHasher',
'PhabricatorBinariesSetupCheck' => 'PhabricatorSetupCheck',
@@ -4675,6 +4672,7 @@
'PhabricatorBotSymbolHandler' => 'PhabricatorBotHandler',
'PhabricatorBotUser' => 'PhabricatorBotTarget',
'PhabricatorBotWhatsNewHandler' => 'PhabricatorBotHandler',
+ 'PhabricatorBritishEnglishTranslation' => 'PhutilTranslation',
'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList',
'PhabricatorBusyUIExample' => 'PhabricatorUIExample',
'PhabricatorCacheDAO' => 'PhabricatorLiskDAO',
@@ -4986,7 +4984,6 @@
'PhabricatorEmbedFileRemarkupRule' => 'PhabricatorObjectRemarkupRule',
'PhabricatorEmojiRemarkupRule' => 'PhutilRemarkupRule',
'PhabricatorEmptyQueryException' => 'Exception',
- 'PhabricatorEnglishTranslation' => 'PhabricatorBaseEnglishTranslation',
'PhabricatorEnvTestCase' => 'PhabricatorTestCase',
'PhabricatorEvent' => 'PhutilEvent',
'PhabricatorEventListener' => 'PhutilEventListener',
@@ -5910,6 +5907,7 @@
'PhabricatorUIConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorUIExampleRenderController' => 'PhabricatorController',
'PhabricatorUIExamplesApplication' => 'PhabricatorApplication',
+ 'PhabricatorUSEnglishTranslation' => 'PhutilTranslation',
'PhabricatorUnitsTestCase' => 'PhabricatorTestCase',
'PhabricatorUnsubscribedFromObjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorUser' => array(
@@ -5954,6 +5952,7 @@
'PhabricatorUserTransaction' => 'PhabricatorApplicationTransaction',
'PhabricatorUsersPolicyRule' => 'PhabricatorPolicyRule',
'PhabricatorVCSResponse' => 'AphrontResponse',
+ 'PhabricatorVeryWowEnglishTranslation' => 'PhutilTranslation',
'PhabricatorWatcherHasObjectEdgeType' => 'PhabricatorEdgeType',
'PhabricatorWordPressAuthProvider' => 'PhabricatorOAuth2AuthProvider',
'PhabricatorWorkerActiveTask' => 'PhabricatorWorkerTask',
diff --git a/src/applications/base/controller/PhabricatorController.php b/src/applications/base/controller/PhabricatorController.php
--- a/src/applications/base/controller/PhabricatorController.php
+++ b/src/applications/base/controller/PhabricatorController.php
@@ -96,13 +96,9 @@
$request->setUser($user);
}
- $translation = $user->getTranslation();
- if ($translation &&
- $translation != PhabricatorEnv::getEnvConfig('translation.provider')) {
- $translation = newv($translation, array());
- PhutilTranslator::getInstance()
- ->setLanguage($translation->getLanguage())
- ->addTranslations($translation->getCleanTranslations());
+ $locale_code = $user->getTranslation();
+ if ($locale_code) {
+ PhabricatorEnv::setLocaleCode($locale_code);
}
$preferences = $user->loadPreferences();
diff --git a/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php b/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php
--- a/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php
+++ b/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php
@@ -203,6 +203,9 @@
'the server as the user you want it to run under.'),
'notification.debug' => pht(
'Notifications no longer have a dedicated debugging mode.'),
+ 'translation.provider' => pht(
+ 'The translation implementation has changed and providers are no '.
+ 'longer used or supported.'),
);
return $ancient_config;
diff --git a/src/applications/config/option/PhabricatorTranslationsConfigOptions.php b/src/applications/config/option/PhabricatorTranslationsConfigOptions.php
--- a/src/applications/config/option/PhabricatorTranslationsConfigOptions.php
+++ b/src/applications/config/option/PhabricatorTranslationsConfigOptions.php
@@ -21,19 +21,6 @@
public function getOptions() {
return array(
- $this->newOption(
- 'translation.provider',
- 'class',
- 'PhabricatorEnglishTranslation')
- ->setBaseClass('PhabricatorTranslation')
- ->setSummary(pht('Translation class that should be used for strings.'))
- ->setDescription(
- pht(
- 'This allows customizing texts used in Phabricator. The class '.
- 'must extend PhabricatorTranslation.'))
- ->addExample('PhabricatorEnglishTranslation', pht('Valid Setting')),
- // TODO: This should be dict<string,string> I think, but that doesn't
- // exist yet.
$this->newOption('translation.override', 'wild', array())
->setSummary(pht('Override translations.'))
->setDescription(
diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php
--- a/src/applications/people/storage/PhabricatorUser.php
+++ b/src/applications/people/storage/PhabricatorUser.php
@@ -190,19 +190,6 @@
return '@'.$this->getUsername();
}
- public function getTranslation() {
- try {
- if ($this->translation &&
- class_exists($this->translation) &&
- is_subclass_of($this->translation, 'PhabricatorTranslation')) {
- return $this->translation;
- }
- } catch (PhutilMissingSymbolException $ex) {
- return null;
- }
- return null;
- }
-
public function isLoggedIn() {
return !($this->getPHID() === null);
}
diff --git a/src/applications/settings/panel/PhabricatorAccountSettingsPanel.php b/src/applications/settings/panel/PhabricatorAccountSettingsPanel.php
--- a/src/applications/settings/panel/PhabricatorAccountSettingsPanel.php
+++ b/src/applications/settings/panel/PhabricatorAccountSettingsPanel.php
@@ -64,20 +64,28 @@
PhutilPerson::SEX_FEMALE => $label_her,
);
+ $locales = PhutilLocale::loadAllLocales();
+ $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
+ $is_dev = PhabricatorEnv::getEnvConfig('phabricator.developer-mode');
+
$translations = array();
- $symbols = id(new PhutilSymbolLoader())
- ->setType('class')
- ->setAncestorClass('PhabricatorTranslation')
- ->setConcreteOnly(true)
- ->selectAndLoadSymbols();
- foreach ($symbols as $symbol) {
- $class = $symbol['name'];
- $translations[$class] = newv($class, array())->getName();
+ foreach ($locales as $locale) {
+ if ($is_serious && $locale->isSillyLocale()) {
+ // Omit silly locales on serious business installs.
+ continue;
+ }
+ if (!$is_dev && $locale->isTestLocale()) {
+ // Omit test locales on installs which aren't in development mode.
+ continue;
+ }
+ $translations[$locale->getLocaleCode()] = $locale->getLocaleName();
}
+
asort($translations);
- $default = PhabricatorEnv::newObjectFromConfig('translation.provider');
+ // TODO: Implement "locale.default" and use it here.
+ $default = 'en_US';
$translations = array(
- '' => pht('Server Default (%s)', $default->getName()),
+ '' => pht('Server Default: %s', $locales[$default]->getLocaleName()),
) + $translations;
$form = new AphrontFormView();
diff --git a/src/docs/contributor/internationalization.diviner b/src/docs/contributor/internationalization.diviner
--- a/src/docs/contributor/internationalization.diviner
+++ b/src/docs/contributor/internationalization.diviner
@@ -1,33 +1,33 @@
@title Internationalization
@group developer
-What is required from developers to get Phabricator translatable.
+Describes Phabricator translation and localization.
-= API =
+Overview
+========
-Translator API is provided by libphutil. It gives us
-@{class@libphutil:PhutilTranslator} class and global @{function@libphutil:pht}
-function built on top of it.
+Phabricator partially supports internationalization, but many of the tools
+are missing or in a prototype state.
-Developers are supposed to call @{function@libphutil:pht} on all strings that
-require translation.
+This document very briefly summarizes some of what exists today.
-Phabricator provides translations for this translator through
-@{class:PhabricatorTranslation} class.
+Writing Translatable Code
+========
-= Adding a New Translation =
+Strings are marked for translation with @{function@libphutil:pht}.
-Adding a translation which uses the same language rules as some already existing
-translation is relatively simple: Just extend @{class:PhabricatorTranslation}
-and you will be able to specify this class in the global configuration
-'translation.provider' and users will be able to select it in their preferences.
+Adding a New Locale
+=========
-= Adding a New Language =
+To add a new locale, subclass @{class:PhutilLocale}.
-Adding a language involves all steps as adding a translation plus specifying the
-language rules in @{method@libphutil:PhutilTranslator::chooseVariant}.
+Translating Strings
+========
-= Singular and Plural =
+To translate strings, subclass @{class:PhutilTranslation}.
+
+Singular and Plural
+========
Different languages have various rules for using singular and plural. All you
need to do is to call @{function@libphutil:pht} with a text that is suitable for
@@ -46,7 +46,8 @@
The ugly identifier passed to @{function@libphutil:pht} will remain in the text
only if the translation doesn't exist.
-= Male and Female =
+Male and Female
+========
Different languages use different words for talking about males, females and
unknown genders. Callsites have to call @{function@libphutil:pht} passing
diff --git a/src/infrastructure/env/PhabricatorEnv.php b/src/infrastructure/env/PhabricatorEnv.php
--- a/src/infrastructure/env/PhabricatorEnv.php
+++ b/src/infrastructure/env/PhabricatorEnv.php
@@ -55,6 +55,7 @@
private static $overrideSource;
private static $requestBaseURI;
private static $cache;
+ private static $localeCode;
/**
* @phutil-external-symbol class PhabricatorStartup
@@ -123,10 +124,34 @@
PhabricatorEventEngine::initialize();
- $translation = PhabricatorEnv::newObjectFromConfig('translation.provider');
- PhutilTranslator::getInstance()
- ->setLanguage($translation->getLanguage())
- ->addTranslations($translation->getCleanTranslations());
+ // TODO: Add a "locale.default" config option once we have some reasonable
+ // defaults which aren't silly nonsense.
+ self::setLocaleCode('en_US');
+ }
+
+ public static function setLocaleCode($locale_code) {
+ if ($locale_code == self::$localeCode) {
+ return;
+ }
+
+ try {
+ $locale = PhutilLocale::loadLocale($locale_code);
+ $translations = PhutilTranslation::getTranslationMapForLocale(
+ $locale_code);
+
+ $override = PhabricatorEnv::getEnvConfig('translation.override');
+ if (!is_array($override)) {
+ $override = array();
+ }
+
+ PhutilTranslator::getInstance()
+ ->setLocale($locale)
+ ->setTranslations($override + $translations);
+
+ self::$localeCode = $locale_code;
+ } catch (Exception $ex) {
+ // Just ignore this; the user likely has an out-of-date locale code.
+ }
}
private static function buildConfigurationSourceStack() {
diff --git a/src/infrastructure/internationalization/translation/PhabricatorAllCapsTranslation.php b/src/infrastructure/internationalization/translation/PhabricatorAllCapsTranslation.php
deleted file mode 100644
--- a/src/infrastructure/internationalization/translation/PhabricatorAllCapsTranslation.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-final class PhabricatorAllCapsTranslation
- extends PhabricatorTranslation {
-
- final public function getLanguage() {
- return 'en-ac';
- }
-
- public function getName() {
- return 'All Caps';
- }
-
- public function getTranslations() {
- return array();
- }
-
-}
diff --git a/src/infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php b/src/infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php
new file mode 100644
--- /dev/null
+++ b/src/infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php
@@ -0,0 +1,31 @@
+<?php
+
+final class PhabricatorBritishEnglishTranslation
+ extends PhutilTranslation {
+
+ public function getLocaleCode() {
+ return 'en_GB';
+ }
+
+ protected function getTranslations() {
+ return array(
+ '%s set this project\'s color to %s.' =>
+ '%s set this project\'s colour to %s.',
+ 'Basic Colors' =>
+ 'Basic Colours',
+ 'Choose Icon and Color...' =>
+ 'Choose Icon and Colour...',
+ 'Choose Background Color' =>
+ 'Choose Background Colour',
+ 'Color' => 'Colour',
+ 'Colors' => 'Colours',
+ 'Colors and Transforms' => 'Colours and Transforms',
+ 'Configure the Phabricator UI, including colors.' =>
+ 'Configure the Phabricator UI, including colours.',
+ 'Flag Color' => 'Flag Colour',
+ 'Sets the color of the main header.' =>
+ 'Sets the colour of the main header.',
+ );
+ }
+
+}
diff --git a/src/infrastructure/internationalization/translation/PhabricatorEnglishTranslation.php b/src/infrastructure/internationalization/translation/PhabricatorEnglishTranslation.php
deleted file mode 100644
--- a/src/infrastructure/internationalization/translation/PhabricatorEnglishTranslation.php
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-
-final class PhabricatorEnglishTranslation
- extends PhabricatorBaseEnglishTranslation {
-
- public function getName() {
- return 'English';
- }
-
- public function getTranslations() {
- return
- PhabricatorEnv::getEnvConfig('translation.override') +
- parent::getTranslations();
- }
-
-}
diff --git a/src/infrastructure/internationalization/translation/PhabricatorTranslation.php b/src/infrastructure/internationalization/translation/PhabricatorTranslation.php
deleted file mode 100644
--- a/src/infrastructure/internationalization/translation/PhabricatorTranslation.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-abstract class PhabricatorTranslation {
-
- abstract public function getLanguage();
- abstract public function getName();
- abstract public function getTranslations();
-
-
- /**
- * Return the cleaned translation array.
- *
- * @return dict<string, wild> Translation map with empty translations removed.
- */
- public function getCleanTranslations() {
- return $this->clean($this->getTranslations());
- }
-
-
- /**
- * Removes NULL-valued translation keys from the translation map, to prevent
- * echoing out empty strings.
- *
- * @param dict<string, wild> Translation map, with empty translations.
- * @return dict<string, wild> Map with empty translations removed.
- */
- protected function clean(array $translation_array) {
- foreach ($translation_array as $key => $translation_string) {
- if ($translation_string === null) {
- unset($translation_array[$key]);
- }
- }
-
- return $translation_array;
- }
-
-}
diff --git a/src/infrastructure/internationalization/translation/PhabricatorBaseEnglishTranslation.php b/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
rename from src/infrastructure/internationalization/translation/PhabricatorBaseEnglishTranslation.php
rename to src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
--- a/src/infrastructure/internationalization/translation/PhabricatorBaseEnglishTranslation.php
+++ b/src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
@@ -1,13 +1,13 @@
<?php
-abstract class PhabricatorBaseEnglishTranslation
- extends PhabricatorTranslation {
+final class PhabricatorUSEnglishTranslation
+ extends PhutilTranslation {
- final public function getLanguage() {
- return 'en';
+ public function getLocaleCode() {
+ return 'en_US';
}
- public function getTranslations() {
+ protected function getTranslations() {
return array(
'No daemon(s) with id(s) "%s" exist!' => array(
'No daemon with id %s exists!',
diff --git a/src/infrastructure/internationalization/translation/PhabricatorVeryWowEnglishTranslation.php b/src/infrastructure/internationalization/translation/PhabricatorVeryWowEnglishTranslation.php
new file mode 100644
--- /dev/null
+++ b/src/infrastructure/internationalization/translation/PhabricatorVeryWowEnglishTranslation.php
@@ -0,0 +1,22 @@
+<?php
+
+final class PhabricatorVeryWowEnglishTranslation
+ extends PhutilTranslation {
+
+ public function getLocaleCode() {
+ return 'en_W*';
+ }
+
+ protected function getTranslations() {
+ return array(
+ 'Search' => 'Search! Wow!',
+ 'Review Code' => 'Wow! Code Review! Wow!',
+ 'Tasks and Bugs' => 'Much Bug! Very Bad!',
+ 'Cancel' => 'Nope!',
+ 'Advanced Search' => 'Much Search!',
+ 'No search results.' => 'No results! Wow!',
+ 'Send Message' => 'Bark! Bark Bark!',
+ );
+ }
+
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Nov 21, 1:34 PM (21 h, 55 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6716835
Default Alt Text
D11747.diff (22 KB)
Attached To
Mode
D11747: Update Phabricator to work with more modular translations
Attached
Detach File
Event Timeline
Log In to Comment