Page MenuHomePhabricator

D9425.diff
No OneTemporary

D9425.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -7,7 +7,7 @@
return array(
'names' =>
array(
- 'core.pkg.css' => '703a28a5',
+ 'core.pkg.css' => '6c5077ff',
'core.pkg.js' => '5f0169b1',
'darkconsole.pkg.js' => 'ca8671ce',
'differential.pkg.css' => '4a93db37',
@@ -104,7 +104,7 @@
'rsrc/css/application/subscriptions/subscribers-list.css' => '5bb30c78',
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
'rsrc/css/application/uiexample/example.css' => '528b19de',
- 'rsrc/css/core/core.css' => '40151074',
+ 'rsrc/css/core/core.css' => '2bc4d840',
'rsrc/css/core/remarkup.css' => 'b510c359',
'rsrc/css/core/syntax.css' => '3c18c1cb',
'rsrc/css/core/z-index.css' => 'efb673ac',
@@ -469,6 +469,7 @@
'rsrc/js/core/behavior-toggle-class.js' => 'a82a7769',
'rsrc/js/core/behavior-tokenizer.js' => 'b3a4b884',
'rsrc/js/core/behavior-tooltip.js' => '48db4145',
+ 'rsrc/js/core/behavior-translate.js' => '4eb0011d',
'rsrc/js/core/behavior-watch-anchor.js' => '06e05112',
'rsrc/js/core/behavior-workflow.js' => '0a3f3021',
'rsrc/js/core/phtize.js' => 'd254d646',
@@ -633,6 +634,7 @@
'javelin-behavior-stripe-payment-form' => '1693a296',
'javelin-behavior-test-payment-form' => 'b3e5ee60',
'javelin-behavior-toggle-class' => 'a82a7769',
+ 'javelin-behavior-translate' => '4eb0011d',
'javelin-behavior-view-placeholder' => '2fa810fc',
'javelin-behavior-workflow' => '0a3f3021',
'javelin-color' => '7e41274a',
@@ -690,7 +692,7 @@
'phabricator-busy' => '6453c869',
'phabricator-chatlog-css' => '852140ff',
'phabricator-content-source-view-css' => '4b8b05d4',
- 'phabricator-core-css' => '40151074',
+ 'phabricator-core-css' => '2bc4d840',
'phabricator-countdown-css' => '86b7b0a0',
'phabricator-crumbs-view-css' => '989a48b6',
'phabricator-dashboard-css' => 'f593f8c2',
@@ -1178,6 +1180,13 @@
1 => 'javelin-dom',
2 => 'javelin-reactor-dom',
),
+ '4eb0011d' =>
+ array(
+ 0 => 'javelin-behavior',
+ 1 => 'javelin-stratcom',
+ 2 => 'javelin-workflow',
+ 3 => 'javelin-dom',
+ ),
'4f344388' =>
array(
0 => 'javelin-install',
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
@@ -1210,6 +1210,7 @@
'PhabricatorApplicationTransactionValueController' => 'applications/transactions/controller/PhabricatorApplicationTransactionValueController.php',
'PhabricatorApplicationTransactionView' => 'applications/transactions/view/PhabricatorApplicationTransactionView.php',
'PhabricatorApplicationTransactions' => 'applications/transactions/application/PhabricatorApplicationTransactions.php',
+ 'PhabricatorApplicationTranslations' => 'applications/translations/application/PhabricatorApplicationTranslations.php',
'PhabricatorApplicationTypeahead' => 'applications/typeahead/application/PhabricatorApplicationTypeahead.php',
'PhabricatorApplicationUIExamples' => 'applications/uiexample/application/PhabricatorApplicationUIExamples.php',
'PhabricatorApplicationUninstallController' => 'applications/meta/controller/PhabricatorApplicationUninstallController.php',
@@ -2156,6 +2157,7 @@
'PhabricatorSettingsPanelEmailPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelEmailPreferences.php',
'PhabricatorSettingsPanelExternalAccounts' => 'applications/settings/panel/PhabricatorSettingsPanelExternalAccounts.php',
'PhabricatorSettingsPanelHomePreferences' => 'applications/settings/panel/PhabricatorSettingsPanelHomePreferences.php',
+ 'PhabricatorSettingsPanelLanguage' => 'applications/settings/panel/PhabricatorSettingsPanelLanguage.php',
'PhabricatorSettingsPanelMultiFactor' => 'applications/settings/panel/PhabricatorSettingsPanelMultiFactor.php',
'PhabricatorSettingsPanelPassword' => 'applications/settings/panel/PhabricatorSettingsPanelPassword.php',
'PhabricatorSettingsPanelSSHKeys' => 'applications/settings/panel/PhabricatorSettingsPanelSSHKeys.php',
@@ -2286,6 +2288,8 @@
'PhabricatorTransformedFile' => 'applications/files/storage/PhabricatorTransformedFile.php',
'PhabricatorTranslation' => 'infrastructure/internationalization/translation/PhabricatorTranslation.php',
'PhabricatorTranslationsConfigOptions' => 'applications/config/option/PhabricatorTranslationsConfigOptions.php',
+ 'PhabricatorTranslationsController' => 'applications/translations/controller/PhabricatorTranslationsController.php',
+ 'PhabricatorTranslationsTranslateController' => 'applications/translations/controller/PhabricatorTranslationsTranslateController.php',
'PhabricatorTrivialTestCase' => 'infrastructure/testing/__tests__/PhabricatorTrivialTestCase.php',
'PhabricatorTwoColumnExample' => 'applications/uiexample/examples/PhabricatorTwoColumnExample.php',
'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadCommonDatasourceController.php',
@@ -3560,6 +3564,7 @@
0 => 'HeraldDAO',
1 => 'PhabricatorFlaggableInterface',
2 => 'PhabricatorPolicyInterface',
+ 3 => 'PhabricatorDestructableInterface',
),
'HeraldRuleController' => 'HeraldController',
'HeraldRuleEdit' => 'HeraldDAO',
@@ -3991,6 +3996,7 @@
'PhabricatorApplicationTransactionValueController' => 'PhabricatorApplicationTransactionController',
'PhabricatorApplicationTransactionView' => 'AphrontView',
'PhabricatorApplicationTransactions' => 'PhabricatorApplication',
+ 'PhabricatorApplicationTranslations' => 'PhabricatorApplication',
'PhabricatorApplicationTypeahead' => 'PhabricatorApplication',
'PhabricatorApplicationUIExamples' => 'PhabricatorApplication',
'PhabricatorApplicationUninstallController' => 'PhabricatorApplicationsController',
@@ -5035,6 +5041,7 @@
'PhabricatorSettingsPanelEmailPreferences' => 'PhabricatorSettingsPanel',
'PhabricatorSettingsPanelExternalAccounts' => 'PhabricatorSettingsPanel',
'PhabricatorSettingsPanelHomePreferences' => 'PhabricatorSettingsPanel',
+ 'PhabricatorSettingsPanelLanguage' => 'PhabricatorSettingsPanel',
'PhabricatorSettingsPanelMultiFactor' => 'PhabricatorSettingsPanel',
'PhabricatorSettingsPanelPassword' => 'PhabricatorSettingsPanel',
'PhabricatorSettingsPanelSSHKeys' => 'PhabricatorSettingsPanel',
@@ -5164,6 +5171,8 @@
'PhabricatorTransactionView' => 'AphrontView',
'PhabricatorTransformedFile' => 'PhabricatorFileDAO',
'PhabricatorTranslationsConfigOptions' => 'PhabricatorApplicationConfigOptions',
+ 'PhabricatorTranslationsController' => 'PhabricatorController',
+ 'PhabricatorTranslationsTranslateController' => 'PhabricatorTranslationsController',
'PhabricatorTrivialTestCase' => 'PhabricatorTestCase',
'PhabricatorTwoColumnExample' => 'PhabricatorUIExample',
'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
@@ -5342,6 +5351,7 @@
4 => 'PhabricatorTokenReceiverInterface',
5 => 'PhabricatorFlaggableInterface',
6 => 'PhabricatorApplicationTransactionInterface',
+ 7 => 'PhabricatorProjectInterface',
),
'PholioMockCommentController' => 'PholioController',
'PholioMockEditController' => 'PholioController',
diff --git a/src/aphront/response/AphrontResponse.php b/src/aphront/response/AphrontResponse.php
--- a/src/aphront/response/AphrontResponse.php
+++ b/src/aphront/response/AphrontResponse.php
@@ -59,6 +59,10 @@
}
public static function processValueForJSONEncoding(&$value, $key) {
+ if ($value instanceof PhutilTranslatableText) {
+ $value = (string)$value;
+ }
+
if ($value instanceof PhutilSafeHTMLProducerInterface) {
// This renders the producer down to PhutilSafeHTML, which will then
// be simplified into a string below.
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
@@ -115,6 +115,11 @@
}
}
+ $pref_translate = PhabricatorUserPreferences::PREFERENCE_TRANSLATE_MODE;
+ if ($preferences->getPreference($pref_translate)) {
+ PhutilTranslator::getInstance()->setTranslateMode(true);
+ }
+
// NOTE: We want to set up the user first so we can render a real page
// here, but fire this before any real logic.
$restricted = array(
diff --git a/src/applications/doorkeeper/engine/DoorkeeperFeedStoryPublisher.php b/src/applications/doorkeeper/engine/DoorkeeperFeedStoryPublisher.php
--- a/src/applications/doorkeeper/engine/DoorkeeperFeedStoryPublisher.php
+++ b/src/applications/doorkeeper/engine/DoorkeeperFeedStoryPublisher.php
@@ -14,13 +14,13 @@
/**
- * Render story text using contextual langauge to identify the object the
+ * Render story text using contextual language to identify the object the
* story is about, instead of the full object name. For example, without
* contextual language a story might render like this:
*
* alincoln created D123: Chop Wood for Log Cabin v2.0
*
- * With contextual langauge, it will render like this instead:
+ * With contextual language, it will render like this instead:
*
* alincoln created this revision.
*
diff --git a/src/applications/settings/controller/PhabricatorSettingsMainController.php b/src/applications/settings/controller/PhabricatorSettingsMainController.php
--- a/src/applications/settings/controller/PhabricatorSettingsMainController.php
+++ b/src/applications/settings/controller/PhabricatorSettingsMainController.php
@@ -141,8 +141,8 @@
$group = null;
foreach ($panels as $panel) {
- if ($panel->getPanelGroup() != $group) {
- $group = $panel->getPanelGroup();
+ if ((string)$panel->getPanelGroup() != $group) {
+ $group = (string)$panel->getPanelGroup();
$nav->addLabel($group);
}
diff --git a/src/applications/settings/panel/PhabricatorSettingsPanelAccount.php b/src/applications/settings/panel/PhabricatorSettingsPanelAccount.php
--- a/src/applications/settings/panel/PhabricatorSettingsPanelAccount.php
+++ b/src/applications/settings/panel/PhabricatorSettingsPanelAccount.php
@@ -39,9 +39,6 @@
$user->setSex(null);
}
- // Checked in runtime.
- $user->setTranslation($request->getStr('translation'));
-
$preferences->setPreference($pref_time, $request->getStr($pref_time));
if (!$errors) {
@@ -65,22 +62,6 @@
PhutilPerson::SEX_FEMALE => $label_her,
);
- $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();
- }
- asort($translations);
- $default = PhabricatorEnv::newObjectFromConfig('translation.provider');
- $translations = array(
- '' => pht('Server Default (%s)', $default->getName()),
- ) + $translations;
-
$form = new AphrontFormView();
$form
->setUser($user)
@@ -97,12 +78,6 @@
->setLabel(pht('Pronoun'))
->setName('sex')
->setValue($user->getSex()))
- ->appendChild(
- id(new AphrontFormSelectControl())
- ->setOptions($translations)
- ->setLabel(pht('Translation'))
- ->setName('translation')
- ->setValue($user->getTranslation()))
->appendRemarkupInstructions(
pht(
"**Custom Date and Time Formats**\n\n".
diff --git a/src/applications/settings/panel/PhabricatorSettingsPanelLanguage.php b/src/applications/settings/panel/PhabricatorSettingsPanelLanguage.php
new file mode 100644
--- /dev/null
+++ b/src/applications/settings/panel/PhabricatorSettingsPanelLanguage.php
@@ -0,0 +1,92 @@
+<?php
+
+final class PhabricatorSettingsPanelLanguage
+ extends PhabricatorSettingsPanel {
+
+ public function getPanelKey() {
+ return 'language';
+ }
+
+ public function getPanelName() {
+ return pht('Language');
+ }
+
+ public function getPanelGroup() {
+ return pht('Account Information');
+ }
+
+ public function processRequest(AphrontRequest $request) {
+ $user = $request->getUser();
+ $username = $user->getUsername();
+
+ $pref_translate = PhabricatorUserPreferences::PREFERENCE_TRANSLATE_MODE;
+ $preferences = $user->loadPreferences();
+
+ $errors = array();
+ if ($request->isFormPost()) {
+ $user->setTranslation($request->getStr('translation'));
+
+ $preferences->setPreference(
+ $pref_translate,
+ $request->getBool($pref_translate));
+
+ if (!$errors) {
+ $preferences->save();
+ $user->save();
+ return id(new AphrontRedirectResponse())
+ ->setURI($this->getPanelURI('?saved=true'));
+ }
+ }
+
+ $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();
+ }
+ asort($translations);
+ $default = PhabricatorEnv::newObjectFromConfig('translation.provider');
+ $translations = array(
+ '' => pht('Server Default (%s)', $default->getName()),
+ ) + $translations;
+
+ $form = new AphrontFormView();
+ $form
+ ->setUser($user)
+ ->appendChild(
+ id(new AphrontFormSelectControl())
+ ->setOptions($translations)
+ ->setLabel(pht('Use Phabricator In'))
+ ->setName('translation')
+ ->setValue($user->getTranslation()))
+ ->appendRemarkupInstructions(
+ pht(
+ "WARNING: This feature does not work yet!\n\n".
+ "IMPORTANT: Enabling this feature may break Phabricator!\n\n".
+ "In the future, you will be able to help translate Phabricator ".
+ "to a new language by enabling Translation Mode. However, this ".
+ "feature does not work yet."))
+ ->appendChild(
+ id(new AphrontFormCheckboxControl())
+ ->addCheckbox(
+ $pref_translate,
+ 1,
+ pht('Enable Translation Mode'),
+ $preferences->getPreference($pref_translate)))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue(pht('Save Language Settings')));
+
+ $form_box = id(new PHUIObjectBoxView())
+ ->setHeaderText(pht('Account Settings'))
+ ->setFormSaved($request->getStr('saved'))
+ ->setFormErrors($errors)
+ ->setForm($form);
+
+ return $form_box;
+ }
+}
diff --git a/src/applications/settings/storage/PhabricatorUserPreferences.php b/src/applications/settings/storage/PhabricatorUserPreferences.php
--- a/src/applications/settings/storage/PhabricatorUserPreferences.php
+++ b/src/applications/settings/storage/PhabricatorUserPreferences.php
@@ -29,6 +29,7 @@
const PREFERENCE_DIFF_FILETREE = 'diff-filetree';
const PREFERENCE_CONPH_NOTIFICATIONS = 'conph-notifications';
+ const PREFERENCE_TRANSLATE_MODE = 'translate-mode';
protected $userPHID;
protected $preferences = array();
diff --git a/src/applications/translations/application/PhabricatorApplicationTranslations.php b/src/applications/translations/application/PhabricatorApplicationTranslations.php
new file mode 100644
--- /dev/null
+++ b/src/applications/translations/application/PhabricatorApplicationTranslations.php
@@ -0,0 +1,33 @@
+<?php
+
+final class PhabricatorApplicationTranslations extends PhabricatorApplication {
+
+ public function getBaseURI() {
+ return '/translations/';
+ }
+
+ public function getIconName() {
+ return 'translations';
+ }
+
+ public function getTitleGlyph() {
+ return '?';
+ }
+
+ public function getApplicationGroup() {
+ return self::GROUP_UTILITIES;
+ }
+
+ public function getShortDescription() {
+ return pht('Internationalization');
+ }
+
+ public function getRoutes() {
+ return array(
+ '/translations/' => array(
+ 'translate/' => 'PhabricatorTranslationsTranslateController',
+ ),
+ );
+ }
+
+}
diff --git a/src/applications/translations/controller/PhabricatorTranslationsController.php b/src/applications/translations/controller/PhabricatorTranslationsController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/translations/controller/PhabricatorTranslationsController.php
@@ -0,0 +1,6 @@
+<?php
+
+abstract class PhabricatorTranslationsController
+ extends PhabricatorController {
+
+}
diff --git a/src/applications/translations/controller/PhabricatorTranslationsTranslateController.php b/src/applications/translations/controller/PhabricatorTranslationsTranslateController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/translations/controller/PhabricatorTranslationsTranslateController.php
@@ -0,0 +1,75 @@
+<?php
+
+final class PhabricatorTranslationsTranslateController
+ extends PhabricatorTranslationsController {
+
+ public function processRequest() {
+ $request = $this->getRequest();
+ $viewer = $request->getUser();
+
+ $spec = phutil_json_decode($request->getStr('spec'));
+ $original = idx($spec, 'orig');
+ $file = idx($spec, 'file');
+ $line = idx($spec, 'line');
+
+ if ($request->isFormPost()) {
+ $translation = $request->getStr('translation');
+
+ $response = array(
+ 'status' => $translation
+ ? 'user'
+ : 'none',
+ );
+ return id(new AphrontAjaxResponse())->setContent($response);
+ }
+
+ $form = id(new AphrontFormView())
+ ->setUser($viewer);
+
+ $form
+ ->addHiddenInput('spec', json_encode($spec))
+ ->appendRemarkupInstructions(
+ pht('WARNING: This feature does not work yet!'))
+ ->appendChild(
+ id(new AphrontFormStaticControl())
+ ->setLabel(pht('Source'))
+ ->setValue($original));
+
+ if ($file && $line) {
+ $file = Filesystem::readablePath(
+ $file,
+ dirname(phutil_get_library_root('phabricator')));
+
+ $defined_href = urisprintf(
+ 'https://secure.phabricator.com/diffusion/P/browse/master/%s$%s',
+ $file,
+ $line);
+
+ $form->appendChild(
+ id(new AphrontFormStaticControl())
+ ->setLabel(pht('Defined'))
+ ->setValue(
+ phutil_tag(
+ 'a',
+ array(
+ 'href' => $defined_href,
+ 'target' => '_blank',
+ ),
+ basename($file).':'.$line)));
+ }
+
+ $form->appendChild(
+ id(new AphrontFormTextAreaControl())
+ ->setLabel(pht('Translation'))
+ ->setName('translation')
+ ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT));
+
+ return $this->newDialog()
+ ->setTitle(pht('Translate String'))
+ ->setWidth(AphrontDialogView::WIDTH_FULL)
+ ->appendChild($form->buildLayoutView())
+ ->addSubmitButton(pht('Save Changes'))
+ ->addCancelButton('/');
+ }
+
+}
diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php
--- a/src/view/page/PhabricatorStandardPageView.php
+++ b/src/view/page/PhabricatorStandardPageView.php
@@ -91,7 +91,7 @@
$title = $prefix.' '.$title;
}
- return $title;
+ return (string)$title;
}
@@ -153,6 +153,13 @@
Javelin::initBehavior('history-install');
Javelin::initBehavior('phabricator-gesture');
+ $prefs = $user->loadPreferences();
+
+ $pref_translate = PhabricatorUserPreferences::PREFERENCE_TRANSLATE_MODE;
+ if ($prefs->getPreference($pref_translate)) {
+ Javelin::initBehavior('translate');
+ }
+
$current_token = null;
if ($user) {
$current_token = $user->getCSRFToken();
diff --git a/webroot/rsrc/css/core/core.css b/webroot/rsrc/css/core/core.css
--- a/webroot/rsrc/css/core/core.css
+++ b/webroot/rsrc/css/core/core.css
@@ -177,3 +177,21 @@
height: 2px;
background: {$sky};
}
+
+.pht-translatable {
+ border-style: dashed;
+ border-width: 0 0 1px;
+ cursor: alias;
+}
+
+.pht-translation-none {
+ border-color: {$indigo};
+}
+
+.pht-translation-file {
+ border-color: {$sky};
+}
+
+.pht-translation-user {
+ border-color: {$green};
+}
diff --git a/webroot/rsrc/js/core/behavior-translate.js b/webroot/rsrc/js/core/behavior-translate.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/core/behavior-translate.js
@@ -0,0 +1,32 @@
+/**
+ * @provides javelin-behavior-translate
+ * @requires javelin-behavior
+ * javelin-stratcom
+ * javelin-workflow
+ * javelin-dom
+ */
+
+JX.behavior('translate', function() {
+
+ JX.Stratcom.listen(
+ 'click',
+ 'pht-translatable',
+ function(e) {
+ if (!e.getRawEvent().shiftKey) {
+ return;
+ }
+ e.kill();
+
+ var node = e.getNode('pht-translatable');
+ var data = node.getAttribute('data-pht');
+
+ new JX.Workflow('/translations/translate/', {spec: data})
+ .setHandler(function(r) {
+ JX.DOM.alterClass(node, 'pht-translation-none', (r.status == 'none'));
+ JX.DOM.alterClass(node, 'pht-translation-file', false);
+ JX.DOM.alterClass(node, 'pht-translation-user', (r.status == 'user'));
+ })
+ .start();
+ });
+
+});

File Metadata

Mime Type
text/plain
Expires
Tue, May 14, 12:03 AM (2 w, 6 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6281578
Default Alt Text
D9425.diff (21 KB)

Event Timeline