Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
MarkForTranslationActionApi.php
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Translate\PageTranslation;
5
6use MediaWiki\Api\ApiBase;
7use MediaWiki\Api\ApiMain;
8use MediaWiki\Context\RequestContext;
10use Wikimedia\ParamValidator\ParamValidator;
11use Wikimedia\Rdbms\IDBAccessObject;
12
19class MarkForTranslationActionApi extends ApiBase {
20
21 public function __construct(
22 ApiMain $mainModule,
23 string $moduleName,
24 private readonly TranslatablePageMarker $translatablePageMarker,
25 private readonly MessageGroupMetadata $messageGroupMetadata,
26 ) {
27 parent::__construct( $mainModule, $moduleName );
28 }
29
30 public function execute() {
31 $this->checkUserRightsAny( 'pagetranslation' );
32
33 $params = $this->extractRequestParams();
34 $title = $this->getTitleFromTitleOrPageId( $params );
35 $revision = $params['revid'] ?? null;
36
37 $translateTitle = $this->getTriState( $params, 'translatetitle' );
38
39 try {
40 $operation = $this->translatablePageMarker->getMarkOperation(
41 $title->toPageRecord( IDBAccessObject::READ_LATEST ),
42 $revision,
43 $translateTitle
44 );
45 } catch ( TranslatablePageMarkException $e ) {
46 $this->addError( $e->getMessageObject() );
47 return;
48 }
49
50 $unitNameValidationResult = $operation->getUnitValidationStatus();
51 if ( !$unitNameValidationResult->isOK() ) {
52 $this->addMessagesFromStatus( $unitNameValidationResult );
53 return;
54 }
55
56 $translateTitle = $operation->titleTranslationState === TranslateTitleEnum::DEFAULT_CHECKED;
57
58 // By default, units are marked nofuzzy if only their tvars have changed
59 $noFuzzyUnits = [];
60 foreach ( $operation->getUnits() as $s ) {
61 if ( $s->type === 'changed' && $s->onlyTvarsChanged() ) {
62 $noFuzzyUnits[] = $s->id;
63 }
64 }
65
66 // Add and subtract nofuzzy flags as specified by the user
67 $noFuzzyUnits = array_unique( array_merge( $noFuzzyUnits, $params['nofuzzyunits'] ?? [] ) );
68 $noFuzzyUnits = array_diff( $noFuzzyUnits, $params['fuzzyunits'] ?? [] );
69
70 $groupId = $operation->getPage()->getMessageGroupId();
71 if ( isset( $params['prioritylanguages'] ) ) {
72 // Set priority languages
73 $priorityLanguages = $params['prioritylanguages'];
74 $priorityLanguageStatus = $this->translatablePageMarker->validatePriorityLanguages( $priorityLanguages );
75 if ( !$priorityLanguageStatus->isOK() ) {
76 $this->addMessagesFromStatus( $priorityLanguageStatus );
77 return;
78 }
79 $forcePriority = $params['forcepriority'] ?? false;
80 $priorityReason = $params['priorityreason'] ?? '';
81 } else {
82 // markForTranslation() sets priority languages unconditionally.
83 // If no changes were requested, we need to load the current values
84 // just to avoid changing it.
85 $blob = (string)$this->messageGroupMetadata->get( $groupId, 'prioritylangs' );
86 $priorityLanguages = $blob !== '' ? explode( ',', $blob ) : [];
87 $forcePriority = $this->messageGroupMetadata->get( $groupId, 'priorityforce' ) === 'on';
88 // If no priority reason is set, set it to an empty string
89 $priorityReason = $this->messageGroupMetadata->get( $groupId, 'priorityreason' );
90 $priorityReason = $priorityReason !== false ? $priorityReason : '';
91 }
92
93 $transclusion = $this->getTriState( $params, 'transclusion' );
94 if ( $transclusion === null ) {
95 $transclusion = $operation->getPage()->supportsTransclusion() ?? $operation->isFirstMark();
96 }
97
98 $translatablePageSettings = new TranslatablePageSettings(
99 $priorityLanguages,
100 $forcePriority,
101 $priorityReason,
102 $noFuzzyUnits,
103 $translateTitle,
104 $params[ 'forcelatestsyntaxversion'] ?? false,
105 $transclusion
106 );
107
108 try {
109 $unitCount = $this->translatablePageMarker->markForTranslation(
110 $operation,
111 $translatablePageSettings,
112 RequestContext::getMain(),
113 $this->getUser()
114 );
115 } catch ( TranslatablePageMarkException $e ) {
116 $this->addError( $e->getMessageObject() );
117 return;
118 }
119 $res = [
120 'result' => 'Success',
121 'firstmark' => $operation->isFirstMark(),
122 'unitcount' => $unitCount,
123 ];
124 $this->getResult()->addValue( null, $this->getModuleName(), $res );
125 }
126
128 private function getTriState( array $params, string $name ): ?bool {
129 return isset( $params[$name] ) ? $params[$name] === 'yes' : null;
130 }
131
133 public function isWriteMode() {
134 return true;
135 }
136
138 public function needsToken() {
139 return 'csrf';
140 }
141
142 protected function getAllowedParams(): array {
143 return [
144 'title' => [
145 ParamValidator::PARAM_TYPE => 'string',
146 ],
147 'pageid' => [
148 ParamValidator::PARAM_TYPE => 'integer',
149 ],
150 'revid' => [
151 ParamValidator::PARAM_TYPE => 'integer',
152 ],
153 'translatetitle' => [
154 ParamValidator::PARAM_TYPE => [ 'yes', 'no' ],
155 ],
156 'prioritylanguages' => [
157 ParamValidator::PARAM_TYPE => 'string',
158 ParamValidator::PARAM_ISMULTI => true,
159 ParamValidator::PARAM_ISMULTI_LIMIT1 => 1000,
160 ParamValidator::PARAM_ISMULTI_LIMIT2 => 1000,
161 ],
162 'forcepriority' => [
163 ParamValidator::PARAM_TYPE => 'boolean',
164 ],
165 'priorityreason' => [
166 ParamValidator::PARAM_TYPE => 'string',
167 ],
168 'nofuzzyunits' => [
169 ParamValidator::PARAM_TYPE => 'string',
170 ParamValidator::PARAM_ISMULTI => true,
171 ParamValidator::PARAM_ISMULTI_LIMIT1 => 1000,
172 ParamValidator::PARAM_ISMULTI_LIMIT2 => 1000,
173 ],
174 'fuzzyunits' => [
175 ParamValidator::PARAM_TYPE => 'string',
176 ParamValidator::PARAM_ISMULTI => true,
177 ParamValidator::PARAM_ISMULTI_LIMIT1 => 1000,
178 ParamValidator::PARAM_ISMULTI_LIMIT2 => 1000,
179 ],
180 'forcelatestsyntaxversion' => [
181 ParamValidator::PARAM_TYPE => 'boolean',
182 ],
183 'transclusion' => [
184 ParamValidator::PARAM_TYPE => [ 'yes', 'no' ],
185 ],
186 ];
187 }
188
189}
return[ 'Translate:AggregateGroupManager'=> static function(MediaWikiServices $services):AggregateGroupManager { return new AggregateGroupManager($services->getTitleFactory(), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:AggregateGroupMessageGroupFactory'=> static function(MediaWikiServices $services):AggregateGroupMessageGroupFactory { return new AggregateGroupMessageGroupFactory($services->get( 'Translate:MessageGroupMetadata'));}, '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:ExternalMessageSourceStateComparator'=> static function(MediaWikiServices $services):ExternalMessageSourceStateComparator { return new ExternalMessageSourceStateComparator(new SimpleStringComparator(), $services->getRevisionLookup(), $services->getPageStore());}, 'Translate:ExternalMessageSourceStateImporter'=> static function(MediaWikiServices $services):ExternalMessageSourceStateImporter { return new ExternalMessageSourceStateImporter($services->get( 'Translate:GroupSynchronizationCache'), $services->getJobQueueGroup(), LoggerFactory::getInstance(LogNames::GROUP_SYNCHRONIZATION), $services->get( 'Translate:MessageIndex'), $services->getTitleFactory(), $services->get( 'Translate:MessageGroupSubscription'), new ServiceOptions(ExternalMessageSourceStateImporter::CONSTRUCTOR_OPTIONS, $services->getMainConfig()));}, 'Translate:FileBasedMessageGroupFactory'=> static function(MediaWikiServices $services):FileBasedMessageGroupFactory { return new FileBasedMessageGroupFactory(new MessageGroupConfigurationParser(), $services->getContentLanguageCode() ->toString(), new ServiceOptions(FileBasedMessageGroupFactory::SERVICE_OPTIONS, $services->getMainConfig()),);}, '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:HookDefinedMessageGroupFactory'=> static function(MediaWikiServices $services):HookDefinedMessageGroupFactory { return new HookDefinedMessageGroupFactory( $services->get( 'Translate:HookRunner'));}, 'Translate:HookRunner'=> static function(MediaWikiServices $services):HookRunner { return new HookRunner( $services->getHookContainer());}, 'Translate:MessageBundleDependencyPurger'=> static function(MediaWikiServices $services):MessageBundleDependencyPurger { return new MessageBundleDependencyPurger( $services->get( 'Translate:TranslatableBundleFactory'));}, 'Translate:MessageBundleMessageGroupFactory'=> static function(MediaWikiServices $services):MessageBundleMessageGroupFactory { return new MessageBundleMessageGroupFactory($services->get( 'Translate:MessageGroupMetadata'), new ServiceOptions(MessageBundleMessageGroupFactory::SERVICE_OPTIONS, $services->getMainConfig()),);}, 'Translate:MessageBundleStore'=> static function(MediaWikiServices $services):MessageBundleStore { return new MessageBundleStore($services->get( 'Translate:RevTagStore'), $services->getJobQueueGroup(), $services->getLanguageNameUtils(), $services->get( 'Translate:MessageIndex'), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:MessageBundleTranslationLoader'=> static function(MediaWikiServices $services):MessageBundleTranslationLoader { return new MessageBundleTranslationLoader( $services->getLanguageFallback());}, 'Translate:MessageGroupMetadata'=> static function(MediaWikiServices $services):MessageGroupMetadata { return new MessageGroupMetadata( $services->getConnectionProvider());}, 'Translate:MessageGroupReviewStore'=> static function(MediaWikiServices $services):MessageGroupReviewStore { return new MessageGroupReviewStore($services->getConnectionProvider(), $services->get( 'Translate:HookRunner'));}, 'Translate:MessageGroupStatsTableFactory'=> static function(MediaWikiServices $services):MessageGroupStatsTableFactory { return new MessageGroupStatsTableFactory($services->get( 'Translate:ProgressStatsTableFactory'), $services->getLinkRenderer(), $services->get( 'Translate:MessageGroupReviewStore'), $services->get( 'Translate:MessageGroupMetadata'), $services->getMainConfig() ->get( 'TranslateWorkflowStates') !==false);}, 'Translate:MessageGroupSubscription'=> static function(MediaWikiServices $services):MessageGroupSubscription { return new MessageGroupSubscription($services->get( 'Translate:MessageGroupSubscriptionStore'), $services->getJobQueueGroup(), $services->getUserIdentityLookup(), LoggerFactory::getInstance(LogNames::GROUP_SUBSCRIPTION), new ServiceOptions(MessageGroupSubscription::CONSTRUCTOR_OPTIONS, $services->getMainConfig()));}, 'Translate:MessageGroupSubscriptionHookHandler'=> static function(MediaWikiServices $services):?MessageGroupSubscriptionHookHandler { if(! $services->getExtensionRegistry() ->isLoaded( 'Echo')) { return null;} return new MessageGroupSubscriptionHookHandler($services->get( 'Translate:MessageGroupSubscription'), $services->getUserFactory());}, 'Translate:MessageGroupSubscriptionStore'=> static function(MediaWikiServices $services):MessageGroupSubscriptionStore { return new MessageGroupSubscriptionStore( $services->getConnectionProvider());}, 'Translate:MessageIndex'=> static function(MediaWikiServices $services):MessageIndex { $params=(array) $services->getMainConfig() ->get( 'TranslateMessageIndex');$class=array_shift( $params);$implementationMap=['HashMessageIndex'=> HashMessageIndex::class, 'CDBMessageIndex'=> CDBMessageIndex::class, 'DatabaseMessageIndex'=> DatabaseMessageIndex::class, 'hash'=> HashMessageIndex::class, 'cdb'=> CDBMessageIndex::class, 'database'=> DatabaseMessageIndex::class,];$messageIndexStoreClass=$implementationMap[$class] ?? $implementationMap['database'];return new MessageIndex(new $messageIndexStoreClass, $services->getMainWANObjectCache(), $services->getJobQueueGroup(), $services->get( 'Translate:HookRunner'), LoggerFactory::getInstance(LogNames::MAIN), $services->getMainObjectStash(), $services->getConnectionProvider(), new ServiceOptions(MessageIndex::SERVICE_OPTIONS, $services->getMainConfig()),);}, '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->getConnectionProvider(), $services->getJsonCodec());}, 'Translate:ProgressStatsTableFactory'=> static function(MediaWikiServices $services):ProgressStatsTableFactory { return new ProgressStatsTableFactory($services->getLinkRenderer(), $services->get( 'Translate:ConfigHelper'), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:RevTagStore'=> static function(MediaWikiServices $services):RevTagStore { return new RevTagStore( $services->getConnectionProvider());}, 'Translate:SubpageListBuilder'=> static function(MediaWikiServices $services):SubpageListBuilder { return new SubpageListBuilder($services->get( 'Translate:TranslatableBundleFactory'), $services->getLinkBatchFactory());}, 'Translate:TranslatableBundleDeleter'=> static function(MediaWikiServices $services):TranslatableBundleDeleter { return new TranslatableBundleDeleter($services->getMainObjectStash(), $services->getJobQueueGroup(), $services->get( 'Translate:SubpageListBuilder'), $services->get( 'Translate:TranslatableBundleFactory'));}, 'Translate:TranslatableBundleExporter'=> static function(MediaWikiServices $services):TranslatableBundleExporter { return new TranslatableBundleExporter($services->get( 'Translate:SubpageListBuilder'), $services->getWikiExporterFactory(), $services->getConnectionProvider());}, '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(), $services->getNamespaceInfo(), $services->getTitleFactory(), $services->getFormatterFactory());}, '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->getConnectionProvider(), $services->getObjectCacheFactory(), $services->getMainConfig() ->get( 'TranslatePageMoveLimit'));}, 'Translate:TranslatableBundleStatusStore'=> static function(MediaWikiServices $services):TranslatableBundleStatusStore { return new TranslatableBundleStatusStore($services->getConnectionProvider() ->getPrimaryDatabase(), $services->getCollationFactory() ->makeCollation( 'uca-default-u-kn'), $services->getDBLoadBalancer() ->getMaintenanceConnectionRef(DB_PRIMARY));}, 'Translate:TranslatablePageMarker'=> static function(MediaWikiServices $services):TranslatablePageMarker { return new TranslatablePageMarker($services->getConnectionProvider(), $services->getJobQueueGroup(), $services->getLinkRenderer(), MessageGroups::singleton(), $services->get( 'Translate:MessageIndex'), $services->getTitleFormatter(), $services->getTitleParser(), $services->get( 'Translate:TranslatablePageParser'), $services->get( 'Translate:TranslatablePageStore'), $services->get( 'Translate:TranslatablePageStateStore'), $services->get( 'Translate:TranslationUnitStoreFactory'), $services->get( 'Translate:MessageGroupMetadata'), $services->getWikiPageFactory(), $services->get( 'Translate:TranslatablePageView'), $services->get( 'Translate:MessageGroupSubscription'), $services->getFormatterFactory(), $services->get( 'Translate:HookRunner'),);}, 'Translate:TranslatablePageMessageGroupFactory'=> static function(MediaWikiServices $services):TranslatablePageMessageGroupFactory { return new TranslatablePageMessageGroupFactory(new ServiceOptions(TranslatablePageMessageGroupFactory::SERVICE_OPTIONS, $services->getMainConfig()),);}, 'Translate:TranslatablePageParser'=> static function(MediaWikiServices $services):TranslatablePageParser { return new TranslatablePageParser($services->get( 'Translate:ParsingPlaceholderFactory'));}, 'Translate:TranslatablePageStateStore'=> static function(MediaWikiServices $services):TranslatablePageStateStore { return new TranslatablePageStateStore($services->get( 'Translate:PersistentCache'), $services->getPageStore());}, 'Translate:TranslatablePageStore'=> static function(MediaWikiServices $services):TranslatablePageStore { return new TranslatablePageStore($services->get( 'Translate:MessageIndex'), $services->getJobQueueGroup(), $services->get( 'Translate:RevTagStore'), $services->getConnectionProvider(), $services->get( 'Translate:TranslatableBundleStatusStore'), $services->get( 'Translate:TranslatablePageParser'), $services->get( 'Translate:MessageGroupMetadata'));}, 'Translate:TranslatablePageView'=> static function(MediaWikiServices $services):TranslatablePageView { return new TranslatablePageView($services->getConnectionProvider(), $services->get( 'Translate:TranslatablePageStateStore'), new ServiceOptions(TranslatablePageView::SERVICE_OPTIONS, $services->getMainConfig()));}, 'Translate:TranslateSandbox'=> static function(MediaWikiServices $services):TranslateSandbox { return new TranslateSandbox($services->getUserFactory(), $services->getConnectionProvider(), $services->getPermissionManager(), $services->getAuthManager(), $services->getUserGroupManager(), $services->getActorStore(), $services->getUserOptionsManager(), $services->getJobQueueGroup(), $services->get( 'Translate:HookRunner'), new ServiceOptions(TranslateSandbox::CONSTRUCTOR_OPTIONS, $services->getMainConfig()));}, 'Translate:TranslationStashReader'=> static function(MediaWikiServices $services):TranslationStashReader { return new TranslationStashStorage( $services->getConnectionProvider() ->getPrimaryDatabase());}, 'Translate:TranslationStatsDataProvider'=> static function(MediaWikiServices $services):TranslationStatsDataProvider { return new TranslationStatsDataProvider(new ServiceOptions(TranslationStatsDataProvider::CONSTRUCTOR_OPTIONS, $services->getMainConfig()), $services->getObjectFactory(), $services->getConnectionProvider());}, '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->getConnectionProvider());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);}, 'Translate:WorkflowStatesMessageGroupLoader'=> static function(MediaWikiServices $services):WorkflowStatesMessageGroupLoader { return new WorkflowStatesMessageGroupLoader(new ServiceOptions(WorkflowStatesMessageGroupLoader::CONSTRUCTOR_OPTIONS, $services->getMainConfig()),);},]
@phpcs-require-sorted-array
Offers functionality for reading and updating Translate group related metadata.
Exception thrown when TranslatablePageMarker is unable to unmark a page for translation.
Service to mark/unmark pages from translation and perform related validations.
Value object containing user configurable settings when marking a page for translation.