From 4ac9fa081a7c045f6a9f1cfc529d82423f485b2e Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Sun, 8 Dec 2013 09:55:49 +0100 Subject: Update to MediaWiki 1.22.0 --- languages/Language.php | 500 +++++++++++++------ languages/LanguageConverter.php | 84 +++- languages/Names.php | 46 +- languages/classes/LanguageAz.php | 2 +- languages/classes/LanguageBe_tarask.php | 12 +- languages/classes/LanguageCu.php | 27 +- languages/classes/LanguageEo.php | 70 +-- languages/classes/LanguageEs.php | 42 ++ languages/classes/LanguageFi.php | 6 +- languages/classes/LanguageGa.php | 21 +- languages/classes/LanguageGan.php | 47 +- languages/classes/LanguageGv.php | 4 +- languages/classes/LanguageHi.php | 44 -- languages/classes/LanguageHr.php | 8 +- languages/classes/LanguageHy.php | 12 +- languages/classes/LanguageIu.php | 20 +- languages/classes/LanguageKaa.php | 6 +- languages/classes/LanguageKk.php | 52 +- languages/classes/LanguageKk_cyrl.php | 62 +-- languages/classes/LanguageKsh.php | 20 +- languages/classes/LanguageKu.php | 64 +-- languages/classes/LanguageLa.php | 90 ++-- languages/classes/LanguageMg.php | 44 -- languages/classes/LanguageMk.php | 49 -- languages/classes/LanguageMt.php | 48 -- languages/classes/LanguageNso.php | 44 -- languages/classes/LanguageOs.php | 38 +- languages/classes/LanguagePl.php | 25 - languages/classes/LanguageSh.php | 58 --- languages/classes/LanguageShi.php | 36 +- languages/classes/LanguageSk.php | 49 -- languages/classes/LanguageSl.php | 27 +- languages/classes/LanguageSr.php | 40 +- languages/classes/LanguageSr_ec.php | 8 +- languages/classes/LanguageSr_el.php | 8 +- languages/classes/LanguageTg.php | 4 +- languages/classes/LanguageTi.php | 44 -- languages/classes/LanguageTl.php | 44 -- languages/classes/LanguageTr.php | 4 +- languages/classes/LanguageTyv.php | 2 +- languages/classes/LanguageUk.php | 37 +- languages/classes/LanguageUz.php | 10 +- languages/classes/LanguageWa.php | 42 +- languages/classes/LanguageZh.php | 58 +-- languages/classes/LanguageZh_hans.php | 2 + languages/data/plurals-mediawiki.xml | 7 + languages/data/plurals.xml | 2 +- languages/messages/MessagesAce.php | 49 +- languages/messages/MessagesAeb.php | 26 +- languages/messages/MessagesAf.php | 234 ++++++--- languages/messages/MessagesAln.php | 43 +- languages/messages/MessagesAm.php | 66 +-- languages/messages/MessagesAn.php | 86 +--- languages/messages/MessagesAng.php | 51 +- languages/messages/MessagesAr.php | 260 ++++++---- languages/messages/MessagesArc.php | 48 +- languages/messages/MessagesArn.php | 10 +- languages/messages/MessagesAry.php | 62 +-- languages/messages/MessagesArz.php | 81 +-- languages/messages/MessagesAs.php | 171 ++++--- languages/messages/MessagesAst.php | 288 +++++++---- languages/messages/MessagesAvk.php | 49 +- languages/messages/MessagesAy.php | 1 + languages/messages/MessagesAz.php | 83 +--- languages/messages/MessagesAzb.php | 173 ++++--- languages/messages/MessagesBa.php | 260 +++++++--- languages/messages/MessagesBar.php | 36 +- languages/messages/MessagesBbc.php | 12 + languages/messages/MessagesBbc_latn.php | 734 ++++++++++++++++++++++++++++ languages/messages/MessagesBcc.php | 64 +-- languages/messages/MessagesBcl.php | 250 +++++++--- languages/messages/MessagesBe.php | 98 ++-- languages/messages/MessagesBe_tarask.php | 268 +++++++--- languages/messages/MessagesBg.php | 184 ++++--- languages/messages/MessagesBho.php | 86 +++- languages/messages/MessagesBi.php | 23 +- languages/messages/MessagesBjn.php | 64 +-- languages/messages/MessagesBn.php | 255 +++++++--- languages/messages/MessagesBo.php | 5 +- languages/messages/MessagesBpy.php | 42 +- languages/messages/MessagesBqi.php | 2 - languages/messages/MessagesBr.php | 239 ++++++--- languages/messages/MessagesBrh.php | 2 - languages/messages/MessagesBs.php | 211 +++++--- languages/messages/MessagesBug.php | 3 - languages/messages/MessagesBxr.php | 72 +++ languages/messages/MessagesCa.php | 257 +++++++--- languages/messages/MessagesCbk_zam.php | 2 +- languages/messages/MessagesCdo.php | 71 ++- languages/messages/MessagesCe.php | 266 ++++++++-- languages/messages/MessagesCeb.php | 29 +- languages/messages/MessagesCh.php | 16 +- languages/messages/MessagesChr.php | 1 + languages/messages/MessagesCkb.php | 150 +++--- languages/messages/MessagesCo.php | 5 +- languages/messages/MessagesCps.php | 19 +- languages/messages/MessagesCrh_cyrl.php | 49 +- languages/messages/MessagesCrh_latn.php | 49 +- languages/messages/MessagesCs.php | 269 ++++++---- languages/messages/MessagesCsb.php | 17 +- languages/messages/MessagesCu.php | 57 ++- languages/messages/MessagesCv.php | 35 +- languages/messages/MessagesCy.php | 269 +++++++--- languages/messages/MessagesDa.php | 306 ++++++++---- languages/messages/MessagesDe.php | 278 ++++++++--- languages/messages/MessagesDe_at.php | 12 +- languages/messages/MessagesDe_ch.php | 72 ++- languages/messages/MessagesDe_formal.php | 73 +-- languages/messages/MessagesDiq.php | 384 +++++++++------ languages/messages/MessagesDsb.php | 91 +--- languages/messages/MessagesDtp.php | 35 +- languages/messages/MessagesDv.php | 86 ++-- languages/messages/MessagesEe.php | 3 - languages/messages/MessagesEgl.php | 14 +- languages/messages/MessagesEl.php | 238 ++++++--- languages/messages/MessagesEml.php | 6 +- languages/messages/MessagesEn.php | 690 +++++++++++++++----------- languages/messages/MessagesEn_ca.php | 33 +- languages/messages/MessagesEn_gb.php | 56 +-- languages/messages/MessagesEo.php | 184 +++---- languages/messages/MessagesEs.php | 278 +++++++---- languages/messages/MessagesEt.php | 270 +++++++--- languages/messages/MessagesEu.php | 147 +++--- languages/messages/MessagesExt.php | 55 +-- languages/messages/MessagesFa.php | 262 +++++++--- languages/messages/MessagesFi.php | 261 +++++++--- languages/messages/MessagesFit.php | 1 - languages/messages/MessagesFj.php | 2 +- languages/messages/MessagesFo.php | 199 +++++--- languages/messages/MessagesFr.php | 274 +++++++---- languages/messages/MessagesFrc.php | 2 - languages/messages/MessagesFrp.php | 145 +++--- languages/messages/MessagesFrr.php | 239 ++++++--- languages/messages/MessagesFur.php | 34 +- languages/messages/MessagesFy.php | 49 +- languages/messages/MessagesGa.php | 62 +-- languages/messages/MessagesGag.php | 10 +- languages/messages/MessagesGan_hans.php | 53 +- languages/messages/MessagesGan_hant.php | 53 +- languages/messages/MessagesGd.php | 47 +- languages/messages/MessagesGl.php | 275 +++++++---- languages/messages/MessagesGn.php | 5 - languages/messages/MessagesGrc.php | 51 +- languages/messages/MessagesGsw.php | 70 +-- languages/messages/MessagesGu.php | 221 ++++++--- languages/messages/MessagesGv.php | 21 +- languages/messages/MessagesHa.php | 2 - languages/messages/MessagesHak.php | 98 ++-- languages/messages/MessagesHaw.php | 9 +- languages/messages/MessagesHe.php | 275 ++++++++--- languages/messages/MessagesHi.php | 222 ++++++--- languages/messages/MessagesHif_latn.php | 196 +++++--- languages/messages/MessagesHil.php | 43 +- languages/messages/MessagesHr.php | 171 ++++--- languages/messages/MessagesHsb.php | 176 ++++--- languages/messages/MessagesHt.php | 25 +- languages/messages/MessagesHu.php | 170 ++++--- languages/messages/MessagesHy.php | 103 ++-- languages/messages/MessagesIa.php | 283 +++++++---- languages/messages/MessagesId.php | 269 ++++++---- languages/messages/MessagesIe.php | 22 +- languages/messages/MessagesIg.php | 29 +- languages/messages/MessagesIk.php | 21 +- languages/messages/MessagesIke_cans.php | 4 +- languages/messages/MessagesIke_latn.php | 4 +- languages/messages/MessagesIlo.php | 252 +++++++--- languages/messages/MessagesInh.php | 22 +- languages/messages/MessagesIo.php | 20 +- languages/messages/MessagesIs.php | 152 +++--- languages/messages/MessagesIt.php | 264 +++++++--- languages/messages/MessagesJa.php | 278 +++++++---- languages/messages/MessagesJam.php | 20 +- languages/messages/MessagesJut.php | 5 - languages/messages/MessagesJv.php | 82 +--- languages/messages/MessagesKa.php | 214 +++++--- languages/messages/MessagesKaa.php | 45 +- languages/messages/MessagesKab.php | 73 +-- languages/messages/MessagesKbd_cyrl.php | 22 +- languages/messages/MessagesKg.php | 13 + languages/messages/MessagesKhw.php | 27 +- languages/messages/MessagesKiu.php | 43 +- languages/messages/MessagesKk_arab.php | 71 +-- languages/messages/MessagesKk_cyrl.php | 189 ++++--- languages/messages/MessagesKk_latn.php | 71 +-- languages/messages/MessagesKm.php | 190 ++++--- languages/messages/MessagesKn.php | 70 ++- languages/messages/MessagesKo.php | 291 +++++++---- languages/messages/MessagesKoi.php | 5 +- languages/messages/MessagesKrc.php | 196 +++++--- languages/messages/MessagesKrj.php | 11 +- languages/messages/MessagesKs.php | 49 +- languages/messages/MessagesKs_arab.php | 8 - languages/messages/MessagesKs_deva.php | 7 - languages/messages/MessagesKsh.php | 217 ++++---- languages/messages/MessagesKu_latn.php | 59 ++- languages/messages/MessagesKw.php | 164 ++++--- languages/messages/MessagesKy.php | 80 +-- languages/messages/MessagesLa.php | 242 ++++----- languages/messages/MessagesLad.php | 24 +- languages/messages/MessagesLb.php | 253 +++++++--- languages/messages/MessagesLbe.php | 2 +- languages/messages/MessagesLez.php | 52 +- languages/messages/MessagesLfn.php | 24 +- languages/messages/MessagesLg.php | 28 +- languages/messages/MessagesLi.php | 71 +-- languages/messages/MessagesLij.php | 50 +- languages/messages/MessagesLiv.php | 6 +- languages/messages/MessagesLmo.php | 12 +- languages/messages/MessagesLn.php | 5 +- languages/messages/MessagesLo.php | 22 +- languages/messages/MessagesLoz.php | 17 +- languages/messages/MessagesLt.php | 172 ++++--- languages/messages/MessagesLtg.php | 10 +- languages/messages/MessagesLus.php | 37 +- languages/messages/MessagesLv.php | 166 ++++--- languages/messages/MessagesLzh.php | 108 ++-- languages/messages/MessagesMai.php | 70 +-- languages/messages/MessagesMap_bms.php | 120 +++-- languages/messages/MessagesMdf.php | 58 +-- languages/messages/MessagesMg.php | 201 +++++--- languages/messages/MessagesMhr.php | 22 +- languages/messages/MessagesMin.php | 211 +++++--- languages/messages/MessagesMk.php | 282 +++++++---- languages/messages/MessagesMl.php | 264 +++++++--- languages/messages/MessagesMn.php | 66 +-- languages/messages/MessagesMr.php | 258 +++++++--- languages/messages/MessagesMrj.php | 2 - languages/messages/MessagesMs.php | 269 +++++++--- languages/messages/MessagesMt.php | 133 +++-- languages/messages/MessagesMwl.php | 22 +- languages/messages/MessagesMy.php | 41 +- languages/messages/MessagesMyv.php | 40 +- languages/messages/MessagesMzn.php | 28 +- languages/messages/MessagesNa.php | 2 +- languages/messages/MessagesNah.php | 21 +- languages/messages/MessagesNan.php | 30 +- languages/messages/MessagesNap.php | 36 +- languages/messages/MessagesNb.php | 249 +++++++--- languages/messages/MessagesNds.php | 61 +-- languages/messages/MessagesNds_nl.php | 264 +++++++--- languages/messages/MessagesNe.php | 186 ++++--- languages/messages/MessagesNew.php | 9 +- languages/messages/MessagesNiu.php | 3 + languages/messages/MessagesNl.php | 286 +++++++---- languages/messages/MessagesNl_informal.php | 361 +++++--------- languages/messages/MessagesNn.php | 212 +++++--- languages/messages/MessagesNov.php | 2 +- languages/messages/MessagesNso.php | 14 +- languages/messages/MessagesNv.php | 2 +- languages/messages/MessagesNy.php | 12 +- languages/messages/MessagesOc.php | 250 ++++++---- languages/messages/MessagesOr.php | 122 ++--- languages/messages/MessagesOs.php | 79 ++- languages/messages/MessagesPa.php | 181 ++++--- languages/messages/MessagesPag.php | 7 +- languages/messages/MessagesPam.php | 53 +- languages/messages/MessagesPap.php | 9 +- languages/messages/MessagesPcd.php | 12 +- languages/messages/MessagesPdc.php | 15 +- languages/messages/MessagesPdt.php | 10 - languages/messages/MessagesPfl.php | 56 +-- languages/messages/MessagesPi.php | 95 +--- languages/messages/MessagesPl.php | 273 +++++++---- languages/messages/MessagesPms.php | 268 +++++++--- languages/messages/MessagesPnb.php | 67 +-- languages/messages/MessagesPnt.php | 20 +- languages/messages/MessagesPrg.php | 61 +-- languages/messages/MessagesPs.php | 102 ++-- languages/messages/MessagesPt.php | 239 ++++++--- languages/messages/MessagesPt_br.php | 263 +++++++--- languages/messages/MessagesQqq.php | 660 ++++++++++++++++++++----- languages/messages/MessagesQu.php | 243 ++++----- languages/messages/MessagesQug.php | 7 +- languages/messages/MessagesRgn.php | 2 - languages/messages/MessagesRm.php | 68 +-- languages/messages/MessagesRo.php | 269 +++++++--- languages/messages/MessagesRoa_tara.php | 261 ++++++---- languages/messages/MessagesRu.php | 300 ++++++++---- languages/messages/MessagesRue.php | 234 ++++++--- languages/messages/MessagesRup.php | 123 ++--- languages/messages/MessagesSa.php | 84 +--- languages/messages/MessagesSah.php | 219 ++++++--- languages/messages/MessagesSat.php | 35 +- languages/messages/MessagesSc.php | 35 +- languages/messages/MessagesScn.php | 110 ++--- languages/messages/MessagesSco.php | 25 +- languages/messages/MessagesSd.php | 9 +- languages/messages/MessagesSdc.php | 49 +- languages/messages/MessagesSe.php | 56 ++- languages/messages/MessagesSei.php | 27 +- languages/messages/MessagesSg.php | 1 + languages/messages/MessagesSgs.php | 31 +- languages/messages/MessagesSh.php | 177 ++++--- languages/messages/MessagesShi.php | 33 +- languages/messages/MessagesSi.php | 125 ++--- languages/messages/MessagesSk.php | 223 ++++++--- languages/messages/MessagesSl.php | 255 +++++++--- languages/messages/MessagesSli.php | 46 +- languages/messages/MessagesSm.php | 2 +- languages/messages/MessagesSma.php | 2 +- languages/messages/MessagesSn.php | 3 + languages/messages/MessagesSo.php | 52 +- languages/messages/MessagesSq.php | 100 ++-- languages/messages/MessagesSr_ec.php | 208 ++++---- languages/messages/MessagesSr_el.php | 152 +++--- languages/messages/MessagesSrn.php | 18 +- languages/messages/MessagesSt.php | 2 +- languages/messages/MessagesStq.php | 64 +-- languages/messages/MessagesSu.php | 59 +-- languages/messages/MessagesSv.php | 278 +++++++---- languages/messages/MessagesSw.php | 84 ++-- languages/messages/MessagesSzl.php | 58 +-- languages/messages/MessagesTa.php | 148 +++--- languages/messages/MessagesTcy.php | 10 +- languages/messages/MessagesTe.php | 135 ++--- languages/messages/MessagesTet.php | 12 +- languages/messages/MessagesTg_cyrl.php | 57 +-- languages/messages/MessagesTg_latn.php | 52 +- languages/messages/MessagesTh.php | 237 +++++---- languages/messages/MessagesTk.php | 65 +-- languages/messages/MessagesTl.php | 113 ++--- languages/messages/MessagesTly.php | 13 +- languages/messages/MessagesTn.php | 3 + languages/messages/MessagesTo.php | 16 +- languages/messages/MessagesTpi.php | 17 +- languages/messages/MessagesTr.php | 225 ++++++--- languages/messages/MessagesTru.php | 12 +- languages/messages/MessagesTs.php | 20 +- languages/messages/MessagesTt_cyrl.php | 85 ++-- languages/messages/MessagesTt_latn.php | 52 +- languages/messages/MessagesTyv.php | 120 +++-- languages/messages/MessagesUdm.php | 20 +- languages/messages/MessagesUg_arab.php | 109 +---- languages/messages/MessagesUk.php | 278 +++++++---- languages/messages/MessagesUr.php | 100 ++-- languages/messages/MessagesUz.php | 71 +-- languages/messages/MessagesVe.php | 10 +- languages/messages/MessagesVec.php | 166 ++++--- languages/messages/MessagesVep.php | 51 +- languages/messages/MessagesVi.php | 326 ++++++++---- languages/messages/MessagesVls.php | 6 +- languages/messages/MessagesVmf.php | 111 +++-- languages/messages/MessagesVo.php | 107 ++-- languages/messages/MessagesVot.php | 16 +- languages/messages/MessagesVro.php | 53 +- languages/messages/MessagesWa.php | 52 +- languages/messages/MessagesWar.php | 156 ++++-- languages/messages/MessagesWo.php | 56 +-- languages/messages/MessagesWuu.php | 118 +++-- languages/messages/MessagesXal.php | 32 +- languages/messages/MessagesXh.php | 3 + languages/messages/MessagesXmf.php | 9 +- languages/messages/MessagesYi.php | 248 +++++++--- languages/messages/MessagesYo.php | 127 ++--- languages/messages/MessagesYue.php | 95 +--- languages/messages/MessagesZea.php | 33 +- languages/messages/MessagesZh_hans.php | 269 +++++++--- languages/messages/MessagesZh_hant.php | 283 +++++++---- languages/messages/MessagesZh_tw.php | 7 +- languages/messages/MessagesZu.php | 47 +- languages/utils/CLDRPluralRuleEvaluator.php | 10 +- 361 files changed, 20583 insertions(+), 15087 deletions(-) create mode 100644 languages/classes/LanguageEs.php delete mode 100644 languages/classes/LanguageHi.php delete mode 100644 languages/classes/LanguageMg.php delete mode 100644 languages/classes/LanguageMk.php delete mode 100644 languages/classes/LanguageMt.php delete mode 100644 languages/classes/LanguageNso.php delete mode 100644 languages/classes/LanguageSh.php delete mode 100644 languages/classes/LanguageSk.php delete mode 100644 languages/classes/LanguageTi.php delete mode 100644 languages/classes/LanguageTl.php create mode 100644 languages/messages/MessagesBbc.php create mode 100644 languages/messages/MessagesBbc_latn.php create mode 100644 languages/messages/MessagesBxr.php (limited to 'languages') diff --git a/languages/Language.php b/languages/Language.php index 1d2e7164..c24dc180 100644 --- a/languages/Language.php +++ b/languages/Language.php @@ -30,10 +30,6 @@ if ( !defined( 'MEDIAWIKI' ) ) { exit( 1 ); } -# Read language names -global $wgLanguageNames; -require_once( __DIR__ . '/Names.php' ); - if ( function_exists( 'mb_strtoupper' ) ) { mb_internal_encoding( 'UTF-8' ); } @@ -44,18 +40,19 @@ if ( function_exists( 'mb_strtoupper' ) ) { * @ingroup Language */ class FakeConverter { - /** * @var Language */ public $mLang; function __construct( $langobj ) { $this->mLang = $langobj; } + function autoConvert( $text, $variant = false ) { return $text; } function autoConvertToAllVariants( $text ) { return array( $this->mLang->getCode() => $text ); } function convert( $t ) { return $t; } function convertTo( $text, $variant ) { return $text; } function convertTitle( $t ) { return $t->getPrefixedText(); } function convertNamespace( $ns ) { return $this->mLang->getFormattedNsText( $ns ); } function getVariants() { return array( $this->mLang->getCode() ); } + function getVariantFallbacks( $variant ) { return $this->mLang->getCode(); } function getPreferredVariant() { return $this->mLang->getCode(); } function getDefaultVariant() { return $this->mLang->getCode(); } function getURLVariant() { return ''; } @@ -66,7 +63,10 @@ class FakeConverter { function markNoConversion( $text, $noParse = false ) { return $text; } function convertCategoryKey( $key ) { return $key; } function convertLinkToAllVariants( $text ) { return $this->autoConvertToAllVariants( $text ); } + /** @deprecated since 1.22 is no longer used */ function armourMath( $text ) { return $text; } + function validateVariant( $variant = null ) { return $variant === $this->mLang->getCode() ? $variant : null; } + function translate( $text, $variant ) { return $text; } } /** @@ -82,7 +82,7 @@ class Language { public $mVariants, $mCode, $mLoaded = false; public $mMagicExtensions = array(), $mMagicHookDone = false; - private $mHtmlCode = null; + private $mHtmlCode = null, $mParentLanguage = false; public $dateFormatStrings = array(); public $mExtendedSpecialPageAliases; @@ -171,6 +171,14 @@ class Language { 'seconds' => 1, ); + /** + * Cache for language fallbacks. + * @see Language::getFallbacksIncludingSiteLanguage + * @since 1.21 + * @var array + */ + static private $fallbackLanguageCache = array(); + /** * Get a cached or new language object for a given language code * @param $code String @@ -221,7 +229,7 @@ class Language { // Check if there is a language class for the code $class = self::classFromCode( $code ); self::preloadLanguageClass( $class ); - if ( MWInit::classExists( $class ) ) { + if ( class_exists( $class ) ) { $lang = new $class; return $lang; } @@ -235,7 +243,7 @@ class Language { $class = self::classFromCode( $fallbackCode ); self::preloadLanguageClass( $class ); - if ( MWInit::classExists( $class ) ) { + if ( class_exists( $class ) ) { $lang = Language::newFromCode( $fallbackCode ); $lang->setCode( $code ); return $lang; @@ -276,7 +284,7 @@ class Language { $alpha = '[a-z]'; $digit = '[0-9]'; $alphanum = '[a-z0-9]'; - $x = 'x' ; # private use singleton + $x = 'x'; # private use singleton $singleton = '[a-wy-z]'; # other singleton $s = $lenient ? '[-_]' : '-'; @@ -327,13 +335,19 @@ class Language { * @return bool */ public static function isValidCode( $code ) { - return - // 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 - // see bugs 37564, 37587, 36938 + static $cache = array(); + if ( isset( $cache[$code] ) ) { + return $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 + // see bugs 37564, 37587, 36938 + $cache[$code] = strcspn( $code, ":/\\\000&<>'\"" ) === strlen( $code ) && !preg_match( Title::getTitleInvalidRegex(), $code ); + + return $cache[$code]; } /** @@ -349,16 +363,16 @@ class Language { public static function isValidBuiltInCode( $code ) { if ( !is_string( $code ) ) { - $type = gettype( $code ); - if ( $type === 'object' ) { + if ( is_object( $code ) ) { $addmsg = " of class " . get_class( $code ); } else { $addmsg = ''; } + $type = gettype( $code ); throw new MWException( __METHOD__ . " must be passed a string, $type given$addmsg" ); } - return (bool)preg_match( '/^[a-z0-9-]+$/i', $code ); + return (bool)preg_match( '/^[a-z0-9-]{2,}$/i', $code ); } /** @@ -372,8 +386,15 @@ class Language { public static function isKnownLanguageTag( $tag ) { static $coreLanguageNames; + // 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; + } + if ( $coreLanguageNames === null ) { - include( MWInit::compiledPath( 'languages/Names.php' ) ); + global $IP; + include "$IP/languages/Names.php"; } if ( isset( $coreLanguageNames[$tag] ) @@ -409,10 +430,8 @@ class Language { return; } - if ( !defined( 'MW_COMPILED' ) ) { - if ( file_exists( "$IP/languages/classes/$class.php" ) ) { - include_once( "$IP/languages/classes/$class.php" ); - } + if ( file_exists( "$IP/languages/classes/$class.php" ) ) { + include_once "$IP/languages/classes/$class.php"; } } @@ -483,6 +502,9 @@ class Language { } /** + * 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. + * * @return array */ public function getNamespaces() { @@ -662,7 +684,18 @@ class Language { } } - $this->namespaceAliases = $aliases; + # Also add converted namespace names as aliases, to avoid confusion. + $convertedNames = array(); + 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; } return $this->namespaceAliases; } @@ -743,20 +776,6 @@ class Language { return $this->getNsText( NS_SPECIAL ) . ':' . $name; } - /** - * @return array - */ - function getQuickbarSettings() { - return array( - $this->getMessage( 'qbsettings-none' ), - $this->getMessage( 'qbsettings-fixedleft' ), - $this->getMessage( 'qbsettings-fixedright' ), - $this->getMessage( 'qbsettings-floatingleft' ), - $this->getMessage( 'qbsettings-floatingright' ), - $this->getMessage( 'qbsettings-directionality' ) - ); - } - /** * @return array */ @@ -857,7 +876,8 @@ class Language { static $coreLanguageNames; if ( $coreLanguageNames === null ) { - include( MWInit::compiledPath( 'languages/Names.php' ) ); + global $IP; + include "$IP/languages/Names.php"; } $names = array(); @@ -1033,8 +1053,8 @@ class Language { * internationalisation, a reduced set of format characters, and a better * escaping format. * - * Supported format characters are dDjlNwzWFmMntLoYyaAgGhHiscrU. See the - * PHP manual for definitions. There are a number of extensions, which + * Supported format characters are dDjlNwzWFmMntLoYyaAgGhHiscrUeIOPTZ. See + * the PHP manual for definitions. There are a number of extensions, which * start with "x": * * xn Do not translate digits of the next numeric format character @@ -1080,22 +1100,25 @@ class Language { * Backslash escaping is also supported. * * Input timestamp is assumed to be pre-normalized to the desired local - * time zone, if any. + * time zone, if any. Note that the format characters crUeIOPTZ will assume + * $ts is UTC if $zone is not given. * * @param $format String * @param $ts String: 14-character timestamp * YYYYMMDDHHMMSS * 01234567890123 + * @param $zone DateTimeZone: Timezone of $ts * @todo handling of "o" format character for Iranian, Hebrew, Hijri & Thai? * + * @throws MWException * @return string */ - function sprintfDate( $format, $ts ) { + function sprintfDate( $format, $ts, DateTimeZone $zone = null ) { $s = ''; $raw = false; $roman = false; $hebrewNum = false; - $unix = false; + $dateTimeObj = false; $rawToggle = false; $iranian = false; $hebrew = false; @@ -1103,6 +1126,15 @@ class Language { $thai = false; $minguo = false; $tenno = false; + + 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" ); + } + for ( $p = 0; $p < strlen( $format ); $p++ ) { $num = false; $code = $format[$p]; @@ -1134,15 +1166,21 @@ class Language { $s .= $this->getMonthNameGen( substr( $ts, 4, 2 ) ); break; case 'xjx': - if ( !$hebrew ) $hebrew = self::tsToHebrew( $ts ); + if ( !$hebrew ) { + $hebrew = self::tsToHebrew( $ts ); + } $s .= $this->getHebrewCalendarMonthNameGen( $hebrew[1] ); break; case 'd': $num = substr( $ts, 6, 2 ); break; case 'D': - if ( !$unix ) $unix = wfTimestamp( TS_UNIX, $ts ); - $s .= $this->getWeekdayAbbreviation( gmdate( 'w', $unix ) + 1 ); + if ( !$dateTimeObj ) { + $dateTimeObj = DateTime::createFromFormat( + 'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' ) + ); + } + $s .= $this->getWeekdayAbbreviation( $dateTimeObj->format( 'w' ) + 1 ); break; case 'j': $num = intval( substr( $ts, 6, 2 ) ); @@ -1166,35 +1204,12 @@ class Language { $num = $hebrew[2]; break; case 'l': - if ( !$unix ) { - $unix = wfTimestamp( TS_UNIX, $ts ); - } - $s .= $this->getWeekdayName( gmdate( 'w', $unix ) + 1 ); - break; - case 'N': - if ( !$unix ) { - $unix = wfTimestamp( TS_UNIX, $ts ); + if ( !$dateTimeObj ) { + $dateTimeObj = DateTime::createFromFormat( + 'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' ) + ); } - $w = gmdate( 'w', $unix ); - $num = $w ? $w : 7; - break; - case 'w': - if ( !$unix ) { - $unix = wfTimestamp( TS_UNIX, $ts ); - } - $num = gmdate( 'w', $unix ); - break; - case 'z': - if ( !$unix ) { - $unix = wfTimestamp( TS_UNIX, $ts ); - } - $num = gmdate( 'z', $unix ); - break; - case 'W': - if ( !$unix ) { - $unix = wfTimestamp( TS_UNIX, $ts ); - } - $num = gmdate( 'W', $unix ); + $s .= $this->getWeekdayName( $dateTimeObj->format( 'w' ) + 1 ); break; case 'F': $s .= $this->getMonthName( substr( $ts, 4, 2 ) ); @@ -1244,30 +1259,12 @@ class Language { } $num = $hebrew[1]; break; - case 't': - if ( !$unix ) { - $unix = wfTimestamp( TS_UNIX, $ts ); - } - $num = gmdate( 't', $unix ); - break; case 'xjt': if ( !$hebrew ) { $hebrew = self::tsToHebrew( $ts ); } $num = $hebrew[3]; break; - case 'L': - if ( !$unix ) { - $unix = wfTimestamp( TS_UNIX, $ts ); - } - $num = gmdate( 'L', $unix ); - break; - case 'o': - if ( !$unix ) { - $unix = wfTimestamp( TS_UNIX, $ts ); - } - $num = gmdate( 'o', $unix ); - break; case 'Y': $num = substr( $ts, 0, 4 ); break; @@ -1343,22 +1340,36 @@ class Language { $num = substr( $ts, 12, 2 ); break; case 'c': - if ( !$unix ) { - $unix = wfTimestamp( TS_UNIX, $ts ); - } - $s .= gmdate( 'c', $unix ); - break; case 'r': - if ( !$unix ) { - $unix = wfTimestamp( TS_UNIX, $ts ); + case 'e': + case 'O': + case 'P': + case 'T': + // Pass through string from $dateTimeObj->format() + if ( !$dateTimeObj ) { + $dateTimeObj = DateTime::createFromFormat( + 'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' ) + ); } - $s .= gmdate( 'r', $unix ); + $s .= $dateTimeObj->format( $code ); break; + case 'w': + case 'N': + case 'z': + case 'W': + case 't': + case 'L': + case 'o': case 'U': - if ( !$unix ) { - $unix = wfTimestamp( TS_UNIX, $ts ); + case 'I': + case 'Z': + // Pass through number from $dateTimeObj->format() + if ( !$dateTimeObj ) { + $dateTimeObj = DateTime::createFromFormat( + 'YmdHis', $ts, $zone ?: new DateTimeZone( 'UTC' ) + ); } - $num = $unix; + $num = $dateTimeObj->format( $code ); break; case '\\': # Backslash escaping @@ -1673,7 +1684,7 @@ class Language { private static function hebrewYearStart( $year ) { $a = intval( ( 12 * ( $year - 1 ) + 17 ) % 19 ); $b = intval( ( $year - 1 ) % 4 ); - $m = 32.044093161144 + 1.5542417966212 * $a + $b / 4.0 - 0.0031777940220923 * ( $year - 1 ); + $m = 32.044093161144 + 1.5542417966212 * $a + $b / 4.0 - 0.0031777940220923 * ( $year - 1 ); if ( $m < 0 ) { $m--; } @@ -1847,13 +1858,13 @@ class Language { } if ( strlen( $s ) == 2 ) { $str = $s . "'"; - } else { + } else { $str = substr( $s, 0, strlen( $s ) - 2 ) . '"'; $str .= substr( $s, strlen( $s ) - 2, 2 ); } $start = substr( $str, 0, strlen( $str ) - 2 ); $end = substr( $str, strlen( $str ) - 2 ); - switch( $end ) { + switch ( $end ) { case 'כ': $str = $start . 'ך'; break; @@ -1936,12 +1947,12 @@ class Language { # will normalize out-of-range values so we don't have to split $minDiff # into hours and minutes. $t = mktime( ( - (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 + (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 $date = date( 'YmdHis', $t ); wfRestoreWarnings(); @@ -1992,6 +2003,8 @@ class Language { * @param $type string May be date, time or both * @param $pref string The format name as it appears in Messages*.php * + * @since 1.22 New type 'pretty' that provides a more readable timestamp format + * * @return string */ function getDateFormatString( $type, $pref ) { @@ -2001,7 +2014,12 @@ class Language { $df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" ); } else { $df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" ); - if ( is_null( $df ) ) { + + if ( $type === 'pretty' && $df === null ) { + $df = $this->getDateFormatString( 'date', $pref ); + } + + if ( $df === null ) { $pref = $this->getDefaultDateFormat(); $df = self::$dataCache->getSubitem( $this->mCode, 'dateFormats', "$pref $type" ); } @@ -2085,6 +2103,8 @@ class Language { $segments = array(); foreach ( $intervals as $intervalName => $intervalValue ) { + // Messages: duration-seconds, duration-minutes, duration-hours, duration-days, duration-weeks, + // duration-years, duration-decades, duration-centuries, duration-millennia $message = wfMessage( 'duration-' . $intervalName )->numParams( $intervalValue ); $segments[] = $message->inLanguage( $this )->escaped(); } @@ -2234,6 +2254,81 @@ class Language { return $this->internalUserTimeAndDate( 'both', $ts, $user, $options ); } + /** + * Convert an MWTimestamp into a pretty human-readable timestamp using + * the given user preferences and relative base time. + * + * DO NOT USE THIS FUNCTION DIRECTLY. Instead, call MWTimestamp::getHumanTimestamp + * on your timestamp object, which will then call this function. Calling + * this function directly will cause hooks to be skipped over. + * + * @see MWTimestamp::getHumanTimestamp + * @param MWTimestamp $ts Timestamp to prettify + * @param MWTimestamp $relativeTo Base timestamp + * @param User $user User preferences to use + * @return string Human timestamp + * @since 1.22 + */ + public function getHumanTimestamp( MWTimestamp $ts, MWTimestamp $relativeTo, User $user ) { + $diff = $ts->diff( $relativeTo ); + $diffDay = (bool)( (int)$ts->timestamp->format( 'w' ) - (int)$relativeTo->timestamp->format( 'w' ) ); + $days = $diff->days ?: (int)$diffDay; + if ( $diff->invert || $days > 5 && $ts->timestamp->format( 'Y' ) !== $relativeTo->timestamp->format( 'Y' ) ) { + // Timestamps are in different years: use full timestamp + // Also do full timestamp for future dates + /** + * @FIXME Add better handling of future timestamps. + */ + $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' )]; + // Messages: + // sunday-at, monday-at, tuesday-at, wednesday-at, thursday-at, friday-at, saturday-at + $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; + } + /** * @param $key string * @return array|null @@ -2523,7 +2618,7 @@ class Language { */ function checkTitleEncoding( $s ) { if ( is_array( $s ) ) { - wfDebugDieBacktrace( 'Given array to checkTitleEncoding.' ); + throw new MWException( 'Given array to checkTitleEncoding.' ); } if ( StringUtils::isUtf8( $s ) ) { return $s; @@ -2817,7 +2912,9 @@ class Language { * @since 1.20 */ function getDirMarkEntity( $opposite = false ) { - if ( $opposite ) { return $this->isRTL() ? '‎' : '‏'; } + if ( $opposite ) { + return $this->isRTL() ? '‎' : '‏'; + } return $this->isRTL() ? '‏' : '‎'; } @@ -2834,7 +2931,9 @@ class Language { function getDirMark( $opposite = false ) { $lrm = "\xE2\x80\x8E"; # LEFT-TO-RIGHT MARK, commonly abbreviated LRM $rlm = "\xE2\x80\x8F"; # RIGHT-TO-LEFT MARK, commonly abbreviated RLM - if ( $opposite ) { return $this->isRTL() ? $lrm : $rlm; } + if ( $opposite ) { + return $this->isRTL() ? $lrm : $rlm; + } return $this->isRTL() ? $rlm : $lrm; } @@ -2878,12 +2977,16 @@ class Language { } /** + * Get all magic words from cache. * @return array */ function getMagicWords() { return self::$dataCache->getItem( $this->mCode, 'magicWords' ); } + /** + * Run the LanguageGetMagic hook once. + */ protected function doMagicHook() { if ( $this->mMagicHookDone ) { return; @@ -2900,17 +3003,16 @@ class Language { * @param $mw */ function getMagic( $mw ) { - $this->doMagicHook(); + // Saves a function call + if ( ! $this->mMagicHookDone ) { + $this->doMagicHook(); + } if ( isset( $this->mMagicExtensions[$mw->mId] ) ) { $rawEntry = $this->mMagicExtensions[$mw->mId]; } else { - $magicWords = $this->getMagicWords(); - if ( isset( $magicWords[$mw->mId] ) ) { - $rawEntry = $magicWords[$mw->mId]; - } else { - $rawEntry = false; - } + $rawEntry = self::$dataCache->getSubitem( + $this->mCode, 'magicWords', $mw->mId ); } if ( !is_array( $rawEntry ) ) { @@ -2967,7 +3069,7 @@ class Language { * 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 - * languages, some such as Pakaran want ੨੯੩,੨੯੫.੨੩੫ and others such as + * languages, some such as Punjabi want ੨੯੩,੨੯੫.੨੩੫ and others such as * Icelandic just want to use commas instead of dots, and dots instead * of commas like "293.291,235". * @@ -3058,7 +3160,7 @@ class Language { $sign = ""; if ( intval( $number ) < 0 ) { // For negative numbers apply the algorithm like positive number and add sign. - $sign = "-"; + $sign = "-"; $number = substr( $number, 1 ); } $integerPart = array(); @@ -3066,20 +3168,20 @@ class Language { $numMatches = preg_match_all( "/(#+)/", $digitGroupingPattern, $matches ); preg_match( "/\d+/", $number, $integerPart ); preg_match( "/\.\d*/", $number, $decimalPart ); - $groupedNumber = ( count( $decimalPart ) > 0 ) ? $decimalPart[0]:""; - if ( $groupedNumber === $number ) { + $groupedNumber = ( count( $decimalPart ) > 0 ) ? $decimalPart[0] : ""; + if ( $groupedNumber === $number ) { // the string does not have any number part. Eg: .12345 return $sign . $groupedNumber; } $start = $end = strlen( $integerPart[0] ); while ( $start > 0 ) { - $match = $matches[0][$numMatches -1] ; + $match = $matches[0][$numMatches - 1]; $matchLen = strlen( $match ); $start = $end - $matchLen; if ( $start < 0 ) { $start = 0; } - $groupedNumber = substr( $number, $start, $end -$start ) . $groupedNumber ; + $groupedNumber = substr( $number, $start, $end -$start ) . $groupedNumber; $end = $start; if ( $numMatches > 1 ) { // use the last pattern for the rest of the number @@ -3256,9 +3358,9 @@ class Language { # We got the first byte only of a multibyte char; remove it. $string = substr( $string, 0, -1 ); } elseif ( $char >= 0x80 && - preg_match( '/^(.*)(?:[\xe0-\xef][\x80-\xbf]|' . - '[\xf0-\xf7][\x80-\xbf]{1,2})$/', $string, $m ) ) - { + preg_match( '/^(.*)(?:[\xe0-\xef][\x80-\xbf]|' . + '[\xf0-\xf7][\x80-\xbf]{1,2})$/', $string, $m ) + ) { # We chopped in the middle of a character; remove it $string = $m[1]; } @@ -3342,7 +3444,9 @@ class Language { break; } } - if ( $pos >= $textLen ) break; // extra iteration just for above checks + if ( $pos >= $textLen ) { + break; // extra iteration just for above checks + } # Read the next char... $ch = $text[$pos]; @@ -3475,7 +3579,7 @@ class Language { function getGrammarForms() { global $wgGrammarForms; if ( isset( $wgGrammarForms[$this->getCode()] ) && is_array( $wgGrammarForms[$this->getCode()] ) ) { - return $wgGrammarForms[$this->getCode()]; + return $wgGrammarForms[$this->getCode()]; } return array(); } @@ -3528,23 +3632,23 @@ class Language { * @return string Correct form of plural for $count in this language */ function convertPlural( $count, $forms ) { - if ( !count( $forms ) ) { - return ''; - } - // Handle explicit n=pluralform cases foreach ( $forms as $index => $form ) { - if ( preg_match( '/\d+=/i', $form ) ) { + if ( preg_match( '/^\d+=/i', $form ) ) { $pos = strpos( $form, '=' ); - if ( substr( $form, 0, $pos ) === (string) $count ) { + if ( substr( $form, 0, $pos ) === (string)$count ) { return substr( $form, $pos + 1 ); } unset( $forms[$index] ); } } + $forms = array_values( $forms ); + if ( !count( $forms ) ) { + return ''; + } - $pluralForm = $this->getPluralForm( $count ); + $pluralForm = $this->getPluralRuleIndexNumber( $count ); $pluralForm = min( $pluralForm, count( $forms ) - 1 ); return $forms[$pluralForm]; } @@ -3708,6 +3812,7 @@ class Language { * * @param $text string * @return string + * @deprecated since 1.22 is no longer used */ public function armourMath( $text ) { return $this->mConverter->armourMath( $text ); @@ -3853,6 +3958,34 @@ class Language { return $this; } + /** + * 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; + } + + $pieces = explode( '-', $this->getCode() ); + $code = $pieces[0]; + if ( !in_array( $code, LanguageConverter::$languagesWithVariants ) ) { + $this->mParentLanguage = null; + return null; + } + $lang = Language::factory( $code ); + if ( !$lang->hasVariant( $this->getCode() ) ) { + $this->mParentLanguage = null; + return null; + } + + $this->mParentLanguage = $lang; + return $lang; + } + /** * Get the RFC 3066 code for this language object * @@ -3887,8 +4020,9 @@ class Language { */ public function setCode( $code ) { $this->mCode = $code; - // Ensure we don't leave an incorrect html code lying around + // Ensure we don't leave incorrect cached data lying around $this->mHtmlCode = null; + $this->mParentLanguage = false; } /** @@ -3984,6 +4118,36 @@ class Language { } } + /** + * 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 + * @return array array( fallbacks, site fallbacks ) + */ + 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 ); + + self::$fallbackLanguageCache[$cacheKey] = array( $fallbacks, $siteFallbacks ); + } + return self::$fallbackLanguageCache[$cacheKey]; + } + /** * Get all messages for a given language * WARNING: this may take a long time. If you just need all message *keys* @@ -4084,15 +4248,14 @@ class Language { * @since 1.18 */ public function formatExpiry( $expiry, $format = true ) { - static $infinity, $infinityMsg; + static $infinity; if ( $infinity === null ) { - $infinityMsg = wfMessage( 'infiniteblock' ); $infinity = wfGetDB( DB_SLAVE )->getInfinity(); } if ( $expiry == '' || $expiry == $infinity ) { return $format === true - ? $infinityMsg + ? $this->getMessageFromDB( 'infiniteblock' ) : $infinity; } else { return $format === true @@ -4307,7 +4470,7 @@ class Language { $nlink = htmlspecialchars( $next ); } else { $nlink = $this->numLink( $title, $offset + $limit, $limit, - $query, $next, 'prevn-title', 'mw-nextlink' ); + $query, $next, 'nextn-title', 'mw-nextlink' ); } # Make links to set number of items per page @@ -4371,7 +4534,7 @@ class Language { /** * Get the plural rules for the language * @since 1.20 - * @return array Associative array with plural form, and plural rule as key-value pairs + * @return array Associative array with plural form number and plural rule as key-value pairs */ public function getPluralRules() { $pluralRules = self::$dataCache->getItem( strtolower( $this->mCode ), 'pluralRules' ); @@ -4388,13 +4551,48 @@ class Language { } /** - * Find the plural form matching to the given number - * It return the form index. - * @return int The index of the plural form + * Get the plural rule types for the language + * @since 1.22 + * @return array Associative array with plural form number and plural rule type as key-value pairs */ - private function getPluralForm( $number ) { + public function getPluralRuleTypes() { + $pluralRuleTypes = self::$dataCache->getItem( strtolower( $this->mCode ), 'pluralRuleTypes' ); + $fallbacks = Language::getFallbacksFor( $this->mCode ); + 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 + * @return int The index number of the plural rule + */ + public function getPluralRuleIndexNumber( $number ) { $pluralRules = $this->getCompiledPluralRules(); $form = CLDRPluralRuleEvaluator::evaluateCompiled( $number, $pluralRules ); return $form; } + + /** + * Find the plural rule type appropriate for the given number + * For example, if the language is set to Arabic, getPluralType(5) should + * return 'few'. + * @since 1.22 + * @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(); + if ( isset( $pluralRuleTypes[$index] ) ) { + return $pluralRuleTypes[$index]; + } else { + return 'other'; + } + } } diff --git a/languages/LanguageConverter.php b/languages/LanguageConverter.php index 43afe653..96a71a09 100644 --- a/languages/LanguageConverter.php +++ b/languages/LanguageConverter.php @@ -246,7 +246,7 @@ class LanguageConverter { * @return Mixed: variant if one found, false otherwise. */ protected function getUserVariant() { - global $wgUser; + global $wgUser, $wgContLang; // memoizing this function wreaks havoc on parserTest.php /* @@ -258,8 +258,12 @@ class LanguageConverter { // Get language variant preference from logged in users // Don't call this on stub objects because that causes infinite // recursion during initialisation - if ( $wgUser->isLoggedIn() ) { - $ret = $wgUser->getOption( 'variant' ); + if ( $wgUser->isLoggedIn() ) { + if ( $this->mMainLanguageCode == $wgContLang->getCode() ) { + $ret = $wgUser->getOption( 'variant' ); + } else { + $ret = $wgUser->getOption( 'variant-' . $this->mMainLanguageCode ); + } } else { // figure out user lang without constructing wgLang to avoid // infinite recursion @@ -344,7 +348,7 @@ class LanguageConverter { } } - if( $this->guessVariant( $text, $toVariant ) ) { + if ( $this->guessVariant( $text, $toVariant ) ) { wfProfileOut( __METHOD__ ); return $text; } @@ -364,11 +368,11 @@ class LanguageConverter { // this one is needed when the text is inside an HTML markup $htmlfix = '|<[^>]+$|^[^<>]*>'; - // disable convert to variants between tags + // disable convert to variants between tags $codefix = '.+?<\/code>|'; - // disable convertsion of + // disable conversion of