Merge "API: i18n for warnings and errors"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 6 Dec 2016 19:57:45 +0000 (19:57 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 6 Dec 2016 19:57:45 +0000 (19:57 +0000)
1  2 
RELEASE-NOTES-1.29
autoload.php
docs/hooks.txt
includes/specials/SpecialEmailuser.php
includes/specials/SpecialUnblock.php
languages/i18n/en.json
languages/i18n/qqq.json

diff --combined RELEASE-NOTES-1.29
@@@ -14,6 -14,14 +14,14 @@@ production
    will still be blocked.
  * The resetpassword right and associated password reset capture feature has
    been removed.
+ * The $error parameter to the EmailUser hook should be set to a Status object
+   or boolean false. This should be compatible with at least MediaWiki 1.23 if
+   not earlier. Returning a raw HTML string is now deprecated.
+ * The $message parameter to the ApiCheckCanExecute hook should be set to an
+   ApiMessage. This is compatible with MediaWiki 1.27 and later. Returning a
+   code for ApiBase::parseMsg() will no longer work.
+ * ApiBase::$messageMap is no longer public. Code attempting to access it will
+   result in a PHP fatal error.
  
  === New features in 1.29 ===
  * (T5233) A cookie can now be set when a user is autoblocked, to track that user if
    body instead.
  * The capture option for action=resetpassword has been removed
  * action=clearhasmsg now requires a POST.
+ * (T47843) API errors and warnings may be requested in non-English languages
+   using the new 'errorformat', 'errorlang', and 'errorsuselocal' parameters.
+ * API error codes may have changed. Most notably, errors from modules using
+   parameter prefixes (e.g. all query submodules) will no longer be prefixed.
+ * action=emailuser may return a "Warnings" status, and now returns 'warnings' and
+   'errors' subelements (as applicable) instead of 'message'.
+ * action=imagerotate returns an 'errors' subelement rather than 'errormessage'.
+ * action=move now reports errors when moving the talk page as an array under
+   key 'talkmove-errors', rather than using 'talkmove-error-code' and
+   'talkmove-error-info'. The format for subpage move errors has also changed.
+ * action=rollback no longer returns a "messageHtml" property on errors. Use
+   errorformat=html if you're wanting HTML formatting of messages.
+ * action=upload now reports optional stash failures as an array under key
+   'stasherrors' rather than a 'stashfailed' text string.
+ * action=watch reports 'errors' and 'warnings' instead of a single 'error'.
  
  === Action API internal changes in 1.29 ===
+ * New methods were added to ApiBase to handle errors and warnings using i18n
+   keys. Methods for using hard-coded English messages were deprecated:
+   * ApiBase::dieUsage() was deprecated
+   * ApiBase::dieUsageMsg() was deprecated
+   * ApiBase::dieUsageMsgOrDebug() was deprecated
+   * ApiBase::getErrorFromStatus() was deprecated
+   * ApiBase::parseMsg() was deprecated
+   * ApiBase::setWarning() was deprecated
+ * ApiBase::$messageMap is no longer public. Code attempting to access it will
+   result in a PHP fatal error.
+ * The $message parameter to the ApiCheckCanExecute hook should be set to an
+   ApiMessage. This is compatible with MediaWiki 1.27 and later. Returning a
+   code for ApiBase::parseMsg() will no longer work.
+ * UsageException is deprecated in favor of ApiUsageException. For the time
+   being ApiUsageException is a subclass of UsageException to allow things that
+   catch only UsageException to still function properly.
+ * If, for some strange reason, code was using an ApiErrorFormatter instead of
+   ApiErrorFormatter_BackCompat, note that the result format has changed and
+   various methods now take a module path rather than a module name.
+ * ApiMessageTrait::getApiCode() now strips 'apierror-' and 'apiwarn-' prefixes
+   from the message key, and maps some message keys for backwards compatibility.
  
  === Languages updated in 1.29 ===
  
@@@ -58,15 -102,6 +102,15 @@@ changes to languages because of Phabric
    required as all sessions are stored in Object Cache now.
  * MWHttpRequest::execute() should be considered to return a StatusValue; the
    Status return type is deprecated.
 +* User::edits() (deprecated in 1.21) was removed.
 +* Xml::escapeJsString() (deprecated in 1.21) was removed.
 +* Article::getText() and Article::prepareTextForEdit() (deprecated in 1.21)
 +  were removed.
 +* Article::getAutosummary() and WikiPage::getAutosummary (deprecated in 1.21)
 +  were removed.
 +* Hooks ArticleViewCustom, EditPageGetDiffText and ShowRawCssJs (deprecated in 1.21)
 +  were removed.
 +* Class RevisiondeleteAction (deprecated in 1.25) was removed.
  
  == Compatibility ==
  
diff --combined autoload.php
@@@ -145,6 -145,7 +145,7 @@@ $wgAutoloadLocalClasses = 
        'ApiUnblock' => __DIR__ . '/includes/api/ApiUnblock.php',
        'ApiUndelete' => __DIR__ . '/includes/api/ApiUndelete.php',
        'ApiUpload' => __DIR__ . '/includes/api/ApiUpload.php',
+       'ApiUsageException' => __DIR__ . '/includes/api/ApiUsageException.php',
        'ApiUserrights' => __DIR__ . '/includes/api/ApiUserrights.php',
        'ApiWatch' => __DIR__ . '/includes/api/ApiWatch.php',
        'ArchivedFile' => __DIR__ . '/includes/filerepo/file/ArchivedFile.php',
        'ExplodeIterator' => __DIR__ . '/includes/libs/ExplodeIterator.php',
        'ExportProgressFilter' => __DIR__ . '/maintenance/backup.inc',
        'ExportSites' => __DIR__ . '/maintenance/exportSites.php',
 +      'ExtensionJsonValidationError' => __DIR__ . '/includes/registration/ExtensionJsonValidationError.php',
 +      'ExtensionJsonValidator' => __DIR__ . '/includes/registration/ExtensionJsonValidator.php',
        'ExtensionLanguages' => __DIR__ . '/maintenance/language/languages.inc',
        'ExtensionProcessor' => __DIR__ . '/includes/registration/ExtensionProcessor.php',
        'ExtensionRegistry' => __DIR__ . '/includes/registration/ExtensionRegistry.php',
        'ResourceLoaderSpecialCharacterDataModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderSpecialCharacterDataModule.php',
        'ResourceLoaderStartUpModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderStartUpModule.php',
        'ResourceLoaderUploadDialogModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUploadDialogModule.php',
 -      'ResourceLoaderUserCSSPrefsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php',
        'ResourceLoaderUserDefaultsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserDefaultsModule.php',
        'ResourceLoaderUserModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserModule.php',
        'ResourceLoaderUserOptionsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserOptionsModule.php',
        'RevisionItemBase' => __DIR__ . '/includes/RevisionList.php',
        'RevisionList' => __DIR__ . '/includes/RevisionList.php',
        'RevisionListBase' => __DIR__ . '/includes/RevisionList.php',
 -      'RevisiondeleteAction' => __DIR__ . '/includes/actions/RevisiondeleteAction.php',
        'RiffExtractor' => __DIR__ . '/includes/libs/RiffExtractor.php',
        'RightsLogFormatter' => __DIR__ . '/includes/logging/RightsLogFormatter.php',
        'RollbackAction' => __DIR__ . '/includes/actions/RollbackAction.php',
        'UploadStashWrongOwnerException' => __DIR__ . '/includes/upload/UploadStash.php',
        'UploadStashZeroLengthFileException' => __DIR__ . '/includes/upload/UploadStash.php',
        'UppercaseCollation' => __DIR__ . '/includes/collation/UppercaseCollation.php',
-       'UsageException' => __DIR__ . '/includes/api/ApiMain.php',
+       'UsageException' => __DIR__ . '/includes/api/ApiUsageException.php',
        'User' => __DIR__ . '/includes/user/User.php',
        'UserArray' => __DIR__ . '/includes/user/UserArray.php',
        'UserArrayFromResult' => __DIR__ . '/includes/user/UserArrayFromResult.php',
diff --combined docs/hooks.txt
@@@ -358,8 -358,12 +358,12 @@@ authenticate and authorize API clients 
  false and set a message to cancel the request.
  $module: Module object
  $user: Current user
- &$message: API usage message to die with, as a message key or array
-   as accepted by ApiBase::dieUsageMsg.
+ &$message: API message to die with. Specific values accepted depend on the
+  MediaWiki version:
+  * 1.29+: IApiMessage, Message, string message key, or key+parameters array to
+    pass to ApiBase::dieWithError().
+  * 1.27+: IApiMessage, or a key or key+parameters in ApiBase::$messageMap.
+  * Earlier: A key or key+parameters in ApiBase::$messageMap.
  
  'APIEditBeforeSave': DEPRECATED! Use EditFilterMergedContent instead.
  Before saving a page with api.php?action=edit, after
@@@ -774,6 -778,14 +778,6 @@@ $article: the articl
  &$sectionanchor: The section anchor link (e.g. "#overview" )
  &$extraq: Extra query parameters which can be added via hooked functions
  
 -'ArticleViewCustom': DEPRECATED! Use ArticleContentViewCustom instead.
 -Allows to output the text of the article in a different format than wikitext.
 -Note that it is preferable to implement proper handing for a custom data type
 -using the ContentHandler facility.
 -$text: text of the page
 -$title: title of the page
 -$output: reference to $wgOut
 -
  'ArticleViewFooter': After showing the footer section of an ordinary page view
  $article: Article object
  $patrolFooterShown: boolean whether patrol footer is shown
@@@ -1409,6 -1421,13 +1413,6 @@@ different data types using the ContentH
  $editPage: EditPage object
  &$newtext: wikitext that will be used as "your version"
  
 -'EditPageGetDiffText': DEPRECATED! Use EditPageGetDiffContent instead.
 -Allow modifying the wikitext that will be used in "Show changes". Note that it
 -is preferable to implement diff handling for different data types using the
 -ContentHandler facility.
 -$editPage: EditPage object
 -&$newtext: wikitext that will be used as "your version"
 -
  'EditPageGetPreviewContent': Allow modifying the wikitext that will be
  previewed. Note that it is preferable to implement previews for different data
  types using the ContentHandler facility.
@@@ -1444,7 -1463,7 +1448,7 @@@ true to allow those checks to occur, an
  &$from: MailAddress object of sending user
  &$subject: subject of the mail
  &$text: text of the mail
- &$error: Out-param for an error
+ &$error: Out-param for an error. Should be set to a Status object or boolean false.
  
  'EmailUserCC': Before sending the copy of the email to the author.
  &$to: MailAddress object of receiving user
@@@ -2539,6 -2558,8 +2543,6 @@@ $user: the User considering the edi
  'PasswordPoliciesForUser': Alter the effective password policy for a user.
  $user: User object whose policy you are modifying
  &$effectivePolicy: Array of policy statements that apply to this user
 -$purpose: string indicating purpose of the check, one of 'login', 'create',
 -  or 'reset'
  
  'PerformRetroactiveAutoblock': Called before a retroactive autoblock is applied
  to a user.
@@@ -2826,6 -2847,12 +2830,6 @@@ Special:ShortPages
  'ShowMissingArticle': Called when generating the output for a non-existent page.
  $article: The article object corresponding to the page
  
 -'ShowRawCssJs': DEPRECATED! Use the ContentGetParserOutput hook instead.
 -Customise the output of raw CSS and JavaScript in page views.
 -$text: Text being shown
 -$title: Title of the custom script/stylesheet page
 -$output: Current OutputPage object
 -
  'ShowSearchHit': Customize display of search hit.
  $searchPage: The SpecialSearch instance.
  $result: The SearchResult to show
@@@ -53,14 -53,13 +53,14 @@@ class SpecialEmailUser extends Unlisted
        }
  
        protected function getFormFields() {
 +              $linkRenderer = $this->getLinkRenderer();
                return [
                        'From' => [
                                'type' => 'info',
                                'raw' => 1,
 -                              'default' => Linker::link(
 +                              'default' => $linkRenderer->makeLink(
                                        $this->getUser()->getUserPage(),
 -                                      htmlspecialchars( $this->getUser()->getName() )
 +                                      $this->getUser()->getName()
                                ),
                                'label-message' => 'emailfrom',
                                'id' => 'mw-emailuser-sender',
@@@ -68,9 -67,9 +68,9 @@@
                        'To' => [
                                'type' => 'info',
                                'raw' => 1,
 -                              'default' => Linker::link(
 +                              'default' => $linkRenderer->makeLink(
                                        $this->mTargetObj->getUserPage(),
 -                                      htmlspecialchars( $this->mTargetObj->getName() )
 +                                      $this->mTargetObj->getName()
                                ),
                                'label-message' => 'emailto',
                                'id' => 'mw-emailuser-recipient',
         * @since 1.20
         * @param array $data
         * @param HTMLForm $form
-        * @return Status|string|bool
+        * @return Status|bool
         */
        public static function uiSubmit( array $data, HTMLForm $form ) {
                return self::submit( $data, $form->getContext() );
         *
         * @param array $data
         * @param IContextSource $context
-        * @return Status|string|bool Status object, or potentially a String on error
-        * or maybe even true on success if anything uses the EmailUser hook.
+        * @return Status|bool
         */
        public static function submit( array $data, IContextSource $context ) {
                $config = $context->getConfig();
                $target = self::getTarget( $data['Target'] );
                if ( !$target instanceof User ) {
                        // Messages used here: notargettext, noemailtext, nowikiemailtext
-                       return $context->msg( $target . 'text' )->parseAsBlock();
+                       return Status::newFatal( $target . 'text' );
                }
  
                $to = MailAddress::newFromUser( $target );
                $text .= $context->msg( 'emailuserfooter',
                        $from->name, $to->name )->inContentLanguage()->text();
  
-               $error = '';
+               $error = false;
                if ( !Hooks::run( 'EmailUser', [ &$to, &$from, &$subject, &$text, &$error ] ) ) {
-                       return $error;
+                       if ( $error instanceof Status ) {
+                               return $error;
+                       } elseif ( $error === false || $error === '' || $error === [] ) {
+                               // Possibly to tell HTMLForm to pretend there was no submission?
+                               return false;
+                       } elseif ( $error === true ) {
+                               // Hook sent the mail itself and indicates success?
+                               return Status::newGood();
+                       } elseif ( is_array( $error ) ) {
+                               $status = Status::newGood();
+                               foreach ( $error as $e ) {
+                                       $status->fatal( $e );
+                               }
+                               return $status;
+                       } elseif ( $error instanceof MessageSpecifier ) {
+                               return Status::newFatal( $error );
+                       } else {
+                               // Ugh. Either a raw HTML string, or something that's supposed
+                               // to be treated like one.
+                               $type = is_object( $error ) ? get_class( $error ) : gettype( $error );
+                               wfDeprecated( "EmailUser hook returning a $type as \$error", '1.29' );
+                               return Status::newFatal( new ApiRawMessage(
+                                       [ '$1', Message::rawParam( (string)$error ) ], 'hookaborted'
+                               ) );
+                       }
                }
  
                if ( $config->get( 'UserEmailUseReplyTo' ) ) {
@@@ -119,14 -119,14 +119,14 @@@ class SpecialUnblock extends SpecialPag
                                $fields['Target']['type'] = 'hidden';
                                switch ( $type ) {
                                        case Block::TYPE_IP:
 -                                              $fields['Name']['default'] = Linker::linkKnown(
 +                                              $fields['Name']['default'] = $this->getLinkRenderer()->makeKnownLink(
                                                        SpecialPage::getTitleFor( 'Contributions', $target->getName() ),
                                                        $target->getName()
                                                );
                                                $fields['Name']['raw'] = true;
                                                break;
                                        case Block::TYPE_USER:
 -                                              $fields['Name']['default'] = Linker::link(
 +                                              $fields['Name']['default'] = $this->getLinkRenderer()->makeLink(
                                                        $target->getUserPage(),
                                                        $target->getName()
                                                );
         * @param array $data
         * @param IContextSource $context
         * @throws ErrorPageError
-        * @return array|bool Array(message key, parameters) on failure, True on success
+        * @return array|bool Array( Array( message key, parameters ) ) on failure, True on success
         */
        public static function processUnblock( array $data, IContextSource $context ) {
                $performer = $context->getUser();
  
                # Delete block
                if ( !$block->delete() ) {
-                       return [ 'ipb_cant_unblock', htmlspecialchars( $block->getTarget() ) ];
+                       return [ [ 'ipb_cant_unblock', htmlspecialchars( $block->getTarget() ) ] ];
                }
  
                # Unset _deleted fields as needed
diff --combined languages/i18n/en.json
        "userrights-user-editname": "Enter a username:",
        "editusergroup": "Load user groups",
        "editinguser": "Changing user rights of {{GENDER:$1|user}} <strong>[[User:$1|$1]]</strong> $2",
 +      "viewinguserrights": "Viewing user rights of {{GENDER:$1|user}} <strong>[[User:$1|$1]]</strong> $2",
        "userrights-editusergroup": "Edit user groups",
 +      "userrights-viewusergroup": "View user groups",
        "saveusergroups": "Save {{GENDER:$1|user}} groups",
        "userrights-groupsmember": "Member of:",
        "userrights-groupsmember-auto": "Implicit member of:",
        "action-upload_by_url": "upload this file from a URL",
        "action-writeapi": "use the write API",
        "action-delete": "delete this page",
-       "action-deleterevision": "delete this revision",
-       "action-deletedhistory": "view this page's deleted history",
+       "action-deleterevision": "delete revisions",
+       "action-deletelogentry": "delete log entries",
+       "action-deletedhistory": "view a page's deleted history",
+       "action-deletedtext": "view deleted revision text",
        "action-browsearchive": "search deleted pages",
-       "action-undelete": "undelete this page",
-       "action-suppressrevision": "review and restore this hidden revision",
+       "action-undelete": "undelete pages",
+       "action-suppressrevision": "review and restore hidden revisions",
        "action-suppressionlog": "view this private log",
        "action-block": "block this user from editing",
        "action-protect": "change protection levels for this page",
        "action-userrights-interwiki": "edit user rights of users on other wikis",
        "action-siteadmin": "lock or unlock the database",
        "action-sendemail": "send emails",
+       "action-editmyoptions": "edit your preferences",
        "action-editmywatchlist": "edit your watchlist",
        "action-viewmywatchlist": "view your watchlist",
        "action-viewmyprivateinfo": "view your private information",
        "emailccsubject": "Copy of your message to $1: $2",
        "emailsent": "Email sent",
        "emailsenttext": "Your email message has been sent.",
 -      "emailuserfooter": "This email was {{GENDER:$1|sent}} by $1 to {{GENDER:$2|$2}} by the \"{{int:emailuser}}\" function at {{SITENAME}}.",
 +      "emailuserfooter": "This email was {{GENDER:$1|sent}} by $1 to {{GENDER:$2|$2}} by the \"{{int:emailuser}}\" function at {{SITENAME}}. {{GENDER:$2|Your}} email will be sent directly to the {{GENDER:$1|original sender}}, revealing {{GENDER:$2|your}} email address to {{GENDER:$1|them}}.",
        "usermessage-summary": "Leaving system message.",
        "usermessage-editor": "System messenger",
        "usermessage-template": "MediaWiki:UserMessage",
        "usercssispublic": "Please note: CSS subpages should not contain confidential data as they are viewable by other users.",
        "restrictionsfield-badip": "Invalid IP address or range: $1",
        "restrictionsfield-label": "Allowed IP ranges:",
-       "restrictionsfield-help": "One IP address or CIDR range per line. To enable everything, use<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+       "restrictionsfield-help": "One IP address or CIDR range per line. To enable everything, use<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+       "revid": "r$1",
+       "pageid": "page ID $1"
  }
diff --combined languages/i18n/qqq.json
        "october-gen": "{{doc-months|10|genitive}}\n{{Identical|October}}",
        "november-gen": "{{doc-months|11|genitive}}\n{{Identical|November}}",
        "december-gen": "{{doc-months|12|genitive}}\n{{Identical|December}}",
 -      "jan": "{{doc-months|1|short}}",
 -      "feb": "{{doc-months|2|short}}",
 -      "mar": "{{doc-months|3|short}}",
 -      "apr": "{{doc-months|4|short}}",
 -      "may": "{{doc-months|5|short}}",
 -      "jun": "{{doc-months|6|short}}",
 +      "jan": "{{doc-months|1|short}}\n{{Identical|January}}",
 +      "feb": "{{doc-months|2|short}}\n{{Identical|February}}",
 +      "mar": "{{doc-months|3|short}}\n{{Identical|March}}",
 +      "apr": "{{doc-months|4|short}}\n{{Identical|April}}",
 +      "may": "{{doc-months|5|short}}\n{{Identical|May}}",
 +      "jun": "{{doc-months|6|short}}\n{{Identical|June}}",
        "jul": "{{doc-months|7|short}}",
        "aug": "{{doc-months|8|short}}",
        "sep": "{{doc-months|9|short}}",
        "userrights-lookup-user": "Label text when managing user rights ([[Special:UserRights]])",
        "userrights-user-editname": "Displayed on [[Special:UserRights]].",
        "editusergroup": "Button name, in page [[Special:Userrights]], in the section named {{MediaWiki:userrights-lookup-user}}. The username or gender of the user is not known when this message is displayed.",
 -      "editinguser": "Appears on [[Special:UserRights]]. Parameters:\n* $1 - a plaintext username\n* $2 - user tool links. e.g. \"(Talk | contribs | block | send email)\"",
 -      "userrights-editusergroup": "Parameter:\n* $1 - (Optional) a username, can be used for GENDER",
 +      "editinguser": "Appears on [[Special:UserRights]]. Parameters:\n* $1 - a plaintext username\n* $2 - user tool links. e.g. \"(Talk | contribs | block | send email)\"\n\nRelated messages:\n* {{msg-mw|viewinguserrights}}",
 +      "viewinguserrights": "Appears on [[Special:UserRights]]. Parameters:\n* $1 - a plaintext username\n* $2 - user tool links. e.g. \"(Talk | contribs | block | send email)\"\n\nRelated messages:\n* {{msg-mw|editinguser}}",
 +      "userrights-editusergroup": "Parameter:\n* $1 - (Optional) a username, can be used for GENDER\n\nRelated messages:\n* {{msg-mw|userrights-viewusergroup}}",
 +      "userrights-viewusergroup": "Parameter:\n* $1 - (Optional) a username, can be used for GENDER\n\nRelated messages:\n* {{msg-mw|userrights-editusergroup}}",
        "saveusergroups": "Button text when editing user groups.\nParameters:\n* $1 - username, for GENDER support",
        "userrights-groupsmember": "Used when editing user groups in [[Special:Userrights]].\n\nThe message is followed by a list of group names.\n\nParameters:\n* $1 - (Optional) the number of items in the list following the message, for PLURAL\n* $2 - (Optional) the user name, for GENDER",
        "userrights-groupsmember-auto": "Used when editing user groups in [[Special:Userrights]]. The message is followed by a list of group names.\n\n\"Implicit\" is for groups that the user was automatically added to (such as \"autoconfirmed\"); cf. {{msg-mw|userrights-groupsmember}}\n\nParameters:\n* $1 - (Optional) the number of items in the list following the message, for PLURAL\n* $2 - (Optional) the user name, for GENDER",
        "action-delete": "{{Doc-action|delete}}",
        "action-deleterevision": "{{Doc-action|deleterevision}}",
        "action-deletedhistory": "{{Doc-action|deletedhistory}}",
+       "action-deletedtext": "{{Doc-action|deletedtext}}",
+       "action-deletelogentry": "{{Doc-action|deletelogentry}}",
        "action-browsearchive": "{{Doc-action|browsearchive}}",
        "action-undelete": "{{Doc-action|undelete}}",
        "action-suppressrevision": "{{Doc-action|suppressrevision}}",
        "action-sendemail": "{{doc-action|sendemail}}\n{{Identical|E-mail}}",
        "action-editmywatchlist": "{{doc-action|editmywatchlist}}\n{{Identical|Edit your watchlist}}",
        "action-viewmywatchlist": "{{doc-action|viewmywatchlist}}\n{{Identical|View your watchlist}}",
+       "action-editmyoptions": "{{Doc-action|editmyoptions}}",
        "action-viewmyprivateinfo": "{{doc-action|viewmyprivateinfo}}",
        "action-editmyprivateinfo": "{{doc-action|editmyprivateinfo}}",
        "action-editcontentmodel": "{{doc-action|editcontentmodel}}",
        "usercssispublic": "A reminder to users that CSS subpages are not preferences but normal pages, and thus can be viewed by other users and the general public. This message is shown to a user whenever they are editing a subpage in their own user-space that ends in .css. See also {{msg-mw|userjsispublic}}",
        "restrictionsfield-badip": "An error message shown when one entered an invalid IP address or range in a restrictions field (such as Special:BotPassword). $1 is the IP address.",
        "restrictionsfield-label": "Field label shown for restriction fields (e.g. on Special:BotPassword).",
-       "restrictionsfield-help": "Placeholder text displayed in restriction fields (e.g. on Special:BotPassword)."
+       "restrictionsfield-help": "Placeholder text displayed in restriction fields (e.g. on Special:BotPassword).",
+       "revid": "Used to format a revision ID number in text. Parameters:\n* $1 - Revision ID number.",
+       "pageid": "Used to format a page ID number in text. Parameters:\n* $1 - Page ID number."
  }