Index: bin/i18n =================================================================== --- /dev/null +++ bin/i18n @@ -0,0 +1 @@ +../scripts/setup/manage_i18n.php \ No newline at end of file Index: scripts/setup/manage_i18n.php =================================================================== --- /dev/null +++ scripts/setup/manage_i18n.php @@ -0,0 +1,21 @@ +#!/usr/bin/env php +setTagline('manage internationalization'); +$args->setSynopsis(<<parseStandardArguments(); + +$workflows = id(new PhutilSymbolLoader()) + ->setAncestorClass('PhabricatorInternationalizationManagementWorkflow') + ->loadObjects(); +$workflows[] = new PhutilHelpArgumentWorkflow(); +$args->parseWorkflows($workflows); Index: src/__phutil_library_map__.php =================================================================== --- src/__phutil_library_map__.php +++ src/__phutil_library_map__.php @@ -1066,7 +1066,7 @@ 'PhabricatorActionListExample' => 'applications/uiexample/examples/PhabricatorActionListExample.php', 'PhabricatorActionListView' => 'view/layout/PhabricatorActionListView.php', 'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php', - 'PhabricatorAllCapsTranslation' => 'infrastructure/internationalization/PhabricatorAllCapsTranslation.php', + 'PhabricatorAllCapsTranslation' => 'infrastructure/internationalization/translation/PhabricatorAllCapsTranslation.php', 'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php', 'PhabricatorAphrontBarExample' => 'applications/uiexample/examples/PhabricatorAphrontBarExample.php', 'PhabricatorAphrontViewTestCase' => 'view/__tests__/PhabricatorAphrontViewTestCase.php', @@ -1230,7 +1230,7 @@ 'PhabricatorAuthenticationConfigOptions' => 'applications/config/option/PhabricatorAuthenticationConfigOptions.php', 'PhabricatorBarePageExample' => 'applications/uiexample/examples/PhabricatorBarePageExample.php', 'PhabricatorBarePageView' => 'view/page/PhabricatorBarePageView.php', - 'PhabricatorBaseEnglishTranslation' => 'infrastructure/internationalization/PhabricatorBaseEnglishTranslation.php', + 'PhabricatorBaseEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBaseEnglishTranslation.php', 'PhabricatorBaseProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorBaseProtocolAdapter.php', 'PhabricatorBot' => 'infrastructure/daemon/bot/PhabricatorBot.php', 'PhabricatorBotBaseStreamingProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorBotBaseStreamingProtocolAdapter.php', @@ -1434,7 +1434,7 @@ 'PhabricatorEmailTokenController' => 'applications/auth/controller/PhabricatorEmailTokenController.php', 'PhabricatorEmailVerificationController' => 'applications/auth/controller/PhabricatorEmailVerificationController.php', 'PhabricatorEmptyQueryException' => 'infrastructure/query/PhabricatorEmptyQueryException.php', - 'PhabricatorEnglishTranslation' => 'infrastructure/internationalization/PhabricatorEnglishTranslation.php', + 'PhabricatorEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorEnglishTranslation.php', 'PhabricatorEnv' => 'infrastructure/env/PhabricatorEnv.php', 'PhabricatorEnvTestCase' => 'infrastructure/env/__tests__/PhabricatorEnvTestCase.php', 'PhabricatorErrorExample' => 'applications/uiexample/examples/PhabricatorErrorExample.php', @@ -1573,6 +1573,8 @@ 'PhabricatorInlineCommentInterface' => 'infrastructure/diff/interface/PhabricatorInlineCommentInterface.php', 'PhabricatorInlineCommentPreviewController' => 'infrastructure/diff/PhabricatorInlineCommentPreviewController.php', 'PhabricatorInlineSummaryView' => 'infrastructure/diff/view/PhabricatorInlineSummaryView.php', + 'PhabricatorInternationalizationManagementExtractWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementExtractWorkflow.php', + 'PhabricatorInternationalizationManagementWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementWorkflow.php', 'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php', 'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php', 'PhabricatorKeyValueDatabaseCache' => 'applications/cache/PhabricatorKeyValueDatabaseCache.php', @@ -2098,7 +2100,7 @@ 'PhabricatorTransactionView' => 'view/layout/PhabricatorTransactionView.php', 'PhabricatorTransactions' => 'applications/transactions/constants/PhabricatorTransactions.php', 'PhabricatorTransformedFile' => 'applications/files/storage/PhabricatorTransformedFile.php', - 'PhabricatorTranslation' => 'infrastructure/internationalization/PhabricatorTranslation.php', + 'PhabricatorTranslation' => 'infrastructure/internationalization/translation/PhabricatorTranslation.php', 'PhabricatorTranslationsConfigOptions' => 'applications/config/option/PhabricatorTranslationsConfigOptions.php', 'PhabricatorTrivialTestCase' => 'infrastructure/testing/__tests__/PhabricatorTrivialTestCase.php', 'PhabricatorTwoColumnExample' => 'applications/uiexample/examples/PhabricatorTwoColumnExample.php', @@ -4270,6 +4272,8 @@ 'PhabricatorInlineCommentInterface' => 'PhabricatorMarkupInterface', 'PhabricatorInlineCommentPreviewController' => 'PhabricatorController', 'PhabricatorInlineSummaryView' => 'AphrontView', + 'PhabricatorInternationalizationManagementExtractWorkflow' => 'PhabricatorInternationalizationManagementWorkflow', + 'PhabricatorInternationalizationManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorJavelinLinter' => 'ArcanistLinter', 'PhabricatorKeyValueDatabaseCache' => 'PhutilKeyValueCache', 'PhabricatorLegalpadConfigOptions' => 'PhabricatorApplicationConfigOptions', Index: src/aphront/AphrontRequest.php =================================================================== --- src/aphront/AphrontRequest.php +++ src/aphront/AphrontRequest.php @@ -357,7 +357,7 @@ 'This Phabricator install is configured as "%s", but you are '. 'using the domain name "%s" to access a page which is trying to '. 'set a cookie. Acccess Phabricator on the configured primary '. - 'domain or a configured alternate domain. Phabricator will not '. + 'domain or a configured alternate domain. Phabricator will not '. 'set cookies on other domains for security reasons.', $configured_as, $accessed_as)); Index: src/infrastructure/internationalization/management/PhabricatorInternationalizationManagementExtractWorkflow.php =================================================================== --- /dev/null +++ src/infrastructure/internationalization/management/PhabricatorInternationalizationManagementExtractWorkflow.php @@ -0,0 +1,99 @@ +setName('extract') + ->setSynopsis(pht('Extract translatable strings.')) + ->setArguments( + array( + array( + 'name' => 'paths', + 'wildcard' => true, + ), + )); + } + + public function execute(PhutilArgumentParser $args) { + $console = PhutilConsole::getConsole(); + $paths = $args->getArg('paths'); + + $futures = array(); + foreach ($paths as $path) { + $root = Filesystem::resolvePath($path); + $path_files = id(new FileFinder($root)) + ->withType('f') + ->withSuffix('php') + ->find(); + + foreach ($path_files as $file) { + $full_path = $root.DIRECTORY_SEPARATOR.$file; + $data = Filesystem::readFile($full_path); + $futures[$full_path] = xhpast_get_parser_future($data); + } + } + + $console->writeOut( + "%s\n", + pht('Found %s file(s)...', new PhutilNumber(count($futures)))); + + $results = array(); + + $bar = id(new PhutilConsoleProgressBar()) + ->setTotal(count($futures)); + foreach (Futures($futures)->limit(8) as $full_path => $future) { + $bar->update(1); + + $tree = XHPASTTree::newFromDataAndResolvedExecFuture( + Filesystem::readFile($full_path), + $future->resolve()); + + $root = $tree->getRootNode(); + $calls = $root->selectDescendantsOfType('n_FUNCTION_CALL'); + foreach ($calls as $call) { + $name = $call->getChildByIndex(0)->getConcreteString(); + if ($name == 'pht') { + $params = $call->getChildByIndex(1, 'n_CALL_PARAMETER_LIST'); + $string_node = $params->getChildByIndex(0); + $string_line = $string_node->getLineNumber(); + try { + $string_value = $string_node->evalStatic(); + + $results[$string_value][] = array( + 'file' => Filesystem::readablePath($full_path), + 'line' => $string_line, + ); + } catch (Exception $ex) { + // TODO: Deal with this junks. + } + } + } + + $tree->dispose(); + } + $bar->done(); + + ksort($results); + + $out = array(); + $out[] = ' $locations) { + foreach ($locations as $location) { + $out[] = ' // '.$location['file'].':'.$location['line']; + } + $out[] = " '".addcslashes($string, "\0..\37\\'\177..\377")."' => null,"; + $out[] = null; + } + $out[] = ');'; + $out[] = null; + + echo implode("\n", $out); + + return 0; + } + +} Index: src/infrastructure/internationalization/management/PhabricatorInternationalizationManagementWorkflow.php =================================================================== --- /dev/null +++ src/infrastructure/internationalization/management/PhabricatorInternationalizationManagementWorkflow.php @@ -0,0 +1,6 @@ +