204 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			PHP
		
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			PHP
		
	
	
| <?php
 | |
| 
 | |
| /**
 | |
|  * Generates the json files stored in resources/currency.
 | |
|  *
 | |
|  * The ISO currency list is used as a base, since it doesn't contain
 | |
|  * deprecated currencies, unlike CLDR (v25 has 139 deprecated entries).
 | |
|  */
 | |
| 
 | |
| require __DIR__ . '/generate_base.php';
 | |
| 
 | |
| $currencyData = json_decode(file_get_contents($currencyData), true);
 | |
| $isoData = simplexml_load_file($isoCurrencies);
 | |
| 
 | |
| $baseData = generate_base_data($currencyData, $isoData);
 | |
| $localizations = generate_localizations($baseData);
 | |
| $localizations = filter_duplicate_localizations($localizations);
 | |
| 
 | |
| // Make sure we're starting from a clean slate.
 | |
| if (is_dir(__DIR__ . '/currency')) {
 | |
|     die('The currency/ directory must not exist.');
 | |
| }
 | |
| 
 | |
| // Prepare the filesystem.
 | |
| mkdir(__DIR__ . '/currency');
 | |
| 
 | |
| // Write out the localizations.
 | |
| foreach ($localizations as $locale => $localizedCurrencies) {
 | |
|     $collator = collator_create($locale);
 | |
|     uasort($localizedCurrencies, function ($a, $b) use ($collator) {
 | |
|         return collator_compare($collator, $a['name'], $b['name']);
 | |
|     });
 | |
|     file_put_json(__DIR__ . '/currency/' . $locale . '.json', $localizedCurrencies);
 | |
| }
 | |
| 
 | |
| $availableLocales = array_keys($localizations);
 | |
| sort($availableLocales);
 | |
| // Base currency definitions and available locales are stored
 | |
| // in PHP, then manually transferred to CurrencyRepository.
 | |
| $data = "<?php\n\n";
 | |
| $data .= export_locales($availableLocales);
 | |
| $data .= export_base_data($baseData);
 | |
| file_put_contents(__DIR__ . '/currency_data.php', $data);
 | |
| 
 | |
| echo "Done.\n";
 | |
| 
 | |
| /**
 | |
|  * Exports base data.
 | |
|  */
 | |
| function export_base_data($baseData)
 | |
| {
 | |
|     $export = '$baseData = [' . "\n";
 | |
|     foreach ($baseData as $currencyCode => $currencyData) {
 | |
|         $export .= "    '" . $currencyCode . "' => ['";
 | |
|         $export .= $currencyData['numeric_code'] . "', " . $currencyData['fraction_digits'];
 | |
|         $export .= "],\n";
 | |
|     }
 | |
|     $export .= "];";
 | |
| 
 | |
|     return $export;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Exports locales.
 | |
|  */
 | |
| function export_locales($data)
 | |
| {
 | |
|     // Wrap the values in single quotes.
 | |
|     $data = array_map(function ($value) {
 | |
|         return "'" . $value . "'";
 | |
|     }, $data);
 | |
| 
 | |
|     $export = '// ' . count($data) . " available locales. \n";
 | |
|     $export .= '$locales = [' . "\n";
 | |
|     $export .= '    ' . implode(', ', $data) . "\n";
 | |
|     $export .= "];\n\n";
 | |
| 
 | |
|     return $export;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Generates the base data.
 | |
|  */
 | |
| function generate_base_data(array $currencyData, $isoData)
 | |
| {
 | |
|     $baseData = [];
 | |
|     $currencyData = $currencyData['supplemental']['currencyData']['fractions'];
 | |
|     foreach ($isoData->CcyTbl->CcyNtry as $currency) {
 | |
|         $attributes = (array) $currency->CcyNm->attributes();
 | |
|         if (!empty($attributes) && !empty($attributes['@attributes']['IsFund'])) {
 | |
|             // Ignore funds.
 | |
|             continue;
 | |
|         }
 | |
|         $currency = (array) $currency;
 | |
|         if (empty($currency['Ccy'])) {
 | |
|             // Ignore placeholders like "Antarctica".
 | |
|             continue;
 | |
|         }
 | |
|         if (substr($currency['CtryNm'], 0, 2) == 'ZZ' || in_array($currency['Ccy'], ['XUA', 'XSU', 'XDR'])) {
 | |
|             // Ignore special currencies.
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         $currencyCode = $currency['Ccy'];
 | |
|         $baseData[$currencyCode] = [
 | |
|             'numeric_code' => $currency['CcyNbr'],
 | |
|         ];
 | |
|         // Take the fraction digits from CLDR, not ISO, because it reflects real
 | |
|         // life usage more closely.
 | |
|         if (isset($currencyData[$currencyCode]['_digits'])) {
 | |
|             $baseData[$currencyCode]['fraction_digits'] = $currencyData[$currencyCode]['_digits'];
 | |
|         } else {
 | |
|             $baseData[$currencyCode]['fraction_digits'] = $currencyData['DEFAULT']['_digits'];
 | |
|         }
 | |
|     }
 | |
|     ksort($baseData);
 | |
| 
 | |
|     return $baseData;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Generates the localizations.
 | |
|  */
 | |
| function generate_localizations(array $baseData)
 | |
| {
 | |
|     global $numbersDirectory;
 | |
| 
 | |
|     $locales = discover_locales();
 | |
|     // Make sure 'en' is processed first so that it can be used as a fallback.
 | |
|     $index = array_search('en', $locales);
 | |
|     unset($locales[$index]);
 | |
|     array_unshift($locales, 'en');
 | |
| 
 | |
|     $localizations = [];
 | |
|     $untranslatedCounts = [];
 | |
|     foreach ($locales as $locale) {
 | |
|         $data = json_decode(file_get_contents($numbersDirectory . $locale . '/currencies.json'), true);
 | |
|         $data = $data['main'][$locale]['numbers']['currencies'];
 | |
|         foreach ($data as $currencyCode => $currency) {
 | |
|             if (isset($baseData[$currencyCode])) {
 | |
|                 $currencyName = $currency['displayName'] ?? $currencyCode;
 | |
|                 // This currency name is untranslated, use the english version.
 | |
|                 if ($currencyCode == $currencyName) {
 | |
|                     $currencyName = $localizations['en'][$currencyCode]['name'];
 | |
|                     // Maintain a count of untranslated currencies per locale.
 | |
|                     $untranslatedCounts += [$locale => 0];
 | |
|                     $untranslatedCounts[$locale]++;
 | |
|                 }
 | |
| 
 | |
|                 $localizations[$locale][$currencyCode] = [
 | |
|                     'name' => $currencyName,
 | |
|                 ];
 | |
|                 // Decrease the dataset size by exporting the symbol only if it's
 | |
|                 // different from the currency code.
 | |
|                 if (isset($currency['symbol']) && $currency['symbol'] != $currencyCode) {
 | |
|                     $localizations[$locale][$currencyCode]['symbol'] = $currency['symbol'];
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Ignore locales that are more than 80% untranslated.
 | |
|     foreach ($untranslatedCounts as $locale => $count) {
 | |
|         $totalCount = count($localizations[$locale]);
 | |
|         $untranslatedPercentage = $count * (100 / $totalCount);
 | |
|         if ($untranslatedPercentage >= 80) {
 | |
|             unset($localizations[$locale]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return $localizations;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Filters out duplicate localizations (same as their parent locale).
 | |
|  *
 | |
|  * For example, "fr-FR" will be removed if "fr" has the same data.
 | |
|  */
 | |
| function filter_duplicate_localizations(array $localizations)
 | |
| {
 | |
|     $duplicates = [];
 | |
|     foreach ($localizations as $locale => $localizedCurrencies) {
 | |
|         if ($parentLocale = \CommerceGuys\Intl\Locale::getParent($locale)) {
 | |
|             $parentCurrencies = isset($localizations[$parentLocale]) ? $localizations[$parentLocale] : [];
 | |
|             $diff = array_udiff($localizedCurrencies, $parentCurrencies, function ($first, $second) {
 | |
|                 return ($first['name'] == $second['name']) ? 0 : 1;
 | |
|             });
 | |
| 
 | |
|             if (empty($diff)) {
 | |
|                 // The duplicates are not removed right away because they might
 | |
|                 // still be needed for other duplicate checks (for example,
 | |
|                 // when there are locales like bs-Latn-BA, bs-Latn, bs).
 | |
|                 $duplicates[] = $locale;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     foreach ($duplicates as $locale) {
 | |
|         unset($localizations[$locale]);
 | |
|     }
 | |
| 
 | |
|     return $localizations;
 | |
| }
 |