Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15274424
D9425.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
21 KB
Referenced Files
None
Subscribers
None
D9425.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Sun, Mar 2, 6:23 AM (20 h, 56 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7216450
Default Alt Text
D9425.diff (21 KB)
Attached To
Mode
D9425: Very rough proof-of-concept of inline-translatable strings
Attached
Detach File
Event Timeline
Log In to Comment