1 <?php
2 /**
3 * WP_CLDR class for fetching localization data from Unicode's Common Locale Data Repository
4 *
5 * The wp-cldr plugin is comprised of the WP_CLDR class, a subset of the reference JSON files from Unicode, and unit tests.
6 *
7 * @link https://github.com/Automattic/wp-cldr
8 *
9 * @package wp-cldr
10 */
11
12 /**
13 * Gives WordPress developers easy access to localized country, region, language, currency, and calendar info from the [Unicode Common Locale Data Repository](http://cldr.unicode.org/).
14 *
15 * Examples:
16 *
17 * The default locale is English:
18 *
19 * ```
20 * $cldr = new WP_CLDR();
21 * $territories_in_english = $cldr->get_territories();
22 * ```
23 *
24 * You can override the default locale per-call by passing in a language slug in the second parameter:
25 *
26 * ```
27 * $germany_in_arabic = $cldr->get_territory_name( 'DE' , 'ar_AR' );
28 * ```
29 *
30 * Use a convenience parameter during instantiation to change the default locale:
31 *
32 * ```
33 * $cldr = new WP_CLDR( 'fr' );
34 * $germany_in_french = $cldr->get_territory_name( 'DE' );
35 * $us_dollar_in_french = $cldr->get_currency_name( 'USD' );
36 * $canadian_french_in_french = $cldr->get_language_name( 'fr-ca' );
37 * $canadian_french_in_english = $cldr->get_language_name( 'fr-ca' , 'en' );
38 * $german_in_german = $cldr->get_language_name( 'de_DE' , 'de-DE' );
39 * $bengali_in_japanese = $cldr->get_language_name( 'bn_BD' , 'ja_JP' );
40 * $us_dollar_symbol_in_simplified_chinese = $cldr->get_currency_symbol( 'USD', 'zh' );
41 * $africa_in_french = $cldr->get_territory_name( '002' );
42 * ```
43 *
44 * Switch locales after the object has been created:
45 *
46 * ```
47 * $cldr->set_locale( 'en' );
48 * $us_dollar_in_english = $cldr->get_currency_name( 'USD' );
49 * ```
50 *
51 * Testing:
52 *
53 * The class includes a suite of PHPUnit tests. To run them, call `phpunit` from the plugin directory.
54 *
55 * @link http://cldr.unicode.org
56 * @link https://github.com/unicode-cldr/cldr-json
57 *
58 * @autounit wp-cldr
59 */
60 class WP_CLDR {
61 /**
62 * The current locale.
63 *
64 * @var string
65 */
66 private $locale = 'en';
67
68 /**
69 * The in-memory array of localized values.
70 *
71 * @var array
72 */
73 private $localized = array();
74
75 /**
76 * Whether or not to use caching.
77 *
78 * @var bool
79 */
80 private $use_cache = true;
81
82 /**
83 * The cache group name to use for the WordPress object cache.
84 */
85 const CACHE_GROUP = 'wp-cldr';
86
87 /**
88 * The CLDR version, which the class uses to determine path to JSON files.
89 */
90 const CLDR_VERSION = '29.0.0';
91
92 /**
93 * Constructs a new instance of the class, including setting defaults for locale and caching.
94 *
95 * @param string $locale Optional. A WordPress locale code.
96 * @param bool $use_cache Optional. Whether to use caching (primarily used to suppress caching for unit testing).
97 */
98 public function __construct( $locale = 'en', $use_cache = true ) {
99 $this->use_cache = $use_cache;
100 $this->set_locale( $locale );
101 }
102
103 /**
104 * Sets the locale.
105 *
106 * @param string $locale A WordPress locale code.
107 */
108 public function set_locale( $locale ) {
109 $this->locale = $locale;
110 $this->initialize_locale_bucket( $locale );
111 }
112
113 /**
114 * Gets CLDR code for the equivalent WordPress locale code.
115 *
116 * @param string $wp_locale A WordPress locale code.
117 * @return string The equivalent CLDR locale code.
118 */
119 public static function get_cldr_locale( $wp_locale ) {
120
121 // Some WordPress locales are significantly different from CLDR locales.
122 $wp2cldr = array(
123 'ary' => 'ar-MA',
124 'mya' => 'my',
125 'no' => 'nb',
126 'oci' => 'oc',
127 'tl' => 'fil',
128 'zh-cn' => 'zh-Hans',
129 'zh-hk' => 'zh-Hant',
130 'zh-sg' => 'zh-Hans',
131 'zh-tw' => 'zh-Hant',
132 'zh' => 'zh-Hans',
133 );
134
135 // Convert underscores to dashes and everything to lowercase.
136 $cleaned_up_wp_locale = '';
137 $cleaned_up_wp_locale = str_replace( '_', '-', $wp_locale );
138 $cleaned_up_wp_locale = strtolower( $cleaned_up_wp_locale );
139
140 // Check for an exact match in exceptions array.
141 if ( isset( $wp2cldr[ $cleaned_up_wp_locale ] ) ) {
142 return $wp2cldr[ $cleaned_up_wp_locale ];
143 }
144
145 // Capitalize country code and initial letter of script code to match CLDR JSON file names.
146 $locale_components = explode( '-', $cleaned_up_wp_locale );
147 if ( isset( $locale_components[1] ) && 2 === strlen( $locale_components[1] ) ) {
148 $locale_components[1] = strtoupper( $locale_components[1] );
149 $cleaned_up_wp_locale = implode( '-', $locale_components );
150 return $cleaned_up_wp_locale;
151 }
152 if ( isset( $locale_components[1] ) && 2 < strlen( $locale_components[1] ) ) {
153 $locale_components[1] = ucfirst( $locale_components[1] );
154 $cleaned_up_wp_locale = implode( '-', $locale_components );
155 return $cleaned_up_wp_locale;
156 }
157
158 return $cleaned_up_wp_locale;
159 }
160
161 /**
162 * Gets the absolute path of a CLDR JSON file for a given WordPress locale and CLDR data item.
163 *
164 * @param string $cldr_locale A CLDR locale.
165 * @param string $bucket The CLDR data item.
166 * @return string An array with the CLDR data from the file, or an empty array if no match with any CLDR data files.
167 */
168 public static function get_cldr_json_path( $cldr_locale, $bucket ) {
169
170 $base_path = __DIR__ . '/data/' . WP_CLDR::CLDR_VERSION;
171
172 switch ( $cldr_locale ) {
173 case 'supplemental':
174 $relative_path = 'supplemental';
175 break;
176
177 default:
178 $relative_path = "main/$cldr_locale";
179 break;
180 }
181
182 return "$base_path/$relative_path/$bucket.json";
183 }
184
185 /**
186 * Checks to see if there is an installed CLDR JSON file for a given CLDR locale and data item.
187 *
188 * @param string $cldr_locale The CLDR locale.
189 * @param string $bucket The CLDR data item.
190 * @return bool Whether or not the CLDR JSON file is available.
191 */
192 public static function is_cldr_json_available( $cldr_locale, $bucket ) {
193 $cldr_json_file_path = self::get_cldr_json_path( $cldr_locale, $bucket );
194 return is_readable( $cldr_json_file_path );
195 }
196
197 /**
198 * Loads a CLDR JSON data file.
199 *
200 * @param string $cldr_locale The CLDR locale.
201 * @param string $bucket The CLDR data item.
202 * @return array An array with the CLDR data from the file, or an empty array if no match with any CLDR data files.
203 */
204 public static function get_cldr_json_file( $cldr_locale, $bucket ) {
205 $cldr_json_path = self::get_cldr_json_path( $cldr_locale, $bucket );
206
207 if ( self::is_cldr_json_available( $cldr_locale, $bucket ) ) {
208 $json_raw = file_get_contents( $cldr_json_path );
209 $json_decoded = json_decode( $json_raw, true );
210 return $json_decoded;
211 }
212
213 return array();
214 }
215
216 /**
217 * Uses fallback logic to get the best available CLDR JSON locale for a given WordPress locale.
218 *
219 * @param string $locale A WordPress locale code.
220 * @param string $bucket The CLDR data item.
221 * @return string The best available CLDR JSON locale, or an empty string if no JSON locale is available.
222 */
223 public static function get_best_available_cldr_json_locale( $locale, $bucket ) {
224 $cldr_locale = self::get_cldr_locale( $locale );
225
226 if ( self::is_cldr_json_available( $cldr_locale, $bucket ) ) {
227 return $cldr_locale;
228 }
229
230 // If there's no language-country locale CLDR file, try falling back to a language-only CLDR file.
231 $language_only_cldr_locale = strtok( $cldr_locale, '-_' );
232 if ( self::is_cldr_json_available( $language_only_cldr_locale, $bucket ) ) {
233 return $language_only_cldr_locale;
234 }
235
236 return '';
237 }
238
239 /**
240 * Initializes a "bucket" of CLDR data items for a WordPress locale.
241 *
242 * @param string $locale Optional. The locale.
243 * @param string $bucket Optional. The CLDR data item.
244 * @return bool Whether or not the locale bucket was successfully initialized.
245 */
246 private function initialize_locale_bucket( $locale, $bucket = 'territories' ) {
247
248 $cache_key = "cldr-$locale-$bucket";
249
250 if ( $this->use_cache ) {
251 $cached_data = wp_cache_get( $cache_key, WP_CLDR::CACHE_GROUP );
252 if ( false !== $cached_data ) {
253 $this->localized[ $locale ][ $bucket ] = $cached_data;
254 return true;
255 }
256 }
257
258 $cldr_locale = self::get_best_available_cldr_json_locale( $locale, $bucket );
259
260 if ( empty( $cldr_locale ) ) {
261 return false;
262 }
263
264 $json_file = self::get_cldr_json_file( $cldr_locale, $bucket );
265
266 // Do some performance-enhancing pre-processing of data items, then put into cache
267 // organized by WordPress $locale instead of $cldr_locale (which isn't visible
268 // outside this method).
269 switch ( $bucket ) {
270 case 'territories':
271 case 'languages':
272 $sorted_array = $json_file['main'][ $cldr_locale ]['localeDisplayNames'][ $bucket ];
273 if ( function_exists( 'collator_create' ) ) {
274 // Sort data according to locale collation rules.
275 $coll = collator_create( $cldr_locale );
276 collator_asort( $coll, $sorted_array, Collator::SORT_STRING );
277 } else {
278 asort( $sorted_array );
279 }
280 $this->localized[ $locale ][ $bucket ] = $sorted_array;
281 break;
282
283 case 'currencies':
284 $this->localized[ $locale ][ $bucket ] = $json_file['main'][ $cldr_locale ]['numbers'][ $bucket ];
285 break;
286
287 case 'timeZoneNames':
288 $this->localized[ $locale ][ $bucket ] = $json_file['main'][ $cldr_locale ]['dates'][ $bucket ];
289 break;
290
291 default:
292 $this->localized[ $locale ][ $bucket ] = $json_file;
293 break;
294 }
295
296 if ( $this->use_cache ) {
297 wp_cache_set( $cache_key, $this->localized[ $locale ][ $bucket ], WP_CLDR::CACHE_GROUP );
298 }
299
300 return true;
301 }
302
303 /**
304 * Flushes the WordPress object cache for a single CLDR data item for a single locale.
305 *
306 * @param string $locale A WordPress locale code.
307 * @param string $bucket A CLDR data item.
308 */
309 public function flush_wp_cache_for_locale_bucket( $locale, $bucket ) {
310 $cache_key = "cldr-$locale-$bucket";
311 return wp_cache_delete( $cache_key, WP_CLDR::CACHE_GROUP );
312 }
313
314 /**
315 * Clears the WordPress object cache for all CLDR data items across all locales.
316 */
317 public function flush_all_wp_caches() {
318 $this->localized = array();
319
320 $locales = $this->get_languages();
321 $supported_buckets = array( 'territories', 'currencies', 'languages', 'weekData', 'telephoneCodeData' );
322 foreach ( array_keys( $locales ) as $locale ) {
323 foreach ( $supported_buckets as $bucket ) {
324 $this->flush_wp_cache_for_locale_bucket( $locale, $bucket );
325 }
326 }
327 }
328
329 /**
330 * Returns a bucket of CLDR data for a locale.
331 *
332 * @param string $locale A WordPress locale code.
333 * @param string $bucket A CLDR data item.
334 * @return array An associative array with the contents of the locale bucket.
335 */
336 private function get_locale_bucket( $locale, $bucket ) {
337 if ( empty( $locale ) ) {
338 $locale = $this->locale;
339 }
340
341 // Check the in-memory array.
342 if ( isset( $this->localized[ $locale ][ $bucket ] ) ) {
343 return $this->localized[ $locale ][ $bucket ];
344 }
345
346 // If it's not in memory, initialize the locale bucket which loads the in-memory array.
347 if ( $this->initialize_locale_bucket( $locale, $bucket ) ) {
348 return $this->localized[ $locale ][ $bucket ];
349 }
350
351 // If the locale bucket cannot be initialized, fall back to English.
352 if ( isset( $this->localized['en'][ $bucket ] ) ) {
353 return $this->localized['en'][ $bucket ];
354 }
355 if ( $this->initialize_locale_bucket( 'en', $bucket ) ) {
356 return $this->localized['en'][ $bucket ];
357 }
358
359 // Since everything else failed, return an empty array.
360 return array();
361 }
362
363 /**
364 * Gets a localized country or region name.
365 *
366 * @link http://www.iso.org/iso/country_codes ISO 3166 country codes
367 * @link http://unstats.un.org/unsd/methods/m49/m49regin.htm UN M.49 region codes
368 *
369 * @param string $territory_code An ISO 3166-1 country code, or a UN M.49 region code.
370 * @param string $locale Optional. A WordPress locale code.
371 * @return string The name of the territory in the provided locale.
372 */
373 public function get_territory_name( $territory_code, $locale = '' ) {
374 $territories_array = $this->get_territories( $locale );
375 if ( isset( $territories_array[ $territory_code ] ) ) {
376 return $territories_array[ $territory_code ];
377 }
378 return '';
379 }
380
381 /**
382 * Gets a localized currency symbol.
383 *
384 * @link http://www.iso.org/iso/currency_codes ISO 4217 currency codes
385 *
386 * @param string $currency_code An ISO 4217 currency code.
387 * @param string $locale Optional. A WordPress locale code.
388 * @return string The symbol for the currency in the provided locale.
389 */
390 public function get_currency_symbol( $currency_code, $locale = '' ) {
391 $currencies_array = $this->get_locale_bucket( $locale, 'currencies' );
392 if ( isset( $currencies_array[ $currency_code ]['symbol'] ) ) {
393 return $currencies_array[ $currency_code ]['symbol'];
394 }
395 return '';
396 }
397
398 /**
399 * Gets a localized currency name.
400 *
401 * @link http://www.iso.org/iso/currency_codes ISO 4217 currency codes
402 *
403 * @param string $currency_code An ISO 4217 currency code.
404 * @param string $locale Optional. A WordPress locale code.
405 * @return string The name of the currency in the provided locale.
406 */
407 public function get_currency_name( $currency_code, $locale = '' ) {
408 $currencies_array = $this->get_locale_bucket( $locale, 'currencies' );
409 if ( isset( $currencies_array[ $currency_code ]['displayName'] ) ) {
410 return $currencies_array[ $currency_code ]['displayName'];
411 }
412 return '';
413 }
414
415 /**
416 * Gets a localized language name.
417 *
418 * @link http://www.iso.org/iso/language_codes ISO 639 language codes
419 *
420 * @param string $language_code An ISO 639 language code.
421 * @param string $locale Optional. A WordPress locale code.
422 * @return string The name of the language in the provided locale.
423 */
424 public function get_language_name( $language_code, $locale = '' ) {
425 $languages = $this->get_languages( $locale );
426
427 $cldr_matched_language_code = self::get_cldr_locale( $language_code );
428 if ( isset( $languages[ $cldr_matched_language_code ] ) ) {
429 return $languages[ $cldr_matched_language_code ];
430 }
431
432 // If no match for a full language code (e.g. `en-NZ`), check for language code only (e.g. `en`).
433 $language_only_cldr_code = strtok( $cldr_matched_language_code, '-_' );
434 if ( isset( $languages[ $language_only_cldr_code ] ) ) {
435 return $languages[ $language_only_cldr_code ];
436 }
437
438 return '';
439 }
440
441 /**
442 * Gets all country and region names in a locale.
443 *
444 * @link http://www.iso.org/iso/country_codes ISO 3166 country codes
445 * @link http://unstats.un.org/unsd/methods/m49/m49regin.htm UN M.49 region codes
446 *
447 * @param string $locale Optional. A WordPress locale code.
448 * @return array An associative array of ISO 3166-1 alpha-2 country codes and UN M.49 region codes, along with localized names, from CLDR
449 */
450 public function get_territories( $locale = '' ) {
451 return $this->get_locale_bucket( $locale, 'territories' );
452 }
453
454 /**
455 * Gets all language names in a locale.
456 *
457 * @link http://www.iso.org/iso/language_codes ISO 639 language codes
458 *
459 * @param string $locale Optional. A WordPress locale code.
460 * @return array An associative array of ISO 639 codes and localized language names from CLDR
461 */
462 public function get_languages( $locale = '' ) {
463 return $this->get_locale_bucket( $locale, 'languages' );
464 }
465
466 /**
467 * Gets telephone code for a country.
468 *
469 * @link http://unicode.org/reports/tr35/tr35-info.html#Telephone_Code_Data CLDR Telephone Code Data
470 * @link http://www.iso.org/iso/country_codes ISO 3166 country codes
471 *
472 * @param string $country_code A two-letter ISO 3166 country code.
473 * @return string The telephone code for the provided country.
474 */
475 public function get_telephone_code( $country_code ) {
476 $json_file = $this->get_locale_bucket( 'supplemental', 'telephoneCodeData' );
477 if ( isset( $json_file['supplemental']['telephoneCodeData'][ $country_code ][0]['telephoneCountryCode'] ) ) {
478 return $json_file['supplemental']['telephoneCodeData'][ $country_code ][0]['telephoneCountryCode'];
479 }
480 return '';
481 }
482
483 /**
484 * Gets the day which typically starts a calendar week in a country.
485 *
486 * @link http://unicode.org/reports/tr35/tr35-dates.html#Week_Data CLDR week data
487 * @link http://www.iso.org/iso/country_codes ISO 3166 country codes
488 *
489 * @param string $country_code A two-letter ISO 3166 country code.
490 * @return string The first three characters, in lowercase, of the English name for the day considered to be the start of the week.
491 */
492 public function get_first_day_of_week( $country_code ) {
493 $json_file = $this->get_locale_bucket( 'supplemental', 'weekData' );
494 if ( isset( $json_file['supplemental']['weekData']['firstDay'][ $country_code ] ) ) {
495 return $json_file['supplemental']['weekData']['firstDay'][ $country_code ];
496 }
497 return '';
498 }
499
500 /**
501 * Gets the currency used in each country worldwide.
502 *
503 * @link http://www.iso.org/iso/country_codes ISO 3166 country codes
504 * @link http://www.iso.org/iso/currency_codes ISO 4217 currency codes
505 *
506 * @return array An associative array of ISO 3166 country codes and the ISO 4217 code for the currency currently used in each country.
507 */
508 public function get_currency_for_all_countries() {
509 $json_file = $this->get_locale_bucket( 'supplemental', 'currencyData' );
510
511 // This CLDR item has a history of all the currencies ever used in a country
512 // so we need to loop through them to find one without a `_to` ending date
513 // and without a `_tender` flag which are always false indicating
514 // the currency wasn't legal tender.
515 $result = array();
516 if ( isset( $json_file['supplemental']['currencyData']['region'] ) ) {
517 foreach ( $json_file['supplemental']['currencyData']['region'] as $country_code => $currencies ) {
518 foreach ( $currencies as $currency_dates ) {
519 if ( ! array_key_exists( '_to', current( $currency_dates ) ) && ! array_key_exists( '_tender', current( $currency_dates ) ) ) {
520 $result[ $country_code ] = key( $currency_dates );
521 }
522 }
523 }
524 }
525 return $result;
526 }
527
528 /**
529 * Gets the currency currently used in a country.
530 *
531 * @link http://www.iso.org/iso/country_codes ISO 3166 country codes
532 * @link http://www.iso.org/iso/currency_codes ISO 4217 currency codes
533 *
534 * @param string $country_code A two-letter ISO 3166-1 country code.
535 * @return string The three-letter ISO 4217 code for the currency currently used in that country.
536 */
537 public function get_currency_for_country( $country_code ) {
538 $currency_for_all_countries = $this->get_currency_for_all_countries();
539 if ( isset( $currency_for_all_countries[ $country_code ] ) ) {
540 return $currency_for_all_countries[ $country_code ];
541 }
542 return '';
543 }
544
545 /**
546 * Gets the countries that use each currency in use today.
547 *
548 * @link http://www.iso.org/iso/currency_codes ISO 4217 currency codes
549 * @link http://www.iso.org/iso/country_codes ISO 3166 country codes
550 *
551 * @return array An associative array of ISO 4217 currency codes and then an array of the ISO 3166 codes for countries which currently each currency.
552 */
553 public function get_countries_for_all_currencies() {
554 $result = array();
555 $currency_for_all_countries = $this->get_currency_for_all_countries();
556 if ( isset( $currency_for_all_countries ) ) {
557 foreach ( $currency_for_all_countries as $country_code => $currency_code ) {
558 $result[ $currency_code ][] = $country_code;
559 }
560 }
561 return $result;
562 }
563
564 /**
565 * Gets the countries that use a particular currency.
566 *
567 * @link http://www.iso.org/iso/currency_codes ISO 4217 currency codes
568 * @link http://www.iso.org/iso/country_codes ISO 3166 country codes
569 *
570 * @param string $currency_code A three-letter ISO 4217 currency code.
571 * @return array The ISO 3166 codes for the countries which currently the currency.
572 */
573 public function get_countries_for_currency( $currency_code ) {
574 $countries_for_all_currencies = $this->get_countries_for_all_currencies();
575 if ( isset( $countries_for_all_currencies[ $currency_code ] ) ) {
576 return $countries_for_all_currencies[ $currency_code ];
577 }
578 return array();
579 }
580
581 /**
582 * Gets the countries contained by a region code.
583 *
584 * @link http://www.unicode.org/cldr/charts/latest/supplemental/territory_containment_un_m_49.html CLDR info page on territory containment
585 * @link http://www.iso.org/iso/country_codes ISO 3166 country codes
586 * @link http://unstats.un.org/unsd/methods/m49/m49regin.htm UN M.49 region codes
587 *
588 * @param string $region_code A UN M.49 region code or a two-letter ISO 3166-1 country code.
589 * @return array The countries included in that region, or the country if $region_code is a country.
590 */
591 public function get_territories_contained( $region_code ) {
592
593 // If $region_code is a country code, return it.
594 if ( preg_match( '/^[A-Z]{2}$/', $region_code ) ) {
595 return array( $region_code );
596 }
597
598 // If it's a region code, recursively find the contained country codes.
599 $result = array();
600 if ( preg_match( '/^\d{3}$/', $region_code ) ) {
601 $json_file = $this->get_locale_bucket( 'supplemental', 'territoryContainment' );
602 if ( isset( $json_file['supplemental']['territoryContainment'][ $region_code ]['_contains'] ) ) {
603 foreach ( $json_file['supplemental']['territoryContainment'][ $region_code ]['_contains'] as $contained_region ) {
604 $result = array_merge( $result, $this->get_territories_contained( $contained_region ) );
605 }
606 }
607 }
608
609 return $result;
610 }
611
612 /**
613 * Gets the languages spoken in a country, in descending order of use.
614 *
615 * @link http://www.iso.org/iso/country_codes ISO 3166 country codes
616 * @link http://www.unicode.org/cldr/charts/latest/supplemental/territory_language_information.html Detail on CLDR language information
617 *
618 * @param string $country_code A two-letter ISO 3166-1 country code.
619 * @return array An associative array with the key of a language code and the value of the percentage of population which speaks the language in that country.
620 */
621 public function get_languages_spoken( $country_code ) {
622 $json_file = $this->get_locale_bucket( 'supplemental', 'territoryInfo' );
623 $result = array();
624 if ( isset( $json_file['supplemental']['territoryInfo'][ $country_code ]['languagePopulation'] ) ) {
625 foreach ( $json_file['supplemental']['territoryInfo'][ $country_code ]['languagePopulation'] as $language => $info ) {
626 $result[ $language ] = $info['_populationPercent'];
627 }
628 arsort( $result );
629 }
630 return $result;
631 }
632
633 /**
634 * Gets the most widely spoken language spoken in a country.
635 *
636 * @link http://www.iso.org/iso/country_codes ISO 3166 country codes
637 * @link http://www.unicode.org/cldr/charts/latest/supplemental/territory_language_information.html Detail on CLDR language information
638 * @link http://www.iso.org/iso/language_codes ISO 639 language codes
639 *
640 * @param string $country_code A two-letter ISO 3166-1 country code.
641 * @return string The ISO 639 code for the language most widely spoken in the country.
642 */
643 public function get_most_spoken_language( $country_code ) {
644 $languages_spoken = $this->get_languages_spoken( $country_code );
645 if ( ! empty( $languages_spoken ) ) {
646 return key( $languages_spoken );
647 }
648 return '';
649 }
650
651 /**
652 * Gets GDP, population, and language information for a country.
653 *
654 * @link http://www.iso.org/iso/country_codes ISO 3166 country codes
655 * @link http://www.unicode.org/cldr/charts/latest/supplemental/territory_language_information.html CLDR's territory information
656 *
657 * @param string $country_code Optional. A two-letter ISO 3166-1 country code.
658 * @return array CLDR's territory information.
659 */
660 public function get_territory_info( $country_code ) {
661 $json_file = $this->get_locale_bucket( 'supplemental', 'territoryInfo' );
662 if ( isset( $json_file['supplemental']['territoryInfo'][ $country_code ] ) ) {
663 return $json_file['supplemental']['territoryInfo'][ $country_code ];
664 }
665 return array();
666 }
667
668 /**
669 * Recursively builds an associative array of the time zone IDs and their localized display names.
670 *
671 * @link http://www.iana.org/time-zones IANA time zone
672 * @link http://unicode.org/reports/tr35/tr35-dates.html#Time_Zone_Names CLDR info on time zone names
673 *
674 * @param string $zones An array of time zone data from CLDR JSON files.
675 * @param string $id_start Optional. The start of the time zone ID (used for recursive calls).
676 * @return array An associative array of time zone IDs (e.g. `Europe/Istanbul`) and the localized exemplar city names.
677 */
678 private function build_cities_array( $zones, $id_start = '' ) {
679 $result = array();
680 foreach ( $zones as $id => $array ) {
681 if ( isset( $array['exemplarCity'] ) ) {
682 $result[ $id_start . $id ] = $array['exemplarCity'];
683 } elseif ( is_array( $array ) ) {
684 $result = array_merge( $result, $this->build_cities_array( $array, $id_start . $id . '/' ) );
685 }
686 }
687 return $result;
688 }
689
690 /**
691 * Gets the time zone city names -- aka exemplars -- for a locale.
692 *
693 * @link http://www.iana.org/time-zones IANA time zone
694 * @link http://unicode.org/reports/tr35/tr35-dates.html#Time_Zone_Names CLDR info on time zone names
695 *
696 * @param string $locale Optional. A WordPress locale code.
697 * @return array As associative array of time zone IDs (e.g. `Europe/Istanbul`) and the localized exemplar city for each.
698 */
699 public function get_time_zone_cities( $locale = '' ) {
700 $time_zone_cities_json = $this->get_locale_bucket( $locale, 'timeZoneNames' );
701 if ( ! empty( $time_zone_cities_json['zone'] ) ) {
702 return $this->build_cities_array( $time_zone_cities_json['zone'] );
703 }
704 return array();
705 }
706
707 /**
708 * Gets the time zone city name -- aka exemplar -- for a time zone ID.
709 *
710 * @link http://www.iana.org/time-zones IANA time zone
711 * @link http://unicode.org/reports/tr35/tr35-dates.html#Time_Zone_Names CLDR info on time zone names
712 *
713 * @param string $time_zone_id An IANA time zone ID (e.g. `Europe/Istanbul`).
714 * @param string $locale Optional. A WordPress locale code.
715 * @return string The localized name of the time zone exemplar city.
716 */
717 public function get_time_zone_city( $time_zone_id, $locale = '' ) {
718 $time_zone_cities = $this->get_time_zone_cities( $locale );
719 if ( ! empty( $time_zone_cities[ $time_zone_id ] ) ) {
720 return $time_zone_cities[ $time_zone_id ];
721 }
722 return '';
723 }
724 }
725