MediaWiki  master
IcuCollation.php
Go to the documentation of this file.
1 <?php
22 
26 class IcuCollation extends Collation {
27  private const FIRST_LETTER_VERSION = 4;
28 
31 
33  private $mainCollator;
34 
36  private $locale;
37 
40 
42  private $useNumericCollation = false;
43 
46 
56  private static $cjkBlocks = [
57  [ 0x2E80, 0x2EFF ], // CJK Radicals Supplement
58  [ 0x2F00, 0x2FDF ], // Kangxi Radicals
59  [ 0x2FF0, 0x2FFF ], // Ideographic Description Characters
60  [ 0x3000, 0x303F ], // CJK Symbols and Punctuation
61  [ 0x31C0, 0x31EF ], // CJK Strokes
62  [ 0x3200, 0x32FF ], // Enclosed CJK Letters and Months
63  [ 0x3300, 0x33FF ], // CJK Compatibility
64  [ 0x3400, 0x4DBF ], // CJK Unified Ideographs Extension A
65  [ 0x4E00, 0x9FFF ], // CJK Unified Ideographs
66  [ 0xF900, 0xFAFF ], // CJK Compatibility Ideographs
67  [ 0xFE30, 0xFE4F ], // CJK Compatibility Forms
68  [ 0x20000, 0x2A6DF ], // CJK Unified Ideographs Extension B
69  [ 0x2A700, 0x2B73F ], // CJK Unified Ideographs Extension C
70  [ 0x2B740, 0x2B81F ], // CJK Unified Ideographs Extension D
71  [ 0x2F800, 0x2FA1F ], // CJK Compatibility Ideographs Supplement
72  ];
73 
95  private static $tailoringFirstLetters = [
96  'af' => [],
97  'am' => [],
98  'ar' => [],
99  'as' => [ "\u{0982}", "\u{0981}", "\u{0983}", "\u{09CE}", "ক্ষ " ],
100  'ast' => [ "Ch", "Ll", "Ñ" ], // not in libicu
101  'az' => [ "Ç", "Ə", "Ğ", "İ", "Ö", "Ş", "Ü" ],
102  'be' => [ "Ё" ],
103  'be-tarask' => [ "Ё" ],
104  'bg' => [],
105  'bn' => [ 'ং', 'ঃ', 'ঁ' ],
106  'bn@collation=traditional' => [
107  'ং', 'ঃ', 'ঁ', 'ক্', 'খ্', 'গ্', 'ঘ্', 'ঙ্', 'চ্', 'ছ্', 'জ্', 'ঝ্',
108  'ঞ্', 'ট্', 'ঠ্', 'ড্', 'ঢ্', 'ণ্', 'ৎ', 'থ্', 'দ্', 'ধ্', 'ন্', 'প্',
109  'ফ্', 'ব্', 'ভ্', 'ম্', 'য্', 'র্', 'ৰ্', 'ল্', 'ৱ্', 'শ্', 'ষ্', 'স্', 'হ্'
110  ],
111  'bo' => [],
112  'br' => [ "Ch", "C'h" ],
113  'bs' => [ "Č", "Ć", "Dž", "Đ", "Lj", "Nj", "Š", "Ž" ],
114  'bs-Cyrl' => [],
115  'ca' => [],
116  'chr' => [],
117  'co' => [], // not in libicu
118  'cs' => [ "Č", "Ch", "Ř", "Š", "Ž" ],
119  'cy' => [ "Ch", "Dd", "Ff", "Ng", "Ll", "Ph", "Rh", "Th" ],
120  'da' => [ "Æ", "Ø", "Å" ],
121  'de' => [],
122  'de-AT@collation=phonebook' => [ 'ä', 'ö', 'ü', 'ß' ],
123  'dsb' => [ "Č", "Ć", "Dź", "Ě", "Ch", "Ł", "Ń", "Ŕ", "Š", "Ś", "Ž", "Ź" ],
124  'ee' => [ "Dz", "Ɖ", "Ɛ", "Ƒ", "Gb", "Ɣ", "Kp", "Ny", "Ŋ", "Ɔ", "Ts", "Ʋ" ],
125  'el' => [],
126  'en' => [],
127  'eo' => [ "Ĉ", "Ĝ", "Ĥ", "Ĵ", "Ŝ", "Ŭ" ],
128  'es' => [ "Ñ" ],
129  'et' => [ "Š", "Ž", "Õ", "Ä", "Ö", "Ü" ],
130  'eu' => [ "Ñ" ], // not in libicu
131  'fa' => [
132  // RTL, let's put each letter on a new line
133  "آ",
134  "ء",
135  "ه",
136  "ا",
137  "و"
138  ],
139  'fi' => [ "Å", "Ä", "Ö" ],
140  'fil' => [ "Ñ", "Ng" ],
141  'fo' => [ "Á", "Ð", "Í", "Ó", "Ú", "Ý", "Æ", "Ø", "Å" ],
142  'fr' => [],
143  'fr-CA' => [], // fr-CA sorts accents slightly different from fr.
144  'fur' => [ "À", "Á", "Â", "È", "Ì", "Ò", "Ù" ], // not in libicu
145  'fy' => [], // not in libicu
146  'ga' => [],
147  'gd' => [], // not in libicu
148  'gl' => [ "Ch", "Ll", "Ñ" ],
149  'gu' => [ "\u{0A82}", "\u{0A83}", "\u{0A81}", "\u{0AB3}" ],
150  'ha' => [ 'Ɓ', 'Ɗ', 'Ƙ', 'Sh', 'Ts', 'Ƴ' ],
151  'haw' => [ 'ʻ' ],
152  'he' => [],
153  'hi' => [ "\u{0902}", "\u{0903}" ],
154  'hr' => [ "Č", "Ć", "Dž", "Đ", "Lj", "Nj", "Š", "Ž" ],
155  'hsb' => [ "Č", "Dź", "Ě", "Ch", "Ł", "Ń", "Ř", "Š", "Ć", "Ž" ],
156  'hu' => [ "Cs", "Dz", "Dzs", "Gy", "Ly", "Ny", "Ö", "Sz", "Ty", "Ü", "Zs" ],
157  'hy' => [ "և" ],
158  'id' => [],
159  'ig' => [ "Ch", "Gb", "Gh", "Gw", "Ị", "Kp", "Kw", "Ṅ", "Nw", "Ny", "Ọ", "Sh", "Ụ" ],
160  'is' => [ "Á", "Ð", "É", "Í", "Ó", "Ú", "Ý", "Þ", "Æ", "Ö", "Å" ],
161  'it' => [],
162  'ka' => [],
163  'kk' => [ "Ү", "І" ],
164  'kl' => [ "Æ", "Ø", "Å" ],
165  'km' => [
166  "រ", "ឫ", "ឬ", "ល", "ឭ", "ឮ", "\u{17BB}\u{17C6}",
167  "\u{17C6}", "\u{17B6}\u{17C6}", "\u{17C7}",
168  "\u{17B7}\u{17C7}", "\u{17BB}\u{17C7}",
169  "\u{17C1}\u{17C7}", "\u{17C4}\u{17C7}",
170  ],
171  'kn' => [ "\u{0C81}", "\u{0C83}", "\u{0CF1}", "\u{0CF2}" ],
172  'kok' => [ "\u{0902}", "\u{0903}", "ळ", "क्ष" ],
173  'ku' => [ "Ç", "Ê", "Î", "Ş", "Û" ], // not in libicu
174  'ky' => [ "Ё" ],
175  'la' => [], // not in libicu
176  'lb' => [],
177  'lkt' => [ 'Č', 'Ǧ', 'Ȟ', 'Š', 'Ž' ],
178  'ln' => [ 'Ɛ' ],
179  'lo' => [],
180  'lt' => [ "Č", "Š", "Ž" ],
181  'lv' => [ "Č", "Ģ", "Ķ", "Ļ", "Ņ", "Š", "Ž" ],
182  'mk' => [ "Ѓ", "Ќ" ],
183  'ml' => [],
184  'mn' => [],
185  'mo' => [ "Ă", "Â", "Î", "Ș", "Ț" ], // not in libicu
186  'mr' => [ "\u{0902}", "\u{0903}", "ळ", "क्ष", "ज्ञ" ],
187  'ms' => [],
188  'mt' => [ "Ċ", "Ġ", "Għ", "Ħ", "Ż" ],
189  'nb' => [ "Æ", "Ø", "Å" ],
190  'ne' => [],
191  'nl' => [],
192  'nn' => [ "Æ", "Ø", "Å" ],
193  'no' => [ "Æ", "Ø", "Å" ], // not in libicu. You should probably use nb or nn instead.
194  'oc' => [], // not in libicu
195  'om' => [ 'Ch', 'Dh', 'Kh', 'Ny', 'Ph', 'Sh' ],
196  'or' => [ "\u{0B01}", "\u{0B02}", "\u{0B03}", "କ୍ଷ" ],
197  'pa' => [ "\u{0A4D}" ],
198  'pl' => [ "Ą", "Ć", "Ę", "Ł", "Ń", "Ó", "Ś", "Ź", "Ż" ],
199  'pt' => [],
200  'rm' => [], // not in libicu
201  'ro' => [ "Ă", "Â", "Î", "Ș", "Ț" ],
202  'ru' => [],
203  'rup' => [ "Ă", "Â", "Î", "Ľ", "Ń", "Ș", "Ț" ], // not in libicu
204  'sco' => [],
205  'se' => [
206  'Á', 'Č', 'Ʒ', 'Ǯ', 'Đ', 'Ǧ', 'Ǥ', 'Ǩ', 'Ŋ',
207  'Š', 'Ŧ', 'Ž', 'Ø', 'Æ', 'Ȧ', 'Ä', 'Ö'
208  ],
209  'si' => [ "\u{0D82}", "\u{0D83}", "\u{0DA4}" ],
210  'sk' => [ "Ä", "Č", "Ch", "Ô", "Š", "Ž" ],
211  'sl' => [ "Č", "Š", "Ž" ],
212  'smn' => [ "Á", "Č", "Đ", "Ŋ", "Š", "Ŧ", "Ž", "Æ", "Ø", "Å", "Ä", "Ö" ],
213  'sq' => [ "Ç", "Dh", "Ë", "Gj", "Ll", "Nj", "Rr", "Sh", "Th", "Xh", "Zh" ],
214  'sr' => [],
215  'sr-Latn' => [ "Č", "Ć", "Dž", "Đ", "Lj", "Nj", "Š", "Ž" ],
216  'sv' => [ "Å", "Ä", "Ö" ],
217  'sv@collation=standard' => [ "Å", "Ä", "Ö" ],
218  'sw' => [],
219  'ta' => [
220  "\u{0B82}", "ஃ", "க்ஷ", "க்", "ங்", "ச்", "ஞ்", "ட்", "ண்", "த்", "ந்",
221  "ப்", "ம்", "ய்", "ர்", "ல்", "வ்", "ழ்", "ள்", "ற்", "ன்", "ஜ்", "ஶ்", "ஷ்",
222  "ஸ்", "ஹ்", "க்ஷ்"
223  ],
224  'te' => [ "\u{0C01}", "\u{0C02}", "\u{0C03}" ],
225  'th' => [ "ฯ", "\u{0E46}", "\u{0E4D}", "\u{0E3A}" ],
226  'tk' => [ "Ç", "Ä", "Ž", "Ň", "Ö", "Ş", "Ü", "Ý" ],
227  'tl' => [ "Ñ", "Ng" ], // not in libicu
228  'to' => [ "Ng", "ʻ" ],
229  'tr' => [ "Ç", "Ğ", "İ", "Ö", "Ş", "Ü" ],
230  '-tr' => [ "ı" ],
231  'tt' => [ "Ә", "Ө", "Ү", "Җ", "Ң", "Һ" ], // not in libicu
232  'uk' => [ "Ґ", "Ь" ],
233  'uz' => [ "Ch", "G'", "Ng", "O'", "Sh" ], // not in libicu
234  'vi' => [ "Ă", "Â", "Đ", "Ê", "Ô", "Ơ", "Ư" ],
235  'vo' => [ "Ä", "Ö", "Ü" ],
236  'yi' => [
237  "\u{05D1}\u{05BF}", "\u{05DB}\u{05BC}", "\u{05E4}\u{05BC}",
238  "\u{05E9}\u{05C2}", "\u{05EA}\u{05BC}"
239  ],
240  'yo' => [ "Ẹ", "Gb", "Ọ", "Ṣ" ],
241  'zu' => [],
242  ];
243 
244  public function __construct( $locale ) {
245  if ( !extension_loaded( 'intl' ) ) {
246  throw new MWException( 'An ICU collation was requested, ' .
247  'but the intl extension is not available.' );
248  }
249 
250  $this->locale = $locale;
251  // Drop everything after the '@' in locale's name
252  $localeParts = explode( '@', $locale );
253  $this->digitTransformLanguage = MediaWikiServices::getInstance()->getLanguageFactory()
254  ->getLanguage( $locale === 'root' ? 'en' : $localeParts[0] );
255 
256  $this->mainCollator = Collator::create( $locale );
257  if ( !$this->mainCollator ) {
258  throw new MWException( "Invalid ICU locale specified for collation: $locale" );
259  }
260 
261  $this->primaryCollator = Collator::create( $locale );
262  $this->primaryCollator->setStrength( Collator::PRIMARY );
263 
264  // If the special suffix for numeric collation is present, turn on numeric collation.
265  if ( substr( $locale, -5, 5 ) === '-u-kn' ) {
266  $this->useNumericCollation = true;
267  // Strip off the special suffix so it doesn't trip up fetchFirstLetterData().
268  $this->locale = substr( $this->locale, 0, -5 );
269  $this->mainCollator->setAttribute( Collator::NUMERIC_COLLATION, Collator::ON );
270  $this->primaryCollator->setAttribute( Collator::NUMERIC_COLLATION, Collator::ON );
271  }
272  }
273 
274  public function getSortKey( $string ) {
275  return $this->mainCollator->getSortKey( $string );
276  }
277 
278  public function getPrimarySortKey( $string ) {
279  return $this->primaryCollator->getSortKey( $string );
280  }
281 
282  public function getFirstLetter( $string ) {
283  $string = strval( $string );
284  if ( $string === '' ) {
285  return '';
286  }
287 
288  $firstChar = mb_substr( $string, 0, 1, 'UTF-8' );
289 
290  // If the first character is a CJK character, just return that character.
291  if ( ord( $firstChar ) > 0x7f && self::isCjk( UtfNormal\Utils::utf8ToCodepoint( $firstChar ) ) ) {
292  return $firstChar;
293  }
294 
295  $sortKey = $this->getPrimarySortKey( $string );
296 
297  // Do a binary search to find the correct letter to sort under
299  [ $this, 'getSortKeyByLetterIndex' ],
300  $this->getFirstLetterCount(),
301  'strcmp',
302  $sortKey );
303 
304  if ( $min === false ) {
305  // Before the first letter
306  return '';
307  }
308 
309  $sortLetter = $this->getLetterByIndex( $min );
310 
311  if ( $this->useNumericCollation ) {
312  // If the sort letter is a number, return '0–9' (or localized equivalent).
313  // ASCII value of 0 is 48. ASCII value of 9 is 57.
314  // Note that this also applies to non-Arabic numerals since they are
315  // mapped to Arabic numeral sort letters. For example, ২ sorts as 2.
316  if ( ord( $sortLetter ) >= 48 && ord( $sortLetter ) <= 57 ) {
317  $sortLetter = wfMessage( 'category-header-numerals' )->numParams( 0, 9 )->text();
318  }
319  }
320  return $sortLetter;
321  }
322 
327  public function getFirstLetterData() {
328  if ( $this->firstLetterData === null ) {
330  $cacheKey = $cache->makeKey(
331  'first-letters',
332  static::class,
333  $this->locale,
334  $this->digitTransformLanguage->getCode(),
335  INTL_ICU_VERSION,
336  self::FIRST_LETTER_VERSION
337  );
338  $this->firstLetterData = $cache->getWithSetCallback( $cacheKey, $cache::TTL_WEEK, function () {
339  return $this->fetchFirstLetterData();
340  } );
341  }
342  return $this->firstLetterData;
343  }
344 
349  private function fetchFirstLetterData() {
350  global $IP;
351  // Generate data from serialized data file
352  if ( isset( self::$tailoringFirstLetters[$this->locale] ) ) {
353  $letters = require "$IP/includes/collation/data/first-letters-root.php";
354  // Append additional characters
355  $letters = array_merge( $letters, self::$tailoringFirstLetters[$this->locale] );
356  // Remove unnecessary ones, if any
357  if ( isset( self::$tailoringFirstLetters['-' . $this->locale] ) ) {
358  $letters = array_diff( $letters, self::$tailoringFirstLetters['-' . $this->locale] );
359  }
360  // Apply digit transforms
361  $digits = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ];
362  $letters = array_diff( $letters, $digits );
363  foreach ( $digits as $digit ) {
364  $letters[] = $this->digitTransformLanguage->formatNum( $digit, true );
365  }
366  } elseif ( $this->locale === 'root' ) {
367  $letters = require "$IP/includes/collation/data/first-letters-root.php";
368  } else {
369  // FIXME: Is this still used?
370  $letters = wfGetPrecompiledData( "first-letters-{$this->locale}.ser" );
371  if ( $letters === false ) {
372  throw new MWException( "MediaWiki does not support ICU locale " .
373  "\"{$this->locale}\"" );
374  }
375  }
376 
377  /* Sort the letters.
378  *
379  * It's impossible to have the precompiled data file properly sorted,
380  * because the sort order changes depending on ICU version. If the
381  * array is not properly sorted, the binary search will return random
382  * results.
383  *
384  * We also take this opportunity to remove primary collisions.
385  */
386  $letterMap = [];
387  foreach ( $letters as $letter ) {
388  $key = $this->getPrimarySortKey( $letter );
389  if ( isset( $letterMap[$key] ) ) {
390  // Primary collision (two characters with the same sort position).
391  // Keep whichever one sorts first in the main collator.
392  $comp = $this->mainCollator->compare( $letter, $letterMap[$key] );
393  wfDebug( "Primary collision '$letter' '{$letterMap[$key]}' (comparison: $comp)" );
394  // If that also has a collision, use codepoint as a tiebreaker.
395  if ( $comp === 0 ) {
396  $comp = UtfNormal\Utils::utf8ToCodepoint( $letter ) <=>
397  UtfNormal\Utils::utf8ToCodepoint( $letterMap[$key] );
398  }
399  if ( $comp < 0 ) {
400  $letterMap[$key] = $letter;
401  }
402  } else {
403  $letterMap[$key] = $letter;
404  }
405  }
406  ksort( $letterMap, SORT_STRING );
407 
408  /* Remove duplicate prefixes. Basically if something has a sortkey
409  * which is a prefix of some other sortkey, then it is an
410  * expansion and probably should not be considered a section
411  * header.
412  *
413  * For example 'þ' is sometimes sorted as if it is the letters
414  * 'th'. Other times it is its own primary element. Another
415  * example is '₨'. Sometimes its a currency symbol. Sometimes it
416  * is an 'R' followed by an 's'.
417  *
418  * Additionally an expanded element should always sort directly
419  * after its first element due to they way sortkeys work.
420  *
421  * UCA sortkey elements are of variable length but no collation
422  * element should be a prefix of some other element, so I think
423  * this is safe. See:
424  * - https://ssl.icu-project.org/repos/icu/icuhtml/trunk/design/collation/ICU_collation_design.htm
425  * - http://site.icu-project.org/design/collation/uca-weight-allocation
426  *
427  * Additionally, there is something called primary compression to
428  * worry about. Basically, if you have two primary elements that
429  * are more than one byte and both start with the same byte then
430  * the first byte is dropped on the second primary. Additionally
431  * either \x03 or \xFF may be added to mean that the next primary
432  * does not start with the first byte of the first primary.
433  *
434  * This shouldn't matter much, as the first primary is not
435  * changed, and that is what we are comparing against.
436  *
437  * tl;dr: This makes some assumptions about how icu implements
438  * collations. It seems incredibly unlikely these assumptions
439  * will change, but nonetheless they are assumptions.
440  */
441 
442  $prev = false;
443  $duplicatePrefixes = [];
444  foreach ( $letterMap as $key => $value ) {
445  // Remove terminator byte. Otherwise the prefix
446  // comparison will get hung up on that.
447  $trimmedKey = rtrim( $key, "\0" );
448  if ( $prev === false || $prev === '' ) {
449  $prev = $trimmedKey;
450  // We don't yet have a collation element
451  // to compare against, so continue.
452  continue;
453  }
454 
455  // Due to the fact the array is sorted, we only have
456  // to compare with the element directly previous
457  // to the current element (skipping expansions).
458  // An element "X" will always sort directly
459  // before "XZ" (Unless we have "XY", but we
460  // do not update $prev in that case).
461  if ( substr( $trimmedKey, 0, strlen( $prev ) ) === $prev ) {
462  $duplicatePrefixes[] = $key;
463  // If this is an expansion, we don't want to
464  // compare the next element to this element,
465  // but to what is currently $prev
466  continue;
467  }
468  $prev = $trimmedKey;
469  }
470  foreach ( $duplicatePrefixes as $badKey ) {
471  wfDebug( "Removing '{$letterMap[$badKey]}' from first letters." );
472  unset( $letterMap[$badKey] );
473  // This code assumes that unsetting does not change sort order.
474  }
475  $data = [
476  'chars' => array_values( $letterMap ),
477  'keys' => array_keys( $letterMap ),
478  ];
479 
480  // Reduce memory usage before caching
481  unset( $letterMap );
482 
483  return $data;
484  }
485 
491  public function getLetterByIndex( $index ) {
492  return $this->getFirstLetterData()['chars'][$index];
493  }
494 
500  public function getSortKeyByLetterIndex( $index ) {
501  return $this->getFirstLetterData()['keys'][$index];
502  }
503 
508  public function getFirstLetterCount() {
509  return count( $this->getFirstLetterData()['chars'] );
510  }
511 
518  public static function isCjk( $codepoint ) {
519  foreach ( self::$cjkBlocks as $block ) {
520  if ( $codepoint >= $block[0] && $codepoint <= $block[1] ) {
521  return true;
522  }
523  }
524  return false;
525  }
526 
534  public static function getUnicodeVersionForICU() {
535  $icuVersion = INTL_ICU_VERSION;
536  if ( !$icuVersion ) {
537  return false;
538  }
539 
540  $versionPrefix = substr( $icuVersion, 0, 3 );
541  // Source: http://site.icu-project.org/download
542  $map = [
543  '67.' => '13.0',
544  '66.' => '13.0',
545  '65.' => '12.0',
546  '64.' => '12.0',
547  '63.' => '11.0',
548  '62.' => '11.0',
549  '61.' => '10.0',
550  '60.' => '10.0',
551  '59.' => '9.0',
552  '58.' => '9.0',
553  '57.' => '8.0',
554  '56.' => '8.0',
555  '55.' => '7.0',
556  '54.' => '7.0',
557  '53.' => '6.3',
558  '52.' => '6.3',
559  '51.' => '6.2',
560  '50.' => '6.2',
561  '49.' => '6.1',
562  '4.8' => '6.0',
563  '4.6' => '6.0',
564  '4.4' => '5.2',
565  '4.2' => '5.1',
566  '4.0' => '5.1',
567  '3.8' => '5.0',
568  '3.6' => '5.0',
569  '3.4' => '4.1',
570  ];
571 
572  return $map[$versionPrefix] ?? false;
573  }
574 }
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:146
IcuCollation\getFirstLetterCount
getFirstLetterCount()
Definition: IcuCollation.php:508
IcuCollation\$primaryCollator
Collator $primaryCollator
Definition: IcuCollation.php:30
IcuCollation\getPrimarySortKey
getPrimarySortKey( $string)
Definition: IcuCollation.php:278
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1198
IcuCollation\$tailoringFirstLetters
static $tailoringFirstLetters
Additional characters (or character groups) to be considered separate letters for given languages,...
Definition: IcuCollation.php:95
Collation
Definition: Collation.php:29
IcuCollation\$mainCollator
Collator $mainCollator
Definition: IcuCollation.php:33
MWException
MediaWiki exception.
Definition: MWException.php:26
IcuCollation\$digitTransformLanguage
Language $digitTransformLanguage
Definition: IcuCollation.php:39
IcuCollation\getSortKeyByLetterIndex
getSortKeyByLetterIndex( $index)
Definition: IcuCollation.php:500
IcuCollation\isCjk
static isCjk( $codepoint)
Test if a code point is a CJK (Chinese, Japanese, Korean) character.
Definition: IcuCollation.php:518
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:913
IcuCollation\getLetterByIndex
getLetterByIndex( $index)
Definition: IcuCollation.php:491
IcuCollation\getFirstLetter
getFirstLetter( $string)
Given a string, return the logical "first letter" to be used for grouping on category pages and so on...
Definition: IcuCollation.php:282
CACHE_ANYTHING
const CACHE_ANYTHING
Definition: Defines.php:90
IcuCollation\getFirstLetterData
getFirstLetterData()
Definition: IcuCollation.php:327
IcuCollation\FIRST_LETTER_VERSION
const FIRST_LETTER_VERSION
Definition: IcuCollation.php:27
IcuCollation\$locale
string $locale
Definition: IcuCollation.php:36
IcuCollation\getUnicodeVersionForICU
static getUnicodeVersionForICU()
Return the version of Unicode appropriate for the version of ICU library currently in use,...
Definition: IcuCollation.php:534
$cache
$cache
Definition: mcc.php:33
wfGetPrecompiledData
wfGetPrecompiledData( $name)
Get an object from the precompiled serialized directory.
Definition: GlobalFunctions.php:2381
IcuCollation\$useNumericCollation
bool $useNumericCollation
Definition: IcuCollation.php:42
ArrayUtils\findLowerBound
static findLowerBound( $valueCallback, $valueCount, $comparisonCallback, $target)
Do a binary search, and return the index of the largest item that sorts less than or equal to the tar...
Definition: ArrayUtils.php:112
IcuCollation\getSortKey
getSortKey( $string)
Given a string, convert it to a (hopefully short) key that can be used for efficient sorting.
Definition: IcuCollation.php:274
IcuCollation\$cjkBlocks
static $cjkBlocks
Unified CJK blocks.
Definition: IcuCollation.php:56
IcuCollation\$firstLetterData
array $firstLetterData
Definition: IcuCollation.php:45
IcuCollation\__construct
__construct( $locale)
Definition: IcuCollation.php:244
$IP
$IP
Definition: WebStart.php:49
Language
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition: Language.php:41
IcuCollation\fetchFirstLetterData
fetchFirstLetterData()
Definition: IcuCollation.php:349
ObjectCache\getLocalServerInstance
static getLocalServerInstance( $fallback=CACHE_NONE)
Factory function for CACHE_ACCEL (referenced from DefaultSettings.php)
Definition: ObjectCache.php:254
IcuCollation
Definition: IcuCollation.php:26