80 global $wgTranslateYamlLibrary;
87 if ( !defined(
'TRANSLATE_FUZZY' ) ) {
88 define(
'TRANSLATE_FUZZY',
'!!FUZZY!!' );
91 if ( $wgTranslateYamlLibrary ===
null ) {
92 $wgTranslateYamlLibrary = function_exists(
'yaml_parse' ) ?
'phpyaml' :
'spyc';
95 $hooks[
'PageSaveComplete'][] = [ TranslateEditAddons::class,
'onSaveComplete' ];
98 global $wgEnablePageTranslation;
99 if ( $wgEnablePageTranslation ) {
101 global $wgSpecialPages, $wgAvailableRights;
102 $wgSpecialPages[
'PageTranslation'] = [
103 'class' => PageTranslationSpecialPage::class,
107 'Translate:TranslationUnitStoreFactory',
108 'Translate:TranslatablePageParser',
112 'Translate:MessageIndex'
115 $wgSpecialPages[
'PageTranslationDeletePage'] = [
116 'class' => DeleteTranslatableBundleSpecialPage::class,
120 'Translate:TranslatableBundleFactory',
121 'Translate:SubpageListBuilder',
127 $wgAvailableRights[] =
'pagetranslation';
129 $wgSpecialPages[
'PageMigration'] = MigrateTranslatablePageSpecialPage::class;
130 $wgSpecialPages[
'PagePreparation'] = PrepareTranslatablePageSpecialPage::class;
132 global $wgActionFilteredLogs, $wgLogActionsHandlers, $wgLogTypes;
141 $wgLogTypes[] =
'pagetranslation';
142 $wgLogActionsHandlers[
'pagetranslation/mark'] = TranslatableBundleLogFormatter::class;
143 $wgLogActionsHandlers[
'pagetranslation/unmark'] = TranslatableBundleLogFormatter::class;
144 $wgLogActionsHandlers[
'pagetranslation/moveok'] = TranslatableBundleLogFormatter::class;
145 $wgLogActionsHandlers[
'pagetranslation/movenok'] = TranslatableBundleLogFormatter::class;
146 $wgLogActionsHandlers[
'pagetranslation/deletelok'] = TranslatableBundleLogFormatter::class;
147 $wgLogActionsHandlers[
'pagetranslation/deletefok'] = TranslatableBundleLogFormatter::class;
148 $wgLogActionsHandlers[
'pagetranslation/deletelnok'] = TranslatableBundleLogFormatter::class;
149 $wgLogActionsHandlers[
'pagetranslation/deletefnok'] = TranslatableBundleLogFormatter::class;
150 $wgLogActionsHandlers[
'pagetranslation/encourage'] = TranslatableBundleLogFormatter::class;
151 $wgLogActionsHandlers[
'pagetranslation/discourage'] = TranslatableBundleLogFormatter::class;
152 $wgLogActionsHandlers[
'pagetranslation/prioritylanguages'] = TranslatableBundleLogFormatter::class;
153 $wgLogActionsHandlers[
'pagetranslation/associate'] = TranslatableBundleLogFormatter::class;
154 $wgLogActionsHandlers[
'pagetranslation/dissociate'] = TranslatableBundleLogFormatter::class;
155 $wgActionFilteredLogs[
'pagetranslation'] = [
156 'mark' => [
'mark' ],
157 'unmark' => [
'unmark' ],
158 'move' => [
'moveok',
'movenok' ],
159 'delete' => [
'deletefok',
'deletefnok',
'deletelok',
'deletelnok' ],
160 'encourage' => [
'encourage' ],
161 'discourage' => [
'discourage' ],
162 'prioritylanguages' => [
'prioritylanguages' ],
163 'aggregategroups' => [
'associate',
'dissociate' ],
166 $wgLogTypes[] =
'messagebundle';
167 $wgLogActionsHandlers[
'messagebundle/moveok'] = TranslatableBundleLogFormatter::class;
168 $wgLogActionsHandlers[
'messagebundle/movenok'] = TranslatableBundleLogFormatter::class;
169 $wgLogActionsHandlers[
'messagebundle/deletefok'] = TranslatableBundleLogFormatter::class;
170 $wgLogActionsHandlers[
'messagebundle/deletefnok'] = TranslatableBundleLogFormatter::class;
171 $wgActionFilteredLogs[
'messagebundle'] = [
172 'move' => [
'moveok',
'movenok' ],
173 'delete' => [
'deletefok',
'deletefnok' ],
176 global $wgJobClasses;
177 $wgJobClasses[
'RenderTranslationPageJob'] = RenderTranslationPageJob::class;
179 $wgJobClasses[
'TranslateRenderJob'] = RenderTranslationPageJob::class;
181 $wgJobClasses[
'TranslatableBundleMoveJob'] = MoveTranslatableBundleJob::class;
182 $wgJobClasses[
'MoveTranslatableBundleJob'] = MoveTranslatableBundleJob::class;
184 $wgJobClasses[
'TranslatableBundleDeleteJob'] = DeleteTranslatableBundleJob::class;
185 $wgJobClasses[
'DeleteTranslatableBundleJob'] = DeleteTranslatableBundleJob::class;
187 $wgJobClasses[
'UpdateTranslatablePageJob'] = UpdateTranslatablePageJob::class;
189 $wgJobClasses[
'TranslationsUpdateJob'] = UpdateTranslatablePageJob::class;
192 global $wgNamespacesWithSubpages, $wgNamespaceProtection;
193 global $wgTranslateMessageNamespaces;
195 $wgNamespacesWithSubpages[NS_TRANSLATIONS] =
true;
196 $wgNamespacesWithSubpages[NS_TRANSLATIONS_TALK] =
true;
199 $wgNamespaceProtection[NS_TRANSLATIONS] = [
'translate' ];
200 $wgTranslateMessageNamespaces[] = NS_TRANSLATIONS;
205 $hooks[
'BeforePageDisplay'][] = [ Hooks::class,
'onBeforePageDisplay' ];
208 $hooks[
'VisualEditorBeforeEditor'][] = [ Hooks::class,
'onVisualEditorBeforeEditor' ];
211 $hooks[
'MultiContentSave'][] = [ Hooks::class,
'tpSyntaxCheck' ];
212 $hooks[
'EditFilterMergedContent'][] =
213 [ Hooks::class,
'tpSyntaxCheckForEditContent' ];
216 $hooks[
'PageSaveComplete'][] = [ Hooks::class,
'addTranstagAfterSave' ];
218 $hooks[
'RevisionRecordInserted'][] = [ Hooks::class,
'updateTranstagOnNullRevisions' ];
221 $hooks[
'ParserFirstCallInit'][] = [ self::class,
'setupParserHooks' ];
222 $hooks[
'LanguageLinks'][] = [ Hooks::class,
'addLanguageLinks' ];
223 $hooks[
'SkinTemplateGetLanguageLink'][] = [ Hooks::class,
'formatLanguageLink' ];
226 $hooks[
'ParserBeforeInternalParse'][] = [ Hooks::class,
'renderTagPage' ];
228 $hooks[
'ParserBeforePreprocess'][] = [ Hooks::class,
'preprocessTagPage' ];
229 $hooks[
'ParserOutputPostCacheTransform'][] =
230 [ Hooks::class,
'onParserOutputPostCacheTransform' ];
232 $hooks[
'BeforeParserFetchTemplateRevisionRecord'][] =
233 [ Hooks::class,
'fetchTranslatableTemplateAndTitle' ];
236 $hooks[
'PageContentLanguage'][] = [ Hooks::class,
'onPageContentLanguage' ];
239 $hooks[
'getUserPermissionsErrorsExpensive'][] =
240 [ Hooks::class,
'onGetUserPermissionsErrorsExpensive' ];
242 $hooks[
'getUserPermissionsErrorsExpensive'][] =
243 [ Hooks::class,
'preventDirectEditing' ];
246 $hooks[
'ArticleViewHeader'][] = [ Hooks::class,
'translatablePageHeader' ];
249 $hooks[
'TitleGetEditNotices'][] = [ Hooks::class,
'onTitleGetEditNotices' ];
252 $hooks[
'SpecialPage_initList'][] = [ Hooks::class,
'replaceMovePage' ];
254 $hooks[
'getUserPermissionsErrorsExpensive'][] =
255 [ Hooks::class,
'lockedPagesCheck' ];
257 $hooks[
'ArticleConfirmDelete'][] = [ Hooks::class,
'disableDelete' ];
260 $hooks[
'SkinSubPageSubtitle'][] = [ Hooks::class,
'replaceSubtitle' ];
263 $hooks[
'SkinTemplateNavigation::Universal'][] = [ Hooks::class,
'translateTab' ];
266 $hooks[
'PageMoveComplete'][] = [ Hooks::class,
'onMovePageTranslationUnits' ];
269 $hooks[
'ArticleDeleteComplete'][] = [ Hooks::class,
'onDeleteTranslationUnit' ];
272 global $wgTranslateUseSandbox;
273 if ( $wgTranslateUseSandbox ) {
274 global $wgSpecialPages, $wgAvailableRights, $wgDefaultUserOptions;
276 $wgSpecialPages[
'ManageTranslatorSandbox'] = [
277 'class' => ManageTranslatorSandboxSpecialPage::class,
279 'Translate:TranslationStashReader',
284 return new ServiceOptions(
285 ManageTranslatorSandboxSpecialPage::CONSTRUCTOR_OPTIONS,
286 MediaWikiServices::getInstance()->getMainConfig()
291 $wgSpecialPages[
'TranslationStash'] = [
292 'class' => TranslationStashSpecialPage::class,
295 'Translate:TranslationStashReader',
301 return new ServiceOptions(
302 TranslationStashSpecialPage::CONSTRUCTOR_OPTIONS,
303 MediaWikiServices::getInstance()->getMainConfig()
308 $wgDefaultUserOptions[
'translate-sandbox'] =
'';
310 $wgAvailableRights[] =
'translate-sandboxmanage';
312 $hooks[
'GetPreferences'][] = [ TranslateSandbox::class,
'onGetPreferences' ];
313 $hooks[
'UserGetRights'][] = [ TranslateSandbox::class,
'enforcePermissions' ];
314 $hooks[
'ApiCheckCanExecute'][] = [ TranslateSandbox::class,
'onApiCheckCanExecute' ];
316 global $wgLogTypes, $wgLogActionsHandlers;
318 $wgLogTypes[] =
'translatorsandbox';
320 $wgLogActionsHandlers[
'translatorsandbox/promoted'] =
'TranslateLogFormatter';
321 $wgLogActionsHandlers[
'translatorsandbox/rejected'] =
'TranslateLogFormatter';
325 $wgLogActionsHandlers[
'newusers/tsbpromoted'] =
'LogFormatter';
327 global $wgJobClasses;
328 $wgJobClasses[
'TranslateSandboxEmailJob'] =
'TranslateSandboxEmailJob';
330 global $wgAPIModules;
331 $wgAPIModules[
'translationstash'] = [
332 'class' => TranslationStashActionApi::class,
338 $wgAPIModules[
'translatesandbox'] = [
339 'class' => TranslatorSandboxActionApi::class,
343 'UserOptionsManager',
349 return new ServiceOptions(
350 TranslatorSandboxActionApi::CONSTRUCTOR_OPTIONS,
351 MediaWikiServices::getInstance()->getMainConfig()
358 global $wgNamespaceRobotPolicies;
359 $wgNamespaceRobotPolicies[NS_TRANSLATIONS] =
'noindex';
362 global $wgTranslateTranslationDefaultService,
363 $wgTranslateTranslationServices;
364 if ( $wgTranslateTranslationDefaultService ===
true ) {
365 $wgTranslateTranslationDefaultService =
'TTMServer';
366 if ( !isset( $wgTranslateTranslationServices[
'TTMServer'] ) ) {
367 $wgTranslateTranslationServices[
'TTMServer'] = [
370 'type' =>
'ttmserver',
376 $hooks[
'SidebarBeforeOutput'][] = [ TranslateToolbox::class,
'toolboxAllTranslations' ];
378 static::registerHookHandlers( $hooks );
503 $dir = __DIR__ .
'/sql';
504 $dbType = $updater->getDB()->getType();
506 if ( $dbType ===
'mysql' || $dbType ===
'sqlite' ) {
507 $updater->addExtensionTable(
508 'translate_sections',
509 "{$dir}/{$dbType}/translate_sections.sql"
511 $updater->addExtensionTable(
513 "{$dir}/{$dbType}/revtag.sql"
515 $updater->addExtensionTable(
516 'translate_groupstats',
517 "{$dir}/{$dbType}/translate_groupstats.sql"
519 $updater->addExtensionTable(
521 "{$dir}/{$dbType}/translate_reviews.sql"
523 $updater->addExtensionTable(
524 'translate_groupreviews',
525 "{$dir}/{$dbType}/translate_groupreviews.sql"
527 $updater->addExtensionTable(
529 "{$dir}/{$dbType}/translate_tm.sql"
531 $updater->addExtensionTable(
532 'translate_metadata',
533 "{$dir}/{$dbType}/translate_metadata.sql"
535 $updater->addExtensionTable(
536 'translate_messageindex',
537 "{$dir}/{$dbType}/translate_messageindex.sql"
539 $updater->addExtensionTable(
541 "{$dir}/{$dbType}/translate_stash.sql"
543 $updater->addExtensionTable(
544 'translate_translatable_bundles',
545 "{$dir}/{$dbType}/translate_translatable_bundles.sql"
549 $updater->addExtensionUpdate( [
552 'trr_user_page_revision',
555 "$dir/translate_reviews-patch-01-primary-key.sql",
559 $updater->addExtensionTable(
561 "{$dir}/{$dbType}/translate_cache.sql"
564 if ( $dbType ===
'mysql' ) {
566 $updater->modifyExtensionField(
569 "{$dir}/{$dbType}/translate_cache-alter-varbinary.sql"
572 } elseif ( $dbType ===
'postgres' ) {
573 $updater->addExtensionTable(
574 'translate_sections',
575 "{$dir}/{$dbType}/tables-generated.sql"
577 $updater->addExtensionUpdate( [
578 'changeField',
'translate_cache',
'tc_exptime',
'TIMESTAMPTZ',
'th_timestamp::timestamp with time zone'
583 $updater->dropExtensionIndex(
584 'translate_messageindex',
586 "{$dir}/{$dbType}/patch-translate_messageindex-unique-to-pk.sql"
588 $updater->dropExtensionIndex(
591 "{$dir}/{$dbType}/patch-translate_tmt-unique-to-pk.sql"
593 $updater->dropExtensionIndex(
595 'rt_type_page_revision',
596 "{$dir}/{$dbType}/patch-revtag-unique-to-pk.sql"
599 $updater->addPostDatabaseUpdateMaintenance( SyncTranslatableBundleStatusMaintenanceScript::class );
688 SpecialSearch $search,
694 if ( $profile !==
'translation' ) {
699 $href = SpecialPage::getTitleFor(
'SearchTranslations' )
700 ->getFullUrl( [
'query' => $term ] );
701 $form = Html::successBox(
702 $search->msg(
'translate-searchprofile-note', $href )->parse(),
709 if ( !$search->getSearchEngine()->supports(
'title-suffix-filter' ) ) {
714 foreach ( $opts as $key => $value ) {
715 $hidden .= Html::hidden( $key, $value );
718 $context = $search->getContext();
719 $code = $context->getLanguage()->getCode();
720 $selected = $context->getRequest()->getVal(
'languagefilter' );
722 $languages = Utilities::getLanguageNames( $code );
725 $selector =
new XmlSelect(
'languagefilter',
'languagefilter' );
726 $selector->setDefault( $selected );
727 $selector->addOption( wfMessage(
'translate-search-nofilter' )->text(),
'-' );
728 foreach ( $languages as $code => $name ) {
729 $selector->addOption(
"$code - $name", $code );
732 $selector = $selector->getHTML();
735 wfMessage(
'translate-search-languagefilter' )->text(),
738 $params = [
'id' =>
'mw-searchoptions' ];
740 $form = Xml::fieldset(
false,
false, $params ) .
741 $hidden . $label . $selector .
742 Html::closeElement(
'fieldset' );
805 public static function addConfig( array &$vars, OutputPage $out ) {
806 $title = $out->getTitle();
807 [ $alias, ] = MediaWikiServices::getInstance()
808 ->getSpecialPageFactory()->resolveAlias( $title->getText() );
810 if ( $title->isSpecialPage()
811 && ( $alias ===
'Translate'
812 || $alias ===
'TranslationStash'
813 || $alias ===
'SearchTranslations' )
815 global $wgTranslateDocumentationLanguageCode, $wgTranslatePermissionUrl,
816 $wgTranslateUseSandbox;
817 $vars[
'TranslateRight'] = $out->getUser()->isAllowed(
'translate' );
818 $vars[
'TranslateMessageReviewRight'] =
819 $out->getUser()->isAllowed(
'translate-messagereview' );
820 $vars[
'DeleteRight'] = $out->getUser()->isAllowed(
'delete' );
821 $vars[
'TranslateManageRight'] = $out->getUser()->isAllowed(
'translate-manage' );
822 $vars[
'wgTranslateDocumentationLanguageCode'] = $wgTranslateDocumentationLanguageCode;
823 $vars[
'wgTranslatePermissionUrl'] = $wgTranslatePermissionUrl;
824 $vars[
'wgTranslateUseSandbox'] = $wgTranslateUseSandbox;
975 Status $status, $summary, User $user
977 if ( !$content instanceof TextContent ) {
982 $text = $content->getText();
983 $title = $context->getTitle();
986 if ( !$handle->isValid() ) {
991 if ( $user->isAllowed(
'translate-manage' ) || $user->equals( FuzzyBot::getUser() ) ) {
996 if ( $handle->isMessageNamespace() && !$handle->isDoc() ) {
997 $group = $handle->getGroup();
999 if ( method_exists( $group,
'getMessageContent' ) ) {
1001 $definition = $group->getMessageContent( $handle );
1003 $definition = $group->getMessage( $handle->getKey(), $group->getSourceLanguage() );
1006 $message =
new FatMessage( $handle->getKey(), $definition );
1007 $message->setTranslation( $text );
1009 $messageValidator = $group->getValidator();
1010 if ( !$messageValidator ) {
1014 $validationResponse = $messageValidator->validateMessage( $message, $handle->getCode() );
1015 if ( $validationResponse->hasErrors() ) {
1016 $status->fatal(
new ApiRawMessage(
1017 $context->msg(
'translate-syntax-error' )->parse(),
1018 'translate-validation-failed',
1021 'errors' => $validationResponse->getDescriptiveErrors( $context ),
1022 'warnings' => $validationResponse->getDescriptiveWarnings( $context )