Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
TranslatablePage.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\PageTranslation;
5
6use LogicException;
12use MediaWiki\Languages\LanguageNameUtils;
13use MediaWiki\Linker\LinkTarget;
14use MediaWiki\MediaWikiServices;
15use MediaWiki\Page\PageIdentity;
16use MediaWiki\Page\PageReference;
17use MediaWiki\Revision\RevisionLookup;
18use MediaWiki\Revision\RevisionRecord;
19use MediaWiki\Revision\SlotRecord;
22use RuntimeException;
23use SpecialPage;
24use TextContent;
25use Title;
27use Wikimedia\Rdbms\Database;
28use Wikimedia\Rdbms\IResultWrapper;
30
42 public const METADATA_KEYS = [
43 'maxid',
44 'priorityforce',
45 'prioritylangs',
46 'priorityreason',
47 'transclusion',
48 'version'
49 ];
51 public const DISPLAY_TITLE_UNIT_ID = 'Page display title';
52
53 protected PageIdentity $title;
55 protected $revTagStore;
57 protected $text;
59 protected $revision;
61 protected $source;
63 protected $pageDisplayTitle;
65 private $targetLanguage;
66
67 protected function __construct( PageIdentity $title ) {
68 $this->title = $title;
69 $this->revTagStore = Services::getInstance()->getRevTagStore();
70 }
71
77 public static function newFromText( Title $title, string $text ): self {
78 $obj = new self( $title );
79 $obj->text = $text;
80 $obj->source = 'text';
81
82 return $obj;
83 }
84
90 public static function newFromRevision( PageIdentity $title, int $revision ): self {
91 $rev = MediaWikiServices::getInstance()
92 ->getRevisionLookup()
93 ->getRevisionByTitle( $title, $revision );
94 if ( $rev === null ) {
95 throw new RuntimeException( 'Revision is null' );
96 }
97
98 $obj = new self( $title );
99 $obj->source = 'revision';
100 $obj->revision = $revision;
101
102 return $obj;
103 }
104
109 public static function newFromTitle( PageIdentity $title ): self {
110 $obj = new self( $title );
111 $obj->source = 'title';
112
113 return $obj;
114 }
115
117 public function getTitle(): Title {
118 return Title::newFromPageIdentity( $this->title );
119 }
120
121 public function getPageIdentity(): PageIdentity {
122 return $this->title;
123 }
124
126 public function getText(): string {
127 if ( $this->text !== null ) {
128 return $this->text;
129 }
130
131 if ( $this->source === 'title' ) {
132 $revision = $this->getMarkedTag();
133 if ( !is_int( $revision ) ) {
134 throw new LogicException(
135 "Trying to load a text for {$this->getPageIdentity()} which is not marked for translation"
136 );
137 }
138 $this->revision = $revision;
139 }
140
141 $flags = Utilities::shouldReadFromPrimary()
142 ? RevisionLookup::READ_LATEST
143 : RevisionLookup::READ_NORMAL;
144 $rev = MediaWikiServices::getInstance()
145 ->getRevisionLookup()
146 ->getRevisionByTitle( $this->getPageIdentity(), $this->revision, $flags );
147 $content = $rev->getContent( SlotRecord::MAIN );
148 $text = ( $content instanceof TextContent ) ? $content->getText() : null;
149
150 if ( !is_string( $text ) ) {
151 throw new RuntimeException( "Failed to load text for {$this->getPageIdentity()}" );
152 }
153
154 $this->text = $text;
155
156 return $this->text;
157 }
158
163 public function getRevision(): ?int {
164 return $this->revision;
165 }
166
172 public function getSourceLanguageCode(): string {
173 return $this->getTitle()->getPageLanguage()->getCode();
174 }
175
177 public function getMessageGroupId(): string {
178 return self::getMessageGroupIdFromTitle( $this->getPageIdentity() );
179 }
180
182 public static function getMessageGroupIdFromTitle( PageReference $page ): string {
183 return 'page-' . MediaWikiServices::getInstance()->getTitleFormatter()->getPrefixedText( $page );
184 }
185
191 $groupId = $this->getMessageGroupId();
192 $group = MessageGroups::getGroup( $groupId );
193 if ( !$group || $group instanceof WikiPageMessageGroup ) {
194 return $group;
195 }
196
197 throw new RuntimeException(
198 "Expected $groupId to be of type WikiPageMessageGroup; got " .
199 get_class( $group )
200 );
201 }
202
204 public function hasPageDisplayTitle(): bool {
205 // Cached value
206 if ( $this->pageDisplayTitle !== null ) {
207 return $this->pageDisplayTitle;
208 }
209
210 // Check if title section exists in list of sections
211 $factory = Services::getInstance()->getTranslationUnitStoreFactory();
212 $store = $factory->getReader( $this->getPageIdentity() );
213 $this->pageDisplayTitle = in_array( self::DISPLAY_TITLE_UNIT_ID, $store->getNames() );
214
215 return $this->pageDisplayTitle;
216 }
217
219 public function getPageDisplayTitle( string $languageCode ): ?string {
220 // Return null if title not marked for translation
221 if ( !$this->hasPageDisplayTitle() ) {
222 return null;
223 }
224
225 // Display title from DB
226 $section = str_replace( ' ', '_', self::DISPLAY_TITLE_UNIT_ID );
227 $page = MediaWikiServices::getInstance()->getTitleFormatter()->getPrefixedDBkey( $this->getPageIdentity() );
228
229 try {
230 $group = $this->getMessageGroup();
231 } catch ( RuntimeException $e ) {
232 return null;
233 }
234
235 // Sanity check, seems to happen during moves
236 if ( !$group ) {
237 return null;
238 }
239
240 return $group->getMessage( "$page/$section", $languageCode, $group::READ_NORMAL );
241 }
242
243 public function getStrippedSourcePageText(): string {
244 $parser = Services::getInstance()->getTranslatablePageParser();
245 $text = $parser->cleanupTags( $this->getText() );
246 $text = preg_replace( '~<languages\s*/>\n?~s', '', $text );
247
248 return $text;
249 }
250
251 public static function getTranslationPageFromTitle( Title $title ): ?TranslationPage {
252 $self = self::isTranslationPage( $title );
253 return $self ? $self->getTranslationPage( $self->targetLanguage ) : null;
254 }
255
256 public function getTranslationPage( string $targetLanguage ): TranslationPage {
257 $mwServices = MediaWikiServices::getInstance();
258 $config = $mwServices->getMainConfig();
259 $parser = Services::getInstance()->getTranslatablePageParser();
260 $parserOutput = $parser->parse( $this->getText() );
261 $pageVersion = (int)TranslateMetadata::get( $this->getMessageGroupId(), 'version' );
262 $wrapUntranslated = $pageVersion >= 2;
263 $languageFactory = $mwServices->getLanguageFactory();
264
265 return new TranslationPage(
266 $parserOutput,
267 $this->getMessageGroup(),
268 $languageFactory->getLanguage( $targetLanguage ),
269 $languageFactory->getLanguage( $this->getSourceLanguageCode() ),
270 $config->get( 'TranslateKeepOutdatedTranslations' ),
271 $wrapUntranslated,
272 $this->getTitle()
273 );
274 }
275
277 public function addMarkedTag( int $revision, array $value = null ) {
278 $this->revTagStore->replaceTag( $this->getPageIdentity(), RevTagStore::TP_MARK_TAG, $revision, $value );
279 self::clearSourcePageCache();
280 }
281
283 public function addReadyTag( int $revision ): void {
284 $this->revTagStore->replaceTag( $this->getPageIdentity(), RevTagStore::TP_READY_TAG, $revision );
285 if ( !self::isSourcePage( $this->getPageIdentity() ) ) {
286 self::clearSourcePageCache();
287 }
288 }
289
291 public function getMarkedTag(): ?int {
292 return $this->revTagStore->getLatestRevisionWithTag( $this->getPageIdentity(), RevTagStore::TP_MARK_TAG );
293 }
294
296 public function getReadyTag(): ?int {
297 return $this->revTagStore->getLatestRevisionWithTag( $this->getPageIdentity(), RevTagStore::TP_READY_TAG );
298 }
299
304 public function unmarkTranslatablePage(): void {
305 $tpPageStore = Services::getInstance()->getTranslatablePageStore();
306 $tpPageStore->unmark( $this->getPageIdentity() );
307 }
308
314 public function getTranslationUrl( $code = false ): string {
315 $params = [
316 'group' => $this->getMessageGroupId(),
317 'action' => 'page',
318 'filter' => '',
319 'language' => $code,
320 ];
321
322 $translate = SpecialPage::getTitleFor( 'Translate' );
323
324 return $translate->getLocalURL( $params );
325 }
326
327 public function getMarkedRevs(): IResultWrapper {
328 $db = Utilities::getSafeReadDB();
329
330 $fields = [ 'rt_revision', 'rt_value' ];
331 $conds = [
332 'rt_page' => $this->getPageIdentity()->getId(),
333 'rt_type' => RevTagStore::TP_MARK_TAG,
334 ];
335 $options = [ 'ORDER BY' => 'rt_revision DESC' ];
336
337 return $db->select( 'revtag', $fields, $conds, __METHOD__, $options );
338 }
339
341 public function getTranslationPages(): array {
342 $mwServices = MediaWikiServices::getInstance();
343
344 $messageGroup = $this->getMessageGroup();
345 $knownLanguageCodes = $messageGroup ? $messageGroup->getTranslatableLanguages() : null;
346 $knownLanguageCodes ??= Utilities::getLanguageNames( LanguageNameUtils::AUTONYMS );
347
348 $prefixedDbTitleKey = $this->getPageIdentity()->getDBkey() . '/';
349 $baseNamespace = $this->getPageIdentity()->getNamespace();
350
351 // Build a link batch query for all translation pages
352 $linkBatch = $mwServices->getLinkBatchFactory()->newLinkBatch();
353 foreach ( array_keys( $knownLanguageCodes ) as $code ) {
354 $linkBatch->add( $baseNamespace, $prefixedDbTitleKey . $code );
355 }
356
357 $translationPages = [];
358 foreach ( $linkBatch->getPageIdentities() as $pageIdentity ) {
359 if ( $pageIdentity->exists() ) {
360 $translationPages[] = Title::castFromPageIdentity( $pageIdentity );
361 }
362 }
363
364 return $translationPages;
365 }
366
368 public function getTranslationUnitPages( ?string $code = null ): array {
369 return $this->getTranslationUnitPagesByTitle( $this->title, $code );
370 }
371
372 public function getTranslationPercentages(): array {
373 // Calculate percentages for the available translations
374 try {
375 $group = $this->getMessageGroup();
376 } catch ( RuntimeException $e ) {
377 return [];
378 }
379
380 if ( !$group ) {
381 return [];
382 }
383
384 $titles = $this->getTranslationPages();
385 $temp = MessageGroupStats::forGroup( $this->getMessageGroupId() );
386 $stats = [];
387
388 foreach ( $titles as $t ) {
389 $handle = new MessageHandle( $t );
390 $code = $handle->getCode();
391
392 // Sometimes we want to display 0.00 for pages for which translation
393 // hasn't started yet.
394 $stats[$code] = 0.00;
395 if ( ( $temp[$code][MessageGroupStats::TOTAL] ?? 0 ) > 0 ) {
396 $total = $temp[$code][MessageGroupStats::TOTAL];
397 $translated = $temp[$code][MessageGroupStats::TRANSLATED];
398 $percentage = $translated / $total;
399 $stats[$code] = sprintf( '%.2f', $percentage );
400 }
401 }
402
403 // Content language is always up-to-date
404 $stats[$this->getSourceLanguageCode()] = 1.00;
405
406 return $stats;
407 }
408
409 public function getTransRev( string $suffix ) {
410 $title = Title::makeTitle( NS_TRANSLATIONS, $suffix );
411
412 $db = Utilities::getSafeReadDB();
413 $fields = 'rt_value';
414 $conds = [
415 'rt_page' => $title->getArticleID(),
416 'rt_type' => RevTagStore::TRANSVER_PROP,
417 ];
418 $options = [ 'ORDER BY' => 'rt_revision DESC' ];
419
420 return $db->selectField( 'revtag', $fields, $conds, __METHOD__, $options );
421 }
422
423 public function supportsTransclusion(): ?bool {
424 $transclusion = TranslateMetadata::get( $this->getMessageGroupId(), 'transclusion' );
425 if ( $transclusion === false ) {
426 return null;
427 }
428
429 return $transclusion === '1';
430 }
431
432 public function setTransclusion( bool $supportsTransclusion ): void {
434 $this->getMessageGroupId(),
435 'transclusion',
436 $supportsTransclusion ? '1' : '0'
437 );
438 }
439
440 public function getRevisionRecordWithFallback(): ?RevisionRecord {
441 $title = $this->getTitle();
442 $store = MediaWikiServices::getInstance()->getRevisionStore();
443 $revRecord = $store->getRevisionByTitle( $title->getSubpage( $this->targetLanguage ) );
444 if ( $revRecord ) {
445 return $revRecord;
446 }
447
448 // Fetch the source fallback
449 return $store->getRevisionByTitle( $title->getSubpage( $this->getSourceLanguageCode() ) );
450 }
451
453 public function isMoveable(): bool {
454 return $this->getMarkedTag() !== null;
455 }
456
458 public function isDeletable(): bool {
459 return $this->getMarkedTag() !== null;
460 }
461
463 public static function isTranslationPage( Title $title ) {
464 $handle = new MessageHandle( $title );
465 if ( !Utilities::isTranslationPage( $handle ) ) {
466 return false;
467 }
468
469 $languageCode = $handle->getCode();
470 $newTitle = $handle->getTitleForBase();
471
472 if ( !$newTitle ) {
473 return false;
474 }
475
476 $page = self::newFromTitle( $newTitle );
477
478 if ( $page->getMarkedTag() === null ) {
479 return false;
480 }
481
482 $page->targetLanguage = $languageCode;
483
484 return $page;
485 }
486
488 public static function parseTranslationUnit( LinkTarget $translationUnit ): array {
489 // Format is Translations:SourcePageNamespace:SourcePageName/SectionName/LanguageCode.
490 // We will drop the namespace immediately here.
491 $parts = explode( '/', $translationUnit->getText() );
492
493 // LanguageCode and SectionName are guaranteed to not have '/'.
494 $language = array_pop( $parts );
495 $section = array_pop( $parts );
496 $sourcepage = implode( '/', $parts );
497
498 return [
499 'sourcepage' => $sourcepage,
500 'section' => $section,
501 'language' => $language
502 ];
503 }
504
505 public static function isSourcePage( PageIdentity $page ): bool {
506 if ( !$page->exists() ) {
507 // No point in loading all translatable pages if the page
508 // doesn’t exist. This also avoids PreconditionExceptions
509 // if $page is a Title pointing to a non-proper page like
510 // a special page.
511 return false;
512 }
513
514 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
515 $cacheKey = $cache->makeKey( 'pagetranslation', 'sourcepages' );
516
517 $translatablePageIds = $cache->getWithSetCallback(
518 $cacheKey,
519 $cache::TTL_HOUR * 2,
520 static function ( $oldValue, &$ttl, array &$setOpts ) {
521 $dbr = MediaWikiServices::getInstance()->getDBLoadBalancer()->getConnection( DB_REPLICA );
522 $setOpts += Database::getCacheSetOptions( $dbr );
523
524 return RevTagStore::getTranslatableBundleIds(
525 RevTagStore::TP_MARK_TAG, RevTagStore::TP_READY_TAG
526 );
527 },
528 [
529 'checkKeys' => [ $cacheKey ],
530 'pcTTL' => $cache::TTL_PROC_SHORT,
531 'pcGroup' => __CLASS__ . ':1',
532 'version' => 2,
533 ]
534 );
535
536 return isset( $translatablePageIds[$page->getId()] );
537 }
538
540 public static function clearSourcePageCache(): void {
541 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
542 $cache->touchCheckKey( $cache->makeKey( 'pagetranslation', 'sourcepages' ) );
543 }
544
545 public static function determineStatus(
546 ?int $readyRevisionId,
547 ?int $markRevisionId,
548 int $latestRevisionId
550 $status = null;
551 if ( $markRevisionId === null ) {
552 // Never marked, check that the latest version is ready
553 if ( $readyRevisionId === $latestRevisionId ) {
554 $status = TranslatablePageStatus::PROPOSED;
555 } else {
556 // Otherwise, ignore such pages
557 return null;
558 }
559 } elseif ( $readyRevisionId === $latestRevisionId ) {
560 if ( $markRevisionId === $readyRevisionId ) {
561 // Marked and latest version is fine
562 $status = TranslatablePageStatus::ACTIVE;
563 } else {
564 $status = TranslatablePageStatus::OUTDATED;
565 }
566 } else {
567 // Marked but latest version is not fine
568 $status = TranslatablePageStatus::BROKEN;
569 }
570
571 return new TranslatablePageStatus( $status );
572 }
573}
574
575class_alias( TranslatablePage::class, 'TranslatablePage' );
return[ 'Translate:ConfigHelper'=> static function():ConfigHelper { return new ConfigHelper();}, 'Translate:CsvTranslationImporter'=> static function(MediaWikiServices $services):CsvTranslationImporter { return new CsvTranslationImporter( $services->getWikiPageFactory());}, 'Translate:EntitySearch'=> static function(MediaWikiServices $services):EntitySearch { return new EntitySearch($services->getMainWANObjectCache(), $services->getCollationFactory() ->makeCollation( 'uca-default-u-kn'), MessageGroups::singleton(), $services->getNamespaceInfo(), $services->get( 'Translate:MessageIndex'), $services->getTitleParser(), $services->getTitleFormatter());}, 'Translate:ExternalMessageSourceStateImporter'=> static function(MediaWikiServices $services):ExternalMessageSourceStateImporter { return new ExternalMessageSourceStateImporter($services->getMainConfig(), $services->get( 'Translate:GroupSynchronizationCache'), $services->getJobQueueGroup(), LoggerFactory::getInstance( 'Translate.GroupSynchronization'), $services->get( 'Translate:MessageIndex'));}, 'Translate:FileFormatFactory'=> static function(MediaWikiServices $services):FileFormatFactory { return new FileFormatFactory( $services->getObjectFactory());}, 'Translate:GroupSynchronizationCache'=> static function(MediaWikiServices $services):GroupSynchronizationCache { return new GroupSynchronizationCache( $services->get( 'Translate:PersistentCache'));}, 'Translate:HookRunner'=> static function(MediaWikiServices $services):HookRunner { return new HookRunner( $services->getHookContainer());}, 'Translate:MessageBundleStore'=> static function(MediaWikiServices $services):MessageBundleStore { return new MessageBundleStore($services->get( 'Translate:RevTagStore'), $services->getJobQueueGroup(), $services->getLanguageNameUtils(), $services->get( 'Translate:MessageIndex'));}, 'Translate:MessageGroupReviewStore'=> static function(MediaWikiServices $services):MessageGroupReviewStore { return new MessageGroupReviewStore($services->getDBLoadBalancer(), $services->get( 'Translate:HookRunner'));}, 'Translate:MessageGroupStatsTableFactory'=> static function(MediaWikiServices $services):MessageGroupStatsTableFactory { return new MessageGroupStatsTableFactory($services->get( 'Translate:ProgressStatsTableFactory'), $services->getDBLoadBalancer(), $services->getLinkRenderer(), $services->get( 'Translate:MessageGroupReviewStore'), $services->getMainConfig() ->get( 'TranslateWorkflowStates') !==false);}, 'Translate:MessageIndex'=> static function(MediaWikiServices $services):MessageIndex { $params=$services->getMainConfig() ->get( 'TranslateMessageIndex');if(is_string( $params)) { $params=(array) $params;} $class=array_shift( $params);return new $class( $params);}, 'Translate:MessagePrefixStats'=> static function(MediaWikiServices $services):MessagePrefixStats { return new MessagePrefixStats( $services->getTitleParser());}, 'Translate:ParsingPlaceholderFactory'=> static function():ParsingPlaceholderFactory { return new ParsingPlaceholderFactory();}, 'Translate:PersistentCache'=> static function(MediaWikiServices $services):PersistentCache { return new PersistentDatabaseCache($services->getDBLoadBalancer(), $services->getJsonCodec());}, 'Translate:ProgressStatsTableFactory'=> static function(MediaWikiServices $services):ProgressStatsTableFactory { return new ProgressStatsTableFactory($services->getLinkRenderer(), $services->get( 'Translate:ConfigHelper'));}, 'Translate:RevTagStore'=> static function(MediaWikiServices $services):RevTagStore { return new RevTagStore($services->getDBLoadBalancerFactory());}, 'Translate:SubpageListBuilder'=> static function(MediaWikiServices $services):SubpageListBuilder { return new SubpageListBuilder($services->get( 'Translate:TranslatableBundleFactory'), $services->getLinkBatchFactory());}, 'Translate:TranslatableBundleExporter'=> static function(MediaWikiServices $services):TranslatableBundleExporter { return new TranslatableBundleExporter($services->get( 'Translate:SubpageListBuilder'), $services->getWikiExporterFactory(), $services->getDBLoadBalancer());}, 'Translate:TranslatableBundleFactory'=> static function(MediaWikiServices $services):TranslatableBundleFactory { return new TranslatableBundleFactory($services->get( 'Translate:TranslatablePageStore'), $services->get( 'Translate:MessageBundleStore'));}, 'Translate:TranslatableBundleImporter'=> static function(MediaWikiServices $services):TranslatableBundleImporter { return new TranslatableBundleImporter($services->getWikiImporterFactory(), $services->get( 'Translate:TranslatablePageParser'), $services->getRevisionLookup());}, 'Translate:TranslatableBundleMover'=> static function(MediaWikiServices $services):TranslatableBundleMover { return new TranslatableBundleMover($services->getMovePageFactory(), $services->getJobQueueGroup(), $services->getLinkBatchFactory(), $services->get( 'Translate:TranslatableBundleFactory'), $services->get( 'Translate:SubpageListBuilder'), $services->getMainConfig() ->get( 'TranslatePageMoveLimit'));}, 'Translate:TranslatableBundleStatusStore'=> static function(MediaWikiServices $services):TranslatableBundleStatusStore { return new TranslatableBundleStatusStore($services->getDBLoadBalancer() ->getConnection(DB_PRIMARY), $services->getCollationFactory() ->makeCollation( 'uca-default-u-kn'), $services->getDBLoadBalancer() ->getMaintenanceConnectionRef(DB_PRIMARY));}, 'Translate:TranslatablePageParser'=> static function(MediaWikiServices $services):TranslatablePageParser { return new TranslatablePageParser($services->get( 'Translate:ParsingPlaceholderFactory'));}, 'Translate:TranslatablePageStore'=> static function(MediaWikiServices $services):TranslatablePageStore { return new TranslatablePageStore($services->get( 'Translate:MessageIndex'), $services->getJobQueueGroup(), $services->get( 'Translate:RevTagStore'), $services->getDBLoadBalancer(), $services->get( 'Translate:TranslatableBundleStatusStore'), $services->get( 'Translate:TranslatablePageParser'),);}, 'Translate:TranslationStashReader'=> static function(MediaWikiServices $services):TranslationStashReader { $db=$services->getDBLoadBalancer() ->getConnection(DB_REPLICA);return new TranslationStashStorage( $db);}, 'Translate:TranslationStatsDataProvider'=> static function(MediaWikiServices $services):TranslationStatsDataProvider { return new TranslationStatsDataProvider(new ServiceOptions(TranslationStatsDataProvider::CONSTRUCTOR_OPTIONS, $services->getMainConfig()), $services->getObjectFactory(), $services->getDBLoadBalancer());}, 'Translate:TranslationUnitStoreFactory'=> static function(MediaWikiServices $services):TranslationUnitStoreFactory { return new TranslationUnitStoreFactory( $services->getDBLoadBalancer());}, 'Translate:TranslatorActivity'=> static function(MediaWikiServices $services):TranslatorActivity { $query=new TranslatorActivityQuery($services->getMainConfig(), $services->getDBLoadBalancer());return new TranslatorActivity($services->getMainObjectStash(), $query, $services->getJobQueueGroup());}, 'Translate:TtmServerFactory'=> static function(MediaWikiServices $services):TtmServerFactory { $config=$services->getMainConfig();$default=$config->get( 'TranslateTranslationDefaultService');if( $default===false) { $default=null;} return new TtmServerFactory( $config->get( 'TranslateTranslationServices'), $default);}]
@phpcs-require-sorted-array
Factory class for accessing message groups individually by id or all of them as a list.
Class to manage revision tags for translatable bundles.
Translatable bundle represents a message group where its translatable content is defined on a wiki pa...
Stores and validates possible statuses for TranslatablePage.
Mixed bag of methods related to translatable pages.
static newFromRevision(PageIdentity $title, int $revision)
Constructs a translatable page from given revision.
addReadyTag(int $revision)
Adds a tag which indicates that this page source is ready for marking for translation.
static newFromTitle(PageIdentity $title)
Constructs a translatable page from title.
getMarkedTag()
Returns the latest revision which has marked tag, if any.
getText()
Returns the text for this translatable page.
hasPageDisplayTitle()
Check whether title is marked for translation.
static getMessageGroupIdFromTitle(PageReference $page)
Constructs MessageGroup id for any title.
getReadyTag()
Returns the latest revision which has ready tag, if any.
addMarkedTag(int $revision, array $value=null)
Adds a tag which indicates that this page is suitable for translation.
getRevision()
Revision is null if object was constructed using newFromText.
getSourceLanguageCode()
Returns the source language of this translatable page.
unmarkTranslatablePage()
Removes all page translation feature data from the database.
getTranslationUrl( $code=false)
Produces a link to translation view of a translation page.
getMessageGroup()
Returns MessageGroup used for translating this page.
const METADATA_KEYS
List of keys in the metadata table that need to be handled for moves and deletions @phpcs-require-sor...
static parseTranslationUnit(LinkTarget $translationUnit)
Helper to guess translation page from translation unit.
static newFromText(Title $title, string $text)
Constructs a translatable page from given text.
getPageDisplayTitle(string $languageCode)
Get translated page title.
Minimal service container.
Definition Services.php:44
Essentially random collection of helper functions, similar to GlobalFunctions.php.
Definition Utilities.php:31
This class abstract MessageGroup statistics calculation and storing.
Class for pointing to messages, like Title class is for titles.
Wraps the translatable page sections into a message group.