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;
11use MediaWiki\Status\Status;
12use Wikimedia\ParamValidator\ParamValidator;
13use Wikimedia\Rdbms\IDBAccessObject;
14
21class MarkForTranslationActionApi extends ApiBase {
22 private TranslatablePageMarker $translatablePageMarker;
23 private MessageGroupMetadata $messageGroupMetadata;
24
25 public function __construct(
26 ApiMain $mainModule,
27 string $moduleName,
28 TranslatablePageMarker $translatablePageMarker,
29 MessageGroupMetadata $messageGroupMetadata
30 ) {
31 parent::__construct( $mainModule, $moduleName );
32 $this->translatablePageMarker = $translatablePageMarker;
33 $this->messageGroupMetadata = $messageGroupMetadata;
34 }
35
36 public function execute() {
37 $this->checkUserRightsAny( 'pagetranslation' );
38
39 $params = $this->extractRequestParams();
40 $title = $this->getTitleFromTitleOrPageId( $params );
41 $revision = $params['revid'] ?? null;
42
43 $translateTitle = $this->getTriState( $params, 'translatetitle' );
44
45 try {
46 $operation = $this->translatablePageMarker->getMarkOperation(
47 $title->toPageRecord( IDBAccessObject::READ_LATEST ),
48 $revision,
49 $translateTitle
50 );
51 } catch ( TranslatablePageMarkException $e ) {
52 $this->addError( $e->getMessageObject() );
53 return;
54 }
55
56 $unitNameValidationResult = $operation->getUnitValidationStatus();
57 if ( !$unitNameValidationResult->isOK() ) {
58 $this->addMessagesFromStatus( $unitNameValidationResult );
59 return;
60 }
61
62 $translateTitle = $operation->titleTranslationState === TranslateTitleEnum::DEFAULT_CHECKED;
63
64 // By default, units are marked nofuzzy if only their tvars have changed
65 $noFuzzyUnits = [];
66 foreach ( $operation->getUnits() as $s ) {
67 if ( $s->type === 'changed' && $s->onlyTvarsChanged() ) {
68 $noFuzzyUnits[] = $s->id;
69 }
70 }
71
72 // Add and subtract nofuzzy flags as specified by the user
73 $noFuzzyUnits = array_unique( array_merge( $noFuzzyUnits, $params['nofuzzyunits'] ?? [] ) );
74 $noFuzzyUnits = array_diff( $noFuzzyUnits, $params['fuzzyunits'] ?? [] );
75
76 $groupId = $operation->getPage()->getMessageGroupId();
77 if ( isset( $params['prioritylanguages'] ) ) {
78 // Set priority languages
79 $priorityLanguages = $params['prioritylanguages'];
80 $priorityLanguageStatus = $this->validatePriorityLanguages( $priorityLanguages );
81 if ( !$priorityLanguageStatus->isOK() ) {
82 $this->addMessagesFromStatus( $priorityLanguageStatus );
83 return;
84 }
85 $forcePriority = $params['forcepriority'] ?? false;
86 $priorityReason = $params['priorityreason'] ?? '';
87 } else {
88 // markForTranslation() sets priority languages unconditionally.
89 // If no changes were requested, we need to load the current values
90 // just to avoid changing it.
91 $blob = (string)$this->messageGroupMetadata->get( $groupId, 'prioritylangs' );
92 $priorityLanguages = $blob !== '' ? explode( ',', $blob ) : [];
93 $forcePriority = $this->messageGroupMetadata->get( $groupId, 'priorityforce' ) === 'on';
94 // If no priority reason is set, set it to an empty string
95 $priorityReason = $this->messageGroupMetadata->get( $groupId, 'priorityreason' );
96 $priorityReason = $priorityReason !== false ? $priorityReason : '';
97 }
98
99 $transclusion = $this->getTriState( $params, 'transclusion' );
100 if ( $transclusion === null ) {
101 $transclusion = $operation->getPage()->supportsTransclusion() ?? $operation->isFirstMark();
102 }
103
104 $translatablePageSettings = new TranslatablePageSettings(
105 $priorityLanguages,
106 $forcePriority,
107 $priorityReason,
108 $noFuzzyUnits,
109 $translateTitle,
110 $params[ 'forcelatestsyntaxversion'] ?? false,
111 $transclusion
112 );
113
114 try {
115 $unitCount = $this->translatablePageMarker->markForTranslation(
116 $operation,
117 $translatablePageSettings,
118 RequestContext::getMain(),
119 $this->getUser()
120 );
121 } catch ( TranslatablePageMarkException $e ) {
122 $this->addError( $e->getMessageObject() );
123 return;
124 }
125 $res = [
126 'result' => 'Success',
127 'firstmark' => $operation->isFirstMark(),
128 'unitcount' => $unitCount,
129 ];
130 $this->getResult()->addValue( null, $this->getModuleName(), $res );
131 }
132
134 private function getTriState( array $params, string $name ): ?bool {
135 return isset( $params[$name] ) ? $params[$name] === 'yes' : null;
136 }
137
138 private function validatePriorityLanguages( array $priorityLanguageCodes ): Status {
139 $knownLanguageCodes = array_keys( Utilities::getLanguageNames( 'en' ) );
140 $invalidLanguageCodes = array_diff( $priorityLanguageCodes, $knownLanguageCodes );
141 $context = $this->getContext();
142
143 if ( $invalidLanguageCodes ) {
144 return Status::newFatal(
145 $context->msg( 'apierror-markfortranslation-invalid-prioritylangs' )
146 ->params(
147 count( $invalidLanguageCodes ),
148 $context->getLanguage()->commaList( $invalidLanguageCodes )
149 )
150 );
151 }
152
153 return Status::newGood();
154 }
155
157 public function isWriteMode() {
158 return true;
159 }
160
162 public function needsToken() {
163 return 'csrf';
164 }
165
166 protected function getAllowedParams(): array {
167 return [
168 'title' => [
169 ParamValidator::PARAM_TYPE => 'string',
170 ],
171 'pageid' => [
172 ParamValidator::PARAM_TYPE => 'integer',
173 ],
174 'revid' => [
175 ParamValidator::PARAM_TYPE => 'integer',
176 ],
177 'translatetitle' => [
178 ParamValidator::PARAM_TYPE => [ 'yes', 'no' ],
179 ],
180 'prioritylanguages' => [
181 ParamValidator::PARAM_TYPE => 'string',
182 ParamValidator::PARAM_ISMULTI => true,
183 ParamValidator::PARAM_ISMULTI_LIMIT1 => 1000,
184 ParamValidator::PARAM_ISMULTI_LIMIT2 => 1000,
185 ],
186 'forcepriority' => [
187 ParamValidator::PARAM_TYPE => 'boolean',
188 ],
189 'priorityreason' => [
190 ParamValidator::PARAM_TYPE => 'string',
191 ],
192 'nofuzzyunits' => [
193 ParamValidator::PARAM_TYPE => 'string',
194 ParamValidator::PARAM_ISMULTI => true,
195 ParamValidator::PARAM_ISMULTI_LIMIT1 => 1000,
196 ParamValidator::PARAM_ISMULTI_LIMIT2 => 1000,
197 ],
198 'fuzzyunits' => [
199 ParamValidator::PARAM_TYPE => 'string',
200 ParamValidator::PARAM_ISMULTI => true,
201 ParamValidator::PARAM_ISMULTI_LIMIT1 => 1000,
202 ParamValidator::PARAM_ISMULTI_LIMIT2 => 1000,
203 ],
204 'forcelatestsyntaxversion' => [
205 ParamValidator::PARAM_TYPE => 'boolean',
206 ],
207 'transclusion' => [
208 ParamValidator::PARAM_TYPE => [ 'yes', 'no' ],
209 ],
210 ];
211 }
212
213}
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->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);}, '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.
Essentially random collection of helper functions, similar to GlobalFunctions.php.
Definition Utilities.php:29