2004-04-04 11:26:29 +00:00
|
|
|
|
<?php
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
/**
|
2012-06-05 20:13:22 +00:00
|
|
|
|
* Internationalisation code.
|
2016-08-11 00:53:30 +00:00
|
|
|
|
* See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more information.
|
2012-06-05 20:13:22 +00:00
|
|
|
|
*
|
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
|
*
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
*
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @file
|
|
|
|
|
|
* @ingroup Language
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
2010-08-20 20:39:04 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @defgroup Language Language
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2015-09-24 07:15:49 +00:00
|
|
|
|
use CLDRPluralRuleParser\Evaluator;
|
2019-03-12 08:53:49 +00:00
|
|
|
|
use Wikimedia\Assert\Assert;
|
2015-09-24 07:15:49 +00:00
|
|
|
|
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Internationalisation code
|
2008-05-21 18:18:58 +00:00
|
|
|
|
* @ingroup Language
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
|
*/
|
2003-04-14 23:10:40 +00:00
|
|
|
|
class Language {
|
2018-06-18 18:30:10 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return autonyms in fetchLanguageName(s).
|
|
|
|
|
|
* @since 1.32
|
|
|
|
|
|
*/
|
|
|
|
|
|
const AS_AUTONYMS = null;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Return all known languages in fetchLanguageName(s).
|
|
|
|
|
|
* @since 1.32
|
|
|
|
|
|
*/
|
|
|
|
|
|
const ALL = 'all';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Return in fetchLanguageName(s) only the languages for which we have at
|
|
|
|
|
|
* least some localisation.
|
|
|
|
|
|
* @since 1.32
|
|
|
|
|
|
*/
|
|
|
|
|
|
const SUPPORTED = 'mwfile';
|
|
|
|
|
|
|
2011-09-18 18:21:19 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @var LanguageConverter
|
|
|
|
|
|
*/
|
2012-09-14 18:57:14 +00:00
|
|
|
|
public $mConverter;
|
2011-09-18 18:21:19 +00:00
|
|
|
|
|
2012-09-14 18:57:14 +00:00
|
|
|
|
public $mVariants, $mCode, $mLoaded = false;
|
2018-06-11 23:50:41 +00:00
|
|
|
|
public $mMagicExtensions = [];
|
2013-06-07 08:50:10 +00:00
|
|
|
|
private $mHtmlCode = null, $mParentLanguage = false;
|
2006-07-26 07:15:39 +00:00
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
public $dateFormatStrings = [];
|
2012-09-14 18:57:14 +00:00
|
|
|
|
public $mExtendedSpecialPageAliases;
|
2006-07-26 07:15:39 +00:00
|
|
|
|
|
2016-12-13 19:51:07 +00:00
|
|
|
|
/** @var array|null */
|
|
|
|
|
|
protected $namespaceNames;
|
|
|
|
|
|
protected $mNamespaceIds, $namespaceAliases;
|
2012-01-21 22:26:14 +00:00
|
|
|
|
|
2010-01-04 08:28:50 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* ReplacementArray object caches
|
|
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
|
public $transformData = [];
|
2010-01-04 08:28:50 +00:00
|
|
|
|
|
2011-04-23 15:19:38 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @var LocalisationCache
|
|
|
|
|
|
*/
|
2019-02-07 09:21:19 +00:00
|
|
|
|
public static $dataCache;
|
2011-04-23 15:19:38 +00:00
|
|
|
|
|
2019-02-07 09:21:19 +00:00
|
|
|
|
public static $mLangObjCache = [];
|
2006-07-26 07:15:39 +00:00
|
|
|
|
|
2018-04-03 21:08:52 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return a fallback chain for messages in getFallbacksFor
|
|
|
|
|
|
* @since 1.32
|
|
|
|
|
|
*/
|
|
|
|
|
|
const MESSAGES_FALLBACKS = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Return a strict fallback chain in getFallbacksFor
|
|
|
|
|
|
* @since 1.32
|
|
|
|
|
|
*/
|
|
|
|
|
|
const STRICT_FALLBACKS = 1;
|
|
|
|
|
|
|
2019-02-07 09:21:19 +00:00
|
|
|
|
public static $mWeekdayMsgs = [
|
2006-07-26 07:15:39 +00:00
|
|
|
|
'sunday', 'monday', 'tuesday', 'wednesday', 'thursday',
|
|
|
|
|
|
'friday', 'saturday'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2006-07-26 07:15:39 +00:00
|
|
|
|
|
2019-02-07 09:21:19 +00:00
|
|
|
|
public static $mWeekdayAbbrevMsgs = [
|
2006-07-26 07:15:39 +00:00
|
|
|
|
'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2006-07-26 07:15:39 +00:00
|
|
|
|
|
2019-02-07 09:21:19 +00:00
|
|
|
|
public static $mMonthMsgs = [
|
2006-07-26 07:15:39 +00:00
|
|
|
|
'january', 'february', 'march', 'april', 'may_long', 'june',
|
|
|
|
|
|
'july', 'august', 'september', 'october', 'november',
|
|
|
|
|
|
'december'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2019-02-07 09:21:19 +00:00
|
|
|
|
public static $mMonthGenMsgs = [
|
2006-07-26 07:15:39 +00:00
|
|
|
|
'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen',
|
|
|
|
|
|
'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen',
|
|
|
|
|
|
'december-gen'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2019-02-07 09:21:19 +00:00
|
|
|
|
public static $mMonthAbbrevMsgs = [
|
2006-07-26 07:15:39 +00:00
|
|
|
|
'jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug',
|
|
|
|
|
|
'sep', 'oct', 'nov', 'dec'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2006-07-26 07:15:39 +00:00
|
|
|
|
|
2019-02-07 09:21:19 +00:00
|
|
|
|
public static $mIranianCalendarMonthMsgs = [
|
2007-11-13 04:05:13 +00:00
|
|
|
|
'iranian-calendar-m1', 'iranian-calendar-m2', 'iranian-calendar-m3',
|
|
|
|
|
|
'iranian-calendar-m4', 'iranian-calendar-m5', 'iranian-calendar-m6',
|
|
|
|
|
|
'iranian-calendar-m7', 'iranian-calendar-m8', 'iranian-calendar-m9',
|
|
|
|
|
|
'iranian-calendar-m10', 'iranian-calendar-m11', 'iranian-calendar-m12'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2007-11-13 04:05:13 +00:00
|
|
|
|
|
2019-02-07 09:21:19 +00:00
|
|
|
|
public static $mHebrewCalendarMonthMsgs = [
|
2007-11-13 17:17:07 +00:00
|
|
|
|
'hebrew-calendar-m1', 'hebrew-calendar-m2', 'hebrew-calendar-m3',
|
|
|
|
|
|
'hebrew-calendar-m4', 'hebrew-calendar-m5', 'hebrew-calendar-m6',
|
|
|
|
|
|
'hebrew-calendar-m7', 'hebrew-calendar-m8', 'hebrew-calendar-m9',
|
|
|
|
|
|
'hebrew-calendar-m10', 'hebrew-calendar-m11', 'hebrew-calendar-m12',
|
|
|
|
|
|
'hebrew-calendar-m6a', 'hebrew-calendar-m6b'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2007-11-13 17:17:07 +00:00
|
|
|
|
|
2019-02-07 09:21:19 +00:00
|
|
|
|
public static $mHebrewCalendarMonthGenMsgs = [
|
2007-11-13 17:17:07 +00:00
|
|
|
|
'hebrew-calendar-m1-gen', 'hebrew-calendar-m2-gen', 'hebrew-calendar-m3-gen',
|
|
|
|
|
|
'hebrew-calendar-m4-gen', 'hebrew-calendar-m5-gen', 'hebrew-calendar-m6-gen',
|
|
|
|
|
|
'hebrew-calendar-m7-gen', 'hebrew-calendar-m8-gen', 'hebrew-calendar-m9-gen',
|
|
|
|
|
|
'hebrew-calendar-m10-gen', 'hebrew-calendar-m11-gen', 'hebrew-calendar-m12-gen',
|
|
|
|
|
|
'hebrew-calendar-m6a-gen', 'hebrew-calendar-m6b-gen'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2019-02-07 09:21:19 +00:00
|
|
|
|
public static $mHijriCalendarMonthMsgs = [
|
2008-06-19 14:46:50 +00:00
|
|
|
|
'hijri-calendar-m1', 'hijri-calendar-m2', 'hijri-calendar-m3',
|
|
|
|
|
|
'hijri-calendar-m4', 'hijri-calendar-m5', 'hijri-calendar-m6',
|
|
|
|
|
|
'hijri-calendar-m7', 'hijri-calendar-m8', 'hijri-calendar-m9',
|
|
|
|
|
|
'hijri-calendar-m10', 'hijri-calendar-m11', 'hijri-calendar-m12'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2007-11-13 17:17:07 +00:00
|
|
|
|
|
2012-04-10 13:37:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @since 1.20
|
|
|
|
|
|
* @var array
|
|
|
|
|
|
*/
|
2019-02-07 09:21:19 +00:00
|
|
|
|
public static $durationIntervals = [
|
2012-12-29 14:07:21 +00:00
|
|
|
|
'millennia' => 31556952000,
|
|
|
|
|
|
'centuries' => 3155695200,
|
|
|
|
|
|
'decades' => 315569520,
|
|
|
|
|
|
'years' => 31556952, // 86400 * ( 365 + ( 24 * 3 + 25 ) / 400 )
|
2012-04-10 13:37:03 +00:00
|
|
|
|
'weeks' => 604800,
|
|
|
|
|
|
'days' => 86400,
|
|
|
|
|
|
'hours' => 3600,
|
|
|
|
|
|
'minutes' => 60,
|
|
|
|
|
|
'seconds' => 1,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2012-04-10 13:37:03 +00:00
|
|
|
|
|
2013-01-16 07:28:54 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Cache for language fallbacks.
|
|
|
|
|
|
* @see Language::getFallbacksIncludingSiteLanguage
|
|
|
|
|
|
* @since 1.21
|
|
|
|
|
|
* @var array
|
|
|
|
|
|
*/
|
2019-02-07 09:21:19 +00:00
|
|
|
|
private static $fallbackLanguageCache = [];
|
2013-01-16 07:28:54 +00:00
|
|
|
|
|
2015-09-26 20:28:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Cache for grammar rules data
|
|
|
|
|
|
* @var MapCacheLRU|null
|
|
|
|
|
|
*/
|
2019-02-07 09:21:19 +00:00
|
|
|
|
private static $grammarTransformations;
|
2015-09-26 20:28:03 +00:00
|
|
|
|
|
2014-09-23 05:27:13 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Cache for language names
|
2015-11-09 23:29:07 +00:00
|
|
|
|
* @var HashBagOStuff|null
|
2014-09-23 05:27:13 +00:00
|
|
|
|
*/
|
2019-02-07 09:21:19 +00:00
|
|
|
|
private static $languageNameCache;
|
2014-09-23 05:27:13 +00:00
|
|
|
|
|
2015-06-29 21:48:41 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Unicode directional formatting characters, for embedBidi()
|
|
|
|
|
|
*/
|
2019-02-07 09:21:19 +00:00
|
|
|
|
private static $lre = "\u{202A}"; // U+202A LEFT-TO-RIGHT EMBEDDING
|
|
|
|
|
|
private static $rle = "\u{202B}"; // U+202B RIGHT-TO-LEFT EMBEDDING
|
|
|
|
|
|
private static $pdf = "\u{202C}"; // U+202C POP DIRECTIONAL FORMATTING
|
2015-06-29 21:48:41 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Directionality test regex for embedBidi(). Matches the first strong directionality codepoint:
|
|
|
|
|
|
* - in group 1 if it is LTR
|
|
|
|
|
|
* - in group 2 if it is RTL
|
|
|
|
|
|
* Does not match if there is no strong directionality codepoint.
|
|
|
|
|
|
*
|
|
|
|
|
|
* The form is '/(?:([strong ltr codepoint])|([strong rtl codepoint]))/u' .
|
|
|
|
|
|
*
|
|
|
|
|
|
* Generated by UnicodeJS (see tools/strongDir) from the UCD; see
|
2017-11-05 05:11:41 +00:00
|
|
|
|
* https://phabricator.wikimedia.org/diffusion/GUJS/ .
|
2015-06-29 21:48:41 +00:00
|
|
|
|
*/
|
|
|
|
|
|
// @codeCoverageIgnoreStart
|
2018-01-01 13:10:16 +00:00
|
|
|
|
// phpcs:ignore Generic.Files.LineLength
|
2019-02-07 09:21:19 +00:00
|
|
|
|
private static $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{1f
|
2015-06-29 21:48:41 +00:00
|
|
|
|
// @codeCoverageIgnoreEnd
|
|
|
|
|
|
|
2006-07-26 07:15:39 +00:00
|
|
|
|
/**
|
2012-11-25 23:01:24 +00:00
|
|
|
|
* Get a cached or new language object for a given language code
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code
|
2017-10-23 09:33:38 +00:00
|
|
|
|
* @throws MWException
|
2011-01-10 04:44:33 +00:00
|
|
|
|
* @return Language
|
2006-07-26 07:15:39 +00:00
|
|
|
|
*/
|
|
|
|
|
|
static function factory( $code ) {
|
2013-01-02 17:40:03 +00:00
|
|
|
|
global $wgDummyLanguageCodes, $wgLangObjCacheSize;
|
|
|
|
|
|
|
|
|
|
|
|
if ( isset( $wgDummyLanguageCodes[$code] ) ) {
|
|
|
|
|
|
$code = $wgDummyLanguageCodes[$code];
|
|
|
|
|
|
}
|
2012-11-25 23:01:24 +00:00
|
|
|
|
|
|
|
|
|
|
// get the language object to process
|
2017-10-06 22:17:58 +00:00
|
|
|
|
$langObj = self::$mLangObjCache[$code] ?? self::newFromCode( $code );
|
2012-11-25 23:01:24 +00:00
|
|
|
|
|
|
|
|
|
|
// merge the language object in to get it up front in the cache
|
2016-02-17 09:09:32 +00:00
|
|
|
|
self::$mLangObjCache = array_merge( [ $code => $langObj ], self::$mLangObjCache );
|
2012-11-25 23:01:24 +00:00
|
|
|
|
// get rid of the oldest ones in case we have an overflow
|
|
|
|
|
|
self::$mLangObjCache = array_slice( self::$mLangObjCache, 0, $wgLangObjCacheSize, true );
|
|
|
|
|
|
|
|
|
|
|
|
return $langObj;
|
2008-11-12 00:11:10 +00:00
|
|
|
|
}
|
2008-11-11 23:26:07 +00:00
|
|
|
|
|
2008-11-12 00:11:10 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Create a language object for a given language code
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code
|
2017-08-11 15:46:31 +00:00
|
|
|
|
* @param bool $fallback Whether we're going through language fallback chain
|
2012-03-05 19:17:55 +00:00
|
|
|
|
* @throws MWException
|
2011-01-10 04:44:33 +00:00
|
|
|
|
* @return Language
|
2008-11-12 00:11:10 +00:00
|
|
|
|
*/
|
2013-07-27 23:01:54 +00:00
|
|
|
|
protected static function newFromCode( $code, $fallback = false ) {
|
2017-07-23 01:24:09 +00:00
|
|
|
|
if ( !self::isValidCode( $code ) ) {
|
2011-02-01 22:43:58 +00:00
|
|
|
|
throw new MWException( "Invalid language code \"$code\"" );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-07-23 01:24:09 +00:00
|
|
|
|
if ( !self::isValidBuiltInCode( $code ) ) {
|
2011-05-25 15:39:47 +00:00
|
|
|
|
// It's not possible to customise this code with class files, so
|
2011-02-28 03:15:39 +00:00
|
|
|
|
// just return a Language object. This is to support uselang= hacks.
|
|
|
|
|
|
$lang = new Language;
|
2018-10-03 09:15:37 +00:00
|
|
|
|
$lang->mCode = $code;
|
2011-02-28 03:15:39 +00:00
|
|
|
|
return $lang;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-08-18 16:41:07 +00:00
|
|
|
|
// Check if there is a language class for the code
|
2013-07-27 23:01:54 +00:00
|
|
|
|
$class = self::classFromCode( $code, $fallback );
|
2018-07-02 09:30:52 +00:00
|
|
|
|
// LanguageCode does not inherit Language
|
|
|
|
|
|
if ( class_exists( $class ) && is_a( $class, 'Language', true ) ) {
|
2011-08-18 16:41:07 +00:00
|
|
|
|
$lang = new $class;
|
|
|
|
|
|
return $lang;
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-08-18 16:41:07 +00:00
|
|
|
|
// Keep trying the fallback list until we find an existing class
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$fallbacks = self::getFallbacksFor( $code );
|
2011-08-18 16:41:07 +00:00
|
|
|
|
foreach ( $fallbacks as $fallbackCode ) {
|
2017-07-23 01:24:09 +00:00
|
|
|
|
if ( !self::isValidBuiltInCode( $fallbackCode ) ) {
|
2011-08-18 16:41:07 +00:00
|
|
|
|
throw new MWException( "Invalid fallback '$fallbackCode' in fallback sequence for '$code'" );
|
|
|
|
|
|
}
|
2006-07-26 07:15:39 +00:00
|
|
|
|
|
2011-08-18 16:41:07 +00:00
|
|
|
|
$class = self::classFromCode( $fallbackCode );
|
2013-08-08 03:18:34 +00:00
|
|
|
|
if ( class_exists( $class ) ) {
|
2015-10-29 01:02:58 +00:00
|
|
|
|
$lang = new $class;
|
2018-10-03 09:15:37 +00:00
|
|
|
|
$lang->mCode = $code;
|
2011-08-18 16:41:07 +00:00
|
|
|
|
return $lang;
|
|
|
|
|
|
}
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
2011-08-18 16:41:07 +00:00
|
|
|
|
|
|
|
|
|
|
throw new MWException( "Invalid fallback sequence for language '$code'" );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-01 12:40:47 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Intended for tests that may change configuration in a way that invalidates caches.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @since 1.32
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function clearCaches() {
|
|
|
|
|
|
if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
|
|
|
|
|
|
throw new MWException( __METHOD__ . ' must not be used outside tests' );
|
|
|
|
|
|
}
|
|
|
|
|
|
self::$dataCache = null;
|
|
|
|
|
|
// Reinitialize $dataCache, since it's expected to always be available
|
|
|
|
|
|
self::getLocalisationCache();
|
|
|
|
|
|
self::$mLangObjCache = [];
|
|
|
|
|
|
self::$fallbackLanguageCache = [];
|
|
|
|
|
|
self::$grammarTransformations = null;
|
|
|
|
|
|
self::$languageNameCache = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-01-14 07:21:10 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Checks whether any localisation is available for that language tag
|
|
|
|
|
|
* in MediaWiki (MessagesXx.php exists).
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param string $code Language tag (in lower case)
|
|
|
|
|
|
* @return bool Whether language is supported
|
|
|
|
|
|
* @since 1.21
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function isSupportedLanguage( $code ) {
|
2015-07-07 12:44:49 +00:00
|
|
|
|
if ( !self::isValidBuiltInCode( $code ) ) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( $code === 'qqq' ) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return is_readable( self::getMessagesFileName( $code ) ) ||
|
|
|
|
|
|
is_readable( self::getJsonMessagesFileName( $code ) );
|
2013-01-14 07:21:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-01-21 04:44:09 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Returns true if a language code string is a well-formed language tag
|
|
|
|
|
|
* according to RFC 5646.
|
|
|
|
|
|
* This function only checks well-formedness; it doesn't check that
|
|
|
|
|
|
* language, script or variant codes actually exist in the repositories.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Based on regexes by Mark Davis of the Unicode Consortium:
|
2017-12-02 20:38:29 +00:00
|
|
|
|
* https://www.unicode.org/repos/cldr/trunk/tools/java/org/unicode/cldr/util/data/langtagRegex.txt
|
2013-01-21 04:44:09 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code
|
|
|
|
|
|
* @param bool $lenient Whether to allow '_' as separator. The default is only '-'.
|
2013-01-21 04:44:09 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return bool
|
|
|
|
|
|
* @since 1.21
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function isWellFormedLanguageTag( $code, $lenient = false ) {
|
|
|
|
|
|
$alpha = '[a-z]';
|
|
|
|
|
|
$digit = '[0-9]';
|
|
|
|
|
|
$alphanum = '[a-z0-9]';
|
2013-04-17 19:10:02 +00:00
|
|
|
|
$x = 'x'; # private use singleton
|
2013-01-21 04:44:09 +00:00
|
|
|
|
$singleton = '[a-wy-z]'; # other singleton
|
|
|
|
|
|
$s = $lenient ? '[-_]' : '-';
|
|
|
|
|
|
|
|
|
|
|
|
$language = "$alpha{2,8}|$alpha{2,3}$s$alpha{3}";
|
|
|
|
|
|
$script = "$alpha{4}"; # ISO 15924
|
|
|
|
|
|
$region = "(?:$alpha{2}|$digit{3})"; # ISO 3166-1 alpha-2 or UN M.49
|
|
|
|
|
|
$variant = "(?:$alphanum{5,8}|$digit$alphanum{3})";
|
|
|
|
|
|
$extension = "$singleton(?:$s$alphanum{2,8})+";
|
|
|
|
|
|
$privateUse = "$x(?:$s$alphanum{1,8})+";
|
|
|
|
|
|
|
|
|
|
|
|
# Define certain grandfathered codes, since otherwise the regex is pretty useless.
|
|
|
|
|
|
# Since these are limited, this is safe even later changes to the registry --
|
|
|
|
|
|
# the only oddity is that it might change the type of the tag, and thus
|
|
|
|
|
|
# the results from the capturing groups.
|
2016-10-09 17:48:14 +00:00
|
|
|
|
# https://www.iana.org/assignments/language-subtag-registry
|
2013-01-21 04:44:09 +00:00
|
|
|
|
|
|
|
|
|
|
$grandfathered = "en{$s}GB{$s}oed"
|
|
|
|
|
|
. "|i{$s}(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|tao|tay|tsu)"
|
|
|
|
|
|
. "|no{$s}(?:bok|nyn)"
|
|
|
|
|
|
. "|sgn{$s}(?:BE{$s}(?:fr|nl)|CH{$s}de)"
|
|
|
|
|
|
. "|zh{$s}min{$s}nan";
|
|
|
|
|
|
|
|
|
|
|
|
$variantList = "$variant(?:$s$variant)*";
|
|
|
|
|
|
$extensionList = "$extension(?:$s$extension)*";
|
|
|
|
|
|
|
|
|
|
|
|
$langtag = "(?:($language)"
|
|
|
|
|
|
. "(?:$s$script)?"
|
|
|
|
|
|
. "(?:$s$region)?"
|
|
|
|
|
|
. "(?:$s$variantList)?"
|
|
|
|
|
|
. "(?:$s$extensionList)?"
|
|
|
|
|
|
. "(?:$s$privateUse)?)";
|
|
|
|
|
|
|
|
|
|
|
|
# The final breakdown, with capturing groups for each of these components
|
|
|
|
|
|
# The variants, extensions, grandfathered, and private-use may have interior '-'
|
|
|
|
|
|
|
|
|
|
|
|
$root = "^(?:$langtag|$privateUse|$grandfathered)$";
|
|
|
|
|
|
|
|
|
|
|
|
return (bool)preg_match( "/$root/", strtolower( $code ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-02-01 22:43:58 +00:00
|
|
|
|
/**
|
2011-05-25 15:39:47 +00:00
|
|
|
|
* Returns true if a language code string is of a valid form, whether or
|
|
|
|
|
|
* not it exists. This includes codes which are used solely for
|
2011-02-28 03:15:39 +00:00
|
|
|
|
* customisation via the MediaWiki namespace.
|
2011-05-29 15:03:33 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2011-05-29 15:03:33 +00:00
|
|
|
|
* @return bool
|
2011-02-01 22:43:58 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public static function isValidCode( $code ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
static $cache = [];
|
2018-06-27 10:16:26 +00:00
|
|
|
|
Assert::parameterType( 'string', $code, '$code' );
|
2015-10-29 01:02:58 +00:00
|
|
|
|
if ( !isset( $cache[$code] ) ) {
|
|
|
|
|
|
// People think language codes are html safe, so enforce it.
|
|
|
|
|
|
// Ideally we should only allow a-zA-Z0-9-
|
|
|
|
|
|
// but, .+ and other chars are often used for {{int:}} hacks
|
2016-10-23 01:46:14 +00:00
|
|
|
|
// see bugs T39564, T39587, T38938
|
2015-10-29 01:02:58 +00:00
|
|
|
|
$cache[$code] =
|
|
|
|
|
|
// Protect against path traversal
|
|
|
|
|
|
strcspn( $code, ":/\\\000&<>'\"" ) === strlen( $code )
|
|
|
|
|
|
&& !preg_match( MediaWikiTitleCodec::getTitleInvalidRegex(), $code );
|
2013-05-03 00:34:25 +00:00
|
|
|
|
}
|
2013-05-03 17:26:14 +00:00
|
|
|
|
return $cache[$code];
|
2011-02-28 03:15:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2011-05-25 15:39:47 +00:00
|
|
|
|
* Returns true if a language code is of a valid form for the purposes of
|
2014-04-01 10:32:00 +00:00
|
|
|
|
* internal customisation of MediaWiki, via Messages*.php or *.json.
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2011-08-11 14:52:57 +00:00
|
|
|
|
* @since 1.18
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return bool
|
2011-02-28 03:15:39 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public static function isValidBuiltInCode( $code ) {
|
2019-03-12 08:53:49 +00:00
|
|
|
|
Assert::parameterType( 'string', $code, '$code' );
|
2012-05-16 14:56:22 +00:00
|
|
|
|
|
2014-07-16 18:13:56 +00:00
|
|
|
|
return (bool)preg_match( '/^[a-z0-9-]{2,}$/', $code );
|
2011-02-01 22:43:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-01-21 04:15:32 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Returns true if a language code is an IETF tag known to MediaWiki.
|
|
|
|
|
|
*
|
2014-08-13 19:41:39 +00:00
|
|
|
|
* @param string $tag
|
2013-01-21 04:15:32 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @since 1.21
|
|
|
|
|
|
* @return bool
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function isKnownLanguageTag( $tag ) {
|
2013-06-11 16:42:10 +00:00
|
|
|
|
// Quick escape for invalid input to avoid exceptions down the line
|
|
|
|
|
|
// when code tries to process tags which are not valid at all.
|
|
|
|
|
|
if ( !self::isValidBuiltInCode( $tag ) ) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-01-29 05:19:58 +00:00
|
|
|
|
if ( isset( MediaWiki\Languages\Data\Names::$names[$tag] )
|
2013-01-21 04:15:32 +00:00
|
|
|
|
|| self::fetchLanguageName( $tag, $tag ) !== ''
|
|
|
|
|
|
) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2009-07-03 06:55:30 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get the LocalisationCache instance
|
2011-02-19 00:44:38 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return LocalisationCache
|
2009-07-03 06:55:30 +00:00
|
|
|
|
*/
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
public static function getLocalisationCache() {
|
|
|
|
|
|
if ( is_null( self::$dataCache ) ) {
|
|
|
|
|
|
global $wgLocalisationCacheConf;
|
|
|
|
|
|
$class = $wgLocalisationCacheConf['class'];
|
|
|
|
|
|
self::$dataCache = new $class( $wgLocalisationCacheConf );
|
|
|
|
|
|
}
|
|
|
|
|
|
return self::$dataCache;
|
2009-07-03 06:55:30 +00:00
|
|
|
|
}
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
|
2006-06-24 18:48:58 +00:00
|
|
|
|
function __construct() {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$this->mConverter = new FakeConverter( $this );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
// Set the code to the name of the descendant
|
2017-03-07 02:14:14 +00:00
|
|
|
|
if ( static::class === 'Language' ) {
|
2006-07-26 07:15:39 +00:00
|
|
|
|
$this->mCode = 'en';
|
|
|
|
|
|
} else {
|
2017-03-07 02:14:14 +00:00
|
|
|
|
$this->mCode = str_replace( '_', '-', strtolower( substr( static::class, 8 ) ) );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
self::getLocalisationCache();
|
2004-02-01 22:00:06 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2008-08-26 14:37:15 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Reduce memory usage
|
|
|
|
|
|
*/
|
|
|
|
|
|
function __destruct() {
|
|
|
|
|
|
foreach ( $this as $name => $value ) {
|
|
|
|
|
|
unset( $this->$name );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
/**
|
2006-07-26 07:15:39 +00:00
|
|
|
|
* Hook which will be called if this is the content language.
|
|
|
|
|
|
* Descendants can use this to register hook functions or modify globals
|
|
|
|
|
|
*/
|
2014-04-21 18:44:54 +00:00
|
|
|
|
function initContLang() {
|
|
|
|
|
|
}
|
2006-07-26 07:15:39 +00:00
|
|
|
|
|
2011-08-18 16:41:07 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
* @since 1.19
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getFallbackLanguages() {
|
2011-08-18 16:41:07 +00:00
|
|
|
|
return self::getFallbacksFor( $this->mCode );
|
2007-01-20 15:31:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Exports $wgBookstoreListEn
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getBookstoreList() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'bookstoreList' );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2005-04-07 19:05:42 +00:00
|
|
|
|
/**
|
2013-03-14 17:02:17 +00:00
|
|
|
|
* Returns an array of localised namespaces indexed by their numbers. If the namespace is not
|
|
|
|
|
|
* available in localised form, it will be included in English.
|
|
|
|
|
|
*
|
2019-01-31 11:26:13 +00:00
|
|
|
|
* @return string[] List of localized namespace names, indexed by numeric namespace ID.
|
2005-04-07 19:05:42 +00:00
|
|
|
|
*/
|
2012-01-27 13:00:26 +00:00
|
|
|
|
public function getNamespaces() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
if ( is_null( $this->namespaceNames ) ) {
|
2010-08-21 08:05:16 +00:00
|
|
|
|
global $wgMetaNamespace, $wgMetaNamespaceTalk, $wgExtraNamespaces;
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2010-08-20 10:25:10 +00:00
|
|
|
|
$validNamespaces = MWNamespace::getCanonicalNamespaces();
|
|
|
|
|
|
|
2016-12-13 19:51:07 +00:00
|
|
|
|
$this->namespaceNames = $wgExtraNamespaces +
|
|
|
|
|
|
self::$dataCache->getItem( $this->mCode, 'namespaceNames' );
|
|
|
|
|
|
$this->namespaceNames += $validNamespaces;
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
|
|
|
|
|
|
$this->namespaceNames[NS_PROJECT] = $wgMetaNamespace;
|
|
|
|
|
|
if ( $wgMetaNamespaceTalk ) {
|
|
|
|
|
|
$this->namespaceNames[NS_PROJECT_TALK] = $wgMetaNamespaceTalk;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$talk = $this->namespaceNames[NS_PROJECT_TALK];
|
|
|
|
|
|
$this->namespaceNames[NS_PROJECT_TALK] =
|
|
|
|
|
|
$this->fixVariableInNamespace( $talk );
|
|
|
|
|
|
}
|
2010-12-19 04:31:15 +00:00
|
|
|
|
|
2010-08-20 05:32:24 +00:00
|
|
|
|
# Sometimes a language will be localised but not actually exist on this wiki.
|
2011-09-22 03:42:14 +00:00
|
|
|
|
foreach ( $this->namespaceNames as $key => $text ) {
|
2010-08-20 10:25:10 +00:00
|
|
|
|
if ( !isset( $validNamespaces[$key] ) ) {
|
|
|
|
|
|
unset( $this->namespaceNames[$key] );
|
|
|
|
|
|
}
|
2010-08-20 05:32:24 +00:00
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
# The above mixing may leave namespaces out of canonical order.
|
|
|
|
|
|
# Re-order by namespace ID number...
|
|
|
|
|
|
ksort( $this->namespaceNames );
|
2011-08-30 13:24:27 +00:00
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
Hooks::run( 'LanguageGetNamespaces', [ &$this->namespaceNames ] );
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
}
|
2014-04-21 18:44:54 +00:00
|
|
|
|
|
2006-07-26 07:15:39 +00:00
|
|
|
|
return $this->namespaceNames;
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
2012-02-07 13:05:31 +00:00
|
|
|
|
|
2012-01-27 13:00:26 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Arbitrarily set all of the namespace names at once. Mainly used for testing
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param array $namespaces Array of namespaces (id => name)
|
2012-01-27 13:00:26 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public function setNamespaces( array $namespaces ) {
|
|
|
|
|
|
$this->namespaceNames = $namespaces;
|
2012-04-26 10:08:21 +00:00
|
|
|
|
$this->mNamespaceIds = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Resets all of the namespace caches. Mainly used for testing
|
|
|
|
|
|
*/
|
2013-03-17 15:13:22 +00:00
|
|
|
|
public function resetNamespaces() {
|
2012-04-26 10:08:21 +00:00
|
|
|
|
$this->namespaceNames = null;
|
|
|
|
|
|
$this->mNamespaceIds = null;
|
|
|
|
|
|
$this->namespaceAliases = null;
|
2012-01-27 13:00:26 +00:00
|
|
|
|
}
|
2005-05-03 12:27:30 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
2015-07-06 09:17:47 +00:00
|
|
|
|
* A convenience function that returns getNamespaces() with spaces instead of underscores
|
|
|
|
|
|
* in values. Useful for producing output to be displayed e.g. in `<select>` forms.
|
2005-05-03 12:27:30 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getFormattedNamespaces() {
|
2005-05-03 12:27:30 +00:00
|
|
|
|
$ns = $this->getNamespaces();
|
2010-07-29 09:43:18 +00:00
|
|
|
|
foreach ( $ns as $k => $v ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$ns[$k] = strtr( $v, '_', ' ' );
|
2005-05-03 12:27:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
return $ns;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get a namespace value by key
|
2015-07-06 09:17:47 +00:00
|
|
|
|
*
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
* <code>
|
2018-07-29 12:24:54 +00:00
|
|
|
|
* $mw_ns = $lang->getNsText( NS_MEDIAWIKI );
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
* echo $mw_ns; // prints 'MediaWiki'
|
|
|
|
|
|
* </code>
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int $index The array key of the namespace to return
|
|
|
|
|
|
* @return string|bool String if the namespace value exists, otherwise false
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getNsText( $index ) {
|
2005-06-18 04:06:54 +00:00
|
|
|
|
$ns = $this->getNamespaces();
|
2017-10-06 22:17:58 +00:00
|
|
|
|
return $ns[$index] ?? false;
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2005-05-03 12:27:30 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* A convenience function that returns the same thing as
|
|
|
|
|
|
* getNsText() except with '_' changed to ' ', useful for
|
|
|
|
|
|
* producing output.
|
|
|
|
|
|
*
|
2012-12-10 10:53:03 +00:00
|
|
|
|
* <code>
|
2018-07-29 12:24:54 +00:00
|
|
|
|
* $mw_ns = $lang->getFormattedNsText( NS_MEDIAWIKI_TALK );
|
2012-12-10 10:53:03 +00:00
|
|
|
|
* echo $mw_ns; // prints 'MediaWiki talk'
|
|
|
|
|
|
* </code>
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2012-12-10 10:53:03 +00:00
|
|
|
|
* @param int $index The array key of the namespace to return
|
|
|
|
|
|
* @return string Namespace name without underscores (empty string if namespace does not exist)
|
2005-05-03 12:27:30 +00:00
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getFormattedNsText( $index ) {
|
2005-05-03 12:27:30 +00:00
|
|
|
|
$ns = $this->getNsText( $index );
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return strtr( $ns, '_', ' ' );
|
2005-05-03 12:27:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-02-12 20:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Returns gender-dependent namespace alias if available.
|
2014-04-01 00:31:06 +00:00
|
|
|
|
* See https://www.mediawiki.org/wiki/Manual:$wgExtraGenderNamespaces
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int $index Namespace index
|
|
|
|
|
|
* @param string $gender Gender key (male, female... )
|
|
|
|
|
|
* @return string
|
2011-02-12 20:40:40 +00:00
|
|
|
|
* @since 1.18
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getGenderNsText( $index, $gender ) {
|
2011-09-16 16:11:54 +00:00
|
|
|
|
global $wgExtraGenderNamespaces;
|
2011-09-18 18:21:19 +00:00
|
|
|
|
|
2014-04-21 18:44:54 +00:00
|
|
|
|
$ns = $wgExtraGenderNamespaces +
|
2015-02-21 09:58:01 +00:00
|
|
|
|
(array)self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
|
2014-04-21 18:44:54 +00:00
|
|
|
|
|
2017-10-06 22:17:58 +00:00
|
|
|
|
return $ns[$index][$gender] ?? $this->getNsText( $index );
|
2011-02-12 20:40:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2014-04-01 00:31:06 +00:00
|
|
|
|
* Whether this language uses gender-dependent namespace aliases.
|
|
|
|
|
|
* See https://www.mediawiki.org/wiki/Manual:$wgExtraGenderNamespaces
|
2011-02-12 20:40:40 +00:00
|
|
|
|
* @return bool
|
|
|
|
|
|
* @since 1.18
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function needsGenderDistinction() {
|
2011-09-19 10:43:00 +00:00
|
|
|
|
global $wgExtraGenderNamespaces, $wgExtraNamespaces;
|
|
|
|
|
|
if ( count( $wgExtraGenderNamespaces ) > 0 ) {
|
|
|
|
|
|
// $wgExtraGenderNamespaces overrides everything
|
|
|
|
|
|
return true;
|
2011-09-22 03:42:14 +00:00
|
|
|
|
} elseif ( isset( $wgExtraNamespaces[NS_USER] ) && isset( $wgExtraNamespaces[NS_USER_TALK] ) ) {
|
2011-09-19 10:43:00 +00:00
|
|
|
|
/// @todo There may be other gender namespace than NS_USER & NS_USER_TALK in the future
|
|
|
|
|
|
// $wgExtraNamespaces overrides any gender aliases specified in i18n files
|
|
|
|
|
|
return false;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Check what is in i18n files
|
2011-09-19 11:31:12 +00:00
|
|
|
|
$aliases = self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
|
2011-09-19 10:43:00 +00:00
|
|
|
|
return count( $aliases ) > 0;
|
|
|
|
|
|
}
|
2011-02-12 20:40:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
/**
|
2007-04-19 18:47:04 +00:00
|
|
|
|
* Get a namespace key by value, case insensitive.
|
|
|
|
|
|
* Only matches namespace names for the current language, not the
|
|
|
|
|
|
* canonical ones defined in Namespace.php.
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $text
|
|
|
|
|
|
* @return int|bool An integer if $text is a valid value otherwise false
|
2007-04-19 18:47:04 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function getLocalNsIndex( $text ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$lctext = $this->lc( $text );
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
$ids = $this->getNamespaceIds();
|
2017-10-06 22:17:58 +00:00
|
|
|
|
return $ids[$lctext] ?? false;
|
2007-04-19 18:47:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getNamespaceAliases() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
if ( is_null( $this->namespaceAliases ) ) {
|
|
|
|
|
|
$aliases = self::$dataCache->getItem( $this->mCode, 'namespaceAliases' );
|
|
|
|
|
|
if ( !$aliases ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$aliases = [];
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
foreach ( $aliases as $name => $index ) {
|
|
|
|
|
|
if ( $index === NS_PROJECT_TALK ) {
|
|
|
|
|
|
unset( $aliases[$name] );
|
|
|
|
|
|
$name = $this->fixVariableInNamespace( $name );
|
|
|
|
|
|
$aliases[$name] = $index;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2011-02-12 20:40:40 +00:00
|
|
|
|
|
2011-09-16 16:11:54 +00:00
|
|
|
|
global $wgExtraGenderNamespaces;
|
2014-04-21 18:44:54 +00:00
|
|
|
|
$genders = $wgExtraGenderNamespaces +
|
|
|
|
|
|
(array)self::$dataCache->getItem( $this->mCode, 'namespaceGenderAliases' );
|
2011-02-12 20:40:40 +00:00
|
|
|
|
foreach ( $genders as $index => $forms ) {
|
|
|
|
|
|
foreach ( $forms as $alias ) {
|
|
|
|
|
|
$aliases[$alias] = $index;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-03-14 11:29:49 +00:00
|
|
|
|
# Also add converted namespace names as aliases, to avoid confusion.
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$convertedNames = [];
|
2013-03-14 11:29:49 +00:00
|
|
|
|
foreach ( $this->getVariants() as $variant ) {
|
|
|
|
|
|
if ( $variant === $this->mCode ) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach ( $this->getNamespaces() as $ns => $_ ) {
|
|
|
|
|
|
$convertedNames[$this->getConverter()->convertNamespace( $ns, $variant )] = $ns;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$this->namespaceAliases = $aliases + $convertedNames;
|
2018-10-02 21:18:38 +00:00
|
|
|
|
|
|
|
|
|
|
# Filter out aliases to namespaces that don't exist, e.g. from extensions
|
|
|
|
|
|
# that aren't loaded here but are included in the l10n cache.
|
|
|
|
|
|
# (array_intersect preserves keys from its first argument)
|
|
|
|
|
|
$this->namespaceAliases = array_intersect(
|
|
|
|
|
|
$this->namespaceAliases,
|
|
|
|
|
|
array_keys( $this->getNamespaces() )
|
|
|
|
|
|
);
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
}
|
2014-04-21 18:44:54 +00:00
|
|
|
|
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return $this->namespaceAliases;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getNamespaceIds() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
if ( is_null( $this->mNamespaceIds ) ) {
|
|
|
|
|
|
global $wgNamespaceAliases;
|
|
|
|
|
|
# Put namespace names and aliases into a hashtable.
|
2010-01-11 04:23:41 +00:00
|
|
|
|
# If this is too slow, then we should arrange it so that it is done
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
# before caching. The catch is that at pre-cache time, the above
|
|
|
|
|
|
# class-specific fixup hasn't been done.
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$this->mNamespaceIds = [];
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
foreach ( $this->getNamespaces() as $index => $name ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$this->mNamespaceIds[$this->lc( $name )] = $index;
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
foreach ( $this->getNamespaceAliases() as $name => $index ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$this->mNamespaceIds[$this->lc( $name )] = $index;
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
if ( $wgNamespaceAliases ) {
|
|
|
|
|
|
foreach ( $wgNamespaceAliases as $name => $index ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$this->mNamespaceIds[$this->lc( $name )] = $index;
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return $this->mNamespaceIds;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2007-04-19 18:47:04 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get a namespace key by value, case insensitive. Canonical namespace
|
|
|
|
|
|
* names override custom ones defined for the current language.
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $text
|
|
|
|
|
|
* @return int|bool An integer if $text is a valid value otherwise false
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getNsIndex( $text ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$lctext = $this->lc( $text );
|
2011-09-19 13:47:15 +00:00
|
|
|
|
$ns = MWNamespace::getCanonicalIndex( $lctext );
|
|
|
|
|
|
if ( $ns !== null ) {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return $ns;
|
|
|
|
|
|
}
|
|
|
|
|
|
$ids = $this->getNamespaceIds();
|
2017-10-06 22:17:58 +00:00
|
|
|
|
return $ids[$lctext] ?? false;
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
/**
|
2005-07-03 07:15:53 +00:00
|
|
|
|
* short names for language variants used for language conversion links.
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code
|
|
|
|
|
|
* @param bool $usemsg Use the "variantname-xyz" message if it exists
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getVariantname( $code, $usemsg = true ) {
|
2011-09-10 17:12:35 +00:00
|
|
|
|
$msg = "variantname-$code";
|
2011-09-22 03:42:14 +00:00
|
|
|
|
if ( $usemsg && wfMessage( $msg )->exists() ) {
|
2011-09-10 17:12:35 +00:00
|
|
|
|
return $this->getMessageFromDB( $msg );
|
2011-09-19 13:47:15 +00:00
|
|
|
|
}
|
2012-03-05 19:17:55 +00:00
|
|
|
|
$name = self::fetchLanguageName( $code );
|
2011-09-22 03:42:14 +00:00
|
|
|
|
if ( $name ) {
|
2011-09-10 17:12:35 +00:00
|
|
|
|
return $name; # if it's defined as a language name, show that
|
|
|
|
|
|
} else {
|
|
|
|
|
|
# otherwise, output the language code
|
|
|
|
|
|
return $code;
|
|
|
|
|
|
}
|
2004-12-24 02:47:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2017-05-24 09:32:41 +00:00
|
|
|
|
* @return string[]|bool List of date format preference keys, or false if disabled.
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getDatePreferences() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'datePreferences' );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2003-07-01 12:56:55 +00:00
|
|
|
|
function getDateFormats() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'dateFormats' );
|
2003-07-01 12:56:55 +00:00
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array|string
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getDefaultDateFormat() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
$df = self::$dataCache->getItem( $this->mCode, 'defaultDateFormat' );
|
|
|
|
|
|
if ( $df === 'dmy or mdy' ) {
|
|
|
|
|
|
global $wgAmericanDates;
|
|
|
|
|
|
return $wgAmericanDates ? 'mdy' : 'dmy';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return $df;
|
|
|
|
|
|
}
|
2006-08-10 08:00:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getDatePreferenceMigrationMap() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'datePreferenceMigrationMap' );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getExtraUserToggles() {
|
2011-11-08 17:20:54 +00:00
|
|
|
|
return (array)self::$dataCache->getItem( $this->mCode, 'extraUserToggles' );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
2004-07-08 15:40:27 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $tog
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2004-04-09 08:27:00 +00:00
|
|
|
|
function getUserToggle( $tog ) {
|
2006-08-06 18:32:12 +00:00
|
|
|
|
return $this->getMessageFromDB( "tog-$tog" );
|
2004-04-09 08:27:00 +00:00
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
|
2012-03-05 00:05:31 +00:00
|
|
|
|
/**
|
2012-02-27 11:59:24 +00:00
|
|
|
|
* Get an array of language names, indexed by code.
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param null|string $inLanguage Code of language in which to return the names
|
2018-06-18 18:30:10 +00:00
|
|
|
|
* Use self::AS_AUTONYMS for autonyms (native names)
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $include One of:
|
2018-06-18 18:30:10 +00:00
|
|
|
|
* self::ALL all available languages
|
2018-05-19 20:46:54 +00:00
|
|
|
|
* 'mw' only if the language is defined in MediaWiki or wgExtraLanguageNames (default)
|
2018-06-18 18:30:10 +00:00
|
|
|
|
* self::SUPPORTED only if the language is in 'mw' *and* has a message file
|
2018-02-22 21:09:04 +00:00
|
|
|
|
* @return array Language code => language name (sorted by key)
|
2012-03-08 19:30:30 +00:00
|
|
|
|
* @since 1.20
|
2012-02-27 11:59:24 +00:00
|
|
|
|
*/
|
2018-06-18 18:30:10 +00:00
|
|
|
|
public static function fetchLanguageNames( $inLanguage = self::AS_AUTONYMS, $include = 'mw' ) {
|
|
|
|
|
|
$cacheKey = $inLanguage === self::AS_AUTONYMS ? 'null' : $inLanguage;
|
2014-09-23 05:27:13 +00:00
|
|
|
|
$cacheKey .= ":$include";
|
|
|
|
|
|
if ( self::$languageNameCache === null ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
self::$languageNameCache = new HashBagOStuff( [ 'maxKeys' => 20 ] );
|
2014-09-23 05:27:13 +00:00
|
|
|
|
}
|
2015-11-09 23:29:07 +00:00
|
|
|
|
|
|
|
|
|
|
$ret = self::$languageNameCache->get( $cacheKey );
|
|
|
|
|
|
if ( !$ret ) {
|
2014-09-23 05:27:13 +00:00
|
|
|
|
$ret = self::fetchLanguageNamesUncached( $inLanguage, $include );
|
|
|
|
|
|
self::$languageNameCache->set( $cacheKey, $ret );
|
|
|
|
|
|
}
|
|
|
|
|
|
return $ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Uncached helper for fetchLanguageNames
|
|
|
|
|
|
* @param null|string $inLanguage Code of language in which to return the names
|
2018-06-18 18:30:10 +00:00
|
|
|
|
* Use self::AS_AUTONYMS for autonyms (native names)
|
2014-09-23 05:27:13 +00:00
|
|
|
|
* @param string $include One of:
|
2018-06-18 18:30:10 +00:00
|
|
|
|
* self::ALL all available languages
|
2014-09-23 05:27:13 +00:00
|
|
|
|
* 'mw' only if the language is defined in MediaWiki or wgExtraLanguageNames (default)
|
2018-06-18 18:30:10 +00:00
|
|
|
|
* self::SUPPORTED only if the language is in 'mw' *and* has a message file
|
2018-02-22 21:09:04 +00:00
|
|
|
|
* @return array Language code => language name (sorted by key)
|
2014-09-23 05:27:13 +00:00
|
|
|
|
*/
|
2018-06-18 18:30:10 +00:00
|
|
|
|
private static function fetchLanguageNamesUncached(
|
|
|
|
|
|
$inLanguage = self::AS_AUTONYMS,
|
|
|
|
|
|
$include = 'mw'
|
|
|
|
|
|
) {
|
2017-06-16 18:43:28 +00:00
|
|
|
|
global $wgExtraLanguageNames, $wgUsePigLatinVariant;
|
2012-02-27 11:59:24 +00:00
|
|
|
|
|
2014-06-29 21:45:07 +00:00
|
|
|
|
// If passed an invalid language code to use, fallback to en
|
2018-06-18 18:30:10 +00:00
|
|
|
|
if ( $inLanguage !== self::AS_AUTONYMS && !self::isValidCode( $inLanguage ) ) {
|
2014-06-29 21:45:07 +00:00
|
|
|
|
$inLanguage = 'en';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$names = [];
|
2010-12-31 18:18:57 +00:00
|
|
|
|
|
2012-08-29 08:07:10 +00:00
|
|
|
|
if ( $inLanguage ) {
|
2012-02-27 11:59:24 +00:00
|
|
|
|
# TODO: also include when $inLanguage is null, when this code is more efficient
|
2016-02-17 09:09:32 +00:00
|
|
|
|
Hooks::run( 'LanguageGetTranslatedLanguageNames', [ &$names, $inLanguage ] );
|
2012-02-27 11:59:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-01-29 05:19:58 +00:00
|
|
|
|
$mwNames = $wgExtraLanguageNames + MediaWiki\Languages\Data\Names::$names;
|
2017-06-16 18:43:28 +00:00
|
|
|
|
if ( $wgUsePigLatinVariant ) {
|
|
|
|
|
|
// Pig Latin (for variant development)
|
|
|
|
|
|
$mwNames['en-x-piglatin'] = 'Igpay Atinlay';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-02-27 11:59:24 +00:00
|
|
|
|
foreach ( $mwNames as $mwCode => $mwName ) {
|
|
|
|
|
|
# - Prefer own MediaWiki native name when not using the hook
|
|
|
|
|
|
# - For other names just add if not added through the hook
|
2012-06-05 22:58:54 +00:00
|
|
|
|
if ( $mwCode === $inLanguage || !isset( $names[$mwCode] ) ) {
|
2012-02-27 11:59:24 +00:00
|
|
|
|
$names[$mwCode] = $mwName;
|
|
|
|
|
|
}
|
2010-12-31 18:18:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-06-18 18:30:10 +00:00
|
|
|
|
if ( $include === self::ALL ) {
|
2014-12-28 11:51:12 +00:00
|
|
|
|
ksort( $names );
|
2012-02-27 11:59:24 +00:00
|
|
|
|
return $names;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$returnMw = [];
|
2012-02-27 11:59:24 +00:00
|
|
|
|
$coreCodes = array_keys( $mwNames );
|
2012-08-29 08:07:10 +00:00
|
|
|
|
foreach ( $coreCodes as $coreCode ) {
|
2012-02-27 11:59:24 +00:00
|
|
|
|
$returnMw[$coreCode] = $names[$coreCode];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-06-18 18:30:10 +00:00
|
|
|
|
if ( $include === self::SUPPORTED ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$namesMwFile = [];
|
2012-02-27 11:59:24 +00:00
|
|
|
|
# We do this using a foreach over the codes instead of a directory
|
|
|
|
|
|
# loop so that messages files in extensions will work correctly.
|
|
|
|
|
|
foreach ( $returnMw as $code => $value ) {
|
2014-04-01 10:32:00 +00:00
|
|
|
|
if ( is_readable( self::getMessagesFileName( $code ) )
|
|
|
|
|
|
|| is_readable( self::getJsonMessagesFileName( $code ) )
|
|
|
|
|
|
) {
|
2012-02-27 11:59:24 +00:00
|
|
|
|
$namesMwFile[$code] = $names[$code];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2014-04-01 10:32:00 +00:00
|
|
|
|
|
2014-12-28 11:51:12 +00:00
|
|
|
|
ksort( $namesMwFile );
|
2012-02-27 11:59:24 +00:00
|
|
|
|
return $namesMwFile;
|
|
|
|
|
|
}
|
2014-04-01 10:32:00 +00:00
|
|
|
|
|
2014-12-28 11:51:12 +00:00
|
|
|
|
ksort( $returnMw );
|
2012-05-09 23:39:11 +00:00
|
|
|
|
# 'mw' option; default if it's not one of the other two options (all/mwfile)
|
|
|
|
|
|
return $returnMw;
|
2012-02-27 11:59:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code The code of the language for which to get the name
|
2018-06-18 18:30:10 +00:00
|
|
|
|
* @param null|string $inLanguage Code of language in which to return the name
|
|
|
|
|
|
* (SELF::AS_AUTONYMS for autonyms)
|
|
|
|
|
|
* @param string $include See fetchLanguageNames()
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @return string Language name or empty
|
2012-02-27 11:59:24 +00:00
|
|
|
|
* @since 1.20
|
|
|
|
|
|
*/
|
2018-06-18 18:30:10 +00:00
|
|
|
|
public static function fetchLanguageName(
|
|
|
|
|
|
$code,
|
|
|
|
|
|
$inLanguage = self::AS_AUTONYMS,
|
|
|
|
|
|
$include = self::ALL
|
|
|
|
|
|
) {
|
2013-12-21 23:28:25 +00:00
|
|
|
|
$code = strtolower( $code );
|
2012-03-08 19:30:30 +00:00
|
|
|
|
$array = self::fetchLanguageNames( $inLanguage, $include );
|
2012-02-27 11:59:24 +00:00
|
|
|
|
return !array_key_exists( $code, $array ) ? '' : $array[$code];
|
2010-12-31 18:18:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2006-07-26 07:15:39 +00:00
|
|
|
|
/**
|
2008-09-30 19:03:22 +00:00
|
|
|
|
* Get a message from the MediaWiki namespace.
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $msg Message name
|
2008-09-30 19:03:22 +00:00
|
|
|
|
* @return string
|
2006-07-26 07:15:39 +00:00
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getMessageFromDB( $msg ) {
|
2014-12-06 11:16:16 +00:00
|
|
|
|
return $this->msg( $msg )->text();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get message object in this language. Only for use inside this class.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param string $msg Message name
|
|
|
|
|
|
* @return Message
|
|
|
|
|
|
*/
|
|
|
|
|
|
protected function msg( $msg ) {
|
|
|
|
|
|
return wfMessage( $msg )->inLanguage( $this );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $key
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getMonthName( $key ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return $this->getMessageFromDB( self::$mMonthMsgs[$key - 1] );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
2011-05-25 15:39:47 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getMonthNamesArray() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$monthNames = [ '' ];
|
2011-09-22 03:42:14 +00:00
|
|
|
|
for ( $i = 1; $i < 13; $i++ ) {
|
2011-04-18 12:54:28 +00:00
|
|
|
|
$monthNames[] = $this->getMonthName( $i );
|
|
|
|
|
|
}
|
|
|
|
|
|
return $monthNames;
|
|
|
|
|
|
}
|
2011-05-25 15:39:47 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $key
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2016-03-24 13:02:50 +00:00
|
|
|
|
public function getMonthNameGen( $key ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return $this->getMessageFromDB( self::$mMonthGenMsgs[$key - 1] );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $key
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2016-03-26 12:54:48 +00:00
|
|
|
|
public function getMonthAbbreviation( $key ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return $this->getMessageFromDB( self::$mMonthAbbrevMsgs[$key - 1] );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
2011-05-25 15:39:47 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2016-03-26 12:54:48 +00:00
|
|
|
|
public function getMonthAbbreviationsArray() {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$monthNames = [ '' ];
|
2011-09-22 03:42:14 +00:00
|
|
|
|
for ( $i = 1; $i < 13; $i++ ) {
|
2011-04-18 12:54:28 +00:00
|
|
|
|
$monthNames[] = $this->getMonthAbbreviation( $i );
|
|
|
|
|
|
}
|
|
|
|
|
|
return $monthNames;
|
|
|
|
|
|
}
|
2011-05-25 15:39:47 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $key
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2016-03-26 12:54:48 +00:00
|
|
|
|
public function getWeekdayName( $key ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return $this->getMessageFromDB( self::$mWeekdayMsgs[$key - 1] );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $key
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2006-07-26 07:15:39 +00:00
|
|
|
|
function getWeekdayAbbreviation( $key ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return $this->getMessageFromDB( self::$mWeekdayAbbrevMsgs[$key - 1] );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $key
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2007-11-13 04:05:13 +00:00
|
|
|
|
function getIranianCalendarMonthName( $key ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return $this->getMessageFromDB( self::$mIranianCalendarMonthMsgs[$key - 1] );
|
2007-11-13 04:05:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $key
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2007-11-13 17:17:07 +00:00
|
|
|
|
function getHebrewCalendarMonthName( $key ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return $this->getMessageFromDB( self::$mHebrewCalendarMonthMsgs[$key - 1] );
|
2007-11-13 17:17:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $key
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2007-11-13 17:17:07 +00:00
|
|
|
|
function getHebrewCalendarMonthNameGen( $key ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return $this->getMessageFromDB( self::$mHebrewCalendarMonthGenMsgs[$key - 1] );
|
2007-11-13 17:17:07 +00:00
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $key
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2008-06-19 14:46:50 +00:00
|
|
|
|
function getHijriCalendarMonthName( $key ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return $this->getMessageFromDB( self::$mHijriCalendarMonthMsgs[$key - 1] );
|
2008-06-19 14:46:50 +00:00
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2014-06-01 02:34:26 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Pass through result from $dateTimeObj->format()
|
2014-08-20 17:35:30 +00:00
|
|
|
|
* @param DateTime|bool|null &$dateTimeObj
|
2014-08-15 16:22:34 +00:00
|
|
|
|
* @param string $ts
|
2014-08-20 17:35:30 +00:00
|
|
|
|
* @param DateTimeZone|bool|null $zone
|
2014-08-15 16:22:34 +00:00
|
|
|
|
* @param string $code
|
|
|
|
|
|
* @return string
|
2014-06-01 02:34:26 +00:00
|
|
|
|
*/
|
|
|
|
|
|
private static function dateTimeObjFormat( &$dateTimeObj, $ts, $zone, $code ) {
|
|
|
|
|
|
if ( !$dateTimeObj ) {
|
|
|
|
|
|
$dateTimeObj = DateTime::createFromFormat(
|
|
|
|
|
|
'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' )
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
return $dateTimeObj->format( $code );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-07-26 07:15:39 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* This is a workalike of PHP's date() function, but with better
|
2010-01-11 04:23:41 +00:00
|
|
|
|
* internationalisation, a reduced set of format characters, and a better
|
2006-07-26 07:15:39 +00:00
|
|
|
|
* escaping format.
|
|
|
|
|
|
*
|
2013-03-22 16:41:03 +00:00
|
|
|
|
* Supported format characters are dDjlNwzWFmMntLoYyaAgGhHiscrUeIOPTZ. See
|
|
|
|
|
|
* the PHP manual for definitions. There are a number of extensions, which
|
2010-10-02 22:45:28 +00:00
|
|
|
|
* start with "x":
|
2006-07-26 07:15:39 +00:00
|
|
|
|
*
|
|
|
|
|
|
* xn Do not translate digits of the next numeric format character
|
2006-09-25 05:59:00 +00:00
|
|
|
|
* xN Toggle raw digit (xn) flag, stays set until explicitly unset
|
2006-07-26 07:15:39 +00:00
|
|
|
|
* xr Use roman numerals for the next numeric format character
|
2007-11-13 17:17:07 +00:00
|
|
|
|
* xh Use hebrew numerals for the next numeric format character
|
2006-07-26 07:15:39 +00:00
|
|
|
|
* xx Literal x
|
|
|
|
|
|
* xg Genitive month name
|
|
|
|
|
|
*
|
2007-11-13 04:05:13 +00:00
|
|
|
|
* xij j (day number) in Iranian calendar
|
|
|
|
|
|
* xiF F (month name) in Iranian calendar
|
|
|
|
|
|
* xin n (month number) in Iranian calendar
|
2011-12-14 00:32:56 +00:00
|
|
|
|
* xiy y (two digit year) in Iranian calendar
|
2007-11-13 04:05:13 +00:00
|
|
|
|
* xiY Y (full year) in Iranian calendar
|
2016-07-30 06:36:58 +00:00
|
|
|
|
* xit t (days in month) in Iranian calendar
|
2016-08-26 14:08:04 +00:00
|
|
|
|
* xiz z (day of the year) in Iranian calendar
|
2007-11-13 04:05:13 +00:00
|
|
|
|
*
|
2007-11-13 17:17:07 +00:00
|
|
|
|
* xjj j (day number) in Hebrew calendar
|
|
|
|
|
|
* xjF F (month name) in Hebrew calendar
|
2007-12-15 14:35:15 +00:00
|
|
|
|
* xjt t (days in month) in Hebrew calendar
|
2007-11-13 17:17:07 +00:00
|
|
|
|
* xjx xg (genitive month name) in Hebrew calendar
|
|
|
|
|
|
* xjn n (month number) in Hebrew calendar
|
|
|
|
|
|
* xjY Y (full year) in Hebrew calendar
|
|
|
|
|
|
*
|
2008-12-30 22:51:05 +00:00
|
|
|
|
* xmj j (day number) in Hijri calendar
|
|
|
|
|
|
* xmF F (month name) in Hijri calendar
|
|
|
|
|
|
* xmn n (month number) in Hijri calendar
|
|
|
|
|
|
* xmY Y (full year) in Hijri calendar
|
2008-06-19 14:46:50 +00:00
|
|
|
|
*
|
2007-12-06 20:14:36 +00:00
|
|
|
|
* xkY Y (full year) in Thai solar calendar. Months and days are
|
|
|
|
|
|
* identical to the Gregorian calendar
|
2009-05-20 01:53:39 +00:00
|
|
|
|
* xoY Y (full year) in Minguo calendar or Juche year.
|
|
|
|
|
|
* Months and days are identical to the
|
|
|
|
|
|
* Gregorian calendar
|
|
|
|
|
|
* xtY Y (full year) in Japanese nengo. Months and days are
|
2009-05-19 16:38:21 +00:00
|
|
|
|
* identical to the Gregorian calendar
|
2007-12-06 20:14:36 +00:00
|
|
|
|
*
|
2006-07-26 07:15:39 +00:00
|
|
|
|
* Characters enclosed in double quotes will be considered literal (with
|
|
|
|
|
|
* the quotes themselves removed). Unmatched quotes will be considered
|
|
|
|
|
|
* literal quotes. Example:
|
|
|
|
|
|
*
|
|
|
|
|
|
* "The month is" F => The month is January
|
|
|
|
|
|
* i's" => 20'11"
|
|
|
|
|
|
*
|
|
|
|
|
|
* Backslash escaping is also supported.
|
2007-06-15 19:07:15 +00:00
|
|
|
|
*
|
|
|
|
|
|
* Input timestamp is assumed to be pre-normalized to the desired local
|
2013-03-22 16:41:03 +00:00
|
|
|
|
* time zone, if any. Note that the format characters crUeIOPTZ will assume
|
|
|
|
|
|
* $ts is UTC if $zone is not given.
|
2010-01-11 04:23:41 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $format
|
|
|
|
|
|
* @param string $ts 14-character timestamp
|
2006-07-26 07:15:39 +00:00
|
|
|
|
* YYYYMMDDHHMMSS
|
|
|
|
|
|
* 01234567890123
|
2018-06-26 21:14:43 +00:00
|
|
|
|
* @param DateTimeZone|null $zone Timezone of $ts
|
2017-07-21 10:22:12 +00:00
|
|
|
|
* @param int &$ttl The amount of time (in seconds) the output may be cached for.
|
2014-06-01 02:34:26 +00:00
|
|
|
|
* Only makes sense if $ts is the current time.
|
2008-12-30 22:51:05 +00:00
|
|
|
|
* @todo handling of "o" format character for Iranian, Hebrew, Hijri & Thai?
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2013-04-25 07:58:39 +00:00
|
|
|
|
* @throws MWException
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
2006-07-26 07:15:39 +00:00
|
|
|
|
*/
|
2016-06-23 10:01:59 +00:00
|
|
|
|
public function sprintfDate( $format, $ts, DateTimeZone $zone = null, &$ttl = 'unused' ) {
|
2006-07-26 07:15:39 +00:00
|
|
|
|
$s = '';
|
|
|
|
|
|
$raw = false;
|
|
|
|
|
|
$roman = false;
|
2007-11-13 17:17:07 +00:00
|
|
|
|
$hebrewNum = false;
|
2013-03-22 16:41:03 +00:00
|
|
|
|
$dateTimeObj = false;
|
2006-09-25 05:59:00 +00:00
|
|
|
|
$rawToggle = false;
|
2007-11-13 04:05:13 +00:00
|
|
|
|
$iranian = false;
|
2007-11-13 17:17:07 +00:00
|
|
|
|
$hebrew = false;
|
2008-06-19 14:46:50 +00:00
|
|
|
|
$hijri = false;
|
2007-12-06 20:14:36 +00:00
|
|
|
|
$thai = false;
|
2009-05-19 16:38:21 +00:00
|
|
|
|
$minguo = false;
|
2009-05-20 01:53:39 +00:00
|
|
|
|
$tenno = false;
|
2013-04-25 07:58:39 +00:00
|
|
|
|
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedSecond = false;
|
|
|
|
|
|
$usedMinute = false;
|
|
|
|
|
|
$usedHour = false;
|
|
|
|
|
|
$usedAMPM = false;
|
|
|
|
|
|
$usedDay = false;
|
|
|
|
|
|
$usedWeek = false;
|
|
|
|
|
|
$usedMonth = false;
|
|
|
|
|
|
$usedYear = false;
|
|
|
|
|
|
$usedISOYear = false;
|
|
|
|
|
|
$usedIsLeapYear = false;
|
|
|
|
|
|
|
|
|
|
|
|
$usedHebrewMonth = false;
|
|
|
|
|
|
$usedIranianMonth = false;
|
|
|
|
|
|
$usedHijriMonth = false;
|
|
|
|
|
|
$usedHebrewYear = false;
|
|
|
|
|
|
$usedIranianYear = false;
|
|
|
|
|
|
$usedHijriYear = false;
|
|
|
|
|
|
$usedTennoYear = false;
|
|
|
|
|
|
|
2013-04-25 07:58:39 +00:00
|
|
|
|
if ( strlen( $ts ) !== 14 ) {
|
|
|
|
|
|
throw new MWException( __METHOD__ . ": The timestamp $ts should have 14 characters" );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( !ctype_digit( $ts ) ) {
|
|
|
|
|
|
throw new MWException( __METHOD__ . ": The timestamp $ts should be a number" );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-04-21 18:44:54 +00:00
|
|
|
|
$formatLength = strlen( $format );
|
|
|
|
|
|
for ( $p = 0; $p < $formatLength; $p++ ) {
|
2006-07-26 07:15:39 +00:00
|
|
|
|
$num = false;
|
|
|
|
|
|
$code = $format[$p];
|
2014-04-21 18:44:54 +00:00
|
|
|
|
if ( $code == 'x' && $p < $formatLength - 1 ) {
|
2006-07-26 07:15:39 +00:00
|
|
|
|
$code .= $format[++$p];
|
|
|
|
|
|
}
|
2007-11-13 04:05:13 +00:00
|
|
|
|
|
2014-04-21 18:44:54 +00:00
|
|
|
|
if ( ( $code === 'xi'
|
|
|
|
|
|
|| $code === 'xj'
|
|
|
|
|
|
|| $code === 'xk'
|
|
|
|
|
|
|| $code === 'xm'
|
|
|
|
|
|
|| $code === 'xo'
|
|
|
|
|
|
|| $code === 'xt' )
|
|
|
|
|
|
&& $p < $formatLength - 1 ) {
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$code .= $format[++$p];
|
|
|
|
|
|
}
|
2007-11-13 04:05:13 +00:00
|
|
|
|
|
2008-06-19 16:14:48 +00:00
|
|
|
|
switch ( $code ) {
|
|
|
|
|
|
case 'xx':
|
|
|
|
|
|
$s .= 'x';
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xn':
|
|
|
|
|
|
$raw = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xN':
|
|
|
|
|
|
$rawToggle = !$rawToggle;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xr':
|
|
|
|
|
|
$roman = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xh':
|
|
|
|
|
|
$hebrewNum = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xg':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedMonth = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$s .= $this->getMonthNameGen( substr( $ts, 4, 2 ) );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xjx':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedHebrewMonth = true;
|
2013-04-17 19:10:02 +00:00
|
|
|
|
if ( !$hebrew ) {
|
|
|
|
|
|
$hebrew = self::tsToHebrew( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$s .= $this->getHebrewCalendarMonthNameGen( $hebrew[1] );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'd':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedDay = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = substr( $ts, 6, 2 );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'D':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedDay = true;
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$s .= $this->getWeekdayAbbreviation(
|
2017-07-23 01:24:09 +00:00
|
|
|
|
self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'w' ) + 1
|
2015-03-03 08:55:08 +00:00
|
|
|
|
);
|
2008-06-19 16:14:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case 'j':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedDay = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = intval( substr( $ts, 6, 2 ) );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xij':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedDay = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$iranian ) {
|
|
|
|
|
|
$iranian = self::tsToIranian( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = $iranian[2];
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xmj':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedDay = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$hijri ) {
|
|
|
|
|
|
$hijri = self::tsToHijri( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = $hijri[2];
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xjj':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedDay = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$hebrew ) {
|
|
|
|
|
|
$hebrew = self::tsToHebrew( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = $hebrew[2];
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'l':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedDay = true;
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$s .= $this->getWeekdayName(
|
2017-07-23 01:24:09 +00:00
|
|
|
|
self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'w' ) + 1
|
2015-03-03 08:55:08 +00:00
|
|
|
|
);
|
2008-06-19 16:14:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case 'F':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedMonth = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$s .= $this->getMonthName( substr( $ts, 4, 2 ) );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xiF':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedIranianMonth = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$iranian ) {
|
|
|
|
|
|
$iranian = self::tsToIranian( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$s .= $this->getIranianCalendarMonthName( $iranian[1] );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xmF':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedHijriMonth = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$hijri ) {
|
|
|
|
|
|
$hijri = self::tsToHijri( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$s .= $this->getHijriCalendarMonthName( $hijri[1] );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xjF':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedHebrewMonth = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$hebrew ) {
|
|
|
|
|
|
$hebrew = self::tsToHebrew( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$s .= $this->getHebrewCalendarMonthName( $hebrew[1] );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'm':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedMonth = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = substr( $ts, 4, 2 );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'M':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedMonth = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$s .= $this->getMonthAbbreviation( substr( $ts, 4, 2 ) );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'n':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedMonth = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = intval( substr( $ts, 4, 2 ) );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xin':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedIranianMonth = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$iranian ) {
|
|
|
|
|
|
$iranian = self::tsToIranian( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = $iranian[1];
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xmn':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedHijriMonth = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$hijri ) {
|
2015-06-16 19:06:19 +00:00
|
|
|
|
$hijri = self::tsToHijri( $ts );
|
2010-04-08 20:19:03 +00:00
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = $hijri[1];
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xjn':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedHebrewMonth = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$hebrew ) {
|
|
|
|
|
|
$hebrew = self::tsToHebrew( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = $hebrew[1];
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xjt':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedHebrewMonth = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$hebrew ) {
|
|
|
|
|
|
$hebrew = self::tsToHebrew( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = $hebrew[3];
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'Y':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedYear = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = substr( $ts, 0, 4 );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xiY':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedIranianYear = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$iranian ) {
|
|
|
|
|
|
$iranian = self::tsToIranian( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = $iranian[0];
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xmY':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedHijriYear = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$hijri ) {
|
|
|
|
|
|
$hijri = self::tsToHijri( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = $hijri[0];
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xjY':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedHebrewYear = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$hebrew ) {
|
|
|
|
|
|
$hebrew = self::tsToHebrew( $ts );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = $hebrew[0];
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'xkY':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedYear = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$thai ) {
|
|
|
|
|
|
$thai = self::tsToYear( $ts, 'thai' );
|
|
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = $thai[0];
|
|
|
|
|
|
break;
|
2009-05-19 16:38:21 +00:00
|
|
|
|
case 'xoY':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedYear = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$minguo ) {
|
|
|
|
|
|
$minguo = self::tsToYear( $ts, 'minguo' );
|
|
|
|
|
|
}
|
2009-05-19 16:38:21 +00:00
|
|
|
|
$num = $minguo[0];
|
|
|
|
|
|
break;
|
2009-05-20 01:53:39 +00:00
|
|
|
|
case 'xtY':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedTennoYear = true;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$tenno ) {
|
|
|
|
|
|
$tenno = self::tsToYear( $ts, 'tenno' );
|
|
|
|
|
|
}
|
2009-05-20 01:53:39 +00:00
|
|
|
|
$num = $tenno[0];
|
|
|
|
|
|
break;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
case 'y':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedYear = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = substr( $ts, 2, 2 );
|
|
|
|
|
|
break;
|
2011-12-14 00:32:56 +00:00
|
|
|
|
case 'xiy':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedIranianYear = true;
|
2011-12-14 00:32:56 +00:00
|
|
|
|
if ( !$iranian ) {
|
|
|
|
|
|
$iranian = self::tsToIranian( $ts );
|
|
|
|
|
|
}
|
|
|
|
|
|
$num = substr( $iranian[0], -2 );
|
|
|
|
|
|
break;
|
2016-07-30 06:36:58 +00:00
|
|
|
|
case 'xit':
|
|
|
|
|
|
$usedIranianYear = true;
|
|
|
|
|
|
if ( !$iranian ) {
|
|
|
|
|
|
$iranian = self::tsToIranian( $ts );
|
|
|
|
|
|
}
|
|
|
|
|
|
$num = self::$IRANIAN_DAYS[$iranian[1] - 1];
|
|
|
|
|
|
break;
|
2016-08-26 14:08:04 +00:00
|
|
|
|
case 'xiz':
|
|
|
|
|
|
$usedIranianYear = true;
|
|
|
|
|
|
if ( !$iranian ) {
|
|
|
|
|
|
$iranian = self::tsToIranian( $ts );
|
|
|
|
|
|
}
|
|
|
|
|
|
$num = $iranian[3];
|
|
|
|
|
|
break;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
case 'a':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedAMPM = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$s .= intval( substr( $ts, 8, 2 ) ) < 12 ? 'am' : 'pm';
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'A':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedAMPM = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$s .= intval( substr( $ts, 8, 2 ) ) < 12 ? 'AM' : 'PM';
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'g':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedHour = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$h = substr( $ts, 8, 2 );
|
2019-01-09 15:52:38 +00:00
|
|
|
|
$num = $h % 12 ?: 12;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case 'G':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedHour = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = intval( substr( $ts, 8, 2 ) );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'h':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedHour = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$h = substr( $ts, 8, 2 );
|
2019-01-09 15:52:38 +00:00
|
|
|
|
$num = sprintf( '%02d', $h % 12 ?: 12 );
|
2010-01-11 04:23:41 +00:00
|
|
|
|
break;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
case 'H':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedHour = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = substr( $ts, 8, 2 );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'i':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedMinute = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = substr( $ts, 10, 2 );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 's':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedSecond = true;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$num = substr( $ts, 12, 2 );
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'c':
|
|
|
|
|
|
case 'r':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedSecond = true;
|
|
|
|
|
|
// fall through
|
2013-03-22 16:41:03 +00:00
|
|
|
|
case 'e':
|
|
|
|
|
|
case 'O':
|
|
|
|
|
|
case 'P':
|
|
|
|
|
|
case 'T':
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$s .= self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
|
2008-06-19 16:14:48 +00:00
|
|
|
|
break;
|
2013-03-22 16:41:03 +00:00
|
|
|
|
case 'w':
|
|
|
|
|
|
case 'N':
|
|
|
|
|
|
case 'z':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedDay = true;
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$num = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
|
2014-06-01 02:34:26 +00:00
|
|
|
|
break;
|
2013-03-22 16:41:03 +00:00
|
|
|
|
case 'W':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedWeek = true;
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$num = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
|
2014-06-01 02:34:26 +00:00
|
|
|
|
break;
|
2013-03-22 16:41:03 +00:00
|
|
|
|
case 't':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedMonth = true;
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$num = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
|
2014-06-01 02:34:26 +00:00
|
|
|
|
break;
|
2013-03-22 16:41:03 +00:00
|
|
|
|
case 'L':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedIsLeapYear = true;
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$num = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
|
2014-06-01 02:34:26 +00:00
|
|
|
|
break;
|
2013-03-22 16:41:03 +00:00
|
|
|
|
case 'o':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedISOYear = true;
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$num = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
|
2014-06-01 02:34:26 +00:00
|
|
|
|
break;
|
2008-06-19 16:14:48 +00:00
|
|
|
|
case 'U':
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$usedSecond = true;
|
|
|
|
|
|
// fall through
|
2013-03-22 16:41:03 +00:00
|
|
|
|
case 'I':
|
|
|
|
|
|
case 'Z':
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$num = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, $code );
|
2008-06-19 16:14:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case '\\':
|
|
|
|
|
|
# Backslash escaping
|
2014-04-21 18:44:54 +00:00
|
|
|
|
if ( $p < $formatLength - 1 ) {
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$s .= $format[++$p];
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$s .= '\\';
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case '"':
|
|
|
|
|
|
# Quoted literal
|
2014-04-21 18:44:54 +00:00
|
|
|
|
if ( $p < $formatLength - 1 ) {
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$endQuote = strpos( $format, '"', $p + 1 );
|
|
|
|
|
|
if ( $endQuote === false ) {
|
|
|
|
|
|
# No terminating quote, assume literal "
|
2008-06-19 15:18:48 +00:00
|
|
|
|
$s .= '"';
|
2008-06-19 16:14:48 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$s .= substr( $format, $p + 1, $endQuote - $p - 1 );
|
|
|
|
|
|
$p = $endQuote;
|
2008-06-19 15:18:48 +00:00
|
|
|
|
}
|
2006-07-26 07:15:39 +00:00
|
|
|
|
} else {
|
2008-06-19 16:14:48 +00:00
|
|
|
|
# Quote at end of string, assume literal "
|
|
|
|
|
|
$s .= '"';
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
2008-06-19 16:14:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
$s .= $format[$p];
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $num !== false ) {
|
|
|
|
|
|
if ( $rawToggle || $raw ) {
|
|
|
|
|
|
$s .= $num;
|
|
|
|
|
|
$raw = false;
|
|
|
|
|
|
} elseif ( $roman ) {
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$s .= self::romanNumeral( $num );
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$roman = false;
|
2010-07-29 09:43:18 +00:00
|
|
|
|
} elseif ( $hebrewNum ) {
|
2008-06-19 16:14:48 +00:00
|
|
|
|
$s .= self::hebrewNumeral( $num );
|
|
|
|
|
|
$hebrewNum = false;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$s .= $this->formatNum( $num, true );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2014-04-21 18:44:54 +00:00
|
|
|
|
|
2016-06-23 10:01:59 +00:00
|
|
|
|
if ( $ttl === 'unused' ) {
|
|
|
|
|
|
// No need to calculate the TTL, the caller wont use it anyway.
|
|
|
|
|
|
} elseif ( $usedSecond ) {
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$ttl = 1;
|
|
|
|
|
|
} elseif ( $usedMinute ) {
|
|
|
|
|
|
$ttl = 60 - substr( $ts, 12, 2 );
|
|
|
|
|
|
} elseif ( $usedHour ) {
|
|
|
|
|
|
$ttl = 3600 - substr( $ts, 10, 2 ) * 60 - substr( $ts, 12, 2 );
|
|
|
|
|
|
} elseif ( $usedAMPM ) {
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$ttl = 43200 - ( substr( $ts, 8, 2 ) % 12 ) * 3600 -
|
|
|
|
|
|
substr( $ts, 10, 2 ) * 60 - substr( $ts, 12, 2 );
|
|
|
|
|
|
} elseif (
|
|
|
|
|
|
$usedDay ||
|
|
|
|
|
|
$usedHebrewMonth ||
|
|
|
|
|
|
$usedIranianMonth ||
|
|
|
|
|
|
$usedHijriMonth ||
|
|
|
|
|
|
$usedHebrewYear ||
|
|
|
|
|
|
$usedIranianYear ||
|
|
|
|
|
|
$usedHijriYear ||
|
|
|
|
|
|
$usedTennoYear
|
|
|
|
|
|
) {
|
|
|
|
|
|
// @todo Someone who understands the non-Gregorian calendars
|
|
|
|
|
|
// should write proper logic for them so that they don't need purged every day.
|
|
|
|
|
|
$ttl = 86400 - substr( $ts, 8, 2 ) * 3600 -
|
|
|
|
|
|
substr( $ts, 10, 2 ) * 60 - substr( $ts, 12, 2 );
|
2014-06-01 02:34:26 +00:00
|
|
|
|
} else {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$possibleTtls = [];
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$timeRemainingInDay = 86400 - substr( $ts, 8, 2 ) * 3600 -
|
|
|
|
|
|
substr( $ts, 10, 2 ) * 60 - substr( $ts, 12, 2 );
|
2014-06-01 02:34:26 +00:00
|
|
|
|
if ( $usedWeek ) {
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$possibleTtls[] =
|
2017-07-23 01:24:09 +00:00
|
|
|
|
( 7 - self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'N' ) ) * 86400 +
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$timeRemainingInDay;
|
2014-06-01 02:34:26 +00:00
|
|
|
|
} elseif ( $usedISOYear ) {
|
|
|
|
|
|
// December 28th falls on the last ISO week of the year, every year.
|
|
|
|
|
|
// The last ISO week of a year can be 52 or 53.
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$lastWeekOfISOYear = DateTime::createFromFormat(
|
|
|
|
|
|
'Ymd',
|
|
|
|
|
|
substr( $ts, 0, 4 ) . '1228',
|
|
|
|
|
|
$zone ?: new DateTimeZone( 'UTC' )
|
|
|
|
|
|
)->format( 'W' );
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$currentISOWeek = self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'W' );
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$weeksRemaining = $lastWeekOfISOYear - $currentISOWeek;
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$timeRemainingInWeek =
|
2017-07-23 01:24:09 +00:00
|
|
|
|
( 7 - self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'N' ) ) * 86400
|
2015-03-03 08:55:08 +00:00
|
|
|
|
+ $timeRemainingInDay;
|
2014-06-01 02:34:26 +00:00
|
|
|
|
$possibleTtls[] = $weeksRemaining * 604800 + $timeRemainingInWeek;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( $usedMonth ) {
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$possibleTtls[] =
|
2017-07-23 01:24:09 +00:00
|
|
|
|
( self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 't' ) -
|
2015-03-03 08:55:08 +00:00
|
|
|
|
substr( $ts, 6, 2 ) ) * 86400
|
|
|
|
|
|
+ $timeRemainingInDay;
|
2014-06-01 02:34:26 +00:00
|
|
|
|
} elseif ( $usedYear ) {
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$possibleTtls[] =
|
2017-07-23 01:24:09 +00:00
|
|
|
|
( self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'L' ) + 364 -
|
|
|
|
|
|
self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'z' ) ) * 86400
|
2014-06-01 02:34:26 +00:00
|
|
|
|
+ $timeRemainingInDay;
|
|
|
|
|
|
} elseif ( $usedIsLeapYear ) {
|
|
|
|
|
|
$year = substr( $ts, 0, 4 );
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$timeRemainingInYear =
|
2017-07-23 01:24:09 +00:00
|
|
|
|
( self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'L' ) + 364 -
|
|
|
|
|
|
self::dateTimeObjFormat( $dateTimeObj, $ts, $zone, 'z' ) ) * 86400
|
2014-06-01 02:34:26 +00:00
|
|
|
|
+ $timeRemainingInDay;
|
|
|
|
|
|
$mod = $year % 4;
|
|
|
|
|
|
if ( $mod || ( !( $year % 100 ) && $year % 400 ) ) {
|
|
|
|
|
|
// this isn't a leap year. see when the next one starts
|
|
|
|
|
|
$nextCandidate = $year - $mod + 4;
|
|
|
|
|
|
if ( $nextCandidate % 100 || !( $nextCandidate % 400 ) ) {
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$possibleTtls[] = ( $nextCandidate - $year - 1 ) * 365 * 86400 +
|
|
|
|
|
|
$timeRemainingInYear;
|
2014-06-01 02:34:26 +00:00
|
|
|
|
} else {
|
2015-03-03 08:55:08 +00:00
|
|
|
|
$possibleTtls[] = ( $nextCandidate - $year + 3 ) * 365 * 86400 +
|
|
|
|
|
|
$timeRemainingInYear;
|
2014-06-01 02:34:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// this is a leap year, so the next year isn't
|
|
|
|
|
|
$possibleTtls[] = $timeRemainingInYear;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( $possibleTtls ) {
|
|
|
|
|
|
$ttl = min( $possibleTtls );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-07-26 07:15:39 +00:00
|
|
|
|
return $s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
private static $GREG_DAYS = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
|
|
|
|
|
|
private static $IRANIAN_DAYS = [ 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 ];
|
2011-05-29 15:40:17 +00:00
|
|
|
|
|
2007-11-13 04:05:13 +00:00
|
|
|
|
/**
|
2010-01-11 04:23:41 +00:00
|
|
|
|
* Algorithm by Roozbeh Pournader and Mohammad Toossi to convert
|
2007-11-13 04:05:13 +00:00
|
|
|
|
* Gregorian dates to Iranian dates. Originally written in C, it
|
|
|
|
|
|
* is released under the terms of GNU Lesser General Public
|
|
|
|
|
|
* License. Conversion to PHP was performed by Niklas Laxström.
|
2010-01-11 04:23:41 +00:00
|
|
|
|
*
|
2007-11-13 04:05:13 +00:00
|
|
|
|
* Link: http://www.farsiweb.info/jalali/jalali.c
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $ts
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2016-04-19 10:18:20 +00:00
|
|
|
|
* @return int[]
|
2007-11-13 04:05:13 +00:00
|
|
|
|
*/
|
|
|
|
|
|
private static function tsToIranian( $ts ) {
|
2017-08-11 13:53:17 +00:00
|
|
|
|
$gy = substr( $ts, 0, 4 ) - 1600;
|
|
|
|
|
|
$gm = substr( $ts, 4, 2 ) - 1;
|
|
|
|
|
|
$gd = substr( $ts, 6, 2 ) - 1;
|
2007-11-13 04:05:13 +00:00
|
|
|
|
|
|
|
|
|
|
# Days passed from the beginning (including leap years)
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$gDayNo = 365 * $gy
|
|
|
|
|
|
+ floor( ( $gy + 3 ) / 4 )
|
|
|
|
|
|
- floor( ( $gy + 99 ) / 100 )
|
|
|
|
|
|
+ floor( ( $gy + 399 ) / 400 );
|
2007-11-13 04:05:13 +00:00
|
|
|
|
|
|
|
|
|
|
// Add days of the past months of this year
|
2010-07-29 09:43:18 +00:00
|
|
|
|
for ( $i = 0; $i < $gm; $i++ ) {
|
2007-11-13 04:05:13 +00:00
|
|
|
|
$gDayNo += self::$GREG_DAYS[$i];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Leap years
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $gm > 1 && ( ( $gy % 4 === 0 && $gy % 100 !== 0 || ( $gy % 400 == 0 ) ) ) ) {
|
2007-11-13 04:05:13 +00:00
|
|
|
|
$gDayNo++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Days passed in current month
|
2011-10-18 17:27:52 +00:00
|
|
|
|
$gDayNo += (int)$gd;
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2007-11-13 04:05:13 +00:00
|
|
|
|
$jDayNo = $gDayNo - 79;
|
|
|
|
|
|
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$jNp = floor( $jDayNo / 12053 );
|
2007-11-13 04:05:13 +00:00
|
|
|
|
$jDayNo %= 12053;
|
|
|
|
|
|
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$jy = 979 + 33 * $jNp + 4 * floor( $jDayNo / 1461 );
|
2007-11-13 04:05:13 +00:00
|
|
|
|
$jDayNo %= 1461;
|
|
|
|
|
|
|
|
|
|
|
|
if ( $jDayNo >= 366 ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$jy += floor( ( $jDayNo - 1 ) / 365 );
|
|
|
|
|
|
$jDayNo = floor( ( $jDayNo - 1 ) % 365 );
|
2007-11-13 04:05:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-08-26 14:08:04 +00:00
|
|
|
|
$jz = $jDayNo;
|
|
|
|
|
|
|
2007-11-13 04:05:13 +00:00
|
|
|
|
for ( $i = 0; $i < 11 && $jDayNo >= self::$IRANIAN_DAYS[$i]; $i++ ) {
|
|
|
|
|
|
$jDayNo -= self::$IRANIAN_DAYS[$i];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$jm = $i + 1;
|
|
|
|
|
|
$jd = $jDayNo + 1;
|
2007-11-13 04:05:13 +00:00
|
|
|
|
|
2016-08-26 14:08:04 +00:00
|
|
|
|
return [ $jy, $jm, $jd, $jz ];
|
2007-11-13 04:05:13 +00:00
|
|
|
|
}
|
2010-04-08 20:19:03 +00:00
|
|
|
|
|
2008-06-19 14:46:50 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Converting Gregorian dates to Hijri dates.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Based on a PHP-Nuke block by Sharjeel which is released under GNU/GPL license
|
|
|
|
|
|
*
|
2016-10-09 17:48:14 +00:00
|
|
|
|
* @see https://phpnuke.org/modules.php?name=News&file=article&sid=8234&mode=thread&order=0&thold=0
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $ts
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2016-04-19 10:18:20 +00:00
|
|
|
|
* @return int[]
|
2008-06-19 14:46:50 +00:00
|
|
|
|
*/
|
2010-04-08 20:19:03 +00:00
|
|
|
|
private static function tsToHijri( $ts ) {
|
2008-06-19 14:46:50 +00:00
|
|
|
|
$year = substr( $ts, 0, 4 );
|
|
|
|
|
|
$month = substr( $ts, 4, 2 );
|
|
|
|
|
|
$day = substr( $ts, 6, 2 );
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2008-06-19 14:46:50 +00:00
|
|
|
|
$zyr = $year;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$zd = $day;
|
|
|
|
|
|
$zm = $month;
|
|
|
|
|
|
$zy = $zyr;
|
|
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
( $zy > 1582 ) || ( ( $zy == 1582 ) && ( $zm > 10 ) ) ||
|
|
|
|
|
|
( ( $zy == 1582 ) && ( $zm == 10 ) && ( $zd > 14 ) )
|
2013-12-01 20:39:00 +00:00
|
|
|
|
) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$zjd = (int)( ( 1461 * ( $zy + 4800 + (int)( ( $zm - 14 ) / 12 ) ) ) / 4 ) +
|
|
|
|
|
|
(int)( ( 367 * ( $zm - 2 - 12 * ( (int)( ( $zm - 14 ) / 12 ) ) ) ) / 12 ) -
|
|
|
|
|
|
(int)( ( 3 * (int)( ( ( $zy + 4900 + (int)( ( $zm - 14 ) / 12 ) ) / 100 ) ) ) / 4 ) +
|
|
|
|
|
|
$zd - 32075;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$zjd = 367 * $zy - (int)( ( 7 * ( $zy + 5001 + (int)( ( $zm - 9 ) / 7 ) ) ) / 4 ) +
|
|
|
|
|
|
(int)( ( 275 * $zm ) / 9 ) + $zd + 1729777;
|
|
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2017-08-11 13:53:17 +00:00
|
|
|
|
$zl = $zjd - 1948440 + 10632;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$zn = (int)( ( $zl - 1 ) / 10631 );
|
|
|
|
|
|
$zl = $zl - 10631 * $zn + 354;
|
2014-04-21 18:44:54 +00:00
|
|
|
|
$zj = ( (int)( ( 10985 - $zl ) / 5316 ) ) * ( (int)( ( 50 * $zl ) / 17719 ) ) +
|
|
|
|
|
|
( (int)( $zl / 5670 ) ) * ( (int)( ( 43 * $zl ) / 15238 ) );
|
|
|
|
|
|
$zl = $zl - ( (int)( ( 30 - $zj ) / 15 ) ) * ( (int)( ( 17719 * $zj ) / 50 ) ) -
|
|
|
|
|
|
( (int)( $zj / 16 ) ) * ( (int)( ( 15238 * $zj ) / 43 ) ) + 29;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$zm = (int)( ( 24 * $zl ) / 709 );
|
|
|
|
|
|
$zd = $zl - (int)( ( 709 * $zm ) / 24 );
|
|
|
|
|
|
$zy = 30 * $zn + $zj - 30;
|
2008-06-19 14:46:50 +00:00
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [ $zy, $zm, $zd ];
|
2008-06-19 14:46:50 +00:00
|
|
|
|
}
|
2007-11-13 04:05:13 +00:00
|
|
|
|
|
2007-11-13 17:17:07 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Converting Gregorian dates to Hebrew dates.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Based on a JavaScript code by Abu Mami and Yisrael Hersch
|
|
|
|
|
|
* (abu-mami@kaluach.net, http://www.kaluach.net), who permitted
|
|
|
|
|
|
* to translate the relevant functions into PHP and release them under
|
|
|
|
|
|
* GNU GPL.
|
2008-08-04 00:53:13 +00:00
|
|
|
|
*
|
2008-08-06 20:06:22 +00:00
|
|
|
|
* The months are counted from Tishrei = 1. In a leap year, Adar I is 13
|
|
|
|
|
|
* and Adar II is 14. In a non-leap year, Adar is 6.
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $ts
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2016-04-19 10:18:20 +00:00
|
|
|
|
* @return int[]
|
2007-11-13 17:17:07 +00:00
|
|
|
|
*/
|
|
|
|
|
|
private static function tsToHebrew( $ts ) {
|
|
|
|
|
|
# Parse date
|
|
|
|
|
|
$year = substr( $ts, 0, 4 );
|
|
|
|
|
|
$month = substr( $ts, 4, 2 );
|
|
|
|
|
|
$day = substr( $ts, 6, 2 );
|
|
|
|
|
|
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# Calculate Hebrew year
|
|
|
|
|
|
$hebrewYear = $year + 3760;
|
|
|
|
|
|
|
|
|
|
|
|
# Month number when September = 1, August = 12
|
|
|
|
|
|
$month += 4;
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $month > 12 ) {
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# Next year
|
|
|
|
|
|
$month -= 12;
|
|
|
|
|
|
$year++;
|
|
|
|
|
|
$hebrewYear++;
|
2007-11-13 17:17:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# Calculate day of year from 1 September
|
|
|
|
|
|
$dayOfYear = $day;
|
2010-07-29 09:43:18 +00:00
|
|
|
|
for ( $i = 1; $i < $month; $i++ ) {
|
|
|
|
|
|
if ( $i == 6 ) {
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# February
|
|
|
|
|
|
$dayOfYear += 28;
|
|
|
|
|
|
# Check if the year is leap
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $year % 400 == 0 || ( $year % 4 == 0 && $year % 100 > 0 ) ) {
|
2007-12-20 15:59:39 +00:00
|
|
|
|
$dayOfYear++;
|
|
|
|
|
|
}
|
2010-07-29 09:43:18 +00:00
|
|
|
|
} elseif ( $i == 8 || $i == 10 || $i == 1 || $i == 3 ) {
|
2007-12-20 15:59:39 +00:00
|
|
|
|
$dayOfYear += 30;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$dayOfYear += 31;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Calculate the start of the Hebrew year
|
|
|
|
|
|
$start = self::hebrewYearStart( $hebrewYear );
|
|
|
|
|
|
|
|
|
|
|
|
# Calculate next year's start
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $dayOfYear <= $start ) {
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# Day is before the start of the year - it is the previous year
|
|
|
|
|
|
# Next year's start
|
|
|
|
|
|
$nextStart = $start;
|
|
|
|
|
|
# Previous year
|
|
|
|
|
|
$year--;
|
|
|
|
|
|
$hebrewYear--;
|
|
|
|
|
|
# Add days since previous year's 1 September
|
2007-12-15 14:35:15 +00:00
|
|
|
|
$dayOfYear += 365;
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( ( $year % 400 == 0 ) || ( $year % 100 != 0 && $year % 4 == 0 ) ) {
|
2007-11-13 17:17:07 +00:00
|
|
|
|
# Leap year
|
2007-12-15 14:35:15 +00:00
|
|
|
|
$dayOfYear++;
|
2007-11-13 17:17:07 +00:00
|
|
|
|
}
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# Start of the new (previous) year
|
|
|
|
|
|
$start = self::hebrewYearStart( $hebrewYear );
|
2007-11-13 17:17:07 +00:00
|
|
|
|
} else {
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# Next year's start
|
|
|
|
|
|
$nextStart = self::hebrewYearStart( $hebrewYear + 1 );
|
2007-11-13 17:17:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# Calculate Hebrew day of year
|
|
|
|
|
|
$hebrewDayOfYear = $dayOfYear - $start;
|
|
|
|
|
|
|
|
|
|
|
|
# Difference between year's days
|
|
|
|
|
|
$diff = $nextStart - $start;
|
|
|
|
|
|
# Add 12 (or 13 for leap years) days to ignore the difference between
|
|
|
|
|
|
# Hebrew and Gregorian year (353 at least vs. 365/6) - now the
|
|
|
|
|
|
# difference is only about the year type
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( ( $year % 400 == 0 ) || ( $year % 100 != 0 && $year % 4 == 0 ) ) {
|
2007-12-20 15:59:39 +00:00
|
|
|
|
$diff += 13;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$diff += 12;
|
2007-11-13 17:17:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# Check the year pattern, and is leap year
|
2007-12-15 14:35:15 +00:00
|
|
|
|
# 0 means an incomplete year, 1 means a regular year, 2 means a complete year
|
|
|
|
|
|
# This is mod 30, to work on both leap years (which add 30 days of Adar I)
|
|
|
|
|
|
# and non-leap years
|
2007-12-20 15:59:39 +00:00
|
|
|
|
$yearPattern = $diff % 30;
|
|
|
|
|
|
# Check if leap year
|
|
|
|
|
|
$isLeap = $diff >= 30;
|
2007-12-15 14:35:15 +00:00
|
|
|
|
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# Calculate day in the month from number of day in the Hebrew year
|
2007-12-15 14:35:15 +00:00
|
|
|
|
# Don't check Adar - if the day is not in Adar, we will stop before;
|
|
|
|
|
|
# if it is in Adar, we will use it to check if it is Adar I or Adar II
|
2007-12-20 15:59:39 +00:00
|
|
|
|
$hebrewDay = $hebrewDayOfYear;
|
|
|
|
|
|
$hebrewMonth = 1;
|
|
|
|
|
|
$days = 0;
|
2010-07-29 09:43:18 +00:00
|
|
|
|
while ( $hebrewMonth <= 12 ) {
|
2007-11-13 17:17:07 +00:00
|
|
|
|
# Calculate days in this month
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $isLeap && $hebrewMonth == 6 ) {
|
2018-12-02 08:59:17 +00:00
|
|
|
|
# Leap year - has Adar I, with 30 days, and Adar II, with 29 days
|
|
|
|
|
|
$days = 30;
|
|
|
|
|
|
if ( $hebrewDay <= $days ) {
|
|
|
|
|
|
# Day in Adar I
|
|
|
|
|
|
$hebrewMonth = 13;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
# Subtract the days of Adar I
|
|
|
|
|
|
$hebrewDay -= $days;
|
|
|
|
|
|
# Try Adar II
|
|
|
|
|
|
$days = 29;
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $hebrewDay <= $days ) {
|
2018-12-02 08:59:17 +00:00
|
|
|
|
# Day in Adar II
|
|
|
|
|
|
$hebrewMonth = 14;
|
2007-12-20 15:59:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2010-07-29 09:43:18 +00:00
|
|
|
|
} elseif ( $hebrewMonth == 2 && $yearPattern == 2 ) {
|
2007-11-13 17:17:07 +00:00
|
|
|
|
# Cheshvan in a complete year (otherwise as the rule below)
|
|
|
|
|
|
$days = 30;
|
2010-07-29 09:43:18 +00:00
|
|
|
|
} elseif ( $hebrewMonth == 3 && $yearPattern == 0 ) {
|
2007-11-13 17:17:07 +00:00
|
|
|
|
# Kislev in an incomplete year (otherwise as the rule below)
|
|
|
|
|
|
$days = 29;
|
|
|
|
|
|
} else {
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# Odd months have 30 days, even have 29
|
|
|
|
|
|
$days = 30 - ( $hebrewMonth - 1 ) % 2;
|
2007-11-13 17:17:07 +00:00
|
|
|
|
}
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $hebrewDay <= $days ) {
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# In the current month
|
2007-11-13 17:17:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
} else {
|
2007-12-20 15:59:39 +00:00
|
|
|
|
# Subtract the days of the current month
|
|
|
|
|
|
$hebrewDay -= $days;
|
|
|
|
|
|
# Try in the next month
|
|
|
|
|
|
$hebrewMonth++;
|
2007-11-13 17:17:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [ $hebrewYear, $hebrewMonth, $hebrewDay, $days ];
|
2007-12-06 20:14:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2007-11-13 17:17:07 +00:00
|
|
|
|
/**
|
2007-12-20 15:59:39 +00:00
|
|
|
|
* This calculates the Hebrew year start, as days since 1 September.
|
2007-11-13 17:17:07 +00:00
|
|
|
|
* Based on Carl Friedrich Gauss algorithm for finding Easter date.
|
|
|
|
|
|
* Used for Hebrew date.
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int $year
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2007-11-13 17:17:07 +00:00
|
|
|
|
*/
|
2007-12-20 15:59:39 +00:00
|
|
|
|
private static function hebrewYearStart( $year ) {
|
|
|
|
|
|
$a = intval( ( 12 * ( $year - 1 ) + 17 ) % 19 );
|
|
|
|
|
|
$b = intval( ( $year - 1 ) % 4 );
|
2013-04-13 11:36:24 +00:00
|
|
|
|
$m = 32.044093161144 + 1.5542417966212 * $a + $b / 4.0 - 0.0031777940220923 * ( $year - 1 );
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $m < 0 ) {
|
2007-11-13 17:17:07 +00:00
|
|
|
|
$m--;
|
|
|
|
|
|
}
|
2007-11-22 09:17:13 +00:00
|
|
|
|
$Mar = intval( $m );
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $m < 0 ) {
|
2007-11-13 17:17:07 +00:00
|
|
|
|
$m++;
|
|
|
|
|
|
}
|
|
|
|
|
|
$m -= $Mar;
|
|
|
|
|
|
|
2010-07-29 09:43:18 +00:00
|
|
|
|
$c = intval( ( $Mar + 3 * ( $year - 1 ) + 5 * $b + 5 ) % 7 );
|
|
|
|
|
|
if ( $c == 0 && $a > 11 && $m >= 0.89772376543210 ) {
|
2007-11-13 17:17:07 +00:00
|
|
|
|
$Mar++;
|
2011-06-17 16:05:35 +00:00
|
|
|
|
} elseif ( $c == 1 && $a > 6 && $m >= 0.63287037037037 ) {
|
2007-11-13 17:17:07 +00:00
|
|
|
|
$Mar += 2;
|
2011-06-17 16:05:35 +00:00
|
|
|
|
} elseif ( $c == 2 || $c == 4 || $c == 6 ) {
|
2007-11-13 17:17:07 +00:00
|
|
|
|
$Mar++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2007-12-20 15:59:39 +00:00
|
|
|
|
$Mar += intval( ( $year - 3761 ) / 100 ) - intval( ( $year - 3761 ) / 400 ) - 24;
|
2007-11-13 17:17:07 +00:00
|
|
|
|
return $Mar;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2007-12-15 14:35:15 +00:00
|
|
|
|
/**
|
2009-05-20 01:53:39 +00:00
|
|
|
|
* Algorithm to convert Gregorian dates to Thai solar dates,
|
|
|
|
|
|
* Minguo dates or Minguo dates.
|
2007-12-15 14:35:15 +00:00
|
|
|
|
*
|
2016-10-09 17:48:14 +00:00
|
|
|
|
* Link: https://en.wikipedia.org/wiki/Thai_solar_calendar
|
|
|
|
|
|
* https://en.wikipedia.org/wiki/Minguo_calendar
|
|
|
|
|
|
* https://en.wikipedia.org/wiki/Japanese_era_name
|
2007-12-15 14:35:15 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $ts 14-character timestamp
|
|
|
|
|
|
* @param string $cName Calender name
|
|
|
|
|
|
* @return array Converted year, month, day
|
2007-12-15 14:35:15 +00:00
|
|
|
|
*/
|
2009-05-20 01:53:39 +00:00
|
|
|
|
private static function tsToYear( $ts, $cName ) {
|
2007-12-15 14:35:15 +00:00
|
|
|
|
$gy = substr( $ts, 0, 4 );
|
|
|
|
|
|
$gm = substr( $ts, 4, 2 );
|
|
|
|
|
|
$gd = substr( $ts, 6, 2 );
|
|
|
|
|
|
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !strcmp( $cName, 'thai' ) ) {
|
2009-05-20 01:53:39 +00:00
|
|
|
|
# Thai solar dates
|
|
|
|
|
|
# Add 543 years to the Gregorian calendar
|
|
|
|
|
|
# Months and days are identical
|
|
|
|
|
|
$gy_offset = $gy + 543;
|
2018-04-21 21:12:02 +00:00
|
|
|
|
# fix for dates between 1912 and 1941
|
|
|
|
|
|
# https://en.wikipedia.org/?oldid=836596673#New_year
|
|
|
|
|
|
if ( $gy >= 1912 && $gy <= 1940 ) {
|
|
|
|
|
|
if ( $gm <= 3 ) {
|
|
|
|
|
|
$gy_offset--;
|
|
|
|
|
|
}
|
|
|
|
|
|
$gm = ( $gm - 3 ) % 12;
|
|
|
|
|
|
}
|
2011-06-17 16:05:35 +00:00
|
|
|
|
} elseif ( ( !strcmp( $cName, 'minguo' ) ) || !strcmp( $cName, 'juche' ) ) {
|
2009-05-20 01:53:39 +00:00
|
|
|
|
# Minguo dates
|
|
|
|
|
|
# Deduct 1911 years from the Gregorian calendar
|
|
|
|
|
|
# Months and days are identical
|
|
|
|
|
|
$gy_offset = $gy - 1911;
|
2011-06-17 16:05:35 +00:00
|
|
|
|
} elseif ( !strcmp( $cName, 'tenno' ) ) {
|
2009-05-20 15:49:30 +00:00
|
|
|
|
# Nengō dates up to Meiji period
|
2009-05-20 01:53:39 +00:00
|
|
|
|
# Deduct years from the Gregorian calendar
|
|
|
|
|
|
# depending on the nengo periods
|
|
|
|
|
|
# Months and days are identical
|
2014-04-21 18:44:54 +00:00
|
|
|
|
if ( ( $gy < 1912 )
|
|
|
|
|
|
|| ( ( $gy == 1912 ) && ( $gm < 7 ) )
|
|
|
|
|
|
|| ( ( $gy == 1912 ) && ( $gm == 7 ) && ( $gd < 31 ) )
|
|
|
|
|
|
) {
|
2009-05-20 15:49:30 +00:00
|
|
|
|
# Meiji period
|
|
|
|
|
|
$gy_gannen = $gy - 1868 + 1;
|
|
|
|
|
|
$gy_offset = $gy_gannen;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( $gy_gannen == 1 ) {
|
2009-05-20 15:49:30 +00:00
|
|
|
|
$gy_offset = '元';
|
2010-04-08 20:19:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
$gy_offset = '明治' . $gy_offset;
|
2011-06-17 16:05:35 +00:00
|
|
|
|
} elseif (
|
2010-04-08 20:19:03 +00:00
|
|
|
|
( ( $gy == 1912 ) && ( $gm == 7 ) && ( $gd == 31 ) ) ||
|
|
|
|
|
|
( ( $gy == 1912 ) && ( $gm >= 8 ) ) ||
|
|
|
|
|
|
( ( $gy > 1912 ) && ( $gy < 1926 ) ) ||
|
|
|
|
|
|
( ( $gy == 1926 ) && ( $gm < 12 ) ) ||
|
|
|
|
|
|
( ( $gy == 1926 ) && ( $gm == 12 ) && ( $gd < 26 ) )
|
2013-12-01 20:39:00 +00:00
|
|
|
|
) {
|
2009-05-20 15:49:30 +00:00
|
|
|
|
# Taishō period
|
|
|
|
|
|
$gy_gannen = $gy - 1912 + 1;
|
|
|
|
|
|
$gy_offset = $gy_gannen;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( $gy_gannen == 1 ) {
|
2009-05-20 15:49:30 +00:00
|
|
|
|
$gy_offset = '元';
|
2010-04-08 20:19:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
$gy_offset = '大正' . $gy_offset;
|
2011-06-17 16:05:35 +00:00
|
|
|
|
} elseif (
|
2010-04-08 20:19:03 +00:00
|
|
|
|
( ( $gy == 1926 ) && ( $gm == 12 ) && ( $gd >= 26 ) ) ||
|
|
|
|
|
|
( ( $gy > 1926 ) && ( $gy < 1989 ) ) ||
|
|
|
|
|
|
( ( $gy == 1989 ) && ( $gm == 1 ) && ( $gd < 8 ) )
|
2013-12-01 20:39:00 +00:00
|
|
|
|
) {
|
2009-05-20 01:53:39 +00:00
|
|
|
|
# Shōwa period
|
|
|
|
|
|
$gy_gannen = $gy - 1926 + 1;
|
2009-05-20 15:08:18 +00:00
|
|
|
|
$gy_offset = $gy_gannen;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( $gy_gannen == 1 ) {
|
2009-05-20 01:53:39 +00:00
|
|
|
|
$gy_offset = '元';
|
2010-04-08 20:19:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
$gy_offset = '昭和' . $gy_offset;
|
2009-05-20 01:53:39 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
# Heisei period
|
|
|
|
|
|
$gy_gannen = $gy - 1989 + 1;
|
2009-05-20 15:08:18 +00:00
|
|
|
|
$gy_offset = $gy_gannen;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( $gy_gannen == 1 ) {
|
2009-05-20 01:53:39 +00:00
|
|
|
|
$gy_offset = '元';
|
2010-04-08 20:19:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
$gy_offset = '平成' . $gy_offset;
|
2009-05-20 01:53:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$gy_offset = $gy;
|
|
|
|
|
|
}
|
2009-05-19 16:38:21 +00:00
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [ $gy_offset, $gm, $gd ];
|
2009-05-19 16:38:21 +00:00
|
|
|
|
}
|
2007-12-15 14:35:15 +00:00
|
|
|
|
|
2015-06-29 21:48:41 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Gets directionality of the first strongly directional codepoint, for embedBidi()
|
|
|
|
|
|
*
|
|
|
|
|
|
* This is the rule the BIDI algorithm uses to determine the directionality of
|
2017-12-02 20:38:29 +00:00
|
|
|
|
* paragraphs ( https://www.unicode.org/reports/tr9/#The_Paragraph_Level ) and
|
|
|
|
|
|
* FSI isolates ( https://www.unicode.org/reports/tr9/#Explicit_Directional_Isolates ).
|
2015-06-29 21:48:41 +00:00
|
|
|
|
*
|
|
|
|
|
|
* TODO: Does not handle BIDI control characters inside the text.
|
|
|
|
|
|
* TODO: Does not handle unallocated characters.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param string $text Text to test
|
|
|
|
|
|
* @return null|string Directionality ('ltr' or 'rtl') or null
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static function strongDirFromContent( $text = '' ) {
|
|
|
|
|
|
if ( !preg_match( self::$strongDirRegex, $text, $matches ) ) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $matches[1] === '' ) {
|
|
|
|
|
|
return 'rtl';
|
|
|
|
|
|
}
|
|
|
|
|
|
return 'ltr';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-07-26 07:15:39 +00:00
|
|
|
|
/**
|
2012-07-17 22:56:51 +00:00
|
|
|
|
* Roman number formatting up to 10000
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int $num
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2006-07-26 07:15:39 +00:00
|
|
|
|
*/
|
|
|
|
|
|
static function romanNumeral( $num ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
static $table = [
|
|
|
|
|
|
[ '', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X' ],
|
|
|
|
|
|
[ '', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC', 'C' ],
|
|
|
|
|
|
[ '', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM', 'M' ],
|
|
|
|
|
|
[ '', 'M', 'MM', 'MMM', 'MMMM', 'MMMMM', 'MMMMMM', 'MMMMMMM',
|
|
|
|
|
|
'MMMMMMMM', 'MMMMMMMMM', 'MMMMMMMMMM' ]
|
|
|
|
|
|
];
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2006-07-26 07:15:39 +00:00
|
|
|
|
$num = intval( $num );
|
2012-07-17 22:56:51 +00:00
|
|
|
|
if ( $num > 10000 || $num <= 0 ) {
|
2006-07-26 07:15:39 +00:00
|
|
|
|
return $num;
|
|
|
|
|
|
}
|
2006-09-25 05:59:00 +00:00
|
|
|
|
|
2006-07-26 07:15:39 +00:00
|
|
|
|
$s = '';
|
2006-09-25 05:59:00 +00:00
|
|
|
|
for ( $pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i-- ) {
|
|
|
|
|
|
if ( $num >= $pow10 ) {
|
2011-10-18 17:27:52 +00:00
|
|
|
|
$s .= $table[$i][(int)floor( $num / $pow10 )];
|
2006-09-25 05:59:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
$num = $num % $pow10;
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
return $s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-12-19 04:31:15 +00:00
|
|
|
|
/**
|
2007-11-13 17:17:07 +00:00
|
|
|
|
* Hebrew Gematria number formatting up to 9999
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int $num
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2007-11-13 17:17:07 +00:00
|
|
|
|
*/
|
|
|
|
|
|
static function hebrewNumeral( $num ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
static $table = [
|
|
|
|
|
|
[ '', 'א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י' ],
|
|
|
|
|
|
[ '', 'י', 'כ', 'ל', 'מ', 'נ', 'ס', 'ע', 'פ', 'צ', 'ק' ],
|
|
|
|
|
|
[ '',
|
|
|
|
|
|
[ 'ק' ],
|
|
|
|
|
|
[ 'ר' ],
|
|
|
|
|
|
[ 'ש' ],
|
|
|
|
|
|
[ 'ת' ],
|
|
|
|
|
|
[ 'ת', 'ק' ],
|
|
|
|
|
|
[ 'ת', 'ר' ],
|
|
|
|
|
|
[ 'ת', 'ש' ],
|
|
|
|
|
|
[ 'ת', 'ת' ],
|
|
|
|
|
|
[ 'ת', 'ת', 'ק' ],
|
|
|
|
|
|
[ 'ת', 'ת', 'ר' ],
|
|
|
|
|
|
],
|
|
|
|
|
|
[ '', 'א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י' ]
|
|
|
|
|
|
];
|
2007-11-13 17:17:07 +00:00
|
|
|
|
|
|
|
|
|
|
$num = intval( $num );
|
|
|
|
|
|
if ( $num > 9999 || $num <= 0 ) {
|
|
|
|
|
|
return $num;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-05-21 23:26:05 +00:00
|
|
|
|
// Round thousands have special notations
|
|
|
|
|
|
if ( $num === 1000 ) {
|
|
|
|
|
|
return "א' אלף";
|
|
|
|
|
|
} elseif ( $num % 1000 === 0 ) {
|
|
|
|
|
|
return $table[0][$num / 1000] . "' אלפים";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$letters = [];
|
2015-05-21 23:26:05 +00:00
|
|
|
|
|
2007-11-13 17:17:07 +00:00
|
|
|
|
for ( $pow10 = 1000, $i = 3; $i >= 0; $pow10 /= 10, $i-- ) {
|
|
|
|
|
|
if ( $num >= $pow10 ) {
|
2015-05-21 22:21:09 +00:00
|
|
|
|
if ( $num === 15 || $num === 16 ) {
|
2015-05-21 23:26:05 +00:00
|
|
|
|
$letters[] = $table[0][9];
|
|
|
|
|
|
$letters[] = $table[0][$num - 9];
|
2007-11-13 17:17:07 +00:00
|
|
|
|
$num = 0;
|
|
|
|
|
|
} else {
|
2015-05-21 23:26:05 +00:00
|
|
|
|
$letters = array_merge(
|
|
|
|
|
|
$letters,
|
|
|
|
|
|
(array)$table[$i][intval( $num / $pow10 )]
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2015-05-21 22:21:09 +00:00
|
|
|
|
if ( $pow10 === 1000 ) {
|
2015-05-21 23:26:05 +00:00
|
|
|
|
$letters[] = "'";
|
2007-11-13 17:17:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2015-05-21 22:21:09 +00:00
|
|
|
|
|
2007-11-13 17:17:07 +00:00
|
|
|
|
$num = $num % $pow10;
|
|
|
|
|
|
}
|
2015-05-21 22:21:09 +00:00
|
|
|
|
|
2015-05-21 23:26:05 +00:00
|
|
|
|
$preTransformLength = count( $letters );
|
|
|
|
|
|
if ( $preTransformLength === 1 ) {
|
|
|
|
|
|
// Add geresh (single quote) to one-letter numbers
|
|
|
|
|
|
$letters[] = "'";
|
2013-04-17 19:10:02 +00:00
|
|
|
|
} else {
|
2015-05-21 23:26:05 +00:00
|
|
|
|
$lastIndex = $preTransformLength - 1;
|
|
|
|
|
|
$letters[$lastIndex] = str_replace(
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ 'כ', 'מ', 'נ', 'פ', 'צ' ],
|
|
|
|
|
|
[ 'ך', 'ם', 'ן', 'ף', 'ץ' ],
|
2015-05-21 23:26:05 +00:00
|
|
|
|
$letters[$lastIndex]
|
|
|
|
|
|
);
|
2015-05-21 22:21:09 +00:00
|
|
|
|
|
2015-05-21 23:26:05 +00:00
|
|
|
|
// Add gershayim (double quote) to multiple-letter numbers,
|
|
|
|
|
|
// but exclude numbers with only one letter after the thousands
|
|
|
|
|
|
// (1001-1009, 1020, 1030, 2001-2009, etc.)
|
|
|
|
|
|
if ( $letters[1] === "'" && $preTransformLength === 3 ) {
|
|
|
|
|
|
$letters[] = "'";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
array_splice( $letters, -1, 0, '"' );
|
|
|
|
|
|
}
|
2007-11-24 11:29:19 +00:00
|
|
|
|
}
|
2015-05-21 22:21:09 +00:00
|
|
|
|
|
2015-05-21 23:26:05 +00:00
|
|
|
|
return implode( $letters );
|
2007-11-13 17:17:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-10-15 19:06:31 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Used by date() and time() to adjust the time output.
|
|
|
|
|
|
*
|
2014-06-18 21:53:07 +00:00
|
|
|
|
* @param string $ts The time in date('YmdHis') format
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param mixed $tz Adjust the time by this amount (default false, mean we
|
|
|
|
|
|
* get user timecorrection setting)
|
2011-10-15 19:06:31 +00:00
|
|
|
|
* @return int
|
|
|
|
|
|
*/
|
2016-03-26 12:54:48 +00:00
|
|
|
|
public function userAdjust( $ts, $tz = false ) {
|
2011-10-15 19:06:31 +00:00
|
|
|
|
global $wgUser, $wgLocalTZoffset;
|
|
|
|
|
|
|
|
|
|
|
|
if ( $tz === false ) {
|
|
|
|
|
|
$tz = $wgUser->getOption( 'timecorrection' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$data = explode( '|', $tz, 3 );
|
|
|
|
|
|
|
|
|
|
|
|
if ( $data[0] == 'ZoneInfo' ) {
|
2016-12-25 04:55:11 +00:00
|
|
|
|
try {
|
|
|
|
|
|
$userTZ = new DateTimeZone( $data[2] );
|
|
|
|
|
|
$date = new DateTime( $ts, new DateTimeZone( 'UTC' ) );
|
|
|
|
|
|
$date->setTimezone( $userTZ );
|
|
|
|
|
|
return $date->format( 'YmdHis' );
|
|
|
|
|
|
} catch ( Exception $e ) {
|
|
|
|
|
|
// Unrecognized timezone, default to 'Offset' with the stored offset.
|
|
|
|
|
|
$data[0] = 'Offset';
|
2011-10-15 19:06:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( $data[0] == 'System' || $tz == '' ) {
|
2014-05-10 11:19:58 +00:00
|
|
|
|
# Global offset in minutes.
|
|
|
|
|
|
$minDiff = $wgLocalTZoffset;
|
2011-10-15 19:06:31 +00:00
|
|
|
|
} elseif ( $data[0] == 'Offset' ) {
|
|
|
|
|
|
$minDiff = intval( $data[1] );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$data = explode( ':', $tz );
|
|
|
|
|
|
if ( count( $data ) == 2 ) {
|
|
|
|
|
|
$data[0] = intval( $data[0] );
|
|
|
|
|
|
$data[1] = intval( $data[1] );
|
|
|
|
|
|
$minDiff = abs( $data[0] ) * 60 + $data[1];
|
|
|
|
|
|
if ( $data[0] < 0 ) {
|
|
|
|
|
|
$minDiff = -$minDiff;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$minDiff = intval( $data[0] ) * 60;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# No difference ? Return time unchanged
|
2018-06-30 09:43:00 +00:00
|
|
|
|
if ( $minDiff == 0 ) {
|
2011-10-15 19:06:31 +00:00
|
|
|
|
return $ts;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-02-10 07:52:26 +00:00
|
|
|
|
Wikimedia\suppressWarnings(); // E_STRICT system time bitching
|
2011-10-15 19:06:31 +00:00
|
|
|
|
# Generate an adjusted date; take advantage of the fact that mktime
|
|
|
|
|
|
# will normalize out-of-range values so we don't have to split $minDiff
|
|
|
|
|
|
# into hours and minutes.
|
|
|
|
|
|
$t = mktime( (
|
2013-04-17 19:10:02 +00:00
|
|
|
|
(int)substr( $ts, 8, 2 ) ), # Hours
|
|
|
|
|
|
(int)substr( $ts, 10, 2 ) + $minDiff, # Minutes
|
|
|
|
|
|
(int)substr( $ts, 12, 2 ), # Seconds
|
|
|
|
|
|
(int)substr( $ts, 4, 2 ), # Month
|
|
|
|
|
|
(int)substr( $ts, 6, 2 ), # Day
|
|
|
|
|
|
(int)substr( $ts, 0, 4 ) ); # Year
|
2011-10-15 19:06:31 +00:00
|
|
|
|
|
|
|
|
|
|
$date = date( 'YmdHis', $t );
|
2018-02-10 07:52:26 +00:00
|
|
|
|
Wikimedia\restoreWarnings();
|
2011-10-15 19:06:31 +00:00
|
|
|
|
|
|
|
|
|
|
return $date;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-04-07 19:05:42 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* This is meant to be used by time(), date(), and timeanddate() to get
|
|
|
|
|
|
* the date preference they're supposed to use, it should be used in
|
|
|
|
|
|
* all children.
|
|
|
|
|
|
*
|
2017-02-25 21:53:36 +00:00
|
|
|
|
* function timeanddate([...], $format = true) {
|
|
|
|
|
|
* $datePreference = $this->dateFormat($format);
|
|
|
|
|
|
* [...]
|
|
|
|
|
|
* }
|
2005-04-07 19:05:42 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int|string|bool $usePrefs If true, the user's preference is used
|
|
|
|
|
|
* if false, the site/language default is used
|
|
|
|
|
|
* if int/string, assumed to be a format.
|
2005-04-07 19:05:42 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2005-09-13 06:55:43 +00:00
|
|
|
|
function dateFormat( $usePrefs = true ) {
|
2006-01-10 17:46:23 +00:00
|
|
|
|
global $wgUser;
|
2005-04-13 08:37:03 +00:00
|
|
|
|
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( is_bool( $usePrefs ) ) {
|
|
|
|
|
|
if ( $usePrefs ) {
|
2006-07-26 07:15:39 +00:00
|
|
|
|
$datePreference = $wgUser->getDatePreference();
|
2005-11-08 00:57:09 +00:00
|
|
|
|
} else {
|
2010-03-27 16:15:17 +00:00
|
|
|
|
$datePreference = (string)User::getDefaultOption( 'date' );
|
2005-11-08 00:57:09 +00:00
|
|
|
|
}
|
2005-04-13 08:37:03 +00:00
|
|
|
|
} else {
|
2005-11-08 00:57:09 +00:00
|
|
|
|
$datePreference = (string)$usePrefs;
|
2005-04-07 19:05:42 +00:00
|
|
|
|
}
|
2005-09-13 06:55:43 +00:00
|
|
|
|
|
2006-01-10 12:22:58 +00:00
|
|
|
|
// return int
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $datePreference == '' ) {
|
2006-07-26 07:15:39 +00:00
|
|
|
|
return 'default';
|
2005-09-13 06:55:43 +00:00
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2005-09-13 06:55:43 +00:00
|
|
|
|
return $datePreference;
|
2005-04-07 19:05:42 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get a format string for a given type and preference
|
2015-09-01 17:19:24 +00:00
|
|
|
|
* @param string $type May be 'date', 'time', 'both', or 'pretty'.
|
|
|
|
|
|
* @param string $pref The format name as it appears in Messages*.php under
|
|
|
|
|
|
* $datePreferences.
|
2011-05-29 15:03:33 +00:00
|
|
|
|
*
|
2013-01-24 21:14:21 +00:00
|
|
|
|
* @since 1.22 New type 'pretty' that provides a more readable timestamp format
|
|
|
|
|
|
*
|
2011-05-29 15:03:33 +00:00
|
|
|
|
* @return string
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function getDateFormatString( $type, $pref ) {
|
2015-09-01 17:19:24 +00:00
|
|
|
|
$wasDefault = false;
|
|
|
|
|
|
if ( $pref == 'default' ) {
|
|
|
|
|
|
$wasDefault = true;
|
|
|
|
|
|
$pref = $this->getDefaultDateFormat();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
if ( !isset( $this->dateFormatStrings[$type][$pref] ) ) {
|
2015-09-01 17:19:24 +00:00
|
|
|
|
$df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
|
2013-01-24 21:14:21 +00:00
|
|
|
|
|
2015-09-01 17:19:24 +00:00
|
|
|
|
if ( $type === 'pretty' && $df === null ) {
|
|
|
|
|
|
$df = $this->getDateFormatString( 'date', $pref );
|
|
|
|
|
|
}
|
2013-01-24 21:14:21 +00:00
|
|
|
|
|
2015-09-01 17:19:24 +00:00
|
|
|
|
if ( !$wasDefault && $df === null ) {
|
|
|
|
|
|
$pref = $this->getDefaultDateFormat();
|
|
|
|
|
|
$df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" );
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
}
|
2015-09-01 17:19:24 +00:00
|
|
|
|
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
$this->dateFormatStrings[$type][$pref] = $df;
|
|
|
|
|
|
}
|
|
|
|
|
|
return $this->dateFormatStrings[$type][$pref];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-04-04 22:58:18 +00:00
|
|
|
|
/**
|
2014-06-18 21:53:07 +00:00
|
|
|
|
* @param string $ts The time format which needs to be turned into a
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* date('YmdHis') format with wfTimestamp(TS_MW,$ts)
|
|
|
|
|
|
* @param bool $adj Whether to adjust the time output according to the
|
|
|
|
|
|
* user configured offset ($timecorrection)
|
|
|
|
|
|
* @param mixed $format True to use user's date format preference
|
|
|
|
|
|
* @param string|bool $timecorrection The time offset as returned by
|
|
|
|
|
|
* validateTimeZone() in Special:Preferences
|
2005-04-04 22:58:18 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2016-03-26 12:54:48 +00:00
|
|
|
|
public function date( $ts, $adj = false, $format = true, $timecorrection = false ) {
|
2010-10-14 15:59:20 +00:00
|
|
|
|
$ts = wfTimestamp( TS_MW, $ts );
|
2010-01-11 04:23:41 +00:00
|
|
|
|
if ( $adj ) {
|
|
|
|
|
|
$ts = $this->userAdjust( $ts, $timecorrection );
|
2006-01-10 12:22:58 +00:00
|
|
|
|
}
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
$df = $this->getDateFormatString( 'date', $this->dateFormat( $format ) );
|
|
|
|
|
|
return $this->sprintfDate( $df, $ts );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
2005-04-04 22:58:18 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
2014-06-18 21:53:07 +00:00
|
|
|
|
* @param string $ts The time format which needs to be turned into a
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* date('YmdHis') format with wfTimestamp(TS_MW,$ts)
|
|
|
|
|
|
* @param bool $adj Whether to adjust the time output according to the
|
|
|
|
|
|
* user configured offset ($timecorrection)
|
|
|
|
|
|
* @param mixed $format True to use user's date format preference
|
|
|
|
|
|
* @param string|bool $timecorrection The time offset as returned by
|
|
|
|
|
|
* validateTimeZone() in Special:Preferences
|
2008-05-21 18:18:58 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2016-03-26 12:54:48 +00:00
|
|
|
|
public function time( $ts, $adj = false, $format = true, $timecorrection = false ) {
|
2010-10-14 15:59:20 +00:00
|
|
|
|
$ts = wfTimestamp( TS_MW, $ts );
|
2010-01-11 04:23:41 +00:00
|
|
|
|
if ( $adj ) {
|
|
|
|
|
|
$ts = $this->userAdjust( $ts, $timecorrection );
|
2004-04-03 00:53:17 +00:00
|
|
|
|
}
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
$df = $this->getDateFormatString( 'time', $this->dateFormat( $format ) );
|
|
|
|
|
|
return $this->sprintfDate( $df, $ts );
|
2005-11-08 00:57:09 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2005-04-04 22:58:18 +00:00
|
|
|
|
/**
|
2014-06-18 21:53:07 +00:00
|
|
|
|
* @param string $ts The time format which needs to be turned into a
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* date('YmdHis') format with wfTimestamp(TS_MW,$ts)
|
|
|
|
|
|
* @param bool $adj Whether to adjust the time output according to the
|
|
|
|
|
|
* user configured offset ($timecorrection)
|
|
|
|
|
|
* @param mixed $format What format to return, if it's false output the
|
|
|
|
|
|
* default one (default true)
|
|
|
|
|
|
* @param string|bool $timecorrection The time offset as returned by
|
|
|
|
|
|
* validateTimeZone() in Special:Preferences
|
2008-05-21 18:18:58 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2016-03-26 12:54:48 +00:00
|
|
|
|
public function timeanddate( $ts, $adj = false, $format = true, $timecorrection = false ) {
|
2007-03-28 19:54:45 +00:00
|
|
|
|
$ts = wfTimestamp( TS_MW, $ts );
|
2010-01-11 04:23:41 +00:00
|
|
|
|
if ( $adj ) {
|
|
|
|
|
|
$ts = $this->userAdjust( $ts, $timecorrection );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
$df = $this->getDateFormatString( 'both', $this->dateFormat( $format ) );
|
|
|
|
|
|
return $this->sprintfDate( $df, $ts );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2012-04-10 13:37:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Takes a number of seconds and turns it into a text using values such as hours and minutes.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @since 1.20
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int $seconds The amount of seconds.
|
2012-04-10 13:37:03 +00:00
|
|
|
|
* @param array $chosenIntervals The intervals to enable.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
|
public function formatDuration( $seconds, array $chosenIntervals = [] ) {
|
2012-04-10 13:37:03 +00:00
|
|
|
|
$intervals = $this->getDurationIntervals( $seconds, $chosenIntervals );
|
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$segments = [];
|
2012-04-10 13:37:03 +00:00
|
|
|
|
|
|
|
|
|
|
foreach ( $intervals as $intervalName => $intervalValue ) {
|
2013-08-31 08:03:05 +00:00
|
|
|
|
// Messages: duration-seconds, duration-minutes, duration-hours, duration-days, duration-weeks,
|
|
|
|
|
|
// duration-years, duration-decades, duration-centuries, duration-millennia
|
2012-12-07 08:54:32 +00:00
|
|
|
|
$message = wfMessage( 'duration-' . $intervalName )->numParams( $intervalValue );
|
2012-04-10 13:37:03 +00:00
|
|
|
|
$segments[] = $message->inLanguage( $this )->escaped();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $this->listToText( $segments );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Takes a number of seconds and returns an array with a set of corresponding intervals.
|
2016-09-27 03:15:08 +00:00
|
|
|
|
* For example 65 will be turned into [ minutes => 1, seconds => 5 ].
|
2012-04-10 13:37:03 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @since 1.20
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int $seconds The amount of seconds.
|
2012-04-10 13:37:03 +00:00
|
|
|
|
* @param array $chosenIntervals The intervals to enable.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
|
public function getDurationIntervals( $seconds, array $chosenIntervals = [] ) {
|
2012-04-10 13:37:03 +00:00
|
|
|
|
if ( empty( $chosenIntervals ) ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$chosenIntervals = [
|
2014-04-21 18:44:54 +00:00
|
|
|
|
'millennia',
|
|
|
|
|
|
'centuries',
|
|
|
|
|
|
'decades',
|
|
|
|
|
|
'years',
|
|
|
|
|
|
'days',
|
|
|
|
|
|
'hours',
|
|
|
|
|
|
'minutes',
|
|
|
|
|
|
'seconds'
|
2016-02-17 09:09:32 +00:00
|
|
|
|
];
|
2012-04-10 13:37:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$intervals = array_intersect_key( self::$durationIntervals, array_flip( $chosenIntervals ) );
|
|
|
|
|
|
$sortedNames = array_keys( $intervals );
|
|
|
|
|
|
$smallestInterval = array_pop( $sortedNames );
|
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$segments = [];
|
2012-04-10 13:37:03 +00:00
|
|
|
|
|
|
|
|
|
|
foreach ( $intervals as $name => $length ) {
|
|
|
|
|
|
$value = floor( $seconds / $length );
|
|
|
|
|
|
|
|
|
|
|
|
if ( $value > 0 || ( $name == $smallestInterval && empty( $segments ) ) ) {
|
|
|
|
|
|
$seconds -= $value * $length;
|
|
|
|
|
|
$segments[$name] = $value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $segments;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-10-15 19:06:31 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Internal helper function for userDate(), userTime() and userTimeAndDate()
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $type Can be 'date', 'time' or 'both'
|
2014-06-18 21:53:07 +00:00
|
|
|
|
* @param string $ts The time format which needs to be turned into a
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* date('YmdHis') format with wfTimestamp(TS_MW,$ts)
|
|
|
|
|
|
* @param User $user User object used to get preferences for timezone and format
|
|
|
|
|
|
* @param array $options Array, can contain the following keys:
|
|
|
|
|
|
* - 'timecorrection': time correction, can have the following values:
|
|
|
|
|
|
* - true: use user's preference
|
|
|
|
|
|
* - false: don't use time correction
|
|
|
|
|
|
* - int: value of time correction in minutes
|
|
|
|
|
|
* - 'format': format to use, can have the following values:
|
|
|
|
|
|
* - true: use user's preference
|
|
|
|
|
|
* - false: use default preference
|
|
|
|
|
|
* - string: format to use
|
2011-12-25 02:54:02 +00:00
|
|
|
|
* @since 1.19
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @return string
|
2011-10-15 19:06:31 +00:00
|
|
|
|
*/
|
|
|
|
|
|
private function internalUserTimeAndDate( $type, $ts, User $user, array $options ) {
|
|
|
|
|
|
$ts = wfTimestamp( TS_MW, $ts );
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$options += [ 'timecorrection' => true, 'format' => true ];
|
2011-10-15 19:06:31 +00:00
|
|
|
|
if ( $options['timecorrection'] !== false ) {
|
|
|
|
|
|
if ( $options['timecorrection'] === true ) {
|
|
|
|
|
|
$offset = $user->getOption( 'timecorrection' );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$offset = $options['timecorrection'];
|
|
|
|
|
|
}
|
|
|
|
|
|
$ts = $this->userAdjust( $ts, $offset );
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $options['format'] === true ) {
|
|
|
|
|
|
$format = $user->getDatePreference();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$format = $options['format'];
|
|
|
|
|
|
}
|
|
|
|
|
|
$df = $this->getDateFormatString( $type, $this->dateFormat( $format ) );
|
|
|
|
|
|
return $this->sprintfDate( $df, $ts );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get the formatted date for the given timestamp and formatted for
|
|
|
|
|
|
* the given user.
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param mixed $ts Mixed: the time format which needs to be turned into a
|
|
|
|
|
|
* date('YmdHis') format with wfTimestamp(TS_MW,$ts)
|
|
|
|
|
|
* @param User $user User object used to get preferences for timezone and format
|
|
|
|
|
|
* @param array $options Array, can contain the following keys:
|
|
|
|
|
|
* - 'timecorrection': time correction, can have the following values:
|
|
|
|
|
|
* - true: use user's preference
|
|
|
|
|
|
* - false: don't use time correction
|
|
|
|
|
|
* - int: value of time correction in minutes
|
|
|
|
|
|
* - 'format': format to use, can have the following values:
|
|
|
|
|
|
* - true: use user's preference
|
|
|
|
|
|
* - false: use default preference
|
|
|
|
|
|
* - string: format to use
|
2011-12-25 02:54:02 +00:00
|
|
|
|
* @since 1.19
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @return string
|
2011-10-15 19:06:31 +00:00
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
|
public function userDate( $ts, User $user, array $options = [] ) {
|
2011-10-15 19:06:31 +00:00
|
|
|
|
return $this->internalUserTimeAndDate( 'date', $ts, $user, $options );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get the formatted time for the given timestamp and formatted for
|
|
|
|
|
|
* the given user.
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param mixed $ts The time format which needs to be turned into a
|
|
|
|
|
|
* date('YmdHis') format with wfTimestamp(TS_MW,$ts)
|
|
|
|
|
|
* @param User $user User object used to get preferences for timezone and format
|
|
|
|
|
|
* @param array $options Array, can contain the following keys:
|
|
|
|
|
|
* - 'timecorrection': time correction, can have the following values:
|
|
|
|
|
|
* - true: use user's preference
|
|
|
|
|
|
* - false: don't use time correction
|
|
|
|
|
|
* - int: value of time correction in minutes
|
|
|
|
|
|
* - 'format': format to use, can have the following values:
|
|
|
|
|
|
* - true: use user's preference
|
|
|
|
|
|
* - false: use default preference
|
|
|
|
|
|
* - string: format to use
|
2011-12-25 02:54:02 +00:00
|
|
|
|
* @since 1.19
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @return string
|
2011-10-15 19:06:31 +00:00
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
|
public function userTime( $ts, User $user, array $options = [] ) {
|
2011-10-15 19:06:31 +00:00
|
|
|
|
return $this->internalUserTimeAndDate( 'time', $ts, $user, $options );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get the formatted date and time for the given timestamp and formatted for
|
|
|
|
|
|
* the given user.
|
|
|
|
|
|
*
|
2014-07-24 12:55:43 +00:00
|
|
|
|
* @param mixed $ts The time format which needs to be turned into a
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* date('YmdHis') format with wfTimestamp(TS_MW,$ts)
|
|
|
|
|
|
* @param User $user User object used to get preferences for timezone and format
|
|
|
|
|
|
* @param array $options Array, can contain the following keys:
|
|
|
|
|
|
* - 'timecorrection': time correction, can have the following values:
|
|
|
|
|
|
* - true: use user's preference
|
|
|
|
|
|
* - false: don't use time correction
|
|
|
|
|
|
* - int: value of time correction in minutes
|
|
|
|
|
|
* - 'format': format to use, can have the following values:
|
|
|
|
|
|
* - true: use user's preference
|
|
|
|
|
|
* - false: use default preference
|
|
|
|
|
|
* - string: format to use
|
2011-12-25 02:54:02 +00:00
|
|
|
|
* @since 1.19
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @return string
|
2011-10-15 19:06:31 +00:00
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
|
public function userTimeAndDate( $ts, User $user, array $options = [] ) {
|
2011-10-15 19:06:31 +00:00
|
|
|
|
return $this->internalUserTimeAndDate( 'both', $ts, $user, $options );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2015-05-24 19:49:59 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get the timestamp in a human-friendly relative format, e.g., "3 days ago".
|
|
|
|
|
|
*
|
|
|
|
|
|
* Determine the difference between the timestamp and the current time, and
|
|
|
|
|
|
* generate a readable timestamp by returning "<N> <units> ago", where the
|
|
|
|
|
|
* largest possible unit is used.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @since 1.26 (Prior to 1.26 method existed but was not meant to be used directly)
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param MWTimestamp $time
|
|
|
|
|
|
* @param MWTimestamp|null $relativeTo The base timestamp to compare to (defaults to now)
|
2015-09-27 07:45:31 +00:00
|
|
|
|
* @param User|null $user User the timestamp is being generated for
|
|
|
|
|
|
* (or null to use main context's user)
|
2015-05-24 19:49:59 +00:00
|
|
|
|
* @return string Formatted timestamp
|
|
|
|
|
|
*/
|
2015-09-27 07:45:31 +00:00
|
|
|
|
public function getHumanTimestamp(
|
|
|
|
|
|
MWTimestamp $time, MWTimestamp $relativeTo = null, User $user = null
|
|
|
|
|
|
) {
|
2015-05-24 19:49:59 +00:00
|
|
|
|
if ( $relativeTo === null ) {
|
|
|
|
|
|
$relativeTo = new MWTimestamp();
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $user === null ) {
|
|
|
|
|
|
$user = RequestContext::getMain()->getUser();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Adjust for the user's timezone.
|
|
|
|
|
|
$offsetThis = $time->offsetForUser( $user );
|
|
|
|
|
|
$offsetRel = $relativeTo->offsetForUser( $user );
|
|
|
|
|
|
|
|
|
|
|
|
$ts = '';
|
2016-02-17 09:09:32 +00:00
|
|
|
|
if ( Hooks::run( 'GetHumanTimestamp', [ &$ts, $time, $relativeTo, $user, $this ] ) ) {
|
2015-05-24 19:49:59 +00:00
|
|
|
|
$ts = $this->getHumanTimestampInternal( $time, $relativeTo, $user );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Reset the timezone on the objects.
|
|
|
|
|
|
$time->timestamp->sub( $offsetThis );
|
|
|
|
|
|
$relativeTo->timestamp->sub( $offsetRel );
|
|
|
|
|
|
|
|
|
|
|
|
return $ts;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-01-24 21:14:21 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Convert an MWTimestamp into a pretty human-readable timestamp using
|
|
|
|
|
|
* the given user preferences and relative base time.
|
|
|
|
|
|
*
|
2015-05-24 19:49:59 +00:00
|
|
|
|
* @see Language::getHumanTimestamp
|
2013-01-24 21:14:21 +00:00
|
|
|
|
* @param MWTimestamp $ts Timestamp to prettify
|
|
|
|
|
|
* @param MWTimestamp $relativeTo Base timestamp
|
|
|
|
|
|
* @param User $user User preferences to use
|
|
|
|
|
|
* @return string Human timestamp
|
2015-05-24 19:49:59 +00:00
|
|
|
|
* @since 1.26
|
2013-01-24 21:14:21 +00:00
|
|
|
|
*/
|
2015-09-27 07:45:31 +00:00
|
|
|
|
private function getHumanTimestampInternal(
|
|
|
|
|
|
MWTimestamp $ts, MWTimestamp $relativeTo, User $user
|
|
|
|
|
|
) {
|
2013-01-24 21:14:21 +00:00
|
|
|
|
$diff = $ts->diff( $relativeTo );
|
2014-04-21 18:44:54 +00:00
|
|
|
|
$diffDay = (bool)( (int)$ts->timestamp->format( 'w' ) -
|
|
|
|
|
|
(int)$relativeTo->timestamp->format( 'w' ) );
|
2013-01-24 21:14:21 +00:00
|
|
|
|
$days = $diff->days ?: (int)$diffDay;
|
2014-04-21 18:44:54 +00:00
|
|
|
|
if ( $diff->invert || $days > 5
|
|
|
|
|
|
&& $ts->timestamp->format( 'Y' ) !== $relativeTo->timestamp->format( 'Y' )
|
|
|
|
|
|
) {
|
2013-01-24 21:14:21 +00:00
|
|
|
|
// Timestamps are in different years: use full timestamp
|
|
|
|
|
|
// Also do full timestamp for future dates
|
|
|
|
|
|
/**
|
2014-07-23 20:04:48 +00:00
|
|
|
|
* @todo FIXME: Add better handling of future timestamps.
|
2013-01-24 21:14:21 +00:00
|
|
|
|
*/
|
|
|
|
|
|
$format = $this->getDateFormatString( 'both', $user->getDatePreference() ?: 'default' );
|
|
|
|
|
|
$ts = $this->sprintfDate( $format, $ts->getTimestamp( TS_MW ) );
|
|
|
|
|
|
} elseif ( $days > 5 ) {
|
|
|
|
|
|
// Timestamps are in same year, but more than 5 days ago: show day and month only.
|
|
|
|
|
|
$format = $this->getDateFormatString( 'pretty', $user->getDatePreference() ?: 'default' );
|
|
|
|
|
|
$ts = $this->sprintfDate( $format, $ts->getTimestamp( TS_MW ) );
|
|
|
|
|
|
} elseif ( $days > 1 ) {
|
|
|
|
|
|
// Timestamp within the past week: show the day of the week and time
|
|
|
|
|
|
$format = $this->getDateFormatString( 'time', $user->getDatePreference() ?: 'default' );
|
|
|
|
|
|
$weekday = self::$mWeekdayMsgs[$ts->timestamp->format( 'w' )];
|
2013-09-22 02:33:50 +00:00
|
|
|
|
// Messages:
|
|
|
|
|
|
// sunday-at, monday-at, tuesday-at, wednesday-at, thursday-at, friday-at, saturday-at
|
2013-01-24 21:14:21 +00:00
|
|
|
|
$ts = wfMessage( "$weekday-at" )
|
|
|
|
|
|
->inLanguage( $this )
|
|
|
|
|
|
->params( $this->sprintfDate( $format, $ts->getTimestamp( TS_MW ) ) )
|
|
|
|
|
|
->text();
|
|
|
|
|
|
} elseif ( $days == 1 ) {
|
|
|
|
|
|
// Timestamp was yesterday: say 'yesterday' and the time.
|
|
|
|
|
|
$format = $this->getDateFormatString( 'time', $user->getDatePreference() ?: 'default' );
|
|
|
|
|
|
$ts = wfMessage( 'yesterday-at' )
|
|
|
|
|
|
->inLanguage( $this )
|
|
|
|
|
|
->params( $this->sprintfDate( $format, $ts->getTimestamp( TS_MW ) ) )
|
|
|
|
|
|
->text();
|
|
|
|
|
|
} elseif ( $diff->h > 1 || $diff->h == 1 && $diff->i > 30 ) {
|
|
|
|
|
|
// Timestamp was today, but more than 90 minutes ago: say 'today' and the time.
|
|
|
|
|
|
$format = $this->getDateFormatString( 'time', $user->getDatePreference() ?: 'default' );
|
|
|
|
|
|
$ts = wfMessage( 'today-at' )
|
|
|
|
|
|
->inLanguage( $this )
|
|
|
|
|
|
->params( $this->sprintfDate( $format, $ts->getTimestamp( TS_MW ) ) )
|
|
|
|
|
|
->text();
|
|
|
|
|
|
|
|
|
|
|
|
// From here on in, the timestamp was soon enough ago so that we can simply say
|
|
|
|
|
|
// XX units ago, e.g., "2 hours ago" or "5 minutes ago"
|
|
|
|
|
|
} elseif ( $diff->h == 1 ) {
|
|
|
|
|
|
// Less than 90 minutes, but more than an hour ago.
|
|
|
|
|
|
$ts = wfMessage( 'hours-ago' )->inLanguage( $this )->numParams( 1 )->text();
|
|
|
|
|
|
} elseif ( $diff->i >= 1 ) {
|
|
|
|
|
|
// A few minutes ago.
|
|
|
|
|
|
$ts = wfMessage( 'minutes-ago' )->inLanguage( $this )->numParams( $diff->i )->text();
|
|
|
|
|
|
} elseif ( $diff->s >= 30 ) {
|
|
|
|
|
|
// Less than a minute, but more than 30 sec ago.
|
|
|
|
|
|
$ts = wfMessage( 'seconds-ago' )->inLanguage( $this )->numParams( $diff->s )->text();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Less than 30 seconds ago.
|
|
|
|
|
|
$ts = wfMessage( 'just-now' )->text();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $ts;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $key
|
2016-12-08 05:04:53 +00:00
|
|
|
|
* @return string|null
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*/
|
2016-03-26 12:54:48 +00:00
|
|
|
|
public function getMessage( $key ) {
|
2011-02-16 14:18:43 +00:00
|
|
|
|
return self::$dataCache->getSubitem( $this->mCode, 'messages', $key );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
2004-07-08 15:40:27 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2004-11-21 07:36:46 +00:00
|
|
|
|
function getAllMessages() {
|
2011-02-16 14:18:43 +00:00
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'messages' );
|
2003-09-21 13:10:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $in
|
|
|
|
|
|
* @param string $out
|
|
|
|
|
|
* @param string $string
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2016-03-26 12:54:48 +00:00
|
|
|
|
public function iconv( $in, $out, $string ) {
|
2009-07-07 09:56:53 +00:00
|
|
|
|
# Even with //IGNORE iconv can whine about illegal characters in
|
|
|
|
|
|
# *input* string. We just ignore those too.
|
2016-10-09 17:48:14 +00:00
|
|
|
|
# REF: https://bugs.php.net/bug.php?id=37166
|
2015-09-12 13:54:13 +00:00
|
|
|
|
# REF: https://phabricator.wikimedia.org/T18885
|
2018-02-10 07:52:26 +00:00
|
|
|
|
Wikimedia\suppressWarnings();
|
2009-07-07 09:56:53 +00:00
|
|
|
|
$text = iconv( $in, $out . '//IGNORE', $string );
|
2018-02-10 07:52:26 +00:00
|
|
|
|
Wikimedia\restoreWarnings();
|
2009-07-07 09:56:53 +00:00
|
|
|
|
return $text;
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
2004-07-08 15:40:27 +00:00
|
|
|
|
|
2016-04-07 10:01:45 +00:00
|
|
|
|
// callback functions for ucwords(), ucwordbreaks()
|
2011-05-29 15:40:17 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param array $matches
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return mixed|string
|
|
|
|
|
|
*/
|
2010-04-08 20:19:03 +00:00
|
|
|
|
function ucwordbreaksCallbackAscii( $matches ) {
|
|
|
|
|
|
return $this->ucfirst( $matches[1] );
|
2006-09-20 10:22:12 +00:00
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param array $matches
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2010-04-08 20:19:03 +00:00
|
|
|
|
function ucwordbreaksCallbackMB( $matches ) {
|
|
|
|
|
|
return mb_strtoupper( $matches[0] );
|
2006-09-20 10:22:12 +00:00
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param array $matches
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2010-04-08 20:19:03 +00:00
|
|
|
|
function ucwordsCallbackMB( $matches ) {
|
|
|
|
|
|
return mb_strtoupper( $matches[0] );
|
2006-09-20 10:22:12 +00:00
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2010-09-02 18:05:58 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Make a string's first character uppercase
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $str
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2010-09-02 18:05:58 +00:00
|
|
|
|
*/
|
2016-03-26 12:54:48 +00:00
|
|
|
|
public function ucfirst( $str ) {
|
Reverted breakage of non-ASCII message keys, Domas says that's not allowed. Optimised Language::lcfirst and Language::ucfirst() instead.
Timings in microseconds for ASCII no-change, ASCII change, non-ASCII no-change, non-ASCII change:
lcfirst: 1.8, 3.6, 21.2, 22.1
ucfirst: 1.5, 2.3, 21.1, 21.7
2009-08-28 17:58:54 +00:00
|
|
|
|
$o = ord( $str );
|
2010-09-02 18:05:58 +00:00
|
|
|
|
if ( $o < 96 ) { // if already uppercase...
|
Reverted breakage of non-ASCII message keys, Domas says that's not allowed. Optimised Language::lcfirst and Language::ucfirst() instead.
Timings in microseconds for ASCII no-change, ASCII change, non-ASCII no-change, non-ASCII change:
lcfirst: 1.8, 3.6, 21.2, 22.1
ucfirst: 1.5, 2.3, 21.1, 21.7
2009-08-28 17:58:54 +00:00
|
|
|
|
return $str;
|
|
|
|
|
|
} elseif ( $o < 128 ) {
|
2010-09-02 18:05:58 +00:00
|
|
|
|
return ucfirst( $str ); // use PHP's ucfirst()
|
Reverted breakage of non-ASCII message keys, Domas says that's not allowed. Optimised Language::lcfirst and Language::ucfirst() instead.
Timings in microseconds for ASCII no-change, ASCII change, non-ASCII no-change, non-ASCII change:
lcfirst: 1.8, 3.6, 21.2, 22.1
ucfirst: 1.5, 2.3, 21.1, 21.7
2009-08-28 17:58:54 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
// fall back to more complex logic in case of multibyte strings
|
2010-09-02 21:38:45 +00:00
|
|
|
|
return $this->uc( $str, true );
|
Reverted breakage of non-ASCII message keys, Domas says that's not allowed. Optimised Language::lcfirst and Language::ucfirst() instead.
Timings in microseconds for ASCII no-change, ASCII change, non-ASCII no-change, non-ASCII change:
lcfirst: 1.8, 3.6, 21.2, 22.1
ucfirst: 1.5, 2.3, 21.1, 21.7
2009-08-28 17:58:54 +00:00
|
|
|
|
}
|
2006-06-09 23:23:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-09-02 18:05:58 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Convert a string to uppercase
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $str
|
|
|
|
|
|
* @param bool $first
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2010-09-02 18:05:58 +00:00
|
|
|
|
*/
|
2016-03-26 12:54:48 +00:00
|
|
|
|
public function uc( $str, $first = false ) {
|
2016-04-07 10:01:45 +00:00
|
|
|
|
if ( $first ) {
|
2010-07-25 18:13:56 +00:00
|
|
|
|
if ( $this->isMultibyte( $str ) ) {
|
2016-04-07 10:01:45 +00:00
|
|
|
|
return mb_strtoupper( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 );
|
2007-01-12 07:26:32 +00:00
|
|
|
|
} else {
|
2016-04-07 10:01:45 +00:00
|
|
|
|
return ucfirst( $str );
|
2007-01-12 07:26:32 +00:00
|
|
|
|
}
|
2016-04-07 10:01:45 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
return $this->isMultibyte( $str ) ? mb_strtoupper( $str ) : strtoupper( $str );
|
2007-01-12 07:26:32 +00:00
|
|
|
|
}
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $str
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return mixed|string
|
|
|
|
|
|
*/
|
2006-07-26 07:15:39 +00:00
|
|
|
|
function lcfirst( $str ) {
|
Reverted breakage of non-ASCII message keys, Domas says that's not allowed. Optimised Language::lcfirst and Language::ucfirst() instead.
Timings in microseconds for ASCII no-change, ASCII change, non-ASCII no-change, non-ASCII change:
lcfirst: 1.8, 3.6, 21.2, 22.1
ucfirst: 1.5, 2.3, 21.1, 21.7
2009-08-28 17:58:54 +00:00
|
|
|
|
$o = ord( $str );
|
|
|
|
|
|
if ( !$o ) {
|
|
|
|
|
|
return strval( $str );
|
|
|
|
|
|
} elseif ( $o >= 128 ) {
|
2010-07-25 18:13:56 +00:00
|
|
|
|
return $this->lc( $str, true );
|
Reverted breakage of non-ASCII message keys, Domas says that's not allowed. Optimised Language::lcfirst and Language::ucfirst() instead.
Timings in microseconds for ASCII no-change, ASCII change, non-ASCII no-change, non-ASCII change:
lcfirst: 1.8, 3.6, 21.2, 22.1
ucfirst: 1.5, 2.3, 21.1, 21.7
2009-08-28 17:58:54 +00:00
|
|
|
|
} elseif ( $o > 96 ) {
|
|
|
|
|
|
return $str;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$str[0] = strtolower( $str[0] );
|
2007-11-12 22:34:39 +00:00
|
|
|
|
return $str;
|
|
|
|
|
|
}
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $str
|
|
|
|
|
|
* @param bool $first
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return mixed|string
|
|
|
|
|
|
*/
|
2006-07-26 07:15:39 +00:00
|
|
|
|
function lc( $str, $first = false ) {
|
2016-04-07 10:01:45 +00:00
|
|
|
|
if ( $first ) {
|
2010-07-25 18:13:56 +00:00
|
|
|
|
if ( $this->isMultibyte( $str ) ) {
|
2016-04-07 10:01:45 +00:00
|
|
|
|
return mb_strtolower( mb_substr( $str, 0, 1 ) ) . mb_substr( $str, 1 );
|
2010-04-08 20:19:03 +00:00
|
|
|
|
} else {
|
2016-04-07 10:01:45 +00:00
|
|
|
|
return strtolower( substr( $str, 0, 1 ) ) . substr( $str, 1 );
|
2010-04-08 20:19:03 +00:00
|
|
|
|
}
|
2016-04-07 10:01:45 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
return $this->isMultibyte( $str ) ? mb_strtolower( $str ) : strtolower( $str );
|
2010-04-08 20:19:03 +00:00
|
|
|
|
}
|
2006-06-09 23:23:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $str
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return bool
|
|
|
|
|
|
*/
|
2006-07-26 07:15:39 +00:00
|
|
|
|
function isMultibyte( $str ) {
|
2015-08-26 01:13:14 +00:00
|
|
|
|
return strlen( $str ) !== mb_strlen( $str );
|
2005-10-22 19:39:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $str
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return mixed|string
|
|
|
|
|
|
*/
|
2010-04-08 20:19:03 +00:00
|
|
|
|
function ucwords( $str ) {
|
2010-07-25 18:13:56 +00:00
|
|
|
|
if ( $this->isMultibyte( $str ) ) {
|
|
|
|
|
|
$str = $this->lc( $str );
|
2006-09-20 10:22:12 +00:00
|
|
|
|
|
|
|
|
|
|
// regexp to find first letter in each word (i.e. after each space)
|
|
|
|
|
|
$replaceRegexp = "/^([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)| ([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/";
|
|
|
|
|
|
|
|
|
|
|
|
// function to use to capitalize a single char
|
2016-04-07 10:01:45 +00:00
|
|
|
|
return preg_replace_callback(
|
|
|
|
|
|
$replaceRegexp,
|
|
|
|
|
|
[ $this, 'ucwordsCallbackMB' ],
|
|
|
|
|
|
$str
|
|
|
|
|
|
);
|
2010-04-08 20:19:03 +00:00
|
|
|
|
} else {
|
2006-09-20 10:22:12 +00:00
|
|
|
|
return ucwords( strtolower( $str ) );
|
2010-04-08 20:19:03 +00:00
|
|
|
|
}
|
2006-09-20 10:22:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* capitalize words at word breaks
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $str
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return mixed
|
|
|
|
|
|
*/
|
2010-04-08 20:19:03 +00:00
|
|
|
|
function ucwordbreaks( $str ) {
|
2010-07-25 18:13:56 +00:00
|
|
|
|
if ( $this->isMultibyte( $str ) ) {
|
|
|
|
|
|
$str = $this->lc( $str );
|
2006-09-20 10:22:12 +00:00
|
|
|
|
|
|
|
|
|
|
// since \b doesn't work for UTF-8, we explicitely define word break chars
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$breaks = "[ \-\(\)\}\{\.,\?!]";
|
2006-09-20 10:22:12 +00:00
|
|
|
|
|
|
|
|
|
|
// find first letter after word break
|
2014-04-21 18:44:54 +00:00
|
|
|
|
$replaceRegexp = "/^([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)|" .
|
|
|
|
|
|
"$breaks([a-z]|[\\xc0-\\xff][\\x80-\\xbf]*)/";
|
2006-09-20 10:22:12 +00:00
|
|
|
|
|
2016-04-07 10:01:45 +00:00
|
|
|
|
return preg_replace_callback(
|
|
|
|
|
|
$replaceRegexp,
|
|
|
|
|
|
[ $this, 'ucwordbreaksCallbackMB' ],
|
|
|
|
|
|
$str
|
|
|
|
|
|
);
|
2010-04-08 20:19:03 +00:00
|
|
|
|
} else {
|
2006-09-20 10:22:12 +00:00
|
|
|
|
return preg_replace_callback(
|
2010-04-08 20:19:03 +00:00
|
|
|
|
'/\b([\w\x80-\xff]+)\b/',
|
2016-02-17 09:09:32 +00:00
|
|
|
|
[ $this, 'ucwordbreaksCallbackAscii' ],
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$str
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2006-09-20 10:22:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2006-10-30 06:25:31 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return a case-folded representation of $s
|
|
|
|
|
|
*
|
2010-01-11 04:23:41 +00:00
|
|
|
|
* This is a representation such that caseFold($s1)==caseFold($s2) if $s1
|
2006-10-30 06:25:31 +00:00
|
|
|
|
* and $s2 are the same except for the case of their characters. It is not
|
|
|
|
|
|
* necessary for the value returned to make sense when displayed.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Do *not* perform any other normalisation in this function. If a caller
|
|
|
|
|
|
* uses this function when it should be using a more general normalisation
|
|
|
|
|
|
* function, then fix the caller.
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $s
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2006-10-30 06:25:31 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function caseFold( $s ) {
|
|
|
|
|
|
return $this->uc( $s );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2019-03-21 14:26:16 +00:00
|
|
|
|
* TODO: $s is not always a string per T218883
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $s
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2003-04-14 23:10:40 +00:00
|
|
|
|
function checkTitleEncoding( $s ) {
|
2019-03-21 14:26:16 +00:00
|
|
|
|
if ( is_array( $s ) ) {
|
|
|
|
|
|
throw new MWException( 'Given array to checkTitleEncoding.' );
|
|
|
|
|
|
}
|
2012-11-16 12:47:10 +00:00
|
|
|
|
if ( StringUtils::isUtf8( $s ) ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return $s;
|
|
|
|
|
|
}
|
2004-07-08 15:40:27 +00:00
|
|
|
|
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return $this->iconv( $this->fallback8bitEncoding(), 'utf-8', $s );
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2011-05-29 15:21:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2006-07-26 07:15:39 +00:00
|
|
|
|
function fallback8bitEncoding() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'fallback8bitEncoding' );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2009-06-24 02:27:51 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Most writing systems use whitespace to break up words.
|
|
|
|
|
|
* Some languages such as Chinese don't conventionally do this,
|
|
|
|
|
|
* which requires special handling when breaking up words for
|
|
|
|
|
|
* searching etc.
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return bool
|
2009-06-24 02:27:51 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function hasWordBreaks() {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2010-04-08 20:19:03 +00:00
|
|
|
|
|
2010-02-02 15:09:01 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Some languages such as Chinese require word segmentation,
|
|
|
|
|
|
* Specify such segmentation when overridden in derived class.
|
2010-04-08 20:19:03 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $string
|
|
|
|
|
|
* @return string
|
2010-02-02 15:09:01 +00:00
|
|
|
|
*/
|
2010-03-10 21:54:23 +00:00
|
|
|
|
function segmentByWord( $string ) {
|
2010-02-02 15:09:01 +00:00
|
|
|
|
return $string;
|
|
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
/**
|
2010-02-02 15:09:01 +00:00
|
|
|
|
* Some languages have special punctuation need to be normalized.
|
2010-01-18 20:54:43 +00:00
|
|
|
|
* Make such changes here.
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $string
|
|
|
|
|
|
* @return string
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
*/
|
2010-02-02 15:09:01 +00:00
|
|
|
|
function normalizeForSearch( $string ) {
|
2010-07-29 09:43:18 +00:00
|
|
|
|
return self::convertDoubleWidth( $string );
|
2008-11-25 02:39:06 +00:00
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
|
2010-01-07 04:50:32 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* convert double-width roman characters to single-width.
|
|
|
|
|
|
* range: ff00-ff5f ~= 0020-007f
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $string
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2010-01-07 04:50:32 +00:00
|
|
|
|
*/
|
|
|
|
|
|
protected static function convertDoubleWidth( $string ) {
|
2010-03-23 19:50:59 +00:00
|
|
|
|
static $full = null;
|
|
|
|
|
|
static $half = null;
|
|
|
|
|
|
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $full === null ) {
|
2010-03-23 19:50:59 +00:00
|
|
|
|
$fullWidth = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
|
|
|
|
$halfWidth = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
|
|
|
|
$full = str_split( $fullWidth, 3 );
|
|
|
|
|
|
$half = str_split( $halfWidth );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$string = str_replace( $full, $half, $string );
|
2010-01-07 04:50:32 +00:00
|
|
|
|
return $string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $string
|
|
|
|
|
|
* @param string $pattern
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2010-02-02 15:09:01 +00:00
|
|
|
|
protected static function insertSpace( $string, $pattern ) {
|
2010-01-07 04:50:32 +00:00
|
|
|
|
$string = preg_replace( $pattern, " $1 ", $string );
|
|
|
|
|
|
$string = preg_replace( '/ +/', ' ', $string );
|
|
|
|
|
|
return $string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param array $termsArray
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2004-11-29 01:22:44 +00:00
|
|
|
|
function convertForSearchResult( $termsArray ) {
|
|
|
|
|
|
# some languages, e.g. Chinese, need to do a conversion
|
|
|
|
|
|
# in order for search results to be displayed correctly
|
|
|
|
|
|
return $termsArray;
|
2005-07-03 07:15:53 +00:00
|
|
|
|
}
|
2004-11-29 01:22:44 +00:00
|
|
|
|
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
/**
|
2010-01-11 04:23:41 +00:00
|
|
|
|
* Get the first character of a string.
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $s
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2004-06-05 08:31:41 +00:00
|
|
|
|
function firstChar( $s ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$matches = [];
|
2010-04-08 20:19:03 +00:00
|
|
|
|
preg_match(
|
|
|
|
|
|
'/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
|
|
|
|
|
|
'[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})/',
|
|
|
|
|
|
$s,
|
|
|
|
|
|
$matches
|
|
|
|
|
|
);
|
2006-07-26 07:15:39 +00:00
|
|
|
|
|
2008-05-19 20:20:33 +00:00
|
|
|
|
if ( isset( $matches[1] ) ) {
|
|
|
|
|
|
if ( strlen( $matches[1] ) != 3 ) {
|
|
|
|
|
|
return $matches[1];
|
|
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2008-05-19 20:20:33 +00:00
|
|
|
|
// Break down Hangul syllables to grab the first jamo
|
2015-03-07 09:27:42 +00:00
|
|
|
|
$code = UtfNormal\Utils::utf8ToCodepoint( $matches[1] );
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( $code < 0xac00 || 0xd7a4 <= $code ) {
|
2008-05-19 20:20:33 +00:00
|
|
|
|
return $matches[1];
|
|
|
|
|
|
} elseif ( $code < 0xb098 ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{3131}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} elseif ( $code < 0xb2e4 ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{3134}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} elseif ( $code < 0xb77c ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{3137}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} elseif ( $code < 0xb9c8 ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{3139}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} elseif ( $code < 0xbc14 ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{3141}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} elseif ( $code < 0xc0ac ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{3142}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} elseif ( $code < 0xc544 ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{3145}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} elseif ( $code < 0xc790 ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{3147}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} elseif ( $code < 0xcc28 ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{3148}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} elseif ( $code < 0xce74 ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{314A}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} elseif ( $code < 0xd0c0 ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{314B}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} elseif ( $code < 0xd30c ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{314C}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} elseif ( $code < 0xd558 ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{314D}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
} else {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
return "\u{314E}";
|
2008-05-19 20:20:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return '';
|
2008-05-19 20:20:33 +00:00
|
|
|
|
}
|
2004-06-05 08:31:41 +00:00
|
|
|
|
}
|
2003-04-14 23:10:40 +00:00
|
|
|
|
|
2014-01-31 16:42:05 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @deprecated No-op since 1.28
|
|
|
|
|
|
*/
|
2005-03-14 02:00:53 +00:00
|
|
|
|
function initEncoding() {
|
2018-06-13 17:48:02 +00:00
|
|
|
|
wfDeprecated( __METHOD__, '1.28' );
|
2014-01-31 16:42:05 +00:00
|
|
|
|
// No-op.
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $s
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
2014-01-31 16:42:05 +00:00
|
|
|
|
* @deprecated No-op since 1.28
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*/
|
2003-04-14 23:10:40 +00:00
|
|
|
|
function recodeForEdit( $s ) {
|
2018-06-13 17:48:02 +00:00
|
|
|
|
wfDeprecated( __METHOD__, '1.28' );
|
2014-01-31 16:42:05 +00:00
|
|
|
|
return $s;
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $s
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
2014-01-31 16:42:05 +00:00
|
|
|
|
* @deprecated No-op since 1.28
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*/
|
2003-04-14 23:10:40 +00:00
|
|
|
|
function recodeInput( $s ) {
|
2018-06-13 17:48:02 +00:00
|
|
|
|
wfDeprecated( __METHOD__, '1.28' );
|
2014-01-31 16:42:05 +00:00
|
|
|
|
return $s;
|
2003-04-14 23:10:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-01-04 08:28:50 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Convert a UTF-8 string to normal form C. In Malayalam and Arabic, this
|
2010-01-11 04:23:41 +00:00
|
|
|
|
* also cleans up certain backwards-compatible sequences, converting them
|
2010-01-04 08:28:50 +00:00
|
|
|
|
* to the modern Unicode equivalent.
|
|
|
|
|
|
*
|
|
|
|
|
|
* This is language-specific for performance reasons only.
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $s
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2010-01-04 08:28:50 +00:00
|
|
|
|
*/
|
2018-08-01 18:49:22 +00:00
|
|
|
|
public function normalize( $s ) {
|
2010-07-08 09:15:53 +00:00
|
|
|
|
global $wgAllUnicodeFixes;
|
2015-03-07 09:27:42 +00:00
|
|
|
|
$s = UtfNormal\Validator::cleanUp( $s );
|
2010-07-08 09:15:53 +00:00
|
|
|
|
if ( $wgAllUnicodeFixes ) {
|
2018-05-19 18:08:17 +00:00
|
|
|
|
$s = $this->transformUsingPairFile( 'normalize-ar.php', $s );
|
|
|
|
|
|
$s = $this->transformUsingPairFile( 'normalize-ml.php', $s );
|
2010-07-08 09:15:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $s;
|
2010-01-04 08:28:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Transform a string using serialized data stored in the given file (which
|
|
|
|
|
|
* must be in the serialized subdirectory of $IP). The file contains pairs
|
2010-01-11 04:23:41 +00:00
|
|
|
|
* mapping source characters to destination characters.
|
2010-01-04 08:28:50 +00:00
|
|
|
|
*
|
2010-01-11 04:23:41 +00:00
|
|
|
|
* The data is cached in process memory. This will go faster if you have the
|
2010-01-04 08:28:50 +00:00
|
|
|
|
* FastStringSearch extension.
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $file
|
|
|
|
|
|
* @param string $string
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2012-03-05 19:17:55 +00:00
|
|
|
|
* @throws MWException
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
2010-01-04 08:28:50 +00:00
|
|
|
|
*/
|
2018-05-19 18:08:17 +00:00
|
|
|
|
protected function transformUsingPairFile( $file, $string ) {
|
2010-01-04 08:28:50 +00:00
|
|
|
|
if ( !isset( $this->transformData[$file] ) ) {
|
2018-05-19 18:08:17 +00:00
|
|
|
|
global $IP;
|
|
|
|
|
|
$data = require "$IP/languages/data/{$file}";
|
2010-01-04 08:28:50 +00:00
|
|
|
|
$this->transformData[$file] = new ReplacementArray( $data );
|
|
|
|
|
|
}
|
|
|
|
|
|
return $this->transformData[$file]->replace( $string );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* For right-to-left language support
|
2005-05-03 12:27:30 +00:00
|
|
|
|
*
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
* @return bool
|
|
|
|
|
|
*/
|
2010-01-11 04:23:41 +00:00
|
|
|
|
function isRTL() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'rtl' );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2009-08-22 01:24:04 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return the correct HTML 'dir' attribute value for this language.
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @return string
|
2009-08-22 01:24:04 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function getDir() {
|
|
|
|
|
|
return $this->isRTL() ? 'rtl' : 'ltr';
|
|
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2009-08-22 01:24:04 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return 'left' or 'right' as appropriate alignment for line-start
|
|
|
|
|
|
* for this language's text direction.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Should be equivalent to CSS3 'start' text-align value....
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @return string
|
2009-08-22 01:24:04 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function alignStart() {
|
|
|
|
|
|
return $this->isRTL() ? 'right' : 'left';
|
|
|
|
|
|
}
|
2010-01-11 04:23:41 +00:00
|
|
|
|
|
2009-08-22 01:24:04 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return 'right' or 'left' as appropriate alignment for line-end
|
|
|
|
|
|
* for this language's text direction.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Should be equivalent to CSS3 'end' text-align value....
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @return string
|
2009-08-22 01:24:04 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function alignEnd() {
|
|
|
|
|
|
return $this->isRTL() ? 'left' : 'right';
|
|
|
|
|
|
}
|
2006-06-20 08:11:56 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
2012-03-31 10:19:37 +00:00
|
|
|
|
* A hidden direction mark (LRM or RLM), depending on the language direction.
|
|
|
|
|
|
* Unlike getDirMark(), this function returns the character as an HTML entity.
|
|
|
|
|
|
* This function should be used when the output is guaranteed to be HTML,
|
|
|
|
|
|
* because it makes the output HTML source code more readable. When
|
|
|
|
|
|
* the output is plain text or can be escaped, getDirMark() should be used.
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param bool $opposite Get the direction mark opposite to your language
|
2012-03-31 10:19:37 +00:00
|
|
|
|
* @return string
|
2012-07-30 08:51:47 +00:00
|
|
|
|
* @since 1.20
|
2012-03-31 10:19:37 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function getDirMarkEntity( $opposite = false ) {
|
2013-04-17 19:10:02 +00:00
|
|
|
|
if ( $opposite ) {
|
|
|
|
|
|
return $this->isRTL() ? '‎' : '‏';
|
|
|
|
|
|
}
|
2012-03-31 10:19:37 +00:00
|
|
|
|
return $this->isRTL() ? '‏' : '‎';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* A hidden direction mark (LRM or RLM), depending on the language direction.
|
|
|
|
|
|
* This function produces them as invisible Unicode characters and
|
|
|
|
|
|
* the output may be hard to read and debug, so it should only be used
|
|
|
|
|
|
* when the output is plain text or can be escaped. When the output is
|
|
|
|
|
|
* HTML, use getDirMarkEntity() instead.
|
2006-06-20 08:11:56 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param bool $opposite Get the direction mark opposite to your language
|
2006-06-20 08:11:56 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-07-06 02:26:06 +00:00
|
|
|
|
function getDirMark( $opposite = false ) {
|
2017-10-07 00:26:23 +00:00
|
|
|
|
$lrm = "\u{200E}"; # LEFT-TO-RIGHT MARK, commonly abbreviated LRM
|
|
|
|
|
|
$rlm = "\u{200F}"; # RIGHT-TO-LEFT MARK, commonly abbreviated RLM
|
2013-04-17 19:10:02 +00:00
|
|
|
|
if ( $opposite ) {
|
|
|
|
|
|
return $this->isRTL() ? $lrm : $rlm;
|
|
|
|
|
|
}
|
2012-03-31 10:19:37 +00:00
|
|
|
|
return $this->isRTL() ? $rlm : $lrm;
|
2006-08-06 18:08:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:21:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2009-06-17 04:26:06 +00:00
|
|
|
|
function capitalizeAllNouns() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'capitalizeAllNouns' );
|
2009-06-17 04:26:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2006-08-06 18:08:21 +00:00
|
|
|
|
/**
|
2012-05-16 22:55:08 +00:00
|
|
|
|
* An arrow, depending on the language direction.
|
2006-08-06 18:08:21 +00:00
|
|
|
|
*
|
2014-04-21 18:44:54 +00:00
|
|
|
|
* @param string $direction The direction of the arrow: forwards (default),
|
|
|
|
|
|
* backwards, left, right, up, down.
|
2006-08-06 18:08:21 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2012-05-16 22:55:08 +00:00
|
|
|
|
function getArrow( $direction = 'forwards' ) {
|
|
|
|
|
|
switch ( $direction ) {
|
2017-12-11 03:07:50 +00:00
|
|
|
|
case 'forwards':
|
|
|
|
|
|
return $this->isRTL() ? '←' : '→';
|
|
|
|
|
|
case 'backwards':
|
|
|
|
|
|
return $this->isRTL() ? '→' : '←';
|
|
|
|
|
|
case 'left':
|
|
|
|
|
|
return '←';
|
|
|
|
|
|
case 'right':
|
|
|
|
|
|
return '→';
|
|
|
|
|
|
case 'up':
|
|
|
|
|
|
return '↑';
|
|
|
|
|
|
case 'down':
|
|
|
|
|
|
return '↓';
|
2012-05-16 22:55:08 +00:00
|
|
|
|
}
|
2006-08-06 18:08:21 +00:00
|
|
|
|
}
|
2003-08-31 09:46:37 +00:00
|
|
|
|
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* To allow "foo[[bar]]" to extend the link over the whole word "foobar"
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return bool
|
|
|
|
|
|
*/
|
2006-08-06 18:08:21 +00:00
|
|
|
|
function linkPrefixExtension() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'linkPrefixExtension' );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
2004-02-15 10:05:52 +00:00
|
|
|
|
|
2011-05-29 15:21:03 +00:00
|
|
|
|
/**
|
2013-05-29 10:21:42 +00:00
|
|
|
|
* Get all magic words from cache.
|
2011-05-29 15:21:03 +00:00
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
function getMagicWords() {
|
|
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'magicWords' );
|
2003-08-31 09:46:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Fill a MagicWord object with data from here
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param MagicWord $mw
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*/
|
2009-08-21 20:18:20 +00:00
|
|
|
|
function getMagic( $mw ) {
|
2018-10-27 12:30:02 +00:00
|
|
|
|
$rawEntry = $this->mMagicExtensions[$mw->mId] ??
|
|
|
|
|
|
self::$dataCache->getSubitem( $this->mCode, 'magicWords', $mw->mId );
|
2006-07-03 03:30:28 +00:00
|
|
|
|
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( !is_array( $rawEntry ) ) {
|
2014-07-23 20:23:50 +00:00
|
|
|
|
wfWarn( "\"$rawEntry\" is not a valid magic word for \"$mw->mId\"" );
|
2007-12-06 22:16:47 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$mw->mCaseSensitive = $rawEntry[0];
|
|
|
|
|
|
$mw->mSynonyms = array_slice( $rawEntry, 1 );
|
2006-08-31 10:19:12 +00:00
|
|
|
|
}
|
2003-08-31 09:46:37 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2007-09-04 02:48:34 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Add magic words to the extension array
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param array $newWords
|
2007-09-04 02:48:34 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function addMagicWordsByLang( $newWords ) {
|
2011-08-18 16:41:07 +00:00
|
|
|
|
$fallbackChain = $this->getFallbackLanguages();
|
2007-09-04 02:48:34 +00:00
|
|
|
|
$fallbackChain = array_reverse( $fallbackChain );
|
|
|
|
|
|
foreach ( $fallbackChain as $code ) {
|
|
|
|
|
|
if ( isset( $newWords[$code] ) ) {
|
|
|
|
|
|
$this->mMagicExtensions = $newWords[$code] + $this->mMagicExtensions;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2006-10-30 06:25:31 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get special page names, as an associative array
|
2014-09-26 13:48:55 +00:00
|
|
|
|
* canonical name => array of valid names, including aliases
|
2014-04-30 18:01:16 +00:00
|
|
|
|
* @return array
|
2006-10-30 06:25:31 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function getSpecialPageAliases() {
|
2008-06-25 10:59:22 +00:00
|
|
|
|
// Cache aliases because it may be slow to load them
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
if ( is_null( $this->mExtendedSpecialPageAliases ) ) {
|
2008-06-25 10:59:22 +00:00
|
|
|
|
// Initialise array
|
2010-01-11 04:23:41 +00:00
|
|
|
|
$this->mExtendedSpecialPageAliases =
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
self::$dataCache->getItem( $this->mCode, 'specialPageAliases' );
|
2006-10-30 06:25:31 +00:00
|
|
|
|
}
|
2008-06-25 10:59:22 +00:00
|
|
|
|
|
2006-10-30 06:25:31 +00:00
|
|
|
|
return $this->mExtendedSpecialPageAliases;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-07-03 07:15:53 +00:00
|
|
|
|
/**
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
* Italic is unsuitable for some languages
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $text The text to be emphasized.
|
2005-05-03 12:27:30 +00:00
|
|
|
|
* @return string
|
* @package MediaWiki and @subpackage Language
* Documented getDefaultUserOptions(), getBookstoreList(), getNsText(),
getNsIndex(), getVariantname(), stripForSearch(), firstChar(), isRTL(),
linkPrefixExtension(), emphasize(), formatNum()
2005-04-05 11:12:30 +00:00
|
|
|
|
*/
|
2004-11-21 07:36:46 +00:00
|
|
|
|
function emphasize( $text ) {
|
2005-05-03 12:27:30 +00:00
|
|
|
|
return "<em>$text</em>";
|
2004-01-30 14:50:26 +00:00
|
|
|
|
}
|
2004-03-02 20:23:56 +00:00
|
|
|
|
|
2012-11-27 19:09:04 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Normally we output all numbers in plain en_US style, that is
|
|
|
|
|
|
* 293,291.235 for twohundredninetythreethousand-twohundredninetyone
|
|
|
|
|
|
* point twohundredthirtyfive. However this is not suitable for all
|
2016-03-08 01:14:34 +00:00
|
|
|
|
* languages, some such as Bengali (bn) want ২,৯৩,২৯১.২৩৫ and others such as
|
2012-11-27 19:09:04 +00:00
|
|
|
|
* Icelandic just want to use commas instead of dots, and dots instead
|
|
|
|
|
|
* of commas like "293.291,235".
|
|
|
|
|
|
*
|
|
|
|
|
|
* An example of this function being called:
|
|
|
|
|
|
* <code>
|
|
|
|
|
|
* wfMessage( 'message' )->numParams( $num )->text()
|
|
|
|
|
|
* </code>
|
|
|
|
|
|
*
|
2014-02-25 11:50:42 +00:00
|
|
|
|
* See $separatorTransformTable on MessageIs.php for
|
2012-11-27 19:09:04 +00:00
|
|
|
|
* the , => . and . => , implementation.
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @todo check if it's viable to use localeconv() for the decimal separator thing.
|
|
|
|
|
|
* @param int|float $number The string to be formatted, should be an integer
|
|
|
|
|
|
* or a floating point number.
|
|
|
|
|
|
* @param bool $nocommafy Set to true for special numbers like dates
|
2012-11-27 19:09:04 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function formatNum( $number, $nocommafy = false ) {
|
2006-04-29 20:07:14 +00:00
|
|
|
|
global $wgTranslateNumerals;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !$nocommafy ) {
|
|
|
|
|
|
$number = $this->commafy( $number );
|
2006-04-29 20:07:14 +00:00
|
|
|
|
$s = $this->separatorTransformTable();
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( $s ) {
|
|
|
|
|
|
$number = strtr( $number, $s );
|
|
|
|
|
|
}
|
2006-04-29 20:07:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( $wgTranslateNumerals ) {
|
2006-04-29 20:07:14 +00:00
|
|
|
|
$s = $this->digitTransformTable();
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( $s ) {
|
|
|
|
|
|
$number = strtr( $number, $s );
|
|
|
|
|
|
}
|
2006-04-29 20:07:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-06 22:55:08 +00:00
|
|
|
|
return (string)$number;
|
2004-03-06 03:03:14 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2012-11-28 10:24:45 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Front-end for non-commafied formatNum
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int|float $number The string to be formatted, should be an integer
|
2012-11-28 10:24:45 +00:00
|
|
|
|
* or a floating point number.
|
|
|
|
|
|
* @since 1.21
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function formatNumNoSeparators( $number ) {
|
|
|
|
|
|
return $this->formatNum( $number, true );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $number
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2014-04-24 02:33:58 +00:00
|
|
|
|
public function parseFormattedNumber( $number ) {
|
2006-12-23 18:58:44 +00:00
|
|
|
|
$s = $this->digitTransformTable();
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( $s ) {
|
2017-02-20 22:46:45 +00:00
|
|
|
|
// eliminate empty array values such as ''. (T66347)
|
2014-04-24 02:33:58 +00:00
|
|
|
|
$s = array_filter( $s );
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$number = strtr( $number, array_flip( $s ) );
|
|
|
|
|
|
}
|
2006-12-23 18:58:44 +00:00
|
|
|
|
|
|
|
|
|
|
$s = $this->separatorTransformTable();
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( $s ) {
|
2017-02-20 22:46:45 +00:00
|
|
|
|
// eliminate empty array values such as ''. (T66347)
|
2014-04-24 02:33:58 +00:00
|
|
|
|
$s = array_filter( $s );
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$number = strtr( $number, array_flip( $s ) );
|
|
|
|
|
|
}
|
2006-12-23 18:58:44 +00:00
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$number = strtr( $number, [ ',' => '' ] );
|
2006-12-23 18:58:44 +00:00
|
|
|
|
return $number;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-04-12 23:21:59 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Adds commas to a given number
|
2011-09-22 05:01:19 +00:00
|
|
|
|
* @since 1.19
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param mixed $number
|
2005-04-12 23:21:59 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2012-11-27 19:09:04 +00:00
|
|
|
|
function commafy( $number ) {
|
2011-09-22 05:01:19 +00:00
|
|
|
|
$digitGroupingPattern = $this->digitGroupingPattern();
|
2017-10-10 18:51:50 +00:00
|
|
|
|
$minimumGroupingDigits = $this->minimumGroupingDigits();
|
2012-11-27 19:09:04 +00:00
|
|
|
|
if ( $number === null ) {
|
2012-01-04 08:56:36 +00:00
|
|
|
|
return '';
|
|
|
|
|
|
}
|
2011-09-22 11:06:48 +00:00
|
|
|
|
|
2011-09-22 05:01:19 +00:00
|
|
|
|
if ( !$digitGroupingPattern || $digitGroupingPattern === "###,###,###" ) {
|
2017-10-10 18:51:50 +00:00
|
|
|
|
// Default grouping is at thousands, use the same for ###,###,### pattern too.
|
|
|
|
|
|
// In some languages it's conventional not to insert a thousands separator
|
|
|
|
|
|
// in numbers that are four digits long (1000-9999).
|
|
|
|
|
|
if ( $minimumGroupingDigits ) {
|
|
|
|
|
|
// Number of '#' characters after last comma in the grouping pattern.
|
|
|
|
|
|
// The pattern is hardcoded here, but this would vary for different patterns.
|
|
|
|
|
|
$primaryGroupingSize = 3;
|
|
|
|
|
|
// Maximum length of a number to suppress digit grouping for.
|
|
|
|
|
|
$maximumLength = $minimumGroupingDigits + $primaryGroupingSize - 1;
|
|
|
|
|
|
if ( preg_match( '/^\-?\d{1,' . $maximumLength . '}(\.\d+)?$/', $number ) ) {
|
|
|
|
|
|
return $number;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2012-11-27 19:09:04 +00:00
|
|
|
|
return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $number ) ) );
|
2011-09-22 11:06:48 +00:00
|
|
|
|
} else {
|
2011-09-22 05:01:19 +00:00
|
|
|
|
// Ref: http://cldr.unicode.org/translation/number-patterns
|
2011-11-11 17:23:12 +00:00
|
|
|
|
$sign = "";
|
2012-11-27 19:09:04 +00:00
|
|
|
|
if ( intval( $number ) < 0 ) {
|
2011-11-11 17:23:12 +00:00
|
|
|
|
// For negative numbers apply the algorithm like positive number and add sign.
|
2013-04-13 11:36:24 +00:00
|
|
|
|
$sign = "-";
|
2012-11-27 19:09:04 +00:00
|
|
|
|
$number = substr( $number, 1 );
|
2011-11-11 17:23:12 +00:00
|
|
|
|
}
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$integerPart = [];
|
|
|
|
|
|
$decimalPart = [];
|
2011-09-22 05:01:19 +00:00
|
|
|
|
$numMatches = preg_match_all( "/(#+)/", $digitGroupingPattern, $matches );
|
2012-11-27 19:09:04 +00:00
|
|
|
|
preg_match( "/\d+/", $number, $integerPart );
|
|
|
|
|
|
preg_match( "/\.\d*/", $number, $decimalPart );
|
2013-04-17 19:10:02 +00:00
|
|
|
|
$groupedNumber = ( count( $decimalPart ) > 0 ) ? $decimalPart[0] : "";
|
2013-04-13 11:36:24 +00:00
|
|
|
|
if ( $groupedNumber === $number ) {
|
2011-09-22 11:52:44 +00:00
|
|
|
|
// the string does not have any number part. Eg: .12345
|
2011-11-11 17:23:12 +00:00
|
|
|
|
return $sign . $groupedNumber;
|
2011-09-22 05:01:19 +00:00
|
|
|
|
}
|
2015-06-16 19:06:19 +00:00
|
|
|
|
$start = $end = ( $integerPart ) ? strlen( $integerPart[0] ) : 0;
|
2011-09-22 11:06:48 +00:00
|
|
|
|
while ( $start > 0 ) {
|
2013-04-17 19:10:02 +00:00
|
|
|
|
$match = $matches[0][$numMatches - 1];
|
2011-09-22 11:06:48 +00:00
|
|
|
|
$matchLen = strlen( $match );
|
|
|
|
|
|
$start = $end - $matchLen;
|
|
|
|
|
|
if ( $start < 0 ) {
|
|
|
|
|
|
$start = 0;
|
|
|
|
|
|
}
|
2017-08-11 13:53:17 +00:00
|
|
|
|
$groupedNumber = substr( $number, $start, $end - $start ) . $groupedNumber;
|
2011-09-22 11:06:48 +00:00
|
|
|
|
$end = $start;
|
|
|
|
|
|
if ( $numMatches > 1 ) {
|
|
|
|
|
|
// use the last pattern for the rest of the number
|
|
|
|
|
|
$numMatches--;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $start > 0 ) {
|
|
|
|
|
|
$groupedNumber = "," . $groupedNumber;
|
|
|
|
|
|
}
|
2011-09-22 05:01:19 +00:00
|
|
|
|
}
|
2011-11-11 17:23:12 +00:00
|
|
|
|
return $sign . $groupedNumber;
|
2011-09-22 05:01:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2012-11-27 19:09:04 +00:00
|
|
|
|
|
2011-09-22 05:01:19 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @return string
|
2011-09-22 05:01:19 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function digitGroupingPattern() {
|
|
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'digitGroupingPattern' );
|
2005-04-12 23:21:59 +00:00
|
|
|
|
}
|
2005-04-13 08:37:03 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2006-04-29 20:07:14 +00:00
|
|
|
|
function digitTransformTable() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'digitTransformTable' );
|
2006-04-29 20:07:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2006-04-29 20:07:14 +00:00
|
|
|
|
function separatorTransformTable() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'separatorTransformTable' );
|
2006-04-29 20:07:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-10 18:51:50 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return int|null
|
|
|
|
|
|
*/
|
|
|
|
|
|
function minimumGroupingDigits() {
|
|
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'minimumGroupingDigits' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-04-13 08:37:03 +00:00
|
|
|
|
/**
|
2008-12-27 19:58:11 +00:00
|
|
|
|
* Take a list of strings and build a locale-friendly comma-separated
|
|
|
|
|
|
* list, using the local comma-separator message.
|
|
|
|
|
|
* The last two strings are chained with an "and".
|
2005-04-13 08:37:03 +00:00
|
|
|
|
*
|
2018-07-13 18:19:51 +00:00
|
|
|
|
* @param string[] $list
|
2005-04-13 08:37:03 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2018-07-13 18:19:51 +00:00
|
|
|
|
public function listToText( array $list ) {
|
|
|
|
|
|
$itemCount = count( $list );
|
|
|
|
|
|
if ( $itemCount < 1 ) {
|
2013-01-07 09:59:16 +00:00
|
|
|
|
return '';
|
|
|
|
|
|
}
|
2018-07-13 18:19:51 +00:00
|
|
|
|
$text = array_pop( $list );
|
|
|
|
|
|
if ( $itemCount > 1 ) {
|
2014-12-06 11:16:16 +00:00
|
|
|
|
$and = $this->msg( 'and' )->escaped();
|
|
|
|
|
|
$space = $this->msg( 'word-separator' )->escaped();
|
2018-07-13 18:19:51 +00:00
|
|
|
|
$comma = '';
|
|
|
|
|
|
if ( $itemCount > 2 ) {
|
2014-12-06 11:16:16 +00:00
|
|
|
|
$comma = $this->msg( 'comma-separator' )->escaped();
|
2013-01-07 09:59:16 +00:00
|
|
|
|
}
|
2018-07-13 18:19:51 +00:00
|
|
|
|
$text = implode( $comma, $list ) . $and . $space . $text;
|
2013-01-07 09:59:16 +00:00
|
|
|
|
}
|
2018-07-13 18:19:51 +00:00
|
|
|
|
return $text;
|
2004-08-01 20:43:54 +00:00
|
|
|
|
}
|
2008-12-27 19:58:11 +00:00
|
|
|
|
|
2008-09-19 18:47:47 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Take a list of strings and build a locale-friendly comma-separated
|
|
|
|
|
|
* list, using the local comma-separator message.
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string[] $list Array of strings to put in a comma list
|
2008-09-30 16:24:23 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-11-28 19:30:34 +00:00
|
|
|
|
function commaList( array $list ) {
|
2011-12-13 15:40:15 +00:00
|
|
|
|
return implode(
|
2012-08-29 08:07:10 +00:00
|
|
|
|
wfMessage( 'comma-separator' )->inLanguage( $this )->escaped(),
|
2011-11-28 19:30:34 +00:00
|
|
|
|
$list
|
2010-04-08 20:19:03 +00:00
|
|
|
|
);
|
2008-09-30 16:24:23 +00:00
|
|
|
|
}
|
2009-03-06 10:56:37 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Take a list of strings and build a locale-friendly semicolon-separated
|
|
|
|
|
|
* list, using the local semicolon-separator message.
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string[] $list Array of strings to put in a semicolon list
|
2009-03-06 10:56:37 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-11-28 19:30:34 +00:00
|
|
|
|
function semicolonList( array $list ) {
|
2011-12-13 15:40:15 +00:00
|
|
|
|
return implode(
|
2012-08-29 08:07:10 +00:00
|
|
|
|
wfMessage( 'semicolon-separator' )->inLanguage( $this )->escaped(),
|
2011-11-28 19:30:34 +00:00
|
|
|
|
$list
|
2010-04-08 20:19:03 +00:00
|
|
|
|
);
|
2009-03-06 10:56:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2008-09-30 16:24:23 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Same as commaList, but separate it with the pipe instead.
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string[] $list Array of strings to put in a pipe list
|
2008-09-30 16:24:23 +00:00
|
|
|
|
* @return string
|
2008-09-19 18:47:47 +00:00
|
|
|
|
*/
|
2011-11-28 19:30:34 +00:00
|
|
|
|
function pipeList( array $list ) {
|
2011-12-13 15:40:15 +00:00
|
|
|
|
return implode(
|
2012-08-29 08:07:10 +00:00
|
|
|
|
wfMessage( 'pipe-separator' )->inLanguage( $this )->escaped(),
|
2011-11-28 19:30:34 +00:00
|
|
|
|
$list
|
2010-04-08 20:19:03 +00:00
|
|
|
|
);
|
2008-09-19 18:47:47 +00:00
|
|
|
|
}
|
2004-08-09 05:38:11 +00:00
|
|
|
|
|
2017-12-06 15:59:30 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Truncate a string to a specified length in bytes, appending an optional
|
|
|
|
|
|
* string (e.g. for ellipsis)
|
|
|
|
|
|
*
|
|
|
|
|
|
* If $length is negative, the string will be truncated from the beginning
|
|
|
|
|
|
*
|
|
|
|
|
|
* @since 1.31
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param string $string String to truncate
|
|
|
|
|
|
* @param int $length Maximum length in bytes
|
|
|
|
|
|
* @param string $ellipsis String to append to the end of truncated text
|
|
|
|
|
|
* @param bool $adjustLength Subtract length of ellipsis from $length
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
function truncateForDatabase( $string, $length, $ellipsis = '...', $adjustLength = true ) {
|
|
|
|
|
|
return $this->truncateInternal(
|
|
|
|
|
|
$string, $length, $ellipsis, $adjustLength, 'strlen', 'substr'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Truncate a string to a specified number of characters, appending an optional
|
|
|
|
|
|
* string (e.g. for ellipsis).
|
|
|
|
|
|
*
|
2019-03-25 16:27:47 +00:00
|
|
|
|
* This provides multibyte version of truncateForDatabase() method of this class,
|
|
|
|
|
|
* suitable for truncation based on number of characters, instead of number of bytes.
|
2017-12-06 15:59:30 +00:00
|
|
|
|
*
|
|
|
|
|
|
* If $length is negative, the string will be truncated from the beginning.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @since 1.31
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param string $string String to truncate
|
|
|
|
|
|
* @param int $length Maximum number of characters
|
|
|
|
|
|
* @param string $ellipsis String to append to the end of truncated text
|
|
|
|
|
|
* @param bool $adjustLength Subtract length of ellipsis from $length
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
function truncateForVisual( $string, $length, $ellipsis = '...', $adjustLength = true ) {
|
|
|
|
|
|
// Passing encoding to mb_strlen and mb_substr is optional.
|
|
|
|
|
|
// Encoding defaults to mb_internal_encoding(), which is set to UTF-8 in Setup.php, so
|
|
|
|
|
|
// explicit specification of encoding is skipped.
|
|
|
|
|
|
// Note: Both multibyte methods are callables invoked in truncateInternal.
|
|
|
|
|
|
return $this->truncateInternal(
|
|
|
|
|
|
$string, $length, $ellipsis, $adjustLength, 'mb_strlen', 'mb_substr'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Internal method used for truncation. This method abstracts text truncation into
|
|
|
|
|
|
* one common method, allowing users to provide length measurement function and
|
|
|
|
|
|
* function for finding substring.
|
|
|
|
|
|
*
|
|
|
|
|
|
* For usages, see truncateForDatabase and truncateForVisual.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param string $string String to truncate
|
|
|
|
|
|
* @param int $length Maximum length of final text
|
|
|
|
|
|
* @param string $ellipsis String to append to the end of truncated text
|
|
|
|
|
|
* @param bool $adjustLength Subtract length of ellipsis from $length
|
|
|
|
|
|
* @param callable $measureLength Callable function used for determining the length of text
|
|
|
|
|
|
* @param callable $getSubstring Callable function used for getting the substrings
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function truncateInternal(
|
2019-04-03 16:38:55 +00:00
|
|
|
|
$string, $length, $ellipsis, $adjustLength, callable $measureLength, callable $getSubstring
|
2017-12-06 15:59:30 +00:00
|
|
|
|
) {
|
2017-06-17 11:56:14 +00:00
|
|
|
|
# Check if there is no need to truncate
|
2017-12-06 15:59:30 +00:00
|
|
|
|
if ( $measureLength( $string ) <= abs( $length ) ) {
|
2017-06-17 11:56:14 +00:00
|
|
|
|
return $string; // no need to truncate
|
|
|
|
|
|
}
|
2017-12-06 15:59:30 +00:00
|
|
|
|
|
2009-02-13 19:13:48 +00:00
|
|
|
|
# Use the localized ellipsis character
|
2010-02-24 04:14:45 +00:00
|
|
|
|
if ( $ellipsis == '...' ) {
|
2012-08-29 08:07:10 +00:00
|
|
|
|
$ellipsis = wfMessage( 'ellipsis' )->inLanguage( $this )->escaped();
|
2009-02-13 19:13:48 +00:00
|
|
|
|
}
|
2011-03-24 03:39:21 +00:00
|
|
|
|
if ( $length == 0 ) {
|
2011-03-24 18:39:30 +00:00
|
|
|
|
return $ellipsis; // convention
|
2004-08-01 20:43:54 +00:00
|
|
|
|
}
|
2017-12-06 15:59:30 +00:00
|
|
|
|
|
2010-01-29 13:39:06 +00:00
|
|
|
|
$stringOriginal = $string;
|
2011-03-24 18:39:30 +00:00
|
|
|
|
# If ellipsis length is >= $length then we can't apply $adjustLength
|
2017-12-06 15:59:30 +00:00
|
|
|
|
if ( $adjustLength && $measureLength( $ellipsis ) >= abs( $length ) ) {
|
2011-03-24 18:39:30 +00:00
|
|
|
|
$string = $ellipsis; // this can be slightly unexpected
|
|
|
|
|
|
# Otherwise, truncate and add ellipsis...
|
2004-08-01 20:43:54 +00:00
|
|
|
|
} else {
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$ellipsisLength = $adjustLength ? $measureLength( $ellipsis ) : 0;
|
2011-03-24 18:39:30 +00:00
|
|
|
|
if ( $length > 0 ) {
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$length -= $ellipsisLength;
|
|
|
|
|
|
$string = $getSubstring( $string, 0, $length ); // xyz...
|
2011-03-24 18:39:30 +00:00
|
|
|
|
$string = $this->removeBadCharLast( $string );
|
2019-03-07 09:55:31 +00:00
|
|
|
|
$string = rtrim( $string ) . $ellipsis;
|
2011-03-24 18:39:30 +00:00
|
|
|
|
} else {
|
2017-12-06 15:59:30 +00:00
|
|
|
|
$length += $ellipsisLength;
|
|
|
|
|
|
$string = $getSubstring( $string, $length ); // ...xyz
|
2011-03-24 18:39:30 +00:00
|
|
|
|
$string = $this->removeBadCharFirst( $string );
|
2019-03-07 09:55:31 +00:00
|
|
|
|
$string = $ellipsis . ltrim( $string );
|
2011-03-24 18:39:30 +00:00
|
|
|
|
}
|
2010-02-11 21:21:22 +00:00
|
|
|
|
}
|
2017-12-06 15:59:30 +00:00
|
|
|
|
|
2017-02-20 22:46:45 +00:00
|
|
|
|
# Do not truncate if the ellipsis makes the string longer/equal (T24181).
|
2011-03-24 18:39:30 +00:00
|
|
|
|
# This check is *not* redundant if $adjustLength, due to the single case where
|
2011-05-25 15:39:47 +00:00
|
|
|
|
# LEN($ellipsis) > ABS($limit arg); $stringOriginal could be shorter than $string.
|
2017-12-06 15:59:30 +00:00
|
|
|
|
if ( $measureLength( $string ) < $measureLength( $stringOriginal ) ) {
|
2010-02-11 21:21:22 +00:00
|
|
|
|
return $string;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return $stringOriginal;
|
2004-04-26 05:14:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2004-08-27 14:55:41 +00:00
|
|
|
|
|
2010-02-24 04:14:45 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Remove bytes that represent an incomplete Unicode character
|
|
|
|
|
|
* at the end of string (e.g. bytes of the char are missing)
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $string
|
2010-02-24 04:14:45 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
protected function removeBadCharLast( $string ) {
|
2011-03-24 18:39:30 +00:00
|
|
|
|
if ( $string != '' ) {
|
|
|
|
|
|
$char = ord( $string[strlen( $string ) - 1] );
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$m = [];
|
2011-03-24 18:39:30 +00:00
|
|
|
|
if ( $char >= 0xc0 ) {
|
|
|
|
|
|
# We got the first byte only of a multibyte char; remove it.
|
|
|
|
|
|
$string = substr( $string, 0, -1 );
|
|
|
|
|
|
} elseif ( $char >= 0x80 &&
|
2015-10-27 03:17:37 +00:00
|
|
|
|
// Use the /s modifier (PCRE_DOTALL) so (.*) also matches newlines
|
2013-04-17 19:10:02 +00:00
|
|
|
|
preg_match( '/^(.*)(?:[\xe0-\xef][\x80-\xbf]|' .
|
2015-10-27 03:17:37 +00:00
|
|
|
|
'[\xf0-\xf7][\x80-\xbf]{1,2})$/s', $string, $m )
|
2013-04-17 19:10:02 +00:00
|
|
|
|
) {
|
2011-03-24 18:39:30 +00:00
|
|
|
|
# We chopped in the middle of a character; remove it
|
|
|
|
|
|
$string = $m[1];
|
|
|
|
|
|
}
|
2010-02-24 04:14:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
return $string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Remove bytes that represent an incomplete Unicode character
|
|
|
|
|
|
* at the start of string (e.g. bytes of the char are missing)
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $string
|
2010-02-24 04:14:45 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
protected function removeBadCharFirst( $string ) {
|
2011-03-24 18:39:30 +00:00
|
|
|
|
if ( $string != '' ) {
|
|
|
|
|
|
$char = ord( $string[0] );
|
|
|
|
|
|
if ( $char >= 0x80 && $char < 0xc0 ) {
|
|
|
|
|
|
# We chopped in the middle of a character; remove the whole thing
|
|
|
|
|
|
$string = preg_replace( '/^[\x80-\xbf]+/', '', $string );
|
|
|
|
|
|
}
|
2010-02-24 04:14:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
return $string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-22 22:05:18 +00:00
|
|
|
|
/**
|
2010-02-24 04:14:45 +00:00
|
|
|
|
* Truncate a string of valid HTML to a specified length in bytes,
|
|
|
|
|
|
* appending an optional string (e.g. for ellipses), and return valid HTML
|
|
|
|
|
|
*
|
|
|
|
|
|
* This is only intended for styled/linked text, such as HTML with
|
2011-03-24 18:39:30 +00:00
|
|
|
|
* tags like <span> and <a>, were the tags are self-contained (valid HTML).
|
|
|
|
|
|
* Also, this will not detect things like "display:none" CSS.
|
2010-02-24 04:14:45 +00:00
|
|
|
|
*
|
2011-03-24 02:54:11 +00:00
|
|
|
|
* Note: since 1.18 you do not need to leave extra room in $length for ellipses.
|
|
|
|
|
|
*
|
2010-10-28 02:47:48 +00:00
|
|
|
|
* @param string $text HTML string to truncate
|
2011-03-24 02:54:11 +00:00
|
|
|
|
* @param int $length (zero/positive) Maximum length (including ellipses)
|
2010-02-24 04:14:45 +00:00
|
|
|
|
* @param string $ellipsis String to append to the truncated text
|
2011-05-29 16:32:43 +00:00
|
|
|
|
* @return string
|
2010-02-24 04:14:45 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function truncateHtml( $text, $length, $ellipsis = '...' ) {
|
|
|
|
|
|
# Use the localized ellipsis character
|
|
|
|
|
|
if ( $ellipsis == '...' ) {
|
2012-08-29 08:07:10 +00:00
|
|
|
|
$ellipsis = wfMessage( 'ellipsis' )->inLanguage( $this )->escaped();
|
2010-02-24 04:14:45 +00:00
|
|
|
|
}
|
2011-03-24 18:39:30 +00:00
|
|
|
|
# Check if there is clearly no need to truncate
|
2010-02-24 04:14:45 +00:00
|
|
|
|
if ( $length <= 0 ) {
|
2011-03-24 18:39:30 +00:00
|
|
|
|
return $ellipsis; // no text shown, nothing to format (convention)
|
2010-04-08 20:19:03 +00:00
|
|
|
|
} elseif ( strlen( $text ) <= $length ) {
|
2011-03-24 18:39:30 +00:00
|
|
|
|
return $text; // string short enough even *with* HTML (short-circuit)
|
2010-02-24 04:14:45 +00:00
|
|
|
|
}
|
2011-03-24 18:39:30 +00:00
|
|
|
|
|
2011-06-28 01:09:02 +00:00
|
|
|
|
$dispLen = 0; // innerHTML legth so far
|
2010-03-07 12:32:21 +00:00
|
|
|
|
$testingEllipsis = false; // checking if ellipses will make string longer/equal?
|
2010-02-24 04:14:45 +00:00
|
|
|
|
$tagType = 0; // 0-open, 1-close
|
|
|
|
|
|
$bracketState = 0; // 1-tag start, 2-tag name, 0-neither
|
|
|
|
|
|
$entityState = 0; // 0-not entity, 1-entity
|
2011-06-28 01:09:02 +00:00
|
|
|
|
$tag = $ret = ''; // accumulated tag name, accumulated result string
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$openTags = []; // open tag stack
|
2011-06-28 01:09:02 +00:00
|
|
|
|
$maybeState = null; // possible truncation state
|
2011-03-24 18:39:30 +00:00
|
|
|
|
|
2010-07-29 09:43:18 +00:00
|
|
|
|
$textLen = strlen( $text );
|
2011-03-24 18:39:30 +00:00
|
|
|
|
$neLength = max( 0, $length - strlen( $ellipsis ) ); // non-ellipsis len if truncated
|
|
|
|
|
|
for ( $pos = 0; true; ++$pos ) {
|
|
|
|
|
|
# Consider truncation once the display length has reached the maximim.
|
2011-06-28 01:09:02 +00:00
|
|
|
|
# We check if $dispLen > 0 to grab tags for the $neLength = 0 case.
|
2011-03-24 18:39:30 +00:00
|
|
|
|
# Check that we're not in the middle of a bracket/entity...
|
2011-06-28 01:09:02 +00:00
|
|
|
|
if ( $dispLen && $dispLen >= $neLength && $bracketState == 0 && !$entityState ) {
|
2011-03-24 18:39:30 +00:00
|
|
|
|
if ( !$testingEllipsis ) {
|
|
|
|
|
|
$testingEllipsis = true;
|
|
|
|
|
|
# Save where we are; we will truncate here unless there turn out to
|
|
|
|
|
|
# be so few remaining characters that truncation is not necessary.
|
2011-06-28 01:09:02 +00:00
|
|
|
|
if ( !$maybeState ) { // already saved? ($neLength = 0 case)
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$maybeState = [ $ret, $openTags ]; // save state
|
2011-06-28 01:09:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
} elseif ( $dispLen > $length && $dispLen > strlen( $ellipsis ) ) {
|
2011-03-24 18:39:30 +00:00
|
|
|
|
# String in fact does need truncation, the truncation point was OK.
|
2011-06-28 01:09:02 +00:00
|
|
|
|
list( $ret, $openTags ) = $maybeState; // reload state
|
|
|
|
|
|
$ret = $this->removeBadCharLast( $ret ); // multi-byte char fix
|
2011-03-24 18:39:30 +00:00
|
|
|
|
$ret .= $ellipsis; // add ellipsis
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2013-04-17 19:10:02 +00:00
|
|
|
|
if ( $pos >= $textLen ) {
|
|
|
|
|
|
break; // extra iteration just for above checks
|
|
|
|
|
|
}
|
2011-03-24 18:39:30 +00:00
|
|
|
|
|
|
|
|
|
|
# Read the next char...
|
2010-02-24 04:14:45 +00:00
|
|
|
|
$ch = $text[$pos];
|
2010-04-08 20:19:03 +00:00
|
|
|
|
$lastCh = $pos ? $text[$pos - 1] : '';
|
2010-02-24 04:14:45 +00:00
|
|
|
|
$ret .= $ch; // add to result string
|
|
|
|
|
|
if ( $ch == '<' ) {
|
2010-02-26 07:11:01 +00:00
|
|
|
|
$this->truncate_endBracket( $tag, $tagType, $lastCh, $openTags ); // for bad HTML
|
2010-02-24 04:14:45 +00:00
|
|
|
|
$entityState = 0; // for bad HTML
|
|
|
|
|
|
$bracketState = 1; // tag started (checking for backslash)
|
|
|
|
|
|
} elseif ( $ch == '>' ) {
|
2010-02-26 07:11:01 +00:00
|
|
|
|
$this->truncate_endBracket( $tag, $tagType, $lastCh, $openTags );
|
2010-02-24 04:14:45 +00:00
|
|
|
|
$entityState = 0; // for bad HTML
|
|
|
|
|
|
$bracketState = 0; // out of brackets
|
|
|
|
|
|
} elseif ( $bracketState == 1 ) {
|
|
|
|
|
|
if ( $ch == '/' ) {
|
|
|
|
|
|
$tagType = 1; // close tag (e.g. "</span>")
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$tagType = 0; // open tag (e.g. "<span>")
|
|
|
|
|
|
$tag .= $ch;
|
|
|
|
|
|
}
|
|
|
|
|
|
$bracketState = 2; // building tag name
|
|
|
|
|
|
} elseif ( $bracketState == 2 ) {
|
|
|
|
|
|
if ( $ch != ' ' ) {
|
|
|
|
|
|
$tag .= $ch;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Name found (e.g. "<a href=..."), add on tag attributes...
|
2010-02-26 07:11:01 +00:00
|
|
|
|
$pos += $this->truncate_skip( $ret, $text, "<>", $pos + 1 );
|
2010-02-24 04:14:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
} elseif ( $bracketState == 0 ) {
|
|
|
|
|
|
if ( $entityState ) {
|
|
|
|
|
|
if ( $ch == ';' ) {
|
|
|
|
|
|
$entityState = 0;
|
2011-06-28 01:09:02 +00:00
|
|
|
|
$dispLen++; // entity is one displayed char
|
2010-02-24 04:14:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2011-06-28 01:09:02 +00:00
|
|
|
|
if ( $neLength == 0 && !$maybeState ) {
|
|
|
|
|
|
// Save state without $ch. We want to *hit* the first
|
|
|
|
|
|
// display char (to get tags) but not *use* it if truncating.
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$maybeState = [ substr( $ret, 0, -1 ), $openTags ];
|
2011-06-28 01:09:02 +00:00
|
|
|
|
}
|
2010-02-24 04:14:45 +00:00
|
|
|
|
if ( $ch == '&' ) {
|
2010-05-30 17:33:59 +00:00
|
|
|
|
$entityState = 1; // entity found, (e.g. " ")
|
2010-02-24 04:14:45 +00:00
|
|
|
|
} else {
|
2011-06-28 01:09:02 +00:00
|
|
|
|
$dispLen++; // this char is displayed
|
2011-03-24 18:39:30 +00:00
|
|
|
|
// Add the next $max display text chars after this in one swoop...
|
2011-06-28 01:09:02 +00:00
|
|
|
|
$max = ( $testingEllipsis ? $length : $neLength ) - $dispLen;
|
2011-03-24 18:39:30 +00:00
|
|
|
|
$skipped = $this->truncate_skip( $ret, $text, "<>&", $pos + 1, $max );
|
2011-06-28 01:09:02 +00:00
|
|
|
|
$dispLen += $skipped;
|
2010-02-24 04:14:45 +00:00
|
|
|
|
$pos += $skipped;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2010-10-28 02:47:48 +00:00
|
|
|
|
// Close the last tag if left unclosed by bad HTML
|
|
|
|
|
|
$this->truncate_endBracket( $tag, $text[$textLen - 1], $tagType, $openTags );
|
2010-02-24 04:14:45 +00:00
|
|
|
|
while ( count( $openTags ) > 0 ) {
|
|
|
|
|
|
$ret .= '</' . array_pop( $openTags ) . '>'; // close open tags
|
|
|
|
|
|
}
|
|
|
|
|
|
return $ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* truncateHtml() helper function
|
|
|
|
|
|
* like strcspn() but adds the skipped chars to $ret
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $ret
|
|
|
|
|
|
* @param string $text
|
|
|
|
|
|
* @param string $search
|
|
|
|
|
|
* @param int $start
|
|
|
|
|
|
* @param null|int $len
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return int
|
|
|
|
|
|
*/
|
2011-03-24 18:39:30 +00:00
|
|
|
|
private function truncate_skip( &$ret, $text, $search, $start, $len = null ) {
|
|
|
|
|
|
if ( $len === null ) {
|
|
|
|
|
|
$len = -1; // -1 means "no limit" for strcspn
|
|
|
|
|
|
} elseif ( $len < 0 ) {
|
|
|
|
|
|
$len = 0; // sanity
|
|
|
|
|
|
}
|
2010-02-24 04:14:45 +00:00
|
|
|
|
$skipCount = 0;
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $start < strlen( $text ) ) {
|
2010-02-24 04:14:45 +00:00
|
|
|
|
$skipCount = strcspn( $text, $search, $start, $len );
|
|
|
|
|
|
$ret .= substr( $text, $start, $skipCount );
|
|
|
|
|
|
}
|
|
|
|
|
|
return $skipCount;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-22 22:05:18 +00:00
|
|
|
|
/**
|
2010-10-28 02:47:48 +00:00
|
|
|
|
* truncateHtml() helper function
|
|
|
|
|
|
* (a) push or pop $tag from $openTags as needed
|
|
|
|
|
|
* (b) clear $tag value
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string &$tag Current HTML tag name we are looking at
|
|
|
|
|
|
* @param int $tagType (0-open tag, 1-close tag)
|
|
|
|
|
|
* @param string $lastCh Character before the '>' that ended this tag
|
|
|
|
|
|
* @param array &$openTags Open tag stack (not accounting for $tag)
|
2010-10-28 02:47:48 +00:00
|
|
|
|
*/
|
2010-02-26 07:11:01 +00:00
|
|
|
|
private function truncate_endBracket( &$tag, $tagType, $lastCh, &$openTags ) {
|
2010-02-24 04:14:45 +00:00
|
|
|
|
$tag = ltrim( $tag );
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $tag != '' ) {
|
|
|
|
|
|
if ( $tagType == 0 && $lastCh != '/' ) {
|
2010-02-24 04:14:45 +00:00
|
|
|
|
$openTags[] = $tag; // tag opened (didn't close itself)
|
2011-06-17 16:05:35 +00:00
|
|
|
|
} elseif ( $tagType == 1 ) {
|
2010-07-29 09:43:18 +00:00
|
|
|
|
if ( $openTags && $tag == $openTags[count( $openTags ) - 1] ) {
|
2010-02-24 04:14:45 +00:00
|
|
|
|
array_pop( $openTags ); // tag closed
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
$tag = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-04-13 08:37:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Grammatical transformations, needed for inflected languages
|
|
|
|
|
|
* Invoked by putting {{grammar:case|word}} in a message
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $word
|
|
|
|
|
|
* @param string $case
|
2005-04-13 08:37:03 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2004-08-27 14:55:41 +00:00
|
|
|
|
function convertGrammar( $word, $case ) {
|
2006-05-25 14:21:45 +00:00
|
|
|
|
global $wgGrammarForms;
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( isset( $wgGrammarForms[$this->getCode()][$case][$word] ) ) {
|
2008-01-02 19:58:15 +00:00
|
|
|
|
return $wgGrammarForms[$this->getCode()][$case][$word];
|
2006-05-25 14:21:45 +00:00
|
|
|
|
}
|
2014-04-21 18:44:54 +00:00
|
|
|
|
|
2015-09-28 10:26:08 +00:00
|
|
|
|
$grammarTransformations = $this->getGrammarTransformations();
|
|
|
|
|
|
|
|
|
|
|
|
if ( isset( $grammarTransformations[$case] ) ) {
|
|
|
|
|
|
$forms = $grammarTransformations[$case];
|
|
|
|
|
|
|
|
|
|
|
|
// Some names of grammar rules are aliases for other rules.
|
|
|
|
|
|
// In such cases the value is a string rather than object,
|
|
|
|
|
|
// so load the actual rules.
|
|
|
|
|
|
if ( is_string( $forms ) ) {
|
|
|
|
|
|
$forms = $grammarTransformations[$forms];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach ( array_values( $forms ) as $rule ) {
|
|
|
|
|
|
$form = $rule[0];
|
|
|
|
|
|
|
|
|
|
|
|
if ( $form === '@metadata' ) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$replacement = $rule[1];
|
|
|
|
|
|
|
|
|
|
|
|
$regex = '/' . addcslashes( $form, '/' ) . '/u';
|
|
|
|
|
|
$patternMatches = preg_match( $regex, $word );
|
|
|
|
|
|
|
|
|
|
|
|
if ( $patternMatches === false ) {
|
|
|
|
|
|
wfLogWarning(
|
|
|
|
|
|
'An error occurred while processing grammar. ' .
|
|
|
|
|
|
"Word: '$word'. Regex: /$form/."
|
|
|
|
|
|
);
|
|
|
|
|
|
} elseif ( $patternMatches === 1 ) {
|
|
|
|
|
|
$word = preg_replace( $regex, $replacement, $word );
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-08-27 14:55:41 +00:00
|
|
|
|
return $word;
|
|
|
|
|
|
}
|
2015-09-26 20:28:03 +00:00
|
|
|
|
|
2012-04-02 13:01:10 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get the grammar forms for the content language
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @return array Array of grammar forms
|
2012-04-02 13:01:10 +00:00
|
|
|
|
* @since 1.20
|
|
|
|
|
|
*/
|
|
|
|
|
|
function getGrammarForms() {
|
|
|
|
|
|
global $wgGrammarForms;
|
2014-04-21 18:44:54 +00:00
|
|
|
|
if ( isset( $wgGrammarForms[$this->getCode()] )
|
|
|
|
|
|
&& is_array( $wgGrammarForms[$this->getCode()] )
|
|
|
|
|
|
) {
|
2013-04-17 19:10:02 +00:00
|
|
|
|
return $wgGrammarForms[$this->getCode()];
|
2012-04-02 13:01:10 +00:00
|
|
|
|
}
|
2014-04-21 18:44:54 +00:00
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [];
|
2012-04-02 13:01:10 +00:00
|
|
|
|
}
|
2015-09-26 20:28:03 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get the grammar transformations data for the language.
|
|
|
|
|
|
* Used like grammar forms, with {{GRAMMAR}} and cases,
|
|
|
|
|
|
* but uses pairs of regexes and replacements instead of code.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return array[] Array of grammar transformations.
|
2016-10-21 22:34:19 +00:00
|
|
|
|
* @throws MWException
|
2015-09-26 20:28:03 +00:00
|
|
|
|
* @since 1.28
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function getGrammarTransformations() {
|
|
|
|
|
|
$languageCode = $this->getCode();
|
|
|
|
|
|
|
|
|
|
|
|
if ( self::$grammarTransformations === null ) {
|
|
|
|
|
|
self::$grammarTransformations = new MapCacheLRU( 10 );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( self::$grammarTransformations->has( $languageCode ) ) {
|
|
|
|
|
|
return self::$grammarTransformations->get( $languageCode );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$data = [];
|
|
|
|
|
|
|
|
|
|
|
|
$grammarDataFile = __DIR__ . "/data/grammarTransformations/$languageCode.json";
|
|
|
|
|
|
if ( is_readable( $grammarDataFile ) ) {
|
|
|
|
|
|
$data = FormatJson::decode(
|
|
|
|
|
|
file_get_contents( $grammarDataFile ),
|
|
|
|
|
|
true
|
|
|
|
|
|
);
|
2016-10-21 20:39:07 +00:00
|
|
|
|
|
2015-09-26 20:28:03 +00:00
|
|
|
|
if ( $data === null ) {
|
|
|
|
|
|
throw new MWException( "Invalid grammar data for \"$languageCode\"." );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self::$grammarTransformations->set( $languageCode, $data );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2009-01-26 09:48:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Provides an alternative text depending on specified gender.
|
2014-04-01 00:31:06 +00:00
|
|
|
|
* Usage {{gender:username|masculine|feminine|unknown}}.
|
2009-01-26 09:48:17 +00:00
|
|
|
|
* username is optional, in which case the gender of current user is used,
|
|
|
|
|
|
* but only in (some) interface messages; otherwise default gender is used.
|
2012-02-08 06:09:58 +00:00
|
|
|
|
*
|
|
|
|
|
|
* If no forms are given, an empty string is returned. If only one form is
|
|
|
|
|
|
* given, it will be returned unconditionally. These details are implied by
|
|
|
|
|
|
* the caller and cannot be overridden in subclasses.
|
|
|
|
|
|
*
|
2014-04-01 00:31:06 +00:00
|
|
|
|
* If three forms are given, the default is to use the third (unknown) form.
|
|
|
|
|
|
* If fewer than three forms are given, the default is to use the first (masculine) form.
|
|
|
|
|
|
* These details can be overridden in subclasses.
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $gender
|
|
|
|
|
|
* @param array $forms
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2009-01-26 09:48:17 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function gender( $gender, $forms ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( !count( $forms ) ) {
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}
|
2009-01-26 09:48:17 +00:00
|
|
|
|
$forms = $this->preConvertPlural( $forms, 2 );
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( $gender === 'male' ) {
|
|
|
|
|
|
return $forms[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $gender === 'female' ) {
|
|
|
|
|
|
return $forms[1];
|
|
|
|
|
|
}
|
2017-10-06 22:17:58 +00:00
|
|
|
|
return $forms[2] ?? $forms[0];
|
2009-01-26 09:48:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2005-09-05 19:22:09 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Plural form transformations, needed for some languages.
|
2007-10-15 10:32:54 +00:00
|
|
|
|
* For example, there are 3 form of plural in Russian and Polish,
|
2005-09-05 19:22:09 +00:00
|
|
|
|
* depending on "count mod 10". See [[w:Plural]]
|
|
|
|
|
|
* For English it is pretty simple.
|
|
|
|
|
|
*
|
2005-09-06 17:02:19 +00:00
|
|
|
|
* Invoked by putting {{plural:count|wordform1|wordform2}}
|
|
|
|
|
|
* or {{plural:count|wordform1|wordform2|wordform3}}
|
2005-09-05 19:22:09 +00:00
|
|
|
|
*
|
2006-01-07 13:09:30 +00:00
|
|
|
|
* Example: {{plural:{{NUMBEROFARTICLES}}|article|articles}}
|
2005-09-05 19:22:09 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int $count Non-localized number
|
|
|
|
|
|
* @param array $forms Different plural forms
|
2007-11-18 20:15:49 +00:00
|
|
|
|
* @return string Correct form of plural for $count in this language
|
|
|
|
|
|
*/
|
|
|
|
|
|
function convertPlural( $count, $forms ) {
|
2013-02-14 09:19:23 +00:00
|
|
|
|
// Handle explicit n=pluralform cases
|
2013-12-03 08:37:14 +00:00
|
|
|
|
$forms = $this->handleExplicitPluralForms( $count, $forms );
|
|
|
|
|
|
if ( is_string( $forms ) ) {
|
|
|
|
|
|
return $forms;
|
2012-09-16 19:13:03 +00:00
|
|
|
|
}
|
2013-05-25 23:19:55 +00:00
|
|
|
|
if ( !count( $forms ) ) {
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}
|
2012-09-16 19:13:03 +00:00
|
|
|
|
|
2013-01-25 01:10:37 +00:00
|
|
|
|
$pluralForm = $this->getPluralRuleIndexNumber( $count );
|
2012-08-29 08:07:10 +00:00
|
|
|
|
$pluralForm = min( $pluralForm, count( $forms ) - 1 );
|
|
|
|
|
|
return $forms[$pluralForm];
|
2007-11-18 20:15:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-12-03 08:37:14 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Handles explicit plural forms for Language::convertPlural()
|
|
|
|
|
|
*
|
|
|
|
|
|
* In {{PLURAL:$1|0=nothing|one|many}}, 0=nothing will be returned if $1 equals zero.
|
|
|
|
|
|
* If an explicitly defined plural form matches the $count, then
|
|
|
|
|
|
* string value returned, otherwise array returned for further consideration
|
|
|
|
|
|
* by CLDR rules or overridden convertPlural().
|
|
|
|
|
|
*
|
|
|
|
|
|
* @since 1.23
|
|
|
|
|
|
*
|
2014-07-24 12:55:43 +00:00
|
|
|
|
* @param int $count Non-localized number
|
|
|
|
|
|
* @param array $forms Different plural forms
|
2013-12-03 08:37:14 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return array|string
|
|
|
|
|
|
*/
|
|
|
|
|
|
protected function handleExplicitPluralForms( $count, array $forms ) {
|
|
|
|
|
|
foreach ( $forms as $index => $form ) {
|
|
|
|
|
|
if ( preg_match( '/\d+=/i', $form ) ) {
|
|
|
|
|
|
$pos = strpos( $form, '=' );
|
2014-07-21 12:47:42 +00:00
|
|
|
|
if ( substr( $form, 0, $pos ) === (string)$count ) {
|
2013-12-03 08:37:14 +00:00
|
|
|
|
return substr( $form, $pos + 1 );
|
|
|
|
|
|
}
|
|
|
|
|
|
unset( $forms[$index] );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return array_values( $forms );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2007-11-18 20:15:49 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Checks that convertPlural was given an array and pads it to requested
|
2011-05-01 19:20:31 +00:00
|
|
|
|
* amount of forms by copying the last one.
|
2007-11-18 20:15:49 +00:00
|
|
|
|
*
|
2019-03-27 10:36:51 +00:00
|
|
|
|
* @param array $forms
|
2014-08-13 19:41:39 +00:00
|
|
|
|
* @param int $count How many forms should there be at least
|
2019-03-27 10:36:51 +00:00
|
|
|
|
* @return array Padded array of forms
|
2005-09-05 19:22:09 +00:00
|
|
|
|
*/
|
2007-12-22 12:41:42 +00:00
|
|
|
|
protected function preConvertPlural( /* Array */ $forms, $count ) {
|
2019-03-27 10:36:51 +00:00
|
|
|
|
return array_pad( $forms, $count, end( $forms ) );
|
2005-09-05 19:22:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-06-29 21:48:41 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Wraps argument with unicode control characters for directionality safety
|
|
|
|
|
|
*
|
|
|
|
|
|
* This solves the problem where directionality-neutral characters at the edge of
|
|
|
|
|
|
* the argument string get interpreted with the wrong directionality from the
|
|
|
|
|
|
* enclosing context, giving renderings that look corrupted like "(Ben_(WMF".
|
|
|
|
|
|
*
|
|
|
|
|
|
* The wrapping is LRE...PDF or RLE...PDF, depending on the detected
|
|
|
|
|
|
* directionality of the argument string, using the BIDI algorithm's own "First
|
|
|
|
|
|
* strong directional codepoint" rule. Essentially, this works round the fact that
|
|
|
|
|
|
* there is no embedding equivalent of U+2068 FSI (isolation with heuristic
|
|
|
|
|
|
* direction inference). The latter is cleaner but still not widely supported.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param string $text Text to wrap
|
|
|
|
|
|
* @return string Text, wrapped in LRE...PDF or RLE...PDF or nothing
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function embedBidi( $text = '' ) {
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$dir = self::strongDirFromContent( $text );
|
2015-06-29 21:48:41 +00:00
|
|
|
|
if ( $dir === 'ltr' ) {
|
|
|
|
|
|
// Wrap in LEFT-TO-RIGHT EMBEDDING ... POP DIRECTIONAL FORMATTING
|
|
|
|
|
|
return self::$lre . $text . self::$pdf;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $dir === 'rtl' ) {
|
|
|
|
|
|
// Wrap in RIGHT-TO-LEFT EMBEDDING ... POP DIRECTIONAL FORMATTING
|
|
|
|
|
|
return self::$rle . $text . self::$pdf;
|
|
|
|
|
|
}
|
|
|
|
|
|
// No strong directionality: do not wrap
|
|
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-08-27 16:35:10 +00:00
|
|
|
|
/**
|
2011-10-06 22:20:40 +00:00
|
|
|
|
* @todo Maybe translate block durations. Note that this function is somewhat misnamed: it
|
|
|
|
|
|
* deals with translating the *duration* ("1 week", "4 days", etc), not the expiry time
|
|
|
|
|
|
* (which is an absolute timestamp). Please note: do NOT add this blindly, as it is used
|
|
|
|
|
|
* on old expiry lengths recorded in log entries. You'd need to provide the start date to
|
|
|
|
|
|
* match up with it.
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $str The validated block duration in English
|
2018-06-26 21:14:43 +00:00
|
|
|
|
* @param User|null $user User object to use timezone from or null for $wgUser
|
2017-01-18 13:08:28 +00:00
|
|
|
|
* @param int $now Current timestamp, for formatting relative block durations
|
2012-02-09 21:17:18 +00:00
|
|
|
|
* @return string Somehow translated block duration
|
2005-08-27 16:35:10 +00:00
|
|
|
|
* @see LanguageFi.php for example implementation
|
|
|
|
|
|
*/
|
2017-01-18 13:08:28 +00:00
|
|
|
|
function translateBlockExpiry( $str, User $user = null, $now = 0 ) {
|
2011-05-21 03:41:16 +00:00
|
|
|
|
$duration = SpecialBlock::getSuggestedDurations( $this );
|
2011-09-22 03:42:14 +00:00
|
|
|
|
foreach ( $duration as $show => $value ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( strcmp( $str, $value ) == 0 ) {
|
2007-09-10 01:53:24 +00:00
|
|
|
|
return htmlspecialchars( trim( $show ) );
|
2007-02-16 20:48:33 +00:00
|
|
|
|
}
|
2006-01-03 20:59:19 +00:00
|
|
|
|
}
|
2011-05-21 03:41:16 +00:00
|
|
|
|
|
2014-06-18 02:45:32 +00:00
|
|
|
|
if ( wfIsInfinity( $str ) ) {
|
|
|
|
|
|
foreach ( $duration as $show => $value ) {
|
|
|
|
|
|
if ( wfIsInfinity( $value ) ) {
|
2011-05-21 03:41:16 +00:00
|
|
|
|
return htmlspecialchars( trim( $show ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2012-11-20 12:13:37 +00:00
|
|
|
|
|
|
|
|
|
|
// If all else fails, return a standard duration or timestamp description.
|
2017-01-18 13:08:28 +00:00
|
|
|
|
$time = strtotime( $str, $now );
|
2012-11-20 12:13:37 +00:00
|
|
|
|
if ( $time === false ) { // Unknown format. Return it as-is in case.
|
|
|
|
|
|
return $str;
|
2017-01-18 13:08:28 +00:00
|
|
|
|
} elseif ( $time !== strtotime( $str, $now + 1 ) ) { // It's a relative timestamp.
|
2017-01-27 08:51:06 +00:00
|
|
|
|
// The result differs based on current time, so the difference
|
|
|
|
|
|
// is a fixed duration length.
|
|
|
|
|
|
return $this->formatDuration( $time - $now );
|
2012-11-20 12:13:37 +00:00
|
|
|
|
} else { // It's an absolute timestamp.
|
|
|
|
|
|
if ( $time === 0 ) {
|
|
|
|
|
|
// wfTimestamp() handles 0 as current time instead of epoch.
|
2016-04-05 17:11:00 +00:00
|
|
|
|
$time = '19700101000000';
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $user ) {
|
|
|
|
|
|
return $this->userTimeAndDate( $time, $user );
|
2012-11-20 12:13:37 +00:00
|
|
|
|
}
|
2016-04-05 17:11:00 +00:00
|
|
|
|
return $this->timeanddate( $time );
|
2012-11-20 12:13:37 +00:00
|
|
|
|
}
|
2005-08-27 16:35:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2005-04-13 08:37:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* languages like Chinese need to be segmented in order for the diff
|
|
|
|
|
|
* to be of any use
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $text
|
|
|
|
|
|
* @return string
|
2005-04-13 08:37:03 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function segmentForDiff( $text ) {
|
2004-12-05 02:17:21 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2005-04-13 08:37:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* and unsegment to show the result
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $text
|
|
|
|
|
|
* @return string
|
2005-04-13 08:37:03 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function unsegmentForDiff( $text ) {
|
2004-12-05 02:17:21 +00:00
|
|
|
|
return $text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-12-12 19:19:23 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Return the LanguageConverter used in the Language
|
2012-01-30 08:10:19 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @since 1.19
|
2011-12-12 19:19:23 +00:00
|
|
|
|
* @return LanguageConverter
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function getConverter() {
|
2011-12-12 19:19:23 +00:00
|
|
|
|
return $this->mConverter;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-18 19:42:42 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* convert text to a variant
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param string $text text to convert
|
|
|
|
|
|
* @param string|bool $variant variant to convert to, or false to use the user's preferred
|
|
|
|
|
|
* variant (if logged in), or the project default variant
|
|
|
|
|
|
* @return string the converted string
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function autoConvert( $text, $variant = false ) {
|
|
|
|
|
|
return $this->mConverter->autoConvert( $text, $variant );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* convert text to all supported variants
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $text
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return array
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function autoConvertToAllVariants( $text ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
return $this->mConverter->autoConvertToAllVariants( $text );
|
2009-05-30 05:07:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* convert text to different variants of a language.
|
|
|
|
|
|
*
|
2018-09-01 08:25:37 +00:00
|
|
|
|
* @warning Glossary state is maintained between calls. This means
|
|
|
|
|
|
* if you pass unescaped text to this method it can cause an XSS
|
|
|
|
|
|
* in later calls to this method, even if the later calls have properly
|
|
|
|
|
|
* escaped the input. Never feed this method user controlled text that
|
|
|
|
|
|
* is not properly escaped!
|
2018-08-30 05:06:39 +00:00
|
|
|
|
* @param string $text Content that has been already escaped for use in HTML
|
|
|
|
|
|
* @return string HTML
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function convert( $text ) {
|
2010-04-10 13:38:50 +00:00
|
|
|
|
return $this->mConverter->convert( $text );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Convert a Title object to a string in the preferred variant
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param Title $title
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function convertTitle( $title ) {
|
2010-04-10 13:38:50 +00:00
|
|
|
|
return $this->mConverter->convertTitle( $title );
|
2004-10-19 18:02:44 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2012-05-29 09:56:21 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Convert a namespace index to a string in the preferred variant
|
|
|
|
|
|
*
|
2017-10-18 19:42:42 +00:00
|
|
|
|
* @param int $ns namespace index (https://www.mediawiki.org/wiki/Manual:Namespace)
|
|
|
|
|
|
* @param string|null $variant variant to convert to, or null to use the user's preferred
|
|
|
|
|
|
* variant (if logged in), or the project default variant
|
|
|
|
|
|
* @return string a string representation of the namespace
|
2012-05-29 09:56:21 +00:00
|
|
|
|
*/
|
2017-10-18 19:42:42 +00:00
|
|
|
|
public function convertNamespace( $ns, $variant = null ) {
|
|
|
|
|
|
return $this->mConverter->convertNamespace( $ns, $variant );
|
2012-05-29 09:56:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Check if this is a language with variants
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return bool
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function hasVariants() {
|
2013-01-26 21:20:04 +00:00
|
|
|
|
return count( $this->getVariants() ) > 1;
|
2006-09-20 10:22:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-12-12 19:19:23 +00:00
|
|
|
|
/**
|
2018-10-19 19:00:52 +00:00
|
|
|
|
* Strict check if the language has the specific variant.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Compare to LanguageConverter::validateVariant() which does a more
|
|
|
|
|
|
* lenient check and attempts to coerce the given code to a valid one.
|
2012-01-30 08:10:19 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @since 1.19
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $variant
|
2011-12-12 19:19:23 +00:00
|
|
|
|
* @return bool
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function hasVariant( $variant ) {
|
2018-10-19 19:00:52 +00:00
|
|
|
|
return $variant && ( $variant === $this->mConverter->validateVariant( $variant ) );
|
2011-12-12 19:19:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2005-06-28 19:56:17 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Perform output conversion on a string, and encode for safe HTML output.
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $text Text to be converted
|
2005-06-28 19:56:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
* @todo this should get integrated somewhere sane
|
|
|
|
|
|
*/
|
2018-12-01 08:47:28 +00:00
|
|
|
|
public function convertHtml( $text ) {
|
|
|
|
|
|
return htmlspecialchars( $this->convert( $text ) );
|
2005-06-28 19:56:17 +00:00
|
|
|
|
}
|
2004-10-19 18:02:44 +00:00
|
|
|
|
|
2011-05-29 15:21:03 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $key
|
2011-05-29 15:21:03 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function convertCategoryKey( $key ) {
|
2005-04-28 03:33:54 +00:00
|
|
|
|
return $this->mConverter->convertCategoryKey( $key );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2005-04-08 16:31:32 +00:00
|
|
|
|
/**
|
2010-12-18 14:34:29 +00:00
|
|
|
|
* Get the list of variants supported by this language
|
2005-04-08 16:31:32 +00:00
|
|
|
|
* see sample implementation in LanguageZh.php
|
|
|
|
|
|
*
|
2017-04-17 20:31:22 +00:00
|
|
|
|
* @return string[] An array of language codes
|
2005-04-08 16:31:32 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function getVariants() {
|
2005-04-15 14:12:39 +00:00
|
|
|
|
return $this->mConverter->getVariants();
|
2004-09-24 18:37:33 +00:00
|
|
|
|
}
|
2005-04-08 16:31:32 +00:00
|
|
|
|
|
2011-05-29 15:21:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function getPreferredVariant() {
|
2010-10-28 16:58:39 +00:00
|
|
|
|
return $this->mConverter->getPreferredVariant();
|
|
|
|
|
|
}
|
2011-02-12 04:06:22 +00:00
|
|
|
|
|
2011-05-29 15:21:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function getDefaultVariant() {
|
2010-10-28 16:58:39 +00:00
|
|
|
|
return $this->mConverter->getDefaultVariant();
|
|
|
|
|
|
}
|
2011-02-12 04:06:22 +00:00
|
|
|
|
|
2011-05-29 15:21:03 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function getURLVariant() {
|
2010-10-28 16:58:39 +00:00
|
|
|
|
return $this->mConverter->getURLVariant();
|
2004-09-24 18:37:33 +00:00
|
|
|
|
}
|
2004-10-21 02:47:51 +00:00
|
|
|
|
|
2005-04-08 16:31:32 +00:00
|
|
|
|
/**
|
2010-04-08 20:19:03 +00:00
|
|
|
|
* If a language supports multiple variants, it is
|
2005-04-07 21:59:02 +00:00
|
|
|
|
* possible that non-existing link in one variant
|
2005-07-03 07:15:53 +00:00
|
|
|
|
* actually exists in another variant. this function
|
2005-04-07 21:59:02 +00:00
|
|
|
|
* tries to find it. See e.g. LanguageZh.php
|
2014-07-24 12:55:43 +00:00
|
|
|
|
* The input parameters may be modified upon return
|
2005-04-08 16:31:32 +00:00
|
|
|
|
*
|
2014-07-24 12:55:43 +00:00
|
|
|
|
* @param string &$link The name of the link
|
|
|
|
|
|
* @param Title &$nt The title object of the link
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param bool $ignoreOtherCond To disable other conditions when
|
|
|
|
|
|
* we need to transclude a template or update a category's link
|
2005-04-07 21:59:02 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function findVariantLink( &$link, &$nt, $ignoreOtherCond = false ) {
|
2009-02-02 07:54:43 +00:00
|
|
|
|
$this->mConverter->findVariantLink( $link, $nt, $ignoreOtherCond );
|
2004-10-21 02:47:51 +00:00
|
|
|
|
}
|
2004-12-07 22:23:21 +00:00
|
|
|
|
|
2005-04-08 16:31:32 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* returns language specific options used by User::getPageRenderHash()
|
|
|
|
|
|
* for example, the preferred language variant
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2005-04-07 21:59:02 +00:00
|
|
|
|
*/
|
2004-12-07 22:23:21 +00:00
|
|
|
|
function getExtraHashOptions() {
|
2005-04-15 14:12:39 +00:00
|
|
|
|
return $this->mConverter->getExtraHashOptions();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2010-04-08 20:19:03 +00:00
|
|
|
|
* For languages that support multiple variants, the title of an
|
2005-04-15 14:12:39 +00:00
|
|
|
|
* article may be displayed differently in different variants. this
|
|
|
|
|
|
* function returns the apporiate title defined in the body of the article.
|
2005-07-03 07:15:53 +00:00
|
|
|
|
*
|
2005-04-15 14:12:39 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function getParsedTitle() {
|
2005-04-15 14:12:39 +00:00
|
|
|
|
return $this->mConverter->getParsedTitle();
|
2004-12-07 22:23:21 +00:00
|
|
|
|
}
|
2005-07-03 07:15:53 +00:00
|
|
|
|
|
2016-01-28 22:40:52 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Refresh the cache of conversion tables when
|
|
|
|
|
|
* MediaWiki:Conversiontable* is updated.
|
|
|
|
|
|
*
|
2016-03-08 22:27:14 +00:00
|
|
|
|
* @param Title $title The Title of the page being updated
|
2016-01-28 22:40:52 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public function updateConversionTable( Title $title ) {
|
|
|
|
|
|
$this->mConverter->updateConversionTable( $title );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2004-12-09 05:51:20 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* A regular expression to match legal word-trailing characters
|
|
|
|
|
|
* which should be merged onto a link of the form [[foo]]bar.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function linkTrail() {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'linkTrail' );
|
2004-12-09 05:51:20 +00:00
|
|
|
|
}
|
2004-12-07 22:23:21 +00:00
|
|
|
|
|
Remove linkprefix message, add $linkPrefixCharset
The existing "linkprefix" message is unlikely to be accurately
customized by message translators (as shown by the fact that, of the 10
distinct customizations prior to Iaa7eaa44 (which made them even more
complicated), 3 were broken or entirely ineffective, 1 was half
ineffective, and 2 more seem to have included the Latin-1 Supplement by
accident) or by local wiki admins. So, like linktrail before it, let's
move it out of the system messages and into a separate language
variable.
At the same time, let's make it a simple character set (like
$wgLegalTitleChars) rather than a complicated regular expression. The
complicated regex now lives in the parser.
This also adjusts the output of the API's action=query&meta=siteinfo and
adds an accessor parallel to the linkTrail accessor to Language.
Note the following changes that are not simply extracting the existing
charset from the linkprefix message for $linkPrefixCharset:
* The En message matched all non-ASCII UTF-8 characters by matching the
component bytes (\\x80-\\xff). The new character set is equivalent.
* Various languages were identical to En and so have no $linkPrefixCharset
set. These are: Ary Az Ce Ga Id Ka Kiu Km Ltg Mk Ms Ne Nn Ro Roa_tara Sc Si
Sr_ec Sr_el Tl Tt_cyrl Tt_latn Ug_arab War
* Cu, Uk, and Udm are changed to match any number of „ or « in the prefix.
* Cv tried to include "«" that was redundant to the range \\x80-\\xff
(see En comment). This was removed.
* Diq was entirely bogus, and so was removed.
* Gu included many additional UTF-8 characters that are redundant to the
range \\x80-\\xff (see En comment). These were removed, and the
resulting character set is equivalent to En.
* Mt has been broken since it was introduced in r37242. The charset used is
equivalent to the broken regex.
Bug: 56031
Change-Id: I3369851b33113fc118a1bace38f3ac310cdd9725
2013-10-23 18:06:19 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* A regular expression character set to match legal word-prefixing
|
|
|
|
|
|
* characters which should be merged onto a link of the form foo[[bar]].
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function linkPrefixCharset() {
|
|
|
|
|
|
return self::$dataCache->getItem( $this->mCode, 'linkPrefixCharset' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2013-06-07 08:50:10 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get the "parent" language which has a converter to convert a "compatible" language
|
|
|
|
|
|
* (in another variant) to this language (eg. zh for zh-cn, but not en for en-gb).
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return Language|null
|
|
|
|
|
|
* @since 1.22
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function getParentLanguage() {
|
|
|
|
|
|
if ( $this->mParentLanguage !== false ) {
|
|
|
|
|
|
return $this->mParentLanguage;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-02-17 19:54:59 +00:00
|
|
|
|
$code = explode( '-', $this->getCode() )[0];
|
2013-06-07 08:50:10 +00:00
|
|
|
|
if ( !in_array( $code, LanguageConverter::$languagesWithVariants ) ) {
|
|
|
|
|
|
$this->mParentLanguage = null;
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$lang = self::factory( $code );
|
2013-06-07 08:50:10 +00:00
|
|
|
|
if ( !$lang->hasVariant( $this->getCode() ) ) {
|
|
|
|
|
|
$this->mParentLanguage = null;
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$this->mParentLanguage = $lang;
|
|
|
|
|
|
return $lang;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-05-16 22:33:33 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Compare with an other language object
|
|
|
|
|
|
*
|
|
|
|
|
|
* @since 1.28
|
|
|
|
|
|
* @param Language $lang
|
2017-08-20 11:20:59 +00:00
|
|
|
|
* @return bool
|
2016-05-16 22:33:33 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public function equals( Language $lang ) {
|
2018-06-28 07:04:09 +00:00
|
|
|
|
return $lang === $this || $lang->getCode() === $this->mCode;
|
2016-05-16 22:33:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2005-07-06 07:53:51 +00:00
|
|
|
|
/**
|
2016-02-19 07:31:51 +00:00
|
|
|
|
* Get the internal language code for this language object
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2012-05-18 19:00:57 +00:00
|
|
|
|
* NOTE: The return value of this function is NOT HTML-safe and must be escaped with
|
|
|
|
|
|
* htmlspecialchars() or similar
|
|
|
|
|
|
*
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
2005-07-06 07:53:51 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function getCode() {
|
2006-07-26 07:15:39 +00:00
|
|
|
|
return $this->mCode;
|
2005-07-06 07:53:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-12-11 18:46:18 +00:00
|
|
|
|
/**
|
2016-02-19 07:31:51 +00:00
|
|
|
|
* Get the code in BCP 47 format which we can use
|
2011-12-11 18:46:18 +00:00
|
|
|
|
* inside of html lang="" tags.
|
2012-05-18 19:00:57 +00:00
|
|
|
|
*
|
|
|
|
|
|
* NOTE: The return value of this function is NOT HTML-safe and must be escaped with
|
|
|
|
|
|
* htmlspecialchars() or similar.
|
|
|
|
|
|
*
|
2011-12-12 20:09:06 +00:00
|
|
|
|
* @since 1.19
|
2011-12-13 15:40:15 +00:00
|
|
|
|
* @return string
|
2011-12-11 18:46:18 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function getHtmlCode() {
|
2011-12-12 20:09:06 +00:00
|
|
|
|
if ( is_null( $this->mHtmlCode ) ) {
|
2017-04-06 15:17:19 +00:00
|
|
|
|
$this->mHtmlCode = LanguageCode::bcp47( $this->getCode() );
|
2011-12-12 20:09:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
return $this->mHtmlCode;
|
2011-12-11 18:46:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code
|
2018-07-07 09:53:04 +00:00
|
|
|
|
* @deprecated since 1.32, use Language::factory to create a new object instead.
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function setCode( $code ) {
|
2018-10-03 09:15:37 +00:00
|
|
|
|
wfDeprecated( __METHOD__, '1.32' );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
$this->mCode = $code;
|
2013-06-07 08:50:10 +00:00
|
|
|
|
// Ensure we don't leave incorrect cached data lying around
|
2011-12-13 19:58:44 +00:00
|
|
|
|
$this->mHtmlCode = null;
|
2013-06-07 08:50:10 +00:00
|
|
|
|
$this->mParentLanguage = false;
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
2005-04-07 23:04:08 +00:00
|
|
|
|
|
2010-01-06 10:20:38 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get the language code from a file name. Inverse of getFileName()
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $filename $prefix . $languageCode . $suffix
|
|
|
|
|
|
* @param string $prefix Prefix before the language code
|
|
|
|
|
|
* @param string $suffix Suffix after the language code
|
2011-05-29 15:03:33 +00:00
|
|
|
|
* @return string Language code, or false if $prefix or $suffix isn't found
|
2010-01-06 10:20:38 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public static function getCodeFromFileName( $filename, $prefix = 'Language', $suffix = '.php' ) {
|
2010-01-06 10:20:38 +00:00
|
|
|
|
$m = null;
|
2010-01-06 19:24:26 +00:00
|
|
|
|
preg_match( '/' . preg_quote( $prefix, '/' ) . '([A-Z][a-z_]+)' .
|
|
|
|
|
|
preg_quote( $suffix, '/' ) . '/', $filename, $m );
|
2010-01-06 10:20:38 +00:00
|
|
|
|
if ( !count( $m ) ) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
return str_replace( '_', '-', strtolower( $m[1] ) );
|
|
|
|
|
|
}
|
2006-07-26 07:15:39 +00:00
|
|
|
|
|
2015-10-29 01:02:58 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* @param string $code
|
2017-08-20 11:20:59 +00:00
|
|
|
|
* @param bool $fallback Whether we're going through language fallback chain
|
2015-10-29 01:02:58 +00:00
|
|
|
|
* @return string Name of the language class
|
|
|
|
|
|
*/
|
2013-07-27 23:01:54 +00:00
|
|
|
|
public static function classFromCode( $code, $fallback = true ) {
|
|
|
|
|
|
if ( $fallback && $code == 'en' ) {
|
2015-10-29 01:02:58 +00:00
|
|
|
|
return 'Language';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return 'Language' . str_replace( '-', '_', ucfirst( $code ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get the name of a file for a certain language code
|
|
|
|
|
|
* @param string $prefix Prepend this to the filename
|
|
|
|
|
|
* @param string $code Language code
|
|
|
|
|
|
* @param string $suffix Append this to the filename
|
|
|
|
|
|
* @throws MWException
|
|
|
|
|
|
* @return string $prefix . $mangledCode . $suffix
|
|
|
|
|
|
*/
|
2018-06-08 21:46:03 +00:00
|
|
|
|
public static function getFileName( $prefix, $code, $suffix = '.php' ) {
|
2015-10-29 01:02:58 +00:00
|
|
|
|
if ( !self::isValidBuiltInCode( $code ) ) {
|
|
|
|
|
|
throw new MWException( "Invalid language code \"$code\"" );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $prefix . str_replace( '-', '_', ucfirst( $code ) ) . $suffix;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:21:03 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code
|
2011-05-29 15:21:03 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public static function getMessagesFileName( $code ) {
|
2006-10-04 01:39:28 +00:00
|
|
|
|
global $IP;
|
2011-12-12 19:32:59 +00:00
|
|
|
|
$file = self::getFileName( "$IP/languages/messages/Messages", $code, '.php' );
|
2016-02-17 09:09:32 +00:00
|
|
|
|
Hooks::run( 'Language::getMessagesFileName', [ $code, &$file ] );
|
2011-12-12 19:32:59 +00:00
|
|
|
|
return $file;
|
2006-10-04 01:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-04-01 10:32:00 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code
|
2014-04-01 10:32:00 +00:00
|
|
|
|
* @return string
|
2016-03-08 22:27:14 +00:00
|
|
|
|
* @throws MWException
|
2014-04-01 10:32:00 +00:00
|
|
|
|
* @since 1.23
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function getJsonMessagesFileName( $code ) {
|
|
|
|
|
|
global $IP;
|
|
|
|
|
|
|
|
|
|
|
|
if ( !self::isValidBuiltInCode( $code ) ) {
|
|
|
|
|
|
throw new MWException( "Invalid language code \"$code\"" );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-04-21 18:44:54 +00:00
|
|
|
|
return "$IP/languages/i18n/$code.json";
|
2014-04-01 10:32:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2006-07-26 07:15:39 +00:00
|
|
|
|
/**
|
2011-09-16 16:55:39 +00:00
|
|
|
|
* Get the first fallback for a given language.
|
2011-05-29 15:21:03 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2012-02-09 21:17:18 +00:00
|
|
|
|
* @return bool|string
|
2006-07-26 07:15:39 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public static function getFallbackFor( $code ) {
|
2015-12-16 09:51:53 +00:00
|
|
|
|
$fallbacks = self::getFallbacksFor( $code );
|
|
|
|
|
|
if ( $fallbacks ) {
|
2015-06-01 23:04:26 +00:00
|
|
|
|
return $fallbacks[0];
|
2011-08-18 16:41:07 +00:00
|
|
|
|
}
|
2015-12-16 09:51:53 +00:00
|
|
|
|
return false;
|
2011-08-18 16:41:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get the ordered list of fallback languages.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @since 1.19
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code Language code
|
2018-04-03 21:08:52 +00:00
|
|
|
|
* @param int $mode Fallback mode, either MESSAGES_FALLBACKS (which always falls back to 'en'),
|
|
|
|
|
|
* or STRICT_FALLBACKS (whic honly falls back to 'en' when explicitly defined)
|
|
|
|
|
|
* @throws MWException
|
|
|
|
|
|
* @return array List of language codes
|
2011-08-18 16:41:07 +00:00
|
|
|
|
*/
|
2018-04-03 21:08:52 +00:00
|
|
|
|
public static function getFallbacksFor( $code, $mode = self::MESSAGES_FALLBACKS ) {
|
2017-07-23 01:24:09 +00:00
|
|
|
|
if ( $code === 'en' || !self::isValidBuiltInCode( $code ) ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return [];
|
2008-04-27 14:37:37 +00:00
|
|
|
|
}
|
2018-04-03 21:08:52 +00:00
|
|
|
|
switch ( $mode ) {
|
|
|
|
|
|
case self::MESSAGES_FALLBACKS:
|
|
|
|
|
|
// For unknown languages, fallbackSequence returns an empty array,
|
|
|
|
|
|
// hardcode fallback to 'en' in that case as English messages are
|
|
|
|
|
|
// always defined.
|
|
|
|
|
|
return self::getLocalisationCache()->getItem( $code, 'fallbackSequence' ) ?: [ 'en' ];
|
|
|
|
|
|
case self::STRICT_FALLBACKS:
|
|
|
|
|
|
// Use this mode when you don't want to fallback to English unless
|
|
|
|
|
|
// explicitly defined, for example when you have language-variant icons
|
|
|
|
|
|
// and an international language-independent fallback.
|
|
|
|
|
|
return self::getLocalisationCache()->getItem( $code, 'originalFallbackSequence' );
|
|
|
|
|
|
default:
|
|
|
|
|
|
throw new MWException( "Invalid fallback mode \"$mode\"" );
|
|
|
|
|
|
}
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2013-01-16 07:28:54 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get the ordered list of fallback languages, ending with the fallback
|
|
|
|
|
|
* language chain for the site language.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @since 1.22
|
|
|
|
|
|
* @param string $code Language code
|
2014-08-13 17:54:49 +00:00
|
|
|
|
* @return array Array( fallbacks, site fallbacks )
|
2013-01-16 07:28:54 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public static function getFallbacksIncludingSiteLanguage( $code ) {
|
|
|
|
|
|
global $wgLanguageCode;
|
|
|
|
|
|
|
|
|
|
|
|
// Usually, we will only store a tiny number of fallback chains, so we
|
|
|
|
|
|
// keep them in static memory.
|
|
|
|
|
|
$cacheKey = "{$code}-{$wgLanguageCode}";
|
|
|
|
|
|
|
|
|
|
|
|
if ( !array_key_exists( $cacheKey, self::$fallbackLanguageCache ) ) {
|
|
|
|
|
|
$fallbacks = self::getFallbacksFor( $code );
|
|
|
|
|
|
|
|
|
|
|
|
// Append the site's fallback chain, including the site language itself
|
|
|
|
|
|
$siteFallbacks = self::getFallbacksFor( $wgLanguageCode );
|
|
|
|
|
|
array_unshift( $siteFallbacks, $wgLanguageCode );
|
|
|
|
|
|
|
|
|
|
|
|
// Eliminate any languages already included in the chain
|
|
|
|
|
|
$siteFallbacks = array_diff( $siteFallbacks, $fallbacks );
|
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
self::$fallbackLanguageCache[$cacheKey] = [ $fallbacks, $siteFallbacks ];
|
2013-01-16 07:28:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
return self::$fallbackLanguageCache[$cacheKey];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2010-01-11 04:23:41 +00:00
|
|
|
|
/**
|
2006-07-26 07:15:39 +00:00
|
|
|
|
* Get all messages for a given language
|
2011-09-14 16:48:29 +00:00
|
|
|
|
* WARNING: this may take a long time. If you just need all message *keys*
|
|
|
|
|
|
* but need the *contents* of only a few messages, consider using getMessageKeysFor().
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return array
|
2006-07-26 07:15:39 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public static function getMessagesFor( $code ) {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::getLocalisationCache()->getItem( $code, 'messages' );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-01-11 04:23:41 +00:00
|
|
|
|
/**
|
2006-08-07 12:21:06 +00:00
|
|
|
|
* Get a message for a given language
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $key
|
|
|
|
|
|
* @param string $code
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2006-08-07 12:21:06 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public static function getMessageFor( $key, $code ) {
|
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput.
* The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true;
* Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache.
* Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words.
* $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c.
* Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess.
* Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly.
* Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load()
* Fixed FileDependency::__sleep()
* In Cdb.php, fixed newlines in debug messages
In MessageCache::get():
* Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII.
* Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us
* Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us.
* Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
|
|
|
|
return self::getLocalisationCache()->getSubitem( $code, 'messages', $key );
|
2006-07-26 07:15:39 +00:00
|
|
|
|
}
|
2011-09-16 16:55:39 +00:00
|
|
|
|
|
2011-09-14 16:48:29 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get all message keys for a given language. This is a faster alternative to
|
|
|
|
|
|
* array_keys( Language::getMessagesFor( $code ) )
|
2011-09-21 19:30:08 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @since 1.19
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $code Language code
|
2014-08-13 17:54:49 +00:00
|
|
|
|
* @return array Array of message keys (strings)
|
2011-09-14 16:48:29 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public static function getMessageKeysFor( $code ) {
|
2016-03-19 00:08:06 +00:00
|
|
|
|
return self::getLocalisationCache()->getSubitemList( $code, 'messages' );
|
2011-09-14 16:48:29 +00:00
|
|
|
|
}
|
2006-07-26 07:15:39 +00:00
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $talk
|
2019-01-31 11:26:13 +00:00
|
|
|
|
* @return string
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*/
|
2009-01-31 17:00:23 +00:00
|
|
|
|
function fixVariableInNamespace( $talk ) {
|
2010-04-08 20:19:03 +00:00
|
|
|
|
if ( strpos( $talk, '$1' ) === false ) {
|
|
|
|
|
|
return $talk;
|
|
|
|
|
|
}
|
2009-01-31 17:00:23 +00:00
|
|
|
|
|
|
|
|
|
|
global $wgMetaNamespace;
|
|
|
|
|
|
$talk = str_replace( '$1', $wgMetaNamespace, $talk );
|
|
|
|
|
|
|
|
|
|
|
|
# Allow grammar transformations
|
2010-01-11 04:23:41 +00:00
|
|
|
|
# Allowing full message-style parsing would make simple requests
|
|
|
|
|
|
# such as action=raw much more expensive than they need to be.
|
2009-01-31 17:00:23 +00:00
|
|
|
|
# This will hopefully cover most cases.
|
2010-01-11 04:23:41 +00:00
|
|
|
|
$talk = preg_replace_callback( '/{{grammar:(.*?)\|(.*?)}}/i',
|
2017-02-01 04:01:54 +00:00
|
|
|
|
[ $this, 'replaceGrammarInNamespace' ], $talk );
|
2009-01-31 17:00:23 +00:00
|
|
|
|
return str_replace( ' ', '_', $talk );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $m
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2006-08-02 03:19:55 +00:00
|
|
|
|
function replaceGrammarInNamespace( $m ) {
|
|
|
|
|
|
return $this->convertGrammar( trim( $m[2] ), trim( $m[1] ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2011-03-18 19:15:56 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Decode an expiry (block, protection, etc) which has come from the DB
|
2012-03-17 22:52:54 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $expiry Database expiry String
|
|
|
|
|
|
* @param bool|int $format True to process using language functions, or TS_ constant
|
2011-03-18 19:15:56 +00:00
|
|
|
|
* to return the expiry in a given timestamp
|
2016-03-08 22:27:14 +00:00
|
|
|
|
* @param string $infinity If $format is not true, use this string for infinite expiry
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @return string
|
2012-07-24 22:20:26 +00:00
|
|
|
|
* @since 1.18
|
2011-03-18 19:15:56 +00:00
|
|
|
|
*/
|
Clean up handling of 'infinity'
There's a bunch of stuff that probably only works because the database
representation of infinity is actually 'infinity' on all databases
besides Oracle, and Oracle in general isn't maintained.
Generally, we should probably use 'infinity' everywhere except where
directly dealing with the database.
* Many extension callers of Language::formatExpiry() with $format !==
true are assuming it'll return 'infinity', none are checking for
$db->getInfinity().
* And Language::formatExpiry() would choke if passed 'infinity', despite
callers doing this.
* And Language::formatExpiry() could be more useful for the API if we
can override the string returned for infinity.
* As for core, Title is using Language::formatExpiry() with TS_MW which
is going to be changing anyway. Extension callers mostly don't exist.
* Block already normalizes its mExpiry field (and ->getExpiry()),
but some stuff is comparing it with $db->getInfinity() anyway. A few
external users set mExpiry to $db->getInfinity(), but this is mostly
because SpecialBlock::parseExpiryInput() returns $db->getInfinity()
while most callers (including all extensions) are assuming 'infinity'.
* And for that matter, Block should use $db->decodeExpiry() instead of
manually doing it, once we make that safe to call with 'infinity' for
all the extensions passing $db->getInfinity() to Block's contructor.
* WikiPage::doUpdateRestrictions() and some of its callers are using
$db->getInfinity(), when all the inserts using that value are using
$db->encodeExpiry() which will convert 'infinity'.
This also cleans up a slave-lag issue I noticed in ApiBlock while
testing.
Bug: T92550
Change-Id: I5eb68c1fb6029da8289276ecf7c81330575029ef
2015-03-12 16:37:04 +00:00
|
|
|
|
public function formatExpiry( $expiry, $format = true, $infinity = 'infinity' ) {
|
|
|
|
|
|
static $dbInfinity;
|
|
|
|
|
|
if ( $dbInfinity === null ) {
|
2017-08-04 18:53:34 +00:00
|
|
|
|
$dbInfinity = wfGetDB( DB_REPLICA )->getInfinity();
|
2011-03-18 19:15:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
Clean up handling of 'infinity'
There's a bunch of stuff that probably only works because the database
representation of infinity is actually 'infinity' on all databases
besides Oracle, and Oracle in general isn't maintained.
Generally, we should probably use 'infinity' everywhere except where
directly dealing with the database.
* Many extension callers of Language::formatExpiry() with $format !==
true are assuming it'll return 'infinity', none are checking for
$db->getInfinity().
* And Language::formatExpiry() would choke if passed 'infinity', despite
callers doing this.
* And Language::formatExpiry() could be more useful for the API if we
can override the string returned for infinity.
* As for core, Title is using Language::formatExpiry() with TS_MW which
is going to be changing anyway. Extension callers mostly don't exist.
* Block already normalizes its mExpiry field (and ->getExpiry()),
but some stuff is comparing it with $db->getInfinity() anyway. A few
external users set mExpiry to $db->getInfinity(), but this is mostly
because SpecialBlock::parseExpiryInput() returns $db->getInfinity()
while most callers (including all extensions) are assuming 'infinity'.
* And for that matter, Block should use $db->decodeExpiry() instead of
manually doing it, once we make that safe to call with 'infinity' for
all the extensions passing $db->getInfinity() to Block's contructor.
* WikiPage::doUpdateRestrictions() and some of its callers are using
$db->getInfinity(), when all the inserts using that value are using
$db->encodeExpiry() which will convert 'infinity'.
This also cleans up a slave-lag issue I noticed in ApiBlock while
testing.
Bug: T92550
Change-Id: I5eb68c1fb6029da8289276ecf7c81330575029ef
2015-03-12 16:37:04 +00:00
|
|
|
|
if ( $expiry == '' || $expiry === 'infinity' || $expiry == $dbInfinity ) {
|
2011-03-18 19:15:56 +00:00
|
|
|
|
return $format === true
|
2013-04-03 21:44:00 +00:00
|
|
|
|
? $this->getMessageFromDB( 'infiniteblock' )
|
2011-03-18 22:03:31 +00:00
|
|
|
|
: $infinity;
|
2011-03-18 19:15:56 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
return $format === true
|
2011-10-06 20:19:23 +00:00
|
|
|
|
? $this->timeanddate( $expiry, /* User preference timezone */ true )
|
2011-03-18 19:15:56 +00:00
|
|
|
|
: wfTimestamp( $format, $expiry );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2015-12-13 19:02:38 +00:00
|
|
|
|
* Formats a time given in seconds into a string representation of that time.
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int|float $seconds
|
2015-12-13 19:02:38 +00:00
|
|
|
|
* @param array $format An optional argument that formats the returned string in different ways:
|
|
|
|
|
|
* If $format['avoid'] === 'avoidseconds': don't show seconds if $seconds >= 1 hour,
|
|
|
|
|
|
* If $format['avoid'] === 'avoidminutes': don't show seconds/minutes if $seconds > 48 hours,
|
2014-04-21 18:44:54 +00:00
|
|
|
|
* If $format['noabbrevs'] is true: use 'seconds' and friends instead of 'seconds-abbrev'
|
|
|
|
|
|
* and friends.
|
2015-12-13 19:02:38 +00:00
|
|
|
|
* @note For backwards compatibility, $format may also be one of the strings 'avoidseconds'
|
2014-04-21 18:44:54 +00:00
|
|
|
|
* or 'avoidminutes'.
|
2011-03-18 19:15:56 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
2016-02-17 09:09:32 +00:00
|
|
|
|
function formatTimePeriod( $seconds, $format = [] ) {
|
2011-09-24 15:44:43 +00:00
|
|
|
|
if ( !is_array( $format ) ) {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$format = [ 'avoid' => $format ]; // For backwards compatibility
|
2011-09-24 15:44:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
if ( !isset( $format['avoid'] ) ) {
|
|
|
|
|
|
$format['avoid'] = false;
|
|
|
|
|
|
}
|
2014-07-21 12:47:42 +00:00
|
|
|
|
if ( !isset( $format['noabbrevs'] ) ) {
|
2011-09-24 15:44:43 +00:00
|
|
|
|
$format['noabbrevs'] = false;
|
|
|
|
|
|
}
|
2011-09-24 17:55:34 +00:00
|
|
|
|
$secondsMsg = wfMessage(
|
|
|
|
|
|
$format['noabbrevs'] ? 'seconds' : 'seconds-abbrev' )->inLanguage( $this );
|
|
|
|
|
|
$minutesMsg = wfMessage(
|
|
|
|
|
|
$format['noabbrevs'] ? 'minutes' : 'minutes-abbrev' )->inLanguage( $this );
|
|
|
|
|
|
$hoursMsg = wfMessage(
|
|
|
|
|
|
$format['noabbrevs'] ? 'hours' : 'hours-abbrev' )->inLanguage( $this );
|
|
|
|
|
|
$daysMsg = wfMessage(
|
|
|
|
|
|
$format['noabbrevs'] ? 'days' : 'days-abbrev' )->inLanguage( $this );
|
2011-10-16 03:27:12 +00:00
|
|
|
|
|
2010-11-07 21:05:01 +00:00
|
|
|
|
if ( round( $seconds * 10 ) < 100 ) {
|
2011-06-27 22:32:58 +00:00
|
|
|
|
$s = $this->formatNum( sprintf( "%.1f", round( $seconds * 10 ) / 10 ) );
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s = $secondsMsg->params( $s )->text();
|
2010-11-07 21:05:01 +00:00
|
|
|
|
} elseif ( round( $seconds ) < 60 ) {
|
2011-06-27 22:32:58 +00:00
|
|
|
|
$s = $this->formatNum( round( $seconds ) );
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s = $secondsMsg->params( $s )->text();
|
2010-11-07 21:05:01 +00:00
|
|
|
|
} elseif ( round( $seconds ) < 3600 ) {
|
2010-04-29 15:09:22 +00:00
|
|
|
|
$minutes = floor( $seconds / 60 );
|
|
|
|
|
|
$secondsPart = round( fmod( $seconds, 60 ) );
|
|
|
|
|
|
if ( $secondsPart == 60 ) {
|
|
|
|
|
|
$secondsPart = 0;
|
|
|
|
|
|
$minutes++;
|
|
|
|
|
|
}
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s = $minutesMsg->params( $this->formatNum( $minutes ) )->text();
|
2011-06-27 22:32:58 +00:00
|
|
|
|
$s .= ' ';
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s .= $secondsMsg->params( $this->formatNum( $secondsPart ) )->text();
|
2011-09-22 03:42:14 +00:00
|
|
|
|
} elseif ( round( $seconds ) <= 2 * 86400 ) {
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
$hours = floor( $seconds / 3600 );
|
|
|
|
|
|
$minutes = floor( ( $seconds - $hours * 3600 ) / 60 );
|
2011-06-19 09:27:08 +00:00
|
|
|
|
$secondsPart = round( $seconds - $hours * 3600 - $minutes * 60 );
|
|
|
|
|
|
if ( $secondsPart == 60 ) {
|
|
|
|
|
|
$secondsPart = 0;
|
|
|
|
|
|
$minutes++;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $minutes == 60 ) {
|
|
|
|
|
|
$minutes = 0;
|
|
|
|
|
|
$hours++;
|
|
|
|
|
|
}
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s = $hoursMsg->params( $this->formatNum( $hours ) )->text();
|
2011-06-27 22:32:58 +00:00
|
|
|
|
$s .= ' ';
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s .= $minutesMsg->params( $this->formatNum( $minutes ) )->text();
|
2016-02-17 09:09:32 +00:00
|
|
|
|
if ( !in_array( $format['avoid'], [ 'avoidseconds', 'avoidminutes' ] ) ) {
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s .= ' ' . $secondsMsg->params( $this->formatNum( $secondsPart ) )->text();
|
2010-04-29 15:09:22 +00:00
|
|
|
|
}
|
2011-06-19 07:25:55 +00:00
|
|
|
|
} else {
|
|
|
|
|
|
$days = floor( $seconds / 86400 );
|
2011-09-24 15:44:43 +00:00
|
|
|
|
if ( $format['avoid'] === 'avoidminutes' ) {
|
2011-06-27 22:32:58 +00:00
|
|
|
|
$hours = round( ( $seconds - $days * 86400 ) / 3600 );
|
|
|
|
|
|
if ( $hours == 24 ) {
|
|
|
|
|
|
$hours = 0;
|
|
|
|
|
|
$days++;
|
|
|
|
|
|
}
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s = $daysMsg->params( $this->formatNum( $days ) )->text();
|
2011-06-27 22:32:58 +00:00
|
|
|
|
$s .= ' ';
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s .= $hoursMsg->params( $this->formatNum( $hours ) )->text();
|
2011-09-24 15:44:43 +00:00
|
|
|
|
} elseif ( $format['avoid'] === 'avoidseconds' ) {
|
2011-06-19 07:25:55 +00:00
|
|
|
|
$hours = floor( ( $seconds - $days * 86400 ) / 3600 );
|
2011-06-27 22:32:58 +00:00
|
|
|
|
$minutes = round( ( $seconds - $days * 86400 - $hours * 3600 ) / 60 );
|
|
|
|
|
|
if ( $minutes == 60 ) {
|
|
|
|
|
|
$minutes = 0;
|
|
|
|
|
|
$hours++;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ( $hours == 24 ) {
|
|
|
|
|
|
$hours = 0;
|
|
|
|
|
|
$days++;
|
|
|
|
|
|
}
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s = $daysMsg->params( $this->formatNum( $days ) )->text();
|
2011-06-27 22:32:58 +00:00
|
|
|
|
$s .= ' ';
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s .= $hoursMsg->params( $this->formatNum( $hours ) )->text();
|
2011-06-27 22:32:58 +00:00
|
|
|
|
$s .= ' ';
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s .= $minutesMsg->params( $this->formatNum( $minutes ) )->text();
|
2011-06-19 07:25:55 +00:00
|
|
|
|
} else {
|
2011-09-23 22:17:10 +00:00
|
|
|
|
$s = $daysMsg->params( $this->formatNum( $days ) )->text();
|
2011-06-27 22:32:58 +00:00
|
|
|
|
$s .= ' ';
|
2011-09-24 15:44:43 +00:00
|
|
|
|
$s .= $this->formatTimePeriod( $seconds - $days * 86400, $format );
|
2010-04-29 15:09:22 +00:00
|
|
|
|
}
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
}
|
2011-06-27 22:32:58 +00:00
|
|
|
|
return $s;
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-05-29 15:40:17 +00:00
|
|
|
|
/**
|
2011-12-31 21:32:42 +00:00
|
|
|
|
* Format a bitrate for output, using an appropriate
|
2014-04-21 18:44:54 +00:00
|
|
|
|
* unit (bps, kbps, Mbps, Gbps, Tbps, Pbps, Ebps, Zbps or Ybps) according to
|
|
|
|
|
|
* the magnitude in question.
|
2011-12-31 21:32:42 +00:00
|
|
|
|
*
|
2012-01-09 14:10:13 +00:00
|
|
|
|
* This use base 1000. For base 1024 use formatSize(), for another base
|
2014-04-21 18:44:54 +00:00
|
|
|
|
* see formatComputingNumbers().
|
2012-01-09 14:10:13 +00:00
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int $bps
|
2011-05-29 15:40:17 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
function formatBitrate( $bps ) {
|
2012-01-08 20:40:13 +00:00
|
|
|
|
return $this->formatComputingNumbers( $bps, 1000, "bitrate-$1bits" );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int $size Size of the unit
|
|
|
|
|
|
* @param int $boundary Size boundary (1000, or 1024 in most cases)
|
|
|
|
|
|
* @param string $messageKey Message key to be uesd
|
2012-01-08 20:40:13 +00:00
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
function formatComputingNumbers( $size, $boundary, $messageKey ) {
|
|
|
|
|
|
if ( $size <= 0 ) {
|
|
|
|
|
|
return str_replace( '$1', $this->formatNum( $size ),
|
|
|
|
|
|
$this->getMessageFromDB( str_replace( '$1', '', $messageKey ) )
|
|
|
|
|
|
);
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
}
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$sizes = [ '', 'kilo', 'mega', 'giga', 'tera', 'peta', 'exa', 'zeta', 'yotta' ];
|
2012-01-08 20:15:08 +00:00
|
|
|
|
$index = 0;
|
2011-12-31 22:53:50 +00:00
|
|
|
|
|
2012-01-08 20:40:13 +00:00
|
|
|
|
$maxIndex = count( $sizes ) - 1;
|
|
|
|
|
|
while ( $size >= $boundary && $index < $maxIndex ) {
|
2012-01-08 20:15:08 +00:00
|
|
|
|
$index++;
|
2012-01-08 20:40:13 +00:00
|
|
|
|
$size /= $boundary;
|
2011-12-31 22:53:50 +00:00
|
|
|
|
}
|
2012-01-08 20:15:08 +00:00
|
|
|
|
|
2012-01-08 20:40:13 +00:00
|
|
|
|
// For small sizes no decimal places necessary
|
2012-01-08 20:15:08 +00:00
|
|
|
|
$round = 0;
|
|
|
|
|
|
if ( $index > 1 ) {
|
|
|
|
|
|
// For MB and bigger two decimal places are smarter
|
|
|
|
|
|
$round = 2;
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
}
|
2012-01-08 20:44:23 +00:00
|
|
|
|
$msg = str_replace( '$1', $sizes[$index], $messageKey );
|
2012-01-08 20:15:08 +00:00
|
|
|
|
|
2012-01-08 20:40:13 +00:00
|
|
|
|
$size = round( $size, $round );
|
2011-12-31 21:32:42 +00:00
|
|
|
|
$text = $this->getMessageFromDB( $msg );
|
2012-01-08 20:40:13 +00:00
|
|
|
|
return str_replace( '$1', $this->formatNum( $size ), $text );
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Format a size in bytes for output, using an appropriate
|
2011-12-31 20:20:15 +00:00
|
|
|
|
* unit (B, KB, MB, GB, TB, PB, EB, ZB or YB) according to the magnitude in question
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
*
|
2012-01-09 14:10:13 +00:00
|
|
|
|
* This method use base 1024. For base 1000 use formatBitrate(), for
|
|
|
|
|
|
* another base see formatComputingNumbers()
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param int $size Size to format
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
* @return string Plain text (not HTML)
|
|
|
|
|
|
*/
|
|
|
|
|
|
function formatSize( $size ) {
|
2012-01-08 20:40:13 +00:00
|
|
|
|
return $this->formatComputingNumbers( $size, 1024, "size-$1bytes" );
|
Basic integrated audio/video support, with Ogg implementation.
* JavaScript video player based loosely on Greg Maxwell's player
* Image page text snippet customisation
* Abstraction of transform parameters in the parser. Introduced Linker::makeImageLink2().
* Made canRender(), mustRender() depend on file, not just on handler. Moved width=0, height=0 checking to ImageHandler::canRender(), since audio streams have width=height=0 but should be rendered.
Also:
* Automatic upgrade for oldimage rows on image page view, allows media handler selection based on oi_*_mime
* oi_*_mime unconditionally referenced, REQUIRES SCHEMA UPGRADE
* Don't destroy file info for missing files on upgrade
* Simple, centralised extension message file handling
* Made MessageCache::loadAllMessages non-static, optimised for repeated-call case due to abuse in User.php
* Support for lightweight parser output hooks, with callback whitelist for security
* Moved Linker::formatSize() to Language, to join the new formatTimePeriod() and formatBitrate()
* Introduced MagicWordArray, regex capture trick requires that magic word IDs DO NOT CONTAIN HYPHENS.
2007-08-15 10:50:09 +00:00
|
|
|
|
}
|
2010-01-08 08:22:19 +00:00
|
|
|
|
|
2011-10-13 11:46:21 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Make a list item, used by various special pages
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param string $page Page link
|
2014-12-06 11:16:16 +00:00
|
|
|
|
* @param string $details HTML safe text between brackets
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param bool $oppositedm Add the direction mark opposite to your
|
|
|
|
|
|
* language, to display text properly
|
2018-04-06 11:07:01 +00:00
|
|
|
|
* @return string HTML escaped
|
2011-10-13 11:46:21 +00:00
|
|
|
|
*/
|
|
|
|
|
|
function specialList( $page, $details, $oppositedm = true ) {
|
2014-12-06 11:16:16 +00:00
|
|
|
|
if ( !$details ) {
|
|
|
|
|
|
return $page;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$dirmark = ( $oppositedm ? $this->getDirMark( true ) : '' ) . $this->getDirMark();
|
2018-01-01 13:10:16 +00:00
|
|
|
|
return $page .
|
2014-12-06 11:16:16 +00:00
|
|
|
|
$dirmark .
|
|
|
|
|
|
$this->msg( 'word-separator' )->escaped() .
|
|
|
|
|
|
$this->msg( 'parentheses' )->rawParams( $details )->escaped();
|
2011-10-13 11:46:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-10-14 14:57:06 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Generate (prev x| next x) (20|50|100...) type links for paging
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param Title $title Title object to link
|
|
|
|
|
|
* @param int $offset
|
|
|
|
|
|
* @param int $limit
|
2014-08-15 16:33:34 +00:00
|
|
|
|
* @param array $query Optional URL query parameter string
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param bool $atend Optional param for specified if this is the last page
|
|
|
|
|
|
* @return string
|
2018-10-25 18:07:00 +00:00
|
|
|
|
* @deprecated since 1.33, use SpecialPage::viewPrevNext()
|
|
|
|
|
|
* instead.
|
2011-10-14 14:57:06 +00:00
|
|
|
|
*/
|
2014-04-21 18:44:54 +00:00
|
|
|
|
public function viewPrevNext( Title $title, $offset, $limit,
|
2016-02-17 09:09:32 +00:00
|
|
|
|
array $query = [], $atend = false
|
2014-04-21 18:44:54 +00:00
|
|
|
|
) {
|
2011-10-14 14:57:06 +00:00
|
|
|
|
// @todo FIXME: Why on earth this needs one message for the text and another one for tooltip?
|
|
|
|
|
|
|
|
|
|
|
|
# Make 'previous' link
|
|
|
|
|
|
$prev = wfMessage( 'prevn' )->inLanguage( $this )->title( $title )->numParams( $limit )->text();
|
2012-01-04 09:06:05 +00:00
|
|
|
|
if ( $offset > 0 ) {
|
2011-10-14 14:57:06 +00:00
|
|
|
|
$plink = $this->numLink( $title, max( $offset - $limit, 0 ), $limit,
|
|
|
|
|
|
$query, $prev, 'prevn-title', 'mw-prevlink' );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$plink = htmlspecialchars( $prev );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Make 'next' link
|
|
|
|
|
|
$next = wfMessage( 'nextn' )->inLanguage( $this )->title( $title )->numParams( $limit )->text();
|
2012-01-04 09:06:05 +00:00
|
|
|
|
if ( $atend ) {
|
2011-10-14 14:57:06 +00:00
|
|
|
|
$nlink = htmlspecialchars( $next );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$nlink = $this->numLink( $title, $offset + $limit, $limit,
|
2013-11-08 17:45:42 +00:00
|
|
|
|
$query, $next, 'nextn-title', 'mw-nextlink' );
|
2011-10-14 14:57:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Make links to set number of items per page
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$numLinks = [];
|
|
|
|
|
|
foreach ( [ 20, 50, 100, 250, 500 ] as $num ) {
|
2011-10-14 14:57:06 +00:00
|
|
|
|
$numLinks[] = $this->numLink( $title, $offset, $num,
|
|
|
|
|
|
$query, $this->formatNum( $num ), 'shown-title', 'mw-numlink' );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return wfMessage( 'viewprevnext' )->inLanguage( $this )->title( $title
|
|
|
|
|
|
)->rawParams( $plink, $nlink, $this->pipeList( $numLinks ) )->escaped();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Helper function for viewPrevNext() that generates links
|
|
|
|
|
|
*
|
2014-04-17 13:31:28 +00:00
|
|
|
|
* @param Title $title Title object to link
|
|
|
|
|
|
* @param int $offset
|
|
|
|
|
|
* @param int $limit
|
|
|
|
|
|
* @param array $query Extra query parameters
|
|
|
|
|
|
* @param string $link Text to use for the link; will be escaped
|
|
|
|
|
|
* @param string $tooltipMsg Name of the message to use as tooltip
|
|
|
|
|
|
* @param string $class Value of the "class" attribute of the link
|
|
|
|
|
|
* @return string HTML fragment
|
2011-10-14 14:57:06 +00:00
|
|
|
|
*/
|
2014-04-21 18:44:54 +00:00
|
|
|
|
private function numLink( Title $title, $offset, $limit, array $query, $link,
|
|
|
|
|
|
$tooltipMsg, $class
|
|
|
|
|
|
) {
|
2016-02-17 09:09:32 +00:00
|
|
|
|
$query = [ 'limit' => $limit, 'offset' => $offset ] + $query;
|
2014-04-21 18:44:54 +00:00
|
|
|
|
$tooltip = wfMessage( $tooltipMsg )->inLanguage( $this )->title( $title )
|
|
|
|
|
|
->numParams( $limit )->text();
|
|
|
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
|
return Html::element( 'a', [ 'href' => $title->getLocalURL( $query ),
|
|
|
|
|
|
'title' => $tooltip, 'class' => $class ], $link );
|
2011-10-14 14:57:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2010-01-08 08:22:19 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Get the conversion rule title, if any.
|
2011-05-29 15:40:17 +00:00
|
|
|
|
*
|
|
|
|
|
|
* @return string
|
2010-01-08 08:22:19 +00:00
|
|
|
|
*/
|
2011-12-13 15:40:15 +00:00
|
|
|
|
public function getConvRuleTitle() {
|
2010-01-15 19:14:23 +00:00
|
|
|
|
return $this->mConverter->getConvRuleTitle();
|
2010-01-08 08:22:19 +00:00
|
|
|
|
}
|
2012-08-29 08:07:10 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get the compiled plural rules for the language
|
|
|
|
|
|
* @since 1.20
|
|
|
|
|
|
* @return array Associative array with plural form, and plural rule as key-value pairs
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function getCompiledPluralRules() {
|
2012-09-15 19:49:44 +00:00
|
|
|
|
$pluralRules = self::$dataCache->getItem( strtolower( $this->mCode ), 'compiledPluralRules' );
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$fallbacks = self::getFallbacksFor( $this->mCode );
|
2012-09-15 19:49:44 +00:00
|
|
|
|
if ( !$pluralRules ) {
|
|
|
|
|
|
foreach ( $fallbacks as $fallbackCode ) {
|
|
|
|
|
|
$pluralRules = self::$dataCache->getItem( strtolower( $fallbackCode ), 'compiledPluralRules' );
|
|
|
|
|
|
if ( $pluralRules ) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return $pluralRules;
|
2012-08-29 08:07:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get the plural rules for the language
|
|
|
|
|
|
* @since 1.20
|
2013-01-25 01:10:37 +00:00
|
|
|
|
* @return array Associative array with plural form number and plural rule as key-value pairs
|
2012-08-29 08:07:10 +00:00
|
|
|
|
*/
|
|
|
|
|
|
public function getPluralRules() {
|
2012-09-15 19:49:44 +00:00
|
|
|
|
$pluralRules = self::$dataCache->getItem( strtolower( $this->mCode ), 'pluralRules' );
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$fallbacks = self::getFallbacksFor( $this->mCode );
|
2012-09-15 19:49:44 +00:00
|
|
|
|
if ( !$pluralRules ) {
|
|
|
|
|
|
foreach ( $fallbacks as $fallbackCode ) {
|
|
|
|
|
|
$pluralRules = self::$dataCache->getItem( strtolower( $fallbackCode ), 'pluralRules' );
|
|
|
|
|
|
if ( $pluralRules ) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return $pluralRules;
|
2012-08-29 08:07:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2013-01-25 01:10:37 +00:00
|
|
|
|
* Get the plural rule types for the language
|
2013-05-20 05:52:14 +00:00
|
|
|
|
* @since 1.22
|
2013-01-25 01:10:37 +00:00
|
|
|
|
* @return array Associative array with plural form number and plural rule type as key-value pairs
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function getPluralRuleTypes() {
|
|
|
|
|
|
$pluralRuleTypes = self::$dataCache->getItem( strtolower( $this->mCode ), 'pluralRuleTypes' );
|
2017-07-23 01:24:09 +00:00
|
|
|
|
$fallbacks = self::getFallbacksFor( $this->mCode );
|
2013-01-25 01:10:37 +00:00
|
|
|
|
if ( !$pluralRuleTypes ) {
|
|
|
|
|
|
foreach ( $fallbacks as $fallbackCode ) {
|
|
|
|
|
|
$pluralRuleTypes = self::$dataCache->getItem( strtolower( $fallbackCode ), 'pluralRuleTypes' );
|
|
|
|
|
|
if ( $pluralRuleTypes ) {
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return $pluralRuleTypes;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Find the index number of the plural rule appropriate for the given number
|
2014-08-14 19:34:55 +00:00
|
|
|
|
* @param int $number
|
2013-01-25 01:10:37 +00:00
|
|
|
|
* @return int The index number of the plural rule
|
2012-08-29 08:07:10 +00:00
|
|
|
|
*/
|
2013-01-25 01:10:37 +00:00
|
|
|
|
public function getPluralRuleIndexNumber( $number ) {
|
2012-08-29 08:07:10 +00:00
|
|
|
|
$pluralRules = $this->getCompiledPluralRules();
|
2015-09-24 07:15:49 +00:00
|
|
|
|
$form = Evaluator::evaluateCompiled( $number, $pluralRules );
|
2012-08-29 08:07:10 +00:00
|
|
|
|
return $form;
|
|
|
|
|
|
}
|
2013-01-25 01:10:37 +00:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Find the plural rule type appropriate for the given number
|
|
|
|
|
|
* For example, if the language is set to Arabic, getPluralType(5) should
|
|
|
|
|
|
* return 'few'.
|
2013-05-20 05:52:14 +00:00
|
|
|
|
* @since 1.22
|
2014-08-14 19:34:55 +00:00
|
|
|
|
* @param int $number
|
2013-01-25 01:10:37 +00:00
|
|
|
|
* @return string The name of the plural rule type, e.g. one, two, few, many
|
|
|
|
|
|
*/
|
|
|
|
|
|
public function getPluralRuleType( $number ) {
|
|
|
|
|
|
$index = $this->getPluralRuleIndexNumber( $number );
|
|
|
|
|
|
$pluralRuleTypes = $this->getPluralRuleTypes();
|
2018-10-27 12:30:02 +00:00
|
|
|
|
return $pluralRuleTypes[$index] ?? 'other';
|
2013-01-25 01:10:37 +00:00
|
|
|
|
}
|
2007-11-13 04:05:13 +00:00
|
|
|
|
}
|