Completed
Push — master ( 8dd3f4...12fc69 )
by Damian
12:56 queued 05:06
created

IntlLocales::validate()   C

Complexity

Conditions 8
Paths 6

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 15
nc 6
nop 1
dl 0
loc 26
rs 5.3846
c 0
b 0
f 0
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
    public function getLocales()
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
    public function getLanguages()
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