Completed
Push — master ( 54463f...1e9f56 )
by mw
325:15 queued 290:54
created

Localizer   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 305
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 3

Test Coverage

Coverage 86.96%

Importance

Changes 0
Metric Value
dl 0
loc 305
ccs 60
cts 69
cp 0.8696
rs 8.8
c 0
b 0
f 0
wmc 36
lcom 2
cbo 3

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getInstance() 0 8 2
A clear() 0 3 1
A getContentLanguage() 0 3 1
A getUserLanguage() 0 3 1
A getPreferredContentLanguage() 0 17 4
A getLanguage() 0 8 4
B getExtraneousLanguage() 0 14 5
A getNamespaceTextById() 0 3 1
A getCanonicalNamespaceTextById() 0 10 2
A getNamespaceIndexByName() 0 3 1
A isSupportedLanguage() 0 11 2
A asBCP47FormattedLanguageCode() 0 3 1
A getLanguageCodeFrom() 0 3 1
A getCanonicalizedUrlByNamespace() 0 13 1
B getAnnotatedLanguageCodeFrom() 0 17 5
A convertDoubleWidth() 0 21 3
1
<?php
2
3
namespace SMW;
4
5
use SMW\ExtraneousLanguage\ExtraneousLanguage;
6
use Language;
7
use Title;
8
9
/**
10
 * @license GNU GPL v2+
11
 * @since 2.1
12
 *
13
 * @author mwjames
14
 */
15
class Localizer {
16
17
	/**
18
	 * @var Localizer
19
	 */
20
	private static $instance = null;
21
22
	/**
23
	 * @var Language
24
	 */
25
	private $contentLanguage = null;
26
27
	/**
28
	 * @since 2.1
29
	 *
30
	 * @param Language $contentLanguage
31
	 */
32 108
	public function __construct( Language $contentLanguage ) {
33 108
		$this->contentLanguage = $contentLanguage;
34 108
	}
35
36
	/**
37
	 * @since 2.1
38
	 *
39
	 * @return Localizer
40
	 */
41 304
	public static function getInstance() {
0 ignored issues
show
Coding Style introduced by
getInstance uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
42
43 304
		if ( self::$instance === null ) {
44 102
			self::$instance = new self( $GLOBALS['wgContLang'] );
45
		}
46
47 304
		return self::$instance;
48
	}
49
50
	/**
51
	 * @since 2.1
52
	 */
53 117
	public static function clear() {
54 117
		self::$instance = null;
55 117
	}
56
57
	/**
58
	 * @since 2.1
59
	 *
60
	 * @return Language
61
	 */
62 302
	public function getContentLanguage() {
63 302
		return $this->contentLanguage;
64
	}
65
66
	/**
67
	 * @since 2.4
68
	 *
69
	 * @return Language
70
	 */
71 267
	public function getUserLanguage() {
0 ignored issues
show
Coding Style introduced by
getUserLanguage uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
72 267
		return $GLOBALS['wgLang'];
73
	}
74
75
	/**
76
	 * @note
77
	 *
78
	 * 1. If the page content language is availabe use it as preferred language
79
	 * (as it is clear that the page content was intended to be in a specific
80
	 * language)
81
	 * 2. If no page content language was assigned use the global content
82
	 * language
83
	 *
84
	 * General rules:
85
	 * - Special pages are in the user language
86
	 * - Display of values (DV) should use the user language if available otherwise
87
	 * use the content language as fallback
88
	 * - Storage of values (DI) should always use the content language
89
	 *
90
	 * Notes:
91
	 * - The page content language is the language in which the content of a page is
92
	 * written in wikitext
93
	 *
94
	 * @since 2.4
95
	 *
96
	 * @param DIWikiPage|Title|null $title
97
	 *
98
	 * @return Language
99
	 */
100 206
	public function getPreferredContentLanguage( $title = null ) {
101
102 206
		$language = '';
103
104 206
		if ( $title instanceof DIWikiPage ) {
105 197
			$title = $title->getTitle();
106
		}
107
108
		// If the page language is different from the global content language
109
		// then we assume that an explicit language object was given otherwise
110
		// the Title is using the content language as fallback
111 206
		if ( $title instanceof Title ) {
0 ignored issues
show
Bug introduced by
The class Title does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
112 198
			$language = $title->getPageLanguage();
113
		}
114
115 206
		return $language instanceof Language ? $language : $this->getContentLanguage();
0 ignored issues
show
Bug introduced by
The class Language does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
116
	}
117
118
	/**
119
	 * @since 2.4
120
	 *
121
	 * @param string $languageCode
122
	 *
123
	 * @return Language
124
	 */
125 11
	public function getLanguage( $languageCode = '' ) {
126
127 11
		if ( $languageCode === '' || !$languageCode || $languageCode === null ) {
128
			return $this->getContentLanguage();
129
		}
130
131 11
		return Language::factory( $languageCode );
132
	}
133
134
	/**
135
	 * @since 2.4
136
	 *
137
	 * @param Language|string $languageCode
0 ignored issues
show
Documentation introduced by
There is no parameter named $languageCode. Did you maybe mean $language?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
138
	 *
139
	 * @return ExtraneousLanguage
140
	 */
141 299
	public function getExtraneousLanguage( $language = '' ) {
142
143 299
		$languageCode = $language;
144
145 299
		if ( $language instanceof Language ) {
0 ignored issues
show
Bug introduced by
The class Language does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
146 24
			$languageCode = $language->getCode();
147
		}
148
149 299
		if ( $languageCode === '' || !$languageCode || $languageCode === null ) {
150 299
			$languageCode = $this->getContentLanguage()->getCode();
151
		}
152
153 299
		return ExtraneousLanguage::getInstance()->fetchByLanguageCode( $languageCode );
154
	}
155
156
	/**
157
	 * @since 2.1
158
	 *
159
	 * @param integer $index
160
	 *
161
	 * @return string
162
	 */
163 282
	public function getNamespaceTextById( $index ) {
164 282
		return str_replace( '_', ' ', $this->contentLanguage->getNsText( $index ) );
165
	}
166
167
	/**
168
	 * @since 2.5
169
	 *
170
	 * @param integer $index
171
	 *
172
	 * @return string
173
	 */
174 3
	public function getCanonicalNamespaceTextById( $index ) {
175 3
176
		$canonicalNames = NamespaceManager::getCanonicalNames();
177
178
		if ( isset( $canonicalNames[$index] ) ) {
179
			return $canonicalNames[$index];
180
		}
181
182
		return \MWNamespace::getCanonicalName( $index );
183
	}
184
185 16
	/**
186
	 * @since 2.1
187 16
	 *
188
	 * @param string $namespaceName
189
	 *
190 16
	 * @return integer|boolean
191
	 */
192
	public function getNamespaceIndexByName( $namespaceName ) {
193
		return $this->contentLanguage->getNsIndex( str_replace( ' ', '_', $namespaceName ) );
194 16
	}
195
196
	/**
197
	 * @since 2.4
198
	 *
199
	 * @param string $languageCode
200
	 *
201
	 * @return boolean
202
	 */
203
	public static function isSupportedLanguage( $languageCode ) {
204
205
		$languageCode = mb_strtolower( $languageCode );
206 223
207 223
		// FIXME 1.19 doesn't know Language::isSupportedLanguage
208
		if ( !method_exists( '\Language', 'isSupportedLanguage' ) ) {
209
			return Language::isValidBuiltInCode( $languageCode );
210
		}
211
212
		return Language::isSupportedLanguage( $languageCode );
213
	}
214
215
	/**
216
	 * @see IETF language tag / BCP 47 standards
217
	 *
218
	 * @since 2.4
219
	 *
220
	 * @param string $languageCode
221
	 *
222
	 * @return string
223
	 */
224
	public static function asBCP47FormattedLanguageCode( $languageCode ) {
225
		return wfBCP47( $languageCode );
226
	}
227
228
	/**
229
	 * @deprecated 2.5, use Localizer::getAnnotatedLanguageCodeFrom instead
230 275
	 * @since 2.4
231
	 *
232 275
	 * @param string &$value
233
	 *
234 275
	 * @return string|false
235
	 */
236 275
	public static function getLanguageCodeFrom( &$value ) {
237 275
		return self::getAnnotatedLanguageCodeFrom( $value );
238
	}
239 275
240
	/**
241
	 * @since 2.5
242
	 *
243
	 * @param integer $index
244
	 * @param string $url
245
	 *
246
	 * @return string
247
	 */
248
	public function getCanonicalizedUrlByNamespace( $index, $url ) {
249
250
		$namespace = $this->getNamespaceTextById( $index );
251 220
252
		return str_replace(
253 220
			array(
254 215
				wfUrlencode( '/' . $namespace .':' ),
255
				'/' . $namespace .':'
256
			),
257 12
			'/' . $this->getCanonicalNamespaceTextById( $index ) . ':',
258 11
			$url
259
		);
260
	}
261
262 12
	/**
263 10
	 * @since 2.4
264
	 *
265
	 * @param string &$value
266 2
	 *
267
	 * @return string|false
268
	 */
269
	public static function getAnnotatedLanguageCodeFrom( &$value ) {
270
271
		if ( strpos( $value, '@' ) === false ) {
272
			return false;
273
		}
274
275
		if ( ( $langCode = mb_substr( strrchr( $value, "@" ), 1 ) ) !== '' ) {
276
			$value = str_replace( '_', ' ', substr_replace( $value, '', ( mb_strlen( $langCode ) + 1 ) * -1 ) );
277
		}
278
279 44
		// Do we want to check here whether isSupportedLanguage or not?
280 44
		if ( $langCode !== '' && ctype_alpha( str_replace( array( '-' ), '', $langCode ) ) ) {
281 44
			return $langCode;
282
		}
283 44
284
		return false;
285
	}
286
287
	/**
288
	 * @see Language::convertDoubleWidth
289
	 *
290
	 * Convert double-width roman characters to single-width.
291
	 * range: ff00-ff5f ~= 0020-007f
292
	 *
293
	 * @param string $string
294
	 *
295
	 * @return string
296
	 */
297
	public static function convertDoubleWidth( $string ) {
298 44
		static $full = null;
299
		static $half = null;
300
301
		if ( $full === null ) {
302
			$fullWidth = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
303
			$halfWidth = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
304
305
			// http://php.net/manual/en/function.str-split.php, mb_str_split
306
			$length = mb_strlen( $fullWidth, "UTF-8" );
307
			$full = array();
308
309
			for ( $i = 0; $i < $length; $i += 1 ) {
310
				$full[] = mb_substr( $fullWidth, $i, 1, "UTF-8" );
311
			}
312
313
			$half = str_split( $halfWidth );
314
		}
315
316
		return str_replace( $full, $half, trim( $string ) );
317
	}
318
319
}
320