11use MediaWiki\MediaWikiServices;
12use MediaWiki\Revision\RevisionRecord;
13use MediaWiki\Revision\SlotRecord;
27 public static function title( $message, $code, $ns = NS_MEDIAWIKI ) {
30 $key = $ns .
':' . $message;
32 if ( !isset( $cache[$key] ) ) {
33 $cache[$key] = Title::capitalize( $message, $ns );
37 return $cache[$key] .
'/' . $code;
50 $pos = strrpos( $text,
'/' );
51 $code = substr( $text, $pos + 1 );
52 $key = substr( $text, 0, $pos );
54 return [ $key, $code ];
65 $title = self::title( $key, $language, $namespace );
66 $data = self::getContents( [ $title ], $namespace );
68 return $data[$title][0] ??
null;
80 $dbr = wfGetDB( DB_REPLICA );
81 $revStore = MediaWikiServices::getInstance()->getRevisionStore();
84 $query = $revStore->getQueryInfo( [
'page',
'user' ] );
89 'page_namespace' => $namespace,
90 'page_title' => $titles,
98 $revisions = $revStore->newRevisionsFromBatch( $rows, [
103 foreach ( $rows as $row ) {
105 $rev = $revisions[$row->rev_id];
108 $content = $rev->getContent( SlotRecord::MAIN );
110 $titleContents[$row->page_title] = [
120 return $titleContents;
130 $store = MediaWikiServices::getInstance()->getRevisionStore();
131 $revision = $store->getRevisionByTitle( $title );
133 if ( $revision ===
null ) {
137 $content = $revision->getContent( SlotRecord::MAIN );
138 $wiki = ( $content instanceof TextContent ) ? $content->getText() :
null;
141 if ( $wiki ===
null ) {
147 if ( $handle->isFuzzy() ) {
148 $wiki = TRANSLATE_FUZZY . str_replace( TRANSLATE_FUZZY,
'', $wiki );
165 $hours = 24, $bots =
false, $ns =
null, array $extraFields = []
167 global $wgTranslateMessageNamespaces;
169 $dbr = wfGetDB( DB_REPLICA );
171 $hours = (int)$hours;
172 $cutoff_unixtime = time() - ( $hours * 3600 );
173 $cutoff = $dbr->timestamp( $cutoff_unixtime );
176 'rc_timestamp >= ' . $dbr->addQuotes( $cutoff ),
177 'rc_namespace' => $ns ?: $wgTranslateMessageNamespaces,
180 $conds[
'rc_bot'] = 0;
184 [
'recentchanges',
'actor' ],
186 'rc_namespace',
'rc_title',
'rc_timestamp',
187 'rc_user_text' =>
'actor_name',
192 [
'actor' => [
'JOIN',
'actor_id=rc_actor' ] ]
194 $rows = iterator_to_array( $res );
197 foreach ( $rows as &$row ) {
198 $pos = strrpos( $row->rc_title,
'/' );
199 $row->lang = $pos ===
false ? $row->rc_title : substr( $row->rc_title, $pos + 1 );
203 usort( $rows,
static function ( $a, $b ) {
204 $x = strcmp( $a->lang, $b->lang );
208 wfTimestamp( TS_MW, $b->rc_timestamp ),
209 wfTimestamp( TS_MW, $a->rc_timestamp )
227 $languages = self::getLanguageNames( $language );
228 return $languages[$code] ?? $code;
238 $selector = self::getLanguageSelector( $language );
239 $selector->setDefault( $selectedId );
240 $selector->setAttribute(
'id',
'language' );
241 $selector->setAttribute(
'name',
'language' );
243 return $selector->getHTML();
253 $languages = self::getLanguageNames( $language );
256 $selector =
new XmlSelect();
257 if ( $labelOption !==
false ) {
258 $selector->addOption( $labelOption,
'-' );
261 foreach ( $languages as $code => $name ) {
262 $selector->addOption(
"$code - $name", $code );
276 $languageNames = MediaWikiServices::getInstance()->getLanguageNameUtils()->getLanguageNames( $code );
278 $deprecatedCodes = LanguageCode::getDeprecatedCodeMapping();
279 foreach ( array_keys( $deprecatedCodes ) as $deprecatedCode ) {
280 unset( $languageNames[ $deprecatedCode ] );
283 Hooks::run(
'TranslateSupportedLanguages', [ &$languageNames, $code ] );
285 return $languageNames;
295 $groups = self::messageKeyToGroups( $namespace, $key );
297 return count( $groups ) ? $groups[0] :
null;
307 $mi = MessageIndex::singleton()->retrieve();
308 $normkey = self::normaliseKey( $namespace, $key );
310 if ( isset( $mi[$normkey] ) ) {
311 return (array)$mi[$normkey];
324 $key = lcfirst( $key );
326 return strtr(
"$namespace:$key",
' ',
'_' );
336 public static function fieldset( $legend, $contents, array $attributes = [] ) {
337 return Xml::openElement(
'fieldset', $attributes ) .
338 Xml::tags(
'legend',
null, $legend ) . $contents .
339 Xml::closeElement(
'fieldset' );
354 $msg = htmlspecialchars( $message );
355 $msg = preg_replace(
'/^ /m',
' ', $msg );
356 $msg = preg_replace(
'/ $/m',
' ', $msg );
357 $msg = preg_replace(
'/ /',
'  ', $msg );
358 $msg = str_replace(
"\n",
'<br />', $msg );
369 global $wgExtensionAssetsPath;
370 return "$wgExtensionAssetsPath/Translate/$path";
380 global $wgTranslateCacheDirectory, $wgCacheDirectory;
382 if ( $wgTranslateCacheDirectory !==
false ) {
383 $dir = $wgTranslateCacheDirectory;
384 } elseif ( $wgCacheDirectory !==
false ) {
385 $dir = $wgCacheDirectory;
387 throw new MWException(
"\$wgCacheDirectory must be configured" );
390 return "$dir/$filename";
401 return "\x7fUNIQ" . dechex( mt_rand( 0, 0x7fffffff ) ) .
402 dechex( mt_rand( 0, 0x7fffffff ) ) .
'-' . $i++;
414 if ( substr( $icon, 0, 7 ) !==
'wiki://' ) {
420 $filename = substr( $icon, 7 );
421 $file = MediaWikiServices::getInstance()->getRepoGroup()->findFile( $filename );
423 wfWarn(
"Unknown message group icon file $icon" );
428 if ( $file->isVectorized() ) {
429 $formats[
'vector'] = $file->getFullUrl();
432 $formats[
'raster'] = $file->createThumb( $size, $size );
444 $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
445 $index = self::shouldReadFromPrimary() ? DB_PRIMARY : DB_REPLICA;
447 return $lb->getConnectionRef( $index );
456 $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
459 if ( PageTranslationHooks::$renderingContext ) {
463 return PHP_SAPI ===
'cli' ||
464 RequestContext::getMain()->getRequest()->wasPosted() ||
465 $lb->hasOrMadeRecentPrimaryChanges();
476 return $handle->
getTitle()->getLocalURL( [
'action' =>
'edit' ] );
479 $title = MediaWikiServices::getInstance()
480 ->getSpecialPageFactory()->getPage(
'Translate' )->getPageTitle();
481 return $title->getFullURL( [
483 'group' => $handle->
getGroup()->getId(),
484 'language' => $handle->
getCode(),
494 return serialize( $value );
503 public static function deserialize( $str, $opts = [
'allowed_classes' =>
false ] ) {
504 return unserialize( $str, $opts );
513 static $version = null;
514 if ( $version ===
null ) {
515 $version = json_decode( file_get_contents( __DIR__ .
'/extension.json' ) )->version;
528 $mwInstance = MediaWikiServices::getInstance();
529 $namespaceInfo = $mwInstance->getNamespaceInfo();
530 return $namespaceInfo->hasSubpages( $title->getNamespace() );
543 $all = self::getLanguageNames( null );
544 return isset( $all[ $code ] );
547 public static function getTextFromTextContent( ?Content $content ): string {
549 throw new UnexpectedValueException(
'Expected $content to be TextContent, got null instead.' );
552 if ( $content instanceof TextContent ) {
553 return $content->getText();
556 throw new UnexpectedValueException(
'Expected $content to be TextContent, but got ' . get_class( $content ) );
567 $namespace = $handle->getTitle()->getNamespace();
568 $base = $handle->
getKey();
570 $dbr = MediaWikiServices::getInstance()
571 ->getDBLoadBalancer()
572 ->getConnection( DB_REPLICA );
574 $titles = $dbr->newSelectQueryBuilder()
575 ->select(
'page_title' )
578 'page_namespace' => $namespace,
579 'page_title ' . $dbr->buildLike(
"$base/", $dbr->anyString() ),
581 ->caller( __METHOD__ )
582 ->orderBy(
'page_title' )
583 ->fetchFieldValues();
585 if ( $titles === [] ) {
589 $pageInfo = self::getContents( $titles, $namespace );
Hooks for page translation.
Class for pointing to messages, like Title class is for titles.
getGroup()
Get the primary MessageGroup this message belongs to.
isValid()
Checks if the handle corresponds to a known message.
getTitle()
Get the original title.
getCode()
Returns the language code.
getInternalKey()
This returns the key that can be used for showMessage parameter for Special:Translate for regular mes...
getKey()
Returns the identified or guessed message key.
Essentially random collection of helper functions, similar to GlobalFunctions.php.
static messageKeyToGroup( $namespace, $key)
Returns the primary group message belongs to.
static serialize( $value)
Serialize the given value.
static getSafeReadDB()
Get a DB handle suitable for read and read-for-write cases.
static getMessageContent( $key, $language, $namespace=NS_MEDIAWIKI)
Loads page content without side effects.
static shouldReadFromPrimary()
Check whether primary should be used for reads to avoid reading stale data.
static getLanguageNames( $code)
Get translated language names for the languages generally supported for translation in the current wi...
static getContents( $titles, $namespace)
Fetches contents for pagenames in given namespace without side effects.
static getPlaceholder()
Returns a random string that can be used as placeholder in strings.
static isSupportedLanguageCode(string $code)
Checks whether a language code is supported for translation at the wiki level.
static languageSelector( $language, $selectedId)
Returns a language selector.
static getLanguageName( $code, $language='en')
Returns a localised language name.
static translationChanges( $hours=24, $bots=false, $ns=null, array $extraFields=[])
Fetches recent changes for titles in given namespaces.
static cacheFile( $filename)
Gets the path for cache files.
static getContentForTitle(Title $title, $addFuzzy=false)
Returns the content for a given title and adds the fuzzy tag if requested.
static convertWhiteSpaceToHTML( $message)
Escapes the message, and does some mangling to whitespace, so that it is preserved when outputted as-...
static getLanguageSelector( $language, $labelOption=false)
Standard language selector in Translate extension.
static title( $message, $code, $ns=NS_MEDIAWIKI)
Does quick normalisation of message name so that in can be looked from the database.
static fieldset( $legend, $contents, array $attributes=[])
Constructs a fieldset with contents.
static getIcon(MessageGroup $g, $size)
Get URLs for icons if available.
static allowsSubpages(Title $title)
Checks if the namespace that the title belongs to allows subpages.
static getEditorUrl(MessageHandle $handle)
Get an URL that points to an editor for this message handle.
static messageKeyToGroups( $namespace, $key)
Returns the all the groups message belongs to.
static normaliseKey( $namespace, $key)
Converts page name and namespace to message index format.
static deserialize( $str, $opts=[ 'allowed_classes'=> false])
Deserialize the given string.
static getTranslations(MessageHandle $handle)
Returns all translations of a given message.
static assetPath( $path)
Construct the web address to given asset.
static figureMessage( $text)
Splits page name into message key and language code.
Interface for message groups.
getIcon()
Returns an icon for this message group if any.