src/TranslatorInterface/TranslationsSpecialPage.php
<?php
declare( strict_types = 1 );
namespace MediaWiki\Extension\Translate\TranslatorInterface;
use HtmlArmor;
use MediaWiki\Extension\Translate\MessageLoading\MessageHandle;
use MediaWiki\Extension\Translate\Utilities\Utilities;
use MediaWiki\Html\Html;
use MediaWiki\HTMLForm\HTMLForm;
use MediaWiki\Language\Language;
use MediaWiki\Languages\LanguageNameUtils;
use MediaWiki\Message\Message;
use MediaWiki\SpecialPage\IncludableSpecialPage;
use MediaWiki\Title\Title;
use SearchEngineFactory;
use Wikimedia\Rdbms\ILoadBalancer;
/**
* Implements a special page which shows all translations for a message.
* Bits taken from SpecialPrefixindex.php and TranslateTasks.php
*
* @author Siebrand Mazeland
* @author Niklas Laxstörm
* @license GPL-2.0-or-later
* @ingroup SpecialPage TranslateSpecialPage
*/
class TranslationsSpecialPage extends IncludableSpecialPage {
private Language $contentLanguage;
private LanguageNameUtils $languageNameUtils;
private ILoadBalancer $loadBalancer;
private SearchEngineFactory $searchEngineFactory;
public function __construct(
Language $contentLanguage,
LanguageNameUtils $languageNameUtils,
ILoadBalancer $loadBalancer,
SearchEngineFactory $searchEngineFactory
) {
parent::__construct( 'Translations' );
$this->contentLanguage = $contentLanguage;
$this->languageNameUtils = $languageNameUtils;
$this->loadBalancer = $loadBalancer;
$this->searchEngineFactory = $searchEngineFactory;
}
protected function getGroupName() {
return 'translation';
}
public function getDescription() {
return $this->msg( 'translations' );
}
public function prefixSearchSubpages( $search, $limit, $offset ) {
return $this->prefixSearchString( $search, $limit, $offset, $this->searchEngineFactory );
}
/**
* Entry point : initialise variables and call subfunctions.
* @param string|null $par Message key. Becomes "MediaWiki:Allmessages" when called like
* Special:Translations/MediaWiki:Allmessages (default null)
*/
public function execute( $par ) {
$this->setHeaders();
$this->outputHeader();
$out = $this->getOutput();
$out->addModuleStyles( 'ext.translate.specialpages.styles' );
$par = (string)$par;
if ( $this->including() ) {
$title = Title::newFromText( $par );
if ( !$title ) {
$out->addWikiMsg( 'translate-translations-including-no-param' );
} else {
$this->showTranslations( $title );
}
return;
}
/**
* GET values.
*/
$request = $this->getRequest();
$message = $request->getText( 'message', $par );
$namespace = $request->getInt( 'namespace', NS_MAIN );
$title = Title::newFromText( $message, $namespace );
$out->addHelpLink(
'Help:Extension:Translate/Statistics_and_reporting#Translations_in_all_languages'
);
if ( !$title ) {
$title = Title::makeTitle( NS_MEDIAWIKI, '' );
$this->namespaceMessageForm( $title );
} else {
$this->namespaceMessageForm( $title );
$out->addHTML( '<br />' );
$this->showTranslations( $title );
}
}
/**
* Message input fieldset
*/
private function namespaceMessageForm( Title $title ): void {
$formDescriptor = [
'textbox' => [
'type' => 'text',
'name' => 'message',
'id' => 'message',
'label-message' => 'translate-translations-messagename',
'size' => 30,
'default' => $title->getText(),
],
'selector' => [
'type' => 'select',
'name' => 'namespace',
'id' => 'namespace',
'label-message' => 'translate-translations-project',
'options' => $this->getSortedNamespaces(),
'default' => $title->getNamespace(),
]
];
HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() )
->setMethod( 'get' )
->setTitle( $this->getPageTitle() ) // Remove subpage
->setSubmitTextMsg( 'allpagessubmit' )
->setWrapperLegendMsg( 'translate-translations-fieldset-title' )
->prepareForm()
->displayForm( false );
}
/**
* Returns sorted array of namespaces.
*
* @return array<string,int>
*/
private function getSortedNamespaces(): array {
$nslist = [];
foreach ( $this->getConfig()->get( 'TranslateMessageNamespaces' ) as $ns ) {
$nslist[$this->contentLanguage->getFormattedNsText( $ns )] = $ns;
}
ksort( $nslist );
return $nslist;
}
/**
* Builds a table with all translations of $title.
*/
private function showTranslations( Title $title ): void {
$handle = new MessageHandle( $title );
$namespace = $title->getNamespace();
$message = $handle->getKey();
if ( !$handle->isValid() ) {
$this->getOutput()->addWikiMsg( 'translate-translations-no-message', $title->getPrefixedText() );
return;
}
$dbr = $this->loadBalancer->getConnection( DB_REPLICA );
/** @var string[] */
$titles = $dbr->newSelectQueryBuilder()
->select( 'page_title' )
->from( 'page' )
->where( [
'page_namespace' => $namespace,
'page_title ' . $dbr->buildLike( "$message/", $dbr->anyString() ),
] )
->caller( __METHOD__ )
->orderBy( 'page_title' )
->fetchFieldValues();
if ( !$titles ) {
$this->getOutput()->addWikiMsg(
'translate-translations-no-message',
$title->getPrefixedText()
);
return;
} else {
$this->getOutput()->addWikiMsg(
'translate-translations-count',
Message::numParam( count( $titles ) )
);
}
$pageInfo = Utilities::getContents( $titles, $namespace );
$rows = [
Html::rawElement(
'tr',
[],
Html::element( 'th', [], $this->msg( 'allmessagesname' )->text() ) .
Html::element( 'th', [], $this->msg( 'allmessagescurrent' )->text() )
),
];
$historyText = "\u{00A0}<sup>" .
$this->msg( 'translate-translations-history-short' )->escaped() .
"</sup>\u{00A0}";
$separator = $this->msg( 'word-separator' )->plain();
foreach ( $titles as $key ) {
$tTitle = Title::makeTitle( $namespace, $key );
$tHandle = new MessageHandle( $tTitle );
$code = $tHandle->getCode();
$text = Utilities::getLanguageName( $code, $this->getLanguage()->getCode() );
$text .= $separator;
$text .= $this->msg( 'parentheses' )->params( $code )->plain();
$tools = [
'edit' => Html::element(
'a',
[ 'href' => Utilities::getEditorUrl( $tHandle ) ],
$text
),
'history' => $this->getLinkRenderer()->makeLink(
$tTitle,
new HtmlArmor( $historyText ),
[
'title' => $this->msg( 'history-title', $tTitle->getPrefixedDBkey() )->text()
],
[ 'action' => 'history' ]
),
];
$class = '';
if ( MessageHandle::hasFuzzyString( $pageInfo[$key][0] ) || $tHandle->isFuzzy() ) {
$class = 'mw-sp-translate-fuzzy';
}
$languageAttributes = [];
if ( $this->languageNameUtils->isKnownLanguageTag( $code ) ) {
$language = $tHandle->getEffectiveLanguage();
$languageAttributes = [
'lang' => $language->getHtmlCode(),
'dir' => $language->getDir(),
];
}
$formattedContent = Utilities::convertWhiteSpaceToHTML( $pageInfo[$key][0] );
$rows[] = Html::rawElement(
'tr',
[ 'class' => $class ],
Html::rawElement( 'td', [], $tools['history'] . $tools['edit'] ) .
Html::rawElement( 'td', $languageAttributes, $formattedContent )
);
}
$out = Html::rawElement(
'table',
[ 'class' => 'mw-sp-translate-table sortable wikitable' ],
"\n" . implode( "\n", $rows ) . "\n"
);
$this->getOutput()->addHTML( $out );
}
}