Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
75.68% covered (warning)
75.68%
28 / 37
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
BabelLanguageCodes
75.68% covered (warning)
75.68%
28 / 37
75.00% covered (warning)
75.00%
3 / 4
16.82
0.00% covered (danger)
0.00%
0 / 1
 mapToMediaWikiCode
18.18% covered (danger)
18.18%
2 / 11
0.00% covered (danger)
0.00%
0 / 1
12.76
 getCode
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 getName
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
4
 getCategoryCode
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * Code for language code and name processing.
4 *
5 * @file
6 * @author Robert Leverington
7 * @license GPL-2.0-or-later
8 */
9
10declare( strict_types = 1 );
11
12namespace MediaWiki\Babel;
13
14use MediaWiki\Language\LanguageCode;
15use MediaWiki\Languages\LanguageNameUtils;
16use MediaWiki\MediaWikiServices;
17
18/**
19 * Handle language code and name processing for the Babel extension, it can also
20 * be used by other extension which need such functionality.
21 */
22class BabelLanguageCodes {
23
24    /**
25     * @var array|null
26     */
27    private static $mapToMediaWikiCodeCache = null;
28
29    /**
30     * Map BCP 47 codes or old deprecated internal codes to current MediaWiki
31     * internal codes (which may not be standard BCP 47 codes).
32     *
33     * @param string $code Code to try and get an internal code for
34     * @return string|bool Language code, or false if code is not mapped
35     */
36    private static function mapToMediaWikiCode( string $code ) {
37        if ( !self::$mapToMediaWikiCodeCache ) {
38            self::$mapToMediaWikiCodeCache = [];
39            // Is the code a proper BCP 47 code for one of MediaWiki's nonstandard codes?
40            // If so, return the internal MediaWiki code.
41            $mapping = LanguageCode::getNonstandardLanguageCodeMapping();
42            foreach ( $mapping as $mwCode => $bcp47code ) {
43                // Careful, because the non-standard language code mapping
44                // also maps deprecated codes to bcp-47 equivalents; we
45                // don't want to return a deprecated code.
46                self::$mapToMediaWikiCodeCache[ strtolower( $bcp47code ) ] =
47                    LanguageCode::replaceDeprecatedCodes( $mwCode );
48            }
49
50            // Is the code one of MediaWiki's legacy fake codes? If so, return the modern
51            // equivalent code (T101086)
52            $mapping = LanguageCode::getDeprecatedCodeMapping();
53            foreach ( $mapping as $deprecatedCode => $mwCode ) {
54                self::$mapToMediaWikiCodeCache[ strtolower( $deprecatedCode ) ] =
55                    $mwCode;
56            }
57        }
58        return self::$mapToMediaWikiCodeCache[ strtolower( $code ) ] ?? false;
59    }
60
61    /**
62     * Takes a language code, and attempt to obtain a better variant of it,
63     * checks the MediaWiki language codes for a match, otherwise checks the
64     * internal Babel language codes (preferring ISO 639-1 over ISO 639-3) map.
65     *
66     * @param string $code Code to try and get a "better" code for.
67     * @return string|null Mediawiki-internal language code, or null
68     *   for invalid language code.
69     */
70    public static function getCode( string $code ): ?string {
71        // Map BCP 47 codes and/or deprecated codes to internal MediaWiki codes
72        $mediawiki = self::mapToMediaWikiCode( $code );
73        if ( $mediawiki !== false ) {
74            $code = $mediawiki;
75        }
76
77        // Is the code known to MediaWiki?
78        $mediawiki = MediaWikiServices::getInstance()->getLanguageNameUtils()->getLanguageName( $code );
79        if ( $mediawiki !== '' ) {
80            return strtolower( $code );
81        }
82
83        // Otherwise, fall back to the ISO 639 codes database
84        static $isoCodes = false;
85        if ( !$isoCodes ) {
86            $isoCodes = require __DIR__ . '/../codes.php';
87        }
88
89        return $isoCodes[$code] ?? null;
90    }
91
92    /**
93     * Take a code as input, and search a language name for it in
94     * a given language via LanguageNameUtils:getLanguageNames() or
95     * else via the internal Babel language names map.
96     *
97     * @param string $code Code to get name for.
98     * @param string|null $language Code of language to attempt to get name in,
99     *  defaults to language of code.
100     * @return string|bool Name of language, or false for invalid language code.
101     */
102    public static function getName( string $code, ?string $language = null ) {
103        // Get correct code, even though it should already be correct.
104        $code = self::getCode( $code );
105        if ( $code === null ) {
106            return false;
107        }
108        $code = strtolower( $code );
109
110        $language ??= $code;
111        $names = MediaWikiServices::getInstance()->getLanguageNameUtils()
112            ->getLanguageNames( $language, LanguageNameUtils::ALL );
113        if ( isset( $names[$code] ) ) {
114            return $names[$code];
115        }
116
117        static $isoNames = false;
118        if ( !$isoNames ) {
119            $isoNames = require __DIR__ . '/../names.php';
120        }
121
122        return $isoNames[$code] ?? false;
123    }
124
125    /**
126     * Return an appropriate category name, given a MediaWiki-internal
127     * language code.  MediaWiki-internal codes are all-lowercase, but
128     * historically our category codes have been partially uppercase
129     * in the style of BCP 47. Eventually, we should probably use true
130     * BCP 47 for category names, but historically we've had internal
131     * codes like `simple` which we don't want to rename to `en-simple`
132     * quite yet.
133     *
134     * @param string $code MediaWiki-internal code.
135     * @return string A backwards-compatible category name for this code.
136     * @since 1.32
137     */
138    public static function getCategoryCode( string $code ): string {
139        if ( strpos( $code, '-' ) !== false ) {
140            return LanguageCode::bcp47( $code );
141        }
142
143        return $code;
144    }
145}