28 if ( !defined(
'MEDIAWIKI' ) ) {
29 echo
"This file is part of MediaWiki, it is not a valid entry point.\n";
67 'sunday',
'monday',
'tuesday',
'wednesday',
'thursday',
72 'sun',
'mon',
'tue',
'wed',
'thu',
'fri',
'sat'
76 'january',
'february',
'march',
'april',
'may_long',
'june',
77 'july',
'august',
'september',
'october',
'november',
81 'january-gen',
'february-gen',
'march-gen',
'april-gen',
'may-gen',
'june-gen',
82 'july-gen',
'august-gen',
'september-gen',
'october-gen',
'november-gen',
86 'jan',
'feb',
'mar',
'apr',
'may',
'jun',
'jul',
'aug',
87 'sep',
'oct',
'nov',
'dec'
91 'iranian-calendar-m1',
'iranian-calendar-m2',
'iranian-calendar-m3',
92 'iranian-calendar-m4',
'iranian-calendar-m5',
'iranian-calendar-m6',
93 'iranian-calendar-m7',
'iranian-calendar-m8',
'iranian-calendar-m9',
94 'iranian-calendar-m10',
'iranian-calendar-m11',
'iranian-calendar-m12'
98 'hebrew-calendar-m1',
'hebrew-calendar-m2',
'hebrew-calendar-m3',
99 'hebrew-calendar-m4',
'hebrew-calendar-m5',
'hebrew-calendar-m6',
100 'hebrew-calendar-m7',
'hebrew-calendar-m8',
'hebrew-calendar-m9',
101 'hebrew-calendar-m10',
'hebrew-calendar-m11',
'hebrew-calendar-m12',
102 'hebrew-calendar-m6a',
'hebrew-calendar-m6b'
106 'hebrew-calendar-m1-gen',
'hebrew-calendar-m2-gen',
'hebrew-calendar-m3-gen',
107 'hebrew-calendar-m4-gen',
'hebrew-calendar-m5-gen',
'hebrew-calendar-m6-gen',
108 'hebrew-calendar-m7-gen',
'hebrew-calendar-m8-gen',
'hebrew-calendar-m9-gen',
109 'hebrew-calendar-m10-gen',
'hebrew-calendar-m11-gen',
'hebrew-calendar-m12-gen',
110 'hebrew-calendar-m6a-gen',
'hebrew-calendar-m6b-gen'
114 'hijri-calendar-m1',
'hijri-calendar-m2',
'hijri-calendar-m3',
115 'hijri-calendar-m4',
'hijri-calendar-m5',
'hijri-calendar-m6',
116 'hijri-calendar-m7',
'hijri-calendar-m8',
'hijri-calendar-m9',
117 'hijri-calendar-m10',
'hijri-calendar-m11',
'hijri-calendar-m12'
124 static public $durationIntervals = [
125 'millennia' => 31556952000,
126 'centuries' => 3155695200,
127 'decades' => 315569520,
142 static private $fallbackLanguageCache = [];
153 static private $lre =
"\xE2\x80\xAA";
154 static private $rle =
"\xE2\x80\xAB";
155 static private $pdf =
"\xE2\x80\xAC";
170 static private $strongDirRegex =
'/(?:([\x{41}-\x{5a}\x{61}-\x{7a}\x{aa}\x{b5}\x{ba}\x{c0}-\x{d6}\x{d8}-\x{f6}\x{f8}-\x{2b8}\x{2bb}-\x{2c1}\x{2d0}\x{2d1}\x{2e0}-\x{2e4}\x{2ee}\x{370}-\x{373}\x{376}\x{377}\x{37a}-\x{37d}\x{37f}\x{386}\x{388}-\x{38a}\x{38c}\x{38e}-\x{3a1}\x{3a3}-\x{3f5}\x{3f7}-\x{482}\x{48a}-\x{52f}\x{531}-\x{556}\x{559}-\x{55f}\x{561}-\x{587}\x{589}\x{903}-\x{939}\x{93b}\x{93d}-\x{940}\x{949}-\x{94c}\x{94e}-\x{950}\x{958}-\x{961}\x{964}-\x{980}\x{982}\x{983}\x{985}-\x{98c}\x{98f}\x{990}\x{993}-\x{9a8}\x{9aa}-\x{9b0}\x{9b2}\x{9b6}-\x{9b9}\x{9bd}-\x{9c0}\x{9c7}\x{9c8}\x{9cb}\x{9cc}\x{9ce}\x{9d7}\x{9dc}\x{9dd}\x{9df}-\x{9e1}\x{9e6}-\x{9f1}\x{9f4}-\x{9fa}\x{a03}\x{a05}-\x{a0a}\x{a0f}\x{a10}\x{a13}-\x{a28}\x{a2a}-\x{a30}\x{a32}\x{a33}\x{a35}\x{a36}\x{a38}\x{a39}\x{a3e}-\x{a40}\x{a59}-\x{a5c}\x{a5e}\x{a66}-\x{a6f}\x{a72}-\x{a74}\x{a83}\x{a85}-\x{a8d}\x{a8f}-\x{a91}\x{a93}-\x{aa8}\x{aaa}-\x{ab0}\x{ab2}\x{ab3}\x{ab5}-\x{ab9}\x{abd}-\x{ac0}\x{ac9}\x{acb}\x{acc}\x{ad0}\x{ae0}\x{ae1}\x{ae6}-\x{af0}\x{af9}\x{b02}\x{b03}\x{b05}-\x{b0c}\x{b0f}\x{b10}\x{b13}-\x{b28}\x{b2a}-\x{b30}\x{b32}\x{b33}\x{b35}-\x{b39}\x{b3d}\x{b3e}\x{b40}\x{b47}\x{b48}\x{b4b}\x{b4c}\x{b57}\x{b5c}\x{b5d}\x{b5f}-\x{b61}\x{b66}-\x{b77}\x{b83}\x{b85}-\x{b8a}\x{b8e}-\x{b90}\x{b92}-\x{b95}\x{b99}\x{b9a}\x{b9c}\x{b9e}\x{b9f}\x{ba3}\x{ba4}\x{ba8}-\x{baa}\x{bae}-\x{bb9}\x{bbe}\x{bbf}\x{bc1}\x{bc2}\x{bc6}-\x{bc8}\x{bca}-\x{bcc}\x{bd0}\x{bd7}\x{be6}-\x{bf2}\x{c01}-\x{c03}\x{c05}-\x{c0c}\x{c0e}-\x{c10}\x{c12}-\x{c28}\x{c2a}-\x{c39}\x{c3d}\x{c41}-\x{c44}\x{c58}-\x{c5a}\x{c60}\x{c61}\x{c66}-\x{c6f}\x{c7f}\x{c82}\x{c83}\x{c85}-\x{c8c}\x{c8e}-\x{c90}\x{c92}-\x{ca8}\x{caa}-\x{cb3}\x{cb5}-\x{cb9}\x{cbd}-\x{cc4}\x{cc6}-\x{cc8}\x{cca}\x{ccb}\x{cd5}\x{cd6}\x{cde}\x{ce0}\x{ce1}\x{ce6}-\x{cef}\x{cf1}\x{cf2}\x{d02}\x{d03}\x{d05}-\x{d0c}\x{d0e}-\x{d10}\x{d12}-\x{d3a}\x{d3d}-\x{d40}\x{d46}-\x{d48}\x{d4a}-\x{d4c}\x{d4e}\x{d57}\x{d5f}-\x{d61}\x{d66}-\x{d75}\x{d79}-\x{d7f}\x{d82}\x{d83}\x{d85}-\x{d96}\x{d9a}-\x{db1}\x{db3}-\x{dbb}\x{dbd}\x{dc0}-\x{dc6}\x{dcf}-\x{dd1}\x{dd8}-\x{ddf}\x{de6}-\x{def}\x{df2}-\x{df4}\x{e01}-\x{e30}\x{e32}\x{e33}\x{e40}-\x{e46}\x{e4f}-\x{e5b}\x{e81}\x{e82}\x{e84}\x{e87}\x{e88}\x{e8a}\x{e8d}\x{e94}-\x{e97}\x{e99}-\x{e9f}\x{ea1}-\x{ea3}\x{ea5}\x{ea7}\x{eaa}\x{eab}\x{ead}-\x{eb0}\x{eb2}\x{eb3}\x{ebd}\x{ec0}-\x{ec4}\x{ec6}\x{ed0}-\x{ed9}\x{edc}-\x{edf}\x{f00}-\x{f17}\x{f1a}-\x{f34}\x{f36}\x{f38}\x{f3e}-\x{f47}\x{f49}-\x{f6c}\x{f7f}\x{f85}\x{f88}-\x{f8c}\x{fbe}-\x{fc5}\x{fc7}-\x{fcc}\x{fce}-\x{fda}\x{1000}-\x{102c}\x{1031}\x{1038}\x{103b}\x{103c}\x{103f}-\x{1057}\x{105a}-\x{105d}\x{1061}-\x{1070}\x{1075}-\x{1081}\x{1083}\x{1084}\x{1087}-\x{108c}\x{108e}-\x{109c}\x{109e}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1360}-\x{137c}\x{1380}-\x{138f}\x{13a0}-\x{13f5}\x{13f8}-\x{13fd}\x{1401}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16f8}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1735}\x{1736}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17b6}\x{17be}-\x{17c5}\x{17c7}\x{17c8}\x{17d4}-\x{17da}\x{17dc}\x{17e0}-\x{17e9}\x{1810}-\x{1819}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191e}\x{1923}-\x{1926}\x{1929}-\x{192b}\x{1930}\x{1931}\x{1933}-\x{1938}\x{1946}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19b0}-\x{19c9}\x{19d0}-\x{19da}\x{1a00}-\x{1a16}\x{1a19}\x{1a1a}\x{1a1e}-\x{1a55}\x{1a57}\x{1a61}\x{1a63}\x{1a64}\x{1a6d}-\x{1a72}\x{1a80}-\x{1a89}\x{1a90}-\x{1a99}\x{1aa0}-\x{1aad}\x{1b04}-\x{1b33}\x{1b35}\x{1b3b}\x{1b3d}-\x{1b41}\x{1b43}-\x{1b4b}\x{1b50}-\x{1b6a}\x{1b74}-\x{1b7c}\x{1b82}-\x{1ba1}\x{1ba6}\x{1ba7}\x{1baa}\x{1bae}-\x{1be5}\x{1be7}\x{1bea}-\x{1bec}\x{1bee}\x{1bf2}\x{1bf3}\x{1bfc}-\x{1c2b}\x{1c34}\x{1c35}\x{1c3b}-\x{1c49}\x{1c4d}-\x{1c7f}\x{1cc0}-\x{1cc7}\x{1cd3}\x{1ce1}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf3}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{200e}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{214f}\x{2160}-\x{2188}\x{2336}-\x{237a}\x{2395}\x{249c}-\x{24e9}\x{26ac}\x{2800}-\x{28ff}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d70}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{302e}\x{302f}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{3190}-\x{31ba}\x{31f0}-\x{321c}\x{3220}-\x{324f}\x{3260}-\x{327b}\x{327f}-\x{32b0}\x{32c0}-\x{32cb}\x{32d0}-\x{32fe}\x{3300}-\x{3376}\x{337b}-\x{33dd}\x{33e0}-\x{33fe}\x{3400}-\x{4db5}\x{4e00}-\x{9fd5}\x{a000}-\x{a48c}\x{a4d0}-\x{a60c}\x{a610}-\x{a62b}\x{a640}-\x{a66e}\x{a680}-\x{a69d}\x{a6a0}-\x{a6ef}\x{a6f2}-\x{a6f7}\x{a722}-\x{a787}\x{a789}-\x{a7ad}\x{a7b0}-\x{a7b7}\x{a7f7}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a824}\x{a827}\x{a830}-\x{a837}\x{a840}-\x{a873}\x{a880}-\x{a8c3}\x{a8ce}-\x{a8d9}\x{a8f2}-\x{a8fd}\x{a900}-\x{a925}\x{a92e}-\x{a946}\x{a952}\x{a953}\x{a95f}-\x{a97c}\x{a983}-\x{a9b2}\x{a9b4}\x{a9b5}\x{a9ba}\x{a9bb}\x{a9bd}-\x{a9cd}\x{a9cf}-\x{a9d9}\x{a9de}-\x{a9e4}\x{a9e6}-\x{a9fe}\x{aa00}-\x{aa28}\x{aa2f}\x{aa30}\x{aa33}\x{aa34}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa4d}\x{aa50}-\x{aa59}\x{aa5c}-\x{aa7b}\x{aa7d}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aaeb}\x{aaee}-\x{aaf5}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{ab30}-\x{ab65}\x{ab70}-\x{abe4}\x{abe6}\x{abe7}\x{abe9}-\x{abec}\x{abf0}-\x{abf9}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{e000}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}\x{10000}-\x{1000b}\x{1000d}-\x{10026}\x{10028}-\x{1003a}\x{1003c}\x{1003d}\x{1003f}-\x{1004d}\x{10050}-\x{1005d}\x{10080}-\x{100fa}\x{10100}\x{10102}\x{10107}-\x{10133}\x{10137}-\x{1013f}\x{101d0}-\x{101fc}\x{10280}-\x{1029c}\x{102a0}-\x{102d0}\x{10300}-\x{10323}\x{10330}-\x{1034a}\x{10350}-\x{10375}\x{10380}-\x{1039d}\x{1039f}-\x{103c3}\x{103c8}-\x{103d5}\x{10400}-\x{1049d}\x{104a0}-\x{104a9}\x{10500}-\x{10527}\x{10530}-\x{10563}\x{1056f}\x{10600}-\x{10736}\x{10740}-\x{10755}\x{10760}-\x{10767}\x{11000}\x{11002}-\x{11037}\x{11047}-\x{1104d}\x{11066}-\x{1106f}\x{11082}-\x{110b2}\x{110b7}\x{110b8}\x{110bb}-\x{110c1}\x{110d0}-\x{110e8}\x{110f0}-\x{110f9}\x{11103}-\x{11126}\x{1112c}\x{11136}-\x{11143}\x{11150}-\x{11172}\x{11174}-\x{11176}\x{11182}-\x{111b5}\x{111bf}-\x{111c9}\x{111cd}\x{111d0}-\x{111df}\x{111e1}-\x{111f4}\x{11200}-\x{11211}\x{11213}-\x{1122e}\x{11232}\x{11233}\x{11235}\x{11238}-\x{1123d}\x{11280}-\x{11286}\x{11288}\x{1128a}-\x{1128d}\x{1128f}-\x{1129d}\x{1129f}-\x{112a9}\x{112b0}-\x{112de}\x{112e0}-\x{112e2}\x{112f0}-\x{112f9}\x{11302}\x{11303}\x{11305}-\x{1130c}\x{1130f}\x{11310}\x{11313}-\x{11328}\x{1132a}-\x{11330}\x{11332}\x{11333}\x{11335}-\x{11339}\x{1133d}-\x{1133f}\x{11341}-\x{11344}\x{11347}\x{11348}\x{1134b}-\x{1134d}\x{11350}\x{11357}\x{1135d}-\x{11363}\x{11480}-\x{114b2}\x{114b9}\x{114bb}-\x{114be}\x{114c1}\x{114c4}-\x{114c7}\x{114d0}-\x{114d9}\x{11580}-\x{115b1}\x{115b8}-\x{115bb}\x{115be}\x{115c1}-\x{115db}\x{11600}-\x{11632}\x{1163b}\x{1163c}\x{1163e}\x{11641}-\x{11644}\x{11650}-\x{11659}\x{11680}-\x{116aa}\x{116ac}\x{116ae}\x{116af}\x{116b6}\x{116c0}-\x{116c9}\x{11700}-\x{11719}\x{11720}\x{11721}\x{11726}\x{11730}-\x{1173f}\x{118a0}-\x{118f2}\x{118ff}\x{11ac0}-\x{11af8}\x{12000}-\x{12399}\x{12400}-\x{1246e}\x{12470}-\x{12474}\x{12480}-\x{12543}\x{13000}-\x{1342e}\x{14400}-\x{14646}\x{16800}-\x{16a38}\x{16a40}-\x{16a5e}\x{16a60}-\x{16a69}\x{16a6e}\x{16a6f}\x{16ad0}-\x{16aed}\x{16af5}\x{16b00}-\x{16b2f}\x{16b37}-\x{16b45}\x{16b50}-\x{16b59}\x{16b5b}-\x{16b61}\x{16b63}-\x{16b77}\x{16b7d}-\x{16b8f}\x{16f00}-\x{16f44}\x{16f50}-\x{16f7e}\x{16f93}-\x{16f9f}\x{1b000}\x{1b001}\x{1bc00}-\x{1bc6a}\x{1bc70}-\x{1bc7c}\x{1bc80}-\x{1bc88}\x{1bc90}-\x{1bc99}\x{1bc9c}\x{1bc9f}\x{1d000}-\x{1d0f5}\x{1d100}-\x{1d126}\x{1d129}-\x{1d166}\x{1d16a}-\x{1d172}\x{1d183}\x{1d184}\x{1d18c}-\x{1d1a9}\x{1d1ae}-\x{1d1e8}\x{1d360}-\x{1d371}\x{1d400}-\x{1d454}\x{1d456}-\x{1d49c}\x{1d49e}\x{1d49f}\x{1d4a2}\x{1d4a5}\x{1d4a6}\x{1d4a9}-\x{1d4ac}\x{1d4ae}-\x{1d4b9}\x{1d4bb}\x{1d4bd}-\x{1d4c3}\x{1d4c5}-\x{1d505}\x{1d507}-\x{1d50a}\x{1d50d}-\x{1d514}\x{1d516}-\x{1d51c}\x{1d51e}-\x{1d539}\x{1d53b}-\x{1d53e}\x{1d540}-\x{1d544}\x{1d546}\x{1d54a}-\x{1d550}\x{1d552}-\x{1d6a5}\x{1d6a8}-\x{1d6da}\x{1d6dc}-\x{1d714}\x{1d716}-\x{1d74e}\x{1d750}-\x{1d788}\x{1d78a}-\x{1d7c2}\x{1d7c4}-\x{1d7cb}\x{1d800}-\x{1d9ff}\x{1da37}-\x{1da3a}\x{1da6d}-\x{1da74}\x{1da76}-\x{1da83}\x{1da85}-\x{1da8b}\x{1f110}-\x{1f12e}\x{1f130}-\x{1f169}\x{1f170}-\x{1f19a}\x{1f1e6}-\x{1f202}\x{1f210}-\x{1f23a}\x{1f240}-\x{1f248}\x{1f250}\x{1f251}\x{20000}-\x{2a6d6}\x{2a700}-\x{2b734}\x{2b740}-\x{2b81d}\x{2b820}-\x{2cea1}\x{2f800}-\x{2fa1d}\x{f0000}-\x{ffffd}\x{100000}-\x{10fffd}])|([\x{590}\x{5be}\x{5c0}\x{5c3}\x{5c6}\x{5c8}-\x{5ff}\x{7c0}-\x{7ea}\x{7f4}\x{7f5}\x{7fa}-\x{815}\x{81a}\x{824}\x{828}\x{82e}-\x{858}\x{85c}-\x{89f}\x{200f}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb4f}\x{10800}-\x{1091e}\x{10920}-\x{10a00}\x{10a04}\x{10a07}-\x{10a0b}\x{10a10}-\x{10a37}\x{10a3b}-\x{10a3e}\x{10a40}-\x{10ae4}\x{10ae7}-\x{10b38}\x{10b40}-\x{10e5f}\x{10e7f}-\x{10fff}\x{1e800}-\x{1e8cf}\x{1e8d7}-\x{1edff}\x{1ef00}-\x{1efff}\x{608}\x{60b}\x{60d}\x{61b}-\x{64a}\x{66d}-\x{66f}\x{671}-\x{6d5}\x{6e5}\x{6e6}\x{6ee}\x{6ef}\x{6fa}-\x{710}\x{712}-\x{72f}\x{74b}-\x{7a5}\x{7b1}-\x{7bf}\x{8a0}-\x{8e2}\x{fb50}-\x{fd3d}\x{fd40}-\x{fdcf}\x{fdf0}-\x{fdfc}\x{fdfe}\x{fdff}\x{fe70}-\x{fefe}\x{1ee00}-\x{1eeef}\x{1eef2}-\x{1eeff}]))/u';
182 if ( isset( $wgDummyLanguageCodes[
$code] ) ) {
183 $code = $wgDummyLanguageCodes[
$code];
187 $langObj = isset( self::$mLangObjCache[$code] )
188 ? self::$mLangObjCache[
$code]
189 : self::newFromCode( $code );
192 self::$mLangObjCache = array_merge( [ $code => $langObj ], self::$mLangObjCache );
194 self::$mLangObjCache = array_slice( self::$mLangObjCache, 0, $wgLangObjCacheSize,
true );
207 throw new MWException(
"Invalid language code \"$code\"" );
219 $class = self::classFromCode(
$code );
220 if ( class_exists( $class ) ) {
227 foreach ( $fallbacks
as $fallbackCode ) {
229 throw new MWException(
"Invalid fallback '$fallbackCode' in fallback sequence for '$code'" );
232 $class = self::classFromCode( $fallbackCode );
233 if ( class_exists( $class ) ) {
240 throw new MWException(
"Invalid fallback sequence for language '$code'" );
252 if ( !self::isValidBuiltInCode(
$code ) ) {
256 if (
$code ===
'qqq' ) {
260 return is_readable( self::getMessagesFileName(
$code ) ) ||
261 is_readable( self::getJsonMessagesFileName(
$code ) );
282 $alphanum =
'[a-z0-9]';
283 $x =
'x'; #
private use singleton
284 $singleton =
'[a-wy-z]'; #
other singleton
285 $s = $lenient ?
'[-_]' :
'-';
287 $language =
"$alpha{2,8}|$alpha{2,3}$s$alpha{3}";
288 $script =
"$alpha{4}"; # ISO 15924
289 $region =
"(?:$alpha{2}|$digit{3})"; # ISO 3166-1 alpha-2
or UN M.49
290 $variant =
"(?:$alphanum{5,8}|$digit$alphanum{3})";
291 $extension =
"$singleton(?:$s$alphanum{2,8})+";
292 $privateUse =
"$x(?:$s$alphanum{1,8})+";
294 # Define certain grandfathered codes, since otherwise the regex is pretty useless.
295 # Since these are limited, this is safe even later changes to the registry --
296 # the only oddity is that it might change the type of the tag, and thus
297 # the results from the capturing groups.
298 # http://www.iana.org/assignments/language-subtag-registry
300 $grandfathered =
"en{$s}GB{$s}oed"
301 .
"|i{$s}(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|tao|tay|tsu)"
302 .
"|no{$s}(?:bok|nyn)"
303 .
"|sgn{$s}(?:BE{$s}(?:fr|nl)|CH{$s}de)"
304 .
"|zh{$s}min{$s}nan";
306 $variantList =
"$variant(?:$s$variant)*";
307 $extensionList =
"$extension(?:$s$extension)*";
309 $langtag =
"(?:($language)"
312 .
"(?:$s$variantList)?"
313 .
"(?:$s$extensionList)?"
314 .
"(?:$s$privateUse)?)";
316 # The final breakdown, with capturing groups for each of these components
317 # The variants, extensions, grandfathered, and private-use may have interior '-'
319 $root =
"^(?:$langtag|$privateUse|$grandfathered)$";
321 return (
bool)preg_match(
"/$root/", strtolower(
$code ) );
342 strcspn( $code,
":/\\\000&<>'\"" ) === strlen( $code )
360 if ( !is_string(
$code ) ) {
361 if ( is_object(
$code ) ) {
362 $addmsg =
" of class " . get_class(
$code );
367 throw new MWException( __METHOD__ .
" must be passed a string, $type given$addmsg" );
370 return (
bool)preg_match(
'/^[a-z0-9-]{2,}$/',
$code );
384 if ( !self::isValidBuiltInCode(
$tag ) ) {
389 || self::fetchLanguageName( $tag, $tag ) !==
''
403 if ( is_null( self::$dataCache ) ) {
405 $class = $wgLocalisationCacheConf[
'class'];
406 self::$dataCache =
new $class( $wgLocalisationCacheConf );
408 return self::$dataCache;
414 if ( get_class( $this ) ==
'Language' ) {
417 $this->mCode = str_replace(
'_',
'-', strtolower( substr( get_class( $this ), 8 ) ) );
419 self::getLocalisationCache();
427 unset( $this->
$name );
443 return self::getFallbacksFor( $this->mCode );
451 return self::$dataCache->getItem( $this->mCode,
'bookstoreList' );
461 if ( is_null( $this->namespaceNames ) ) {
464 $this->namespaceNames = self::$dataCache->getItem( $this->mCode,
'namespaceNames' );
467 $this->namespaceNames = $wgExtraNamespaces + $this->namespaceNames + $validNamespaces;
470 if ( $wgMetaNamespaceTalk ) {
478 # Sometimes a language will be localised but not actually exist on this wiki.
479 foreach ( $this->namespaceNames
as $key => $text ) {
480 if ( !isset( $validNamespaces[
$key] ) ) {
481 unset( $this->namespaceNames[$key] );
485 # The above mixing may leave namespaces out of canonical order.
486 # Re-order by namespace ID number...
487 ksort( $this->namespaceNames );
489 Hooks::run(
'LanguageGetNamespaces', [ &$this->namespaceNames ] );
501 $this->mNamespaceIds = null;
508 $this->namespaceNames = null;
509 $this->mNamespaceIds = null;
510 $this->namespaceAliases = null;
521 foreach ( $ns
as $k => $v ) {
522 $ns[$k] = strtr( $v,
'_',
' ' );
540 return isset( $ns[$index] ) ? $ns[$index] :
false;
558 return strtr( $ns,
'_',
' ' );
572 $ns = $wgExtraGenderNamespaces +
573 (
array)self::$dataCache->getItem( $this->mCode,
'namespaceGenderAliases' );
575 return isset( $ns[$index][$gender] ) ? $ns[$index][$gender] : $this->
getNsText( $index );
586 if ( count( $wgExtraGenderNamespaces ) > 0 ) {
589 } elseif ( isset( $wgExtraNamespaces[
NS_USER] ) && isset( $wgExtraNamespaces[
NS_USER_TALK] ) ) {
595 $aliases = self::$dataCache->getItem( $this->mCode,
'namespaceGenderAliases' );
596 return count( $aliases ) > 0;
609 $lctext = $this->
lc( $text );
611 return isset( $ids[$lctext] ) ? $ids[$lctext] :
false;
618 if ( is_null( $this->namespaceAliases ) ) {
619 $aliases = self::$dataCache->getItem( $this->mCode,
'namespaceAliases' );
623 foreach ( $aliases
as $name => $index ) {
625 unset( $aliases[
$name] );
627 $aliases[
$name] = $index;
633 $genders = $wgExtraGenderNamespaces +
634 (
array)self::$dataCache->getItem( $this->mCode,
'namespaceGenderAliases' );
635 foreach ( $genders
as $index => $forms ) {
636 foreach ( $forms
as $alias ) {
637 $aliases[$alias] = $index;
641 # Also add converted namespace names as aliases, to avoid confusion.
642 $convertedNames = [];
644 if ( $variant === $this->mCode ) {
648 $convertedNames[$this->
getConverter()->convertNamespace( $ns, $variant )] = $ns;
652 $this->namespaceAliases = $aliases + $convertedNames;
662 if ( is_null( $this->mNamespaceIds ) ) {
664 # Put namespace names and aliases into a hashtable.
665 # If this is too slow, then we should arrange it so that it is done
666 # before caching. The catch is that at pre-cache time, the above
667 # class-specific fixup hasn't been done.
668 $this->mNamespaceIds = [];
670 $this->mNamespaceIds[$this->
lc(
$name )] = $index;
673 $this->mNamespaceIds[$this->
lc(
$name )] = $index;
675 if ( $wgNamespaceAliases ) {
676 foreach ( $wgNamespaceAliases
as $name => $index ) {
677 $this->mNamespaceIds[$this->
lc(
$name )] = $index;
692 $lctext = $this->
lc( $text );
694 if ( $ns !== null ) {
698 return isset( $ids[$lctext] ) ? $ids[$lctext] :
false;
709 $msg =
"variantname-$code";
710 if ( $usemsg &&
wfMessage( $msg )->exists() ) {
715 return $name; #
if it's defined as a language name, show that
717 # otherwise, output the language code
725 public function getDatePreferences() {
726 return self::$dataCache->getItem( $this->mCode, 'datePreferences
' );
732 function getDateFormats() {
733 return self::$dataCache->getItem( $this->mCode, 'dateFormats
' );
739 public function getDefaultDateFormat() {
740 $df = self::$dataCache->getItem( $this->mCode, 'defaultDateFormat
' );
741 if ( $df === 'dmy
or mdy
' ) {
742 global $wgAmericanDates;
743 return $wgAmericanDates ? 'mdy
' : 'dmy
';
752 public function getDatePreferenceMigrationMap() {
753 return self::$dataCache->getItem( $this->mCode, 'datePreferenceMigrationMap
' );
760 function getImageFile( $image ) {
761 return self::$dataCache->getSubitem( $this->mCode, 'imageFiles
', $image );
768 public function getImageFiles() {
769 return self::$dataCache->getItem( $this->mCode, 'imageFiles
' );
775 public function getExtraUserToggles() {
776 return (array)self::$dataCache->getItem( $this->mCode, 'extraUserToggles
' );
783 function getUserToggle( $tog ) {
784 return $this->getMessageFromDB( "tog-$tog" );
798 public static function fetchLanguageNames( $inLanguage = null, $include = 'mw
' ) {
799 $cacheKey = $inLanguage === null ? 'null
' : $inLanguage;
800 $cacheKey .= ":$include";
801 if ( self::$languageNameCache === null ) {
802 self::$languageNameCache = new HashBagOStuff( [ 'maxKeys
' => 20 ] );
805 $ret = self::$languageNameCache->get( $cacheKey );
807 $ret = self::fetchLanguageNamesUncached( $inLanguage, $include );
808 self::$languageNameCache->set( $cacheKey, $ret );
823 private static function fetchLanguageNamesUncached( $inLanguage = null, $include = 'mw
' ) {
824 global $wgExtraLanguageNames;
826 // If passed an invalid language code to use, fallback to en
827 if ( $inLanguage !== null && !Language::isValidCode( $inLanguage ) ) {
834 # TODO: also include when $inLanguage is null, when this code is more efficient
835 Hooks::run( 'LanguageGetTranslatedLanguageNames
', [ &$names, $inLanguage ] );
838 $mwNames = $wgExtraLanguageNames + MediaWiki\Languages\Data\Names::$names;
839 foreach ( $mwNames as $mwCode => $mwName ) {
840 # - Prefer own MediaWiki native name when not using the hook
841 # - For other names just add if not added through the hook
842 if ( $mwCode === $inLanguage || !isset( $names[$mwCode] ) ) {
843 $names[$mwCode] = $mwName;
847 if ( $include === 'all
' ) {
853 $coreCodes = array_keys( $mwNames );
854 foreach ( $coreCodes as $coreCode ) {
855 $returnMw[$coreCode] = $names[$coreCode];
858 if ( $include === 'mwfile
' ) {
860 # We do this using a foreach over the codes instead of a directory
861 # loop so that messages files in extensions will work correctly.
862 foreach ( $returnMw as $code => $value ) {
863 if ( is_readable( self::getMessagesFileName( $code ) )
864 || is_readable( self::getJsonMessagesFileName( $code ) )
866 $namesMwFile[$code] = $names[$code];
870 ksort( $namesMwFile );
887 $code = strtolower( $code );
888 $array = self::fetchLanguageNames( $inLanguage, $include );
889 return !array_key_exists( $code, $array ) ?
'' : $array[
$code];
899 return $this->
msg( $msg )->text();
908 protected function msg( $msg ) {
909 return wfMessage( $msg )->inLanguage( $this );
924 $monthNames = [
'' ];
925 for ( $i = 1; $i < 13; $i++ ) {
951 $monthNames = [
'' ];
952 for ( $i = 1; $i < 13; $i++ ) {
1015 if ( !$dateTimeObj ) {
1016 $dateTimeObj = DateTime::createFromFormat(
1020 return $dateTimeObj->format(
$code );
1095 $dateTimeObj =
false;
1104 $usedSecond =
false;
1105 $usedMinute =
false;
1112 $usedISOYear =
false;
1113 $usedIsLeapYear =
false;
1115 $usedHebrewMonth =
false;
1116 $usedIranianMonth =
false;
1117 $usedHijriMonth =
false;
1118 $usedHebrewYear =
false;
1119 $usedIranianYear =
false;
1120 $usedHijriYear =
false;
1121 $usedTennoYear =
false;
1123 if ( strlen( $ts ) !== 14 ) {
1124 throw new MWException( __METHOD__ .
": The timestamp $ts should have 14 characters" );
1127 if ( !ctype_digit( $ts ) ) {
1128 throw new MWException( __METHOD__ .
": The timestamp $ts should be a number" );
1131 $formatLength = strlen( $format );
1132 for ( $p = 0; $p < $formatLength; $p++ ) {
1134 $code = $format[$p];
1135 if (
$code ==
'x' && $p < $formatLength - 1 ) {
1136 $code .= $format[++$p];
1139 if ( (
$code ===
'xi'
1145 && $p < $formatLength - 1 ) {
1146 $code .= $format[++$p];
1157 $rawToggle = !$rawToggle;
1170 $usedHebrewMonth =
true;
1172 $hebrew = self::tsToHebrew( $ts );
1178 $num = substr( $ts, 6, 2 );
1188 $num = intval( substr( $ts, 6, 2 ) );
1193 $iranian = self::tsToIranian( $ts );
1200 $hijri = self::tsToHijri( $ts );
1207 $hebrew = self::tsToHebrew( $ts );
1222 $usedIranianMonth =
true;
1224 $iranian = self::tsToIranian( $ts );
1229 $usedHijriMonth =
true;
1231 $hijri = self::tsToHijri( $ts );
1236 $usedHebrewMonth =
true;
1238 $hebrew = self::tsToHebrew( $ts );
1244 $num = substr( $ts, 4, 2 );
1252 $num = intval( substr( $ts, 4, 2 ) );
1255 $usedIranianMonth =
true;
1257 $iranian = self::tsToIranian( $ts );
1262 $usedHijriMonth =
true;
1264 $hijri = self::tsToHijri( $ts );
1269 $usedHebrewMonth =
true;
1271 $hebrew = self::tsToHebrew( $ts );
1276 $usedHebrewMonth =
true;
1278 $hebrew = self::tsToHebrew( $ts );
1284 $num = substr( $ts, 0, 4 );
1287 $usedIranianYear =
true;
1289 $iranian = self::tsToIranian( $ts );
1294 $usedHijriYear =
true;
1296 $hijri = self::tsToHijri( $ts );
1301 $usedHebrewYear =
true;
1303 $hebrew = self::tsToHebrew( $ts );
1310 $thai = self::tsToYear( $ts,
'thai' );
1317 $minguo = self::tsToYear( $ts,
'minguo' );
1322 $usedTennoYear =
true;
1324 $tenno = self::tsToYear( $ts,
'tenno' );
1330 $num = substr( $ts, 2, 2 );
1333 $usedIranianYear =
true;
1335 $iranian = self::tsToIranian( $ts );
1337 $num = substr( $iranian[0], -2 );
1341 $s .= intval( substr( $ts, 8, 2 ) ) < 12 ?
'am' :
'pm';
1345 $s .= intval( substr( $ts, 8, 2 ) ) < 12 ?
'AM' :
'PM';
1349 $h = substr( $ts, 8, 2 );
1350 $num = $h % 12 ? $h % 12 : 12;
1354 $num = intval( substr( $ts, 8, 2 ) );
1358 $h = substr( $ts, 8, 2 );
1359 $num = sprintf(
'%02d', $h % 12 ? $h % 12 : 12 );
1363 $num = substr( $ts, 8, 2 );
1367 $num = substr( $ts, 10, 2 );
1371 $num = substr( $ts, 12, 2 );
1398 $usedIsLeapYear =
true;
1402 $usedISOYear =
true;
1413 # Backslash escaping
1414 if ( $p < $formatLength - 1 ) {
1415 $s .= $format[++$p];
1422 if ( $p < $formatLength - 1 ) {
1423 $endQuote = strpos( $format,
'"', $p + 1 );
1424 if ( $endQuote ===
false ) {
1425 # No terminating quote, assume literal "
1428 $s .= substr( $format, $p + 1, $endQuote - $p - 1 );
1432 # Quote at end of string, assume literal "
1439 if ( $num !==
false ) {
1440 if ( $rawToggle || $raw ) {
1443 } elseif ( $roman ) {
1446 } elseif ( $hebrewNum ) {
1447 $s .= self::hebrewNumeral( $num );
1455 if ( $usedSecond ) {
1457 } elseif ( $usedMinute ) {
1458 $ttl = 60 - substr( $ts, 12, 2 );
1459 } elseif ( $usedHour ) {
1460 $ttl = 3600 - substr( $ts, 10, 2 ) * 60 - substr( $ts, 12, 2 );
1461 } elseif ( $usedAMPM ) {
1462 $ttl = 43200 - ( substr( $ts, 8, 2 ) % 12 ) * 3600 -
1463 substr( $ts, 10, 2 ) * 60 - substr( $ts, 12, 2 );
1467 $usedIranianMonth ||
1476 $ttl = 86400 - substr( $ts, 8, 2 ) * 3600 -
1477 substr( $ts, 10, 2 ) * 60 - substr( $ts, 12, 2 );
1480 $timeRemainingInDay = 86400 - substr( $ts, 8, 2 ) * 3600 -
1481 substr( $ts, 10, 2 ) * 60 - substr( $ts, 12, 2 );
1485 $timeRemainingInDay;
1486 } elseif ( $usedISOYear ) {
1489 $lastWeekOfISOYear = DateTime::createFromFormat(
1491 substr( $ts, 0, 4 ) .
'1228',
1495 $weeksRemaining = $lastWeekOfISOYear - $currentISOWeek;
1496 $timeRemainingInWeek =
1498 + $timeRemainingInDay;
1499 $possibleTtls[] = $weeksRemaining * 604800 + $timeRemainingInWeek;
1505 substr( $ts, 6, 2 ) ) * 86400
1506 + $timeRemainingInDay;
1507 } elseif ( $usedYear ) {
1511 + $timeRemainingInDay;
1512 } elseif ( $usedIsLeapYear ) {
1513 $year = substr( $ts, 0, 4 );
1514 $timeRemainingInYear =
1517 + $timeRemainingInDay;
1519 if ( $mod || ( !( $year % 100 ) && $year % 400 ) ) {
1521 $nextCandidate = $year - $mod + 4;
1522 if ( $nextCandidate % 100 || !( $nextCandidate % 400 ) ) {
1523 $possibleTtls[] = ( $nextCandidate - $year - 1 ) * 365 * 86400 +
1524 $timeRemainingInYear;
1526 $possibleTtls[] = ( $nextCandidate - $year + 3 ) * 365 * 86400 +
1527 $timeRemainingInYear;
1531 $possibleTtls[] = $timeRemainingInYear;
1535 if ( $possibleTtls ) {
1536 $ttl = min( $possibleTtls );
1543 private static $GREG_DAYS = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
1544 private static $IRANIAN_DAYS = [ 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 ];
1559 $gy = substr( $ts, 0, 4 ) -1600;
1560 $gm = substr( $ts, 4, 2 ) -1;
1561 $gd = substr( $ts, 6, 2 ) -1;
1563 # Days passed from the beginning (including leap years)
1565 + floor( ( $gy + 3 ) / 4 )
1566 - floor( ( $gy + 99 ) / 100 )
1567 + floor( ( $gy + 399 ) / 400 );
1570 for ( $i = 0; $i < $gm; $i++ ) {
1571 $gDayNo += self::$GREG_DAYS[$i];
1575 if ( $gm > 1 && ( ( $gy % 4 === 0 && $gy % 100 !== 0 || ( $gy % 400 == 0 ) ) ) ) {
1580 $gDayNo += (int)$gd;
1582 $jDayNo = $gDayNo - 79;
1584 $jNp = floor( $jDayNo / 12053 );
1587 $jy = 979 + 33 * $jNp + 4 * floor( $jDayNo / 1461 );
1590 if ( $jDayNo >= 366 ) {
1591 $jy += floor( ( $jDayNo - 1 ) / 365 );
1592 $jDayNo = floor( ( $jDayNo - 1 ) % 365 );
1595 for ( $i = 0; $i < 11 && $jDayNo >= self::$IRANIAN_DAYS[$i]; $i++ ) {
1596 $jDayNo -= self::$IRANIAN_DAYS[$i];
1602 return [ $jy, $jm, $jd ];
1617 $year = substr( $ts, 0, 4 );
1618 $month = substr( $ts, 4, 2 );
1619 $day = substr( $ts, 6, 2 );
1627 ( $zy > 1582 ) || ( ( $zy == 1582 ) && ( $zm > 10 ) ) ||
1628 ( ( $zy == 1582 ) && ( $zm == 10 ) && ( $zd > 14 ) )
1630 $zjd = (int)( ( 1461 * ( $zy + 4800 + (
int)( ( $zm - 14 ) / 12 ) ) ) / 4 ) +
1631 (
int)( ( 367 * ( $zm - 2 - 12 * ( (int)( ( $zm - 14 ) / 12 ) ) ) ) / 12 ) -
1632 (
int)( ( 3 * (int)( ( ( $zy + 4900 + (
int)( ( $zm - 14 ) / 12 ) ) / 100 ) ) ) / 4 ) +
1635 $zjd = 367 * $zy - (int)( ( 7 * ( $zy + 5001 + (
int)( ( $zm - 9 ) / 7 ) ) ) / 4 ) +
1636 (
int)( ( 275 * $zm ) / 9 ) + $zd + 1729777;
1639 $zl = $zjd -1948440 + 10632;
1640 $zn = (int)( ( $zl - 1 ) / 10631 );
1641 $zl = $zl - 10631 * $zn + 354;
1642 $zj = ( (int)( ( 10985 - $zl ) / 5316 ) ) * ( (int)( ( 50 * $zl ) / 17719 ) ) +
1643 ( (int)( $zl / 5670 ) ) * ( (
int)( ( 43 * $zl ) / 15238 ) );
1644 $zl = $zl - ( (int)( ( 30 - $zj ) / 15 ) ) * ( (int)( ( 17719 * $zj ) / 50 ) ) -
1645 ( (int)( $zj / 16 ) ) * ( (
int)( ( 15238 * $zj ) / 43 ) ) + 29;
1646 $zm = (int)( ( 24 * $zl ) / 709 );
1647 $zd = $zl - (int)( ( 709 * $zm ) / 24 );
1648 $zy = 30 * $zn + $zj - 30;
1650 return [ $zy, $zm, $zd ];
1670 $year = substr( $ts, 0, 4 );
1671 $month = substr( $ts, 4, 2 );
1672 $day = substr( $ts, 6, 2 );
1674 # Calculate Hebrew year
1675 $hebrewYear = $year + 3760;
1677 # Month number when September = 1, August = 12
1679 if ( $month > 12 ) {
1686 # Calculate day of year from 1 September
1688 for ( $i = 1; $i < $month; $i++ ) {
1692 # Check if the year is leap
1693 if ( $year % 400 == 0 || ( $year % 4 == 0 && $year % 100 > 0 ) ) {
1696 } elseif ( $i == 8 || $i == 10 || $i == 1 || $i == 3 ) {
1703 # Calculate the start of the Hebrew year
1704 $start = self::hebrewYearStart( $hebrewYear );
1706 # Calculate next year's start
1707 if ( $dayOfYear <= $start ) {
1708 # Day is before the start of the year - it is the previous year
1710 $nextStart = $start;
1714 # Add days since previous year's 1 September
1716 if ( ( $year % 400 == 0 ) || ( $year % 100 != 0 && $year % 4 == 0 ) ) {
1720 # Start of the new (previous) year
1721 $start = self::hebrewYearStart( $hebrewYear );
1724 $nextStart = self::hebrewYearStart( $hebrewYear + 1 );
1727 # Calculate Hebrew day of year
1728 $hebrewDayOfYear = $dayOfYear - $start;
1730 # Difference between year's days
1731 $diff = $nextStart - $start;
1732 # Add 12 (or 13 for leap years) days to ignore the difference between
1733 # Hebrew and Gregorian year (353 at least vs. 365/6) - now the
1734 # difference is only about the year type
1735 if ( ( $year % 400 == 0 ) || ( $year % 100 != 0 && $year % 4 == 0 ) ) {
1741 # Check the year pattern, and is leap year
1742 # 0 means an incomplete year, 1 means a regular year, 2 means a complete year
1743 # This is mod 30, to work on both leap years (which add 30 days of Adar I)
1744 # and non-leap years
1745 $yearPattern = $diff % 30;
1746 # Check if leap year
1747 $isLeap = $diff >= 30;
1749 # Calculate day in the month from number of day in the Hebrew year
1750 # Don't check Adar - if the day is not in Adar, we will stop before;
1751 # if it is in Adar, we will use it to check if it is Adar I or Adar II
1752 $hebrewDay = $hebrewDayOfYear;
1755 while ( $hebrewMonth <= 12 ) {
1756 # Calculate days in this month
1757 if ( $isLeap && $hebrewMonth == 6 ) {
1758 # Adar in a leap year
1760 # Leap year - has Adar I, with 30 days, and Adar II, with 29 days
1762 if ( $hebrewDay <= $days ) {
1766 # Subtract the days of Adar I
1767 $hebrewDay -= $days;
1770 if ( $hebrewDay <= $days ) {
1776 } elseif ( $hebrewMonth == 2 && $yearPattern == 2 ) {
1777 # Cheshvan in a complete year (otherwise as the rule below)
1779 } elseif ( $hebrewMonth == 3 && $yearPattern == 0 ) {
1780 # Kislev in an incomplete year (otherwise as the rule below)
1783 # Odd months have 30 days, even have 29
1784 $days = 30 - ( $hebrewMonth - 1 ) % 2;
1786 if ( $hebrewDay <= $days ) {
1787 # In the current month
1790 # Subtract the days of the current month
1791 $hebrewDay -= $days;
1792 # Try in the next month
1797 return [ $hebrewYear, $hebrewMonth, $hebrewDay, $days ];
1810 $a = intval( ( 12 * ( $year - 1 ) + 17 ) % 19 );
1811 $b = intval( ( $year - 1 ) % 4 );
1812 $m = 32.044093161144 + 1.5542417966212 * $a + $b / 4.0 - 0.0031777940220923 * ( $year - 1 );
1816 $Mar = intval( $m );
1822 $c = intval( ( $Mar + 3 * ( $year - 1 ) + 5 * $b + 5 ) % 7 );
1823 if ( $c == 0 && $a > 11 && $m >= 0.89772376543210 ) {
1825 } elseif ( $c == 1 && $a > 6 && $m >= 0.63287037037037 ) {
1827 } elseif ( $c == 2 || $c == 4 || $c == 6 ) {
1831 $Mar += intval( ( $year - 3761 ) / 100 ) - intval( ( $year - 3761 ) / 400 ) - 24;
1848 $gy = substr( $ts, 0, 4 );
1849 $gm = substr( $ts, 4, 2 );
1850 $gd = substr( $ts, 6, 2 );
1852 if ( !strcmp( $cName,
'thai' ) ) {
1854 # Add 543 years to the Gregorian calendar
1855 # Months and days are identical
1856 $gy_offset = $gy + 543;
1857 } elseif ( ( !strcmp( $cName,
'minguo' ) ) || !strcmp( $cName,
'juche' ) ) {
1859 # Deduct 1911 years from the Gregorian calendar
1860 # Months and days are identical
1861 $gy_offset = $gy - 1911;
1862 } elseif ( !strcmp( $cName,
'tenno' ) ) {
1863 # Nengō dates up to Meiji period
1864 # Deduct years from the Gregorian calendar
1865 # depending on the nengo periods
1866 # Months and days are identical
1868 || ( ( $gy == 1912 ) && ( $gm < 7 ) )
1869 || ( ( $gy == 1912 ) && ( $gm == 7 ) && ( $gd < 31 ) )
1872 $gy_gannen = $gy - 1868 + 1;
1873 $gy_offset = $gy_gannen;
1874 if ( $gy_gannen == 1 ) {
1877 $gy_offset =
'明治' . $gy_offset;
1879 ( ( $gy == 1912 ) && ( $gm == 7 ) && ( $gd == 31 ) ) ||
1880 ( ( $gy == 1912 ) && ( $gm >= 8 ) ) ||
1881 ( ( $gy > 1912 ) && ( $gy < 1926 ) ) ||
1882 ( ( $gy == 1926 ) && ( $gm < 12 ) ) ||
1883 ( ( $gy == 1926 ) && ( $gm == 12 ) && ( $gd < 26 ) )
1886 $gy_gannen = $gy - 1912 + 1;
1887 $gy_offset = $gy_gannen;
1888 if ( $gy_gannen == 1 ) {
1891 $gy_offset =
'大正' . $gy_offset;
1893 ( ( $gy == 1926 ) && ( $gm == 12 ) && ( $gd >= 26 ) ) ||
1894 ( ( $gy > 1926 ) && ( $gy < 1989 ) ) ||
1895 ( ( $gy == 1989 ) && ( $gm == 1 ) && ( $gd < 8 ) )
1898 $gy_gannen = $gy - 1926 + 1;
1899 $gy_offset = $gy_gannen;
1900 if ( $gy_gannen == 1 ) {
1903 $gy_offset =
'昭和' . $gy_offset;
1906 $gy_gannen = $gy - 1989 + 1;
1907 $gy_offset = $gy_gannen;
1908 if ( $gy_gannen == 1 ) {
1911 $gy_offset =
'平成' . $gy_offset;
1917 return [ $gy_offset, $gm, $gd ];
1934 if ( !preg_match( self::$strongDirRegex, $text,
$matches ) ) {
1952 [
'',
'I',
'II',
'III',
'IV',
'V',
'VI',
'VII',
'VIII',
'IX',
'X' ],
1953 [
'',
'X',
'XX',
'XXX',
'XL',
'L',
'LX',
'LXX',
'LXXX',
'XC',
'C' ],
1954 [
'',
'C',
'CC',
'CCC',
'CD',
'D',
'DC',
'DCC',
'DCCC',
'CM',
'M' ],
1955 [
'',
'M',
'MM',
'MMM',
'MMMM',
'MMMMM',
'MMMMMM',
'MMMMMMM',
1956 'MMMMMMMM',
'MMMMMMMMM',
'MMMMMMMMMM' ]
1959 $num = intval( $num );
1960 if ( $num > 10000 || $num <= 0 ) {
1965 for ( $pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i-- ) {
1966 if ( $num >= $pow10 ) {
1967 $s .= $table[$i][(int)floor( $num / $pow10 )];
1969 $num = $num % $pow10;
1983 [
'',
'א',
'ב',
'ג',
'ד',
'ה',
'ו',
'ז',
'ח',
'ט',
'י' ],
1984 [
'',
'י',
'כ',
'ל',
'מ',
'נ',
'ס',
'ע',
'פ',
'צ',
'ק' ],
1997 [
'',
'א',
'ב',
'ג',
'ד',
'ה',
'ו',
'ז',
'ח',
'ט',
'י' ]
2000 $num = intval( $num );
2001 if ( $num > 9999 || $num <= 0 ) {
2006 if ( $num === 1000 ) {
2008 } elseif ( $num % 1000 === 0 ) {
2009 return $table[0][$num / 1000] .
"' אלפים";
2014 for ( $pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i-- ) {
2015 if ( $num >= $pow10 ) {
2016 if ( $num === 15 || $num === 16 ) {
2017 $letters[] = $table[0][9];
2018 $letters[] = $table[0][$num - 9];
2021 $letters = array_merge(
2023 (
array)$table[$i][intval( $num / $pow10 )]
2026 if ( $pow10 === 1000 ) {
2032 $num = $num % $pow10;
2035 $preTransformLength = count( $letters );
2036 if ( $preTransformLength === 1 ) {
2040 $lastIndex = $preTransformLength - 1;
2041 $letters[$lastIndex] = str_replace(
2042 [
'כ',
'מ',
'נ',
'פ',
'צ' ],
2043 [
'ך',
'ם',
'ן',
'ף',
'ץ' ],
2044 $letters[$lastIndex]
2050 if ( $letters[1] ===
"'" && $preTransformLength === 3 ) {
2053 array_splice( $letters, -1, 0,
'"' );
2057 return implode( $letters );
2071 if ( $tz ===
false ) {
2072 $tz = $wgUser->getOption(
'timecorrection' );
2075 $data = explode(
'|', $tz, 3 );
2077 if ( $data[0] ==
'ZoneInfo' ) {
2078 MediaWiki\suppressWarnings();
2079 $userTZ = timezone_open( $data[2] );
2080 MediaWiki\restoreWarnings();
2081 if ( $userTZ !==
false ) {
2082 $date = date_create( $ts, timezone_open(
'UTC' ) );
2083 date_timezone_set( $date, $userTZ );
2084 $date = date_format( $date,
'YmdHis' );
2087 # Unrecognized timezone, default to 'Offset' with the stored offset.
2088 $data[0] =
'Offset';
2091 if ( $data[0] ==
'System' || $tz ==
'' ) {
2092 # Global offset in minutes.
2094 } elseif ( $data[0] ==
'Offset' ) {
2095 $minDiff = intval( $data[1] );
2097 $data = explode(
':', $tz );
2098 if ( count( $data ) == 2 ) {
2099 $data[0] = intval( $data[0] );
2100 $data[1] = intval( $data[1] );
2101 $minDiff = abs( $data[0] ) * 60 + $data[1];
2102 if ( $data[0] < 0 ) {
2103 $minDiff = -$minDiff;
2106 $minDiff = intval( $data[0] ) * 60;
2110 # No difference ? Return time unchanged
2111 if ( 0 == $minDiff ) {
2115 MediaWiki\suppressWarnings();
2116 # Generate an adjusted date; take advantage of the fact that mktime
2117 # will normalize out-of-range values so we don't have to split $minDiff
2118 # into hours and minutes.
2120 (
int)substr( $ts, 8, 2 ) ), # Hours
2121 (
int)substr( $ts, 10, 2 ) + $minDiff, # Minutes
2122 (
int)substr( $ts, 12, 2 ), # Seconds
2123 (
int)substr( $ts, 4, 2 ), # Month
2124 (
int)substr( $ts, 6, 2 ), # Day
2125 (
int)substr( $ts, 0, 4 ) ); # Year
2127 $date =
date(
'YmdHis',
$t );
2128 MediaWiki\restoreWarnings();
2153 if ( is_bool( $usePrefs ) ) {
2155 $datePreference = $wgUser->getDatePreference();
2160 $datePreference = (
string)$usePrefs;
2164 if ( $datePreference ==
'' ) {
2168 return $datePreference;
2182 $wasDefault =
false;
2183 if ( $pref ==
'default' ) {
2188 if ( !isset( $this->dateFormatStrings[
$type][$pref] ) ) {
2189 $df = self::$dataCache->getSubitem( $this->mCode,
'dateFormats',
"$pref $type" );
2191 if (
$type ===
'pretty' && $df === null ) {
2195 if ( !$wasDefault && $df === null ) {
2197 $df = self::$dataCache->getSubitem( $this->mCode,
'dateFormats',
"$pref $type" );
2200 $this->dateFormatStrings[
$type][$pref] = $df;
2202 return $this->dateFormatStrings[
$type][$pref];
2215 function date( $ts, $adj =
false, $format =
true, $timecorrection =
false ) {
2218 $ts = $this->
userAdjust( $ts, $timecorrection );
2234 function time( $ts, $adj =
false, $format =
true, $timecorrection =
false ) {
2237 $ts = $this->
userAdjust( $ts, $timecorrection );
2254 function timeanddate( $ts, $adj =
false, $format =
true, $timecorrection =
false ) {
2257 $ts = $this->
userAdjust( $ts, $timecorrection );
2278 foreach ( $intervals
as $intervalName => $intervalValue ) {
2281 $message =
wfMessage(
'duration-' . $intervalName )->numParams( $intervalValue );
2282 $segments[] = $message->inLanguage( $this )->escaped();
2300 if ( empty( $chosenIntervals ) ) {
2301 $chosenIntervals = [
2313 $intervals = array_intersect_key( self::$durationIntervals, array_flip( $chosenIntervals ) );
2314 $sortedNames = array_keys( $intervals );
2315 $smallestInterval = array_pop( $sortedNames );
2319 foreach ( $intervals
as $name => $length ) {
2320 $value = floor( $seconds / $length );
2322 if (
$value > 0 || (
$name == $smallestInterval && empty( $segments ) ) ) {
2323 $seconds -=
$value * $length;
2352 $options += [
'timecorrection' =>
true,
'format' =>
true ];
2353 if ( $options[
'timecorrection'] !==
false ) {
2354 if ( $options[
'timecorrection'] ===
true ) {
2355 $offset = $user->
getOption(
'timecorrection' );
2357 $offset = $options[
'timecorrection'];
2361 if ( $options[
'format'] ===
true ) {
2364 $format = $options[
'format'];
2457 if ( $relativeTo === null ) {
2460 if (
$user === null ) {
2466 $offsetRel = $relativeTo->offsetForUser(
$user );
2469 if (
Hooks::run(
'GetHumanTimestamp', [ &$ts, $time, $relativeTo,
$user, $this ] ) ) {
2474 $time->timestamp->sub( $offsetThis );
2475 $relativeTo->timestamp->sub( $offsetRel );
2494 $diff = $ts->
diff( $relativeTo );
2495 $diffDay = (bool)( (
int)$ts->timestamp->
format(
'w' ) -
2496 (int)$relativeTo->timestamp->
format(
'w' ) );
2497 $days = $diff->days ?: (int)$diffDay;
2498 if ( $diff->invert || $days > 5
2499 && $ts->timestamp->
format(
'Y' ) !== $relativeTo->timestamp->
format(
'Y' )
2508 } elseif ( $days > 5 ) {
2512 } elseif ( $days > 1 ) {
2515 $weekday = self::$mWeekdayMsgs[$ts->timestamp->
format(
'w' )];
2519 ->inLanguage( $this )
2522 } elseif ( $days == 1 ) {
2526 ->inLanguage( $this )
2529 } elseif ( $diff->h > 1 || $diff->h == 1 && $diff->i > 30 ) {
2533 ->inLanguage( $this )
2539 } elseif ( $diff->h == 1 ) {
2541 $ts =
wfMessage(
'hours-ago' )->inLanguage( $this )->numParams( 1 )->text();
2542 } elseif ( $diff->i >= 1 ) {
2544 $ts =
wfMessage(
'minutes-ago' )->inLanguage( $this )->numParams( $diff->i )->text();
2545 } elseif ( $diff->s >= 30 ) {
2547 $ts =
wfMessage(
'seconds-ago' )->inLanguage( $this )->numParams( $diff->s )->text();
2561 return self::$dataCache->getSubitem( $this->mCode,
'messages',
$key );
2568 return self::$dataCache->getItem( $this->mCode,
'messages' );
2578 # This is a wrapper for iconv in all languages except esperanto,
2579 # which does some nasty x-conversions beforehand
2581 # Even with //IGNORE iconv can whine about illegal characters in
2582 # *input* string. We just ignore those too.
2583 # REF: http://bugs.php.net/bug.php?id=37166
2584 # REF: https://phabricator.wikimedia.org/T18885
2585 MediaWiki\suppressWarnings();
2586 $text =
iconv( $in,
$out .
'//IGNORE', $string );
2587 MediaWiki\restoreWarnings();
2606 return mb_strtoupper(
$matches[0] );
2614 return mb_strtoupper(
$matches[0] );
2628 } elseif ( $o < 128 ) {
2632 return $this->
uc( $str,
true );
2644 function uc( $str, $first =
false ) {
2647 return mb_strtoupper( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 );
2652 return $this->
isMultibyte( $str ) ? mb_strtoupper( $str ) : strtoupper( $str );
2663 return strval( $str );
2664 } elseif ( $o >= 128 ) {
2665 return $this->
lc( $str,
true );
2666 } elseif ( $o > 96 ) {
2669 $str[0] = strtolower( $str[0] );
2679 function lc( $str, $first =
false ) {
2682 return mb_strtolower( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 );
2684 return strtolower( substr( $str, 0, 1 ) ) . substr( $str, 1 );
2687 return $this->
isMultibyte( $str ) ? mb_strtolower( $str ) : strtolower( $str );
2696 return strlen( $str ) !== mb_strlen( $str );
2705 $str = $this->
lc( $str );
2708 $replaceRegexp =
"/^([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)| ([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/";
2711 return preg_replace_callback(
2713 [ $this,
'ucwordsCallbackMB' ],
2717 return ucwords( strtolower( $str ) );
2729 $str = $this->
lc( $str );
2732 $breaks =
"[ \-\(\)\}\{\.,\?!]";
2735 $replaceRegexp =
"/^([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)|" .
2736 "$breaks([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/";
2738 return preg_replace_callback(
2740 [ $this,
'ucwordbreaksCallbackMB' ],
2744 return preg_replace_callback(
2745 '/\b([\w\x80-\xff]+)\b/',
2746 [ $this,
'ucwordbreaksCallbackAscii' ],
2768 return $this->
uc(
$s );
2777 if ( is_array(
$s ) ) {
2778 throw new MWException(
'Given array to checkTitleEncoding.' );
2791 return self::$dataCache->getItem( $this->mCode,
'fallback8bitEncoding' );
2825 return self::convertDoubleWidth( $string );
2837 static $full = null;
2838 static $half = null;
2840 if ( $full === null ) {
2841 $fullWidth =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
2842 $halfWidth =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
2843 $full = str_split( $fullWidth, 3 );
2844 $half = str_split( $halfWidth );
2847 $string = str_replace( $full, $half, $string );
2857 $string = preg_replace( $pattern,
" $1 ", $string );
2858 $string = preg_replace(
'/ +/',
' ', $string );
2867 # some languages, e.g. Chinese, need to do a conversion
2868 # in order for search results to be displayed correctly
2881 '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
2882 '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})/',
2888 if ( strlen(
$matches[1] ) != 3 ) {
2896 } elseif (
$code < 0xb098 ) {
2897 return "\xe3\x84\xb1";
2898 } elseif (
$code < 0xb2e4 ) {
2899 return "\xe3\x84\xb4";
2900 } elseif (
$code < 0xb77c ) {
2901 return "\xe3\x84\xb7";
2902 } elseif (
$code < 0xb9c8 ) {
2903 return "\xe3\x84\xb9";
2904 } elseif (
$code < 0xbc14 ) {
2905 return "\xe3\x85\x81";
2906 } elseif (
$code < 0xc0ac ) {
2907 return "\xe3\x85\x82";
2908 } elseif (
$code < 0xc544 ) {
2909 return "\xe3\x85\x85";
2910 } elseif (
$code < 0xc790 ) {
2911 return "\xe3\x85\x87";
2912 } elseif (
$code < 0xcc28 ) {
2913 return "\xe3\x85\x88";
2914 } elseif (
$code < 0xce74 ) {
2915 return "\xe3\x85\x8a";
2916 } elseif (
$code < 0xd0c0 ) {
2917 return "\xe3\x85\x8b";
2918 } elseif (
$code < 0xd30c ) {
2919 return "\xe3\x85\x8c";
2920 } elseif (
$code < 0xd558 ) {
2921 return "\xe3\x85\x8d";
2923 return "\xe3\x85\x8e";
2931 # Some languages may have an alternate char encoding option
2932 # (Esperanto X-coding, Japanese furigana conversion, etc)
2933 # If this language is used as the primary content language,
2934 # an override to the defaults can be set here on startup.
2942 # For some languages we'll want to explicitly specify
2943 # which characters make it into the edit box raw
2944 # or are converted in some way or another.
2946 if ( $wgEditEncoding ==
'' || $wgEditEncoding ==
'UTF-8' ) {
2949 return $this->
iconv(
'UTF-8', $wgEditEncoding,
$s );
2958 # Take the previous into account.
2960 if ( $wgEditEncoding !=
'' ) {
2965 if ( $enc ==
'UTF-8' ) {
2968 return $this->
iconv( $enc,
'UTF-8',
$s );
2985 $s = UtfNormal\Validator::cleanUp(
$s );
2986 if ( $wgAllUnicodeFixes ) {
3009 if ( !isset( $this->transformData[$file] ) ) {
3011 if ( $data ===
false ) {
3012 throw new MWException( __METHOD__ .
": The transformation file $file is missing" );
3016 return $this->transformData[$file]->replace( $string );
3025 return self::$dataCache->getItem( $this->mCode,
'rtl' );
3033 return $this->
isRTL() ?
'rtl' :
'ltr';
3045 return $this->
isRTL() ?
'right' :
'left';
3057 return $this->
isRTL() ?
'left' :
'right';
3073 return $this->
isRTL() ?
'‎' :
'‏';
3075 return $this->
isRTL() ?
'‏' :
'‎';
3089 $lrm =
"\xE2\x80\x8E"; # LEFT-TO-RIGHT MARK, commonly abbreviated LRM
3090 $rlm =
"\xE2\x80\x8F"; # RIGHT-TO-LEFT MARK, commonly abbreviated RLM
3092 return $this->
isRTL() ? $lrm : $rlm;
3094 return $this->
isRTL() ? $rlm : $lrm;
3101 return self::$dataCache->getItem( $this->mCode,
'capitalizeAllNouns' );
3112 switch ( $direction ) {
3114 return $this->
isRTL() ?
'←' :
'→';
3116 return $this->
isRTL() ?
'→' :
'←';
3134 return self::$dataCache->getItem( $this->mCode,
'linkPrefixExtension' );
3142 return self::$dataCache->getItem( $this->mCode,
'magicWords' );
3149 if ( $this->mMagicHookDone ) {
3152 $this->mMagicHookDone =
true;
3153 Hooks::run(
'LanguageGetMagic', [ &$this->mMagicExtensions, $this->
getCode() ] );
3163 if ( !$this->mMagicHookDone ) {
3167 if ( isset( $this->mMagicExtensions[$mw->mId] ) ) {
3168 $rawEntry = $this->mMagicExtensions[$mw->mId];
3170 $rawEntry = self::$dataCache->getSubitem(
3171 $this->mCode,
'magicWords', $mw->mId );
3174 if ( !is_array( $rawEntry ) ) {
3175 wfWarn(
"\"$rawEntry\" is not a valid magic word for \"$mw->mId\"" );
3177 $mw->mCaseSensitive = $rawEntry[0];
3178 $mw->mSynonyms = array_slice( $rawEntry, 1 );
3189 $fallbackChain = array_reverse( $fallbackChain );
3190 foreach ( $fallbackChain
as $code ) {
3191 if ( isset( $newWords[$code] ) ) {
3204 if ( is_null( $this->mExtendedSpecialPageAliases ) ) {
3206 $this->mExtendedSpecialPageAliases =
3207 self::$dataCache->getItem( $this->mCode,
'specialPageAliases' );
3209 [ &$this->mExtendedSpecialPageAliases, $this->
getCode() ] );
3222 return "<em>$text</em>";
3249 if ( !$nocommafy ) {
3250 $number = $this->
commafy( $number );
3253 $number = strtr( $number,
$s );
3257 if ( $wgTranslateNumerals ) {
3260 $number = strtr( $number,
$s );
3276 return $this->
formatNum( $number,
true );
3287 $s = array_filter(
$s );
3288 $number = strtr( $number, array_flip(
$s ) );
3294 $s = array_filter(
$s );
3295 $number = strtr( $number, array_flip(
$s ) );
3298 $number = strtr( $number, [
',' =>
'' ] );
3310 if ( $number === null ) {
3316 return strrev( (
string)preg_replace(
'/(\d{3})(?=\d)(?!\d*\.)/',
'$1,', strrev( $number ) ) );
3320 if ( intval( $number ) < 0 ) {
3323 $number = substr( $number, 1 );
3328 preg_match(
"/\d+/", $number, $integerPart );
3329 preg_match(
"/\.\d*/", $number, $decimalPart );
3330 $groupedNumber = ( count( $decimalPart ) > 0 ) ? $decimalPart[0] :
"";
3331 if ( $groupedNumber === $number ) {
3333 return $sign . $groupedNumber;
3335 $start = $end = ( $integerPart ) ? strlen( $integerPart[0] ) : 0;
3336 while ( $start > 0 ) {
3337 $match =
$matches[0][$numMatches - 1];
3338 $matchLen = strlen( $match );
3339 $start = $end - $matchLen;
3343 $groupedNumber = substr( $number, $start, $end -$start ) . $groupedNumber;
3345 if ( $numMatches > 1 ) {
3350 $groupedNumber =
"," . $groupedNumber;
3353 return $sign . $groupedNumber;
3361 return self::$dataCache->getItem( $this->mCode,
'digitGroupingPattern' );
3368 return self::$dataCache->getItem( $this->mCode,
'digitTransformTable' );
3375 return self::$dataCache->getItem( $this->mCode,
'separatorTransformTable' );
3388 $m = count( $l ) - 1;
3393 $and = $this->
msg(
'and' )->escaped();
3394 $space = $this->
msg(
'word-separator' )->escaped();
3396 $comma = $this->
msg(
'comma-separator' )->escaped();
3400 for ( $i = $m - 1; $i >= 0; $i-- ) {
3401 if ( $i == $m - 1 ) {
3402 $s = $l[$i] . $and . $space .
$s;
3404 $s = $l[$i] . $comma .
$s;
3418 wfMessage(
'comma-separator' )->inLanguage( $this )->escaped(),
3431 wfMessage(
'semicolon-separator' )->inLanguage( $this )->escaped(),
3443 wfMessage(
'pipe-separator' )->inLanguage( $this )->escaped(),
3465 function truncate( $string, $length, $ellipsis =
'...', $adjustLength =
true ) {
3466 # Use the localized ellipsis character
3467 if ( $ellipsis ==
'...' ) {
3468 $ellipsis =
wfMessage(
'ellipsis' )->inLanguage( $this )->escaped();
3470 # Check if there is no need to truncate
3471 if ( $length == 0 ) {
3473 } elseif ( strlen( $string ) <= abs( $length ) ) {
3476 $stringOriginal = $string;
3477 # If ellipsis length is >= $length then we can't apply $adjustLength
3478 if ( $adjustLength && strlen( $ellipsis ) >= abs( $length ) ) {
3479 $string = $ellipsis;
3480 # Otherwise, truncate and add ellipsis...
3482 $eLength = $adjustLength ? strlen( $ellipsis ) : 0;
3483 if ( $length > 0 ) {
3484 $length -= $eLength;
3485 $string = substr( $string, 0, $length );
3487 $string = rtrim( $string );
3488 $string = $string . $ellipsis;
3490 $length += $eLength;
3491 $string = substr( $string, $length );
3493 $string = ltrim( $string );
3494 $string = $ellipsis . $string;
3497 # Do not truncate if the ellipsis makes the string longer/equal (bug 22181).
3498 # This check is *not* redundant if $adjustLength, due to the single case where
3499 # LEN($ellipsis) > ABS($limit arg); $stringOriginal could be shorter than $string.
3500 if ( strlen( $string ) < strlen( $stringOriginal ) ) {
3503 return $stringOriginal;
3515 if ( $string !=
'' ) {
3516 $char = ord( $string[strlen( $string ) - 1] );
3518 if ( $char >= 0xc0 ) {
3519 # We got the first byte only of a multibyte char; remove it.
3520 $string = substr( $string, 0, -1 );
3521 } elseif ( $char >= 0x80 &&
3523 preg_match(
'/^(.*)(?:[\xe0-\xef][\x80-\xbf]|' .
3524 '[\xf0-\xf7][\x80-\xbf]{1,2})$/s', $string, $m )
3526 # We chopped in the middle of a character; remove it
3541 if ( $string !=
'' ) {
3542 $char = ord( $string[0] );
3543 if ( $char >= 0x80 && $char < 0xc0 ) {
3544 # We chopped in the middle of a character; remove the whole thing
3545 $string = preg_replace(
'/^[\x80-\xbf]+/',
'', $string );
3567 # Use the localized ellipsis character
3568 if ( $ellipsis ==
'...' ) {
3569 $ellipsis =
wfMessage(
'ellipsis' )->inLanguage( $this )->escaped();
3571 # Check if there is clearly no need to truncate
3572 if ( $length <= 0 ) {
3574 } elseif ( strlen( $text ) <= $length ) {
3579 $testingEllipsis =
false;
3587 $textLen = strlen( $text );
3588 $neLength = max( 0, $length - strlen( $ellipsis ) );
3589 for ( $pos = 0;
true; ++$pos ) {
3590 # Consider truncation once the display length has reached the maximim.
3591 # We check if $dispLen > 0 to grab tags for the $neLength = 0 case.
3592 # Check that we're not in the middle of a bracket/entity...
3593 if ( $dispLen && $dispLen >= $neLength && $bracketState == 0 && !$entityState ) {
3594 if ( !$testingEllipsis ) {
3595 $testingEllipsis =
true;
3596 # Save where we are; we will truncate here unless there turn out to
3597 # be so few remaining characters that truncation is not necessary.
3598 if ( !$maybeState ) {
3599 $maybeState = [
$ret, $openTags ];
3601 } elseif ( $dispLen > $length && $dispLen > strlen( $ellipsis ) ) {
3602 # String in fact does need truncation, the truncation point was OK.
3603 list(
$ret, $openTags ) = $maybeState;
3609 if ( $pos >= $textLen ) {
3613 # Read the next char...
3615 $lastCh = $pos ? $text[$pos - 1] :
'';
3621 } elseif ( $ch ==
'>' ) {
3625 } elseif ( $bracketState == 1 ) {
3633 } elseif ( $bracketState == 2 ) {
3640 } elseif ( $bracketState == 0 ) {
3641 if ( $entityState ) {
3647 if ( $neLength == 0 && !$maybeState ) {
3650 $maybeState = [ substr(
$ret, 0, -1 ), $openTags ];
3657 $max = ( $testingEllipsis ? $length : $neLength ) - $dispLen;
3659 $dispLen += $skipped;
3667 while ( count( $openTags ) > 0 ) {
3668 $ret .=
'</' . array_pop( $openTags ) .
'>';
3685 if ( $len === null ) {
3687 } elseif ( $len < 0 ) {
3691 if ( $start < strlen( $text ) ) {
3692 $skipCount = strcspn( $text, $search, $start, $len );
3693 $ret .= substr( $text, $start, $skipCount );
3710 if ( $tagType == 0 && $lastCh !=
'/' ) {
3712 } elseif ( $tagType == 1 ) {
3713 if ( $openTags &&
$tag == $openTags[count( $openTags ) - 1] ) {
3714 array_pop( $openTags );
3731 if ( isset( $wgGrammarForms[$this->
getCode()][$case][$word] ) ) {
3732 return $wgGrammarForms[$this->
getCode()][$case][$word];
3744 if ( isset( $wgGrammarForms[$this->
getCode()] )
3745 && is_array( $wgGrammarForms[$this->
getCode()] )
3747 return $wgGrammarForms[$this->
getCode()];
3772 if ( !count( $forms ) ) {
3776 if ( $gender ===
'male' ) {
3779 if ( $gender ===
'female' ) {
3782 return isset( $forms[2] ) ? $forms[2] : $forms[0];
3803 if ( is_string( $forms ) ) {
3806 if ( !count( $forms ) ) {
3811 $pluralForm = min( $pluralForm, count( $forms ) - 1 );
3812 return $forms[$pluralForm];
3831 foreach ( $forms
as $index => $form ) {
3832 if ( preg_match(
'/\d+=/i', $form ) ) {
3833 $pos = strpos( $form,
'=' );
3834 if ( substr( $form, 0, $pos ) === (
string)
$count ) {
3835 return substr( $form, $pos + 1 );
3837 unset( $forms[$index] );
3840 return array_values( $forms );
3852 while ( count( $forms ) <
$count ) {
3853 $forms[] = $forms[count( $forms ) - 1];
3876 if (
$dir ===
'ltr' ) {
3878 return self::$lre . $text . self::$pdf;
3880 if (
$dir ===
'rtl' ) {
3882 return self::$rle . $text . self::$pdf;
3902 foreach ( $duration
as $show =>
$value ) {
3903 if ( strcmp( $str,
$value ) == 0 ) {
3904 return htmlspecialchars( trim( $show ) );
3909 foreach ( $duration
as $show =>
$value ) {
3911 return htmlspecialchars( trim( $show ) );
3917 $time = strtotime( $str, 0 );
3918 if (
$time ===
false ) {
3920 } elseif (
$time !== strtotime( $str, 1 ) ) {
3924 if (
$time === 0 ) {
3926 $time =
'19700101000000';
3973 return $this->mConverter->autoConvertToAllVariants( $text );
3983 return $this->mConverter->convert( $text );
3993 return $this->mConverter->convertTitle(
$title );
4003 return $this->mConverter->convertNamespace( $ns );
4023 return (
bool)$this->mConverter->validateVariant( $variant );
4034 return htmlspecialchars( $this->
convert( $text, $isTitle ) );
4042 return $this->mConverter->convertCategoryKey(
$key );
4052 return $this->mConverter->getVariants();
4059 return $this->mConverter->getPreferredVariant();
4066 return $this->mConverter->getDefaultVariant();
4073 return $this->mConverter->getURLVariant();
4089 $this->mConverter->findVariantLink(
$link, $nt, $ignoreOtherCond );
4099 return $this->mConverter->getExtraHashOptions();
4110 return $this->mConverter->getParsedTitle();
4120 $this->mConverter->updateConversionTable( $title );
4138 return $this->mConverter->markNoConversion( $text );
4151 return self::$dataCache->getItem( $this->mCode,
'linkTrail' );
4161 return self::$dataCache->getItem( $this->mCode,
'linkPrefixCharset' );
4172 if ( $this->mParentLanguage !==
false ) {
4178 $this->mParentLanguage = null;
4182 if ( !
$lang->hasVariant( $this->getCode() ) ) {
4183 $this->mParentLanguage = null;
4187 $this->mParentLanguage =
$lang;
4214 if ( is_null( $this->mHtmlCode ) ) {
4224 $this->mCode =
$code;
4226 $this->mHtmlCode = null;
4227 $this->mParentLanguage =
false;
4239 preg_match(
'/' . preg_quote( $prefix,
'/' ) .
'([A-Z][a-z_]+)' .
4240 preg_quote( $suffix,
'/' ) .
'/', $filename, $m );
4241 if ( !count( $m ) ) {
4244 return str_replace(
'_',
'-', strtolower( $m[1] ) );
4252 if (
$code ==
'en' ) {
4255 return 'Language' . str_replace(
'-',
'_',
ucfirst(
$code ) );
4268 if ( !self::isValidBuiltInCode(
$code ) ) {
4269 throw new MWException(
"Invalid language code \"$code\"" );
4272 return $prefix . str_replace(
'-',
'_',
ucfirst(
$code ) ) . $suffix;
4281 $file = self::getFileName(
"$IP/languages/messages/Messages",
$code,
'.php' );
4295 if ( !self::isValidBuiltInCode(
$code ) ) {
4296 throw new MWException(
"Invalid language code \"$code\"" );
4299 return "$IP/languages/i18n/$code.json";
4310 $fallbacks = self::getFallbacksFor(
$code );
4312 return $fallbacks[0];
4330 return self::getLocalisationCache()->getItem(
$code,
'fallbackSequence' ) ?: [
'en' ];
4346 $cacheKey =
"{$code}-{$wgLanguageCode}";
4348 if ( !array_key_exists( $cacheKey, self::$fallbackLanguageCache ) ) {
4349 $fallbacks = self::getFallbacksFor(
$code );
4352 $siteFallbacks = self::getFallbacksFor( $wgLanguageCode );
4353 array_unshift( $siteFallbacks, $wgLanguageCode );
4356 $siteFallbacks = array_diff( $siteFallbacks, $fallbacks );
4358 self::$fallbackLanguageCache[$cacheKey] = [ $fallbacks, $siteFallbacks ];
4360 return self::$fallbackLanguageCache[$cacheKey];
4373 return self::getLocalisationCache()->getItem(
$code,
'messages' );
4385 return self::getLocalisationCache()->getSubitem(
$code,
'messages',
$key );
4397 return self::getLocalisationCache()->getSubitemList(
$code,
'messages' );
4405 if ( strpos( $talk,
'$1' ) ===
false ) {
4410 $talk = str_replace(
'$1', $wgMetaNamespace, $talk );
4412 # Allow grammar transformations
4413 # Allowing full message-style parsing would make simple requests
4414 # such as action=raw much more expensive than they need to be.
4415 # This will hopefully cover most cases.
4416 $talk = preg_replace_callback(
'/{{grammar:(.*?)\|(.*?)}}/i',
4417 [ &$this,
'replaceGrammarInNamespace' ], $talk );
4418 return str_replace(
' ',
'_', $talk );
4439 public function formatExpiry( $expiry, $format =
true, $infinity =
'infinity' ) {
4441 if ( $dbInfinity === null ) {
4445 if ( $expiry ==
'' || $expiry ===
'infinity' || $expiry == $dbInfinity ) {
4446 return $format ===
true
4450 return $format ===
true
4469 if ( !is_array( $format ) ) {
4470 $format = [
'avoid' => $format ];
4472 if ( !isset( $format[
'avoid'] ) ) {
4473 $format[
'avoid'] =
false;
4475 if ( !isset( $format[
'noabbrevs'] ) ) {
4476 $format[
'noabbrevs'] =
false;
4479 $format[
'noabbrevs'] ?
'seconds' :
'seconds-abbrev' )->inLanguage( $this );
4481 $format[
'noabbrevs'] ?
'minutes' :
'minutes-abbrev' )->inLanguage( $this );
4483 $format[
'noabbrevs'] ?
'hours' :
'hours-abbrev' )->inLanguage( $this );
4485 $format[
'noabbrevs'] ?
'days' :
'days-abbrev' )->inLanguage( $this );
4487 if ( round( $seconds * 10 ) < 100 ) {
4488 $s = $this->
formatNum( sprintf(
"%.1f", round( $seconds * 10 ) / 10 ) );
4489 $s = $secondsMsg->params(
$s )->text();
4490 } elseif ( round( $seconds ) < 60 ) {
4492 $s = $secondsMsg->params(
$s )->text();
4493 } elseif ( round( $seconds ) < 3600 ) {
4494 $minutes = floor( $seconds / 60 );
4495 $secondsPart = round( fmod( $seconds, 60 ) );
4496 if ( $secondsPart == 60 ) {
4500 $s = $minutesMsg->params( $this->
formatNum( $minutes ) )->text();
4502 $s .= $secondsMsg->params( $this->
formatNum( $secondsPart ) )->text();
4503 } elseif ( round( $seconds ) <= 2 * 86400 ) {
4504 $hours = floor( $seconds / 3600 );
4505 $minutes = floor( ( $seconds - $hours * 3600 ) / 60 );
4506 $secondsPart = round( $seconds - $hours * 3600 - $minutes * 60 );
4507 if ( $secondsPart == 60 ) {
4511 if ( $minutes == 60 ) {
4515 $s = $hoursMsg->params( $this->
formatNum( $hours ) )->text();
4517 $s .= $minutesMsg->params( $this->
formatNum( $minutes ) )->text();
4518 if ( !in_array( $format[
'avoid'], [
'avoidseconds',
'avoidminutes' ] ) ) {
4519 $s .=
' ' . $secondsMsg->params( $this->
formatNum( $secondsPart ) )->text();
4522 $days = floor( $seconds / 86400 );
4523 if ( $format[
'avoid'] ===
'avoidminutes' ) {
4524 $hours = round( ( $seconds - $days * 86400 ) / 3600 );
4525 if ( $hours == 24 ) {
4529 $s = $daysMsg->params( $this->
formatNum( $days ) )->text();
4531 $s .= $hoursMsg->params( $this->
formatNum( $hours ) )->text();
4532 } elseif ( $format[
'avoid'] ===
'avoidseconds' ) {
4533 $hours = floor( ( $seconds - $days * 86400 ) / 3600 );
4534 $minutes = round( ( $seconds - $days * 86400 - $hours * 3600 ) / 60 );
4535 if ( $minutes == 60 ) {
4539 if ( $hours == 24 ) {
4543 $s = $daysMsg->params( $this->
formatNum( $days ) )->text();
4545 $s .= $hoursMsg->params( $this->
formatNum( $hours ) )->text();
4547 $s .= $minutesMsg->params( $this->
formatNum( $minutes ) )->text();
4549 $s = $daysMsg->params( $this->
formatNum( $days ) )->text();
4580 return str_replace(
'$1', $this->
formatNum( $size ),
4584 $sizes = [
'',
'kilo',
'mega',
'giga',
'tera',
'peta',
'exa',
'zeta',
'yotta' ];
4587 $maxIndex = count( $sizes ) - 1;
4588 while ( $size >= $boundary && $index < $maxIndex ) {
4599 $msg = str_replace(
'$1', $sizes[$index], $messageKey );
4601 $size = round( $size, $round );
4603 return str_replace(
'$1', $this->
formatNum( $size ), $text );
4638 $this->
msg(
'word-separator' )->escaped() .
4639 $this->
msg(
'parentheses' )->rawParams( $details )->escaped();
4657 # Make 'previous' link
4658 $prev =
wfMessage(
'prevn' )->inLanguage( $this )->title( $title )->numParams(
$limit )->text();
4659 if ( $offset > 0 ) {
4661 $query, $prev,
'prevn-title',
'mw-prevlink' );
4663 $plink = htmlspecialchars( $prev );
4667 $next =
wfMessage(
'nextn' )->inLanguage( $this )->title( $title )->numParams(
$limit )->text();
4669 $nlink = htmlspecialchars( $next );
4672 $query, $next,
'nextn-title',
'mw-nextlink' );
4675 # Make links to set number of items per page
4677 foreach ( [ 20, 50, 100, 250, 500 ]
as $num ) {
4678 $numLinks[] = $this->
numLink( $title, $offset, $num,
4682 return wfMessage(
'viewprevnext' )->inLanguage( $this )->title( $title
4683 )->rawParams( $plink, $nlink, $this->
pipeList( $numLinks ) )->escaped();
4701 $query = [
'limit' =>
$limit,
'offset' => $offset ] +
$query;
4702 $tooltip =
wfMessage( $tooltipMsg )->inLanguage( $this )->title( $title )
4703 ->numParams(
$limit )->text();
4706 'title' => $tooltip,
'class' => $class ],
$link );
4715 return $this->mConverter->getConvRuleTitle();
4724 $pluralRules = self::$dataCache->getItem( strtolower( $this->mCode ),
'compiledPluralRules' );
4726 if ( !$pluralRules ) {
4727 foreach ( $fallbacks
as $fallbackCode ) {
4728 $pluralRules = self::$dataCache->getItem( strtolower( $fallbackCode ),
'compiledPluralRules' );
4729 if ( $pluralRules ) {
4734 return $pluralRules;
4743 $pluralRules = self::$dataCache->getItem( strtolower( $this->mCode ),
'pluralRules' );
4745 if ( !$pluralRules ) {
4746 foreach ( $fallbacks
as $fallbackCode ) {
4747 $pluralRules = self::$dataCache->getItem( strtolower( $fallbackCode ),
'pluralRules' );
4748 if ( $pluralRules ) {
4753 return $pluralRules;
4762 $pluralRuleTypes = self::$dataCache->getItem( strtolower( $this->mCode ),
'pluralRuleTypes' );
4764 if ( !$pluralRuleTypes ) {
4765 foreach ( $fallbacks
as $fallbackCode ) {
4766 $pluralRuleTypes = self::$dataCache->getItem( strtolower( $fallbackCode ),
'pluralRuleTypes' );
4767 if ( $pluralRuleTypes ) {
4772 return $pluralRuleTypes;
4782 $form = Evaluator::evaluateCompiled( $number, $pluralRules );
4797 if ( isset( $pluralRuleTypes[$index] ) ) {
4798 return $pluralRuleTypes[$index];
utf8ToCodepoint($char)
Determine the Unicode codepoint of a single-character UTF-8 sequence.
#define the
table suitable for use with IDatabase::select()
formatTimePeriod($seconds, $format=[])
getDirMark($opposite=false)
A hidden direction mark (LRM or RLM), depending on the language direction.
getSpecialPageAliases()
Get special page names, as an associative array canonical name => array of valid names, including aliases.
getWeekdayAbbreviation($key)
getDateFormatString($type, $pref)
Get a format string for a given type and preference.
getPluralRuleTypes()
Get the plural rule types for the language.
getHumanTimestamp(MWTimestamp $time, MWTimestamp $relativeTo=null, User $user=null)
Get the timestamp in a human-friendly relative format, e.g., "3 days ago".
static getLocalisationCache()
Get the LocalisationCache instance.
convertPlural($count, $forms)
Plural form transformations, needed for some languages.
diff(MWTimestamp $relativeTo)
Calculate the difference between two MWTimestamp objects.
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
doMagicHook()
Run the LanguageGetMagic hook once.
wfGetDB($db, $groups=[], $wiki=false)
Get a Database object.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
static isKnownLanguageTag($tag)
Returns true if a language code is an IETF tag known to MediaWiki.
the array() calling protocol came about after MediaWiki 1.4rc1.
static insertSpace($string, $pattern)
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
magic word the default is to use $key to get the and $key value or $key value text $key value html to format the value $key
convertGrammar($word, $case)
Grammatical transformations, needed for inflected languages Invoked by putting {{grammar:case|word}} ...
static LocalisationCache $dataCache
handleExplicitPluralForms($count, array $forms)
Handles explicit plural forms for Language::convertPlural()
hasVariant($variant)
Check if the language has the specific variant.
markNoConversion($text, $noParse=false)
Prepare external link text for conversion.
setNamespaces(array $namespaces)
Arbitrarily set all of the namespace names at once.
format($format)
Format the timestamp in a given format.
static HashBagOStuff null $languageNameCache
Cache for language names.
transformUsingPairFile($file, $string)
Transform a string using serialized data stored in the given file (which must be in the serialized su...
date($ts, $adj=false, $format=true, $timecorrection=false)
getHtmlCode()
Get the code in BCP 47 format which we can use inside of html lang="" tags.
truncate_skip(&$ret, $text, $search, $start, $len=null)
truncateHtml() helper function like strcspn() but adds the skipped chars to $ret
static isWellFormedLanguageTag($code, $lenient=false)
Returns true if a language code string is a well-formed language tag according to RFC 5646...
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
removeBadCharFirst($string)
Remove bytes that represent an incomplete Unicode character at the start of string (e...
convertNamespace($ns)
Convert a namespace index to a string in the preferred variant.
static getMessageFor($key, $code)
Get a message for a given language.
offsetForUser(User $user)
Adjust the timestamp depending on the given user's preferences.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
getLocalNsIndex($text)
Get a namespace key by value, case insensitive.
alignEnd()
Return 'right' or 'left' as appropriate alignment for line-end for this language's text direction...
firstChar($s)
Get the first character of a string.
globals txt Globals are evil The original MediaWiki code relied on globals for processing context far too often MediaWiki development since then has been a story of slowly moving context out of global variables and into objects Storing processing context in object member variables allows those objects to be reused in a much more flexible way Consider the elegance of
database rows
$wgLangObjCacheSize
Language cache size, or really how many languages can we handle simultaneously without degrading to c...
if(!isset($args[0])) $lang
hasVariants()
Check if this is a language with variants.
getCompiledPluralRules()
Get the compiled plural rules for the language.
getNsIndex($text)
Get a namespace key by value, case insensitive.
getNsText($index)
Get a namespace value by key.
sprintfDate($format, $ts, DateTimeZone $zone=null, &$ttl=null)
This is a workalike of PHP's date() function, but with better internationalisation, a reduced set of format characters, and a better escaping format.
$wgEditEncoding
Character set for use in the article edit box.
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
iconv($in, $out, $string)
$wgMetaNamespace
Name of the project namespace.
formatComputingNumbers($size, $boundary, $messageKey)
static getFallbacksIncludingSiteLanguage($code)
Get the ordered list of fallback languages, ending with the fallback language chain for the site lang...
formatNumNoSeparators($number)
Front-end for non-commafied formatNum.
truncate_endBracket(&$tag, $tagType, $lastCh, &$openTags)
truncateHtml() helper function (a) push or pop $tag from $openTags as needed (b) clear $tag value ...
A fake language converter.
linkTrail()
A regular expression to match legal word-trailing characters which should be merged onto a link of th...
wfUrlProtocolsWithoutProtRel()
Like wfUrlProtocols(), but excludes '//' from the protocol list.
normalize($s)
Convert a UTF-8 string to normal form C.
$wgNamespaceAliases
Namespace aliases.
static getCodeFromFileName($filename, $prefix= 'Language', $suffix= '.php')
Get the language code from a file name.
internalUserTimeAndDate($type, $ts, User $user, array $options)
Internal helper function for userDate(), userTime() and userTimeAndDate()
static getMessageKeysFor($code)
Get all message keys for a given language.
static tsToHijri($ts)
Converting Gregorian dates to Hijri dates.
formatExpiry($expiry, $format=true, $infinity= 'infinity')
Decode an expiry (block, protection, etc) which has come from the DB.
getVariants()
Get the list of variants supported by this language see sample implementation in LanguageZh.php.
Represents a title within MediaWiki.
dateFormat($usePrefs=true)
This is meant to be used by time(), date(), and timeanddate() to get the date preference they're supp...
when a variable name is used in a it is silently declared as a new local masking the global
autoConvertToAllVariants($text)
convert text to all supported variants
static getFallbacksFor($code)
Get the ordered list of fallback languages.
We ve cleaned up the code here by removing clumps of infrequently used code and moving them off somewhere else It s much easier for someone working with this code to see what s _really_ going and make changes or fix bugs In we can take all the code that deals with the little used title reversing options(say) and put it in one place.Instead of having little title-reversing if-blocks spread all over the codebase in showAnArticle
$wgExtraGenderNamespaces
Same as above, but for namespaces with gender distinction.
parseFormattedNumber($number)
$wgTranslateNumerals
For Hindi and Arabic use local numerals instead of Western style (0-9) numerals in interface...
static isUtf8($value)
Test whether a string is valid UTF-8.
see documentation in includes Linker php for Linker::makeImageLink & $time
static $mWeekdayAbbrevMsgs
the value to return A Title object or null for latest to be modified or replaced by the hook handler or if authentication is not possible after cache objects are set for highlighting & $link
static newFromCode($code)
Create a language object for a given language code.
time($ts, $adj=false, $format=true, $timecorrection=false)
embedBidi($text= '')
Wraps argument with unicode control characters for directionality safety.
static getJsonMessagesFileName($code)
wfTimestamp($outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
$wgLanguageCode
Site language code.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
formatSize($size)
Format a size in bytes for output, using an appropriate unit (B, KB, MB, GB, TB, PB, EB, ZB or YB) according to the magnitude in question.
semicolonList(array $list)
Take a list of strings and build a locale-friendly semicolon-separated list, using the local semicolo...
addMagicWordsByLang($newWords)
Add magic words to the extension array.
segmentForDiff($text)
languages like Chinese need to be segmented in order for the diff to be of any use ...
static $lre
Unicode directional formatting characters, for embedBidi()
convertHtml($text, $isTitle=false)
Perform output conversion on a string, and encode for safe HTML output.
when a variable name is used in a function
ucwordbreaksCallbackAscii($matches)
static $mHijriCalendarMonthMsgs
ucwordsCallbackMB($matches)
linkPrefixCharset()
A regular expression character set to match legal word-prefixing characters which should be merged on...
static getMain()
Static methods.
getIranianCalendarMonthName($key)
LanguageConverter $mConverter
msg($msg)
Get message object in this language.
__destruct()
Reduce memory usage.
formatBitrate($bps)
Format a bitrate for output, using an appropriate unit (bps, kbps, Mbps, Gbps, Tbps, Pbps, Ebps, Zbps or Ybps) according to the magnitude in question.
truncateHtml($text, $length, $ellipsis= '...')
Truncate a string of valid HTML to a specified length in bytes, appending an optional string (e...
$wgLocalisationCacheConf
Localisation cache configuration.
getArrow($direction= 'forwards')
An arrow, depending on the language direction.
wfWarn($msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
static convertDoubleWidth($string)
convert double-width roman characters to single-width.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
viewPrevNext(Title $title, $offset, $limit, array $query=[], $atend=false)
Generate (prev x| next x) (20|50|100...) type links for paging.
getConverter()
Return the LanguageConverter used in the Language.
static $mIranianCalendarMonthMsgs
static hebrewNumeral($num)
Hebrew Gematria number formatting up to 9999.
getFormattedNsText($index)
A convenience function that returns the same thing as getNsText() except with '_' changed to ' '...
getMonthAbbreviation($key)
getLocalURL($query= '', $query2=false)
Get a URL with no fragment or server name (relative URL) from a Title object.
static tsToHebrew($ts)
Converting Gregorian dates to Hebrew dates.
getBookstoreList()
Exports $wgBookstoreListEn.
listToText(array $l)
Take a list of strings and build a locale-friendly comma-separated list, using the local comma-separa...
$wgDummyLanguageCodes
List of language codes that don't correspond to an actual language.
caseFold($s)
Return a case-folded representation of $s.
static getMessagesFileName($code)
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock()-offset Set to overwrite offset parameter in $wgRequest set to ''to unsetoffset-wrap String Wrap the message in html(usually something like"<
$wgAllUnicodeFixes
Set this to always convert certain Unicode sequences to modern ones regardless of the content languag...
static isValidBuiltInCode($code)
Returns true if a language code is of a valid form for the purposes of internal customisation of Medi...
getTimestamp($style=TS_UNIX)
Get the timestamp represented by this object in a certain form.
static isValidCode($code)
Returns true if a language code string is of a valid form, whether or not it exists.
uc($str, $first=false)
Convert a string to uppercase.
static getMessagesFor($code)
Get all messages for a given language WARNING: this may take a long time.
ucwordbreaksCallbackMB($matches)
static $strongDirRegex
Directionality test regex for embedBidi().
needsGenderDistinction()
Whether this language uses gender-dependent namespace aliases.
wfIsInfinity($str)
Determine input string is represents as infinity.
getHebrewCalendarMonthNameGen($key)
updateConversionTable(Title $title)
Refresh the cache of conversion tables when MediaWiki:Conversiontable* is updated.
convertTitle($title)
Convert a Title object to a string in the preferred variant.
convert($text)
convert text to different variants of a language.
wfBCP47($code)
Get the normalised IETF language tag See unit test for examples.
$wgMetaNamespaceTalk
Name of the project talk namespace.
namespace and then decline to actually register it file or subcat img or subcat $title
getVariantname($code, $usemsg=true)
short names for language variants used for language conversion links.
static getFileName($prefix= 'Language', $code, $suffix= '.php')
Get the name of a file for a certain language code.
formatDuration($seconds, array $chosenIntervals=[])
Takes a number of seconds and turns it into a text using values such as hours and minutes...
static run($event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
static getSuggestedDurations($lang=null)
Get an array of suggested block durations from MediaWiki:Ipboptions.
ucwordbreaks($str)
capitalize words at word breaks
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books $tag
userTime($ts, User $user, array $options=[])
Get the formatted time for the given timestamp and formatted for the given user.
static $mHebrewCalendarMonthMsgs
pipeList(array $list)
Same as commaList, but separate it with the pipe instead.
getMessageFromDB($msg)
Get a message from the MediaWiki namespace.
formatNum($number, $nocommafy=false)
Normally we output all numbers in plain en_US style, that is 293,291.235 for twohundredninetythreetho...
return['SiteStore'=> function(MediaWikiServices $services){$loadBalancer=wfGetLB();$rawSiteStore=new DBSiteStore($loadBalancer);$cache=wfGetCache(wfIsHHVM()?CACHE_ACCEL:CACHE_ANYTHING);return new CachingSiteStore($rawSiteStore, $cache);},'SiteLookup'=> function(MediaWikiServices $services){return $services->getSiteStore();},'ConfigFactory'=> function(MediaWikiServices $services){$registry=$services->getBootstrapConfig() ->get( 'ConfigRegistry');$factory=new ConfigFactory();foreach($registry as $name=> $callback){$factory->register($name, $callback);}return $factory;},'MainConfig'=> function(MediaWikiServices $services){return $services->getConfigFactory() ->makeConfig( 'main');},'StatsdDataFactory'=> function(MediaWikiServices $services){return new BufferingStatsdDataFactory(rtrim($services->getMainConfig() ->get( 'StatsdMetricPrefix'), '.'));},'EventRelayerGroup'=> function(MediaWikiServices $services){return new EventRelayerGroup($services->getMainConfig() ->get( 'EventRelayerConfig'));},'SearchEngineFactory'=> function(MediaWikiServices $services){return new SearchEngineFactory($services->getSearchEngineConfig());},'SearchEngineConfig'=> function(MediaWikiServices $services){global $wgContLang;return new SearchEngineConfig($services->getMainConfig(), $wgContLang);},'SkinFactory'=> function(MediaWikiServices $services){return new SkinFactory();},]
$mExtendedSpecialPageAliases
namespace and then decline to actually register it & $namespaces
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
getPluralRules()
Get the plural rules for the language.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable & $code
static fetchLanguageName($code, $inLanguage=null, $include= 'all')
resetNamespaces()
Resets all of the namespace caches.
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account $user
segmentByWord($string)
Some languages such as Chinese require word segmentation, Specify such segmentation when overridden i...
getMagicWords()
Get all magic words from cache.
numLink(Title $title, $offset, $limit, array $query, $link, $tooltipMsg, $class)
Helper function for viewPrevNext() that generates links.
ucfirst($str)
Make a string's first character uppercase.
getOption($oname, $defaultOverride=null, $ignoreHidden=false)
Get the user's current setting for a given option.
getHijriCalendarMonthName($key)
static getFallbackFor($code)
Get the first fallback for a given language.
timeanddate($ts, $adj=false, $format=true, $timecorrection=false)
getPluralRuleType($number)
Find the plural rule type appropriate for the given number For example, if the language is set to Ara...
userAdjust($ts, $tz=false)
Used by date() and time() to adjust the time output.
userDate($ts, User $user, array $options=[])
Get the formatted date for the given timestamp and formatted for the given user.
getConvRuleTitle()
Get the conversion rule title, if any.
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
getMagic($mw)
Fill a MagicWord object with data from here.
static classFromCode($code)
$wgExtraNamespaces
Additional namespaces.
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
getHumanTimestampInternal(MWTimestamp $ts, MWTimestamp $relativeTo, User $user)
Convert an MWTimestamp into a pretty human-readable timestamp using the given user preferences and re...
getCode()
Get the internal language code for this language object.
replaceGrammarInNamespace($m)
commafy($number)
Adds commas to a given number.
userTimeAndDate($ts, User $user, array $options=[])
Get the formatted date and time for the given timestamp and formatted for the given user...
translateBlockExpiry($str, User $user=null)
truncate($string, $length, $ellipsis= '...', $adjustLength=true)
Truncate a string to a specified length in bytes, appending an optional string (e.g.
static romanNumeral($num)
Roman number formatting up to 10000.
convertForSearchResult($termsArray)
removeBadCharLast($string)
Remove bytes that represent an incomplete Unicode character at the end of string (e.g.
static tsToIranian($ts)
Algorithm by Roozbeh Pournader and Mohammad Toossi to convert Gregorian dates to Iranian dates...
$transformData
ReplacementArray object caches.
specialList($page, $details, $oppositedm=true)
Make a list item, used by various special pages.
getExtraHashOptions()
returns language specific options used by User::getPageRenderHash() for example, the preferred langua...
getParsedTitle()
For languages that support multiple variants, the title of an article may be displayed differently in...
preConvertPlural($forms, $count)
Checks that convertPlural was given an array and pads it to requested amount of forms by copying the ...
findVariantLink(&$link, &$nt, $ignoreOtherCond=false)
If a language supports multiple variants, it is possible that non-existing link in one variant actual...
$wgGrammarForms
Some languages need different word forms, usually for different cases.
emphasize($text)
Italic is unsuitable for some languages.
getDirMarkEntity($opposite=false)
A hidden direction mark (LRM or RLM), depending on the language direction.
separatorTransformTable()
isRTL()
For right-to-left language support.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object to manipulate or replace but no entry for that model exists in $wgContentHandlers if desired whether it is OK to use $contentModel on $title Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok inclusive $limit
getDatePreference()
Get the user's preferred date format.
getParentLanguage()
Get the "parent" language which has a converter to convert a "compatible" language (in another varian...
getDir()
Return the correct HTML 'dir' attribute value for this language.
getFormattedNamespaces()
A convenience function that returns getNamespaces() with spaces instead of underscores in values...
$wgLocalTZoffset
Set an offset from UTC in minutes to use for the default timezone setting for anonymous users and new...
normalizeForSearch($string)
Some languages have special punctuation need to be normalized.
getDurationIntervals($seconds, array $chosenIntervals=[])
Takes a number of seconds and returns an array with a set of corresponding intervals.
linkPrefixExtension()
To allow "foo[[bar]]" to extend the link over the whole word "foobar".
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring which defines all default service and specifies how they depend on each other("wiring").When a new service is added to MediaWiki core
getGrammarForms()
Get the grammar forms for the content language.
static dateTimeObjFormat(&$dateTimeObj, $ts, $zone, $code)
Pass through result from $dateTimeObj->format()
=Architecture==Two class hierarchies are used to provide the functionality associated with the different content models:*Content interface(and AbstractContent base class) define functionality that acts on the concrete content of a page, and *ContentHandler base class provides functionality specific to a content model, but not acting on concrete content.The most important function of ContentHandler is to act as a factory for the appropriate implementation of Content.These Content objects are to be used by MediaWiki everywhere, instead of passing page content around as text.All manipulation and analysis of page content must be done via the appropriate methods of the Content object.For each content model, a subclass of ContentHandler has to be registered with $wgContentHandlers.The ContentHandler object for a given content model can be obtained using ContentHandler::getForModelID($id).Also Title, WikiPage and Revision now have getContentHandler() methods for convenience.ContentHandler objects are singletons that provide functionality specific to the content type, but not directly acting on the content of some page.ContentHandler::makeEmptyContent() and ContentHandler::unserializeContent() can be used to create a Content object of the appropriate type.However, it is recommended to instead use WikiPage::getContent() resp.Revision::getContent() to get a page's content as a Content object.These two methods should be the ONLY way in which page content is accessed.Another important function of ContentHandler objects is to define custom action handlers for a content model, see ContentHandler::getActionOverrides().This is similar to what WikiPage::getActionOverrides() was already doing.==Serialization==With the ContentHandler facility, page content no longer has to be text based.Objects implementing the Content interface are used to represent and handle the content internally.For storage and data exchange, each content model supports at least one serialization format via ContentHandler::serializeContent($content).The list of supported formats for a given content model can be accessed using ContentHandler::getSupportedFormats().Content serialization formats are identified using MIME type like strings.The following formats are built in:*text/x-wiki-wikitext *text/javascript-for js pages *text/css-for css pages *text/plain-for future use, e.g.with plain text messages.*text/html-for future use, e.g.with plain html messages.*application/vnd.php.serialized-for future use with the api and for extensions *application/json-for future use with the api, and for use by extensions *application/xml-for future use with the api, and for use by extensions In PHP, use the corresponding CONTENT_FORMAT_XXX constant.Note that when using the API to access page content, especially action=edit, action=parse and action=query &prop=revisions, the model and format of the content should always be handled explicitly.Without that information, interpretation of the provided content is not reliable.The same applies to XML dumps generated via maintenance/dumpBackup.php or Special:Export.Also note that the API will provide encapsulated, serialized content-so if the API was called with format=json, and contentformat is also json(or rather, application/json), the page content is represented as a string containing an escaped json structure.Extensions that use JSON to serialize some types of page content may provide specialized API modules that allow access to that content in a more natural form.==Compatibility==The ContentHandler facility is introduced in a way that should allow all existing code to keep functioning at least for pages that contain wikitext or other text based content.However, a number of functions and hooks have been deprecated in favor of new versions that are aware of the page's content model, and will now generate warnings when used.Most importantly, the following functions have been deprecated:*Revisions::getText() is deprecated in favor Revisions::getContent()*WikiPage::getText() is deprecated in favor WikiPage::getContent() Also, the old Article::getContent()(which returns text) is superceded by Article::getContentObject().However, both methods should be avoided since they do not provide clean access to the page's actual content.For instance, they may return a system message for non-existing pages.Use WikiPage::getContent() instead.Code that relies on a textual representation of the page content should eventually be rewritten.However, ContentHandler::getContentText() provides a stop-gap that can be used to get text for a page.Its behavior is controlled by $wgContentHandlerTextFallback it
getGenderNsText($index, $gender)
Returns gender-dependent namespace alias if available.
static getDefaultOption($opt)
Get a given default option value.
initContLang()
Hook which will be called if this is the content language.
static factory($code)
Get a cached or new language object for a given language code.
fixVariableInNamespace($talk)
getNamespaces()
Returns an array of localised namespaces indexed by their numbers.
wfGetPrecompiledData($name)
Get an object from the precompiled serialized directory.
gender($gender, $forms)
Provides an alternative text depending on specified gender.
commaList(array $list)
Take a list of strings and build a locale-friendly comma-separated list, using the local comma-separa...
static $mHebrewCalendarMonthGenMsgs
static array $languagesWithVariants
languages supporting variants
static element($element, $attribs=[], $contents= '')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
static getCanonicalIndex($name)
Returns the index for a given canonical name, or NULL The input must be converted to lower case first...
static getCanonicalNamespaces($rebuild=false)
Returns array of all defined namespaces with their canonical (English) names.
getMonthAbbreviationsArray()
Library for creating and parsing MW-style timestamps.
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect as a string mapping parameter names to values & $type
hasWordBreaks()
Most writing systems use whitespace to break up words.
static strongDirFromContent($text= '')
Gets directionality of the first strongly directional codepoint, for embedBidi()
static isSupportedLanguage($code)
Checks whether any localisation is available for that language tag in MediaWiki (MessagesXx.php exists).
alignStart()
Return 'left' or 'right' as appropriate alignment for line-start for this language's text direction...
static tsToYear($ts, $cName)
Algorithm to convert Gregorian dates to Thai solar dates, Minguo dates or Minguo dates.
getPluralRuleIndexNumber($number)
Find the index number of the plural rule appropriate for the given number.
static hebrewYearStart($year)
This calculates the Hebrew year start, as days since 1 September.
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached $page
getHebrewCalendarMonthName($key)
unsegmentForDiff($text)
and unsegment to show the result
Allows to change the fields on the form that will be generated $name