Completed
Push — authenticator-refactor ( 16f104...61b037 )
by Simon
06:52
created

IntlLocales   C

Complexity

Total Complexity 34

Size/Duplication

Total Lines 1612
Duplicated Lines 2.36 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 38
loc 1612
rs 6.3225
c 0
b 0
f 0
wmc 34
lcom 1
cbo 4

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A scriptDirection() 0 15 4
A localeFromLang() 0 21 4
A langFromLocale() 0 4 1
A getLocales() 19 19 3
A getLanguages() 19 19 3
A localeName() 0 4 1
A languageName() 0 4 1
A getCountries() 0 21 3
A countryName() 0 4 1
A countryFromLocale() 0 4 2
C validate() 0 26 8
A reset() 0 6 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace SilverStripe\i18n\Data\Intl;
4
5
use Collator;
6
use Exception;
7
use Locale;
8
use SilverStripe\Core\Config\Configurable;
9
use SilverStripe\Core\Injector\Injectable;
10
use SilverStripe\Core\Resettable;
11
use SilverStripe\i18n\Data\Locales;
12
use SilverStripe\i18n\i18n;
13
14
/**
15
 * Locale metadata
16
 *
17
 * Language codes follow ISO 639-1 (2 letter), unless not present, in which case a locale will be
18
 * encoded in ISO 639-3 (3 letter). See https://en.wikipedia.org/wiki/ISO_639
19
 *
20
 * Country codes follow ISO 3166-1 alpha-2 (2 letter), unless not present, in which case a country
21
 * code will be encoded in ISO 3166-1 alpha-3 (3 letter). See https://en.wikipedia.org/wiki/ISO_3166-1
22
 */
23
class IntlLocales implements Locales, Resettable
24
{
25
    use Injectable;
26
    use Configurable;
27
28
    public function __construct()
29
    {
30
        if (!class_exists(Locale::class)) {
31
            throw new Exception("This backend requires the php-intl extension");
32
        }
33
    }
34
35
    /**
36
     * An exhaustive list of possible locales (code => language and country)
37
     *
38
     * @config
39
     * @var array
40
     */
41
    private static $locales = array (
42
        'aa_DJ' => 'Afar (Djibouti)',
43
        'ab_GE' => 'Abkhazian (Georgia)',
44
        'abr_GH' => 'Abron (Ghana)',
45
        'ace_ID' => 'Achinese (Indonesia)',
46
        'ady_RU' => 'Adyghe (Russia)',
47
        'af_ZA' => 'Afrikaans (South Africa)',
48
        'ak_GH' => 'Akan (Ghana)',
49
        'am_ET' => 'Amharic (Ethiopia)',
50
        'ar_AE' => 'Arabic (United Arab Emirates)',
51
        'ar_BH' => 'Arabic (Bahrain)',
52
        'ar_DZ' => 'Arabic (Algeria)',
53
        'ar_EG' => 'Arabic (Egypt)',
54
        'ar_EH' => 'Arabic (Western Sahara)',
55
        'ar_IQ' => 'Arabic (Iraq)',
56
        'ar_JO' => 'Arabic (Jordan)',
57
        'ar_KW' => 'Arabic (Kuwait)',
58
        'ar_LB' => 'Arabic (Lebanon)',
59
        'ar_LY' => 'Arabic (Libya)',
60
        'ar_MA' => 'Arabic (Morocco)',
61
        'ar_MR' => 'Arabic (Mauritania)',
62
        'ar_OM' => 'Arabic (Oman)',
63
        'ar_PS' => 'Arabic (Palestinian Territory)',
64
        'ar_QA' => 'Arabic (Qatar)',
65
        'ar_SA' => 'Arabic (Saudi Arabia)',
66
        'ar_SD' => 'Arabic (Sudan)',
67
        'ar_SY' => 'Arabic (Syria)',
68
        'ar_TD' => 'Arabic (Chad)',
69
        'ar_TN' => 'Arabic (Tunisia)',
70
        'ar_YE' => 'Arabic (Yemen)',
71
        'as_IN' => 'Assamese (India)',
72
        'ast_ES' => 'Asturian (Spain)',
73
        'auv_FR' => 'Auvergnat (France)',
74
        'av_RU' => 'Avaric (Russia)',
75
        'awa_IN' => 'Awadhi (India)',
76
        'ay_BO' => 'Aymara (Bolivia)',
77
        'ay_PE' => 'Aymara (Peru)',
78
        'az_AZ' => 'Azerbaijani (Azerbaijan)',
79
        'az_IR' => 'Azerbaijani (Iran)',
80
        'ba_RU' => 'Bashkir (Russia)',
81
        'ban_ID' => 'Balinese (Indonesia)',
82
        'bcc_PK' => 'Balochi, Southern (Pakistan)',
83
        'bcl_PH' => 'Bicolano, Central (Philippines)',
84
        'be_BY' => 'Belarusian (Belarus)',
85
        'bew_ID' => 'Betawi (Indonesia)',
86
        'bg_BG' => 'Bulgarian (Bulgaria)',
87
        'bgc_IN' => 'Haryanvi (India)',
88
        'bgn_PK' => 'Balochi, Western (Pakistan)',
89
        'bgp_PK' => 'Balochi, Easter (Pakistan)',
90
        'bhb_IN' => 'Bhili (India)',
91
        'bhi_IN' => 'Bhilali (India)',
92
        'bhk_PH' => 'Bicolano, Albay (Philippines)',
93
        'bho_IN' => 'Bhojpuri (India)',
94
        'bho_MU' => 'Bhojpuri (Mauritius)',
95
        'bho_NP' => 'Bhojpuri (Nepal)',
96
        'bi_VU' => 'Bislama (Vanuatu)',
97
        'bjj_IN' => 'Kanauji (India)',
98
        'bjn_ID' => 'Banjar (Indonesia)',
99
        'bm_ML' => 'Bambara (Mali)',
100
        'bn_BD' => 'Bengali (Bangladesh)',
101
        'bn_IN' => 'Bengali (India)',
102
        'bo_CN' => 'Tibetan (China)',
103
        'bqi_IR' => 'Bakhtiari (Iran)',
104
        'brh_PK' => 'Brahui (Pakistan)',
105
        'bs_BA' => 'Bosnian (Bosnia and Herzegovina)',
106
        'btk_ID' => 'Batak (Indonesia)',
107
        'buc_YT' => 'Bushi (Mayotte)',
108
        'bug_ID' => 'Buginese (Indonesia)',
109
        'ca_AD' => 'Catalan (Andorra)',
110
        'ca_ES' => 'Catalan (Spain)',
111
        'ce_RU' => 'Chechen (Russia)',
112
        'ceb_PH' => 'Cebuano (Philippines)',
113
        'cgg_UG' => 'Chiga (Uganda)',
114
        'ch_GU' => 'Chamorro (Guam)',
115
        'chk_FM' => 'Chuukese (Micronesia)',
116
        'crk_CA' => 'Cree, Plains (Canada)',
117
        'cs_CZ' => 'Czech (Czech Republic)',
118
        'cwd_CA' => 'Cree, Woods (Canada)',
119
        'cy_GB' => 'Welsh (United Kingdom)',
120
        'da_DK' => 'Danish (Denmark)',
121
        'da_GL' => 'Danish (Greenland)',
122
        'dcc_IN' => 'Deccan (India)',
123
        'de_AT' => 'German (Austria)',
124
        'de_BE' => 'German (Belgium)',
125
        'de_CH' => 'German (Switzerland)',
126
        'de_DE' => 'German (Germany)',
127
        'de_LI' => 'German (Liechtenstein)',
128
        'de_LU' => 'German (Luxembourg)',
129
        'dgo_IN' => 'Dogri (India)',
130
        'dhd_IN' => 'Dhundari (India)',
131
        'diq_TR' => 'Dimli (Turkey)',
132
        'dje_NE' => 'Zarma (Niger)',
133
        'dv_MV' => 'Divehi (Maldives)',
134
        'dz_BT' => 'Dzongkha (Bhutan)',
135
        'ee_GH' => 'Ewe (Ghana)',
136
        'el_CY' => 'Greek (Cyprus)',
137
        'el_GR' => 'Greek (Greece)',
138
        'en_AS' => 'English (American Samoa)',
139
        'en_AU' => 'English (Australia)',
140
        'en_BM' => 'English (Bermuda)',
141
        'en_BS' => 'English (Bahamas)',
142
        'en_CA' => 'English (Canada)',
143
        'en_DE' => 'English (Germany)',
144
        'en_ES' => 'English (Spain)',
145
        'en_FR' => 'English (France)',
146
        'en_GB' => 'English (United Kingdom)',
147
        'en_HK' => 'English (Hong Kong SAR China)',
148
        'en_IE' => 'English (Ireland)',
149
        'en_IN' => 'English (India)',
150
        'en_IT' => 'English (Italy)',
151
        'en_JM' => 'English (Jamaica)',
152
        'en_KE' => 'English (Kenya)',
153
        'en_LR' => 'English (Liberia)',
154
        'en_MM' => 'English (Myanmar)',
155
        'en_MW' => 'English (Malawi)',
156
        'en_MY' => 'English (Malaysia)',
157
        'en_NL' => 'English (Netherlands)',
158
        'en_NZ' => 'English (New Zealand)',
159
        'en_PH' => 'English (Philippines)',
160
        'en_SG' => 'English (Singapore)',
161
        'en_TT' => 'English (Trinidad and Tobago)',
162
        'en_US' => 'English (United States)',
163
        'en_ZA' => 'English (South Africa)',
164
        'eo_XX' => 'Esperanto',
165
        'es_419' => 'Spanish (Latin America)',
166
        'es_AR' => 'Spanish (Argentina)',
167
        'es_BO' => 'Spanish (Bolivia)',
168
        'es_CL' => 'Spanish (Chile)',
169
        'es_CO' => 'Spanish (Colombia)',
170
        'es_CR' => 'Spanish (Costa Rica)',
171
        'es_CU' => 'Spanish (Cuba)',
172
        'es_DO' => 'Spanish (Dominican Republic)',
173
        'es_EC' => 'Spanish (Ecuador)',
174
        'es_ES' => 'Spanish (Spain)',
175
        'es_GQ' => 'Spanish (Equatorial Guinea)',
176
        'es_GT' => 'Spanish (Guatemala)',
177
        'es_HN' => 'Spanish (Honduras)',
178
        'es_MX' => 'Spanish (Mexico)',
179
        'es_NI' => 'Spanish (Nicaragua)',
180
        'es_PA' => 'Spanish (Panama)',
181
        'es_PE' => 'Spanish (Peru)',
182
        'es_PH' => 'Spanish (Philippines)',
183
        'es_PR' => 'Spanish (Puerto Rico)',
184
        'es_PY' => 'Spanish (Paraguay)',
185
        'es_SV' => 'Spanish (El Salvador)',
186
        'es_US' => 'Spanish (United States)',
187
        'es_UY' => 'Spanish (Uruguay)',
188
        'es_VE' => 'Spanish (Venezuela)',
189
        'et_EE' => 'Estonian (Estonia)',
190
        'eu_ES' => 'Basque (Spain)',
191
        'fa_AF' => 'Persian (Afghanistan)',
192
        'fa_IR' => 'Persian (Iran)',
193
        'fa_PK' => 'Persian (Pakistan)',
194
        'fan_GQ' => 'Fang (Equatorial Guinea)',
195
        'fi_FI' => 'Finnish (Finland)',
196
        'fi_SE' => 'Finnish (Sweden)',
197
        'fil_PH' => 'Filipino (Philippines)',
198
        'fj_FJ' => 'Fijian (Fiji)',
199
        'fo_FO' => 'Faroese (Faroe Islands)',
200
        'fon_BJ' => 'Fon (Benin)',
201
        'fr_002' => 'French (Africa)',
202
        'fr_BE' => 'French (Belgium)',
203
        'fr_CA' => 'French (Canada)',
204
        'fr_CH' => 'French (Switzerland)',
205
        'fr_DZ' => 'French (Algeria)',
206
        'fr_FR' => 'French (France)',
207
        'fr_GF' => 'French (French Guiana)',
208
        'fr_GP' => 'French (Guadeloupe)',
209
        'fr_HT' => 'French (Haiti)',
210
        'fr_KM' => 'French (Comoros)',
211
        'fr_MA' => 'French (Morocco)',
212
        'fr_MQ' => 'French (Martinique)',
213
        'fr_MU' => 'French (Mauritius)',
214
        'fr_NC' => 'French (New Caledonia)',
215
        'fr_PF' => 'French (French Polynesia)',
216
        'fr_PM' => 'French (Saint Pierre and Miquelon)',
217
        'fr_RE' => 'French (Reunion)',
218
        'fr_SC' => 'French (Seychelles)',
219
        'fr_SN' => 'French (Senegal)',
220
        'fr_US' => 'French (United States)',
221
        'fuv_NG' => 'Fulfulde (Nigeria)',
222
        'ga_GB' => 'Irish (United Kingdom)',
223
        'ga_IE' => 'Irish (Ireland)',
224
        'gaa_GH' => 'Ga (Ghana)',
225
        'gbm_IN' => 'Garhwali (India)',
226
        'gcr_GF' => 'Guianese Creole French (French Guiana)',
227
        'gd_GB' => 'Scottish Gaelic (United Kingdom)',
228
        'gil_KI' => 'Gilbertese (Kiribati)',
229
        'gl_ES' => 'Galician (Spain)',
230
        'glk_IR' => 'Gilaki (Iran)',
231
        'gn_PY' => 'Guarani (Paraguay)',
232
        'gno_IN' => 'Gondi, Northern (India)',
233
        'gsw_CH' => 'Swiss German (Switzerland)',
234
        'gsw_LI' => 'Swiss German (Liechtenstein)',
235
        'gu_IN' => 'Gujarati (India)',
236
        'guz_KE' => 'Gusii (Kenya)',
237
        'ha_NE' => 'Hausa (Niger)',
238
        'ha_NG' => 'Hausa (Nigeria)',
239
        'haw_US' => 'Hawaiian (United States)',
240
        'haz_AF' => 'Hazaragi (Afghanistan)',
241
        'he_IL' => 'Hebrew (Israel)',
242
        'hi_IN' => 'Hindi (India)',
243
        'hil_PH' => 'Hiligaynon (Philippines)',
244
        'hne_IN' => 'Chhattisgarhi (India)',
245
        'hno_PK' => 'Hindko, Northern (Pakistan)',
246
        'hoc_IN' => 'Ho (India)',
247
        'hr_AT' => 'Croatian (Austria)',
248
        'hr_BA' => 'Croatian (Bosnia and Herzegovina)',
249
        'hr_HR' => 'Croatian (Croatia)',
250
        'ht_HT' => 'Haitian (Haiti)',
251
        'hu_AT' => 'Hungarian (Austria)',
252
        'hu_HU' => 'Hungarian (Hungary)',
253
        'hu_RO' => 'Hungarian (Romania)',
254
        'hu_RS' => 'Hungarian (Serbia)',
255
        'hy_AM' => 'Armenian (Armenia)',
256
        'id_ID' => 'Indonesian (Indonesia)',
257
        'ig_NG' => 'Igbo (Nigeria)',
258
        'ilo_PH' => 'Iloko (Philippines)',
259
        'inh_RU' => 'Ingush (Russia)',
260
        'is_IS' => 'Icelandic (Iceland)',
261
        'it_CH' => 'Italian (Switzerland)',
262
        'it_FR' => 'Italian (France)',
263
        'it_HR' => 'Italian (Croatia)',
264
        'it_IT' => 'Italian (Italy)',
265
        'it_SM' => 'Italian (San Marino)',
266
        'it_US' => 'Italian (United States)',
267
        'iu_CA' => 'Inuktitut (Canada)',
268
        'ja_JP' => 'Japanese (Japan)',
269
        'jv_ID' => 'Javanese (Indonesia)',
270
        'ka_GE' => 'Georgian (Georgia)',
271
        'kam_KE' => 'Kamba (Kenya)',
272
        'kbd_RU' => 'Kabardian (Russia)',
273
        'kfy_IN' => 'Kumauni (India)',
274
        'kha_IN' => 'Khasi (India)',
275
        'khn_IN' => 'Khandesi (India)',
276
        'ki_KE' => 'Kikuyu (Kenya)',
277
        'kj_NA' => 'Kuanyama (Namibia)',
278
        'kk_CN' => 'Kazakh (China)',
279
        'kk_KZ' => 'Kazakh (Kazakhstan)',
280
        'kl_DK' => 'Kalaallisut (Denmark)',
281
        'kl_GL' => 'Kalaallisut (Greenland)',
282
        'kln_KE' => 'Kalenjin (Kenya)',
283
        'km_KH' => 'Khmer (Cambodia)',
284
        'kn_IN' => 'Kannada (India)',
285
        'ko_KR' => 'Korean (Korea)',
286
        'koi_RU' => 'Komi-Permyak (Russia)',
287
        'kok_IN' => 'Konkani (India)',
288
        'kos_FM' => 'Kosraean (Micronesia)',
289
        'kpv_RU' => 'Komi-Zyrian (Russia)',
290
        'krc_RU' => 'Karachay-Balkar (Russia)',
291
        'kru_IN' => 'Kurukh (India)',
292
        'ks_IN' => 'Kashmiri (India)',
293
        'ku_IQ' => 'Kurdish (Iraq)',
294
        'ku_IR' => 'Kurdish (Iran)',
295
        'ku_SY' => 'Kurdish (Syria)',
296
        'ku_TR' => 'Kurdish (Turkey)',
297
        'kum_RU' => 'Kumyk (Russia)',
298
        'kxm_TH' => 'Khmer, Northern (Thailand)',
299
        'ky_KG' => 'Kirghiz (Kyrgyzstan)',
300
        'la_VA' => 'Latin (Vatican)',
301
        'lah_PK' => 'Lahnda (Pakistan)',
302
        'lb_LU' => 'Luxembourgish (Luxembourg)',
303
        'lbe_RU' => 'Lak (Russia)',
304
        'lc_XX' => 'LOLCAT',
305
        'lez_RU' => 'Lezghian (Russia)',
306
        'lg_UG' => 'Ganda (Uganda)',
307
        'lij_IT' => 'Ligurian (Italy)',
308
        'lij_MC' => 'Ligurian (Monaco)',
309
        'ljp_ID' => 'Lampung (Indonesia)',
310
        'lmn_IN' => 'Lambadi (India)',
311
        'ln_CD' => 'Lingala (Congo - Kinshasa)',
312
        'ln_CG' => 'Lingala (Congo - Brazzaville)',
313
        'lo_LA' => 'Lao (Laos)',
314
        'lrc_IR' => 'Luri, Northern (Iran)',
315
        'lt_LT' => 'Lithuanian (Lithuania)',
316
        'luo_KE' => 'Luo (Kenya)',
317
        'luy_KE' => 'Luyia (Kenya)',
318
        'lv_LV' => 'Latvian (Latvia)',
319
        'mad_ID' => 'Madurese (Indonesia)',
320
        'mai_IN' => 'Maithili (India)',
321
        'mai_NP' => 'Maithili (Nepal)',
322
        'mak_ID' => 'Makasar (Indonesia)',
323
        'mdf_RU' => 'Moksha (Russia)',
324
        'mdh_PH' => 'Maguindanao (Philippines)',
325
        'mer_KE' => 'Meru (Kenya)',
326
        'mfa_TH' => 'Malay, Pattani (Thailand)',
327
        'mfe_MU' => 'Morisyen (Mauritius)',
328
        'mg_MG' => 'Malagasy (Madagascar)',
329
        'mh_MH' => 'Marshallese (Marshall Islands)',
330
        'mi_NZ' => 'te reo Māori (New Zealand)',
331
        'min_ID' => 'Minangkabau (Indonesia)',
332
        'mk_MK' => 'Macedonian (Macedonia)',
333
        'ml_IN' => 'Malayalam (India)',
334
        'mn_CN' => 'Mongolian (China)',
335
        'mn_MN' => 'Mongolian (Mongolia)',
336
        'mni_IN' => 'Manipuri (India)',
337
        'mr_IN' => 'Marathi (India)',
338
        'ms_BN' => 'Malay (Brunei)',
339
        'ms_CC' => 'Malay (Cocos Islands)',
340
        'ms_ID' => 'Malay (Indonesia)',
341
        'ms_MY' => 'Malay (Malaysia)',
342
        'ms_SG' => 'Malay (Singapore)',
343
        'mt_MT' => 'Maltese (Malta)',
344
        'mtr_IN' => 'Mewari (India)',
345
        'mup_IN' => 'Malvi (India)',
346
        'muw_IN' => 'Mundari (India)',
347
        'my_MM' => 'Burmese (Myanmar)',
348
        'myv_RU' => 'Erzya (Russia)',
349
        'na_NR' => 'Nauru (Nauru)',
350
        'nb_NO' => 'Norwegian Bokmal (Norway)',
351
        'nb_SJ' => 'Norwegian Bokmal (Svalbard and Jan Mayen)',
352
        'nd_ZW' => 'North Ndebele (Zimbabwe)',
353
        'ndc_MZ' => 'Ndau (Mozambique)',
354
        'ne_IN' => 'Nepali (India)',
355
        'ne_NP' => 'Nepali (Nepal)',
356
        'ng_NA' => 'Ndonga (Namibia)',
357
        'ngl_MZ' => 'Lomwe (Mozambique)',
358
        'niu_NU' => 'Niuean (Niue)',
359
        'nl_AN' => 'Dutch (Netherlands Antilles)',
360
        'nl_AW' => 'Dutch (Aruba)',
361
        'nl_BE' => 'Dutch (Belgium)',
362
        'nl_NL' => 'Dutch (Netherlands)',
363
        'nl_SR' => 'Dutch (Suriname)',
364
        'nn_NO' => 'Norwegian Nynorsk (Norway)',
365
        'nod_TH' => 'Thai, Northern (Thailand)',
366
        'noe_IN' => 'Nimadi (India)',
367
        'nso_ZA' => 'Northern Sotho (South Africa)',
368
        'ny_MW' => 'Nyanja (Malawi)',
369
        'ny_ZM' => 'Nyanja (Zambia)',
370
        'nyn_UG' => 'Nyankole (Uganda)',
371
        'om_ET' => 'Oromo (Ethiopia)',
372
        'or_IN' => 'Oriya (India)',
373
        'pa_IN' => 'Punjabi (India)',
374
        'pag_PH' => 'Pangasinan (Philippines)',
375
        'pap_AN' => 'Papiamento (Netherlands Antilles)',
376
        'pap_AW' => 'Papiamento (Aruba)',
377
        'pau_PW' => 'Palauan (Palau)',
378
        'pl_PL' => 'Polish (Poland)',
379
        'pl_UA' => 'Polish (Ukraine)',
380
        'pon_FM' => 'Pohnpeian (Micronesia)',
381
        'ps_AF' => 'Pashto (Afghanistan)',
382
        'ps_PK' => 'Pashto (Pakistan)',
383
        'pt_AO' => 'Portuguese (Angola)',
384
        'pt_BR' => 'Portuguese (Brazil)',
385
        'pt_CV' => 'Portuguese (Cape Verde)',
386
        'pt_GW' => 'Portuguese (Guinea-Bissau)',
387
        'pt_MZ' => 'Portuguese (Mozambique)',
388
        'pt_PT' => 'Portuguese (Portugal)',
389
        'pt_ST' => 'Portuguese (Sao Tome and Principe)',
390
        'pt_TL' => 'Portuguese (East Timor)',
391
        'qu_BO' => 'Quechua (Bolivia)',
392
        'qu_PE' => 'Quechua (Peru)',
393
        'rcf_RE' => 'R�union Creole French (Reunion)',
394
        'rej_ID' => 'Rejang (Indonesia)',
395
        'rif_MA' => 'Tarifit (Morocco)',
396
        'rjb_IN' => 'Rajbanshi (India)',
397
        'rm_CH' => 'Rhaeto-Romance (Switzerland)',
398
        'rmt_IR' => 'Domari (Iran)',
399
        'rn_BI' => 'Rundi (Burundi)',
400
        'ro_MD' => 'Romanian (Moldova)',
401
        'ro_RO' => 'Romanian (Romania)',
402
        'ro_RS' => 'Romanian (Serbia)',
403
        'ru_BY' => 'Russian (Belarus)',
404
        'ru_KG' => 'Russian (Kyrgyzstan)',
405
        'ru_KZ' => 'Russian (Kazakhstan)',
406
        'ru_RU' => 'Russian (Russia)',
407
        'ru_SJ' => 'Russian (Svalbard and Jan Mayen)',
408
        'ru_UA' => 'Russian (Ukraine)',
409
        'rw_RW' => 'Kinyarwanda (Rwanda)',
410
        'sa_IN' => 'Sanskrit (India)',
411
        'sah_RU' => 'Yakut (Russia)',
412
        'sas_ID' => 'Sasak (Indonesia)',
413
        'sat_IN' => 'Santali (India)',
414
        'sck_IN' => 'Sadri (India)',
415
        'sco_GB' => 'Scots (United Kingdom)',
416
        'sco_SCO' => 'Scots',
417
        'sd_IN' => 'Sindhi (India)',
418
        'sd_PK' => 'Sindhi (Pakistan)',
419
        'se_NO' => 'Northern Sami (Norway)',
420
        'sg_CF' => 'Sango (Central African Republic)',
421
        'si_LK' => 'Sinhalese (Sri Lanka)',
422
        'sid_ET' => 'Sidamo (Ethiopia)',
423
        'sk_RS' => 'Slovak (Serbia)',
424
        'sk_SK' => 'Slovak (Slovakia)',
425
        'sl_AT' => 'Slovenian (Austria)',
426
        'sl_SI' => 'Slovenian (Slovenia)',
427
        'sm_AS' => 'Samoan (American Samoa)',
428
        'sm_WS' => 'Samoan (Samoa)',
429
        'sn_ZW' => 'Shona (Zimbabwe)',
430
        'so_DJ' => 'Somali (Djibouti)',
431
        'so_ET' => 'Somali (Ethiopia)',
432
        'so_SO' => 'Somali (Somalia)',
433
        'sou_TH' => 'Thai, Southern (Thailand)',
434
        'sq_AL' => 'Albanian (Albania)',
435
        'sr_BA' => 'Serbian (Bosnia and Herzegovina)',
436
        'sr_ME' => 'Serbian (Montenegro)',
437
        'sr_RS' => 'Serbian (Serbia)',
438
        'ss_SZ' => 'Swati (Swaziland)',
439
        'ss_ZA' => 'Swati (South Africa)',
440
        'st_LS' => 'Southern Sotho (Lesotho)',
441
        'st_ZA' => 'Southern Sotho (South Africa)',
442
        'su_ID' => 'Sundanese (Indonesia)',
443
        'sv_AX' => 'Swedish (Aland Islands)',
444
        'sv_FI' => 'Swedish (Finland)',
445
        'sv_SE' => 'Swedish (Sweden)',
446
        'sw_KE' => 'Swahili (Kenya)',
447
        'sw_SO' => 'Swahili (Somalia)',
448
        'sw_TZ' => 'Swahili (Tanzania)',
449
        'sw_UG' => 'Swahili (Uganda)',
450
        'swb_KM' => 'Comorian (Comoros)',
451
        'swb_YT' => 'Comorian (Mayotte)',
452
        'swv_IN' => 'Shekhawati (India)',
453
        'ta_IN' => 'Tamil (India)',
454
        'ta_LK' => 'Tamil (Sri Lanka)',
455
        'ta_MY' => 'Tamil (Malaysia)',
456
        'ta_SG' => 'Tamil (Singapore)',
457
        'tcy_IN' => 'Tulu (India)',
458
        'te_IN' => 'Telugu (India)',
459
        'tet_TL' => 'Tetum (East Timor)',
460
        'tg_TJ' => 'Tajik (Tajikistan)',
461
        'th_TH' => 'Thai (Thailand)',
462
        'ti_ER' => 'Tigrinya (Eritrea)',
463
        'ti_ET' => 'Tigrinya (Ethiopia)',
464
        'tk_IR' => 'Turkmen (Iran)',
465
        'tk_TM' => 'Turkmen (Turkmenistan)',
466
        'tkl_TK' => 'Tokelau (Tokelau)',
467
        'tl_PH' => 'Tagalog (Philippines)',
468
        'tl_US' => 'Tagalog (United States)',
469
        'tn_BW' => 'Tswana (Botswana)',
470
        'tn_ZA' => 'Tswana (South Africa)',
471
        'to_TO' => 'Tonga (Tonga)',
472
        'tr_CY' => 'Turkish (Cyprus)',
473
        'tr_DE' => 'Turkish (Germany)',
474
        'tr_MK' => 'Turkish (Macedonia)',
475
        'tr_TR' => 'Turkish (Turkey)',
476
        'ts_MZ' => 'Tsonga (Mozambique)',
477
        'ts_ZA' => 'Tsonga (South Africa)',
478
        'tsg_PH' => 'Tausug (Philippines)',
479
        'tt_RU' => 'Tatar (Russia)',
480
        'tts_TH' => 'Thai, Northeastern (Thailand)',
481
        'tvl_TV' => 'Tuvalu (Tuvalu)',
482
        'tw_GH' => 'Twi (Ghana)',
483
        'ty_PF' => 'Tahitian (French Polynesia)',
484
        'tyv_RU' => 'Tuvinian (Russia)',
485
        'tzm_MA' => 'Tamazight, Central Atlas (Morocco)',
486
        'udm_RU' => 'Udmurt (Russia)',
487
        'ug_CN' => 'Uighur (China)',
488
        'uk_UA' => 'Ukrainian (Ukraine)',
489
        'uli_FM' => 'Ulithian (Micronesia)',
490
        'ur_IN' => 'Urdu (India)',
491
        'ur_PK' => 'Urdu (Pakistan)',
492
        'uz_AF' => 'Uzbek (Afghanistan)',
493
        'uz_UZ' => 'Uzbek (Uzbekistan)',
494
        've_ZA' => 'Venda (South Africa)',
495
        'vi_US' => 'Vietnamese (United States)',
496
        'vi_VN' => 'Vietnamese (Vietnam)',
497
        'vmw_MZ' => 'Waddar (Mozambique)',
498
        'wal_ET' => 'Walamo (Ethiopia)',
499
        'war_PH' => 'Waray (Philippines)',
500
        'wbq_IN' => 'Waddar (India)',
501
        'wbr_IN' => 'Wagdi (India)',
502
        'wo_MR' => 'Wolof (Mauritania)',
503
        'wo_SN' => 'Wolof (Senegal)',
504
        'wtm_IN' => 'Mewati (India)',
505
        'xh_ZA' => 'Xhosa (South Africa)',
506
        'xnr_IN' => 'Kangri (India)',
507
        'xog_UG' => 'Soga (Uganda)',
508
        'yap_FM' => 'Yapese (Micronesia)',
509
        'yo_NG' => 'Yoruba (Nigeria)',
510
        'za_CN' => 'Zhuang (China)',
511
        'zh_CN' => 'Chinese (China)',
512
        'zh_HK' => 'Chinese (Hong Kong SAR China)',
513
        'zh_MO' => 'Chinese (Macao SAR China)',
514
        'zh_SG' => 'Chinese (Singapore)',
515
        'zh_TW' => 'Chinese (Taiwan)',
516
        'zh_US' => 'Chinese (United States)',
517
        'zh_cmn' => 'Chinese (Mandarin)',
518
        'zh_yue' => 'Chinese (Cantonese)',
519
        'zu_ZA' => 'Zulu (South Africa)'
520
    );
521
522
    /**
523
     * List of language names
524
     *
525
     * Language codes follow ISO 639-1 (2 letter), unless not present, in which case a locale will be
526
     * encoded in ISO 639-3 (3 letter). See https://en.wikipedia.org/wiki/ISO_639
527
     *
528
     * @config
529
     * @var array
530
     */
531
    private static $languages = array(
532
        'af' => 'Afrikaans',
533
        'sq' => 'Albanian',
534
        'ar' => 'Arabic',
535
        'eu' => 'Basque',
536
        'be' => 'Belarusian',
537
        'bn' => 'Bengali',
538
        'bg' => 'Bulgarian',
539
        'ca' => 'Catalan',
540
        'zh' => 'Chinese',
541
        'hr' => 'Croatian',
542
        'cs' => 'Czech',
543
        'cy' => 'Welsh',
544
        'da' => 'Danish',
545
        'nl' => 'Dutch',
546
        'en' => 'English',
547
        'eo' => 'Esperanto',
548
        'et' => 'Estonian',
549
        'fo' => 'Faroese',
550
        'fi' => 'Finnish',
551
        'fr' => 'French',
552
        'gd' => 'Gaelic',
553
        'gl' => 'Galician',
554
        'de' => 'German',
555
        'el' => 'Greek',
556
        'gu' => 'Gujarati',
557
        'ha' => 'Hausa',
558
        'he' => 'Hebrew',
559
        'hi' => 'Hindi',
560
        'hu' => 'Hungarian',
561
        'is' => 'Icelandic',
562
        'io' => 'Ido',
563
        'id' => 'Indonesian',
564
        'ga' => 'Irish',
565
        'it' => 'Italian',
566
        'ja' => 'Japanese',
567
        'jv' => 'Javanese',
568
        'ko' => 'Korean',
569
        'ku' => 'Kurdish',
570
        'lv' => 'Latvian',
571
        'lt' => 'Lithuanian',
572
        'lmo' => 'Lombard',
573
        'mk' => 'Macedonian',
574
        'mi' => 'te reo Māori',
575
        'ms' => 'Malay',
576
        'mt' => 'Maltese',
577
        'mr' => 'Marathi',
578
        'ne' => 'Nepali',
579
        'nb' => 'Norwegian',
580
        'om' => 'Oromo',
581
        'fa' => 'Persian',
582
        'pl' => 'Polish',
583
        'pt' => 'Portuguese',
584
        'pa' => 'Punjabi',
585
        'qu' => 'Quechua',
586
        'rm' => 'Romansh',
587
        'ro' => 'Romanian',
588
        'ru' => 'Russian',
589
        'sco' => 'Scots',
590
        'sr' => 'Serbian',
591
        'sk' => 'Slovak',
592
        'sl' => 'Slovenian',
593
        'es' => 'Spanish',
594
        'sv' => 'Swedish',
595
        'tl' => 'Tagalog',
596
        'ta' => 'Tamil',
597
        'te' => 'Telugu',
598
        'to' => 'Tonga',
599
        'ts' => 'Tsonga',
600
        'tn' => 'Tswana',
601
        'tr' => 'Turkish',
602
        'tk' => 'Turkmen',
603
        'tw' => 'Twi',
604
        'uk' => 'Ukrainian',
605
        'ur' => 'Urdu',
606
        'uz' => 'Uzbek',
607
        've' => 'Venda',
608
        'vi' => 'Vietnamese',
609
        'wa' => 'Walloon',
610
        'wo' => 'Wolof',
611
        'xh' => 'Xhosa',
612
        'yi' => 'Yiddish',
613
        'zu' => 'Zulu',
614
    );
615
616
    /**
617
     * Config for ltr/rtr of specific locales.
618
     * Will default to ltr.
619
     *
620
     * @config
621
     * @var array
622
     */
623
    private static $text_direction = [
624
        'ar' => 'rtl',
625
        'dv' => 'rtl',
626
        'fa' => 'rtl',
627
        'ha_Arab' => 'rtl',
628
        'he' => 'rtl',
629
        'ku' => 'rtl',
630
        'pa_Arab' => 'rtl',
631
        'ps' => 'rtl',
632
        'syr' => 'rtl',
633
        'ug' => 'rtl',
634
        'ur' => 'rtl',
635
        'uz_Arab' => 'rtl',
636
    ];
637
638
    /**
639
     * @config
640
     * @var array $likely_subtags Provides you "likely locales"
641
     * for a given "short" language code. This is a guess,
642
     * as we can't disambiguate from e.g. "en" to "en_US" - it
643
     * could also mean "en_UK".
644
     * @see http://www.unicode.org/cldr/data/charts/supplemental/likely_subtags.html
645
     */
646
    private static $likely_subtags = array(
647
        'aa' => 'aa_ET',
648
        'ab' => 'ab_GE',
649
        'ady' => 'ady_RU',
650
        'af' => 'af_ZA',
651
        'ak' => 'ak_GH',
652
        'am' => 'am_ET',
653
        'ar' => 'ar_EG',
654
        'as' => 'as_IN',
655
        'ast' => 'ast_ES',
656
        'av' => 'av_RU',
657
        'ay' => 'ay_BO',
658
        'az' => 'az_AZ',
659
        'az_Cyrl' => 'az_AZ',
660
        'az_Arab' => 'az_IR',
661
        'az_IR' => 'az_IR',
662
        'ba' => 'ba_RU',
663
        'be' => 'be_BY',
664
        'bg' => 'bg_BG',
665
        'bi' => 'bi_VU',
666
        'bn' => 'bn_BD',
667
        'bo' => 'bo_CN',
668
        'bs' => 'bs_BA',
669
        'ca' => 'ca_ES',
670
        'ce' => 'ce_RU',
671
        'ceb' => 'ceb_PH',
672
        'ch' => 'ch_GU',
673
        'chk' => 'chk_FM',
674
        'crk' => 'crk_CA',
675
        'cs' => 'cs_CZ',
676
        'cwd' => 'cwd_CA',
677
        'cy' => 'cy_GB',
678
        'da' => 'da_DK',
679
        'de' => 'de_DE',
680
        'dv' => 'dv_MV',
681
        'dz' => 'dz_BT',
682
        'ee' => 'ee_GH',
683
        'efi' => 'efi_NG',
684
        'el' => 'el_GR',
685
        'en' => 'en_US',
686
        'es' => 'es_ES',
687
        'et' => 'et_EE',
688
        'eu' => 'eu_ES',
689
        'eo' => 'eo_XX',
690
        'fa' => 'fa_IR',
691
        'fi' => 'fi_FI',
692
        'fil' => 'fil_PH',
693
        'fj' => 'fj_FJ',
694
        'fo' => 'fo_FO',
695
        'fr' => 'fr_FR',
696
        'fur' => 'fur_IT',
697
        'fy' => 'fy_NL',
698
        'ga' => 'ga_IE',
699
        'gaa' => 'gaa_GH',
700
        'gd' => 'gd_GB',
701
        'gil' => 'gil_KI',
702
        'gl' => 'gl_ES',
703
        'gn' => 'gn_PY',
704
        'gu' => 'gu_IN',
705
        'ha' => 'ha_NG',
706
        'ha_Arab' => 'ha_SD',
707
        'ha_SD' => 'ha_SD',
708
        'haw' => 'haw_US',
709
        'he' => 'he_IL',
710
        'hi' => 'hi_IN',
711
        'hil' => 'hil_PH',
712
        'ho' => 'ho_PG',
713
        'hr' => 'hr_HR',
714
        'ht' => 'ht_HT',
715
        'hu' => 'hu_HU',
716
        'hy' => 'hy_AM',
717
        'id' => 'id_ID',
718
        'ig' => 'ig_NG',
719
        'ii' => 'ii_CN',
720
        'ilo' => 'ilo_PH',
721
        'inh' => 'inh_RU',
722
        'is' => 'is_IS',
723
        'it' => 'it_IT',
724
        'iu' => 'iu_CA',
725
        'ja' => 'ja_JP',
726
        'jv' => 'jv_ID',
727
        'ka' => 'ka_GE',
728
        'kaj' => 'kaj_NG',
729
        'kam' => 'kam_KE',
730
        'kbd' => 'kbd_RU',
731
        'kha' => 'kha_IN',
732
        'kk' => 'kk_KZ',
733
        'kl' => 'kl_GL',
734
        'km' => 'km_KH',
735
        'kn' => 'kn_IN',
736
        'ko' => 'ko_KR',
737
        'koi' => 'koi_RU',
738
        'kok' => 'kok_IN',
739
        'kos' => 'kos_FM',
740
        'kpe' => 'kpe_LR',
741
        'kpv' => 'kpv_RU',
742
        'krc' => 'krc_RU',
743
        'ks' => 'ks_IN',
744
        'ku' => 'ku_IQ',
745
        'ku_Latn' => 'ku_TR',
746
        'ku_TR' => 'ku_TR',
747
        'kum' => 'kum_RU',
748
        'kxm' => 'kxm_TH',
749
        'ky' => 'ky_KG',
750
        'la' => 'la_VA',
751
        'lah' => 'lah_PK',
752
        'lb' => 'lb_LU',
753
        'lbe' => 'lbe_RU',
754
        'lez' => 'lez_RU',
755
        'ln' => 'ln_CD',
756
        'lo' => 'lo_LA',
757
        'lt' => 'lt_LT',
758
        'lv' => 'lv_LV',
759
        'mai' => 'mai_IN',
760
        'mdf' => 'mdf_RU',
761
        'mdh' => 'mdh_PH',
762
        'mg' => 'mg_MG',
763
        'mh' => 'mh_MH',
764
        'mi' => 'mi_NZ',
765
        'mk' => 'mk_MK',
766
        'ml' => 'ml_IN',
767
        'mn' => 'mn_MN',
768
        'mn_CN' => 'mn_CN',
769
        'mn_Mong' => 'mn_CN',
770
        'mr' => 'mr_IN',
771
        'ms' => 'ms_MY',
772
        'mt' => 'mt_MT',
773
        'my' => 'my_MM',
774
        'myv' => 'myv_RU',
775
        'na' => 'na_NR',
776
        'nb' => 'nb_NO',
777
        'ne' => 'ne_NP',
778
        'niu' => 'niu_NU',
779
        'nl' => 'nl_NL',
780
        'nn' => 'nn_NO',
781
        'nr' => 'nr_ZA',
782
        'nso' => 'nso_ZA',
783
        'ny' => 'ny_MW',
784
        'om' => 'om_ET',
785
        'or' => 'or_IN',
786
        'os' => 'os_GE',
787
        'pa' => 'pa_IN',
788
        'pa_Arab' => 'pa_PK',
789
        'pa_PK' => 'pa_PK',
790
        'pag' => 'pag_PH',
791
        'pap' => 'pap_AN',
792
        'pau' => 'pau_PW',
793
        'pl' => 'pl_PL',
794
        'pon' => 'pon_FM',
795
        'ps' => 'ps_AF',
796
        'pt' => 'pt_BR',
797
        'qu' => 'qu_PE',
798
        'rm' => 'rm_CH',
799
        'rn' => 'rn_BI',
800
        'ro' => 'ro_RO',
801
        'ru' => 'ru_RU',
802
        'rw' => 'rw_RW',
803
        'sa' => 'sa_IN',
804
        'sah' => 'sah_RU',
805
        'sat' => 'sat_IN',
806
        'sd' => 'sd_IN',
807
        'se' => 'se_NO',
808
        'sg' => 'sg_CF',
809
        'si' => 'si_LK',
810
        'sid' => 'sid_ET',
811
        'sk' => 'sk_SK',
812
        'sl' => 'sl_SI',
813
        'sm' => 'sm_WS',
814
        'sn' => 'sn_ZW',
815
        'so' => 'so_SO',
816
        'sq' => 'sq_AL',
817
        'sr' => 'sr_RS',
818
        'ss' => 'ss_ZA',
819
        'st' => 'st_ZA',
820
        'su' => 'su_ID',
821
        'sv' => 'sv_SE',
822
        'sw' => 'sw_TZ',
823
        'swb' => 'swb_KM',
824
        'ta' => 'ta_IN',
825
        'te' => 'te_IN',
826
        'tet' => 'tet_TL',
827
        'tg' => 'tg_TJ',
828
        'th' => 'th_TH',
829
        'ti' => 'ti_ET',
830
        'tig' => 'tig_ER',
831
        'tk' => 'tk_TM',
832
        'tkl' => 'tkl_TK',
833
        'tl' => 'tl_PH',
834
        'tn' => 'tn_ZA',
835
        'to' => 'to_TO',
836
        'tpi' => 'tpi_PG',
837
        'tr' => 'tr_TR',
838
        'trv' => 'trv_TW',
839
        'ts' => 'ts_ZA',
840
        'tsg' => 'tsg_PH',
841
        'tt' => 'tt_RU',
842
        'tts' => 'tts_TH',
843
        'tvl' => 'tvl_TV',
844
        'tw' => 'tw_GH',
845
        'ty' => 'ty_PF',
846
        'tyv' => 'tyv_RU',
847
        'udm' => 'udm_RU',
848
        'ug' => 'ug_CN',
849
        'uk' => 'uk_UA',
850
        'uli' => 'uli_FM',
851
        'und' => 'en_US',
852
        'und_AD' => 'ca_AD',
853
        'und_AE' => 'ar_AE',
854
        'und_AF' => 'fa_AF',
855
        'und_AL' => 'sq_AL',
856
        'und_AM' => 'hy_AM',
857
        'und_AN' => 'pap_AN',
858
        'und_AO' => 'pt_AO',
859
        'und_AR' => 'es_AR',
860
        'und_AS' => 'sm_AS',
861
        'und_AT' => 'de_AT',
862
        'und_AW' => 'nl_AW',
863
        'und_AX' => 'sv_AX',
864
        'und_AZ' => 'az_AZ',
865
        'und_Arab' => 'ar_EG',
866
        'und_Arab_CN' => 'ug_CN',
867
        'und_Arab_DJ' => 'ar_DJ',
868
        'und_Arab_ER' => 'ar_ER',
869
        'und_Arab_IL' => 'ar_IL',
870
        'und_Arab_IN' => 'ur_IN',
871
        'und_Arab_PK' => 'ur_PK',
872
        'und_Armn' => 'hy_AM',
873
        'und_BA' => 'bs_BA',
874
        'und_BD' => 'bn_BD',
875
        'und_BE' => 'nl_BE',
876
        'und_BF' => 'fr_BF',
877
        'und_BG' => 'bg_BG',
878
        'und_BH' => 'ar_BH',
879
        'und_BI' => 'rn_BI',
880
        'und_BJ' => 'fr_BJ',
881
        'und_BL' => 'fr_BL',
882
        'und_BN' => 'ms_BN',
883
        'und_BO' => 'es_BO',
884
        'und_BR' => 'pt_BR',
885
        'und_BT' => 'dz_BT',
886
        'und_BY' => 'be_BY',
887
        'und_Beng' => 'bn_BD',
888
        'und_CD' => 'fr_CD',
889
        'und_CF' => 'sg_CF',
890
        'und_CG' => 'ln_CG',
891
        'und_CH' => 'de_CH',
892
        'und_CI' => 'fr_CI',
893
        'und_CL' => 'es_CL',
894
        'und_CM' => 'fr_CM',
895
        'und_CN' => 'zh_CN',
896
        'und_CO' => 'es_CO',
897
        'und_CR' => 'es_CR',
898
        'und_CU' => 'es_CU',
899
        'und_CV' => 'pt_CV',
900
        'und_CY' => 'el_CY',
901
        'und_CZ' => 'cs_CZ',
902
        'und_Cans' => 'cwd_CA',
903
        'und_Cyrl' => 'ru_RU',
904
        'und_Cyrl_BA' => 'sr_BA',
905
        'und_Cyrl_GE' => 'ab_GE',
906
        'und_DE' => 'de_DE',
907
        'und_DJ' => 'aa_DJ',
908
        'und_DK' => 'da_DK',
909
        'und_DO' => 'es_DO',
910
        'und_DZ' => 'ar_DZ',
911
        'und_Deva' => 'hi_IN',
912
        'und_EC' => 'es_EC',
913
        'und_EE' => 'et_EE',
914
        'und_EG' => 'ar_EG',
915
        'und_EH' => 'ar_EH',
916
        'und_ER' => 'ti_ER',
917
        'und_ES' => 'es_ES',
918
        'und_ET' => 'am_ET',
919
        'und_Ethi' => 'am_ET',
920
        'und_FI' => 'fi_FI',
921
        'und_FJ' => 'fj_FJ',
922
        'und_FM' => 'chk_FM',
923
        'und_FO' => 'fo_FO',
924
        'und_FR' => 'fr_FR',
925
        'und_GA' => 'fr_GA',
926
        'und_GE' => 'ka_GE',
927
        'und_GF' => 'fr_GF',
928
        'und_GH' => 'ak_GH',
929
        'und_GL' => 'kl_GL',
930
        'und_GN' => 'fr_GN',
931
        'und_GP' => 'fr_GP',
932
        'und_GQ' => 'fr_GQ',
933
        'und_GR' => 'el_GR',
934
        'und_GT' => 'es_GT',
935
        'und_GU' => 'ch_GU',
936
        'und_GW' => 'pt_GW',
937
        'und_Geor' => 'ka_GE',
938
        'und_Grek' => 'el_GR',
939
        'und_Gujr' => 'gu_IN',
940
        'und_Guru' => 'pa_IN',
941
        'und_HK' => 'zh_HK',
942
        'und_HN' => 'es_HN',
943
        'und_HR' => 'hr_HR',
944
        'und_HT' => 'ht_HT',
945
        'und_HU' => 'hu_HU',
946
        'und_Hani' => 'zh_CN',
947
        'und_Hans' => 'zh_CN',
948
        'und_Hant' => 'zh_TW',
949
        'und_Hebr' => 'he_IL',
950
        'und_ID' => 'id_ID',
951
        'und_IL' => 'he_IL',
952
        'und_IN' => 'hi_IN',
953
        'und_IQ' => 'ar_IQ',
954
        'und_IR' => 'fa_IR',
955
        'und_IS' => 'is_IS',
956
        'und_IT' => 'it_IT',
957
        'und_JO' => 'ar_JO',
958
        'und_JP' => 'ja_JP',
959
        'und_Jpan' => 'ja_JP',
960
        'und_KG' => 'ky_KG',
961
        'und_KH' => 'km_KH',
962
        'und_KM' => 'ar_KM',
963
        'und_KP' => 'ko_KP',
964
        'und_KR' => 'ko_KR',
965
        'und_KW' => 'ar_KW',
966
        'und_KZ' => 'ru_KZ',
967
        'und_Khmr' => 'km_KH',
968
        'und_Knda' => 'kn_IN',
969
        'und_Kore' => 'ko_KR',
970
        'und_LA' => 'lo_LA',
971
        'und_LB' => 'ar_LB',
972
        'und_LI' => 'de_LI',
973
        'und_LK' => 'si_LK',
974
        'und_LS' => 'st_LS',
975
        'und_LT' => 'lt_LT',
976
        'und_LU' => 'fr_LU',
977
        'und_LV' => 'lv_LV',
978
        'und_LY' => 'ar_LY',
979
        'und_Laoo' => 'lo_LA',
980
        'und_Latn_CN' => 'ii_CN',
981
        'und_Latn_CY' => 'tr_CY',
982
        'und_Latn_DZ' => 'fr_DZ',
983
        'und_Latn_ET' => 'om_ET',
984
        'und_Latn_KM' => 'fr_KM',
985
        'und_Latn_MA' => 'fr_MA',
986
        'und_Latn_MK' => 'sq_MK',
987
        'und_Latn_SY' => 'fr_SY',
988
        'und_Latn_TD' => 'fr_TD',
989
        'und_Latn_TN' => 'fr_TN',
990
        'und_MA' => 'ar_MA',
991
        'und_MC' => 'fr_MC',
992
        'und_MD' => 'ro_MD',
993
        'und_ME' => 'sr_ME',
994
        'und_MF' => 'fr_MF',
995
        'und_MG' => 'mg_MG',
996
        'und_MH' => 'mh_MH',
997
        'und_MK' => 'mk_MK',
998
        'und_ML' => 'fr_ML',
999
        'und_MM' => 'my_MM',
1000
        'und_MN' => 'mn_MN',
1001
        'und_MO' => 'zh_MO',
1002
        'und_MQ' => 'fr_MQ',
1003
        'und_MR' => 'ar_MR',
1004
        'und_MT' => 'mt_MT',
1005
        'und_MV' => 'dv_MV',
1006
        'und_MW' => 'ny_MW',
1007
        'und_MX' => 'es_MX',
1008
        'und_MY' => 'ms_MY',
1009
        'und_MZ' => 'pt_MZ',
1010
        'und_Mlym' => 'ml_IN',
1011
        'und_Mong' => 'mn_CN',
1012
        'und_Mymr' => 'my_MM',
1013
        'und_NC' => 'fr_NC',
1014
        'und_NE' => 'ha_NE',
1015
        'und_NG' => 'ha_NG',
1016
        'und_NI' => 'es_NI',
1017
        'und_NL' => 'nl_NL',
1018
        'und_NO' => 'nb_NO',
1019
        'und_NP' => 'ne_NP',
1020
        'und_NR' => 'na_NR',
1021
        'und_NU' => 'niu_NU',
1022
        'und_OM' => 'ar_OM',
1023
        'und_Orya' => 'or_IN',
1024
        'und_PA' => 'es_PA',
1025
        'und_PE' => 'es_PE',
1026
        'und_PF' => 'ty_PF',
1027
        'und_PG' => 'tpi_PG',
1028
        'und_PH' => 'fil_PH',
1029
        'und_PK' => 'ur_PK',
1030
        'und_PL' => 'pl_PL',
1031
        'und_PM' => 'fr_PM',
1032
        'und_PR' => 'es_PR',
1033
        'und_PS' => 'ar_PS',
1034
        'und_PT' => 'pt_PT',
1035
        'und_PW' => 'pau_PW',
1036
        'und_PY' => 'gn_PY',
1037
        'und_QA' => 'ar_QA',
1038
        'und_RE' => 'fr_RE',
1039
        'und_RO' => 'ro_RO',
1040
        'und_RS' => 'sr_RS',
1041
        'und_RU' => 'ru_RU',
1042
        'und_RW' => 'rw_RW',
1043
        'und_SA' => 'ar_SA',
1044
        'und_SD' => 'ar_SD',
1045
        'und_SE' => 'sv_SE',
1046
        'und_SI' => 'sl_SI',
1047
        'und_SJ' => 'nb_SJ',
1048
        'und_SK' => 'sk_SK',
1049
        'und_SM' => 'it_SM',
1050
        'und_SN' => 'fr_SN',
1051
        'und_SO' => 'so_SO',
1052
        'und_SR' => 'nl_SR',
1053
        'und_ST' => 'pt_ST',
1054
        'und_SV' => 'es_SV',
1055
        'und_SY' => 'ar_SY',
1056
        'und_Sinh' => 'si_LK',
1057
        'und_TD' => 'ar_TD',
1058
        'und_TG' => 'ee_TG',
1059
        'und_TH' => 'th_TH',
1060
        'und_TJ' => 'tg_TJ',
1061
        'und_TK' => 'tkl_TK',
1062
        'und_TL' => 'tet_TL',
1063
        'und_TM' => 'tk_TM',
1064
        'und_TN' => 'ar_TN',
1065
        'und_TO' => 'to_TO',
1066
        'und_TR' => 'tr_TR',
1067
        'und_TV' => 'tvl_TV',
1068
        'und_TW' => 'zh_TW',
1069
        'und_Taml' => 'ta_IN',
1070
        'und_Telu' => 'te_IN',
1071
        'und_Thaa' => 'dv_MV',
1072
        'und_Thai' => 'th_TH',
1073
        'und_Tibt' => 'bo_CN',
1074
        'und_UA' => 'uk_UA',
1075
        'und_UY' => 'es_UY',
1076
        'und_UZ' => 'uz_UZ',
1077
        'und_VA' => 'la_VA',
1078
        'und_VE' => 'es_VE',
1079
        'und_VN' => 'vi_VN',
1080
        'und_VU' => 'fr_VU',
1081
        'und_WF' => 'fr_WF',
1082
        'und_WS' => 'sm_WS',
1083
        'und_YE' => 'ar_YE',
1084
        'und_YT' => 'fr_YT',
1085
        'und_ZW' => 'sn_ZW',
1086
        'ur' => 'ur_PK',
1087
        'uz' => 'uz_UZ',
1088
        'uz_AF' => 'uz_AF',
1089
        'uz_Arab' => 'uz_AF',
1090
        've' => 've_ZA',
1091
        'vi' => 'vi_VN',
1092
        'wal' => 'wal_ET',
1093
        'war' => 'war_PH',
1094
        'wo' => 'wo_SN',
1095
        'xh' => 'xh_ZA',
1096
        'yap' => 'yap_FM',
1097
        'yo' => 'yo_NG',
1098
        'za' => 'za_CN',
1099
        'zh' => 'zh_CN',
1100
        'zh_HK' => 'zh_HK',
1101
        'zh_Hani' => 'zh_CN',
1102
        'zh_Hant' => 'zh_TW',
1103
        'zh_MO' => 'zh_MO',
1104
        'zh_TW' => 'zh_TW',
1105
        'zu' => 'zu_ZA',
1106
    );
1107
1108
1109
1110
    /**
1111
     * Standard list of countries
1112
     *
1113
     * @var array
1114
     */
1115
    private static $countries = [
1116
        'ad' => 'Andorra',
1117
        'ae' => 'United Arab Emirates',
1118
        'af' => 'Afghanistan',
1119
        'ag' => 'Antigua and Barbuda',
1120
        'ai' => 'Anguilla',
1121
        'al' => 'Albania',
1122
        'am' => 'Armenia',
1123
        'an' => 'Netherlands Antilles',
1124
        'ao' => 'Angola',
1125
        'aq' => 'Antarctica',
1126
        'ar' => 'Argentina',
1127
        'as' => 'American Samoa',
1128
        'at' => 'Austria',
1129
        'au' => 'Australia',
1130
        'aw' => 'Aruba',
1131
        'ax' => 'Åland Islands',
1132
        'az' => 'Azerbaijan',
1133
        'ba' => 'Bosnia and Herzegovina',
1134
        'bb' => 'Barbados',
1135
        'bd' => 'Bangladesh',
1136
        'be' => 'Belgium',
1137
        'bf' => 'Burkina Faso',
1138
        'bg' => 'Bulgaria',
1139
        'bh' => 'Bahrain',
1140
        'bi' => 'Burundi',
1141
        'bj' => 'Benin',
1142
        'bl' => 'Saint Barthélemy',
1143
        'bm' => 'Bermuda',
1144
        'bn' => 'Brunei',
1145
        'bo' => 'Bolivia',
1146
        'bq' => 'British Antarctic Territory',
1147
        'br' => 'Brazil',
1148
        'bs' => 'Bahamas',
1149
        'bt' => 'Bhutan',
1150
        'bv' => 'Bouvet Island',
1151
        'bw' => 'Botswana',
1152
        'by' => 'Belarus',
1153
        'bz' => 'Belize',
1154
        'ca' => 'Canada',
1155
        'cc' => 'Cocos [Keeling] Islands',
1156
        'cd' => 'Congo - Kinshasa',
1157
        'cf' => 'Central African Republic',
1158
        'cg' => 'Congo - Brazzaville',
1159
        'ch' => 'Switzerland',
1160
        'ci' => 'Côte d’Ivoire',
1161
        'ck' => 'Cook Islands',
1162
        'cl' => 'Chile',
1163
        'cm' => 'Cameroon',
1164
        'cn' => 'China',
1165
        'co' => 'Colombia',
1166
        'cr' => 'Costa Rica',
1167
        'cs' => 'Serbia and Montenegro',
1168
        'ct' => 'Canton and Enderbury Islands',
1169
        'cu' => 'Cuba',
1170
        'cv' => 'Cape Verde',
1171
        'cx' => 'Christmas Island',
1172
        'cy' => 'Cyprus',
1173
        'cz' => 'Czech Republic',
1174
        'de' => 'Germany',
1175
        'dj' => 'Djibouti',
1176
        'dk' => 'Denmark',
1177
        'dm' => 'Dominica',
1178
        'do' => 'Dominican Republic',
1179
        'dz' => 'Algeria',
1180
        'ec' => 'Ecuador',
1181
        'ee' => 'Estonia',
1182
        'eg' => 'Egypt',
1183
        'eh' => 'Western Sahara',
1184
        'er' => 'Eritrea',
1185
        'es' => 'Spain',
1186
        'et' => 'Ethiopia',
1187
        'fi' => 'Finland',
1188
        'fj' => 'Fiji',
1189
        'fk' => 'Falkland Islands',
1190
        'fm' => 'Micronesia',
1191
        'fo' => 'Faroe Islands',
1192
        'fq' => 'French Southern and Antarctic Territories',
1193
        'fr' => 'France',
1194
        'fx' => 'Metropolitan France',
1195
        'ga' => 'Gabon',
1196
        'gb' => 'United Kingdom',
1197
        'gd' => 'Grenada',
1198
        'ge' => 'Georgia',
1199
        'gf' => 'French Guiana',
1200
        'gg' => 'Guernsey',
1201
        'gh' => 'Ghana',
1202
        'gi' => 'Gibraltar',
1203
        'gl' => 'Greenland',
1204
        'gm' => 'Gambia',
1205
        'gn' => 'Guinea',
1206
        'gp' => 'Guadeloupe',
1207
        'gq' => 'Equatorial Guinea',
1208
        'gr' => 'Greece',
1209
        'gs' => 'South Georgia and the South Sandwich Islands',
1210
        'gt' => 'Guatemala',
1211
        'gu' => 'Guam',
1212
        'gw' => 'Guinea-Bissau',
1213
        'gy' => 'Guyana',
1214
        'hk' => 'Hong Kong SAR China',
1215
        'hm' => 'Heard Island and McDonald Islands',
1216
        'hn' => 'Honduras',
1217
        'hr' => 'Croatia',
1218
        'ht' => 'Haiti',
1219
        'hu' => 'Hungary',
1220
        'id' => 'Indonesia',
1221
        'ie' => 'Ireland',
1222
        'il' => 'Israel',
1223
        'im' => 'Isle of Man',
1224
        'in' => 'India',
1225
        'io' => 'British Indian Ocean Territory',
1226
        'iq' => 'Iraq',
1227
        'ir' => 'Iran',
1228
        'is' => 'Iceland',
1229
        'it' => 'Italy',
1230
        'je' => 'Jersey',
1231
        'jm' => 'Jamaica',
1232
        'jo' => 'Jordan',
1233
        'jp' => 'Japan',
1234
        'jt' => 'Johnston Island',
1235
        'ke' => 'Kenya',
1236
        'kg' => 'Kyrgyzstan',
1237
        'kh' => 'Cambodia',
1238
        'ki' => 'Kiribati',
1239
        'km' => 'Comoros',
1240
        'kn' => 'Saint Kitts and Nevis',
1241
        'kp' => 'North Korea',
1242
        'kr' => 'South Korea',
1243
        'kw' => 'Kuwait',
1244
        'ky' => 'Cayman Islands',
1245
        'kz' => 'Kazakhstan',
1246
        'la' => 'Laos',
1247
        'lb' => 'Lebanon',
1248
        'lc' => 'Saint Lucia',
1249
        'li' => 'Liechtenstein',
1250
        'lk' => 'Sri Lanka',
1251
        'lr' => 'Liberia',
1252
        'ls' => 'Lesotho',
1253
        'lt' => 'Lithuania',
1254
        'lu' => 'Luxembourg',
1255
        'lv' => 'Latvia',
1256
        'ly' => 'Libya',
1257
        'ma' => 'Morocco',
1258
        'mc' => 'Monaco',
1259
        'md' => 'Moldova',
1260
        'me' => 'Montenegro',
1261
        'mf' => 'Saint Martin',
1262
        'mg' => 'Madagascar',
1263
        'mh' => 'Marshall Islands',
1264
        'mi' => 'Midway Islands',
1265
        'mk' => 'Macedonia',
1266
        'ml' => 'Mali',
1267
        'mm' => 'Myanmar [Burma]',
1268
        'mn' => 'Mongolia',
1269
        'mo' => 'Macau SAR China',
1270
        'mp' => 'Northern Mariana Islands',
1271
        'mq' => 'Martinique',
1272
        'mr' => 'Mauritania',
1273
        'ms' => 'Montserrat',
1274
        'mt' => 'Malta',
1275
        'mu' => 'Mauritius',
1276
        'mv' => 'Maldives',
1277
        'mw' => 'Malawi',
1278
        'mx' => 'Mexico',
1279
        'my' => 'Malaysia',
1280
        'mz' => 'Mozambique',
1281
        'na' => 'Namibia',
1282
        'nc' => 'New Caledonia',
1283
        'ne' => 'Niger',
1284
        'nf' => 'Norfolk Island',
1285
        'ng' => 'Nigeria',
1286
        'ni' => 'Nicaragua',
1287
        'nl' => 'Netherlands',
1288
        'no' => 'Norway',
1289
        'np' => 'Nepal',
1290
        'nq' => 'Dronning Maud Land',
1291
        'nr' => 'Nauru',
1292
        'nt' => 'Neutral Zone',
1293
        'nu' => 'Niue',
1294
        'nz' => 'New Zealand',
1295
        'om' => 'Oman',
1296
        'pa' => 'Panama',
1297
        'pc' => 'Pacific Islands Trust Territory',
1298
        'pe' => 'Peru',
1299
        'pf' => 'French Polynesia',
1300
        'pg' => 'Papua New Guinea',
1301
        'ph' => 'Philippines',
1302
        'pk' => 'Pakistan',
1303
        'pl' => 'Poland',
1304
        'pm' => 'Saint Pierre and Miquelon',
1305
        'pn' => 'Pitcairn Islands',
1306
        'pr' => 'Puerto Rico',
1307
        'ps' => 'Palestinian Territories',
1308
        'pt' => 'Portugal',
1309
        'pu' => 'U.S. Miscellaneous Pacific Islands',
1310
        'pw' => 'Palau',
1311
        'py' => 'Paraguay',
1312
        'pz' => 'Panama Canal Zone',
1313
        'qa' => 'Qatar',
1314
        'qo' => 'Outlying Oceania',
1315
        'qu' => 'European Union',
1316
        're' => 'Réunion',
1317
        'ro' => 'Romania',
1318
        'rs' => 'Serbia',
1319
        'ru' => 'Russia',
1320
        'rw' => 'Rwanda',
1321
        'sa' => 'Saudi Arabia',
1322
        'sb' => 'Solomon Islands',
1323
        'sc' => 'Seychelles',
1324
        'sd' => 'Sudan',
1325
        'se' => 'Sweden',
1326
        'sg' => 'Singapore',
1327
        'sh' => 'Saint Helena',
1328
        'si' => 'Slovenia',
1329
        'sj' => 'Svalbard and Jan Mayen',
1330
        'sk' => 'Slovakia',
1331
        'sl' => 'Sierra Leone',
1332
        'sm' => 'San Marino',
1333
        'sn' => 'Senegal',
1334
        'so' => 'Somalia',
1335
        'sr' => 'Suriname',
1336
        'st' => 'São Tomé and Príncipe',
1337
        'su' => 'Union of Soviet Socialist Republics',
1338
        'sv' => 'El Salvador',
1339
        'sy' => 'Syria',
1340
        'sz' => 'Swaziland',
1341
        'tc' => 'Turks and Caicos Islands',
1342
        'td' => 'Chad',
1343
        'tf' => 'French Southern Territories',
1344
        'tg' => 'Togo',
1345
        'th' => 'Thailand',
1346
        'tj' => 'Tajikistan',
1347
        'tk' => 'Tokelau',
1348
        'tl' => 'Timor-Leste',
1349
        'tm' => 'Turkmenistan',
1350
        'tn' => 'Tunisia',
1351
        'to' => 'Tonga',
1352
        'tr' => 'Turkey',
1353
        'tt' => 'Trinidad and Tobago',
1354
        'tv' => 'Tuvalu',
1355
        'tw' => 'Taiwan',
1356
        'tz' => 'Tanzania',
1357
        'ua' => 'Ukraine',
1358
        'ug' => 'Uganda',
1359
        'um' => 'U.S. Minor Outlying Islands',
1360
        'us' => 'United States',
1361
        'uy' => 'Uruguay',
1362
        'uz' => 'Uzbekistan',
1363
        'va' => 'Vatican City',
1364
        'vc' => 'Saint Vincent and the Grenadines',
1365
        'vd' => 'North Vietnam',
1366
        've' => 'Venezuela',
1367
        'vg' => 'British Virgin Islands',
1368
        'vi' => 'U.S. Virgin Islands',
1369
        'vn' => 'Vietnam',
1370
        'vu' => 'Vanuatu',
1371
        'wf' => 'Wallis and Futuna',
1372
        'wk' => 'Wake Island',
1373
        'ws' => 'Samoa',
1374
        'yd' => 'People\'s Democratic Republic of Yemen',
1375
        'ye' => 'Yemen',
1376
        'yt' => 'Mayotte',
1377
        'za' => 'South Africa',
1378
        'zm' => 'Zambia',
1379
        'zw' => 'Zimbabwe',
1380
    ];
1381
1382
    /**
1383
     * Returns the script direction in format compatible with the HTML "dir" attribute.
1384
     *
1385
     * @see http://www.w3.org/International/tutorials/bidi-xhtml/
1386
     * @param string $locale Optional locale incl. region (underscored)
1387
     * @return string "rtl" or "ltr"
1388
     */
1389
    public function scriptDirection($locale = null)
1390
    {
1391
        $dirs = static::config()->get('text_direction');
1392
        if (!$locale) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $locale of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1393
            $locale = i18n::get_locale();
1394
        }
1395
        if (isset($dirs[$locale])) {
1396
            return $dirs[$locale];
1397
        }
1398
        $lang = $this->langFromLocale($locale);
1399
        if (isset($dirs[$lang])) {
1400
            return $dirs[$lang];
1401
        }
1402
        return 'ltr';
1403
    }
1404
1405
    /**
1406
     * Provides you "likely locales"
1407
     * for a given "short" language code. This is a guess,
1408
     * as we can't disambiguate from e.g. "en" to "en_US" - it
1409
     * could also mean "en_UK". Based on the Unicode CLDR
1410
     * project.
1411
     * @see http://www.unicode.org/cldr/data/charts/supplemental/likely_subtags.html
1412
     *
1413
     * @param string $lang Short language code, e.g. "en"
1414
     * @return string Long locale, e.g. "en_US"
1415
     */
1416
    public function localeFromLang($lang)
1417
    {
1418
        $lang = Locale::canonicalize($lang);
1419
1420
        // Check subtags
1421
        $subtags = $this->config()->get('likely_subtags');
1422
        if (isset($subtags[$lang])) {
1423
            return $subtags[$lang];
1424
        }
1425
1426
        // Search locales
1427
        $locales = $this->config()->get('locales');
1428
        foreach ($locales as $locale => $name) {
1429
            if (Locale::filterMatches($lang, $locale)) {
1430
                return $locale;
1431
            }
1432
        }
1433
1434
        // Default to lang_LANG
1435
        return strtolower($lang) . '_' . strtoupper($lang);
1436
    }
1437
1438
    /**
1439
     * Returns the "short" language name from a locale,
1440
     * e.g. "en_US" would return "en".
1441
     *
1442
     * @param string $locale E.g. "en_US"
1443
     * @return string Short language code, e.g. "en"
1444
     */
1445
    public function langFromLocale($locale)
1446
    {
1447
        return Locale::getPrimaryLanguage($locale);
1448
    }
1449
1450
    /**
1451
     * Cache of localised locales, keyed by locale localised in
1452
     *
1453
     * @var array
1454
     */
1455
    private static $cache_locales = [];
1456
1457
    /**
1458
     * Get all locale codes and names
1459
     *
1460
     * @return array Map of locale code => name
1461
     */
1462 View Code Duplication
    public function getLocales()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1463
    {
1464
        // Cache by locale
1465
        $locale = i18n::get_locale();
1466
        if (!empty(static::$cache_locales[$locale])) {
0 ignored issues
show
Bug introduced by
Since $cache_locales is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $cache_locales to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
1467
            return static::$cache_locales[$locale];
0 ignored issues
show
Bug introduced by
Since $cache_locales is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $cache_locales to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
1468
        }
1469
1470
        // Localise all locales
1471
        $locales = $this->config()->get('locales');
1472
        $localised = [];
1473
        foreach ($locales as $code => $default) {
1474
            $localised[$code] = $this->localeName($code);
1475
        }
1476
1477
        // Save cache
1478
        static::$cache_locales[$locale] = $localised;
0 ignored issues
show
Bug introduced by
Since $cache_locales is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $cache_locales to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
1479
        return $localised;
1480
    }
1481
1482
    /**
1483
     * Cache of localised languages, keyed by locale localised in
1484
     *
1485
     * @var array
1486
     */
1487
    private static $cache_languages = [];
1488
1489
    /**
1490
     * Get all language codes and names
1491
     *
1492
     * @return array Map of language code => name
1493
     */
1494 View Code Duplication
    public function getLanguages()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1495
    {
1496
        // Cache by locale
1497
        $locale = i18n::get_locale();
1498
        if (!empty(static::$cache_languages[$locale])) {
0 ignored issues
show
Bug introduced by
Since $cache_languages is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $cache_languages to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
1499
            return static::$cache_languages[$locale];
0 ignored issues
show
Bug introduced by
Since $cache_languages is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $cache_languages to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
1500
        }
1501
1502
        // Localise all languages
1503
        $languages = $this->config()->get('languages');
1504
        $localised = [];
1505
        foreach ($languages as $code => $default) {
1506
            $localised[$code] = $this->languageName($code);
1507
        }
1508
1509
        // Save cache
1510
        static::$cache_languages[$locale] = $localised;
0 ignored issues
show
Bug introduced by
Since $cache_languages is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $cache_languages to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
1511
        return $localised;
1512
    }
1513
1514
    /**
1515
     * Get name of locale
1516
     *
1517
     * @param string $locale
1518
     * @return string
1519
     */
1520
    public function localeName($locale)
1521
    {
1522
        return Locale::getDisplayName($locale, i18n::get_locale());
1523
    }
1524
1525
    /**
1526
     * Get language name for this language or locale code
1527
     *
1528
     * @param string $code
1529
     * @return string
1530
     */
1531
    public function languageName($code)
1532
    {
1533
        return Locale::getDisplayLanguage($code, i18n::get_locale());
1534
    }
1535
1536
    /**
1537
     * Cache of localised countries, keyed by locale localised in
1538
     *
1539
     * @var array
1540
     */
1541
    private static $cache_countries = [];
1542
1543
    /**
1544
     * Get all country codes and names
1545
     *
1546
     * @return array Map of country code => name
1547
     */
1548
    public function getCountries()
1549
    {
1550
        // Cache by locale
1551
        $locale = i18n::get_locale();
1552
        if (!empty(static::$cache_countries[$locale])) {
0 ignored issues
show
Bug introduced by
Since $cache_countries is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $cache_countries to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
1553
            return static::$cache_countries[$locale];
0 ignored issues
show
Bug introduced by
Since $cache_countries is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $cache_countries to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
1554
        }
1555
1556
        // Localise all countries
1557
        $countries = $this->config()->get('countries');
1558
        $localised = [];
1559
        foreach ($countries as $code => $default) {
1560
            $localised[$code] = $this->countryName($code);
1561
        }
1562
1563
        // Always sort by localised name, not key
1564
        $collator = new Collator(i18n::get_locale());
1565
        $collator->asort($localised);
1566
        static::$cache_countries[$locale] = $localised;
0 ignored issues
show
Bug introduced by
Since $cache_countries is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $cache_countries to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
1567
        return $localised;
1568
    }
1569
1570
    /**
1571
     * Get name of country
1572
     *
1573
     * @param string $code ISO 3166-1 country code
1574
     * @return string
1575
     */
1576
    public function countryName($code)
1577
    {
1578
        return Locale::getDisplayRegion('-' . $code, i18n::get_locale());
1579
    }
1580
1581
    /**
1582
     * Returns the country code / suffix on any locale
1583
     *
1584
     * @param string $locale E.g. "en_US"
1585
     * @return string Country code, e.g. "us"
1586
     */
1587
    public function countryFromLocale($locale)
1588
    {
1589
        return strtolower(Locale::getRegion($locale)) ?: null;
1590
    }
1591
1592
    /**
1593
     * Validates a "long" locale format (e.g. "en_US") by checking it against {@link $locales}.
1594
     *
1595
     * @param string $locale
1596
     * @return bool
1597
     */
1598
    public function validate($locale)
1599
    {
1600
        if (!$locale) {
1601
            return false;
1602
        }
1603
        $lang = $this->langFromLocale($locale);
1604
        $region = $this->countryFromLocale($locale);
1605
        if (!$lang || !$region) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $region of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1606
            return false;
1607
        }
1608
1609
        // Check the configurable whitelist
1610
        $localeCode = strtolower($lang) . '_' . strtoupper($region);
1611
        $locales = $this->getLocales();
1612
1613
        if (array_key_exists($localeCode, $locales)
1614
            || array_key_exists(strtolower($localeCode), $locales)
1615
        ) {
1616
            return true;
1617
        }
1618
1619
        // Fallback
1620
        return strcasecmp($lang, $region)
1621
            && strcasecmp($lang, $locale)
1622
            && strcasecmp($region, $locale);
1623
    }
1624
1625
    /**
1626
     * Reset the local cache of this object
1627
     */
1628
    public static function reset()
1629
    {
1630
        static::$cache_countries = [];
0 ignored issues
show
Bug introduced by
Since $cache_countries is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $cache_countries to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
1631
        static::$cache_languages = [];
0 ignored issues
show
Bug introduced by
Since $cache_languages is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $cache_languages to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
1632
        static::$cache_locales = [];
0 ignored issues
show
Bug introduced by
Since $cache_locales is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $cache_locales to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
1633
    }
1634
}
1635