97 'as' => [
"\u{0982}",
"\u{0981}",
"\u{0983}",
"\u{09CE}",
"ক্ষ " ],
98 'ast' => [
"Ch",
"Ll",
"Ñ" ],
99 'az' => [
"Ç",
"Ə",
"Ğ",
"İ",
"Ö",
"Ş",
"Ü" ],
101 'be-tarask' => [
"Ё" ],
103 'bn' => [
'ং',
'ঃ',
'ঁ' ],
104 'bn@collation=traditional' => [
105 'ং',
'ঃ',
'ঁ',
'ক্',
'খ্',
'গ্',
'ঘ্',
'ঙ্',
'চ্',
'ছ্',
'জ্',
'ঝ্',
106 'ঞ্',
'ট্',
'ঠ্',
'ড্',
'ঢ্',
'ণ্',
'ৎ',
'থ্',
'দ্',
'ধ্',
'ন্',
'প্',
107 'ফ্',
'ব্',
'ভ্',
'ম্',
'য্',
'র্',
'ৰ্',
'ল্',
'ৱ্',
'শ্',
'ষ্',
'স্',
'হ্'
110 'br' => [
"Ch",
"C'h" ],
111 'bs' => [
"Č",
"Ć",
"Dž",
"Đ",
"Lj",
"Nj",
"Š",
"Ž" ],
116 'cs' => [
"Č",
"Ch",
"Ř",
"Š",
"Ž" ],
117 'cy' => [
"Ch",
"Dd",
"Ff",
"Ng",
"Ll",
"Ph",
"Rh",
"Th" ],
118 'da' => [
"Æ",
"Ø",
"Å" ],
120 'de-AT@collation=phonebook' => [
'ä',
'ö',
'ü',
'ß' ],
121 'dsb' => [
"Č",
"Ć",
"Dź",
"Ě",
"Ch",
"Ł",
"Ń",
"Ŕ",
"Š",
"Ś",
"Ž",
"Ź" ],
122 'ee' => [
"Dz",
"Ɖ",
"Ɛ",
"Ƒ",
"Gb",
"Ɣ",
"Kp",
"Ny",
"Ŋ",
"Ɔ",
"Ts",
"Ʋ" ],
125 'eo' => [
"Ĉ",
"Ĝ",
"Ĥ",
"Ĵ",
"Ŝ",
"Ŭ" ],
127 'et' => [
"Š",
"Ž",
"Õ",
"Ä",
"Ö",
"Ü" ],
137 'fi' => [
"Å",
"Ä",
"Ö" ],
138 'fil' => [
"Ñ",
"Ng" ],
139 'fo' => [
"Á",
"Ð",
"Í",
"Ó",
"Ú",
"Ý",
"Æ",
"Ø",
"Å" ],
142 'fur' => [
"À",
"Á",
"Â",
"È",
"Ì",
"Ò",
"Ù" ],
146 'gl' => [
"Ch",
"Ll",
"Ñ" ],
147 'gu' => [
"\u{0A82}",
"\u{0A83}",
"\u{0A81}",
"\u{0AB3}" ],
148 'ha' => [
'Ɓ',
'Ɗ',
'Ƙ',
'Sh',
'Ts',
'Ƴ' ],
151 'hi' => [
"\u{0902}",
"\u{0903}" ],
152 'hr' => [
"Č",
"Ć",
"Dž",
"Đ",
"Lj",
"Nj",
"Š",
"Ž" ],
153 'hsb' => [
"Č",
"Dź",
"Ě",
"Ch",
"Ł",
"Ń",
"Ř",
"Š",
"Ć",
"Ž" ],
154 'hu' => [
"Cs",
"Dz",
"Dzs",
"Gy",
"Ly",
"Ny",
"Ö",
"Sz",
"Ty",
"Ü",
"Zs" ],
157 'ig' => [
"Ch",
"Gb",
"Gh",
"Gw",
"Ị",
"Kp",
"Kw",
"Ṅ",
"Nw",
"Ny",
"Ọ",
"Sh",
"Ụ" ],
158 'is' => [
"Á",
"Ð",
"É",
"Í",
"Ó",
"Ú",
"Ý",
"Þ",
"Æ",
"Ö",
"Å" ],
161 'kk' => [
"Ү",
"І" ],
162 'kl' => [
"Æ",
"Ø",
"Å" ],
164 "រ",
"ឫ",
"ឬ",
"ល",
"ឭ",
"ឮ",
"\u{17BB}\u{17C6}",
165 "\u{17C6}",
"\u{17B6}\u{17C6}",
"\u{17C7}",
166 "\u{17B7}\u{17C7}",
"\u{17BB}\u{17C7}",
167 "\u{17C1}\u{17C7}",
"\u{17C4}\u{17C7}",
169 'kn' => [
"\u{0C81}",
"\u{0C83}",
"\u{0CF1}",
"\u{0CF2}" ],
170 'kok' => [
"\u{0902}",
"\u{0903}",
"ळ",
"क्ष" ],
171 'ku' => [
"Ç",
"Ê",
"Î",
"Ş",
"Û" ],
175 'lkt' => [
'Č',
'Ǧ',
'Ȟ',
'Š',
'Ž' ],
178 'lt' => [
"Č",
"Š",
"Ž" ],
179 'lv' => [
"Č",
"Ģ",
"Ķ",
"Ļ",
"Ņ",
"Š",
"Ž" ],
180 'mk' => [
"Ѓ",
"Ќ" ],
183 'mo' => [
"Ă",
"Â",
"Î",
"Ș",
"Ț" ],
184 'mr' => [
"\u{0902}",
"\u{0903}",
"ळ",
"क्ष",
"ज्ञ" ],
186 'mt' => [
"Ċ",
"Ġ",
"Għ",
"Ħ",
"Ż" ],
187 'nb' => [
"Æ",
"Ø",
"Å" ],
190 'nn' => [
"Æ",
"Ø",
"Å" ],
191 'no' => [
"Æ",
"Ø",
"Å" ],
193 'om' => [
'Ch',
'Dh',
'Kh',
'Ny',
'Ph',
'Sh' ],
194 'or' => [
"\u{0B01}",
"\u{0B02}",
"\u{0B03}",
"କ୍ଷ" ],
195 'pa' => [
"\u{0A4D}" ],
196 'pl' => [
"Ą",
"Ć",
"Ę",
"Ł",
"Ń",
"Ó",
"Ś",
"Ź",
"Ż" ],
199 'ro' => [
"Ă",
"Â",
"Î",
"Ș",
"Ț" ],
201 'rup' => [
"Ă",
"Â",
"Î",
"Ľ",
"Ń",
"Ș",
"Ț" ],
204 'Á',
'Č',
'Ʒ',
'Ǯ',
'Đ',
'Ǧ',
'Ǥ',
'Ǩ',
'Ŋ',
205 'Š',
'Ŧ',
'Ž',
'Ø',
'Æ',
'Ȧ',
'Ä',
'Ö'
207 'si' => [
"\u{0D82}",
"\u{0D83}",
"\u{0DA4}" ],
208 'sk' => [
"Ä",
"Č",
"Ch",
"Ô",
"Š",
"Ž" ],
209 'sl' => [
"Č",
"Š",
"Ž" ],
210 'smn' => [
"Á",
"Č",
"Đ",
"Ŋ",
"Š",
"Ŧ",
"Ž",
"Æ",
"Ø",
"Å",
"Ä",
"Ö" ],
211 'sq' => [
"Ç",
"Dh",
"Ë",
"Gj",
"Ll",
"Nj",
"Rr",
"Sh",
"Th",
"Xh",
"Zh" ],
213 'sr-Latn' => [
"Č",
"Ć",
"Dž",
"Đ",
"Lj",
"Nj",
"Š",
"Ž" ],
214 'sv' => [
"Å",
"Ä",
"Ö" ],
215 'sv@collation=standard' => [
"Å",
"Ä",
"Ö" ],
218 "\u{0B82}",
"ஃ",
"க்ஷ",
"க்",
"ங்",
"ச்",
"ஞ்",
"ட்",
"ண்",
"த்",
"ந்",
219 "ப்",
"ம்",
"ய்",
"ர்",
"ல்",
"வ்",
"ழ்",
"ள்",
"ற்",
"ன்",
"ஜ்",
"ஶ்",
"ஷ்",
222 'te' => [
"\u{0C01}",
"\u{0C02}",
"\u{0C03}" ],
223 'th' => [
"ฯ",
"\u{0E46}",
"\u{0E4D}",
"\u{0E3A}" ],
224 'tk' => [
"Ç",
"Ä",
"Ž",
"Ň",
"Ö",
"Ş",
"Ü",
"Ý" ],
225 'tl' => [
"Ñ",
"Ng" ],
226 'to' => [
"Ng",
"ʻ" ],
227 'tr' => [
"Ç",
"Ğ",
"İ",
"Ö",
"Ş",
"Ü" ],
228 'tt' => [
"Ә",
"Ө",
"Ү",
"Җ",
"Ң",
"Һ" ],
229 'uk' => [
"Ґ",
"Ь" ],
230 'uz' => [
"Ch",
"G'",
"Ng",
"O'",
"Sh" ],
231 'vi' => [
"Ă",
"Â",
"Đ",
"Ê",
"Ô",
"Ơ",
"Ư" ],
232 'vo' => [
"Ä",
"Ö",
"Ü" ],
234 "\u{05D1}\u{05BF}",
"\u{05DB}\u{05BC}",
"\u{05E4}\u{05BC}",
235 "\u{05E9}\u{05C2}",
"\u{05EA}\u{05BC}"
237 'yo' => [
"Ẹ",
"Gb",
"Ọ",
"Ṣ" ],
247 if ( !extension_loaded(
'intl' ) ) {
248 throw new MWException(
'An ICU collation was requested, ' .
249 'but the intl extension is not available.' );
254 $localeParts = explode(
'@',
$locale );
257 $this->mainCollator = Collator::create(
$locale );
258 if ( !$this->mainCollator ) {
259 throw new MWException(
"Invalid ICU locale specified for collation: $locale" );
262 $this->primaryCollator = Collator::create(
$locale );
263 $this->primaryCollator->setStrength( Collator::PRIMARY );
266 if ( substr(
$locale, -5, 5 ) ===
'-u-kn' ) {
267 $this->useNumericCollation =
true;
269 $this->locale = substr( $this->locale, 0, -5 );
270 $this->mainCollator->setAttribute( Collator::NUMERIC_COLLATION, Collator::ON );
271 $this->primaryCollator->setAttribute( Collator::NUMERIC_COLLATION, Collator::ON );
276 return $this->mainCollator->getSortKey( $string );
280 return $this->primaryCollator->getSortKey( $string );
284 $string = strval( $string );
285 if ( $string ===
'' ) {
289 $firstChar = mb_substr( $string, 0, 1,
'UTF-8' );
292 if ( ord( $firstChar ) > 0x7f && self::isCjk(
UtfNormal\Utils::utf8ToCodepoint( $firstChar ) ) ) {
300 [ $this,
'getSortKeyByLetterIndex' ],
305 if ( $min ===
false ) {
312 if ( $this->useNumericCollation ) {
317 if ( ord( $sortLetter ) >= 48 && ord( $sortLetter ) <= 57 ) {
318 $sortLetter =
wfMessage(
'category-header-numerals' )->numParams( 0, 9 )->text();
329 if ( $this->firstLetterData ===
null ) {
331 $cacheKey =
$cache->makeKey(
335 $this->digitTransformLanguage->getCode(),
339 $this->firstLetterData =
$cache->getWithSetCallback( $cacheKey, $cache::TTL_WEEK,
function () {
353 if ( isset( self::$tailoringFirstLetters[$this->locale] ) ) {
354 $letters = require
"$IP/includes/collation/data/first-letters-root.php";
356 $letters = array_merge( $letters, self::$tailoringFirstLetters[$this->locale] );
358 if ( isset( self::$tailoringFirstLetters[
'-' . $this->locale] ) ) {
359 $letters = array_diff( $letters, self::$tailoringFirstLetters[
'-' . $this->locale] );
362 $digits = [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9' ];
363 $letters = array_diff( $letters, $digits );
364 foreach ( $digits
as $digit ) {
365 $letters[] = $this->digitTransformLanguage->formatNum( $digit,
true );
368 if ( $this->locale ===
'root' ) {
369 $letters = require
"$IP/includes/collation/data/first-letters-root.php";
373 if ( $letters ===
false ) {
374 throw new MWException(
"MediaWiki does not support ICU locale " .
375 "\"{$this->locale}\"" );
390 foreach ( $letters
as $letter ) {
392 if ( isset( $letterMap[$key] ) ) {
395 $comp = $this->mainCollator->compare( $letter, $letterMap[$key] );
396 wfDebug(
"Primary collision '$letter' '{$letterMap[$key]}' (comparison: $comp)\n" );
399 $comp = UtfNormal\Utils::utf8ToCodepoint( $letter ) <=>
400 UtfNormal\Utils::utf8ToCodepoint( $letterMap[$key] );
403 $letterMap[$key] = $letter;
406 $letterMap[$key] = $letter;
409 ksort( $letterMap, SORT_STRING );
446 $duplicatePrefixes = [];
447 foreach ( $letterMap
as $key =>
$value ) {
450 $trimmedKey = rtrim( $key,
"\0" );
451 if ( $prev ===
false || $prev ===
'' ) {
464 if ( substr( $trimmedKey, 0, strlen( $prev ) ) === $prev ) {
465 $duplicatePrefixes[] = $key;
473 foreach ( $duplicatePrefixes
as $badKey ) {
474 wfDebug(
"Removing '{$letterMap[$badKey]}' from first letters.\n" );
475 unset( $letterMap[$badKey] );
479 'chars' => array_values( $letterMap ),
480 'keys' => array_keys( $letterMap ),
521 public static function isCjk( $codepoint ) {
522 foreach ( self::$cjkBlocks
as $block ) {
523 if ( $codepoint >= $block[0] && $codepoint <= $block[1] ) {
544 return INTL_ICU_VERSION;
555 $icuVersion = INTL_ICU_VERSION;
556 if ( !$icuVersion ) {
560 $versionPrefix = substr( $icuVersion, 0, 3 );
586 return $map[$versionPrefix] ??
false;