Merge "Moved addAutopromoteOnceGroups() call to a deferred update"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Mon, 1 Jun 2015 19:24:56 +0000 (19:24 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 1 Jun 2015 19:24:56 +0000 (19:24 +0000)
70 files changed:
.jshintrc
.mailmap
CREDITS
Gemfile
Gemfile.lock
RELEASE-NOTES-1.26
autoload.php
includes/MWTimestamp.php
includes/api/ApiQueryCategoryMembers.php
includes/api/i18n/ko.json
includes/api/i18n/zh-hans.json
includes/changes/RecentChange.php
includes/deferred/DeferredUpdates.php
includes/exception/HttpError.php
includes/installer/i18n/es.json
includes/installer/i18n/nn.json
includes/installer/i18n/wuu.json
includes/jobqueue/Job.php
includes/jobqueue/jobs/ActivityUpdateJob.php
includes/jobqueue/jobs/AssembleUploadChunksJob.php
includes/jobqueue/jobs/DoubleRedirectJob.php
includes/jobqueue/jobs/DuplicateJob.php
includes/jobqueue/jobs/EmaillingJob.php
includes/jobqueue/jobs/EnotifNotifyJob.php
includes/jobqueue/jobs/EnqueueJob.php
includes/jobqueue/jobs/HTMLCacheUpdateJob.php
includes/jobqueue/jobs/NullJob.php
includes/jobqueue/jobs/PublishStashedFileJob.php
includes/jobqueue/jobs/RecentChangesUpdateJob.php
includes/jobqueue/jobs/RefreshLinksJob.php
includes/jobqueue/jobs/ThumbnailRenderJob.php
includes/jobqueue/jobs/UploadFromUrlJob.php
includes/parser/MWTidy.php
includes/parser/Parser.php
includes/parser/ParserDiffTest.php
includes/parser/Preprocessor_DOM.php
includes/parser/Preprocessor_Hash.php
includes/parser/StripState.php
includes/specials/SpecialMediaStatistics.php
includes/specials/SpecialUndelete.php
includes/upload/UploadBase.php
includes/utils/MWFunction.php [deleted file]
languages/Language.php
languages/LanguageConverter.php
languages/classes/LanguageEt.php
languages/i18n/arq.json
languages/i18n/ca.json
languages/i18n/es.json
languages/i18n/gl.json
languages/i18n/hi.json
languages/i18n/ko.json
languages/i18n/ku-latn.json
languages/i18n/nn.json
languages/i18n/ru.json
languages/i18n/tr.json
languages/i18n/uk.json
languages/i18n/wuu.json
maintenance/jsduck/categories.json
resources/Resources.php
resources/src/mediawiki.skinning/elements.css
resources/src/mediawiki.ui/components/icons.less
resources/src/mediawiki.widgets/AUTHORS.txt [new file with mode: 0644]
resources/src/mediawiki.widgets/LICENSE.txt [new file with mode: 0644]
resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css [new file with mode: 0644]
resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js [new file with mode: 0644]
resources/src/mediawiki.widgets/mw.widgets.js [new file with mode: 0644]
resources/src/mediawiki/mediawiki.Title.js
resources/src/mediawiki/mediawiki.js
tests/phpunit/includes/exception/HttpErrorTest.php [new file with mode: 0644]
tests/phpunit/includes/utils/MWFunctionTest.php [deleted file]

index 4bb2440..d72c31d 100644 (file)
--- a/.jshintrc
+++ b/.jshintrc
@@ -21,6 +21,7 @@
        "globals": {
                "mediaWiki": true,
                "JSON": true,
+               "OO": true,
                "jQuery": false,
                "QUnit": false,
                "sinon": false
index a1f0054..12ff31d 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -22,6 +22,7 @@ ayush_garg <ayush.ce13@iitp.ac.in>
 Bahodir Mansurov <bmansurov@wikimedia.org>
 Bartosz Dziewoński <matma.rex@gmail.com>
 Bartosz Dziewoński <matma.rex@gmail.com> <matmarex@wikimedia.org>
+Bartosz Dziewoński <matma.rex@gmail.com> <bdziewonski@wikimedia.org>
 Bene <benestar.wikimedia@gmail.com>
 Brad Jorsch <bjorsch@wikimedia.org>
 Brian Wolff <bawolff+wn@gmail.com>
diff --git a/CREDITS b/CREDITS
index 7725034..22dee7b 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -240,6 +240,7 @@ following names for their contribution to the product.
 * Van de Bugger
 * Ville Stadista
 * Vitaliy Filippov
+* Vivek Ghaisas
 * Waldir Pimenta
 * William Demchick
 * Yusuke Matsubara
diff --git a/Gemfile b/Gemfile
index 6f9c053..a67be6b 100644 (file)
--- a/Gemfile
+++ b/Gemfile
@@ -3,5 +3,5 @@
 
 source 'https://rubygems.org'
 
-gem 'mediawiki_selenium', '~> 1.0.1'
+gem 'mediawiki_selenium', '~> 1.2.0'
 gem 'rubocop', require: false
index 0b360ae..0d0a5c2 100644 (file)
@@ -5,7 +5,7 @@ GEM
     astrolabe (1.3.0)
       parser (>= 2.2.0.pre.3, < 3.0)
     builder (3.2.2)
-    childprocess (0.5.5)
+    childprocess (0.5.6)
       ffi (~> 1.0, >= 1.0.11)
     cucumber (1.3.19)
       builder (>= 2.1.2)
@@ -13,11 +13,11 @@ GEM
       gherkin (~> 2.12)
       multi_json (>= 1.7.5, < 2.0)
       multi_test (>= 0.1.2)
-    data_magic (0.20)
+    data_magic (0.21)
       faker (>= 1.1.2)
       yml_reader (>= 0.4)
     diff-lcs (1.2.5)
-    domain_name (0.5.23)
+    domain_name (0.5.24)
       unf (>= 0.0.5, < 1.0.0)
     faker (1.4.3)
       i18n (~> 0.5)
@@ -26,7 +26,7 @@ GEM
     faraday-cookie_jar (0.0.6)
       faraday (>= 0.7.4)
       http-cookie (~> 1.0.0)
-    ffi (1.9.6)
+    ffi (1.9.8)
     gherkin (2.12.2)
       multi_json (~> 1.3)
     headless (1.0.2)
@@ -37,7 +37,7 @@ GEM
     mediawiki_api (0.3.1)
       faraday (~> 0.9, >= 0.9.0)
       faraday-cookie_jar (~> 0.0, >= 0.0.6)
-    mediawiki_selenium (1.0.1)
+    mediawiki_selenium (1.2.0)
       cucumber (~> 1.3, >= 1.3.10)
       headless (~> 1.0, >= 1.0.1)
       json (~> 1.8, >= 1.8.1)
@@ -47,12 +47,12 @@ GEM
       rspec-expectations (~> 2.14, >= 2.14.4)
       syntax (~> 1.2, >= 1.2.0)
       thor (~> 0.19, >= 0.19.1)
-    mime-types (2.4.3)
+    mime-types (2.6.1)
     multi_json (1.11.0)
     multi_test (0.1.2)
     multipart-post (2.0.0)
     netrc (0.10.3)
-    page-object (1.0.3)
+    page-object (1.1.0)
       page_navigation (>= 0.9)
       selenium-webdriver (>= 2.44.0)
       watir-webdriver (>= 0.6.11)
@@ -62,7 +62,8 @@ GEM
       ast (>= 1.1, < 3.0)
     powerpack (0.1.0)
     rainbow (2.0.0)
-    rest-client (1.7.3)
+    rest-client (1.8.0)
+      http-cookie (>= 1.0.2, < 2.0)
       mime-types (>= 1.16, < 3.0)
       netrc (~> 0.7)
     rspec-expectations (2.99.2)
@@ -84,15 +85,15 @@ GEM
     thor (0.19.1)
     unf (0.1.4)
       unf_ext
-    unf_ext (0.0.6)
+    unf_ext (0.0.7.1)
     watir-webdriver (0.7.0)
       selenium-webdriver (>= 2.45)
-    websocket (1.2.1)
+    websocket (1.2.2)
     yml_reader (0.5)
 
 PLATFORMS
   ruby
 
 DEPENDENCIES
-  mediawiki_selenium (~> 1.0.1)
+  mediawiki_selenium (~> 1.2.0)
   rubocop
index 588dc56..af9e9d2 100644 (file)
@@ -44,16 +44,29 @@ changes to languages because of Bugzilla reports.
 * Added PageHistoryPager::doBatchLookups hook.
 * Added ParserCacheSaveComplete to ParserCache
 * supportsDirectEditing and supportsDirectApiEditing methods added to
-ContentHandler, to provide a way for ApiEditPage and EditPage to check
-if direct editing of content is allowed. These methods return false,
-by default for the ContentHandler base class and true for TextContentHandler
-and it's derivative classes (everything in core). For Content types that
-do not support direct editing, an alternative mechanism should be provided
-for editing, such as action overrides or specific api modules.
+  ContentHandler, to provide a way for ApiEditPage and EditPage to check
+  if direct editing of content is allowed. These methods return false,
+  by default for the ContentHandler base class and true for TextContentHandler
+  and it's derivative classes (everything in core). For Content types that
+  do not support direct editing, an alternative mechanism should be provided
+  for editing, such as action overrides or specific api modules.
 * mediaWiki.confirmCloseWindow now returns an object of functions, instead of
-one function. The callback can't be called directly any more. The callback function
-is replaced with confirmCloseWindow.release().
+  one function. The callback can't be called directly any more. The callback
+  function is replaced with confirmCloseWindow.release().
 * Removed maintenance script deleteImageMemcached.php.
+* MWFunction::newObj() was removed (deprecated in 1.25).
+  ObjectFactory::getObjectFromSpec() should be used instead.
+* The parser will no longer randomize the string it uses to mark the place of
+  items that were stripped during parsing. It will use a fixed string instead.
+  This causes the parser to re-use the regular expressions it uses to search
+  and replace markers rather than generate novel expressions on each parse.
+  Re-using regular expressions will improve performance on HHVM and the
+  forthcoming PHP 7. The interfaces changes accompanying this change are:
+  - Parser::getRandomString() and Parser::uniqPrefix() have been deprecated.
+  - The $uniq_prefix argument for Parser::extractTagsAndParams() and the
+    $prefix argument for StripState::_construct() are deprecated and their
+    value is ignored.
+
 
 == Compatibility ==
 
index 8749310..612bc96 100644 (file)
@@ -708,7 +708,6 @@ $wgAutoloadLocalClasses = array(
        'MWDocGen' => __DIR__ . '/maintenance/mwdocgen.php',
        'MWException' => __DIR__ . '/includes/exception/MWException.php',
        'MWExceptionHandler' => __DIR__ . '/includes/exception/MWExceptionHandler.php',
-       'MWFunction' => __DIR__ . '/includes/utils/MWFunction.php',
        'MWHookException' => __DIR__ . '/includes/Hooks.php',
        'MWHttpRequest' => __DIR__ . '/includes/HttpFunctions.php',
        'MWMemcached' => __DIR__ . '/includes/objectcache/MemcachedClient.php',
index ea91470..f2bd6ba 100644 (file)
@@ -199,42 +199,19 @@ class MWTimestamp {
         *
         * @since 1.20
         * @since 1.22 Uses Language::getHumanTimestamp to produce the timestamp
+        * @deprecated since 1.26 Use Language::getHumanTimestamp directly
         *
-        * @param MWTimestamp|null $relativeTo The base timestamp to compare to
-        *   (defaults to now).
-        * @param User|null $user User the timestamp is being generated for (or null
-        *   to use main context's user).
-        * @param Language|null $lang Language to use to make the human timestamp
-        *   (or null to use main context's language).
+        * @param MWTimestamp|null $relativeTo The base timestamp to compare to (defaults to now)
+        * @param User|null $user User the timestamp is being generated for (or null to use main context's user)
+        * @param Language|null $lang Language to use to make the human timestamp (or null to use main context's language)
         * @return string Formatted timestamp
         */
-       public function getHumanTimestamp( MWTimestamp $relativeTo = null,
-               User $user = null, Language $lang = null
-       ) {
-               if ( $relativeTo === null ) {
-                       $relativeTo = new self();
-               }
-               if ( $user === null ) {
-                       $user = RequestContext::getMain()->getUser();
-               }
+       public function getHumanTimestamp( MWTimestamp $relativeTo = null, User $user = null, Language $lang = null ) {
                if ( $lang === null ) {
                        $lang = RequestContext::getMain()->getLanguage();
                }
 
-               // Adjust for the user's timezone.
-               $offsetThis = $this->offsetForUser( $user );
-               $offsetRel = $relativeTo->offsetForUser( $user );
-
-               $ts = '';
-               if ( Hooks::run( 'GetHumanTimestamp', array( &$ts, $this, $relativeTo, $user, $lang ) ) ) {
-                       $ts = $lang->getHumanTimestamp( $this, $relativeTo, $user );
-               }
-
-               // Reset the timezone on the objects.
-               $this->timestamp->sub( $offsetThis );
-               $relativeTo->timestamp->sub( $offsetRel );
-
-               return $ts;
+               return $lang->getHumanTimestamp( $this, $relativeTo, $user );
        }
 
        /**
index ec0c1d1..4042bd7 100644 (file)
@@ -158,7 +158,9 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
                                        }
                                        $startsortkey = pack( 'H*', $params['starthexsortkey'] );
                                } else {
-                                       $this->logFeatureUsage( 'list=categorymembers&cmstartsortkey' );
+                                       if ( $params['startsortkey'] !== null ) {
+                                               $this->logFeatureUsage( 'list=categorymembers&cmstartsortkey' );
+                                       }
                                        $startsortkey = $params['startsortkey'];
                                }
                                if ( $params['endsortkeyprefix'] !== null ) {
@@ -169,7 +171,9 @@ class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
                                        }
                                        $endsortkey = pack( 'H*', $params['endhexsortkey'] );
                                } else {
-                                       $this->logFeatureUsage( 'list=categorymembers&cmendsortkey' );
+                                       if ( $params['endsortkey'] !== null ) {
+                                               $this->logFeatureUsage( 'list=categorymembers&cmendsortkey' );
+                                       }
                                        $endsortkey = $params['endsortkey'];
                                }
 
index a9bdf2b..3ff138d 100644 (file)
        "apihelp-edit-param-bot": "이 편집을 봇으로 표시.",
        "apihelp-edit-example-edit": "문서 편집",
        "apihelp-expandtemplates-param-title": "문서 제목",
+       "apihelp-login-param-name": "계정 이름.",
+       "apihelp-login-param-password": "비밀번호.",
+       "apihelp-login-example-login": "로그인.",
+       "apihelp-move-description": "문서 이동하기.",
+       "api-help-title": "미디어위키 API 도움말",
+       "api-help-lead": "이 페이지는 자동으로 생성된 미디어위키 API 도움말 문서입니다.\n\n설명 문서 및 예시: https://www.mediawiki.org/wiki/API",
+       "api-help-main-header": "메인 모듈",
+       "api-help-flag-deprecated": "이 모듈은 사용되지 않습니다.",
+       "api-help-flag-readrights": "이 모듈은 read 권한을 요구합니다.",
+       "api-help-flag-writerights": "이 모듈은 write 권한을 요구합니다.",
+       "api-help-flag-mustbeposted": "이 모듈은 POST 요청만을 허용합니다.",
+       "api-help-source": "출처: $1",
+       "api-help-license": "라이선스: [[$1|$2]]",
+       "api-help-license-noname": "라이선스: [[$1|링크 참조]]",
+       "api-help-license-unknown": "라이선스: <span class=\"apihelp-unknown\">알 수 없음</span>",
+       "api-help-parameters": "{{PLURAL:$1|변수}}:",
+       "api-help-param-deprecated": "사용 중지됨.",
+       "api-help-param-required": "이 변수는 필수 입력 사항입니다.",
+       "api-help-datatypes-header": "데이터 유형",
        "api-help-datatypes": "API 요청 내 몇몇 매개변수형에 대해 더 자세히 설명해보겠습니다:\n;boolean\n:Boolean 매개변수들은 HTML 체크박스처럼 동작합니다: 만약 매개변수가 지저오딨다면, 값에 상관없이 참의 값으로 여겨집니다. 거짓값은 매개변수 전체를 생략하여 표현해보세요.\n;timestamp\n:타임스팸프들은 여러 형식으로 표현될 수 있으나 ISO 8601 날짜와 시간이 추천됩니다. 모든 시간은 UTC이어야 하며, 포함된 시간대는 모두 무시됩니다.\n:* ISO 8601 날짜와 시간, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (구두점과 <kbd>Z</kbd>는 선택입니다.)\n:* ISO 8601 날짜와 시간과 (무시되는) 소수 초, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>.<var>00001</var>Z</kbd> (대시, 콜론과 <kbd>Z</kbd> 는 선택입니다.)\n:* 미디어위키 형식, <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* 일반적인 수 형식 <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (<kbd>GMT</kbd>, <kbd>+<var>##</var></kbd>, 또는 <kbd>-<var>##</var></kbd>와 같은 선택적 시간대는 무시됩니다)\n:*RFC 2822 형식 (시간대는 생략될 수 있음), <kbd><var>Mon</var>, <var>15</var> <var>Jan</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* RFC 850 형식 (시간대는 생략될 수 있음), <kbd><var>Monday</var>, <var>15</var>-<var>Jan</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* C ctime 형식, <kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* 1부터 13자리까지의 숫자로 표현된 1970-01-01T00:00:00Z 부터 흐른 시간(초)",
+       "api-help-param-type-integer": "유형: {{PLURAL:$1|1=정수|2=정수 목록}}",
+       "api-help-param-type-boolean": "유형: 부울 ([[Special:ApiHelp/main#main/datatypes|자세한 정보]])",
        "api-help-param-list": "{{PLURAL:$1|1=하나의 값|2=값 (\"{{!}}\"로 구분)}}: $2",
-       "api-help-param-default": "기본값: $1"
+       "api-help-param-default": "기본값: $1",
+       "api-help-param-default-empty": "기본값: <span class=\"apihelp-empty\">(비어 있음)</span>",
+       "api-help-param-no-description": "<span class=\"apihelp-empty\">(설명 없음)</span>",
+       "api-help-examples": "{{PLURAL:$1|예시}}:",
+       "api-help-permissions": "{{PLURAL:$1|권한}}:",
+       "api-help-permissions-granted-to": "{{PLURAL:$1|다음 그룹에 부여됨}}: $2",
+       "api-credits": "API 개발자:\n* Roan Kattouw (선임 개발자, 2007년 9월–2009년)\n* Victor Vasiliev\n* Bryan Tong Minh\n* Sam Reed\n* Yuri Astrakhan (초기 개발자, 선임 개발자 2006년 9월~2007년 9월)\n* Brad Jorsch (선임 개발자 2013년–현재)\n\n당신의 의견이나 제안, 질문은 mediawiki-api@lists.wikimedia.org 로 보내주시거나,\nhttps://phabricator.wikimedia.org/ 에 버그 신고를 해 주시기 바랍니다.."
 }
index 6849b27..e576f6d 100644 (file)
        "api-help-param-deprecated": "不推荐使用。",
        "api-help-param-required": "这个参数是必须的。",
        "api-help-datatypes-header": "数据类型",
-       "api-help-datatypes": "一些在API请求中的参数类型需要更进一步解释:\n;boolean\n:布尔参数就像HTML复选框一样工作:如果指定参数,无论何值都被认为是真。如果要假值,则可完全忽略参数。\n;timestamp\n:时间戳可被指定为很多格式。推荐使用ISO 8601日期和时间标准。所有时间为UTC时间,包含的任何时区会被忽略。\n:* ISO 8601日期和时间,<kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd>(标点和<kbd>Z</kbd>是可选项)\n:* 带小数秒(会被忽略)的ISO 8601日期和时间,<kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>.<var>00001</var>Z</kbd>(破折号、括号和<kbd>Z</kbd>是可选的)\n:* MediaWiki格式,<kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* 一般数字格式,<kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>(<kbd>GMT</kbd>、<kbd>+<var>##</var></kbd>或<kbd>-<var>##</var></kbd>的可选时区会被忽略)\n:* EXIF格式,<kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* RFC 2822格式(时区可能会被省略),<kbd><var>Mon</var>, <var>15</var> <var>Jan</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* RFC 850格式(时区可能会被省略),<kbd><var>Monday</var>, <var>15</var>-<var>Jan</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* C ctime格式,<kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* 秒数是从1970-01-01T00:00:00Z开始,作为1到13位数的整数",
+       "api-help-datatypes": "一些在API请求中的参数类型需要更进一步解释:\n;boolean\n:布尔参数就像HTML复选框一样工作:如果指定参数,无论何值都被认为是真。如果要假值,则可完全忽略参数。\n;timestamp\n:时间戳可被指定为很多格式。推荐使用ISO 8601日期和时间标准。所有时间为UTC时间,包含的任何时区会被忽略。\n:* ISO 8601日期和时间,<kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd>(标点和<kbd>Z</kbd>是可选项)\n:* 带小数秒(会被忽略)的ISO 8601日期和时间,<kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>.<var>00001</var>Z</kbd>(破折号、括号和<kbd>Z</kbd>是可选的)\n:* MediaWiki格式,<kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* 一般数字格式,<kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>(<kbd>GMT</kbd>、<kbd>+<var>##</var></kbd>或<kbd>-<var>##</var></kbd>的可选时区会被忽略)\n:* EXIF格式,<kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* RFC 2822格式(时区可能会被省略),<kbd><var>Mon</var>, <var>15</var> <var>Jan</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* RFC 850格式(时区可能会被省略),<kbd><var>Monday</var>, <var>15</var>-<var>Jan</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* C ctime格式,<kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* 秒数是从1970-01-01T00:00:00Z开始,作为1到13位数的整数(除了<kbd>0</kbd>)\n:* 字符串<kbd>now</kbd>",
        "api-help-param-type-limit": "类型:整数或<kbd>max</kbd>",
        "api-help-param-type-integer": "类型:{{PLURAL:$1|1=整数|2=整数列表}}",
        "api-help-param-type-boolean": "类型:布尔值([[Special:ApiHelp/main#main/datatypes|详细信息]])",
index 7ea6777..13e94db 100644 (file)
@@ -164,7 +164,7 @@ class RecentChange {
         * Obtain the recent change with a given rc_id value
         *
         * @param int $rcid The rc_id value to retrieve
-        * @return RecentChange
+        * @return RecentChange|null
         */
        public static function newFromId( $rcid ) {
                return self::newFromConds( array( 'rc_id' => $rcid ), __METHOD__ );
@@ -176,7 +176,7 @@ class RecentChange {
         * @param array $conds Array of conditions
         * @param mixed $fname Override the method name in profiling/logs
         * @param array $options Query options
-        * @return RecentChange
+        * @return RecentChange|null
         */
        public static function newFromConds( $conds, $fname = __METHOD__, $options = array() ) {
                $dbr = wfGetDB( DB_SLAVE );
index 082d435..b7e5b0a 100644 (file)
@@ -39,6 +39,7 @@ interface DeferrableUpdate {
  * Deferred updates can be run at the end of the request,
  * after the HTTP response has been sent. In CLI mode, updates
  * are only deferred until there is no local master DB transaction.
+ * When updates are deferred, they go into a simple FIFO queue.
  *
  * @since 1.19
  */
index b81c573..d3ee9b9 100644 (file)
@@ -35,7 +35,7 @@ class HttpError extends MWException {
         *
         * @param int $httpCode HTTP status code to send to the client
         * @param string|Message $content Content of the message
-        * @param string|Message $header Content of the header (\<title\> and \<h1\>)
+        * @param string|Message|null $header Content of the header (\<title\> and \<h1\>)
         */
        public function __construct( $httpCode, $content, $header = null ) {
                parent::__construct( $content );
@@ -113,21 +113,21 @@ class HttpError extends MWException {
         */
        public function getHTML() {
                if ( $this->header === null ) {
-                       $header = HttpStatus::getMessage( $this->httpCode );
+                       $titleHtml = htmlspecialchars( HttpStatus::getMessage( $this->httpCode ) );
                } elseif ( $this->header instanceof Message ) {
-                       $header = $this->header->escaped();
+                       $titleHtml = $this->header->escaped();
                } else {
-                       $header = htmlspecialchars( $this->header );
+                       $titleHtml = htmlspecialchars( $this->header );
                }
 
                if ( $this->content instanceof Message ) {
-                       $content = $this->content->escaped();
+                       $contentHtml = $this->content->escaped();
                } else {
-                       $content = htmlspecialchars( $this->content );
+                       $contentHtml = htmlspecialchars( $this->content );
                }
 
                return "<!DOCTYPE html>\n" .
-               "<html><head><title>$header</title></head>\n" .
-               "<body><h1>$header</h1><p>$content</p></body></html>\n";
+               "<html><head><title>$titleHtml</title></head>\n" .
+               "<body><h1>$titleHtml</h1><p>$contentHtml</p></body></html>\n";
        }
 }
index fd929be..995d576 100644 (file)
        "config-install-begin": "Al pulsar en «{{int:config-continue}}» comenzará el proceso de instalación de MediaWiki.\nSi quieres realizar algún cambio, pulsa en «{{int:config-back}}».",
        "config-install-step-done": "hecho",
        "config-install-step-failed": "falló",
-       "config-install-extensions": "Extensiones inclusive",
+       "config-install-extensions": "Incluyendo extensiones",
        "config-install-database": "Configurando la base de datos",
        "config-install-schema": "Creando el esquema",
        "config-install-pg-schema-not-exist": "El esquema PostgreSQL no existe.",
index 5d75be7..06c1469 100644 (file)
@@ -2,7 +2,8 @@
        "@metadata": {
                "authors": [
                        "Harald Khan",
-                       "Nghtwlkr"
+                       "Nghtwlkr",
+                       "Njardarlogar"
                ]
        },
        "config-your-language": "Språket ditt:",
@@ -36,6 +37,7 @@
        "config-postgres-old": "PostgreSQL $1 eller seinare krevst, du har $2.",
        "config-email-settings": "E-postinnstillingar",
        "config-logo": "Logo-URL:",
+       "config-help": "hjelp",
        "mainpagetext": "'''MediaWiki er no installert.'''",
        "mainpagedocfooter": "Sjå [//meta.wikimedia.org/wiki/Help:Contents brukarmanualen] for informasjon om bruk og oppsettshjelp for wikiprogramvara.\n\n==Kome i gang==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Liste over oppsettsinnstillingar]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Spørsmål og svar om MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce E-postliste med informasjon om nye MediaWiki-versjonar]"
 }
index 01052d3..283ad3c 100644 (file)
@@ -1,9 +1,11 @@
 {
        "@metadata": {
                "authors": [
-                       "Wu-chinese.com"
+                       "Wu-chinese.com",
+                       "Poiuyt"
                ]
        },
+       "config-information": "信息",
        "mainpagetext": "'''MediaWiki安装成功哉!'''",
        "mainpagedocfooter": "请访问[//meta.wikimedia.org/wiki/Help:Contents 用户手册]以获得使用此维基软件个信息!\n\n== 入门 ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings MediaWiki 配置设置列表]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki 常见问题解答]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki 发布邮件列表]"
 }
index f8de0b5..87bd836 100644 (file)
@@ -32,7 +32,7 @@ abstract class Job implements IJobSpecification {
        /** @var string */
        public $command;
 
-       /** @var array|bool Array of job parameters or false if none */
+       /** @var array Array of job parameters */
        public $params;
 
        /** @var array Additional queue metadata */
@@ -58,11 +58,11 @@ abstract class Job implements IJobSpecification {
         *
         * @param string $command Job command
         * @param Title $title Associated title
-        * @param array|bool $params Job parameters
+        * @param array $params Job parameters
         * @throws MWException
         * @return Job
         */
-       public static function factory( $command, Title $title, $params = false ) {
+       public static function factory( $command, Title $title, $params = array() ) {
                global $wgJobClasses;
                if ( isset( $wgJobClasses[$command] ) ) {
                        $class = $wgJobClasses[$command];
@@ -80,7 +80,7 @@ abstract class Job implements IJobSpecification {
        public function __construct( $command, $title, $params = false ) {
                $this->command = $command;
                $this->title = $title;
-               $this->params = $params;
+               $this->params = is_array( $params ) ? $params : array(); // sanity
 
                // expensive jobs may set this to true
                $this->removeDuplicates = false;
index 495bda9..f146e6e 100644 (file)
@@ -27,7 +27,7 @@
  * @since 1.26
  */
 class ActivityUpdateJob extends Job {
-       function __construct( $title, $params ) {
+       function __construct( Title $title, array $params ) {
                parent::__construct( 'activityUpdateJob', $title, $params );
 
                if ( !isset( $params['type'] ) ) {
index b7f09e7..a1de77e 100644 (file)
@@ -27,7 +27,7 @@
  * @ingroup Upload
  */
 class AssembleUploadChunksJob extends Job {
-       public function __construct( $title, $params ) {
+       public function __construct( Title $title, array $params ) {
                parent::__construct( 'AssembleUploadChunks', $title, $params );
                $this->removeDuplicates = true;
        }
index 2561f2f..ab63896 100644 (file)
@@ -40,6 +40,16 @@ class DoubleRedirectJob extends Job {
        /** @var User */
        private static $user;
 
+       /**
+        * @param Title $title
+        * @param array $params
+        */
+       function __construct( Title $title, array $params ) {
+               parent::__construct( 'fixDoubleRedirect', $title, $params );
+               $this->reason = $params['reason'];
+               $this->redirTitle = Title::newFromText( $params['redirTitle'] );
+       }
+
        /**
         * Insert jobs into the job queue to fix redirects to the given title
         * @param string $reason The reason for the fix, see message
@@ -81,16 +91,6 @@ class DoubleRedirectJob extends Job {
                JobQueueGroup::singleton()->push( $jobs );
        }
 
-       /**
-        * @param Title $title
-        * @param array|bool $params
-        */
-       function __construct( $title, $params = false ) {
-               parent::__construct( 'fixDoubleRedirect', $title, $params );
-               $this->reason = $params['reason'];
-               $this->redirTitle = Title::newFromText( $params['redirTitle'] );
-       }
-
        /**
         * @return bool
         */
index c5e3a23..068d531 100644 (file)
@@ -33,7 +33,7 @@ final class DuplicateJob extends Job {
         * @param Title $title
         * @param array $params Job parameters
         */
-       function __construct( $title, $params ) {
+       function __construct( Title $title, array $params ) {
                parent::__construct( 'duplicate', $title, $params );
        }
 
index df8ae63..68e96fc 100644 (file)
@@ -28,7 +28,7 @@
  * @ingroup JobQueue
  */
 class EmaillingJob extends Job {
-       function __construct( $title, $params ) {
+       function __construct( Title $title = null, array $params ) {
                parent::__construct( 'sendMail', Title::newMainPage(), $params );
        }
 
index 1ed99a5..9a5c3c7 100644 (file)
@@ -27,7 +27,7 @@
  * @ingroup JobQueue
  */
 class EnotifNotifyJob extends Job {
-       function __construct( $title, $params ) {
+       function __construct( Title $title, array $params ) {
                parent::__construct( 'enotifNotify', $title, $params );
        }
 
index 4514e19..ca597ca 100755 (executable)
@@ -40,7 +40,7 @@ final class EnqueueJob extends Job {
         * @param Title $title
         * @param array $params Job parameters
         */
-       function __construct( $title, $params ) {
+       function __construct( Title $title, array $params ) {
                parent::__construct( 'enqueue', $title, $params );
        }
 
index e5e521c..a9010c2 100644 (file)
@@ -34,7 +34,7 @@
  * @ingroup JobQueue
  */
 class HTMLCacheUpdateJob extends Job {
-       function __construct( $title, $params = '' ) {
+       function __construct( Title $title, array $params ) {
                parent::__construct( 'htmlCacheUpdate', $title, $params );
                // Base backlink purge jobs can be de-duplicated
                $this->removeDuplicates = ( !isset( $params['range'] ) && !isset( $params['pages'] ) );
index f94d6eb..26d3c5c 100644 (file)
@@ -49,7 +49,7 @@ class NullJob extends Job {
         * @param Title $title
         * @param array $params Job parameters (lives, usleep)
         */
-       function __construct( $title, $params ) {
+       function __construct( Title $title, array $params ) {
                parent::__construct( 'null', $title, $params );
                if ( !isset( $this->params['lives'] ) ) {
                        $this->params['lives'] = 1;
index a922dd3..8a180ec 100644 (file)
@@ -29,7 +29,7 @@
  * @ingroup JobQueue
  */
 class PublishStashedFileJob extends Job {
-       public function __construct( $title, $params ) {
+       public function __construct( Title $title, array $params ) {
                parent::__construct( 'PublishStashedFile', $title, $params );
                $this->removeDuplicates = true;
        }
index cc04595..e86d914 100644 (file)
@@ -27,7 +27,7 @@
  * @since 1.25
  */
 class RecentChangesUpdateJob extends Job {
-       function __construct( $title, $params ) {
+       function __construct( Title $title, array $params ) {
                parent::__construct( 'recentChangesUpdate', $title, $params );
 
                if ( !isset( $params['type'] ) ) {
index 749913a..f706455 100644 (file)
@@ -39,7 +39,7 @@ class RefreshLinksJob extends Job {
 
        const CLOCK_FUDGE = 10;
 
-       function __construct( $title, $params = '' ) {
+       function __construct( Title $title, array $params ) {
                parent::__construct( 'refreshLinks', $title, $params );
                // A separate type is used just for cascade-protected backlinks
                if ( !empty( $this->params['prioritize'] ) ) {
index ab38138..a58fa8b 100644 (file)
@@ -27,7 +27,7 @@
  * @ingroup JobQueue
  */
 class ThumbnailRenderJob extends Job {
-       public function __construct( $title, $params ) {
+       public function __construct( Title $title, array $params ) {
                parent::__construct( 'ThumbnailRender', $title, $params );
        }
 
index d15fd02..a15d51e 100644 (file)
@@ -39,7 +39,7 @@ class UploadFromUrlJob extends Job {
        /** @var User */
        protected $user;
 
-       public function __construct( $title, $params ) {
+       public function __construct( Title $title, array $params ) {
                parent::__construct( 'uploadFromUrl', $title, $params );
        }
 
index d446ccf..e29ee88 100644 (file)
@@ -40,13 +40,10 @@ class MWTidyWrapper {
         */
        protected $mTokens;
 
-       protected $mUniqPrefix;
-
        protected $mMarkerIndex;
 
        public function __construct() {
                $this->mTokens = null;
-               $this->mUniqPrefix = null;
        }
 
        /**
@@ -55,8 +52,6 @@ class MWTidyWrapper {
         */
        public function getWrapped( $text ) {
                $this->mTokens = new ReplacementArray;
-               $this->mUniqPrefix = "\x7fUNIQ" .
-                       dechex( mt_rand( 0, 0x7fffffff ) ) . dechex( mt_rand( 0, 0x7fffffff ) );
                $this->mMarkerIndex = 0;
 
                // Replace <mw:editsection> elements with placeholders
@@ -86,7 +81,7 @@ class MWTidyWrapper {
         * @return string
         */
        public function replaceCallback( $m ) {
-               $marker = "{$this->mUniqPrefix}-item-{$this->mMarkerIndex}" . Parser::MARKER_SUFFIX;
+               $marker = Parser::MARKER_PREFIX . "-item-{$this->mMarkerIndex}" . Parser::MARKER_SUFFIX;
                $this->mMarkerIndex++;
                $this->mTokens->setPair( $marker, $m[0] );
                return $marker;
index 27de039..f86e731 100644 (file)
@@ -114,8 +114,20 @@ class Parser {
        const OT_MSG = 3;
        const OT_PLAIN = 4; # like extractSections() - portions of the original are returned unchanged.
 
-       # Marker Suffix needs to be accessible staticly.
+       /**
+        * @var string Prefix and suffix for temporary replacement strings
+        * for the multipass parser.
+        *
+        * \x7f should never appear in input as it's disallowed in XML.
+        * Using it at the front also gives us a little extra robustness
+        * since it shouldn't match when butted up against identifier-like
+        * string constructs.
+        *
+        * Must not consist of all title characters, or else it will change
+        * the behavior of <nowiki> in a link.
+        */
        const MARKER_SUFFIX = "-QINU\x7f";
+       const MARKER_PREFIX = "\x7fUNIQ-";
 
        # Markers used for wrapping the table of contents
        const TOC_START = '<mw:toc>';
@@ -206,9 +218,10 @@ class Parser {
        public $mInputSize = false; # For {{PAGESIZE}} on current page.
 
        /**
-        * @var string
-        */
-       public $mUniqPrefix;
+        * @var string Deprecated accessor for the strip marker prefix.
+        * @deprecated since 1.26; use Parser::MARKER_PREFIX instead.
+        **/
+       public $mUniqPrefix = Parser::MARKER_PREFIX;
 
        /**
         * @var array Array with the language name of each language link (i.e. the
@@ -336,18 +349,7 @@ class Parser {
                $this->mLangLinkLanguages = array();
                $this->currentRevisionCache = null;
 
-               /**
-                * Prefix for temporary replacement strings for the multipass parser.
-                * \x07 should never appear in input as it's disallowed in XML.
-                * Using it at the front also gives us a little extra robustness
-                * since it shouldn't match when butted up against identifier-like
-                * string constructs.
-                *
-                * Must not consist of all title characters, or else it will change
-                * the behavior of <nowiki> in a link.
-                */
-               $this->mUniqPrefix = "\x7fUNIQ" . self::getRandomString();
-               $this->mStripState = new StripState( $this->mUniqPrefix );
+               $this->mStripState = new StripState;
 
                # Clear these on every parse, bug 4549
                $this->mTplRedirCache = $this->mTplDomCache = array();
@@ -399,6 +401,9 @@ class Parser {
                global $wgShowHostnames;
 
                if ( $clearState ) {
+                       // We use U+007F DELETE to construct strip markers, so we have to make
+                       // sure that this character does not occur in the input text.
+                       $text = strtr( $text, "\x7f", "?" );
                        $magicScopeVariable = $this->lock();
                }
 
@@ -410,11 +415,6 @@ class Parser {
                        $this->mOutput->resetParseStartTime();
                }
 
-               # Remove the strip marker tag prefix from the input, if present.
-               if ( $clearState ) {
-                       $text = str_replace( $this->mUniqPrefix, '', $text );
-               }
-
                $oldRevisionId = $this->mRevisionId;
                $oldRevisionObject = $this->mRevisionObject;
                $oldRevisionTimestamp = $this->mRevisionTimestamp;
@@ -686,8 +686,10 @@ class Parser {
         * Get a random string
         *
         * @return string
+        * @deprecated since 1.26; use wfRandomString() instead.
         */
        public static function getRandomString() {
+               wfDeprecated( __METHOD__, '1.26' );
                return wfRandomString( 16 );
        }
 
@@ -705,18 +707,11 @@ class Parser {
         * Accessor for mUniqPrefix.
         *
         * @return string
+        * @deprecated since 1.26; use Parser::MARKER_PREFIX instead.
         */
        public function uniqPrefix() {
-               if ( !isset( $this->mUniqPrefix ) ) {
-                       # @todo FIXME: This is probably *horribly wrong*
-                       # LanguageConverter seems to want $wgParser's uniqPrefix, however
-                       # if this is called for a parser cache hit, the parser may not
-                       # have ever been initialized in the first place.
-                       # Not really sure what the heck is supposed to be going on here.
-                       return '';
-                       # throw new MWException( "Accessing uninitialized mUniqPrefix" );
-               }
-               return $this->mUniqPrefix;
+               wfDeprecated( __METHOD__, '1.26' );
+               return self::MARKER_PREFIX;
        }
 
        /**
@@ -907,10 +902,14 @@ class Parser {
         * @param array $elements List of element names. Comments are always extracted.
         * @param string $text Source text string.
         * @param array $matches Out parameter, Array: extracted tags
-        * @param string $uniq_prefix
+        * @param string|null $uniq_prefix
         * @return string Stripped text
+        * @since 1.26 The uniq_prefix argument is deprecated.
         */
-       public static function extractTagsAndParams( $elements, $text, &$matches, $uniq_prefix = '' ) {
+       public static function extractTagsAndParams( $elements, $text, &$matches, $uniq_prefix = null ) {
+               if ( $uniq_prefix !== null ) {
+                       wfDeprecated( __METHOD__ . ' called with $prefix argument', '1.26' );
+               }
                static $n = 1;
                $stripped = '';
                $matches = array();
@@ -938,7 +937,7 @@ class Parser {
                                $inside = $p[4];
                        }
 
-                       $marker = "$uniq_prefix-$element-" . sprintf( '%08X', $n++ ) . self::MARKER_SUFFIX;
+                       $marker = self::MARKER_PREFIX . "-$element-" . sprintf( '%08X', $n++ ) . self::MARKER_SUFFIX;
                        $stripped .= $marker;
 
                        if ( $close === '/>' ) {
@@ -991,10 +990,10 @@ class Parser {
         * @return string
         */
        public function insertStripItem( $text ) {
-               $rnd = "{$this->mUniqPrefix}-item-{$this->mMarkerIndex}-" . self::MARKER_SUFFIX;
+               $marker = self::MARKER_PREFIX . "-item-{$this->mMarkerIndex}-" . self::MARKER_SUFFIX;
                $this->mMarkerIndex++;
-               $this->mStripState->addGeneral( $rnd, $text );
-               return $rnd;
+               $this->mStripState->addGeneral( $marker, $text );
+               return $marker;
        }
 
        /**
@@ -1257,7 +1256,7 @@ class Parser {
 
                # replaceInternalLinks may sometimes leave behind
                # absolute URLs, which have to be masked to hide them from replaceExternalLinks
-               $text = str_replace( $this->mUniqPrefix . 'NOPARSE', '', $text );
+               $text = str_replace( self::MARKER_PREFIX . 'NOPARSE', '', $text );
 
                $text = $this->doMagicLinks( $text );
                $text = $this->formatHeadings( $text, $origText, $isMain );
@@ -2355,7 +2354,7 @@ class Parser {
         */
        public function armorLinks( $text ) {
                return preg_replace( '/\b((?i)' . $this->mUrlProtocols . ')/',
-                       "{$this->mUniqPrefix}NOPARSE$1", $text );
+                       self::MARKER_PREFIX . "NOPARSE$1", $text );
        }
 
        /**
@@ -2627,7 +2626,7 @@ class Parser {
                                $closematch = preg_match(
                                        '/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'
                                                . '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|'
-                                               . $this->mUniqPrefix
+                                               . self::MARKER_PREFIX
                                                . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)/iS',
                                        $t
                                );
@@ -3896,7 +3895,11 @@ class Parser {
                // Defaults to Parser::statelessFetchTemplate()
                $templateCb = $this->mOptions->getTemplateCallback();
                $stuff = call_user_func( $templateCb, $title, $this );
+               // We use U+007F DELETE to distinguish strip markers from regular text.
                $text = $stuff['text'];
+               if ( is_string( $stuff['text'] ) ) {
+                       $text = strtr( $text, "\x7f", "?" );
+               }
                $finalTitle = isset( $stuff['finalTitle'] ) ? $stuff['finalTitle'] : $title;
                if ( isset( $stuff['deps'] ) ) {
                        foreach ( $stuff['deps'] as $dep ) {
@@ -4190,7 +4193,7 @@ class Parser {
                $name = $frame->expand( $params['name'] );
                $attrText = !isset( $params['attr'] ) ? null : $frame->expand( $params['attr'] );
                $content = !isset( $params['inner'] ) ? null : $frame->expand( $params['inner'] );
-               $marker = "{$this->mUniqPrefix}-$name-"
+               $marker = self::MARKER_PREFIX . "-$name-"
                        . sprintf( '%08X', $this->mMarkerIndex++ ) . self::MARKER_SUFFIX;
 
                $isFunctionTag = isset( $this->mFunctionTagHooks[strtolower( $name )] ) &&
@@ -4435,7 +4438,7 @@ class Parser {
                $prevlevel = 0;
                $toclevel = 0;
                $prevtoclevel = 0;
-               $markerRegex = "{$this->mUniqPrefix}-h-(\d+)-" . self::MARKER_SUFFIX;
+               $markerRegex = self::MARKER_PREFIX . "-h-(\d+)-" . self::MARKER_SUFFIX;
                $baseTitleText = $this->mTitle->getPrefixedDBkey();
                $oldType = $this->mOutputType;
                $this->setOutputType( self::OT_WIKI );
@@ -5774,7 +5777,7 @@ class Parser {
        public function replaceTransparentTags( $text ) {
                $matches = array();
                $elements = array_keys( $this->mTransparentTagHooks );
-               $text = self::extractTagsAndParams( $elements, $text, $matches, $this->mUniqPrefix );
+               $text = self::extractTagsAndParams( $elements, $text, $matches );
                $replacements = array();
 
                foreach ( $matches as $marker => $data ) {
@@ -6233,7 +6236,7 @@ class Parser {
                $i = 0;
                $out = '';
                while ( $i < strlen( $s ) ) {
-                       $markerStart = strpos( $s, $this->mUniqPrefix, $i );
+                       $markerStart = strpos( $s, self::MARKER_PREFIX, $i );
                        if ( $markerStart === false ) {
                                $out .= call_user_func( $callback, substr( $s, $i ) );
                                break;
index 174c1d6..32f5d06 100644 (file)
@@ -29,7 +29,6 @@ class ParserDiffTest
        public $parsers;
        public $conf;
        public $shortOutput = false;
-       public $dtUniqPrefix;
 
        public function __construct( $conf ) {
                if ( !isset( $conf['parsers'] ) ) {
@@ -43,12 +42,6 @@ class ParserDiffTest
                        return;
                }
 
-               global $wgHooks;
-               static $doneHook = false;
-               if ( !$doneHook ) {
-                       $doneHook = true;
-                       $wgHooks['ParserClearState'][] = array( $this, 'onClearState' );
-               }
                if ( isset( $this->conf['shortOutput'] ) ) {
                        $this->shortOutput = $this->conf['shortOutput'];
                }
@@ -126,18 +119,4 @@ class ParserDiffTest
                        $parser->setFunctionHook( $id, $callback, $flags );
                }
        }
-
-       /**
-        * @param Parser $parser
-        * @return bool
-        */
-       public function onClearState( &$parser ) {
-               // hack marker prefixes to get identical output
-               if ( !isset( $this->dtUniqPrefix ) ) {
-                       $this->dtUniqPrefix = $parser->uniqPrefix();
-               } else {
-                       $parser->mUniqPrefix = $this->dtUniqPrefix;
-               }
-               return true;
-       }
 }
index caef648..ff34d9b 100644 (file)
@@ -853,7 +853,8 @@ class PPDStackElement {
                $close,             // Matching closing character
                $count,             // Number of opening characters found (number of "=" for heading)
                $parts,             // Array of PPDPart objects describing pipe-separated parts.
-               $lineStart;         // True if the open char appeared at the start of the input line. Not set for headings.
+               $lineStart;         // True if the open char appeared at the start of the input line.
+                                   // Not set for headings.
 
        public $partClass = 'PPDPart';
 
@@ -1271,7 +1272,7 @@ class PPFrame_DOM implements PPFrame {
                                                $titleText = $this->title->getPrefixedDBkey();
                                                $this->parser->mHeadings[] = array( $titleText, $headingIndex );
                                                $serial = count( $this->parser->mHeadings ) - 1;
-                                               $marker = "{$this->parser->mUniqPrefix}-h-$serial-" . Parser::MARKER_SUFFIX;
+                                               $marker = Parser::MARKER_PREFIX . "-h-$serial-" . Parser::MARKER_SUFFIX;
                                                $count = $contextNode->getAttribute( 'level' );
                                                $s = substr( $s, 0, $count ) . $marker . substr( $s, $count );
                                                $this->parser->mStripState->addGeneral( $marker, '' );
index d32fb57..308ef44 100644 (file)
@@ -112,7 +112,6 @@ class Preprocessor_Hash implements Preprocessor {
         * @return PPNode_Hash_Tree
         */
        public function preprocessToObj( $text, $flags = 0 ) {
-
                // Check cache.
                global $wgMemc, $wgPreprocessorCacheThreshold;
 
@@ -1185,7 +1184,7 @@ class PPFrame_Hash implements PPFrame {
                                                $titleText = $this->title->getPrefixedDBkey();
                                                $this->parser->mHeadings[] = array( $titleText, $bits['i'] );
                                                $serial = count( $this->parser->mHeadings ) - 1;
-                                               $marker = "{$this->parser->mUniqPrefix}-h-$serial-" . Parser::MARKER_SUFFIX;
+                                               $marker = Parser::MARKER_PREFIX . "-h-$serial-" . Parser::MARKER_SUFFIX;
                                                $s = substr( $s, 0, $bits['level'] ) . $marker . substr( $s, $bits['level'] );
                                                $this->parser->mStripState->addGeneral( $marker, '' );
                                                $out .= $s;
index 7e38acc..b11dc8c 100644 (file)
@@ -37,15 +37,20 @@ class StripState {
        const UNSTRIP_RECURSION_LIMIT = 20;
 
        /**
-        * @param string $prefix
+        * @param string|null $prefix
+        * @since 1.26 The prefix argument should be omitted, as the strip marker
+        *  prefix string is now a constant.
         */
-       public function __construct( $prefix ) {
-               $this->prefix = $prefix;
+       public function __construct( $prefix = null ) {
+               if ( $prefix !== null ) {
+                       wfDeprecated( __METHOD__ . ' with called with $prefix argument' .
+                               ' (call with no arguments instead)', '1.26' );
+               }
                $this->data = array(
                        'nowiki' => array(),
                        'general' => array()
                );
-               $this->regex = "/{$this->prefix}([^\x7f]+)" . Parser::MARKER_SUFFIX . '/';
+               $this->regex = '/' . Parser::MARKER_PREFIX . "([^\x7f]+)" . Parser::MARKER_SUFFIX . '/';
                $this->circularRefGuard = array();
        }
 
@@ -166,10 +171,10 @@ class StripState {
         * @return StripState
         */
        public function getSubState( $text ) {
-               $subState = new StripState( $this->prefix );
+               $subState = new StripState();
                $pos = 0;
                while ( true ) {
-                       $startPos = strpos( $text, $this->prefix, $pos );
+                       $startPos = strpos( $text, Parser::MARKER_PREFIX, $pos );
                        $endPos = strpos( $text, Parser::MARKER_SUFFIX, $pos );
                        if ( $startPos === false || $endPos === false ) {
                                break;
@@ -202,7 +207,7 @@ class StripState {
         * @return array
         */
        public function merge( $otherState, $texts ) {
-               $mergePrefix = Parser::getRandomString();
+               $mergePrefix = wfRandomString( 16 );
 
                foreach ( $otherState->data as $type => $items ) {
                        foreach ( $items as $key => $value ) {
@@ -222,7 +227,7 @@ class StripState {
         */
        protected function mergeCallback( $m ) {
                $key = $m[1];
-               return "{$this->prefix}{$this->tempMergePrefix}-$key" . Parser::MARKER_SUFFIX;
+               return Parser::MARKER_PREFIX . $this->tempMergePrefix . '-' . $key . Parser::MARKER_SUFFIX;
        }
 
        /**
index b62de5d..8f14a41 100644 (file)
@@ -111,7 +111,11 @@ class MediaStatisticsPage extends QueryPage {
        protected function outputResults( $out, $skin, $dbr, $res, $num, $offset ) {
                $prevMediaType = null;
                foreach ( $res as $row ) {
-                       list( $mediaType, $mime, $totalCount, $totalBytes ) = $this->splitFakeTitle( $row->title );
+                       $mediaStats = $this->splitFakeTitle( $row->title );
+                       if ( count( $mediaStats ) < 4 ) {
+                               continue;
+                       }
+                       list( $mediaType, $mime, $totalCount, $totalBytes ) = $mediaStats;
                        if ( $prevMediaType !== $mediaType ) {
                                if ( $prevMediaType !== null ) {
                                        // We're not at beginning, so we have to
index f2362a1..8a66273 100644 (file)
@@ -756,7 +756,7 @@ class SpecialUndelete extends SpecialPage {
         * @param User $user
         * @return bool
         */
-       private function isAllowed( $permission, User $user = null ) {
+       protected function isAllowed( $permission, User $user = null ) {
                $user = $user ? : $this->getUser();
                if ( $this->mTargetObj !== null ) {
                        return $this->mTargetObj->userCan( $permission, $user );
@@ -1206,7 +1206,7 @@ class SpecialUndelete extends SpecialPage {
                $repo->streamFile( $path );
        }
 
-       private function showHistory() {
+       protected function showHistory() {
                $out = $this->getOutput();
                if ( $this->mAllowed ) {
                        $out->addModules( 'mediawiki.special.undelete' );
@@ -1377,7 +1377,7 @@ class SpecialUndelete extends SpecialPage {
                return true;
        }
 
-       private function formatRevisionRow( $row, $earliestLiveTime, $remaining ) {
+       protected function formatRevisionRow( $row, $earliestLiveTime, $remaining ) {
                $rev = Revision::newFromArchiveRow( $row,
                        array(
                                'title' => $this->mTargetObj
index df91588..d7c19ef 100644 (file)
@@ -746,11 +746,11 @@ abstract class UploadBase {
                $file = $this->getLocalFile();
 
                foreach ( $sizes as $size ) {
-                       if ( $file->isVectorized()
-                               || $file->getWidth() > $size ) {
-                                       $jobs[] = new ThumbnailRenderJob( $file->getTitle(), array(
-                                               'transformParams' => array( 'width' => $size ),
-                                       ) );
+                       if ( $file->isVectorized() || $file->getWidth() > $size ) {
+                               $jobs[] = new ThumbnailRenderJob(
+                                       $file->getTitle(),
+                                       array( 'transformParams' => array( 'width' => $size ) )
+                               );
                        }
                }
 
diff --git a/includes/utils/MWFunction.php b/includes/utils/MWFunction.php
deleted file mode 100644 (file)
index fa7eebe..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-/**
- * Helper methods to call functions and instance objects.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-class MWFunction {
-
-       /**
-        * @param string $class
-        * @param array $args
-        * @return object
-        * @deprecated 1.25 Use ObjectFactory::getObjectFromSpec() instead
-        */
-       public static function newObj( $class, $args = array() ) {
-               wfDeprecated( __METHOD__, '1.25' );
-
-               return ObjectFactory::getObjectFromSpec( array(
-                       'class' => $class,
-                       'args' => $args,
-                       'closure_expansion' => false,
-               ) );
-       }
-}
index e1a2047..18f4594 100644 (file)
@@ -2462,22 +2462,56 @@ class Language {
                return $this->internalUserTimeAndDate( 'both', $ts, $user, $options );
        }
 
+       /**
+        * Get the timestamp in a human-friendly relative format, e.g., "3 days ago".
+        *
+        * Determine the difference between the timestamp and the current time, and
+        * generate a readable timestamp by returning "<N> <units> ago", where the
+        * largest possible unit is used.
+        *
+        * @since 1.26 (Prior to 1.26 method existed but was not meant to be used directly)
+        *
+        * @param MWTimestamp $time
+        * @param MWTimestamp|null $relativeTo The base timestamp to compare to (defaults to now)
+        * @param User|null $user User the timestamp is being generated for (or null to use main context's user)
+        * @return string Formatted timestamp
+        */
+       public function getHumanTimestamp( MWTimestamp $time, MWTimestamp $relativeTo = null, User $user = null ) {
+               if ( $relativeTo === null ) {
+                       $relativeTo = new MWTimestamp();
+               }
+               if ( $user === null ) {
+                       $user = RequestContext::getMain()->getUser();
+               }
+
+               // Adjust for the user's timezone.
+               $offsetThis = $time->offsetForUser( $user );
+               $offsetRel = $relativeTo->offsetForUser( $user );
+
+               $ts = '';
+               if ( Hooks::run( 'GetHumanTimestamp', array( &$ts, $time, $relativeTo, $user, $this ) ) ) {
+                       $ts = $this->getHumanTimestampInternal( $time, $relativeTo, $user );
+               }
+
+               // Reset the timezone on the objects.
+               $time->timestamp->sub( $offsetThis );
+               $relativeTo->timestamp->sub( $offsetRel );
+
+               return $ts;
+       }
+
        /**
         * Convert an MWTimestamp into a pretty human-readable timestamp using
         * the given user preferences and relative base time.
         *
-        * DO NOT USE THIS FUNCTION DIRECTLY. Instead, call MWTimestamp::getHumanTimestamp
-        * on your timestamp object, which will then call this function. Calling
-        * this function directly will cause hooks to be skipped over.
-        *
-        * @see MWTimestamp::getHumanTimestamp
+        * @see Language::getHumanTimestamp
         * @param MWTimestamp $ts Timestamp to prettify
         * @param MWTimestamp $relativeTo Base timestamp
         * @param User $user User preferences to use
         * @return string Human timestamp
-        * @since 1.22
+        * @since 1.26
         */
-       public function getHumanTimestamp( MWTimestamp $ts, MWTimestamp $relativeTo, User $user ) {
+       private function getHumanTimestampInternal( MWTimestamp $ts, MWTimestamp $relativeTo, User $user ) {
                $diff = $ts->diff( $relativeTo );
                $diffDay = (bool)( (int)$ts->timestamp->format( 'w' ) -
                        (int)$relativeTo->timestamp->format( 'w' ) );
index 844888e..a6b687c 100644 (file)
@@ -355,12 +355,7 @@ class LanguageConverter {
                   2. HTML entities
                   3. placeholders created by the parser
                */
-               global $wgParser;
-               if ( isset( $wgParser ) && $wgParser->UniqPrefix() != '' ) {
-                       $marker = '|' . $wgParser->UniqPrefix() . '[\-a-zA-Z0-9]+';
-               } else {
-                       $marker = '';
-               }
+               $marker = '|' . Parser::MARKER_PREFIX . '[\-a-zA-Z0-9]+';
 
                // this one is needed when the text is inside an HTML markup
                $htmlfix = '|<[^>]+$|^[^<>]*>';
index 6425a53..759531b 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * Estonian (Eesti) specific code.
+ * Estonian (eesti) specific code.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  */
 
 /**
- * Estonian (Eesti)
+ * Estonian (eesti)
  *
  * @ingroup Language
  */
 class LanguageEt extends Language {
        /**
-        * Avoid grouping whole numbers between 0 to 9999
-        *
+        * Avoid grouping whole numbers between -9999 to 9999
         * @param string $_
-        *
         * @return string
         */
        function commafy( $_ ) {
-               if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
+               if ( !preg_match( '/^\-?\d{1,4}(\.\d+)?$/', $_ ) ) {
                        return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
                } else {
                        return $_;
index 5ddc49c..0886963 100644 (file)
        "preview": "شوفه-قبلي",
        "showpreview": "بين معاينة",
        "showdiff": "عرض التبديلات",
+       "blankarticle": "<strong>ردّ البال:</strong> الپاجة الّي كريّيتها راهي خاوية.\nيلا تعاود تكليكي على {{int:savearticle}}\"، الپاجة غادي تنخلق بلا ما يكون فيها حتا محتاوا.",
        "anoneditwarning": "'''توليهة:''' راك ما دخلتش بل حساب تاعك.\nيلا تدير شي تبدال، غادي تتسجّل لادريسة آيبي تاعك فل متراخ تاع هاد الصفحة و تكون باينة ل كلّ واحد. يلا [$1 تتكونيكتا]</strong> ولا <strong>[$2 تخلق حساب]</strong>، التبدالات تاعك غادي يبانو تحت السميّة تاع المستعملي تاعك، و كاين تاني مزيّات وحدخرين.",
+       "anonpreviewwarning": "<em>ما راكش مسجّل داخل. لوكان تحفّظ التبدالات ضركا غادي تتسجّل لادريسة إيپي تاعك فل تاريخ تاع هاد الپاجة.</em>",
+       "missingsummary": "<strong>تفكار:</strong> راك ما مدّيتش تلخيص على التبدال تاعك.\nيلا تكليكي على \"{{int:savearticle}}\" مجّديد، التبدال تاعك غادي يتسجّل بلاش.",
+       "selfredirect": "<strong>ردّ البال:</strong> راك توجّه هاد الپاجة على روحها.\nبالاك راك غلطت فل ختيّار تاع التقيان تاع الپاجة، ولا تاني ما راكش فل پاجة الّي راك حاب تإيديتيها.\nيلا تكليكي على \"{{int:savearticle}}\" مجّديد، هاد التوجاه غادي ينخلق كيما هاك.",
+       "missingcommenttext": "الله يحفضك حُطّ شي تعليق هنا لتحت.",
+       "missingcommentheader": "<strong>تفكار:</strong> راك ما حطّيتش علوان تاع الموضوع تاع التعليق تاعك.\nيلا تكليكي على \"{{int:savearticle}}\" مجّديد، التبدال تاعك غادي يتسجّل بلاش.",
+       "summary-preview": "شوفة خفيفة على التلخيص:",
+       "subject-preview": "شوفة خفيفة على العلوان / الموضوع:",
+       "previewerrortext": "صرات غلطة فل محاولة باش تشوف خفيف ف` التبدالات تاعك.",
+       "blockedtitle": "المستعملي هادا راه محبّس",
+       "blockedtext": "<strong>السميّة تاع المستعملي تاع ولا الإييي راهم محبّسين</strong>\n\nالّي دار التحباس هوّا $1.\nالسبّة تاع التحباس هيّا: <em>$2</em>.\n\n* البدية تاع التحباس: $8\n* الكمال تاع التحباس: $6\n* المقصود تاع التحباس: $7\n\nتنجم تتاصل ب $1 ولا شي واحد من  [[{{MediaWiki:Grouppage-sysop}}|الإيداريّين]] باش تهدر على التحباس.\nما تنجمش تستعمل الخاصيّة تاع  \"ابعت إيمال ل هاد المستعملي\" غير يلا راك وضّعت إيمال صحيح فل  [[Special:Preferences|الختيّارات تاع الحساب تاعك]] و تاني ما راكش مبلوكي فيهم.\nلادريسة إيپي تاعك تاع ضركا هيّا $3، و النمرو تاع التعراف تاع التحباس هوّا #$5.\nالله يخلّيك حطّ كامل هاد المعلومات يلا بغيت تبعت مطلب على هاد الشي.",
+       "autoblockedtext": "لادريسة تاع الإيپي تاعك راهي محبّسة خاطر راهي اتستعملت من عند مستعملي الّي راه بداتهُ محبّس من عند $1.\nالسبّة تاع التحباس هيّا: <em>$2</em>.\n\n* البدية تاع التحباس: $8\n* الكمال تاع التحباس: $6\n* المقصود تاع التحباس: $7\n\nتنجم تتاصل ب $1 ولا شي واحد من  [[{{MediaWiki:Grouppage-sysop}}|الإيداريّين]] باش تهدر على التحباس.\nما تنجمش تستعمل الخاصيّة تاع  \"ابعت إيمال ل هاد المستعملي\" غير يلا راك وضّعت إيمال صحيح فل  [[Special:Preferences|الختيّارات تاع الحساب تاعك]] و تاني ما راكش مبلوكي فيهم.\nلادريسة إيپي تاعك تاع ضركا هيّا $3، و النمرو تاع التعراف تاع التحباس هوّا #$5.\nالله يخلّيك حطّ كامل هاد المعلومات يلا بغيت تبعت مطلب على هاد الشي.",
+       "blockednoreason": "ما تمدّت حتا سبّة",
+       "whitelistedittext": "لازم لك $1 باش تنجم تبدّل الپاجات.",
        "loginreqlink": "اتكونيكتا",
        "newarticle": "(جديد)",
        "newarticletext": "راك تبعت وصيلة لباجه لم ما تخدمتش بعد.\nباش تصنع هاذ الباجه ابدا الكتبه فالصندوق التحت (شوف في [$1  زياده باجه المساعده] لمعلومات).\nإذا كانت زيارتك لهاذ الباجه غلطه، ادرك على بوطون''ولى'' في نافيقاتور الإنترنت نتاعك.",
        "sharedupload-desc-here": "هاذ الملف جاي من $1. يمكن يكون مستعمل من بروجيات وحد أخرين.\nالتوصيف نتاعو في [$2 باجت الصفات] محطوطه هنا لتحت.",
        "upload-disallowed-here": "ما تنحمش تعدّل هاد التصويرة",
        "randompage": "باجة على الزهر",
-       "statistics": "إحصاويّات",
+       "statistics": "إحصائيّات",
        "nbytes": "{{PLURAL:$1|بايت 1|$1 بايت}}",
        "nmembers": "$1 اعضاء{{PLURAL:$1||s}}",
        "prefixindex": "كامل الباجات الباديه ب",
index 8c7c044..531b9a5 100644 (file)
        "tags-edit-reason": "Motiu:",
        "tags-edit-success": "S’han aplicat els canvis correctament.",
        "tags-edit-failure": "No s’han pogut aplicar els canvis:\n$1",
+       "tags-edit-none-selected": "Seleccioneu com a mínim una etiqueta per afegir o suprimir.",
        "comparepages": "Comparar pàgines",
        "compare-page1": "Pàgina 1",
        "compare-page2": "Pàgina 2",
index d848778..6f68070 100644 (file)
        "uploaddisabledtext": "Se desactivó la carga de archivos.",
        "php-uploaddisabledtext": "La subida de archivos está deshabilitada en PHP. Por favor compruebe <code>file_uploads</code> en php.ini.",
        "uploadscripted": "Este archivo contiene script o código HTML que puede ser interpretado erróneamente por un navegador web.",
+       "upload-scripted-pi-callback": "No se pueden cargar archivos que contengan instrucciones de procesamiento en forma de hojas de estilo XML.",
        "uploaded-script-svg": "Se encontró el elemento habilitado para secuencias de órdenes «$1» en el archivo SVG cargado.",
        "uploaded-hostile-svg": "Se encontró código CSS no seguro en el elemento de estilo del archivo SVG cargado.",
        "uploaded-href-attribute-svg": "No se permite que los archivos SVG contengan los atributos de «href» <code>&lt;$1 $2=\"$3\"&gt;</code> apuntando a recursos no locales (p. ej., http:// o javascript:).",
        "filedelete-maintenance": "Borrado y restauración de archivos temporalmente deshabilitados durante el mantenimiento.",
        "filedelete-maintenance-title": "No se puede eliminar el archivo",
        "mimesearch": "Búsqueda por MIME",
-       "mimesearch-summary": "Esta página permite el filtrado de ficheros por su tipo MIME.\nEntrada: contenttype/subtype o contenttype/*, p. ej. <code>image/jpeg</code>.",
+       "mimesearch-summary": "Esta página permite el filtrado de ficheros por su tipo MIME.\nEntrada: tipo/subtipo o tipo/*, p. ej. <code>image/jpeg</code>.",
        "mimetype": "Tipo MIME:",
        "download": "descargar",
        "unwatchedpages": "Páginas no vigiladas",
index 859c6e6..c6b998a 100644 (file)
        "feedback-cancel": "Cancelar",
        "feedback-close": "Feito",
        "feedback-external-bug-report-button": "Gardar unha tarefa técnica",
-       "feedback-dialog-title": "Enviar opinión",
-       "feedback-dialog-intro": "Pode usar o formulario simple de abaixo para enviar a súa opinión. O seu comentario será engadido á páxina \"$1\", xunto co seu nome de usuario.",
+       "feedback-dialog-title": "Enviar comentarios",
+       "feedback-dialog-intro": "Pode usar o formulario simple de abaixo para enviar os seus comentarios sobre o editor visual. O seu comentario será engadido á páxina \"$1\", xunto co seu nome de usuario.",
        "feedback-error-title": "Erro",
        "feedback-error1": "Erro: Resultado da API non recoñecido",
        "feedback-error2": "Erro: Fallo de edición",
index 8517748..630adae 100644 (file)
        "content-model-css": "सी॰एस॰एस",
        "content-json-empty-object": "रिक्त ऑब्जेक्ट",
        "content-json-empty-array": "रिक्त ऐरे",
+       "duplicate-args-warning": "<strong>चेतावनी:</strong> [[:$1]] प्राचल \"$3\" के लिए [[:$2]] को एक से अधिक बार काम में ले रहा है। केवल अन्त में दिया गया मान ही काम में लिया जायेगा।",
        "duplicate-args-category": "टेम्पलेट कॉल में डुप्लिकेट तर्क का उपयोग करते हुए पन्ने",
        "duplicate-args-category-desc": "पेज जैसे तर्कों के डुप्लिकेट का उपयोग करने वाले टेम्पलेट कॉल, जैसे <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> ओैर <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "expensive-parserfunction-warning": "'''चेतावनी:''' इस पृष्ठ पर बहुत अधिक संख्या में कीमती पार्सर फ़ंक्शनों का प्रयोग किया गया है।\n\nइनका प्रयोग $2 से कम बार होना चाहिये, इस समय प्रयोग $1 बार {{PLURAL:$1|है|हैं}}।",
        "uploaddisabledtext": "फ़ाइल अपलोड अक्षम हैं।",
        "php-uploaddisabledtext": "पी॰एच॰पी में फ़ाइल अपलोड बंद हैं।\nकृपया file_uploads जमाव की जाँच करें।",
        "uploadscripted": "इस फ़ाइल में एच॰टी॰एम॰एल या स्क्रिप्ट कोड है, जो वेब ब्राउज़र द्वारा गलत पढ़ा जा सकता है।",
+       "upload-scripted-pi-callback": "उस फाइल को अपलोड नहीं किया जा सकता जिसमें एक्सएमएल-स्टाइलशीट प्रसंस्करण निर्देश समाविष्ट हैं।",
+       "uploaded-script-svg": "अपलोड की गयी एसवीजी फ़ाइल में स्क्रीप्ट अवयव \"$1\" पाया गया।",
+       "uploaded-hostile-svg": "अपलोड की गयी एसवीजी फाइल के शैली अवयव में असुरक्षित सीएसएस पायी गयी।",
+       "uploaded-event-handler-on-svg": "सेटिंग ईवेंट हैंडलर (आयोजन प्रबन्धनकर्ता वरियता) <code>$1=\"$2\"</code> एसवीजी फ़ाइल में अनुमत नहीं है।",
+       "uploaded-href-attribute-svg": "गैर-स्थानीय लक्ष्य के साथ एचआरईऍफ श्रेय (Href attributes) <code>&lt;$1 $2=\"$3\"&gt;</code> (उदाहरण के लिए http://, जावास्क्रीप्ट:, इत्यादि) एसवीजी फाइल में अनुमत नहीं हैं।",
+       "uploaded-href-unsafe-target-svg": "अपलोड की गयी फ़ाइल में असुरक्षित लक्ष्य <code>&lt;$1 $2=\"$3\"&gt;</code> पाये गए।",
+       "uploaded-animate-svg": "चिप्पि \"animate\" पायी गई जिससे href परिवर्तित हो सकता है, अपलोड की गयी फ़ाइल में \"from\" विशेषता <code>&lt;$1 $2=\"$3\"&gt;</code> काम में ली जा रही है।",
        "uploadscriptednamespace": "इस एस॰वी॰जी फ़ाइल में अमान्य नामस्थान \"$1\" है।",
        "uploadinvalidxml": "अपलोड की गई फ़ाइल में स्थित XML पार्स नहीं की जा सकी।",
        "uploadvirus": "इस फ़ाइल में व्हाईरस हैं! अधिक जानकारी: $1",
index 7b0d948..4cadd83 100644 (file)
@@ -47,7 +47,8 @@
                        "Twotwo2019",
                        "SeoJeongHo",
                        "Banwol",
-                       "Ysjbserver"
+                       "Ysjbserver",
+                       "LiteHell"
                ]
        },
        "tog-underline": "링크에 밑줄:",
        "uploaddisabledtext": "파일 올리기 기능이 비활성화되어 있습니다.",
        "php-uploaddisabledtext": "PHP 파일 올리기가 비활성화되었습니다. 파일 올리기 설정을 확인하십시오.",
        "uploadscripted": "이 파일에는 HTML이나 다른 스크립트 코드가 포함되어 있어, 웹 브라우저에서 오류를 일으킬 수 있습니다.",
+       "uploaded-remote-url-svg": "원격 URL로 style 속성이 설정된 SVG파일은 금지됩니다. 업로드된 SVG 파일에서 <code>$1=\"$2\"</code>를 발견하였습니다.",
        "uploadscriptednamespace": "이 SVG 파일은 사용할 수 없는 이름공간 '$1'을 포함하고 있습니다.",
        "uploadinvalidxml": "업로드된 파일의 XML의 구문을 분석할 수 없습니다.",
        "uploadvirus": "파일이 바이러스를 포함하고 있습니다!\n자세한 설명: $1",
index 64f409c..45cb44c 100644 (file)
        "rcshowhideliu-show": "nîşan bide",
        "rcshowhideliu-hide": "veşêre",
        "rcshowhideanons": "Bikarhênerên netomarkirî (IP) $1",
-       "rcshowhideanons-show": "Nîşan bide",
+       "rcshowhideanons-show": "nîşan bide",
        "rcshowhideanons-hide": "veşêre",
        "rcshowhidepatr": "Guherandinên kontrolkirî $1",
        "rcshowhidepatr-show": "Nîşan bide",
        "brokenredirects-delete": "jê bibe",
        "withoutinterwiki": "Rûpelên bê girêdanên ziman",
        "withoutinterwiki-legend": "Pêşbendik",
-       "withoutinterwiki-submit": "Nîşan bide",
+       "withoutinterwiki-submit": "nîşan bide",
        "nbytes": "$1 {{PLURAL:$1|byte|byte}}",
        "ncategories": "$1 {{PLURAL:$1|Kategorî|Kategorî}}",
        "nlinks": "$1 {{PLURAL:$1|girêdan|girêdan}}",
        "linksearch": "Lêgerîna girêdanên derve",
        "linksearch-ns": "Valahiya nav:",
        "linksearch-ok": "Lêgerîn",
-       "listusers-submit": "Nîşan bide",
+       "listusers-submit": "nîşan bide",
        "listusers-noresult": "Bikarhêner nehate dîtin.",
        "listusers-blocked": "(hate astengkirin)",
        "activeusers": "Lîsteya bikarhênerên çalak",
index 56cabca..960106c 100644 (file)
        "unwatchthispage": "Fjern overvaking",
        "notanarticle": "Ikkje innhaldsside",
        "notvisiblerev": "Sideversjonen er sletta",
-       "watchlist-details": "{{PLURAL:$1|Éi side|$1 sider}} på overvakingslista di, utan separat teljing av diskusjonssider.",
+       "watchlist-details": "Du har {{PLURAL:$1|éi side|$1 sider}} på overvakingslista di (med tilhøyrande diskusjonssider).",
        "wlheader-enotif": "Funksjonen for endringsmeldingar per e-post er på.",
        "wlheader-showupdated": "Sider som har vorte endra sidan du sist såg på dei er '''utheva'''",
        "wlnote": "Nedanfor er {{PLURAL:$1|den siste endringa|dei siste '''$1''' endringane}} {{PLURAL:$2|den siste timen|dei siste '''$2''' timane}}, for $3, kl. $4.",
        "logentry-rights-rights-legacy": "$1 {{GENDER:$2|endra}} gruppemedlemskap for $3",
        "logentry-rights-autopromote": "$1 vart automatisk {{GENDER:$2|forfremja}} frå $4 til $5",
        "logentry-upload-upload": "$1 {{GENDER:$2|lasta opp}} $3",
+       "log-name-tag": "Merkelogg",
        "rightsnone": "(ingen)",
        "revdelete-summary": "Samandrag",
        "feedback-adding": "Legg til attendemeldinga til sida...",
index 1bbceb4..9dfb787 100644 (file)
        "content-model-css": "CSS",
        "content-json-empty-object": "Пустой объект",
        "content-json-empty-array": "Пустой массив",
+       "duplicate-args-warning": "<strong>Внимание:</strong> [[:$1]] вызывает [[:$2]] с более чем одним значением параметра «$3». Будет использовано только последнее указанное значение.",
        "duplicate-args-category": "Страницы, использующие повторяющиеся аргументы в вызовах шаблонов",
        "duplicate-args-category-desc": "Страницы, содержащие вызовы шаблонов, использующие повторяющиеся аргументы, такие как <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> или <code><nowiki>{{foo|bar|1=bar}}</nowiki></code>.",
        "expensive-parserfunction-warning": "'''Внимание!''' Эта страница содержит слишком много вызовов ресурсоёмких функций.\n\nДолжно быть не более {{PLURAL:$2|$2 вызова|$2 вызовов|1=одного вызова}}, в то время как сейчас здесь $1 {{PLURAL:$1|вызов|вызовов|вызова}}.",
        "upload-scripted-pi-callback": "Невозможно загрузить файл, содержащий инструкции обработки таблицы стилей XML.",
        "uploaded-script-svg": "Найден небезопасный элемент с поддержкой сценариев «$1» в загруженном SVG-файле.",
        "uploaded-hostile-svg": "Найден небезопасный CSS-код в элементе стиля загруженного SVG-файла.",
+       "uploaded-event-handler-on-svg": "Установка атрибутов обработчика событий <code>$1=\"$2\"</code> не разрешено для SVG-файлов.",
+       "uploaded-href-attribute-svg": "В SVG-файлах не допускаются href-атрибуты <code><$1 $2=\"$3\"></code> с нелокальной целью (т.е. http://, javascript:, и пр.).",
        "uploaded-href-unsafe-target-svg": "В загруженном SVG-файле найдена ссылка на небезопасную цель <code>&lt;$1 $2=\"$3\"&gt;</code>.",
        "uploaded-setting-href-svg": "Использование тега «set» для добавления атрибута «href» в родительский элемент заблокировано.",
+       "uploaded-image-filter-svg": "В загруженном SVG-файле найден фильтр изображений с URL-адресом <code>&lt;$1 $2=\"$3\"&gt;</code>.",
        "uploadscriptednamespace": "Этот SVG-файл содержит некорректное пространство имён '$1'",
        "uploadinvalidxml": "XML в загруженном файле не может быть проанализирован.",
        "uploadvirus": "Файл содержит вирус! См. $1",
index 614788e..c37821f 100644 (file)
        "pool-timeout": "Kilit için zaman bitimi bekleniyor",
        "pool-queuefull": "Havuz sırası dolu",
        "pool-errorunknown": "Bilinmeyen hata",
-       "pool-servererror": "Anket sayacı hizmeti kullanılamıyor ($1).",
+       "pool-servererror": "Havuz sayacı hizmeti kullanılamıyor ($1).",
        "poolcounter-usage-error": "Kullanım hatası: $1",
        "aboutsite": "{{SITENAME}} hakkında",
        "aboutpage": "Project:Hakkında",
        "content-model-css": "CSS",
        "content-json-empty-object": "Boş nesne",
        "content-json-empty-array": "Boş dizi",
+       "duplicate-args-warning": "<strong>Uyarı:</strong>[[:$1]] [[:$2]] şablonunu \"$3\" parametresi için birden fazla değerle çağırıyor. Sadece sağlanan son değer kullanılacak.",
        "duplicate-args-category": "Yinelenen şablon değişkenleri kullanan sayfalar",
        "duplicate-args-category-desc": "Sayfada içeren şablonları çağırmak için bu terimler kullanılır <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> or <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "expensive-parserfunction-warning": "Uyarı: Bu sayfa çok fazla zengin derleyici fonksiyonu çağrısı içeriyor.\n\nBu $2 çağrıdan az olmalı, şu anda {{PLURAL:$1|1 çağrı var|$1 çağrı var}}.",
        "userrights-lookup-user": "Kullanıcı gruplarını düzenle",
        "userrights-user-editname": "Kullanıcı adı giriniz:",
        "editusergroup": "Kullanıcı grupları düzenle",
-       "editinguser": "'''[[User:$1|$1]]'''  $2 kullanıcısının yetkilerini değiştirmektesiniz",
+       "editinguser": "<strong>'''[[User:$1|$1]]'''</strong> $2 kullanıcısının yetkileri değiştiriliyor",
        "userrights-editusergroup": "Kullanıcı grupları düzenle",
        "saveusergroups": "Kullanıcı grupları kaydet",
        "userrights-groupsmember": "İçinde olduğu gruplar:",
        "uploaddisabledtext": "Dosya yüklemeleri devredışı bırakılmıştır.",
        "php-uploaddisabledtext": "PHP dosyası yüklemeleri devre dışıdır. Lütfen file_uploads ayarını kontrol edin.",
        "uploadscripted": "Bu dosya bir internet tarayıcısı tarafından hatalı çevrilebilecek bir HTML veya script kodu içermektedir.",
+       "upload-scripted-pi-callback": "xml-stylesheet işleme talimatları içeren bir dosyalar yüklenemez.",
+       "uploaded-script-svg": "Yüklenen SVG dosyasında komutlanabilir (scriptable) öğe bulundu: \"$1\"",
+       "uploaded-hostile-svg": "Yüklenen SVG dosyasının \"style\" öğesinde güvensiz CSS bulundu.",
+       "uploaded-event-handler-on-svg": "SVG dosyalarında event-handler özniteliğini <code>$1=\"$2\"</code> şeklinde ayarlanmasına izin verilmiyor.",
+       "uploaded-href-attribute-svg": "SVG dosyalarında yerel olmayan (örn. http://, javascript:, vb.) hedefleri olan <code>&lt;$1 $2=\"$3\"&gt;</code> href özniteliklerine izin verilmez.",
+       "uploaded-href-unsafe-target-svg": "Yüklenen SVG dosyasında <code>&lt;$1 $2=\"$3\"&gt;</code> güvensiz hedefine href bulundu.",
+       "uploaded-animate-svg": "\"animate\" etiketi bulundu, href'i değiştiriyor olabilir. Yüklenen SVG dosyasındaki \"from\" özniteliği kullanılıyor  <code>&lt;$1 $2=\"$3\"&gt;</code>",
        "uploadscriptednamespace": "Bu SVG dosyası geçersiz \"$1\" alan adını içermektedir.",
        "uploadinvalidxml": "Yüklenen dosyadaki XML işlenemedi.",
        "uploadvirus": "Bu dosya virüslüdür! Detayları: $1",
index cc2f201..9d0daf9 100644 (file)
        "listfiles-delete": "видалити",
        "listfiles-summary": "Ця спеціальна сторінка показує всі завантажені файли.",
        "listfiles_search_for": "Пошук по назві зображення:",
-       "listfiles-userdoesnotexist": "Ð\9eблÑ\8bковий Ð·Ð°Ð¿Ð¸Ñ\81 Â«$1» Ð½Ðµ Ð·Ð°Ñ\80еÑ\8dстровано.",
+       "listfiles-userdoesnotexist": "Ð\9eблÑ\96ковий Ð·Ð°Ð¿Ð¸Ñ\81 Â«$1» Ð½Ðµ Ð·Ð°Ñ\80еÑ\94стровано.",
        "imgfile": "файл",
        "listfiles": "Список файлів",
        "listfiles_thumb": "Мініатюра",
index 3c93d85..04e30ad 100644 (file)
@@ -17,7 +17,8 @@
                        "Impersonator 1",
                        "LNDDYL",
                        "TheChampionMan1234",
-                       "Fitoschido"
+                       "Fitoschido",
+                       "Poiuyt"
                ]
        },
        "tog-underline": "鏈接下橫線:",
@@ -25,7 +26,7 @@
        "tog-hidepatrolled": "此垡變化裏囥脫巡脫編",
        "tog-newpageshidepatrolled": "新頁表裏囥脫巡脫頁",
        "tog-extendwatchlist": "擴大關注表,顯示全部變化,弗單清此垡個",
-       "tog-usenewrc": "使用强化版个近段辰光个改动(JavaScript)",
+       "tog-usenewrc": "使用折叠版个近段辰光个改动搭关注表",
        "tog-numberheadings": "標題自動編號",
        "tog-showtoolbar": "顯示編傢伙欄",
        "tog-editondblclick": "捺兩記編頁",
@@ -44,7 +45,7 @@
        "tog-shownumberswatching": "顯示關注人數",
        "tog-oldsig": "能界签名先望:",
        "tog-fancysig": "畀簽名當wiki文本(弗自動鏈接)",
-       "tog-uselivepreview": "用當場先望(試驗)",
+       "tog-uselivepreview": "使用实时预览",
        "tog-forceeditsummary": "編要空白到提醒我",
        "tog-watchlisthideown": "關注表裏囥脫我所編",
        "tog-watchlisthidebots": "關注表裏囥脫機器人所編",
        "tog-prefershttps": "登录后老世用保险连接",
        "underline-always": "老世",
        "underline-never": "老世弗",
-       "underline-default": "ç\9a®è\86\9aè¦\81å¼\97æµ\81覽å\99¨é»\98èª\8d",
+       "underline-default": "ç\9a®è\82¤æ\88\96æµ\8fè§\88å\99¨é»\98认设置",
        "editfont-style": "編寫區字體樣式:",
-       "editfont-default": "æµ\81覽å\99¨é»\98èª\8d",
-       "editfont-monospace": "樣闊字體",
-       "editfont-sansserif": "Sans-serif字體",
-       "editfont-serif": "Serif字體",
-       "sunday": "星期日",
-       "monday": "星期一",
-       "tuesday": "星期二",
-       "wednesday": "星期三",
-       "thursday": "星期四",
-       "friday": "星期五",
-       "saturday": "星期六",
+       "editfont-default": "æµ\8fè§\88å\99¨é»\98认",
+       "editfont-monospace": "等阔字体",
+       "editfont-sansserif": "无衬线字体",
+       "editfont-serif": "衬线字体",
+       "sunday": "礼拜日",
+       "monday": "礼拜一",
+       "tuesday": "礼拜两",
+       "wednesday": "礼拜三",
+       "thursday": "礼拜四",
+       "friday": "礼拜五",
+       "saturday": "礼拜六",
        "sun": "日",
        "mon": "一",
-       "tue": "äº\8c",
+       "tue": "两",
        "wed": "三",
        "thu": "四",
        "fri": "五",
@@ -93,7 +94,7 @@
        "november": "11月",
        "december": "12月",
        "january-gen": "一月",
-       "february-gen": "äº\8c月",
+       "february-gen": "两月",
        "march-gen": "三月",
        "april-gen": "四月",
        "may-gen": "五月",
        "december-date": "12月 $1",
        "pagecategories": "{{PLURAL:$1|分类}}",
        "category_header": "“$1”分類裏個頁",
-       "subcategories": "å\85\92å\88\86é¡\9e",
+       "subcategories": "å­\90å\88\86ç±»",
        "category-media-header": "\"$1\"分类里个媒体",
        "category-empty": "''箇分类里页搭媒体能界还呒有。''",
        "hidden-categories": "$1囥脫分類",
        "mypage": "我个页面",
        "mytalk": "我个讨论",
        "anontalk": "箇IP地址個話",
-       "navigation": "å°\8e航",
+       "navigation": "导航",
        "and": "&#32;搭",
        "qbfind": "尋",
-       "qbbrowse": "æµ\81覽",
+       "qbbrowse": "æµ\8fè§\88",
        "qbedit": "編",
        "qbpageoptions": "箇頁",
        "qbmyoptions": "我頁",
        "actions": "动作",
        "namespaces": "名字空间",
        "variants": "变量",
+       "navigation-heading": "导航菜单",
        "errorpagetitle": "錯誤",
        "returnto": "返回$1。",
-       "tagline": "从{{SITENAME}}来",
-       "help": "幫忙",
+       "tagline": "来自{{SITENAME}}",
+       "help": "帮忙",
        "search": "寻",
        "searchbutton": "搜寻",
        "go": "去",
        "permalink": "老世链接",
        "print": "打印",
        "view": "望",
+       "view-foreign": "登$1上看",
        "edit": "编",
        "create": "建",
+       "create-local": "添加本地说明",
        "editthispage": "編箇頁",
        "create-this-page": "建箇頁",
        "delete": "刪",
        "unprotectthispage": "變更箇頁保態",
        "newpage": "新页",
        "talkpage": "探討箇頁",
-       "talkpagelinktext": "è¨\8eè«\96",
+       "talkpagelinktext": "讨论",
        "specialpage": "特別頁",
        "personaltools": "私人家伙",
        "articlepage": "望內容頁",
-       "talk": "探讨",
+       "talk": "讨论",
        "views": "望",
-       "toolbox": "家伙匣",
+       "toolbox": "家",
        "userpage": "望用戶頁",
        "projectpage": "望計劃頁",
        "imagepage": "望文件頁",
        "otherlanguages": "别样话版",
        "redirectedfrom": "(从$1转戳到箇里)",
        "redirectpagesub": "轉戳頁",
+       "redirectto": "重定向到:",
        "lastmodifiedat": "箇页此垡来$1 $2改进。",
        "viewcount": "箇頁望過$1垡。",
        "protectedpage": "受保頁",
        "pool-queuefull": "池队列满哉",
        "pool-errorunknown": "弗识个错误",
        "aboutsite": "有关{{SITENAME}}",
-       "aboutpage": "Project:有关",
-       "copyright": "内容侪拉$1下底发布。",
+       "aboutpage": "Project:关于",
+       "copyright": "除非另外声明,内容侪拉$1下底发布。",
        "copyrightpage": "{{ns:project}}:版权",
-       "currentevents": "箇阶段个事干",
-       "currentevents-url": "Project:箇阶段个事干",
-       "disclaimers": "甮追問",
-       "disclaimerpage": "Project:甮追問",
+       "currentevents": "近段辰光个事体",
+       "currentevents-url": "Project:近段辰光个事体",
+       "disclaimers": "免责声明",
+       "disclaimerpage": "Project:免责声明",
        "edithelp": "編寫幫助",
        "mainpage": "封面",
        "mainpage-description": "封面",
        "policy-url": "Project:策略",
-       "portal": "社å\8d\80è\87ºé\96\80",
-       "portal-url": "Project:社å\8d\80è\87ºé\96\80",
-       "privacy": "é\9a±ç§\81ç­\96ç\95¥",
-       "privacypage": "Project:é\9a±ç§\81ç­\96ç\95¥",
+       "portal": "社å\8cºé\97¨å \82",
+       "portal-url": "Project:社å\8cºé\97¨å \82",
+       "privacy": "é\9a\90ç§\81æ\94¿ç­\96",
+       "privacypage": "Project:é\9a\90ç§\81æ\94¿ç­\96",
        "badaccess": "权限",
        "badaccess-group0": "弗準爾做箇操作。",
        "badaccess-groups": "爾個請求要徠{{PLURAL:$2|箇個}}用戶組裏好用:$1。",
        "ok": "好",
        "retrievedfrom": "取自“$1”",
        "youhavenewmessages": "你侬有$1($2)。",
-       "newmessageslinkplural": "{{PLURAL:$1|新消息}}",
+       "newmessageslinkplural": "{{PLURAL:$1|新消息|999=新消息}}",
        "newmessagesdifflinkplural": "此垡̺{{PLURAL:$1|变化}}",
        "youhavenewmessagesmulti": "爾徠$1裏有新信息",
-       "editsection": "ç·¨",
+       "editsection": "ç¼\96è¾\91",
        "editold": "编",
        "viewsourceold": "望源碼",
        "editlink": "编",
-       "viewsourcelink": "æ\9c\9bæº\90碼",
+       "viewsourcelink": "æ\9c\9bæº\90ç \81",
        "editsectionhint": "编段: $1",
        "toc": "目录",
        "showtoc": "顯示",
        "badtitle": "坏标题",
        "badtitletext": "所请求页面个标题是无效个、弗存在,跨语言或跨wiki链接个标题错误。渠作兴包含一只或多只弗好用拉标题里向字符。",
        "perfcached": "下向是缓存数据,呒数弗是最新个。 A maximum of {{PLURAL:$1|one result is|$1 results are}} available in the cache.",
-       "perfcachedts": "下头是缓存数据,压末一趟更新辰光是$1。 A maximum of {{PLURAL:$4|one result is|$4 results are}} available in the cache.",
+       "perfcachedts": "下头是缓存数据,阿末一趟更新辰光是$1。缓存里最多有{{PLURAL:$4|$4条结果}}。",
        "querypage-no-updates": "当前禁止对此页面进行更新。箇搭个数据弗好立即刷新。",
        "viewsource": "望源码",
        "actionthrottled": "动作已压制",
        "viewsourcetext": "侬可以查看搭仔复制箇只页面个源码:",
        "viewyourtext": "你侬好望也好畀'''你侬编个'''复制到箇页:",
        "protectedinterface": "箇页为箇维基个软件提供界面文本,锁牢定防乱用。\n加改全部维基个译文,用[//translatewiki.net/ translatewiki.net],MediaWiki软件个本地化计划。",
-       "editinginterface": "'''警告:''' 侬来里编写个页面是畀软件用个界面文本。箇页变化会影响各许人个界面样子。假使要畀全部维基翻译,用 [//translatewiki.net/wiki/Main_Page?setlang=zh-hans translatewiki.net],MediaWiki软件个本地化计划。",
+       "editinginterface": "<strong>警告:</strong>侬来里编写个页面是畀软件用个界面文本。箇页变化会影响各许人个界面样子。",
        "cascadeprotected": "箇只页面拨保护拉许,因为箇只页面拨下底已经标注“级联保护”个{{PLURAL:$1|一只|多只}}被保护页面包含:\n$2",
        "namespaceprotected": "侬无没编辑'''$1'''名字空间里向页面个权限。",
        "customcssprotected": "箇CSS页你呒处编,箇页有各许用户个私人设置。",
        "invalidtitle-knownnamespace": "非法个题目头,有名字空间$2搭文字$3",
        "invalidtitle-unknownnamespace": "非法个题目头,有弗识个数字$1搭文字$2",
        "exception-nologin": "朆登录",
-       "exception-nologin-text": "箇页要勿箇操作需要你登录到箇wiki裏来。",
+       "exception-nologin-text": "请登录来访问箇页面或操作。",
        "virus-badscanner": "设置问题:未知个反病毒扫描器:''$1''",
        "virus-scanfailed": "扫描失败(代码 $1)",
        "virus-unknownscanner": "未知个反病毒扫描器:",
        "welcomeuser": "走来赞,$1!",
        "welcomecreation-msg": "你个账号建起来哉。\n覅忘记哉走去改你个[[Special:Preferences|{{SITENAME}}个私人偏好]]。",
        "yourname": "用户名:",
+       "userlogin-yourname": "用户名",
        "userlogin-yourname-ph": "打进你侬个用户名",
        "createacct-another-username-ph": "打进用户名",
        "yourpassword": "密码:",
+       "userlogin-yourpassword": "密码",
        "userlogin-yourpassword-ph": "密码打进去",
        "createacct-yourpassword-ph": "密码打进去",
        "yourpasswordagain": "密码再打一遍:",
-       "createacct-yourpasswordagain-ph": "密码打一遍添",
+       "createacct-yourpasswordagain": "确认密码",
+       "createacct-yourpasswordagain-ph": "再打一遍密码",
        "remembermypassword": "徕箇浏览器里畀我登进去个记牢(记$1{{PLURAL:$1|日|日}})",
-       "userlogin-remembermypassword": "长期徕线里",
+       "userlogin-remembermypassword": "记牢我个登录状态",
        "userlogin-signwithsecure": "用保险链接",
        "yourdomainname": "侬个域名:",
        "password-change-forbidden": "箇wiki裏呒处改你侬个密码。",
        "logout": "登出",
        "userlogout": "登出",
        "notloggedin": "弗曾登录",
-       "userlogin-noaccount": "账号还呒?",
+       "userlogin-noaccount": "呒不账号?",
        "userlogin-joinproject": "加进{{SITENAME}}",
        "nologin": "你侬还呒有账号?'''$1'''。",
        "nologinlink": "建新账号",
        "gotaccount": "已经有仔帐号哉? '''$1'''。",
        "gotaccountlink": "登录",
        "userlogin-resetlink": "忘记登录细节?",
-       "userlogin-resetpassword-link": "转设密码",
+       "userlogin-resetpassword-link": "忘脱密码?",
+       "userlogin-helplink2": "登录帮忙",
        "userlogin-loggedin": "你侬用{{GENDER:$1|$1}}登进来哉。用下向个表以别样身份登进。",
        "userlogin-createanother": "建别样账号",
        "createacct-emailrequired": "电子信地址",
        "passwordtooshort": "密码起码要$1个字符。",
        "password-name-match": "密码弗好搭户名一样。",
        "password-login-forbidden": "用箇名字搭密码是弗准个。",
-       "mailmypassword": "新密码用电子信寄畀我",
+       "mailmypassword": "重置密码",
        "passwordremindertitle": "{{SITENAME}} 个临时新密码",
        "passwordremindertext": "有人(作兴是侬,来自IP地址$1)已经请求{{SITENAME}}个新密码($4)。\n用户“$2”个一只新临时密码现在已经设置好为“$3”。\n假使箇只动作是侬发起个,侬需要立即登录并选择一只新个密码。\n侬个临时密码会得垃拉$5日里向过期。\n\n假使箇只请求弗是侬发起个,或者侬已经拿密码想起来外加弗准备改脱渠,\n侬可以忽略此消息并继续使用侬个旧密码。",
        "noemail": "用户\"$1\"弗曾登记电子邮件地址。",
        "noemailcreate": "侬要提供只有效个电子邮件地址",
        "passwordsent": "用户\"$1\"个新密码已经寄往登记个电子邮件地址。\n请收着仔再登录。",
        "blocked-mailpassword": "侬个IP地址处于查封状态,弗允许编辑,为仔安全起见,密码恢复功能已经禁用。",
-       "eauthentsent": "一封确认信已经发送到指定个e-mail地址。垃拉发送其它邮件到箇只账户之前,侬必须首先按照箇封信里向个指示确认箇只电子邮箱真实有效。",
+       "eauthentsent": "一封确认信已经发送到指定个电子邮箱地址。\n垃拉其它邮件发送到箇只账户之前,侬必须首先按照箇封信里向个指示,确认箇只邮箱真实有效。",
        "throttled-mailpassword": "密码转设电子信徕最近$1个钟头里发畀你侬哉。保险点,密码转设电子信$1个钟头只一垡好发。",
        "mailerror": "发送邮件错误:$1",
        "acct_creation_throttle_hit": "弗好意思,使用箇只IP个访客已经创建仔$1只账号,迭个是箇段辰光里向所允许个最大值。箇咾使用箇只IP个地址个访客暂时弗好再创建账户。",
-       "emailauthenticated": "侬个电子邮箱地址已经垃拉$2 $3确认有效。",
-       "emailnotauthenticated": "侬个邮箱地址<strong>还弗曾认证</strong>。下底眼功能将弗会发送任何邮件。",
+       "emailauthenticated": "侬个电子邮箱地址已经垃拉$2 $3确认。",
+       "emailnotauthenticated": "侬个电子邮箱地址还朆确认。\n下底个功能弗会发送任何邮件。",
        "noemailprefs": "指定一只电子邮箱地址以使用箇眼功能。",
        "emailconfirmlink": "确认邮箱地址",
        "invalidemailaddress": "邮箱地址格式弗对,请输入正确个邮箱地址或清空输入框。",
        "createaccount-title": "垃拉{{SITENAME}}里向创建新账户",
        "createaccount-text": "有人垃拉{{SITENAME}}里向利用侬个邮箱创建仔一只叫 \"$2\" 个新帐户($4),密码是 \"$3\" 。侬应该立即登录并更改密码。\n\n如果箇个账户创建错误个说话,侬可以忽略此信息。",
        "login-throttled": "你侬试登忒多次哉。\n等 $1 再试试凑相。",
-       "login-abort-generic": "登录弗成功 - 流产",
+       "login-abort-generic": "登录弗成功 - 已终止",
        "loginlanguagelabel": "语言:$1",
        "suspicious-userlogout": "侬登出个要求已经拨回头脱,因为渠可能是由已损坏个浏览器或者缓存代理传送个。",
+       "pt-login": "登录",
+       "pt-login-button": "登录",
+       "pt-createaccount": "建账号",
+       "pt-userlogout": "登出",
        "changepassword": "改密码",
-       "resetpass_announce": "侬是通过一只临时发送到e-mail里向个代码登录的。要完成登录,侬必须垃此地设定一只新密码:",
+       "resetpass_announce": "要完成登录,侬必须设定一只新密码。",
        "resetpass_header": "更改密码",
        "oldpassword": "旧密码:",
        "newpassword": "新密码:",
        "resetpass-submit-cancel": "取消",
        "resetpass-wrong-oldpass": "无效个临时或者现有密码。\n侬作兴已经成功拿密码改脱,或者已经请求一个新个临时密码。",
        "resetpass-temp-password": "临时密码:",
+       "passwordreset": "重置密码",
        "passwordreset-username": "用戶名",
-       "bold_sample": "黑体文本",
-       "bold_tip": "黑体文本",
+       "bold_sample": "粗体文字",
+       "bold_tip": "粗体文字",
        "italic_sample": "斜体文本",
        "italic_tip": "斜体文本",
        "link_sample": "链接标题",
        "media_tip": "文件链接",
        "sig_tip": "签名搭辰光戳",
        "hr_tip": "水平线 (小心用)",
-       "summary": "摘要:",
+       "summary": "摘要",
        "subject": "主题 / 标题:",
        "minoredit": "箇是小变化",
        "watchthis": "关注箇页",
        "preview": "望望相",
        "showpreview": "显示望望相",
        "showdiff": "显示变化",
-       "anoneditwarning": "'''警告:''' 你侬朆登进来。\n你侬个IP地址会记进箇页个编史里。",
+       "anoneditwarning": "<strong>警告:</strong>你呒不登录。如果你做仔啥编辑,箇么你个IP地址会公开可见。如果你<strong>[$1 登录]</strong>或<strong>[$2 创建]</strong>一个账号,你个编辑会归功于你用户名下底,而且会有其他好处。",
        "anonpreviewwarning": "''侬弗曾登录。侬个IP位址会得记录拉此页个编辑历史里向。''",
        "missingsummary": "'''提示:''' 侬弗曾提供编辑摘要。假使侬再次单击保存,侬个编辑将弗带编辑摘要保存。",
        "missingcommenttext": "请垃下头输入备注。",
        "blockedtitle": "用户拨查封",
        "blockedtext": "侬个用户名或IP地址已经拨$1查封。\n\n箇趟查封是由$1所封个。原因是''$2''。\n\n* 箇趟查封开始个辰光是:$8\n* 箇趟查封到期个辰光是:$6\n* 对于畀查封者:$7\n\n侬可以联络$1或者其他个 [[{{MediaWiki:Grouppage-sysop}}|管理员]],讨论箇趟查封。\n除非侬已经垃侬个 [[Special:Preferences|个人设置]]里向设置仔一只有效个电子邮件地址,弗然侬弗好使用「e-mail箇位用户」功能。当设置了一只有效个电子邮件地址之后,箇只功能是弗会畀封锁个。\n\n侬个IP地址是$3,而该查封ID是 #$5。 请垃拉侬个查询里向注明以上所有资料。",
        "autoblockedtext": "侬个IP地址已经自动查封,由于之前另一位 搭侬用一样IP个用户畀$1所查封。\n而查封个原因是:\n\n:''$2''\n\n* 箇趟查封个开始辰光是:$8\n* 箇趟查封个到期辰光是:$6\n* 对于畀查封者:$7\n\n侬可以联络$1或者其他个 [[{{MediaWiki:Grouppage-sysop}}|管理员]],讨论箇趟查封。\n除非侬已经垃侬个 [[Special:Preferences|个人设置]]里向设置仔一只有效个电子邮件地址,弗然侬弗好使用「e-mail箇位用户」功能。当设置了一只有效个电子邮件地址之后,箇只功能是弗会畀封锁个。\n\n侬个IP地址是$3,而该查封ID是 #$5。 请垃拉侬个查询里向注明以上所有资料。",
-       "blockednoreason": "弗曾拨原因",
+       "blockednoreason": "朆畀出原因",
        "whitelistedittext": "侬必须$1才能编辑。",
        "confirmedittext": "垃拉编辑此页之前侬必须确认侬个邮箱地址。请通过[[Special:Preferences|个人设置]]设置并验证侬个邮箱地址。",
        "nosuchsectiontitle": "寻弗着箇只段落",
        "session_fail_preview": "'''弗好意思!由于会话数据落失,我伲弗好处理侬个编辑。'''请重试。如果再次失败,请尝试[[Special:UserLogout|登出]]之后重新登录。",
        "session_fail_preview_html": "'''弗好意思!我伲弗好处理侬垃拉进程数据落失辰光个编辑。'''\n\n''由于{{SITENAME}}允许使用原始个 HTML,为著防范 JavaScript 攻击,预览已畀隐藏。''\n\n'''如果这是一次合法的编辑,请重新进行尝试。'''如果还不行,请 [[Special:UserLogout|退出]]并重新登录。",
        "token_suffix_mismatch": "'''由于侬用户端里向个编辑令牌毁损仔一些标点符号字元,为防止编辑个文字损坏,侬个编辑已经畀回头。'''\n箇种情况通常出现垃拉使用含有交关bug、以网络为主个匿名代理服务个辰光。",
-       "editing": "徕里编$1",
+       "editing": "来里编$1",
+       "creating": "创建“$1”",
        "editingsection": "徕里编写$1(段)",
        "editingcomment": "垃许编辑 $1 (新段落)",
        "editconflict": "编辑冲突: $1",
        "currentrev": "最后版本",
        "currentrev-asof": "于$1个最新修订版",
        "revisionasof": "垃拉$1所作出个修订版",
-       "revision-info": "垃拉$1由$2所作版本",
+       "revision-info": "{{GENDER:$6|$2}}$1个版本$7",
        "previousrevision": "←还旧版",
        "nextrevision": "新点个版本→",
        "currentrevisionlink": "最后版本",
        "history-feed-description": "wiki里向本页个修订历史",
        "history-feed-item-nocomment": "$1垃拉$2",
        "history-feed-empty": "请求个页面弗存在。渠作兴已畀删除或重命名。\n尝试[[Special:Search|搜索本站]]获得相关新建页面。",
-       "rev-deleted-comment": "(备注已删除)",
+       "rev-deleted-comment": "(编辑摘要畀删脱)",
        "rev-deleted-user": "(用户名已删除)",
-       "rev-deleted-event": "(日志动作已删除)",
+       "rev-deleted-event": "(日志细节畀删脱)",
        "rev-deleted-user-contribs": "[用户名或IP地址已删除 - 垃贡献里向囥脱编辑]",
        "rev-deleted-text-permission": "箇只页面版本已畀'''删除'''。\n垃拉[{{fullurl:{{#Special:Log}}/delete|page={{PAGENAMEE}}}} 删除日志]里向可以寻着详细信息。",
-       "rev-deleted-text-unhide": "箇只页面修订已经畀'''删除'''。\n垃拉[{{fullurl:{{#Special:Log}}/delete|page={{PAGENAMEE}}}} 删除日志]里向可以寻着详细信息。\n作为管理员,如果侬想继续个闲话,侬可以仍旧[$1 查看箇趟修订]。",
-       "rev-suppressed-text-unhide": "箇只页面修订已经畀'''废止'''。\n垃拉[{{fullurl:{{#Special:Log}}/suppress|page={{PAGENAMEE}}}} 废止日志]里向可以寻着详细信息。\n作为管理员,如果侬想继续个闲话,侬可以仍旧[$1 查看箇趟修订]。",
-       "rev-deleted-text-view": "箇只页面修订已经畀'''删除'''。作为管理员,侬可以查看渠;\n垃拉[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 删除日志]里向可以寻着详细信息。",
-       "rev-suppressed-text-view": "箇只页面修订已经畀'''废止'''。作为管理员,侬可以查看渠;\n垃拉[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 废止日志]里向可以寻着详细信息。",
+       "rev-deleted-text-unhide": "箇只页面修订已经畀<strong>删脱</strong>。\n垃拉[{{fullurl:{{#Special:Log}}/delete|page={{PAGENAMEE}}}} 删除日志]里向可以寻着详细信息。\n如果侬想继续个说话,侬仍旧好[$1 查看箇趟修订]。",
+       "rev-suppressed-text-unhide": "箇只页面修订已经畀<strong>监督囥脱</strong>。\n垃拉[{{fullurl:{{#Special:Log}}/suppress|page={{PAGENAMEE}}}} 监督日志]里向可以寻着详细信息。\n如果侬想继续个说话,侬仍旧好[$1 查看箇趟修订]。",
+       "rev-deleted-text-view": "箇只页面修订已经畀<strong>删脱</strong>。\n侬可以查看渠;垃拉[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 删除日志]里向可以寻着详细信息。",
+       "rev-suppressed-text-view": "箇只页面修订已经畀<strong>监督囥脱</strong>。\n侬可以查看渠;垃拉[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 监督日志]里向可以寻着详细信息。",
        "rev-deleted-no-diff": "因为其中一趟修订已畀'''删除''',侬弗可以查看差异。\n垃拉[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 删除日志]里向可以寻着更多信息。",
        "rev-suppressed-no-diff": "箇只页面个其中一趟版本已经畀'''删除''',箇咾弗可以查看箇趟版本。",
-       "rev-deleted-unhide-diff": "箇只页面个其中一趟修订已经畀'''删除'''。\n垃拉[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 删除日志]里向可以寻着更多信息。\n作为管理员,如果侬想继续个闲话,侬仍旧可以[$1 查看箇趟修订]。",
-       "rev-suppressed-unhide-diff": "箇只页面个其中一趟修订已经拨'''废止'''。\n垃拉[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 废止日志]里向可以寻着更多资料。\n作为管理员,如果侬想继续个闲话,侬可以仍旧[$1 查看箇趟修订]。",
-       "rev-deleted-diff-view": "差异里向个一趟修订已拨'''删除'''。\n作为管理员,侬可以查看箇个差异。详细信息可垃拉[{{fullurl: {{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 删除日志]里向寻着。",
-       "rev-suppressed-diff-view": "差异里向个一趟修订已拨'''废止'''。\n作为管理员,侬可以查看箇个差异。详细信息可垃拉[{{fullurl: {{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 废止日志]里向寻着。",
+       "rev-deleted-unhide-diff": "箇只页面个其中一趟修订已经畀<strong>删脱</strong>。\n垃拉[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 删除日志]里向可以寻着更多信息。\n如果侬想继续个说话,侬仍旧好[$1 查看箇趟修订]。",
+       "rev-suppressed-unhide-diff": "箇只页面个其中一趟修订已经畀<strong>监督囥脱</strong>。\n垃拉[{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 监督日志]里向可以寻着详细信息。\n如果侬想继续个说话,侬仍旧好[$1 查看箇趟修订]。",
+       "rev-deleted-diff-view": "差异对比里向个一趟修订已经畀<strong>删脱</strong>。\n侬可以查看箇个差异;详细信息可垃拉[{{fullurl: {{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 删除日志]里向寻着。",
+       "rev-suppressed-diff-view": "差异对比里向个一趟修订已经畀<strong>监督囥脱</strong>。\n侬可以查看箇个差异;详细信息可垃拉[{{fullurl: {{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 监督日志]里向寻着。",
        "rev-delundel": "显示/囥脱",
        "rev-showdeleted": "显示",
        "revisiondelete": "删除 / 反删除版本",
        "revertmerge": "反合并",
        "mergelogpagetext": "下底是只最近发生个页面历史合并个记录列表。",
        "history-title": "“$1”的版本历史",
+       "difference-title": "“$1”版本间个差别",
        "lineno": "第$1排:",
        "compareselectedversions": "比较选中个版本",
        "showhideselectedversions": "显示/囥脱选定修订版本",
        "editundo": "撤销",
+       "diff-multi-sameuser": "(朆显示同一用户个$1个中间版本)",
        "searchresults": "搜寻结果",
        "searchresults-title": "搜寻“$1”个结果",
        "titlematches": "页面标题匹配",
        "shown-title": "一页显示$1个结果",
        "viewprevnext": "查看($1 {{int:pipe-separator}} $2)($3)",
        "searchmenu-exists": "'''箇wiki里有一页名字“[[:$1]]”哉'''",
-       "searchmenu-new": "'''徕箇wiki里建“[[:$1]]”页!'''",
+       "searchmenu-new": "<strong>登箇Wiki上建“[[:$1]]”页!</strong>{{PLURAL:$2|0=|另见寻着个页面。|另见搜寻个结果。}}",
        "searchprofile-articles": "内容页",
        "searchprofile-images": "多媒体",
        "searchprofile-everything": "全部",
        "searchprofile-advanced": "高级",
-       "searchprofile-articles-tooltip": "徕$1里搜寻",
+       "searchprofile-articles-tooltip": "登$1里向寻",
        "searchprofile-images-tooltip": "搜寻文件",
        "searchprofile-everything-tooltip": "搜寻全部内容(包括讨论页)",
        "searchprofile-advanced-tooltip": "垃拉自定义名字空间里向搜索",
        "searchrelated": "相关",
        "searchall": "全部",
        "showingresults": "下头显示从第<b>$2</b>条开始个<b>$1</b>条结果:",
+       "search-showingresults": "{{PLURAL:$4|<strong>$3</strong>条结果里个<strong>$1</strong>条|<strong>$3</strong>条结果里个<strong>$1~$2</strong>条}}",
        "search-nonefound": "查询呒有结果。",
        "powersearch-legend": "高级搜索",
        "powersearch-ns": "垃拉箇眼名字空间里向搜索:",
        "right-movefile": "移文件",
        "right-upload": "傳文件",
        "right-reupload": "文件以舊換新",
+       "right-writeapi": "使用写入API",
        "right-delete": "刪頁面",
        "right-browsearchive": "搜尋已刪頁",
        "right-viewmywatchlist": "望自己個關注表",
        "action-editmyprivateinfo": "編私人信息",
        "nchanges": "$1趟更改",
        "enhancedrc-history": "歷史",
-       "recentchanges": "箇阶段个变化",
+       "recentchanges": "近段辰光个改动",
        "recentchanges-legend": "箇阶段个变化选项",
        "recentchanges-summary": "登该个页面浪跟踪最近对维基百科个改动。",
        "recentchanges-feed-description": "跟踪此订阅垃拉 wiki 高头个最近更改。",
        "recentchanges-label-newpage": "建新页来编",
        "recentchanges-label-minor": "箇是小编写",
+       "recentchanges-label-bot": "箇编辑由机器人执行",
+       "recentchanges-label-unpatrolled": "该编辑还朆巡查",
+       "recentchanges-label-plusminus": "箇页面字节数前后个变化",
+       "recentchanges-legend-heading": "'''说明:'''",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}}(见[[Special:NewPages|新页面列表]])",
        "rclistfrom": "显示 $3 $2 以来个新改动",
        "rcshowhideminor": "$1小编写",
+       "rcshowhideminor-show": "显示",
+       "rcshowhideminor-hide": "囥脱",
        "rcshowhidebots": "$1机器人",
-       "rcshowhideliu": "$1登录个用户",
+       "rcshowhidebots-show": "显示",
+       "rcshowhidebots-hide": "囥脱",
+       "rcshowhideliu": "$1注册用户",
+       "rcshowhideliu-hide": "囥脱",
        "rcshowhideanons": "$1匿名用户",
-       "rcshowhidemine": "$1我个修改",
+       "rcshowhideanons-show": "显示",
+       "rcshowhideanons-hide": "囥脱",
+       "rcshowhidemine": "$1我个编辑",
+       "rcshowhidemine-show": "显示",
+       "rcshowhidemine-hide": "囥脱",
        "rclinks": "显示来拉上个 $2 日里向个最近 $1 趟改动<br />$3",
        "diff": "两样",
        "hist": "历史",
        "minoreditletter": "小",
        "newpageletter": "新",
        "boteditletter": "机",
+       "rc-change-size-new": "更改后有$1字节",
        "newsectionsummary": "/* $1 */ 新段落",
        "rc-enhanced-expand": "显示细节",
        "rc-enhanced-hide": "畀细节囥脱",
-       "recentchangeslinked": "相关变化",
+       "recentchangeslinked": "搭界个改动",
        "recentchangeslinked-feed": "搭界个改动",
        "recentchangeslinked-toolbox": "相关变化",
        "recentchangeslinked-title": "搭“$1”有关个改动",
        "lockmanager-notlocked": "“$1”朆鎖牢,嘸處開鎖。",
        "img-auth-nofile": "“$1”文件嘸。",
        "upload-curl-error6": "URL走弗進。",
+       "license-header": "授权协议",
        "listfiles_search_for": "寻图片名字:",
        "imgfile": "源文件",
        "listfiles": "文件列表",
        "nolinkstoimage": "呒有页链到箇文件。",
        "linkstoimage-redirect": "$1(文件轉戳到)$2",
        "sharedupload": "箇只文件来源于$1,渠作兴垃拉其它项目当中拨应用。",
-       "sharedupload-desc-here": "箇文件$1里个,作兴会来别个项目里用。\n渠个描述页里所描述个显示如下。",
+       "sharedupload-desc-here": "箇文件$1里个,作兴会畀别个项目使用。\n渠个[$2 描述页]里个说明显示如下。",
        "uploadnewversion-linktext": "上载该文件个新版",
+       "upload-disallowed-here": "你弗可以覆盖伊只文件。",
        "filerevert": "恢复$1",
        "filerevert-legend": "恢复文物",
        "filerevert-comment": "理由:",
        "pager-older-n": "旧$1次",
        "booksources": "书源",
        "booksources-search-legend": "搜索图书来源",
+       "booksources-search": "搜寻",
        "specialloguserlabel": "用戶:",
        "speciallogtitlelabel": "目標(標題要弗用戶):",
        "log": "记录",
        "deletereasonotherlist": "别个理由",
        "rollback": "恢复编辑",
        "rollbacklink": "回退",
+       "rollbacklinkcount": "回退$1届编辑",
        "rollbackfailed": "恢复失败",
        "revertpage": "恢复[[Special:Contributions/$2|$2]] ([[User talk:$2|讲张]])个改动;恢复到[[User:$1|$1]]个上一版本",
        "protectlogpage": "保护日志",
        "undelete-search-submit": "搜尋",
        "namespace": "名字空间:",
        "invert": "反选择",
+       "tooltip-invert": "请选择该框来囥脱指定名字空间(搭有关名字空间,如果你选择)个页面更改",
+       "namespace_association": "有关个名字空间",
+       "tooltip-namespace_association": "选中该复选框可包括搭选定名字空间有关个讨论页或子页面",
        "blanknamespace": "(主)",
-       "contributions": "用户贡献",
+       "contributions": "{{GENDER:$1|用户}}贡献",
        "contributions-title": "$1个贡献",
        "mycontris": "我个贡献",
        "contribsub2": "$1个贡献($2)",
        "allmessagesnotsupportedDB": "'''{{ns:special}}:Allmessages''' 呒处显示,因为 '''$wgUseDatabaseMessages''' 关勒浪。",
        "thumbnail-more": "放大",
        "filemissing": "文件寻弗着哉",
-       "tooltip-pt-userpage": "你侬个ç\94¨æ\88·é¡µ",
-       "tooltip-pt-mytalk": "你侬个讨论页",
-       "tooltip-pt-preferences": "我欢喜个",
+       "tooltip-pt-userpage": "侬个用户页",
+       "tooltip-pt-mytalk": "侬个讨论页",
+       "tooltip-pt-preferences": "侬个设置",
        "tooltip-pt-watchlist": "监控修改页面列表",
-       "tooltip-pt-mycontris": "你侬个贡ç\8c®å\88\97表",
+       "tooltip-pt-mycontris": "侬个贡献列表",
        "tooltip-pt-login": "鼓励大家登录进来,不过也弗是板定要求",
        "tooltip-pt-logout": "登出",
+       "tooltip-pt-createaccount": "建议你建立一个账号并登录,但必过箇弗是板要个",
        "tooltip-ca-talk": "讨论内容页",
        "tooltip-ca-edit": "箇页你侬好编。保存之前望望相起。",
        "tooltip-ca-addsection": "开始新段",
-       "tooltip-ca-viewsource": "箇页受保,你侬好望源代码",
+       "tooltip-ca-viewsource": "箇页受保护,你好望源代码",
        "tooltip-ca-history": "箇页以早个版本",
        "tooltip-ca-protect": "保护箇页",
        "tooltip-ca-delete": "删脱箇页",
        "tooltip-search": "搜寻{{SITENAME}}",
        "tooltip-search-go": "转到页本确切名称,如果存在",
        "tooltip-search-fulltext": "搜寻包含箇星文本个页面",
-       "tooltip-p-logo": "封面",
+       "tooltip-p-logo": "翻到封面",
        "tooltip-n-mainpage": "翻到封面",
        "tooltip-n-mainpage-description": "翻到封面",
        "tooltip-n-portal": "有关箇计划,啥好做,应该哪能做",
        "tooltip-summary": "打进短摘要",
        "interlanguage-link-title": "̩$1 - $2",
        "anonymous": "{{SITENAME}}浪个匿名用户",
+       "simpleantispam-label": "反垃圾检查。\n<strong>覅</strong>加进伊个!",
+       "pageinfo-toolboxlink": "页面信息",
        "deletedrevision": "拨删脱个旧修订 $1",
        "previousdiff": "←老版",
        "nextdiff": "新版→",
        "file-info-size": "$1×$2像素,文件大小:$3,MIME类型:$4",
        "file-nohires": "无更高分辨率可提供。",
        "svg-long-desc": "SVG文件,名义大小:$1×$2像素,文件大小:$3",
-       "show-big-image": "完整分辨率",
+       "show-big-image": "原始文件",
+       "show-big-image-preview": "本预览个尺寸:$1。",
+       "show-big-image-other": "其他{{PLURAL:$2|分辨率}}:$1。",
+       "show-big-image-size": "$1×$2像素",
        "newimages": "新文件陈列室",
        "ilsubmit": "搜寻",
        "bad_image_list": "格式如下:\n\n只列出项目(线开始* )的审议。\n第一个环节上线必须是一个链接到一个坏文件。\n其后的任何链接在同一行被认为是例外情况,即网页的文件,则可能会发生内部。",
        "metadata-help": "箇只文件里向包含有扩展个信息。箇些信息可能是由数码相机或扫描仪垃拉创建或数字化过程中所添加个。\n\n如果此文件个源文件已经修改,一些信息垃拉修改后个文件里向将弗能完全反映出来。",
        "metadata-expand": "显示详细资料",
        "metadata-collapse": "隐藏详细资料",
-       "metadata-fields": "垃拉本信息里向所列出个 EXIF 元数据域包含垃拉图片显示页面,\n当元数据表损坏个辰光只显示下头眼信息,别个元数据默认为隐藏。\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+       "metadata-fields": "垃拉本信息里向列出个图像元数据域包含垃拉图片显示页面,来元数据表损坏个辰光只显示下头眼信息。\n别个元数据默认囥脱。\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+       "exif-orientation": "方位",
+       "exif-xresolution": "水平分辨率",
+       "exif-yresolution": "垂直分辨率",
+       "exif-datetime": "文件更改日脚辰光",
+       "exif-make": "照相机厂商",
+       "exif-model": "照相机型号",
+       "exif-software": "使用软件",
        "exif-artist": "作者",
+       "exif-exifversion": "Exif版本",
+       "exif-colorspace": "色彩空间",
+       "exif-datetimeoriginal": "数据生成日脚辰光",
+       "exif-datetimedigitized": "数字化日脚辰光",
+       "exif-orientation-1": "标准",
        "exif-componentsconfiguration-0": "弗存在",
        "exif-subjectdistance-value": "$1米",
        "exif-contrast-2": "高",
        "confirmemail_subject": "{{SITENAME}}电子邮件地址确认",
        "confirmemail_body": "用IP地址$1嗰人(呒数是你侬),徕translatewiki.net里一个账号“$2”建起,用你侬个电子信箱地址。\n\n确认记箇账号是弗是你侬嘅,激活translatewiki.net里嗰电子信功能。用浏览器打开下向嗰链接:\n\n$3\n\n假使你侬*朆*注册过箇账号,揿下向嗰链接取消电子信确认:\n\n$5\n\n确认码会到$4过期。",
        "confirmemail_body_changed": "用IP地址$1嗰人,(呒数是你侬)徕{{SITENAME}}里一个账号“$2”建起,用你侬个电子信箱地址。\n\n确认记箇账号是弗是你侬嘅,激活{{SITENAME}}里嗰电子信功能。用浏览器打开下向嗰链接:\n\n$3\n\n假使你侬*朆*注册过箇账号,揿下向嗰链接取消电子信确认:\n\n$5\n\n确认码会到$4过期。",
-       "scarytranscludetoolong": "[对呒起,URL太长了]",
+       "scarytranscludetoolong": "[URL忒长]",
        "confirmrecreate": "用户[[User:$1|$1]] ([[User talk:$1|讲张]])勒拉倷开始编辑该页面之后拿俚删脱,理由是: : ''$2'' 请拿定章程,倷阿是真个要重建该页面。",
        "confirm_purge_button": "确定",
        "comma-separator": "、",
        "table_pager_next": "下页",
        "table_pager_prev": "上页",
        "table_pager_first": "头一页",
-       "table_pager_last": "末一页",
+       "table_pager_last": "末一页",
        "table_pager_limit": "显示 $1 条每页",
        "autoredircomment": "重定向页面至[[$1]]",
        "autosumm-new": "新页面:$1",
        "watchlisttools-view": "望相关修改",
        "watchlisttools-edit": "望搭编关注表",
        "watchlisttools-raw": "编写原始关注表",
+       "signature": "[[{{ns:user}}:$1|$2]]([[{{ns:user_talk}}:$1|讨论]])",
        "version": "版本",
        "specialpages": "特殊页",
+       "tag-filter": "[[Special:Tags|标签]]过滤器:",
+       "tag-list-wrapper": "([[Special:Tags|$1个标签]]:$2)",
        "tags-active-yes": "好",
        "tags-active-no": "弗",
        "dberr-info-hidden": "(數據庫服務器連弗上)",
+       "logentry-delete-delete": "$1{{GENDER:$2|删除}}页面$3",
        "revdelete-restricted": "已将限制应用到管理员",
        "revdelete-unrestricted": "已移除对管理员个限制",
+       "logentry-move-move": "$1{{GENDER:$2|捅荡}}页面$3到$4",
+       "logentry-newusers-create": "用户账号$1畀{{GENDER:$2|创建}}",
+       "logentry-upload-upload": "$1{{GENDER:$2|上传}}$3",
        "rightsnone": "(呒)",
-       "revdelete-summary": "编辑摘要"
+       "revdelete-summary": "编辑摘要",
+       "searchsuggest-search": "搜寻"
 }
index eab2b63..43e2d87 100644 (file)
@@ -22,6 +22,7 @@
                                "name": "General",
                                "classes": [
                                        "mw.Title",
+                                       "mw.MalformedTitleException",
                                        "mw.Uri",
                                        "mw.messagePoster.*",
                                        "mw.notification",
index 1f5ac16..3571a13 100644 (file)
@@ -94,20 +94,23 @@ return array(
         * including more than one of them into your skin as this will result in duplicate CSS.
         */
        'mediawiki.skinning.elements' => array(
+               'position' => 'top',
                'styles' => array(
                        'resources/src/mediawiki.skinning/elements.css' => array( 'media' => 'screen' ),
                ),
        ),
        'mediawiki.skinning.content' => array(
+               'position' => 'top',
                'styles' => array(
                        'resources/src/mediawiki.skinning/elements.css' => array( 'media' => 'screen' ),
                        'resources/src/mediawiki.skinning/content.css' => array( 'media' => 'screen' ),
                ),
        ),
+       // Used in the web installer. Test it after modifying this definition!
        'mediawiki.skinning.interface' => array(
                'position' => 'top',
+               // Display wiki logo on .mw-wiki-logo elements.
                'class' => 'ResourceLoaderSkinModule',
-               // Used in the web installer. Test it after modifying this definition!
                'styles' => array(
                        'resources/src/mediawiki.skinning/elements.css' => array( 'media' => 'screen' ),
                        'resources/src/mediawiki.skinning/content.css' => array( 'media' => 'screen' ),
@@ -127,12 +130,19 @@ return array(
        ),
 
        'mediawiki.skinning.content.externallinks' => array(
-               'position' => 'top',
+               'position' => 'bottom',
                'styles' => array(
                        'resources/src/mediawiki.skinning/content.externallinks.css' => array( 'media' => 'screen' ),
                ),
        ),
 
+       // Display wiki logo on .mw-wiki-logo elements.
+       // This is also part of 'mediawiki.skinning.interface' module; the skin shouldn't load them both.
+       'mediawiki.skinning.logo' => array(
+               'position' => 'top',
+               'class' => 'ResourceLoaderSkinModule',
+       ),
+
        /* jQuery */
 
        'jquery' => array(
@@ -1600,8 +1610,8 @@ return array(
 
        /* MediaWiki Installer */
 
+       // Used in the web installer. Test it after modifying this definition!
        'mediawiki.legacy.config' => array(
-               // Used in the web installer. Test it after modifying this definition!
                // These files are not actually loaded via ResourceLoader, so dependencies etc. won't work.
                'scripts' => 'mw-config/config.js',
                'styles' => 'mw-config/config.css',
@@ -1628,8 +1638,8 @@ return array(
                'dependencies' => 'jquery.byteLimit',
                'messages' => array( 'protect-unchain-permissions' )
        ),
+       // Used in the web installer. Test it after modifying this definition!
        'mediawiki.legacy.shared' => array(
-               // Used in the web installer. Test it after modifying this definition!
                'position' => 'top',
                'styles' => array(
                        'resources/src/mediawiki.legacy/shared.css' => array( 'media' => 'screen' )
@@ -1725,6 +1735,23 @@ return array(
                'targets' => array( 'desktop', 'mobile' ),
        ),
 
+       'mediawiki.widgets' => array(
+               'scripts' => array(
+                       'resources/src/mediawiki.widgets/mw.widgets.js',
+                       'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js',
+               ),
+               'skinStyles' => array(
+                       'default' => 'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css',
+               ),
+               'dependencies' => array(
+                       'oojs-ui',
+               ),
+               'messages' => array(
+                       // …
+               ),
+               'targets' => array( 'desktop', 'mobile' ),
+       ),
+
        /* es5-shim */
        'es5-shim' => array(
                'scripts' => array(
@@ -1804,8 +1831,8 @@ return array(
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.indicators' => array(
                'position' => 'top',
@@ -1824,112 +1851,112 @@ return array(
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-alerts.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-content' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-content.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-editing-advanced' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-editing-advanced.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-editing-core' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-editing-core.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-editing-list' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-editing-list.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-editing-styling' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-editing-styling.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-interactions' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-interactions.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-layout' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-layout.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-location' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-location.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-media' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-media.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-moderation' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-moderation.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-movement' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-movement.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-user' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-user.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
        'oojs-ui.styles.icons-wikimedia' => array(
                'position' => 'top',
                'class' => 'ResourceLoaderImageModule',
                'localBasePath' => "$IP/resources/lib/oojs-ui/themes/mediawiki",
                'data' => 'icons-wikimedia.json',
-               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:after, .mw-ui-icon-{name}:before',
-               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:after, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
+               'selectorWithoutVariant' => '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before',
+               'selectorWithVariant' => '.oo-ui-image-{variant} .oo-ui-icon-{name}, .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before, .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before, .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before',
        ),
 
 );
index 8140d1a..9c59fc1 100644 (file)
@@ -237,10 +237,6 @@ textarea {
        box-sizing: border-box;
 }
 
-select {
-       vertical-align: top;
-}
-
 /* Emulate Center */
 .center {
        width: 100%;
index a6e6490..d9e8c42 100644 (file)
@@ -4,7 +4,6 @@
 // Mixins
 .mixin-mw-ui-icon-bgimage(@iconSvg, @iconPng) {
        &.mw-ui-icon {
-               &:after,
                &:before {
                        .background-image-svg(@iconSvg, @iconPng);
                }
@@ -54,7 +53,6 @@
                }
        }
 
-       &.mw-ui-icon-after:after,
        &.mw-ui-icon-before:before,
        &.mw-ui-icon-element:before {
                background-position: 50% 50%;
                        margin-right: @iconGutterWidth;
                }
        }
-
-       // Icons with text before
-       //
-       // Markup:
-       // <div class="mw-ui-icon mw-ui-icon-after mw-ui-icon-ok mw-ui-progressive mw-ui-button">OK</div>
-       //
-       // Styleguide 6.1.3
-       &.mw-ui-icon-after {
-               &:after {
-                       position: relative;
-                       float: right;
-                       width: @iconSize;
-                       margin-left: @iconGutterWidth;
-               }
-       }
 }
diff --git a/resources/src/mediawiki.widgets/AUTHORS.txt b/resources/src/mediawiki.widgets/AUTHORS.txt
new file mode 100644 (file)
index 0000000..10064b2
--- /dev/null
@@ -0,0 +1,10 @@
+Authors (alphabetically)
+
+Alex Monk <krenair@wikimedia.org>
+Bartosz Dziewoński <bdziewonski@wikimedia.org>
+Ed Sanders <esanders@wikimedia.org>
+James D. Forrester <jforrester@wikimedia.org>
+Roan Kattouw <roan@wikimedia.org>
+Sucheta Ghoshal <sghoshal@wikimedia.org>
+Timo Tijhof <timo@wikimedia.org>
+Trevor Parscal <trevor@wikimedia.org>
diff --git a/resources/src/mediawiki.widgets/LICENSE.txt b/resources/src/mediawiki.widgets/LICENSE.txt
new file mode 100644 (file)
index 0000000..b03ca80
--- /dev/null
@@ -0,0 +1,25 @@
+Copyright (c) 2011-2015 MediaWiki Widgets Team and others under the
+terms of The MIT License (MIT), as follows:
+
+This software consists of voluntary contributions made by many
+individuals (AUTHORS.txt) For exact contribution history, see the
+revision history and logs, available at https://gerrit.wikimedia.org
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css b/resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css
new file mode 100644 (file)
index 0000000..0065f70
--- /dev/null
@@ -0,0 +1,10 @@
+/*!
+ * MediaWiki Widgets – TitleInputWidget styles.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+.mw-widget-TitleInputWidget {
+       width: 30em;
+}
diff --git a/resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js b/resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js
new file mode 100644 (file)
index 0000000..bfedb6b
--- /dev/null
@@ -0,0 +1,132 @@
+/*!
+ * MediaWiki Widgets – TitleInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+       /**
+        * Creates an mw.widgets.TitleInputWidget object.
+        *
+        * @class
+        * @extends OO.ui.TextInputWidget
+        * @mixins OO.ui.LookupElement
+        *
+        * @constructor
+        * @param {Object} [config] Configuration options
+        * @cfg {number} [namespace] Namespace to prepend to queries
+        */
+       mw.widgets.TitleInputWidget = function MWWTitleInputWidget( config ) {
+               // Config initialization
+               config = config || {};
+
+               // Parent constructor
+               OO.ui.TextInputWidget.call( this, config );
+
+               // Mixin constructors
+               OO.ui.LookupElement.call( this, config );
+
+               // Properties
+               this.namespace = config.namespace || null;
+
+               // Initialization
+               this.$element.addClass( 'mw-widget-TitleInputWidget' );
+               this.lookupMenu.$element.addClass( 'mw-widget-TitleInputWidget-menu' );
+       };
+
+       /* Inheritance */
+
+       OO.inheritClass( mw.widgets.TitleInputWidget, OO.ui.TextInputWidget );
+
+       OO.mixinClass( mw.widgets.TitleInputWidget, OO.ui.LookupElement );
+
+       /* Methods */
+
+       /**
+        * @inheritdoc
+        */
+       mw.widgets.TitleInputWidget.prototype.onLookupMenuItemChoose = function ( item ) {
+               this.closeLookupMenu();
+               this.setLookupsDisabled( true );
+               this.setValue( item.getData() );
+               this.setLookupsDisabled( false );
+       };
+
+       /**
+        * @inheritdoc
+        */
+       mw.widgets.TitleInputWidget.prototype.getLookupRequest = function () {
+               var value = this.value;
+
+               // Prefix with default namespace name
+               if ( this.namespace !== null && mw.Title.newFromText( value, this.namespace ) ) {
+                       value = mw.Title.newFromText( value, this.namespace ).getPrefixedText();
+               }
+
+               // Dont send leading ':' to open search
+               if ( value.charAt( 0 ) === ':' ) {
+                       value = value.slice( 1 );
+               }
+
+               return new mw.Api().get( {
+                       action: 'opensearch',
+                       search: value,
+                       suggest: ''
+               } );
+       };
+
+       /**
+        * @inheritdoc
+        */
+       mw.widgets.TitleInputWidget.prototype.getLookupCacheDataFromResponse = function ( data ) {
+               return data[1] || [];
+       };
+
+       /**
+        * @inheritdoc
+        */
+       mw.widgets.TitleInputWidget.prototype.getLookupMenuOptionsFromData = function ( data ) {
+               var i, len, title, value,
+                       items = [],
+                       matchingPages = data;
+
+               // Matching pages
+               if ( matchingPages && matchingPages.length ) {
+                       for ( i = 0, len = matchingPages.length; i < len; i++ ) {
+                               title = new mw.Title( matchingPages[i] );
+                               if ( this.namespace !== null ) {
+                                       value = title.getRelativeText( this.namespace );
+                               } else {
+                                       value = title.getPrefixedText();
+                               }
+                               items.push( new OO.ui.MenuOptionWidget( {
+                                       data: value,
+                                       label: value
+                               } ) );
+                       }
+               }
+
+               return items;
+       };
+
+       /**
+        * Get title object corresponding to #getValue
+        *
+        * @returns {mw.Title|null} Title object, or null if value is invalid
+        */
+       mw.widgets.TitleInputWidget.prototype.getTitle = function () {
+               var title = this.getValue(),
+                       // mw.Title doesn't handle null well
+                       titleObj = mw.Title.newFromText( title, this.namespace !== null ? this.namespace : undefined );
+
+               return titleObj;
+       };
+
+       /**
+        * @inheritdoc
+        */
+       mw.widgets.TitleInputWidget.prototype.isValid = function () {
+               return $.Deferred().resolve( !!this.getTitle() ).promise();
+       };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.widgets/mw.widgets.js b/resources/src/mediawiki.widgets/mw.widgets.js
new file mode 100644 (file)
index 0000000..dc8b0cf
--- /dev/null
@@ -0,0 +1 @@
+mediaWiki.widgets = {};
index 3efb7ec..8785b0b 100644 (file)
         * @param {string} title Title of the page. If no second argument given,
         *  this will be searched for a namespace
         * @param {number} [namespace=NS_MAIN] If given, will used as default namespace for the given title
-        * @throws {Error} When the title is invalid
+        * @throws {mw.MalformedTitleException} Throws when the title is invalid with details on why the title is invalid
         */
        function Title( title, namespace ) {
                var parsed = parse( title, namespace );
-               if ( !parsed ) {
-                       throw new Error( 'Unable to parse title' );
-               }
 
                this.namespace = parsed.namespace;
                this.title = parsed.title;
         * @method parse
         * @param {string} title
         * @param {number} [defaultNamespace=NS_MAIN]
-        * @return {Object|boolean}
+        * @return {Object}
+        * @throws {mw.MalformedTitleException} When the title is invalid
         */
        parse = function ( title, defaultNamespace ) {
                var namespace, m, id, i, fragment, ext;
                }
 
                if ( title === '' ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-empty', title );
                }
 
                // Process namespace prefix (if any)
                                if ( namespace === NS_TALK && ( m = title.match( rSplit ) ) ) {
                                        // Disallow titles like Talk:File:x (subject should roundtrip: talk:file:x -> file:x -> file_talk:x)
                                        if ( getNsIdByName( m[1] ) !== false ) {
-                                               return false;
+                                               throw new MalformedTitleException( 'title-invalid-talk-namespace', title );
                                        }
                                }
                        }
 
                // Reject illegal characters
                if ( title.match( rInvalid ) ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-characters', title, [ title.match( rInvalid )[0] ] );
                }
 
                // Disallow titles that browsers or servers might resolve as directory navigation
                                title.slice( -3 ) === '/..'
                        )
                ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-relative', title );
                }
 
                // Disallow magic tilde sequence
                if ( title.indexOf( '~~~' ) !== -1 ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-magic-tilde', title );
                }
 
                // Disallow titles exceeding the TITLE_MAX_BYTES byte size limit (size of underlying database field)
                // Note: The PHP implementation also asserts that even in NS_SPECIAL, the title should
                // be less than 512 bytes.
                if ( namespace !== NS_SPECIAL && $.byteLength( title ) > TITLE_MAX_BYTES ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-too-long', title, [ TITLE_MAX_BYTES ] );
                }
 
                // Can't make a link to a namespace alone.
                if ( title === '' && namespace !== NS_MAIN ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-empty', title );
                }
 
                // Any remaining initial :s are illegal.
                if ( title.charAt( 0 ) === ':' ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-leading-colon', title );
                }
 
                // For backwards-compatibility with old mw.Title, we separate the extension from the
         * @return {mw.Title|null} A valid Title object or null if the title is invalid
         */
        Title.newFromText = function ( title, namespace ) {
-               var t, parsed = parse( title, namespace );
-               if ( !parsed ) {
+               var t, parsed;
+               try {
+                       parsed = parse( title, namespace );
+               } catch ( e ) {
                        return null;
                }
 
        // Expose
        mw.Title = Title;
 
+       /**
+        * @class mw.MalformedTitleException
+        *
+        * Custom exception class that provides parameters for additional error
+        * information regarding the reason behind the invalidity of the requested
+        * title.  The information can be used in i18n messages that can be displayed
+        * to the user.
+        *
+        * Based on MalformedTitleException.php#__construct
+        *
+        * @constructor
+        * @param {string} message Reason e.g. invalid-title-too-long for a long title
+        * @param {string} titleText The invalid title text involved
+        * @param {Array} errorMessageParameters Additional error information
+        */
+       function MalformedTitleException( message, titleText, errorMessageParameters ) {
+               this.message = message;
+               this.titleText = titleText;
+               if ( errorMessageParameters ) {
+                       this.errorMessageParameters = errorMessageParameters;
+               } else {
+                       this.errorMessageParameters = [ ];
+               }
+
+               if ( titleText ) {
+                       this.errorMessageParameters.push( titleText );
+               }
+       }
+
+       MalformedTitleException.prototype = createObject(Error.prototype);
+       MalformedTitleException.prototype.name = 'MalformedTitleException';
+       MalformedTitleException.prototype.constructor = MalformedTitleException;
+       mw.MalformedTitleException = MalformedTitleException;
+
 }( mediaWiki, jQuery ) );
index f2b4b00..0c24720 100644 (file)
 
                        /**
                         * @since 1.26
-                        * @param {Object[]} modules List of module registry objects
+                        * @param {Array} modules List of module names
                         * @return {string} Hash of concatenated version hashes.
                         */
                        function getCombinedVersion( modules ) {
                                var hashes = $.map( modules, function ( module ) {
-                                       return module.version;
+                                       return registry[module].version;
                                } );
                                // Trim for consistency with server-side ResourceLoader::makeHash. It also helps
                                // save precious space in the limited query string. Otherwise modules are more
diff --git a/tests/phpunit/includes/exception/HttpErrorTest.php b/tests/phpunit/includes/exception/HttpErrorTest.php
new file mode 100644 (file)
index 0000000..66fe90c
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @todo tests for HttpError::report
+ *
+ * @covers HttpError
+ */
+class HttpErrorTest extends MediaWikiTestCase {
+
+       public function testIsLoggable() {
+               $httpError = new HttpError( 500, 'server error!' );
+               $this->assertFalse( $httpError->isLoggable(), 'http error is not loggable' );
+       }
+
+       public function testGetStatusCode() {
+               $httpError = new HttpError( 500, 'server error!' );
+               $this->assertEquals( 500, $httpError->getStatusCode() );
+       }
+
+       /**
+        * @dataProvider getHtmlProvider
+        */
+       public function testGetHtml( array $expected, $content, $header ) {
+               $httpError = new HttpError( 500, $content, $header );
+               $errorHtml = $httpError->getHtml();
+
+               foreach ( $expected as $key => $html ) {
+                       $this->assertContains( $html, $errorHtml, $key );
+               }
+       }
+
+       public function getHtmlProvider() {
+               return array(
+                       array(
+                               array(
+                                       'head html' => '<head><title>Server Error 123</title></head>',
+                                       'body html' => '<body><h1>Server Error 123</h1>'
+                                               . '<p>a server error!</p></body>'
+                               ),
+                               'a server error!',
+                               'Server Error 123'
+                       ),
+                       array(
+                               array(
+                                       'head html' => '<head><title>loginerror</title></head>',
+                                       'body html' => '<body><h1>loginerror</h1>'
+                                       . '<p>suspicious-userlogout</p></body>'
+                               ),
+                               new RawMessage( 'suspicious-userlogout' ),
+                               new RawMessage( 'loginerror' )
+                       ),
+                       array(
+                               array(
+                                       'head html' => '<html><head><title>Internal Server Error</title></head>',
+                                       'body html' => '<body><h1>Internal Server Error</h1>'
+                                               . '<p>a server error!</p></body></html>'
+                               ),
+                               'a server error!',
+                               null
+                       )
+               );
+       }
+
+
+}
diff --git a/tests/phpunit/includes/utils/MWFunctionTest.php b/tests/phpunit/includes/utils/MWFunctionTest.php
deleted file mode 100644 (file)
index f4d1799..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-/**
- * @covers MWFunction
- */
-class MWFunctionTest extends MediaWikiTestCase {
-       public function testNewObjFunction() {
-               $arg1 = 'Foo';
-               $arg2 = 'Bar';
-               $arg3 = array( 'Baz' );
-               $arg4 = new ExampleObject;
-
-               $args = array( $arg1, $arg2, $arg3, $arg4 );
-
-               $newObject = new MWBlankClass( $arg1, $arg2, $arg3, $arg4 );
-               $this->hideDeprecated( 'MWFunction::newObj' );
-               $this->assertEquals(
-                       MWFunction::newObj( 'MWBlankClass', $args )->args,
-                       $newObject->args
-               );
-       }
-}
-
-class MWBlankClass {
-
-       public $args = array();
-
-       function __construct( $arg1, $arg2, $arg3, $arg4 ) {
-               $this->args = array( $arg1, $arg2, $arg3, $arg4 );
-       }
-}
-
-class ExampleObject {
-}