Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Language often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Language, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 41 | class Language { |
||
| 42 | /** |
||
| 43 | * @var LanguageConverter |
||
| 44 | */ |
||
| 45 | public $mConverter; |
||
| 46 | |||
| 47 | public $mVariants, $mCode, $mLoaded = false; |
||
| 48 | public $mMagicExtensions = [], $mMagicHookDone = false; |
||
| 49 | private $mHtmlCode = null, $mParentLanguage = false; |
||
| 50 | |||
| 51 | public $dateFormatStrings = []; |
||
| 52 | public $mExtendedSpecialPageAliases; |
||
| 53 | |||
| 54 | protected $namespaceNames, $mNamespaceIds, $namespaceAliases; |
||
| 55 | |||
| 56 | /** |
||
| 57 | * ReplacementArray object caches |
||
| 58 | */ |
||
| 59 | public $transformData = []; |
||
| 60 | |||
| 61 | /** |
||
| 62 | * @var LocalisationCache |
||
| 63 | */ |
||
| 64 | static public $dataCache; |
||
| 65 | |||
| 66 | static public $mLangObjCache = []; |
||
| 67 | |||
| 68 | static public $mWeekdayMsgs = [ |
||
| 69 | 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', |
||
| 70 | 'friday', 'saturday' |
||
| 71 | ]; |
||
| 72 | |||
| 73 | static public $mWeekdayAbbrevMsgs = [ |
||
| 74 | 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' |
||
| 75 | ]; |
||
| 76 | |||
| 77 | static public $mMonthMsgs = [ |
||
| 78 | 'january', 'february', 'march', 'april', 'may_long', 'june', |
||
| 79 | 'july', 'august', 'september', 'october', 'november', |
||
| 80 | 'december' |
||
| 81 | ]; |
||
| 82 | static public $mMonthGenMsgs = [ |
||
| 83 | 'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen', |
||
| 84 | 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen', |
||
| 85 | 'december-gen' |
||
| 86 | ]; |
||
| 87 | static public $mMonthAbbrevMsgs = [ |
||
| 88 | 'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', |
||
| 89 | 'sep', 'oct', 'nov', 'dec' |
||
| 90 | ]; |
||
| 91 | |||
| 92 | static public $mIranianCalendarMonthMsgs = [ |
||
| 93 | 'iranian-calendar-m1', 'iranian-calendar-m2', 'iranian-calendar-m3', |
||
| 94 | 'iranian-calendar-m4', 'iranian-calendar-m5', 'iranian-calendar-m6', |
||
| 95 | 'iranian-calendar-m7', 'iranian-calendar-m8', 'iranian-calendar-m9', |
||
| 96 | 'iranian-calendar-m10', 'iranian-calendar-m11', 'iranian-calendar-m12' |
||
| 97 | ]; |
||
| 98 | |||
| 99 | static public $mHebrewCalendarMonthMsgs = [ |
||
| 100 | 'hebrew-calendar-m1', 'hebrew-calendar-m2', 'hebrew-calendar-m3', |
||
| 101 | 'hebrew-calendar-m4', 'hebrew-calendar-m5', 'hebrew-calendar-m6', |
||
| 102 | 'hebrew-calendar-m7', 'hebrew-calendar-m8', 'hebrew-calendar-m9', |
||
| 103 | 'hebrew-calendar-m10', 'hebrew-calendar-m11', 'hebrew-calendar-m12', |
||
| 104 | 'hebrew-calendar-m6a', 'hebrew-calendar-m6b' |
||
| 105 | ]; |
||
| 106 | |||
| 107 | static public $mHebrewCalendarMonthGenMsgs = [ |
||
| 108 | 'hebrew-calendar-m1-gen', 'hebrew-calendar-m2-gen', 'hebrew-calendar-m3-gen', |
||
| 109 | 'hebrew-calendar-m4-gen', 'hebrew-calendar-m5-gen', 'hebrew-calendar-m6-gen', |
||
| 110 | 'hebrew-calendar-m7-gen', 'hebrew-calendar-m8-gen', 'hebrew-calendar-m9-gen', |
||
| 111 | 'hebrew-calendar-m10-gen', 'hebrew-calendar-m11-gen', 'hebrew-calendar-m12-gen', |
||
| 112 | 'hebrew-calendar-m6a-gen', 'hebrew-calendar-m6b-gen' |
||
| 113 | ]; |
||
| 114 | |||
| 115 | static public $mHijriCalendarMonthMsgs = [ |
||
| 116 | 'hijri-calendar-m1', 'hijri-calendar-m2', 'hijri-calendar-m3', |
||
| 117 | 'hijri-calendar-m4', 'hijri-calendar-m5', 'hijri-calendar-m6', |
||
| 118 | 'hijri-calendar-m7', 'hijri-calendar-m8', 'hijri-calendar-m9', |
||
| 119 | 'hijri-calendar-m10', 'hijri-calendar-m11', 'hijri-calendar-m12' |
||
| 120 | ]; |
||
| 121 | |||
| 122 | /** |
||
| 123 | * @since 1.20 |
||
| 124 | * @var array |
||
| 125 | */ |
||
| 126 | static public $durationIntervals = [ |
||
| 127 | 'millennia' => 31556952000, |
||
| 128 | 'centuries' => 3155695200, |
||
| 129 | 'decades' => 315569520, |
||
| 130 | 'years' => 31556952, // 86400 * ( 365 + ( 24 * 3 + 25 ) / 400 ) |
||
| 131 | 'weeks' => 604800, |
||
| 132 | 'days' => 86400, |
||
| 133 | 'hours' => 3600, |
||
| 134 | 'minutes' => 60, |
||
| 135 | 'seconds' => 1, |
||
| 136 | ]; |
||
| 137 | |||
| 138 | /** |
||
| 139 | * Cache for language fallbacks. |
||
| 140 | * @see Language::getFallbacksIncludingSiteLanguage |
||
| 141 | * @since 1.21 |
||
| 142 | * @var array |
||
| 143 | */ |
||
| 144 | static private $fallbackLanguageCache = []; |
||
| 145 | |||
| 146 | /** |
||
| 147 | * Cache for language names |
||
| 148 | * @var HashBagOStuff|null |
||
| 149 | */ |
||
| 150 | static private $languageNameCache; |
||
| 151 | |||
| 152 | /** |
||
| 153 | * Unicode directional formatting characters, for embedBidi() |
||
| 154 | */ |
||
| 155 | static private $lre = "\xE2\x80\xAA"; // U+202A LEFT-TO-RIGHT EMBEDDING |
||
| 156 | static private $rle = "\xE2\x80\xAB"; // U+202B RIGHT-TO-LEFT EMBEDDING |
||
| 157 | static private $pdf = "\xE2\x80\xAC"; // U+202C POP DIRECTIONAL FORMATTING |
||
| 158 | |||
| 159 | /** |
||
| 160 | * Directionality test regex for embedBidi(). Matches the first strong directionality codepoint: |
||
| 161 | * - in group 1 if it is LTR |
||
| 162 | * - in group 2 if it is RTL |
||
| 163 | * Does not match if there is no strong directionality codepoint. |
||
| 164 | * |
||
| 165 | * The form is '/(?:([strong ltr codepoint])|([strong rtl codepoint]))/u' . |
||
| 166 | * |
||
| 167 | * Generated by UnicodeJS (see tools/strongDir) from the UCD; see |
||
| 168 | * https://git.wikimedia.org/summary/unicodejs.git . |
||
| 169 | */ |
||
| 170 | // @codingStandardsIgnoreStart |
||
| 171 | // @codeCoverageIgnoreStart |
||
| 172 | 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'; |
||
| 173 | // @codeCoverageIgnoreEnd |
||
| 174 | // @codingStandardsIgnoreEnd |
||
| 175 | |||
| 176 | /** |
||
| 177 | * Get a cached or new language object for a given language code |
||
| 178 | * @param string $code |
||
| 179 | * @return Language |
||
| 180 | */ |
||
| 181 | static function factory( $code ) { |
||
| 200 | |||
| 201 | /** |
||
| 202 | * Create a language object for a given language code |
||
| 203 | * @param string $code |
||
| 204 | * @throws MWException |
||
| 205 | * @return Language |
||
| 206 | */ |
||
| 207 | protected static function newFromCode( $code ) { |
||
| 244 | |||
| 245 | /** |
||
| 246 | * Checks whether any localisation is available for that language tag |
||
| 247 | * in MediaWiki (MessagesXx.php exists). |
||
| 248 | * |
||
| 249 | * @param string $code Language tag (in lower case) |
||
| 250 | * @return bool Whether language is supported |
||
| 251 | * @since 1.21 |
||
| 252 | */ |
||
| 253 | public static function isSupportedLanguage( $code ) { |
||
| 265 | |||
| 266 | /** |
||
| 267 | * Returns true if a language code string is a well-formed language tag |
||
| 268 | * according to RFC 5646. |
||
| 269 | * This function only checks well-formedness; it doesn't check that |
||
| 270 | * language, script or variant codes actually exist in the repositories. |
||
| 271 | * |
||
| 272 | * Based on regexes by Mark Davis of the Unicode Consortium: |
||
| 273 | * http://unicode.org/repos/cldr/trunk/tools/java/org/unicode/cldr/util/data/langtagRegex.txt |
||
| 274 | * |
||
| 275 | * @param string $code |
||
| 276 | * @param bool $lenient Whether to allow '_' as separator. The default is only '-'. |
||
| 277 | * |
||
| 278 | * @return bool |
||
| 279 | * @since 1.21 |
||
| 280 | */ |
||
| 281 | public static function isWellFormedLanguageTag( $code, $lenient = false ) { |
||
| 325 | |||
| 326 | /** |
||
| 327 | * Returns true if a language code string is of a valid form, whether or |
||
| 328 | * not it exists. This includes codes which are used solely for |
||
| 329 | * customisation via the MediaWiki namespace. |
||
| 330 | * |
||
| 331 | * @param string $code |
||
| 332 | * |
||
| 333 | * @return bool |
||
| 334 | */ |
||
| 335 | public static function isValidCode( $code ) { |
||
| 349 | |||
| 350 | /** |
||
| 351 | * Returns true if a language code is of a valid form for the purposes of |
||
| 352 | * internal customisation of MediaWiki, via Messages*.php or *.json. |
||
| 353 | * |
||
| 354 | * @param string $code |
||
| 355 | * |
||
| 356 | * @throws MWException |
||
| 357 | * @since 1.18 |
||
| 358 | * @return bool |
||
| 359 | */ |
||
| 360 | public static function isValidBuiltInCode( $code ) { |
||
| 374 | |||
| 375 | /** |
||
| 376 | * Returns true if a language code is an IETF tag known to MediaWiki. |
||
| 377 | * |
||
| 378 | * @param string $tag |
||
| 379 | * |
||
| 380 | * @since 1.21 |
||
| 381 | * @return bool |
||
| 382 | */ |
||
| 383 | public static function isKnownLanguageTag( $tag ) { |
||
| 398 | |||
| 399 | /** |
||
| 400 | * Get the LocalisationCache instance |
||
| 401 | * |
||
| 402 | * @return LocalisationCache |
||
| 403 | */ |
||
| 404 | public static function getLocalisationCache() { |
||
| 412 | |||
| 413 | function __construct() { |
||
| 423 | |||
| 424 | /** |
||
| 425 | * Reduce memory usage |
||
| 426 | */ |
||
| 427 | function __destruct() { |
||
| 432 | |||
| 433 | /** |
||
| 434 | * Hook which will be called if this is the content language. |
||
| 435 | * Descendants can use this to register hook functions or modify globals |
||
| 436 | */ |
||
| 437 | function initContLang() { |
||
| 439 | |||
| 440 | /** |
||
| 441 | * @return array |
||
| 442 | * @since 1.19 |
||
| 443 | */ |
||
| 444 | public function getFallbackLanguages() { |
||
| 447 | |||
| 448 | /** |
||
| 449 | * Exports $wgBookstoreListEn |
||
| 450 | * @return array |
||
| 451 | */ |
||
| 452 | public function getBookstoreList() { |
||
| 455 | |||
| 456 | /** |
||
| 457 | * Returns an array of localised namespaces indexed by their numbers. If the namespace is not |
||
| 458 | * available in localised form, it will be included in English. |
||
| 459 | * |
||
| 460 | * @return array |
||
| 461 | */ |
||
| 462 | public function getNamespaces() { |
||
| 496 | |||
| 497 | /** |
||
| 498 | * Arbitrarily set all of the namespace names at once. Mainly used for testing |
||
| 499 | * @param array $namespaces Array of namespaces (id => name) |
||
| 500 | */ |
||
| 501 | public function setNamespaces( array $namespaces ) { |
||
| 505 | |||
| 506 | /** |
||
| 507 | * Resets all of the namespace caches. Mainly used for testing |
||
| 508 | */ |
||
| 509 | public function resetNamespaces() { |
||
| 514 | |||
| 515 | /** |
||
| 516 | * A convenience function that returns getNamespaces() with spaces instead of underscores |
||
| 517 | * in values. Useful for producing output to be displayed e.g. in `<select>` forms. |
||
| 518 | * |
||
| 519 | * @return array |
||
| 520 | */ |
||
| 521 | public function getFormattedNamespaces() { |
||
| 528 | |||
| 529 | /** |
||
| 530 | * Get a namespace value by key |
||
| 531 | * |
||
| 532 | * <code> |
||
| 533 | * $mw_ns = $wgContLang->getNsText( NS_MEDIAWIKI ); |
||
| 534 | * echo $mw_ns; // prints 'MediaWiki' |
||
| 535 | * </code> |
||
| 536 | * |
||
| 537 | * @param int $index The array key of the namespace to return |
||
| 538 | * @return string|bool String if the namespace value exists, otherwise false |
||
| 539 | */ |
||
| 540 | public function getNsText( $index ) { |
||
| 544 | |||
| 545 | /** |
||
| 546 | * A convenience function that returns the same thing as |
||
| 547 | * getNsText() except with '_' changed to ' ', useful for |
||
| 548 | * producing output. |
||
| 549 | * |
||
| 550 | * <code> |
||
| 551 | * $mw_ns = $wgContLang->getFormattedNsText( NS_MEDIAWIKI_TALK ); |
||
| 552 | * echo $mw_ns; // prints 'MediaWiki talk' |
||
| 553 | * </code> |
||
| 554 | * |
||
| 555 | * @param int $index The array key of the namespace to return |
||
| 556 | * @return string Namespace name without underscores (empty string if namespace does not exist) |
||
| 557 | */ |
||
| 558 | public function getFormattedNsText( $index ) { |
||
| 562 | |||
| 563 | /** |
||
| 564 | * Returns gender-dependent namespace alias if available. |
||
| 565 | * See https://www.mediawiki.org/wiki/Manual:$wgExtraGenderNamespaces |
||
| 566 | * @param int $index Namespace index |
||
| 567 | * @param string $gender Gender key (male, female... ) |
||
| 568 | * @return string |
||
| 569 | * @since 1.18 |
||
| 570 | */ |
||
| 571 | public function getGenderNsText( $index, $gender ) { |
||
| 579 | |||
| 580 | /** |
||
| 581 | * Whether this language uses gender-dependent namespace aliases. |
||
| 582 | * See https://www.mediawiki.org/wiki/Manual:$wgExtraGenderNamespaces |
||
| 583 | * @return bool |
||
| 584 | * @since 1.18 |
||
| 585 | */ |
||
| 586 | public function needsGenderDistinction() { |
||
| 601 | |||
| 602 | /** |
||
| 603 | * Get a namespace key by value, case insensitive. |
||
| 604 | * Only matches namespace names for the current language, not the |
||
| 605 | * canonical ones defined in Namespace.php. |
||
| 606 | * |
||
| 607 | * @param string $text |
||
| 608 | * @return int|bool An integer if $text is a valid value otherwise false |
||
| 609 | */ |
||
| 610 | function getLocalNsIndex( $text ) { |
||
| 615 | |||
| 616 | /** |
||
| 617 | * @return array |
||
| 618 | */ |
||
| 619 | public function getNamespaceAliases() { |
||
| 659 | |||
| 660 | /** |
||
| 661 | * @return array |
||
| 662 | */ |
||
| 663 | public function getNamespaceIds() { |
||
| 685 | |||
| 686 | /** |
||
| 687 | * Get a namespace key by value, case insensitive. Canonical namespace |
||
| 688 | * names override custom ones defined for the current language. |
||
| 689 | * |
||
| 690 | * @param string $text |
||
| 691 | * @return int|bool An integer if $text is a valid value otherwise false |
||
| 692 | */ |
||
| 693 | public function getNsIndex( $text ) { |
||
| 702 | |||
| 703 | /** |
||
| 704 | * short names for language variants used for language conversion links. |
||
| 705 | * |
||
| 706 | * @param string $code |
||
| 707 | * @param bool $usemsg Use the "variantname-xyz" message if it exists |
||
| 708 | * @return string |
||
| 709 | */ |
||
| 710 | public function getVariantname( $code, $usemsg = true ) { |
||
| 723 | |||
| 724 | /** |
||
| 725 | * @return array |
||
| 726 | */ |
||
| 727 | public function getDatePreferences() { |
||
| 730 | |||
| 731 | /** |
||
| 732 | * @return array |
||
| 733 | */ |
||
| 734 | function getDateFormats() { |
||
| 737 | |||
| 738 | /** |
||
| 739 | * @return array|string |
||
| 740 | */ |
||
| 741 | public function getDefaultDateFormat() { |
||
| 750 | |||
| 751 | /** |
||
| 752 | * @return array |
||
| 753 | */ |
||
| 754 | public function getDatePreferenceMigrationMap() { |
||
| 757 | |||
| 758 | /** |
||
| 759 | * @param string $image |
||
| 760 | * @return array|null |
||
| 761 | */ |
||
| 762 | function getImageFile( $image ) { |
||
| 765 | |||
| 766 | /** |
||
| 767 | * @return array |
||
| 768 | * @since 1.24 |
||
| 769 | */ |
||
| 770 | public function getImageFiles() { |
||
| 773 | |||
| 774 | /** |
||
| 775 | * @return array |
||
| 776 | */ |
||
| 777 | public function getExtraUserToggles() { |
||
| 780 | |||
| 781 | /** |
||
| 782 | * @param string $tog |
||
| 783 | * @return string |
||
| 784 | */ |
||
| 785 | function getUserToggle( $tog ) { |
||
| 788 | |||
| 789 | /** |
||
| 790 | * Get an array of language names, indexed by code. |
||
| 791 | * @param null|string $inLanguage Code of language in which to return the names |
||
| 792 | * Use null for autonyms (native names) |
||
| 793 | * @param string $include One of: |
||
| 794 | * 'all' all available languages |
||
| 795 | * 'mw' only if the language is defined in MediaWiki or wgExtraLanguageNames (default) |
||
| 796 | * 'mwfile' only if the language is in 'mw' *and* has a message file |
||
| 797 | * @return array Language code => language name |
||
| 798 | * @since 1.20 |
||
| 799 | */ |
||
| 800 | public static function fetchLanguageNames( $inLanguage = null, $include = 'mw' ) { |
||
| 814 | |||
| 815 | /** |
||
| 816 | * Uncached helper for fetchLanguageNames |
||
| 817 | * @param null|string $inLanguage Code of language in which to return the names |
||
| 818 | * Use null for autonyms (native names) |
||
| 819 | * @param string $include One of: |
||
| 820 | * 'all' all available languages |
||
| 821 | * 'mw' only if the language is defined in MediaWiki or wgExtraLanguageNames (default) |
||
| 822 | * 'mwfile' only if the language is in 'mw' *and* has a message file |
||
| 823 | * @return array Language code => language name |
||
| 824 | */ |
||
| 825 | private static function fetchLanguageNamesUncached( $inLanguage = null, $include = 'mw' ) { |
||
| 880 | |||
| 881 | /** |
||
| 882 | * @param string $code The code of the language for which to get the name |
||
| 883 | * @param null|string $inLanguage Code of language in which to return the name (null for autonyms) |
||
| 884 | * @param string $include 'all', 'mw' or 'mwfile'; see fetchLanguageNames() |
||
| 885 | * @return string Language name or empty |
||
| 886 | * @since 1.20 |
||
| 887 | */ |
||
| 888 | public static function fetchLanguageName( $code, $inLanguage = null, $include = 'all' ) { |
||
| 893 | |||
| 894 | /** |
||
| 895 | * Get a message from the MediaWiki namespace. |
||
| 896 | * |
||
| 897 | * @param string $msg Message name |
||
| 898 | * @return string |
||
| 899 | */ |
||
| 900 | public function getMessageFromDB( $msg ) { |
||
| 903 | |||
| 904 | /** |
||
| 905 | * Get message object in this language. Only for use inside this class. |
||
| 906 | * |
||
| 907 | * @param string $msg Message name |
||
| 908 | * @return Message |
||
| 909 | */ |
||
| 910 | protected function msg( $msg ) { |
||
| 913 | |||
| 914 | /** |
||
| 915 | * @param string $key |
||
| 916 | * @return string |
||
| 917 | */ |
||
| 918 | public function getMonthName( $key ) { |
||
| 921 | |||
| 922 | /** |
||
| 923 | * @return array |
||
| 924 | */ |
||
| 925 | View Code Duplication | public function getMonthNamesArray() { |
|
| 932 | |||
| 933 | /** |
||
| 934 | * @param string $key |
||
| 935 | * @return string |
||
| 936 | */ |
||
| 937 | public function getMonthNameGen( $key ) { |
||
| 940 | |||
| 941 | /** |
||
| 942 | * @param string $key |
||
| 943 | * @return string |
||
| 944 | */ |
||
| 945 | public function getMonthAbbreviation( $key ) { |
||
| 948 | |||
| 949 | /** |
||
| 950 | * @return array |
||
| 951 | */ |
||
| 952 | View Code Duplication | public function getMonthAbbreviationsArray() { |
|
| 959 | |||
| 960 | /** |
||
| 961 | * @param string $key |
||
| 962 | * @return string |
||
| 963 | */ |
||
| 964 | public function getWeekdayName( $key ) { |
||
| 967 | |||
| 968 | /** |
||
| 969 | * @param string $key |
||
| 970 | * @return string |
||
| 971 | */ |
||
| 972 | function getWeekdayAbbreviation( $key ) { |
||
| 975 | |||
| 976 | /** |
||
| 977 | * @param string $key |
||
| 978 | * @return string |
||
| 979 | */ |
||
| 980 | function getIranianCalendarMonthName( $key ) { |
||
| 983 | |||
| 984 | /** |
||
| 985 | * @param string $key |
||
| 986 | * @return string |
||
| 987 | */ |
||
| 988 | function getHebrewCalendarMonthName( $key ) { |
||
| 991 | |||
| 992 | /** |
||
| 993 | * @param string $key |
||
| 994 | * @return string |
||
| 995 | */ |
||
| 996 | function getHebrewCalendarMonthNameGen( $key ) { |
||
| 999 | |||
| 1000 | /** |
||
| 1001 | * @param string $key |
||
| 1002 | * @return string |
||
| 1003 | */ |
||
| 1004 | function getHijriCalendarMonthName( $key ) { |
||
| 1007 | |||
| 1008 | /** |
||
| 1009 | * Pass through result from $dateTimeObj->format() |
||
| 1010 | * @param DateTime|bool|null &$dateTimeObj |
||
| 1011 | * @param string $ts |
||
| 1012 | * @param DateTimeZone|bool|null $zone |
||
| 1013 | * @param string $code |
||
| 1014 | * @return string |
||
| 1015 | */ |
||
| 1016 | private static function dateTimeObjFormat( &$dateTimeObj, $ts, $zone, $code ) { |
||
| 1024 | |||
| 1025 | /** |
||
| 1026 | * This is a workalike of PHP's date() function, but with better |
||
| 1027 | * internationalisation, a reduced set of format characters, and a better |
||
| 1028 | * escaping format. |
||
| 1029 | * |
||
| 1030 | * Supported format characters are dDjlNwzWFmMntLoYyaAgGhHiscrUeIOPTZ. See |
||
| 1031 | * the PHP manual for definitions. There are a number of extensions, which |
||
| 1032 | * start with "x": |
||
| 1033 | * |
||
| 1034 | * xn Do not translate digits of the next numeric format character |
||
| 1035 | * xN Toggle raw digit (xn) flag, stays set until explicitly unset |
||
| 1036 | * xr Use roman numerals for the next numeric format character |
||
| 1037 | * xh Use hebrew numerals for the next numeric format character |
||
| 1038 | * xx Literal x |
||
| 1039 | * xg Genitive month name |
||
| 1040 | * |
||
| 1041 | * xij j (day number) in Iranian calendar |
||
| 1042 | * xiF F (month name) in Iranian calendar |
||
| 1043 | * xin n (month number) in Iranian calendar |
||
| 1044 | * xiy y (two digit year) in Iranian calendar |
||
| 1045 | * xiY Y (full year) in Iranian calendar |
||
| 1046 | * |
||
| 1047 | * xjj j (day number) in Hebrew calendar |
||
| 1048 | * xjF F (month name) in Hebrew calendar |
||
| 1049 | * xjt t (days in month) in Hebrew calendar |
||
| 1050 | * xjx xg (genitive month name) in Hebrew calendar |
||
| 1051 | * xjn n (month number) in Hebrew calendar |
||
| 1052 | * xjY Y (full year) in Hebrew calendar |
||
| 1053 | * |
||
| 1054 | * xmj j (day number) in Hijri calendar |
||
| 1055 | * xmF F (month name) in Hijri calendar |
||
| 1056 | * xmn n (month number) in Hijri calendar |
||
| 1057 | * xmY Y (full year) in Hijri calendar |
||
| 1058 | * |
||
| 1059 | * xkY Y (full year) in Thai solar calendar. Months and days are |
||
| 1060 | * identical to the Gregorian calendar |
||
| 1061 | * xoY Y (full year) in Minguo calendar or Juche year. |
||
| 1062 | * Months and days are identical to the |
||
| 1063 | * Gregorian calendar |
||
| 1064 | * xtY Y (full year) in Japanese nengo. Months and days are |
||
| 1065 | * identical to the Gregorian calendar |
||
| 1066 | * |
||
| 1067 | * Characters enclosed in double quotes will be considered literal (with |
||
| 1068 | * the quotes themselves removed). Unmatched quotes will be considered |
||
| 1069 | * literal quotes. Example: |
||
| 1070 | * |
||
| 1071 | * "The month is" F => The month is January |
||
| 1072 | * i's" => 20'11" |
||
| 1073 | * |
||
| 1074 | * Backslash escaping is also supported. |
||
| 1075 | * |
||
| 1076 | * Input timestamp is assumed to be pre-normalized to the desired local |
||
| 1077 | * time zone, if any. Note that the format characters crUeIOPTZ will assume |
||
| 1078 | * $ts is UTC if $zone is not given. |
||
| 1079 | * |
||
| 1080 | * @param string $format |
||
| 1081 | * @param string $ts 14-character timestamp |
||
| 1082 | * YYYYMMDDHHMMSS |
||
| 1083 | * 01234567890123 |
||
| 1084 | * @param DateTimeZone $zone Timezone of $ts |
||
| 1085 | * @param[out] int $ttl The amount of time (in seconds) the output may be cached for. |
||
| 1086 | * Only makes sense if $ts is the current time. |
||
| 1087 | * @todo handling of "o" format character for Iranian, Hebrew, Hijri & Thai? |
||
| 1088 | * |
||
| 1089 | * @throws MWException |
||
| 1090 | * @return string |
||
| 1091 | */ |
||
| 1092 | public function sprintfDate( $format, $ts, DateTimeZone $zone = null, &$ttl = null ) { |
||
| 1544 | |||
| 1545 | private static $GREG_DAYS = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; |
||
| 1546 | private static $IRANIAN_DAYS = [ 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 ]; |
||
| 1547 | |||
| 1548 | /** |
||
| 1549 | * Algorithm by Roozbeh Pournader and Mohammad Toossi to convert |
||
| 1550 | * Gregorian dates to Iranian dates. Originally written in C, it |
||
| 1551 | * is released under the terms of GNU Lesser General Public |
||
| 1552 | * License. Conversion to PHP was performed by Niklas Laxström. |
||
| 1553 | * |
||
| 1554 | * Link: http://www.farsiweb.info/jalali/jalali.c |
||
| 1555 | * |
||
| 1556 | * @param string $ts |
||
| 1557 | * |
||
| 1558 | * @return int[] |
||
| 1559 | */ |
||
| 1560 | private static function tsToIranian( $ts ) { |
||
| 1606 | |||
| 1607 | /** |
||
| 1608 | * Converting Gregorian dates to Hijri dates. |
||
| 1609 | * |
||
| 1610 | * Based on a PHP-Nuke block by Sharjeel which is released under GNU/GPL license |
||
| 1611 | * |
||
| 1612 | * @see http://phpnuke.org/modules.php?name=News&file=article&sid=8234&mode=thread&order=0&thold=0 |
||
| 1613 | * |
||
| 1614 | * @param string $ts |
||
| 1615 | * |
||
| 1616 | * @return int[] |
||
| 1617 | */ |
||
| 1618 | private static function tsToHijri( $ts ) { |
||
| 1654 | |||
| 1655 | /** |
||
| 1656 | * Converting Gregorian dates to Hebrew dates. |
||
| 1657 | * |
||
| 1658 | * Based on a JavaScript code by Abu Mami and Yisrael Hersch |
||
| 1659 | * ([email protected], http://www.kaluach.net), who permitted |
||
| 1660 | * to translate the relevant functions into PHP and release them under |
||
| 1661 | * GNU GPL. |
||
| 1662 | * |
||
| 1663 | * The months are counted from Tishrei = 1. In a leap year, Adar I is 13 |
||
| 1664 | * and Adar II is 14. In a non-leap year, Adar is 6. |
||
| 1665 | * |
||
| 1666 | * @param string $ts |
||
| 1667 | * |
||
| 1668 | * @return int[] |
||
| 1669 | */ |
||
| 1670 | private static function tsToHebrew( $ts ) { |
||
| 1801 | |||
| 1802 | /** |
||
| 1803 | * This calculates the Hebrew year start, as days since 1 September. |
||
| 1804 | * Based on Carl Friedrich Gauss algorithm for finding Easter date. |
||
| 1805 | * Used for Hebrew date. |
||
| 1806 | * |
||
| 1807 | * @param int $year |
||
| 1808 | * |
||
| 1809 | * @return string |
||
| 1810 | */ |
||
| 1811 | private static function hebrewYearStart( $year ) { |
||
| 1836 | |||
| 1837 | /** |
||
| 1838 | * Algorithm to convert Gregorian dates to Thai solar dates, |
||
| 1839 | * Minguo dates or Minguo dates. |
||
| 1840 | * |
||
| 1841 | * Link: http://en.wikipedia.org/wiki/Thai_solar_calendar |
||
| 1842 | * http://en.wikipedia.org/wiki/Minguo_calendar |
||
| 1843 | * http://en.wikipedia.org/wiki/Japanese_era_name |
||
| 1844 | * |
||
| 1845 | * @param string $ts 14-character timestamp |
||
| 1846 | * @param string $cName Calender name |
||
| 1847 | * @return array Converted year, month, day |
||
| 1848 | */ |
||
| 1849 | private static function tsToYear( $ts, $cName ) { |
||
| 1921 | |||
| 1922 | /** |
||
| 1923 | * Gets directionality of the first strongly directional codepoint, for embedBidi() |
||
| 1924 | * |
||
| 1925 | * This is the rule the BIDI algorithm uses to determine the directionality of |
||
| 1926 | * paragraphs ( http://unicode.org/reports/tr9/#The_Paragraph_Level ) and |
||
| 1927 | * FSI isolates ( http://unicode.org/reports/tr9/#Explicit_Directional_Isolates ). |
||
| 1928 | * |
||
| 1929 | * TODO: Does not handle BIDI control characters inside the text. |
||
| 1930 | * TODO: Does not handle unallocated characters. |
||
| 1931 | * |
||
| 1932 | * @param string $text Text to test |
||
| 1933 | * @return null|string Directionality ('ltr' or 'rtl') or null |
||
| 1934 | */ |
||
| 1935 | private static function strongDirFromContent( $text = '' ) { |
||
| 1944 | |||
| 1945 | /** |
||
| 1946 | * Roman number formatting up to 10000 |
||
| 1947 | * |
||
| 1948 | * @param int $num |
||
| 1949 | * |
||
| 1950 | * @return string |
||
| 1951 | */ |
||
| 1952 | static function romanNumeral( $num ) { |
||
| 1975 | |||
| 1976 | /** |
||
| 1977 | * Hebrew Gematria number formatting up to 9999 |
||
| 1978 | * |
||
| 1979 | * @param int $num |
||
| 1980 | * |
||
| 1981 | * @return string |
||
| 1982 | */ |
||
| 1983 | static function hebrewNumeral( $num ) { |
||
| 2061 | |||
| 2062 | /** |
||
| 2063 | * Used by date() and time() to adjust the time output. |
||
| 2064 | * |
||
| 2065 | * @param string $ts The time in date('YmdHis') format |
||
| 2066 | * @param mixed $tz Adjust the time by this amount (default false, mean we |
||
| 2067 | * get user timecorrection setting) |
||
| 2068 | * @return int |
||
| 2069 | */ |
||
| 2070 | public function userAdjust( $ts, $tz = false ) { |
||
| 2134 | |||
| 2135 | /** |
||
| 2136 | * This is meant to be used by time(), date(), and timeanddate() to get |
||
| 2137 | * the date preference they're supposed to use, it should be used in |
||
| 2138 | * all children. |
||
| 2139 | * |
||
| 2140 | *<code> |
||
| 2141 | * function timeanddate([...], $format = true) { |
||
| 2142 | * $datePreference = $this->dateFormat($format); |
||
| 2143 | * [...] |
||
| 2144 | * } |
||
| 2145 | *</code> |
||
| 2146 | * |
||
| 2147 | * @param int|string|bool $usePrefs If true, the user's preference is used |
||
| 2148 | * if false, the site/language default is used |
||
| 2149 | * if int/string, assumed to be a format. |
||
| 2150 | * @return string |
||
| 2151 | */ |
||
| 2152 | function dateFormat( $usePrefs = true ) { |
||
| 2172 | |||
| 2173 | /** |
||
| 2174 | * Get a format string for a given type and preference |
||
| 2175 | * @param string $type May be 'date', 'time', 'both', or 'pretty'. |
||
| 2176 | * @param string $pref The format name as it appears in Messages*.php under |
||
| 2177 | * $datePreferences. |
||
| 2178 | * |
||
| 2179 | * @since 1.22 New type 'pretty' that provides a more readable timestamp format |
||
| 2180 | * |
||
| 2181 | * @return string |
||
| 2182 | */ |
||
| 2183 | function getDateFormatString( $type, $pref ) { |
||
| 2206 | |||
| 2207 | /** |
||
| 2208 | * @param string $ts The time format which needs to be turned into a |
||
| 2209 | * date('YmdHis') format with wfTimestamp(TS_MW,$ts) |
||
| 2210 | * @param bool $adj Whether to adjust the time output according to the |
||
| 2211 | * user configured offset ($timecorrection) |
||
| 2212 | * @param mixed $format True to use user's date format preference |
||
| 2213 | * @param string|bool $timecorrection The time offset as returned by |
||
| 2214 | * validateTimeZone() in Special:Preferences |
||
| 2215 | * @return string |
||
| 2216 | */ |
||
| 2217 | View Code Duplication | public function date( $ts, $adj = false, $format = true, $timecorrection = false ) { |
|
| 2225 | |||
| 2226 | /** |
||
| 2227 | * @param string $ts The time format which needs to be turned into a |
||
| 2228 | * date('YmdHis') format with wfTimestamp(TS_MW,$ts) |
||
| 2229 | * @param bool $adj Whether to adjust the time output according to the |
||
| 2230 | * user configured offset ($timecorrection) |
||
| 2231 | * @param mixed $format True to use user's date format preference |
||
| 2232 | * @param string|bool $timecorrection The time offset as returned by |
||
| 2233 | * validateTimeZone() in Special:Preferences |
||
| 2234 | * @return string |
||
| 2235 | */ |
||
| 2236 | View Code Duplication | public function time( $ts, $adj = false, $format = true, $timecorrection = false ) { |
|
| 2244 | |||
| 2245 | /** |
||
| 2246 | * @param string $ts The time format which needs to be turned into a |
||
| 2247 | * date('YmdHis') format with wfTimestamp(TS_MW,$ts) |
||
| 2248 | * @param bool $adj Whether to adjust the time output according to the |
||
| 2249 | * user configured offset ($timecorrection) |
||
| 2250 | * @param mixed $format What format to return, if it's false output the |
||
| 2251 | * default one (default true) |
||
| 2252 | * @param string|bool $timecorrection The time offset as returned by |
||
| 2253 | * validateTimeZone() in Special:Preferences |
||
| 2254 | * @return string |
||
| 2255 | */ |
||
| 2256 | View Code Duplication | public function timeanddate( $ts, $adj = false, $format = true, $timecorrection = false ) { |
|
| 2264 | |||
| 2265 | /** |
||
| 2266 | * Takes a number of seconds and turns it into a text using values such as hours and minutes. |
||
| 2267 | * |
||
| 2268 | * @since 1.20 |
||
| 2269 | * |
||
| 2270 | * @param int $seconds The amount of seconds. |
||
| 2271 | * @param array $chosenIntervals The intervals to enable. |
||
| 2272 | * |
||
| 2273 | * @return string |
||
| 2274 | */ |
||
| 2275 | public function formatDuration( $seconds, array $chosenIntervals = [] ) { |
||
| 2289 | |||
| 2290 | /** |
||
| 2291 | * Takes a number of seconds and returns an array with a set of corresponding intervals. |
||
| 2292 | * For example 65 will be turned into array( minutes => 1, seconds => 5 ). |
||
| 2293 | * |
||
| 2294 | * @since 1.20 |
||
| 2295 | * |
||
| 2296 | * @param int $seconds The amount of seconds. |
||
| 2297 | * @param array $chosenIntervals The intervals to enable. |
||
| 2298 | * |
||
| 2299 | * @return array |
||
| 2300 | */ |
||
| 2301 | public function getDurationIntervals( $seconds, array $chosenIntervals = [] ) { |
||
| 2332 | |||
| 2333 | /** |
||
| 2334 | * Internal helper function for userDate(), userTime() and userTimeAndDate() |
||
| 2335 | * |
||
| 2336 | * @param string $type Can be 'date', 'time' or 'both' |
||
| 2337 | * @param string $ts The time format which needs to be turned into a |
||
| 2338 | * date('YmdHis') format with wfTimestamp(TS_MW,$ts) |
||
| 2339 | * @param User $user User object used to get preferences for timezone and format |
||
| 2340 | * @param array $options Array, can contain the following keys: |
||
| 2341 | * - 'timecorrection': time correction, can have the following values: |
||
| 2342 | * - true: use user's preference |
||
| 2343 | * - false: don't use time correction |
||
| 2344 | * - int: value of time correction in minutes |
||
| 2345 | * - 'format': format to use, can have the following values: |
||
| 2346 | * - true: use user's preference |
||
| 2347 | * - false: use default preference |
||
| 2348 | * - string: format to use |
||
| 2349 | * @since 1.19 |
||
| 2350 | * @return string |
||
| 2351 | */ |
||
| 2352 | private function internalUserTimeAndDate( $type, $ts, User $user, array $options ) { |
||
| 2371 | |||
| 2372 | /** |
||
| 2373 | * Get the formatted date for the given timestamp and formatted for |
||
| 2374 | * the given user. |
||
| 2375 | * |
||
| 2376 | * @param mixed $ts Mixed: the time format which needs to be turned into a |
||
| 2377 | * date('YmdHis') format with wfTimestamp(TS_MW,$ts) |
||
| 2378 | * @param User $user User object used to get preferences for timezone and format |
||
| 2379 | * @param array $options Array, can contain the following keys: |
||
| 2380 | * - 'timecorrection': time correction, can have the following values: |
||
| 2381 | * - true: use user's preference |
||
| 2382 | * - false: don't use time correction |
||
| 2383 | * - int: value of time correction in minutes |
||
| 2384 | * - 'format': format to use, can have the following values: |
||
| 2385 | * - true: use user's preference |
||
| 2386 | * - false: use default preference |
||
| 2387 | * - string: format to use |
||
| 2388 | * @since 1.19 |
||
| 2389 | * @return string |
||
| 2390 | */ |
||
| 2391 | public function userDate( $ts, User $user, array $options = [] ) { |
||
| 2394 | |||
| 2395 | /** |
||
| 2396 | * Get the formatted time for the given timestamp and formatted for |
||
| 2397 | * the given user. |
||
| 2398 | * |
||
| 2399 | * @param mixed $ts The time format which needs to be turned into a |
||
| 2400 | * date('YmdHis') format with wfTimestamp(TS_MW,$ts) |
||
| 2401 | * @param User $user User object used to get preferences for timezone and format |
||
| 2402 | * @param array $options Array, can contain the following keys: |
||
| 2403 | * - 'timecorrection': time correction, can have the following values: |
||
| 2404 | * - true: use user's preference |
||
| 2405 | * - false: don't use time correction |
||
| 2406 | * - int: value of time correction in minutes |
||
| 2407 | * - 'format': format to use, can have the following values: |
||
| 2408 | * - true: use user's preference |
||
| 2409 | * - false: use default preference |
||
| 2410 | * - string: format to use |
||
| 2411 | * @since 1.19 |
||
| 2412 | * @return string |
||
| 2413 | */ |
||
| 2414 | public function userTime( $ts, User $user, array $options = [] ) { |
||
| 2417 | |||
| 2418 | /** |
||
| 2419 | * Get the formatted date and time for the given timestamp and formatted for |
||
| 2420 | * the given user. |
||
| 2421 | * |
||
| 2422 | * @param mixed $ts The time format which needs to be turned into a |
||
| 2423 | * date('YmdHis') format with wfTimestamp(TS_MW,$ts) |
||
| 2424 | * @param User $user User object used to get preferences for timezone and format |
||
| 2425 | * @param array $options Array, can contain the following keys: |
||
| 2426 | * - 'timecorrection': time correction, can have the following values: |
||
| 2427 | * - true: use user's preference |
||
| 2428 | * - false: don't use time correction |
||
| 2429 | * - int: value of time correction in minutes |
||
| 2430 | * - 'format': format to use, can have the following values: |
||
| 2431 | * - true: use user's preference |
||
| 2432 | * - false: use default preference |
||
| 2433 | * - string: format to use |
||
| 2434 | * @since 1.19 |
||
| 2435 | * @return string |
||
| 2436 | */ |
||
| 2437 | public function userTimeAndDate( $ts, User $user, array $options = [] ) { |
||
| 2440 | |||
| 2441 | /** |
||
| 2442 | * Get the timestamp in a human-friendly relative format, e.g., "3 days ago". |
||
| 2443 | * |
||
| 2444 | * Determine the difference between the timestamp and the current time, and |
||
| 2445 | * generate a readable timestamp by returning "<N> <units> ago", where the |
||
| 2446 | * largest possible unit is used. |
||
| 2447 | * |
||
| 2448 | * @since 1.26 (Prior to 1.26 method existed but was not meant to be used directly) |
||
| 2449 | * |
||
| 2450 | * @param MWTimestamp $time |
||
| 2451 | * @param MWTimestamp|null $relativeTo The base timestamp to compare to (defaults to now) |
||
| 2452 | * @param User|null $user User the timestamp is being generated for |
||
| 2453 | * (or null to use main context's user) |
||
| 2454 | * @return string Formatted timestamp |
||
| 2455 | */ |
||
| 2456 | public function getHumanTimestamp( |
||
| 2481 | |||
| 2482 | /** |
||
| 2483 | * Convert an MWTimestamp into a pretty human-readable timestamp using |
||
| 2484 | * the given user preferences and relative base time. |
||
| 2485 | * |
||
| 2486 | * @see Language::getHumanTimestamp |
||
| 2487 | * @param MWTimestamp $ts Timestamp to prettify |
||
| 2488 | * @param MWTimestamp $relativeTo Base timestamp |
||
| 2489 | * @param User $user User preferences to use |
||
| 2490 | * @return string Human timestamp |
||
| 2491 | * @since 1.26 |
||
| 2492 | */ |
||
| 2493 | private function getHumanTimestampInternal( |
||
| 2557 | |||
| 2558 | /** |
||
| 2559 | * @param string $key |
||
| 2560 | * @return array|null |
||
| 2561 | */ |
||
| 2562 | public function getMessage( $key ) { |
||
| 2565 | |||
| 2566 | /** |
||
| 2567 | * @return array |
||
| 2568 | */ |
||
| 2569 | function getAllMessages() { |
||
| 2572 | |||
| 2573 | /** |
||
| 2574 | * @param string $in |
||
| 2575 | * @param string $out |
||
| 2576 | * @param string $string |
||
| 2577 | * @return string |
||
| 2578 | */ |
||
| 2579 | public function iconv( $in, $out, $string ) { |
||
| 2592 | |||
| 2593 | // callback functions for ucwords(), ucwordbreaks() |
||
| 2594 | |||
| 2595 | /** |
||
| 2596 | * @param array $matches |
||
| 2597 | * @return mixed|string |
||
| 2598 | */ |
||
| 2599 | function ucwordbreaksCallbackAscii( $matches ) { |
||
| 2602 | |||
| 2603 | /** |
||
| 2604 | * @param array $matches |
||
| 2605 | * @return string |
||
| 2606 | */ |
||
| 2607 | function ucwordbreaksCallbackMB( $matches ) { |
||
| 2610 | |||
| 2611 | /** |
||
| 2612 | * @param array $matches |
||
| 2613 | * @return string |
||
| 2614 | */ |
||
| 2615 | function ucwordsCallbackMB( $matches ) { |
||
| 2616 | return mb_strtoupper( $matches[0] ); |
||
| 2617 | } |
||
| 2618 | |||
| 2619 | /** |
||
| 2620 | * Make a string's first character uppercase |
||
| 2621 | * |
||
| 2622 | * @param string $str |
||
| 2623 | * |
||
| 2624 | * @return string |
||
| 2625 | */ |
||
| 2626 | public function ucfirst( $str ) { |
||
| 2627 | $o = ord( $str ); |
||
| 2628 | if ( $o < 96 ) { // if already uppercase... |
||
| 2629 | return $str; |
||
| 2630 | } elseif ( $o < 128 ) { |
||
| 2631 | return ucfirst( $str ); // use PHP's ucfirst() |
||
| 2632 | } else { |
||
| 2633 | // fall back to more complex logic in case of multibyte strings |
||
| 2634 | return $this->uc( $str, true ); |
||
| 2635 | } |
||
| 2636 | } |
||
| 2637 | |||
| 2638 | /** |
||
| 2639 | * Convert a string to uppercase |
||
| 2640 | * |
||
| 2641 | * @param string $str |
||
| 2642 | * @param bool $first |
||
| 2643 | * |
||
| 2644 | * @return string |
||
| 2645 | */ |
||
| 2646 | public function uc( $str, $first = false ) { |
||
| 2647 | if ( $first ) { |
||
| 2648 | if ( $this->isMultibyte( $str ) ) { |
||
| 2649 | return mb_strtoupper( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 ); |
||
| 2650 | } else { |
||
| 2651 | return ucfirst( $str ); |
||
| 2652 | } |
||
| 2653 | } else { |
||
| 2654 | return $this->isMultibyte( $str ) ? mb_strtoupper( $str ) : strtoupper( $str ); |
||
| 2655 | } |
||
| 2656 | } |
||
| 2657 | |||
| 2658 | /** |
||
| 2659 | * @param string $str |
||
| 2660 | * @return mixed|string |
||
| 2661 | */ |
||
| 2662 | function lcfirst( $str ) { |
||
| 2675 | |||
| 2676 | /** |
||
| 2677 | * @param string $str |
||
| 2678 | * @param bool $first |
||
| 2679 | * @return mixed|string |
||
| 2680 | */ |
||
| 2681 | function lc( $str, $first = false ) { |
||
| 2682 | if ( $first ) { |
||
| 2683 | if ( $this->isMultibyte( $str ) ) { |
||
| 2684 | return mb_strtolower( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 ); |
||
| 2685 | } else { |
||
| 2686 | return strtolower( substr( $str, 0, 1 ) ) . substr( $str, 1 ); |
||
| 2687 | } |
||
| 2688 | } else { |
||
| 2689 | return $this->isMultibyte( $str ) ? mb_strtolower( $str ) : strtolower( $str ); |
||
| 2690 | } |
||
| 2691 | } |
||
| 2692 | |||
| 2693 | /** |
||
| 2694 | * @param string $str |
||
| 2695 | * @return bool |
||
| 2696 | */ |
||
| 2697 | function isMultibyte( $str ) { |
||
| 2700 | |||
| 2701 | /** |
||
| 2702 | * @param string $str |
||
| 2703 | * @return mixed|string |
||
| 2704 | */ |
||
| 2705 | function ucwords( $str ) { |
||
| 2706 | if ( $this->isMultibyte( $str ) ) { |
||
| 2707 | $str = $this->lc( $str ); |
||
| 2708 | |||
| 2709 | // regexp to find first letter in each word (i.e. after each space) |
||
| 2710 | $replaceRegexp = "/^([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)| ([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/"; |
||
| 2711 | |||
| 2712 | // function to use to capitalize a single char |
||
| 2713 | return preg_replace_callback( |
||
| 2714 | $replaceRegexp, |
||
| 2715 | [ $this, 'ucwordsCallbackMB' ], |
||
| 2716 | $str |
||
| 2717 | ); |
||
| 2718 | } else { |
||
| 2719 | return ucwords( strtolower( $str ) ); |
||
| 2720 | } |
||
| 2721 | } |
||
| 2722 | |||
| 2723 | /** |
||
| 2724 | * capitalize words at word breaks |
||
| 2725 | * |
||
| 2726 | * @param string $str |
||
| 2727 | * @return mixed |
||
| 2728 | */ |
||
| 2729 | function ucwordbreaks( $str ) { |
||
| 2730 | if ( $this->isMultibyte( $str ) ) { |
||
| 2731 | $str = $this->lc( $str ); |
||
| 2732 | |||
| 2733 | // since \b doesn't work for UTF-8, we explicitely define word break chars |
||
| 2734 | $breaks = "[ \-\(\)\}\{\.,\?!]"; |
||
| 2735 | |||
| 2736 | // find first letter after word break |
||
| 2737 | $replaceRegexp = "/^([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)|" . |
||
| 2738 | "$breaks([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/"; |
||
| 2739 | |||
| 2740 | return preg_replace_callback( |
||
| 2741 | $replaceRegexp, |
||
| 2742 | [ $this, 'ucwordbreaksCallbackMB' ], |
||
| 2743 | $str |
||
| 2744 | ); |
||
| 2745 | } else { |
||
| 2746 | return preg_replace_callback( |
||
| 2747 | '/\b([\w\x80-\xff]+)\b/', |
||
| 2748 | [ $this, 'ucwordbreaksCallbackAscii' ], |
||
| 2749 | $str |
||
| 2750 | ); |
||
| 2751 | } |
||
| 2752 | } |
||
| 2753 | |||
| 2754 | /** |
||
| 2755 | * Return a case-folded representation of $s |
||
| 2756 | * |
||
| 2757 | * This is a representation such that caseFold($s1)==caseFold($s2) if $s1 |
||
| 2758 | * and $s2 are the same except for the case of their characters. It is not |
||
| 2759 | * necessary for the value returned to make sense when displayed. |
||
| 2760 | * |
||
| 2761 | * Do *not* perform any other normalisation in this function. If a caller |
||
| 2762 | * uses this function when it should be using a more general normalisation |
||
| 2763 | * function, then fix the caller. |
||
| 2764 | * |
||
| 2765 | * @param string $s |
||
| 2766 | * |
||
| 2767 | * @return string |
||
| 2768 | */ |
||
| 2769 | function caseFold( $s ) { |
||
| 2770 | return $this->uc( $s ); |
||
| 2771 | } |
||
| 2772 | |||
| 2773 | /** |
||
| 2774 | * @param string $s |
||
| 2775 | * @return string |
||
| 2776 | * @throws MWException |
||
| 2777 | */ |
||
| 2778 | function checkTitleEncoding( $s ) { |
||
| 2779 | if ( is_array( $s ) ) { |
||
| 2780 | throw new MWException( 'Given array to checkTitleEncoding.' ); |
||
| 2781 | } |
||
| 2782 | if ( StringUtils::isUtf8( $s ) ) { |
||
| 2783 | return $s; |
||
| 2784 | } |
||
| 2785 | |||
| 2786 | return $this->iconv( $this->fallback8bitEncoding(), 'utf-8', $s ); |
||
| 2787 | } |
||
| 2788 | |||
| 2789 | /** |
||
| 2790 | * @return array |
||
| 2791 | */ |
||
| 2792 | function fallback8bitEncoding() { |
||
| 2795 | |||
| 2796 | /** |
||
| 2797 | * Most writing systems use whitespace to break up words. |
||
| 2798 | * Some languages such as Chinese don't conventionally do this, |
||
| 2799 | * which requires special handling when breaking up words for |
||
| 2800 | * searching etc. |
||
| 2801 | * |
||
| 2802 | * @return bool |
||
| 2803 | */ |
||
| 2804 | function hasWordBreaks() { |
||
| 2805 | return true; |
||
| 2806 | } |
||
| 2807 | |||
| 2808 | /** |
||
| 2809 | * Some languages such as Chinese require word segmentation, |
||
| 2810 | * Specify such segmentation when overridden in derived class. |
||
| 2811 | * |
||
| 2812 | * @param string $string |
||
| 2813 | * @return string |
||
| 2814 | */ |
||
| 2815 | function segmentByWord( $string ) { |
||
| 2816 | return $string; |
||
| 2817 | } |
||
| 2818 | |||
| 2819 | /** |
||
| 2820 | * Some languages have special punctuation need to be normalized. |
||
| 2821 | * Make such changes here. |
||
| 2822 | * |
||
| 2823 | * @param string $string |
||
| 2824 | * @return string |
||
| 2825 | */ |
||
| 2826 | function normalizeForSearch( $string ) { |
||
| 2829 | |||
| 2830 | /** |
||
| 2831 | * convert double-width roman characters to single-width. |
||
| 2832 | * range: ff00-ff5f ~= 0020-007f |
||
| 2833 | * |
||
| 2834 | * @param string $string |
||
| 2835 | * |
||
| 2836 | * @return string |
||
| 2837 | */ |
||
| 2838 | protected static function convertDoubleWidth( $string ) { |
||
| 2852 | |||
| 2853 | /** |
||
| 2854 | * @param string $string |
||
| 2855 | * @param string $pattern |
||
| 2856 | * @return string |
||
| 2857 | */ |
||
| 2858 | protected static function insertSpace( $string, $pattern ) { |
||
| 2863 | |||
| 2864 | /** |
||
| 2865 | * @param array $termsArray |
||
| 2866 | * @return array |
||
| 2867 | */ |
||
| 2868 | function convertForSearchResult( $termsArray ) { |
||
| 2873 | |||
| 2874 | /** |
||
| 2875 | * Get the first character of a string. |
||
| 2876 | * |
||
| 2877 | * @param string $s |
||
| 2878 | * @return string |
||
| 2879 | */ |
||
| 2880 | function firstChar( $s ) { |
||
| 2931 | |||
| 2932 | function initEncoding() { |
||
| 2938 | |||
| 2939 | /** |
||
| 2940 | * @param string $s |
||
| 2941 | * @return string |
||
| 2942 | */ |
||
| 2943 | function recodeForEdit( $s ) { |
||
| 2954 | |||
| 2955 | /** |
||
| 2956 | * @param string $s |
||
| 2957 | * @return string |
||
| 2958 | */ |
||
| 2959 | function recodeInput( $s ) { |
||
| 2973 | |||
| 2974 | /** |
||
| 2975 | * Convert a UTF-8 string to normal form C. In Malayalam and Arabic, this |
||
| 2976 | * also cleans up certain backwards-compatible sequences, converting them |
||
| 2977 | * to the modern Unicode equivalent. |
||
| 2978 | * |
||
| 2979 | * This is language-specific for performance reasons only. |
||
| 2980 | * |
||
| 2981 | * @param string $s |
||
| 2982 | * |
||
| 2983 | * @return string |
||
| 2984 | */ |
||
| 2985 | function normalize( $s ) { |
||
| 2995 | |||
| 2996 | /** |
||
| 2997 | * Transform a string using serialized data stored in the given file (which |
||
| 2998 | * must be in the serialized subdirectory of $IP). The file contains pairs |
||
| 2999 | * mapping source characters to destination characters. |
||
| 3000 | * |
||
| 3001 | * The data is cached in process memory. This will go faster if you have the |
||
| 3002 | * FastStringSearch extension. |
||
| 3003 | * |
||
| 3004 | * @param string $file |
||
| 3005 | * @param string $string |
||
| 3006 | * |
||
| 3007 | * @throws MWException |
||
| 3008 | * @return string |
||
| 3009 | */ |
||
| 3010 | function transformUsingPairFile( $file, $string ) { |
||
| 3020 | |||
| 3021 | /** |
||
| 3022 | * For right-to-left language support |
||
| 3023 | * |
||
| 3024 | * @return bool |
||
| 3025 | */ |
||
| 3026 | function isRTL() { |
||
| 3029 | |||
| 3030 | /** |
||
| 3031 | * Return the correct HTML 'dir' attribute value for this language. |
||
| 3032 | * @return string |
||
| 3033 | */ |
||
| 3034 | function getDir() { |
||
| 3037 | |||
| 3038 | /** |
||
| 3039 | * Return 'left' or 'right' as appropriate alignment for line-start |
||
| 3040 | * for this language's text direction. |
||
| 3041 | * |
||
| 3042 | * Should be equivalent to CSS3 'start' text-align value.... |
||
| 3043 | * |
||
| 3044 | * @return string |
||
| 3045 | */ |
||
| 3046 | function alignStart() { |
||
| 3049 | |||
| 3050 | /** |
||
| 3051 | * Return 'right' or 'left' as appropriate alignment for line-end |
||
| 3052 | * for this language's text direction. |
||
| 3053 | * |
||
| 3054 | * Should be equivalent to CSS3 'end' text-align value.... |
||
| 3055 | * |
||
| 3056 | * @return string |
||
| 3057 | */ |
||
| 3058 | function alignEnd() { |
||
| 3061 | |||
| 3062 | /** |
||
| 3063 | * A hidden direction mark (LRM or RLM), depending on the language direction. |
||
| 3064 | * Unlike getDirMark(), this function returns the character as an HTML entity. |
||
| 3065 | * This function should be used when the output is guaranteed to be HTML, |
||
| 3066 | * because it makes the output HTML source code more readable. When |
||
| 3067 | * the output is plain text or can be escaped, getDirMark() should be used. |
||
| 3068 | * |
||
| 3069 | * @param bool $opposite Get the direction mark opposite to your language |
||
| 3070 | * @return string |
||
| 3071 | * @since 1.20 |
||
| 3072 | */ |
||
| 3073 | function getDirMarkEntity( $opposite = false ) { |
||
| 3079 | |||
| 3080 | /** |
||
| 3081 | * A hidden direction mark (LRM or RLM), depending on the language direction. |
||
| 3082 | * This function produces them as invisible Unicode characters and |
||
| 3083 | * the output may be hard to read and debug, so it should only be used |
||
| 3084 | * when the output is plain text or can be escaped. When the output is |
||
| 3085 | * HTML, use getDirMarkEntity() instead. |
||
| 3086 | * |
||
| 3087 | * @param bool $opposite Get the direction mark opposite to your language |
||
| 3088 | * @return string |
||
| 3089 | */ |
||
| 3090 | function getDirMark( $opposite = false ) { |
||
| 3098 | |||
| 3099 | /** |
||
| 3100 | * @return array |
||
| 3101 | */ |
||
| 3102 | function capitalizeAllNouns() { |
||
| 3105 | |||
| 3106 | /** |
||
| 3107 | * An arrow, depending on the language direction. |
||
| 3108 | * |
||
| 3109 | * @param string $direction The direction of the arrow: forwards (default), |
||
| 3110 | * backwards, left, right, up, down. |
||
| 3111 | * @return string |
||
| 3112 | */ |
||
| 3113 | function getArrow( $direction = 'forwards' ) { |
||
| 3129 | |||
| 3130 | /** |
||
| 3131 | * To allow "foo[[bar]]" to extend the link over the whole word "foobar" |
||
| 3132 | * |
||
| 3133 | * @return bool |
||
| 3134 | */ |
||
| 3135 | function linkPrefixExtension() { |
||
| 3138 | |||
| 3139 | /** |
||
| 3140 | * Get all magic words from cache. |
||
| 3141 | * @return array |
||
| 3142 | */ |
||
| 3143 | function getMagicWords() { |
||
| 3146 | |||
| 3147 | /** |
||
| 3148 | * Run the LanguageGetMagic hook once. |
||
| 3149 | */ |
||
| 3150 | protected function doMagicHook() { |
||
| 3157 | |||
| 3158 | /** |
||
| 3159 | * Fill a MagicWord object with data from here |
||
| 3160 | * |
||
| 3161 | * @param MagicWord $mw |
||
| 3162 | */ |
||
| 3163 | function getMagic( $mw ) { |
||
| 3183 | |||
| 3184 | /** |
||
| 3185 | * Add magic words to the extension array |
||
| 3186 | * |
||
| 3187 | * @param array $newWords |
||
| 3188 | */ |
||
| 3189 | function addMagicWordsByLang( $newWords ) { |
||
| 3198 | |||
| 3199 | /** |
||
| 3200 | * Get special page names, as an associative array |
||
| 3201 | * canonical name => array of valid names, including aliases |
||
| 3202 | * @return array |
||
| 3203 | */ |
||
| 3204 | function getSpecialPageAliases() { |
||
| 3216 | |||
| 3217 | /** |
||
| 3218 | * Italic is unsuitable for some languages |
||
| 3219 | * |
||
| 3220 | * @param string $text The text to be emphasized. |
||
| 3221 | * @return string |
||
| 3222 | */ |
||
| 3223 | function emphasize( $text ) { |
||
| 3226 | |||
| 3227 | /** |
||
| 3228 | * Normally we output all numbers in plain en_US style, that is |
||
| 3229 | * 293,291.235 for twohundredninetythreethousand-twohundredninetyone |
||
| 3230 | * point twohundredthirtyfive. However this is not suitable for all |
||
| 3231 | * languages, some such as Bengali (bn) want ২,৯৩,২৯১.২৩৫ and others such as |
||
| 3232 | * Icelandic just want to use commas instead of dots, and dots instead |
||
| 3233 | * of commas like "293.291,235". |
||
| 3234 | * |
||
| 3235 | * An example of this function being called: |
||
| 3236 | * <code> |
||
| 3237 | * wfMessage( 'message' )->numParams( $num )->text() |
||
| 3238 | * </code> |
||
| 3239 | * |
||
| 3240 | * See $separatorTransformTable on MessageIs.php for |
||
| 3241 | * the , => . and . => , implementation. |
||
| 3242 | * |
||
| 3243 | * @todo check if it's viable to use localeconv() for the decimal separator thing. |
||
| 3244 | * @param int|float $number The string to be formatted, should be an integer |
||
| 3245 | * or a floating point number. |
||
| 3246 | * @param bool $nocommafy Set to true for special numbers like dates |
||
| 3247 | * @return string |
||
| 3248 | */ |
||
| 3249 | public function formatNum( $number, $nocommafy = false ) { |
||
| 3268 | |||
| 3269 | /** |
||
| 3270 | * Front-end for non-commafied formatNum |
||
| 3271 | * |
||
| 3272 | * @param int|float $number The string to be formatted, should be an integer |
||
| 3273 | * or a floating point number. |
||
| 3274 | * @since 1.21 |
||
| 3275 | * @return string |
||
| 3276 | */ |
||
| 3277 | public function formatNumNoSeparators( $number ) { |
||
| 3280 | |||
| 3281 | /** |
||
| 3282 | * @param string $number |
||
| 3283 | * @return string |
||
| 3284 | */ |
||
| 3285 | public function parseFormattedNumber( $number ) { |
||
| 3303 | |||
| 3304 | /** |
||
| 3305 | * Adds commas to a given number |
||
| 3306 | * @since 1.19 |
||
| 3307 | * @param mixed $number |
||
| 3308 | * @return string |
||
| 3309 | */ |
||
| 3310 | function commafy( $number ) { |
||
| 3358 | |||
| 3359 | /** |
||
| 3360 | * @return string |
||
| 3361 | */ |
||
| 3362 | function digitGroupingPattern() { |
||
| 3365 | |||
| 3366 | /** |
||
| 3367 | * @return array |
||
| 3368 | */ |
||
| 3369 | function digitTransformTable() { |
||
| 3372 | |||
| 3373 | /** |
||
| 3374 | * @return array |
||
| 3375 | */ |
||
| 3376 | function separatorTransformTable() { |
||
| 3379 | |||
| 3380 | /** |
||
| 3381 | * Take a list of strings and build a locale-friendly comma-separated |
||
| 3382 | * list, using the local comma-separator message. |
||
| 3383 | * The last two strings are chained with an "and". |
||
| 3384 | * NOTE: This function will only work with standard numeric array keys (0, 1, 2…) |
||
| 3385 | * |
||
| 3386 | * @param string[] $l |
||
| 3387 | * @return string |
||
| 3388 | */ |
||
| 3389 | function listToText( array $l ) { |
||
| 3411 | |||
| 3412 | /** |
||
| 3413 | * Take a list of strings and build a locale-friendly comma-separated |
||
| 3414 | * list, using the local comma-separator message. |
||
| 3415 | * @param string[] $list Array of strings to put in a comma list |
||
| 3416 | * @return string |
||
| 3417 | */ |
||
| 3418 | function commaList( array $list ) { |
||
| 3424 | |||
| 3425 | /** |
||
| 3426 | * Take a list of strings and build a locale-friendly semicolon-separated |
||
| 3427 | * list, using the local semicolon-separator message. |
||
| 3428 | * @param string[] $list Array of strings to put in a semicolon list |
||
| 3429 | * @return string |
||
| 3430 | */ |
||
| 3431 | function semicolonList( array $list ) { |
||
| 3437 | |||
| 3438 | /** |
||
| 3439 | * Same as commaList, but separate it with the pipe instead. |
||
| 3440 | * @param string[] $list Array of strings to put in a pipe list |
||
| 3441 | * @return string |
||
| 3442 | */ |
||
| 3443 | function pipeList( array $list ) { |
||
| 3449 | |||
| 3450 | /** |
||
| 3451 | * Truncate a string to a specified length in bytes, appending an optional |
||
| 3452 | * string (e.g. for ellipses) |
||
| 3453 | * |
||
| 3454 | * The database offers limited byte lengths for some columns in the database; |
||
| 3455 | * multi-byte character sets mean we need to ensure that only whole characters |
||
| 3456 | * are included, otherwise broken characters can be passed to the user |
||
| 3457 | * |
||
| 3458 | * If $length is negative, the string will be truncated from the beginning |
||
| 3459 | * |
||
| 3460 | * @param string $string String to truncate |
||
| 3461 | * @param int $length Maximum length (including ellipses) |
||
| 3462 | * @param string $ellipsis String to append to the truncated text |
||
| 3463 | * @param bool $adjustLength Subtract length of ellipsis from $length. |
||
| 3464 | * $adjustLength was introduced in 1.18, before that behaved as if false. |
||
| 3465 | * @return string |
||
| 3466 | */ |
||
| 3467 | function truncate( $string, $length, $ellipsis = '...', $adjustLength = true ) { |
||
| 3508 | |||
| 3509 | /** |
||
| 3510 | * Remove bytes that represent an incomplete Unicode character |
||
| 3511 | * at the end of string (e.g. bytes of the char are missing) |
||
| 3512 | * |
||
| 3513 | * @param string $string |
||
| 3514 | * @return string |
||
| 3515 | */ |
||
| 3516 | protected function removeBadCharLast( $string ) { |
||
| 3534 | |||
| 3535 | /** |
||
| 3536 | * Remove bytes that represent an incomplete Unicode character |
||
| 3537 | * at the start of string (e.g. bytes of the char are missing) |
||
| 3538 | * |
||
| 3539 | * @param string $string |
||
| 3540 | * @return string |
||
| 3541 | */ |
||
| 3542 | protected function removeBadCharFirst( $string ) { |
||
| 3552 | |||
| 3553 | /** |
||
| 3554 | * Truncate a string of valid HTML to a specified length in bytes, |
||
| 3555 | * appending an optional string (e.g. for ellipses), and return valid HTML |
||
| 3556 | * |
||
| 3557 | * This is only intended for styled/linked text, such as HTML with |
||
| 3558 | * tags like <span> and <a>, were the tags are self-contained (valid HTML). |
||
| 3559 | * Also, this will not detect things like "display:none" CSS. |
||
| 3560 | * |
||
| 3561 | * Note: since 1.18 you do not need to leave extra room in $length for ellipses. |
||
| 3562 | * |
||
| 3563 | * @param string $text HTML string to truncate |
||
| 3564 | * @param int $length (zero/positive) Maximum length (including ellipses) |
||
| 3565 | * @param string $ellipsis String to append to the truncated text |
||
| 3566 | * @return string |
||
| 3567 | */ |
||
| 3568 | function truncateHtml( $text, $length, $ellipsis = '...' ) { |
||
| 3674 | |||
| 3675 | /** |
||
| 3676 | * truncateHtml() helper function |
||
| 3677 | * like strcspn() but adds the skipped chars to $ret |
||
| 3678 | * |
||
| 3679 | * @param string $ret |
||
| 3680 | * @param string $text |
||
| 3681 | * @param string $search |
||
| 3682 | * @param int $start |
||
| 3683 | * @param null|int $len |
||
| 3684 | * @return int |
||
| 3685 | */ |
||
| 3686 | private function truncate_skip( &$ret, $text, $search, $start, $len = null ) { |
||
| 3699 | |||
| 3700 | /** |
||
| 3701 | * truncateHtml() helper function |
||
| 3702 | * (a) push or pop $tag from $openTags as needed |
||
| 3703 | * (b) clear $tag value |
||
| 3704 | * @param string &$tag Current HTML tag name we are looking at |
||
| 3705 | * @param int $tagType (0-open tag, 1-close tag) |
||
| 3706 | * @param string $lastCh Character before the '>' that ended this tag |
||
| 3707 | * @param array &$openTags Open tag stack (not accounting for $tag) |
||
| 3708 | */ |
||
| 3709 | private function truncate_endBracket( &$tag, $tagType, $lastCh, &$openTags ) { |
||
| 3722 | |||
| 3723 | /** |
||
| 3724 | * Grammatical transformations, needed for inflected languages |
||
| 3725 | * Invoked by putting {{grammar:case|word}} in a message |
||
| 3726 | * |
||
| 3727 | * @param string $word |
||
| 3728 | * @param string $case |
||
| 3729 | * @return string |
||
| 3730 | */ |
||
| 3731 | function convertGrammar( $word, $case ) { |
||
| 3739 | /** |
||
| 3740 | * Get the grammar forms for the content language |
||
| 3741 | * @return array Array of grammar forms |
||
| 3742 | * @since 1.20 |
||
| 3743 | */ |
||
| 3744 | function getGrammarForms() { |
||
| 3754 | /** |
||
| 3755 | * Provides an alternative text depending on specified gender. |
||
| 3756 | * Usage {{gender:username|masculine|feminine|unknown}}. |
||
| 3757 | * username is optional, in which case the gender of current user is used, |
||
| 3758 | * but only in (some) interface messages; otherwise default gender is used. |
||
| 3759 | * |
||
| 3760 | * If no forms are given, an empty string is returned. If only one form is |
||
| 3761 | * given, it will be returned unconditionally. These details are implied by |
||
| 3762 | * the caller and cannot be overridden in subclasses. |
||
| 3763 | * |
||
| 3764 | * If three forms are given, the default is to use the third (unknown) form. |
||
| 3765 | * If fewer than three forms are given, the default is to use the first (masculine) form. |
||
| 3766 | * These details can be overridden in subclasses. |
||
| 3767 | * |
||
| 3768 | * @param string $gender |
||
| 3769 | * @param array $forms |
||
| 3770 | * |
||
| 3771 | * @return string |
||
| 3772 | */ |
||
| 3773 | function gender( $gender, $forms ) { |
||
| 3786 | |||
| 3787 | /** |
||
| 3788 | * Plural form transformations, needed for some languages. |
||
| 3789 | * For example, there are 3 form of plural in Russian and Polish, |
||
| 3790 | * depending on "count mod 10". See [[w:Plural]] |
||
| 3791 | * For English it is pretty simple. |
||
| 3792 | * |
||
| 3793 | * Invoked by putting {{plural:count|wordform1|wordform2}} |
||
| 3794 | * or {{plural:count|wordform1|wordform2|wordform3}} |
||
| 3795 | * |
||
| 3796 | * Example: {{plural:{{NUMBEROFARTICLES}}|article|articles}} |
||
| 3797 | * |
||
| 3798 | * @param int $count Non-localized number |
||
| 3799 | * @param array $forms Different plural forms |
||
| 3800 | * @return string Correct form of plural for $count in this language |
||
| 3801 | */ |
||
| 3802 | function convertPlural( $count, $forms ) { |
||
| 3816 | |||
| 3817 | /** |
||
| 3818 | * Handles explicit plural forms for Language::convertPlural() |
||
| 3819 | * |
||
| 3820 | * In {{PLURAL:$1|0=nothing|one|many}}, 0=nothing will be returned if $1 equals zero. |
||
| 3821 | * If an explicitly defined plural form matches the $count, then |
||
| 3822 | * string value returned, otherwise array returned for further consideration |
||
| 3823 | * by CLDR rules or overridden convertPlural(). |
||
| 3824 | * |
||
| 3825 | * @since 1.23 |
||
| 3826 | * |
||
| 3827 | * @param int $count Non-localized number |
||
| 3828 | * @param array $forms Different plural forms |
||
| 3829 | * |
||
| 3830 | * @return array|string |
||
| 3831 | */ |
||
| 3832 | protected function handleExplicitPluralForms( $count, array $forms ) { |
||
| 3844 | |||
| 3845 | /** |
||
| 3846 | * Checks that convertPlural was given an array and pads it to requested |
||
| 3847 | * amount of forms by copying the last one. |
||
| 3848 | * |
||
| 3849 | * @param array $forms Array of forms given to convertPlural |
||
| 3850 | * @param int $count How many forms should there be at least |
||
| 3851 | * @return array Padded array of forms or an exception if not an array |
||
| 3852 | */ |
||
| 3853 | protected function preConvertPlural( /* Array */ $forms, $count ) { |
||
| 3859 | |||
| 3860 | /** |
||
| 3861 | * Wraps argument with unicode control characters for directionality safety |
||
| 3862 | * |
||
| 3863 | * This solves the problem where directionality-neutral characters at the edge of |
||
| 3864 | * the argument string get interpreted with the wrong directionality from the |
||
| 3865 | * enclosing context, giving renderings that look corrupted like "(Ben_(WMF". |
||
| 3866 | * |
||
| 3867 | * The wrapping is LRE...PDF or RLE...PDF, depending on the detected |
||
| 3868 | * directionality of the argument string, using the BIDI algorithm's own "First |
||
| 3869 | * strong directional codepoint" rule. Essentially, this works round the fact that |
||
| 3870 | * there is no embedding equivalent of U+2068 FSI (isolation with heuristic |
||
| 3871 | * direction inference). The latter is cleaner but still not widely supported. |
||
| 3872 | * |
||
| 3873 | * @param string $text Text to wrap |
||
| 3874 | * @return string Text, wrapped in LRE...PDF or RLE...PDF or nothing |
||
| 3875 | */ |
||
| 3876 | public function embedBidi( $text = '' ) { |
||
| 3889 | |||
| 3890 | /** |
||
| 3891 | * @todo Maybe translate block durations. Note that this function is somewhat misnamed: it |
||
| 3892 | * deals with translating the *duration* ("1 week", "4 days", etc), not the expiry time |
||
| 3893 | * (which is an absolute timestamp). Please note: do NOT add this blindly, as it is used |
||
| 3894 | * on old expiry lengths recorded in log entries. You'd need to provide the start date to |
||
| 3895 | * match up with it. |
||
| 3896 | * |
||
| 3897 | * @param string $str The validated block duration in English |
||
| 3898 | * @param User $user User object to use timezone from or null for $wgUser |
||
| 3899 | * @return string Somehow translated block duration |
||
| 3900 | * @see LanguageFi.php for example implementation |
||
| 3901 | */ |
||
| 3902 | function translateBlockExpiry( $str, User $user = null ) { |
||
| 3903 | $duration = SpecialBlock::getSuggestedDurations( $this ); |
||
| 3904 | foreach ( $duration as $show => $value ) { |
||
| 3905 | if ( strcmp( $str, $value ) == 0 ) { |
||
| 3906 | return htmlspecialchars( trim( $show ) ); |
||
| 3907 | } |
||
| 3908 | } |
||
| 3909 | |||
| 3910 | if ( wfIsInfinity( $str ) ) { |
||
| 3911 | foreach ( $duration as $show => $value ) { |
||
| 3912 | if ( wfIsInfinity( $value ) ) { |
||
| 3913 | return htmlspecialchars( trim( $show ) ); |
||
| 3914 | } |
||
| 3915 | } |
||
| 3916 | } |
||
| 3917 | |||
| 3918 | // If all else fails, return a standard duration or timestamp description. |
||
| 3919 | $time = strtotime( $str, 0 ); |
||
| 3920 | if ( $time === false ) { // Unknown format. Return it as-is in case. |
||
| 3921 | return $str; |
||
| 3922 | } elseif ( $time !== strtotime( $str, 1 ) ) { // It's a relative timestamp. |
||
| 3923 | // $time is relative to 0 so it's a duration length. |
||
| 3924 | return $this->formatDuration( $time ); |
||
| 3925 | } else { // It's an absolute timestamp. |
||
| 3926 | if ( $time === 0 ) { |
||
| 3927 | // wfTimestamp() handles 0 as current time instead of epoch. |
||
| 3928 | $time = '19700101000000'; |
||
| 3929 | } |
||
| 3930 | if ( $user ) { |
||
| 3931 | return $this->userTimeAndDate( $time, $user ); |
||
| 3932 | } |
||
| 3933 | return $this->timeanddate( $time ); |
||
| 3934 | } |
||
| 3935 | } |
||
| 3936 | |||
| 3937 | /** |
||
| 3938 | * languages like Chinese need to be segmented in order for the diff |
||
| 3939 | * to be of any use |
||
| 3940 | * |
||
| 3941 | * @param string $text |
||
| 3942 | * @return string |
||
| 3943 | */ |
||
| 3944 | public function segmentForDiff( $text ) { |
||
| 3947 | |||
| 3948 | /** |
||
| 3949 | * and unsegment to show the result |
||
| 3950 | * |
||
| 3951 | * @param string $text |
||
| 3952 | * @return string |
||
| 3953 | */ |
||
| 3954 | public function unsegmentForDiff( $text ) { |
||
| 3957 | |||
| 3958 | /** |
||
| 3959 | * Return the LanguageConverter used in the Language |
||
| 3960 | * |
||
| 3961 | * @since 1.19 |
||
| 3962 | * @return LanguageConverter |
||
| 3963 | */ |
||
| 3964 | public function getConverter() { |
||
| 3967 | |||
| 3968 | /** |
||
| 3969 | * convert text to all supported variants |
||
| 3970 | * |
||
| 3971 | * @param string $text |
||
| 3972 | * @return array |
||
| 3973 | */ |
||
| 3974 | public function autoConvertToAllVariants( $text ) { |
||
| 3977 | |||
| 3978 | /** |
||
| 3979 | * convert text to different variants of a language. |
||
| 3980 | * |
||
| 3981 | * @param string $text |
||
| 3982 | * @return string |
||
| 3983 | */ |
||
| 3984 | public function convert( $text ) { |
||
| 3987 | |||
| 3988 | /** |
||
| 3989 | * Convert a Title object to a string in the preferred variant |
||
| 3990 | * |
||
| 3991 | * @param Title $title |
||
| 3992 | * @return string |
||
| 3993 | */ |
||
| 3994 | public function convertTitle( $title ) { |
||
| 3997 | |||
| 3998 | /** |
||
| 3999 | * Convert a namespace index to a string in the preferred variant |
||
| 4000 | * |
||
| 4001 | * @param int $ns |
||
| 4002 | * @return string |
||
| 4003 | */ |
||
| 4004 | public function convertNamespace( $ns ) { |
||
| 4007 | |||
| 4008 | /** |
||
| 4009 | * Check if this is a language with variants |
||
| 4010 | * |
||
| 4011 | * @return bool |
||
| 4012 | */ |
||
| 4013 | public function hasVariants() { |
||
| 4016 | |||
| 4017 | /** |
||
| 4018 | * Check if the language has the specific variant |
||
| 4019 | * |
||
| 4020 | * @since 1.19 |
||
| 4021 | * @param string $variant |
||
| 4022 | * @return bool |
||
| 4023 | */ |
||
| 4024 | public function hasVariant( $variant ) { |
||
| 4027 | |||
| 4028 | /** |
||
| 4029 | * Perform output conversion on a string, and encode for safe HTML output. |
||
| 4030 | * @param string $text Text to be converted |
||
| 4031 | * @param bool $isTitle Whether this conversion is for the article title |
||
| 4032 | * @return string |
||
| 4033 | * @todo this should get integrated somewhere sane |
||
| 4034 | */ |
||
| 4035 | public function convertHtml( $text, $isTitle = false ) { |
||
| 4038 | |||
| 4039 | /** |
||
| 4040 | * @param string $key |
||
| 4041 | * @return string |
||
| 4042 | */ |
||
| 4043 | public function convertCategoryKey( $key ) { |
||
| 4046 | |||
| 4047 | /** |
||
| 4048 | * Get the list of variants supported by this language |
||
| 4049 | * see sample implementation in LanguageZh.php |
||
| 4050 | * |
||
| 4051 | * @return array An array of language codes |
||
| 4052 | */ |
||
| 4053 | public function getVariants() { |
||
| 4056 | |||
| 4057 | /** |
||
| 4058 | * @return string |
||
| 4059 | */ |
||
| 4060 | public function getPreferredVariant() { |
||
| 4063 | |||
| 4064 | /** |
||
| 4065 | * @return string |
||
| 4066 | */ |
||
| 4067 | public function getDefaultVariant() { |
||
| 4070 | |||
| 4071 | /** |
||
| 4072 | * @return string |
||
| 4073 | */ |
||
| 4074 | public function getURLVariant() { |
||
| 4077 | |||
| 4078 | /** |
||
| 4079 | * If a language supports multiple variants, it is |
||
| 4080 | * possible that non-existing link in one variant |
||
| 4081 | * actually exists in another variant. this function |
||
| 4082 | * tries to find it. See e.g. LanguageZh.php |
||
| 4083 | * The input parameters may be modified upon return |
||
| 4084 | * |
||
| 4085 | * @param string &$link The name of the link |
||
| 4086 | * @param Title &$nt The title object of the link |
||
| 4087 | * @param bool $ignoreOtherCond To disable other conditions when |
||
| 4088 | * we need to transclude a template or update a category's link |
||
| 4089 | */ |
||
| 4090 | public function findVariantLink( &$link, &$nt, $ignoreOtherCond = false ) { |
||
| 4093 | |||
| 4094 | /** |
||
| 4095 | * returns language specific options used by User::getPageRenderHash() |
||
| 4096 | * for example, the preferred language variant |
||
| 4097 | * |
||
| 4098 | * @return string |
||
| 4099 | */ |
||
| 4100 | function getExtraHashOptions() { |
||
| 4103 | |||
| 4104 | /** |
||
| 4105 | * For languages that support multiple variants, the title of an |
||
| 4106 | * article may be displayed differently in different variants. this |
||
| 4107 | * function returns the apporiate title defined in the body of the article. |
||
| 4108 | * |
||
| 4109 | * @return string |
||
| 4110 | */ |
||
| 4111 | public function getParsedTitle() { |
||
| 4114 | |||
| 4115 | /** |
||
| 4116 | * Refresh the cache of conversion tables when |
||
| 4117 | * MediaWiki:Conversiontable* is updated. |
||
| 4118 | * |
||
| 4119 | * @param Title $title The Title of the page being updated |
||
| 4120 | */ |
||
| 4121 | public function updateConversionTable( Title $title ) { |
||
| 4124 | |||
| 4125 | /** |
||
| 4126 | * Prepare external link text for conversion. When the text is |
||
| 4127 | * a URL, it shouldn't be converted, and it'll be wrapped in |
||
| 4128 | * the "raw" tag (-{R| }-) to prevent conversion. |
||
| 4129 | * |
||
| 4130 | * This function is called "markNoConversion" for historical |
||
| 4131 | * reasons. |
||
| 4132 | * |
||
| 4133 | * @param string $text Text to be used for external link |
||
| 4134 | * @param bool $noParse Wrap it without confirming it's a real URL first |
||
| 4135 | * @return string The tagged text |
||
| 4136 | */ |
||
| 4137 | public function markNoConversion( $text, $noParse = false ) { |
||
| 4145 | |||
| 4146 | /** |
||
| 4147 | * A regular expression to match legal word-trailing characters |
||
| 4148 | * which should be merged onto a link of the form [[foo]]bar. |
||
| 4149 | * |
||
| 4150 | * @return string |
||
| 4151 | */ |
||
| 4152 | public function linkTrail() { |
||
| 4155 | |||
| 4156 | /** |
||
| 4157 | * A regular expression character set to match legal word-prefixing |
||
| 4158 | * characters which should be merged onto a link of the form foo[[bar]]. |
||
| 4159 | * |
||
| 4160 | * @return string |
||
| 4161 | */ |
||
| 4162 | public function linkPrefixCharset() { |
||
| 4165 | |||
| 4166 | /** |
||
| 4167 | * Get the "parent" language which has a converter to convert a "compatible" language |
||
| 4168 | * (in another variant) to this language (eg. zh for zh-cn, but not en for en-gb). |
||
| 4169 | * |
||
| 4170 | * @return Language|null |
||
| 4171 | * @since 1.22 |
||
| 4172 | */ |
||
| 4173 | public function getParentLanguage() { |
||
| 4192 | |||
| 4193 | /** |
||
| 4194 | * Compare with an other language object |
||
| 4195 | * |
||
| 4196 | * @since 1.28 |
||
| 4197 | * @param Language $lang |
||
| 4198 | * @return boolean |
||
| 4199 | */ |
||
| 4200 | public function equals( Language $lang ) { |
||
| 4201 | return $lang->getCode() === $this->mCode; |
||
| 4202 | } |
||
| 4203 | |||
| 4204 | /** |
||
| 4205 | * Get the internal language code for this language object |
||
| 4206 | * |
||
| 4207 | * NOTE: The return value of this function is NOT HTML-safe and must be escaped with |
||
| 4208 | * htmlspecialchars() or similar |
||
| 4209 | * |
||
| 4210 | * @return string |
||
| 4211 | */ |
||
| 4212 | public function getCode() { |
||
| 4215 | |||
| 4216 | /** |
||
| 4217 | * Get the code in BCP 47 format which we can use |
||
| 4218 | * inside of html lang="" tags. |
||
| 4219 | * |
||
| 4220 | * NOTE: The return value of this function is NOT HTML-safe and must be escaped with |
||
| 4221 | * htmlspecialchars() or similar. |
||
| 4222 | * |
||
| 4223 | * @since 1.19 |
||
| 4224 | * @return string |
||
| 4225 | */ |
||
| 4226 | public function getHtmlCode() { |
||
| 4232 | |||
| 4233 | /** |
||
| 4234 | * @param string $code |
||
| 4235 | */ |
||
| 4236 | public function setCode( $code ) { |
||
| 4242 | |||
| 4243 | /** |
||
| 4244 | * Get the language code from a file name. Inverse of getFileName() |
||
| 4245 | * @param string $filename $prefix . $languageCode . $suffix |
||
| 4246 | * @param string $prefix Prefix before the language code |
||
| 4247 | * @param string $suffix Suffix after the language code |
||
| 4248 | * @return string Language code, or false if $prefix or $suffix isn't found |
||
| 4249 | */ |
||
| 4250 | public static function getCodeFromFileName( $filename, $prefix = 'Language', $suffix = '.php' ) { |
||
| 4259 | |||
| 4260 | /** |
||
| 4261 | * @param string $code |
||
| 4262 | * @return string Name of the language class |
||
| 4263 | */ |
||
| 4264 | public static function classFromCode( $code ) { |
||
| 4271 | |||
| 4272 | /** |
||
| 4273 | * Get the name of a file for a certain language code |
||
| 4274 | * @param string $prefix Prepend this to the filename |
||
| 4275 | * @param string $code Language code |
||
| 4276 | * @param string $suffix Append this to the filename |
||
| 4277 | * @throws MWException |
||
| 4278 | * @return string $prefix . $mangledCode . $suffix |
||
| 4279 | */ |
||
| 4280 | public static function getFileName( $prefix = 'Language', $code, $suffix = '.php' ) { |
||
| 4287 | |||
| 4288 | /** |
||
| 4289 | * @param string $code |
||
| 4290 | * @return string |
||
| 4291 | */ |
||
| 4292 | public static function getMessagesFileName( $code ) { |
||
| 4298 | |||
| 4299 | /** |
||
| 4300 | * @param string $code |
||
| 4301 | * @return string |
||
| 4302 | * @throws MWException |
||
| 4303 | * @since 1.23 |
||
| 4304 | */ |
||
| 4305 | public static function getJsonMessagesFileName( $code ) { |
||
| 4314 | |||
| 4315 | /** |
||
| 4316 | * Get the first fallback for a given language. |
||
| 4317 | * |
||
| 4318 | * @param string $code |
||
| 4319 | * |
||
| 4320 | * @return bool|string |
||
| 4321 | */ |
||
| 4322 | public static function getFallbackFor( $code ) { |
||
| 4329 | |||
| 4330 | /** |
||
| 4331 | * Get the ordered list of fallback languages. |
||
| 4332 | * |
||
| 4333 | * @since 1.19 |
||
| 4334 | * @param string $code Language code |
||
| 4335 | * @return array Non-empty array, ending in "en" |
||
| 4336 | */ |
||
| 4337 | public static function getFallbacksFor( $code ) { |
||
| 4345 | |||
| 4346 | /** |
||
| 4347 | * Get the ordered list of fallback languages, ending with the fallback |
||
| 4348 | * language chain for the site language. |
||
| 4349 | * |
||
| 4350 | * @since 1.22 |
||
| 4351 | * @param string $code Language code |
||
| 4352 | * @return array Array( fallbacks, site fallbacks ) |
||
| 4353 | */ |
||
| 4354 | public static function getFallbacksIncludingSiteLanguage( $code ) { |
||
| 4375 | |||
| 4376 | /** |
||
| 4377 | * Get all messages for a given language |
||
| 4378 | * WARNING: this may take a long time. If you just need all message *keys* |
||
| 4379 | * but need the *contents* of only a few messages, consider using getMessageKeysFor(). |
||
| 4380 | * |
||
| 4381 | * @param string $code |
||
| 4382 | * |
||
| 4383 | * @return array |
||
| 4384 | */ |
||
| 4385 | public static function getMessagesFor( $code ) { |
||
| 4388 | |||
| 4389 | /** |
||
| 4390 | * Get a message for a given language |
||
| 4391 | * |
||
| 4392 | * @param string $key |
||
| 4393 | * @param string $code |
||
| 4394 | * |
||
| 4395 | * @return string |
||
| 4396 | */ |
||
| 4397 | public static function getMessageFor( $key, $code ) { |
||
| 4400 | |||
| 4401 | /** |
||
| 4402 | * Get all message keys for a given language. This is a faster alternative to |
||
| 4403 | * array_keys( Language::getMessagesFor( $code ) ) |
||
| 4404 | * |
||
| 4405 | * @since 1.19 |
||
| 4406 | * @param string $code Language code |
||
| 4407 | * @return array Array of message keys (strings) |
||
| 4408 | */ |
||
| 4409 | public static function getMessageKeysFor( $code ) { |
||
| 4412 | |||
| 4413 | /** |
||
| 4414 | * @param string $talk |
||
| 4415 | * @return mixed |
||
| 4416 | */ |
||
| 4417 | function fixVariableInNamespace( $talk ) { |
||
| 4433 | |||
| 4434 | /** |
||
| 4435 | * @param string $m |
||
| 4436 | * @return string |
||
| 4437 | */ |
||
| 4438 | function replaceGrammarInNamespace( $m ) { |
||
| 4441 | |||
| 4442 | /** |
||
| 4443 | * Decode an expiry (block, protection, etc) which has come from the DB |
||
| 4444 | * |
||
| 4445 | * @param string $expiry Database expiry String |
||
| 4446 | * @param bool|int $format True to process using language functions, or TS_ constant |
||
| 4447 | * to return the expiry in a given timestamp |
||
| 4448 | * @param string $infinity If $format is not true, use this string for infinite expiry |
||
| 4449 | * @return string |
||
| 4450 | * @since 1.18 |
||
| 4451 | */ |
||
| 4452 | public function formatExpiry( $expiry, $format = true, $infinity = 'infinity' ) { |
||
| 4468 | |||
| 4469 | /** |
||
| 4470 | * @todo Document |
||
| 4471 | * @param int|float $seconds |
||
| 4472 | * @param array $format Optional |
||
| 4473 | * If $format['avoid'] === 'avoidseconds': don't mention seconds if $seconds >= 1 hour. |
||
| 4474 | * If $format['avoid'] === 'avoidminutes': don't mention seconds/minutes if $seconds > 48 hours. |
||
| 4475 | * If $format['noabbrevs'] is true: use 'seconds' and friends instead of 'seconds-abbrev' |
||
| 4476 | * and friends. |
||
| 4477 | * For backwards compatibility, $format may also be one of the strings 'avoidseconds' |
||
| 4478 | * or 'avoidminutes'. |
||
| 4479 | * @return string |
||
| 4480 | */ |
||
| 4481 | function formatTimePeriod( $seconds, $format = [] ) { |
||
| 4569 | |||
| 4570 | /** |
||
| 4571 | * Format a bitrate for output, using an appropriate |
||
| 4572 | * unit (bps, kbps, Mbps, Gbps, Tbps, Pbps, Ebps, Zbps or Ybps) according to |
||
| 4573 | * the magnitude in question. |
||
| 4574 | * |
||
| 4575 | * This use base 1000. For base 1024 use formatSize(), for another base |
||
| 4576 | * see formatComputingNumbers(). |
||
| 4577 | * |
||
| 4578 | * @param int $bps |
||
| 4579 | * @return string |
||
| 4580 | */ |
||
| 4581 | function formatBitrate( $bps ) { |
||
| 4584 | |||
| 4585 | /** |
||
| 4586 | * @param int $size Size of the unit |
||
| 4587 | * @param int $boundary Size boundary (1000, or 1024 in most cases) |
||
| 4588 | * @param string $messageKey Message key to be uesd |
||
| 4589 | * @return string |
||
| 4590 | */ |
||
| 4591 | function formatComputingNumbers( $size, $boundary, $messageKey ) { |
||
| 4618 | |||
| 4619 | /** |
||
| 4620 | * Format a size in bytes for output, using an appropriate |
||
| 4621 | * unit (B, KB, MB, GB, TB, PB, EB, ZB or YB) according to the magnitude in question |
||
| 4622 | * |
||
| 4623 | * This method use base 1024. For base 1000 use formatBitrate(), for |
||
| 4624 | * another base see formatComputingNumbers() |
||
| 4625 | * |
||
| 4626 | * @param int $size Size to format |
||
| 4627 | * @return string Plain text (not HTML) |
||
| 4628 | */ |
||
| 4629 | function formatSize( $size ) { |
||
| 4632 | |||
| 4633 | /** |
||
| 4634 | * Make a list item, used by various special pages |
||
| 4635 | * |
||
| 4636 | * @param string $page Page link |
||
| 4637 | * @param string $details HTML safe text between brackets |
||
| 4638 | * @param bool $oppositedm Add the direction mark opposite to your |
||
| 4639 | * language, to display text properly |
||
| 4640 | * @return HTML escaped string |
||
| 4641 | */ |
||
| 4642 | function specialList( $page, $details, $oppositedm = true ) { |
||
| 4654 | |||
| 4655 | /** |
||
| 4656 | * Generate (prev x| next x) (20|50|100...) type links for paging |
||
| 4657 | * |
||
| 4658 | * @param Title $title Title object to link |
||
| 4659 | * @param int $offset |
||
| 4660 | * @param int $limit |
||
| 4661 | * @param array $query Optional URL query parameter string |
||
| 4662 | * @param bool $atend Optional param for specified if this is the last page |
||
| 4663 | * @return string |
||
| 4664 | */ |
||
| 4665 | public function viewPrevNext( Title $title, $offset, $limit, |
||
| 4698 | |||
| 4699 | /** |
||
| 4700 | * Helper function for viewPrevNext() that generates links |
||
| 4701 | * |
||
| 4702 | * @param Title $title Title object to link |
||
| 4703 | * @param int $offset |
||
| 4704 | * @param int $limit |
||
| 4705 | * @param array $query Extra query parameters |
||
| 4706 | * @param string $link Text to use for the link; will be escaped |
||
| 4707 | * @param string $tooltipMsg Name of the message to use as tooltip |
||
| 4708 | * @param string $class Value of the "class" attribute of the link |
||
| 4709 | * @return string HTML fragment |
||
| 4710 | */ |
||
| 4711 | private function numLink( Title $title, $offset, $limit, array $query, $link, |
||
| 4721 | |||
| 4722 | /** |
||
| 4723 | * Get the conversion rule title, if any. |
||
| 4724 | * |
||
| 4725 | * @return string |
||
| 4726 | */ |
||
| 4727 | public function getConvRuleTitle() { |
||
| 4730 | |||
| 4731 | /** |
||
| 4732 | * Get the compiled plural rules for the language |
||
| 4733 | * @since 1.20 |
||
| 4734 | * @return array Associative array with plural form, and plural rule as key-value pairs |
||
| 4735 | */ |
||
| 4736 | View Code Duplication | public function getCompiledPluralRules() { |
|
| 4749 | |||
| 4750 | /** |
||
| 4751 | * Get the plural rules for the language |
||
| 4752 | * @since 1.20 |
||
| 4753 | * @return array Associative array with plural form number and plural rule as key-value pairs |
||
| 4754 | */ |
||
| 4755 | View Code Duplication | public function getPluralRules() { |
|
| 4768 | |||
| 4769 | /** |
||
| 4770 | * Get the plural rule types for the language |
||
| 4771 | * @since 1.22 |
||
| 4772 | * @return array Associative array with plural form number and plural rule type as key-value pairs |
||
| 4773 | */ |
||
| 4774 | View Code Duplication | public function getPluralRuleTypes() { |
|
| 4787 | |||
| 4788 | /** |
||
| 4789 | * Find the index number of the plural rule appropriate for the given number |
||
| 4790 | * @param int $number |
||
| 4791 | * @return int The index number of the plural rule |
||
| 4792 | */ |
||
| 4793 | public function getPluralRuleIndexNumber( $number ) { |
||
| 4798 | |||
| 4799 | /** |
||
| 4800 | * Find the plural rule type appropriate for the given number |
||
| 4801 | * For example, if the language is set to Arabic, getPluralType(5) should |
||
| 4802 | * return 'few'. |
||
| 4803 | * @since 1.22 |
||
| 4804 | * @param int $number |
||
| 4805 | * @return string The name of the plural rule type, e.g. one, two, few, many |
||
| 4806 | */ |
||
| 4807 | public function getPluralRuleType( $number ) { |
||
| 4816 | } |
||
| 4817 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.