PHP Classes

File: bin/build.php

Recommend this page to a friend!
  Classes of Michele Locati   Punic   bin/build.php   Download  
File: bin/build.php
Role: Application script
Content type: text/plain
Description: Configuration script
Class: Punic
Localize numbers, dates, units using Unicode CLDR
Author: By
Last change: Fix URL of full JSON data for newer CLDR versions
Effectively remove ZZ country from territoryInfo
Add minority_official support for languages
Ckeck languages
Remove "Unknown territory" from territoryInfo, let's be sure we have all the data of territoryInfo
PSR-2
Add territoryInfo.json to Punic data files
Date: 9 years ago
Size: 48,055 bytes
 

Contents

Class file image Download
<?php function handleError($errno, $errstr, $errfile, $errline) { if ($errno == E_NOTICE || $errno == E_WARNING) { throw new Exception("$errstr in $errfile @ line $errline", $errno); } } set_error_handler('handleError'); try { echo "Initializing... "; define('CLDR_VERSION', 26); define('ROOT_DIR', dirname(__DIR__)); define('SOURCE_DIR', ROOT_DIR . DIRECTORY_SEPARATOR . 'temp' . DIRECTORY_SEPARATOR . 'source-data'); define('DESTINATION_DIR', ROOT_DIR . DIRECTORY_SEPARATOR . 'code' . DIRECTORY_SEPARATOR . 'data'); define('TESTS_DIR', ROOT_DIR . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'dataFiles'); if (isset($argv)) { foreach ($argv as $i => $arg) { if ($i > 0) { if ((strcasecmp($arg, 'debug') === 0) || (strcasecmp($arg, '--debug') === 0)) { defined('DEBUG') or define('DEBUG', true); } if ((strcasecmp($arg, 'full') === 0) || (strcasecmp($arg, '--full') === 0)) { defined('FULL_JSON') or define('FULL_JSON', true); } if ((strcasecmp($arg, 'post-clean') === 0) || (strcasecmp($arg, '--post-clean') === 0)) { defined('POST_CLEAN') or define('POST_CLEAN', true); } } } } defined('DEBUG') or define('DEBUG', false); defined('FULL_JSON') or define('FULL_JSON', false); define('LOCAL_ZIP_FILE', SOURCE_DIR . DIRECTORY_SEPARATOR . (FULL_JSON ? 'cldr_full' : 'cldr') . '-' . CLDR_VERSION . '.zip'); define('SOURCE_DIR_DATA', SOURCE_DIR . DIRECTORY_SEPARATOR . (FULL_JSON ? 'cldr_full' : 'cldr') . '-' . CLDR_VERSION); defined('POST_CLEAN') or define('POST_CLEAN', false); if (!is_dir(SOURCE_DIR)) { if (mkdir(SOURCE_DIR, 0777, true) === false) { echo "Failed to create " . SOURCE_DIR . "\n"; die(1); } } echo "done.\n"; if (is_dir(DESTINATION_DIR)) { echo "Cleanup old data folder... "; deleteFromFilesystem(DESTINATION_DIR); echo "done.\n"; } echo "Creating data folder... "; if (mkdir(DESTINATION_DIR, 0777, false) === false) { echo "Failed to create " . DESTINATION_DIR . "\n"; die(1); } echo "done.\n"; if (!is_dir(TESTS_DIR)) { echo "Creating tests folder... "; if (mkdir(TESTS_DIR, 0777, false) === false) { echo "Failed to create " . TESTS_DIR . "\n"; die(1); } echo "done.\n"; } if (!is_dir(SOURCE_DIR_DATA)) { if (!is_file(LOCAL_ZIP_FILE)) { downloadCLDR(); } ExtractCLDR(); } copyData(); if (POST_CLEAN) { echo "Cleanup temporary data folder... "; deleteFromFilesystem(SOURCE_DIR_DATA); echo "done.\n"; } die(0); } catch (Exception $x) { echo $x->getMessage(), "\n"; die(1); } function downloadCLDR() { if(version_compare(CLDR_VERSION, 26) >= 0) { $remoteURL = 'http://unicode.org/Public/cldr/' . CLDR_VERSION . '/' . (FULL_JSON ? 'json-full.zip' : 'json.zip'); } else { $remoteURL = 'http://unicode.org/Public/cldr/' . CLDR_VERSION . '/' . (FULL_JSON ? 'json_full.zip' : 'json.zip'); } $zipFrom = null; $zipTo = null; echo "Downloading $remoteURL... "; try { $zipFrom = fopen($remoteURL, 'rb'); if ($zipFrom === false) { throw new Exception("Failed to read $remoteURL"); } $zipTo = fopen(LOCAL_ZIP_FILE, 'wb'); if ($zipTo === false) { throw new Exception("Failed to create " . LOCAL_ZIP_FILE); } while (!feof($zipFrom)) { $buffer = fread($zipFrom, 4096); if ($buffer === false) { throw new Exception("Failed to fetch data from $remoteURL"); } if (fwrite($zipTo, $buffer) === false) { throw new Exception("Failed to write data to " . LOCAL_ZIP_FILE); } } fclose($zipTo); $zipTo = null; fclose($zipFrom); $zipFrom = null; echo "done.\n"; } catch (Exception $x) { if ($zipTo) { fclose($zipTo); $zipTo = null; } if ($zipFrom) { fclose($zipFrom); $zipFrom = null; } if (is_file(LOCAL_ZIP_FILE)) { unlink(LOCAL_ZIP_FILE); } throw $x; } } function extractCLDR() { $zip = null; echo "Extracting " . LOCAL_ZIP_FILE . "... "; try { $zip = new ZipArchive(); $rc = $zip->open(LOCAL_ZIP_FILE); if ($rc !== true) { throw new Exception("Opening " . LOCAL_ZIP_FILE . " failed with return code $rc"); } $zip->extractTo(SOURCE_DIR_DATA); $zip->close(); $zip = null; echo "done.\n"; } catch (Exception $x) { if ($zip) { @$zip->close(); $zip = null; } if (is_dir(SOURCE_DIR_DATA)) { try { deleteFromFilesystem(SOURCE_DIR_DATA); } catch (Exception $foo) { } } throw $x; } } function copyData() { $copy = array( 'ca-gregorian.json' => array('kind' => 'main', 'save-as' => 'calendar.json', 'roots' => array('dates', 'calendars', 'gregorian')), 'timeZoneNames.json' => array('kind' => 'main', 'roots' => array('dates', 'timeZoneNames')), 'listPatterns.json' => array('kind' => 'main', 'roots' => array('listPatterns')), 'units.json' => array('kind' => 'main', 'roots' => array('units')), 'dateFields.json' => array('kind' => 'main', 'roots' => array('dates', 'fields')), 'languages.json' => array('kind' => 'main', 'roots' => array('localeDisplayNames', 'languages')), 'territories.json' => array('kind' => 'main', 'roots' => array('localeDisplayNames', 'territories')), 'localeDisplayNames.json' => array('kind' => 'main', 'roots' => array('localeDisplayNames')), 'numbers.json' => array('kind' => 'main', 'roots' => array('numbers')), /* 'characters.json' => array('kind' => 'main', 'roots' => array('characters')), 'contextTransforms.json' => array('kind' => 'main', 'roots' => array('contextTransforms')), 'currencies.json' => array('kind' => 'main', 'roots' => array('numbers', 'currencies')), 'delimiters.json' => array('kind' => 'main', 'roots' => array('delimiters')), 'layout.json' => array('kind' => 'main', 'roots' => array('layout', 'orientation')), 'measurementSystemNames.json' => array('kind' => 'main', 'roots' => array('localeDisplayNames', 'measurementSystemNames')), 'scripts.json' => array('kind' => 'main', 'roots' => array('localeDisplayNames', 'scripts')), 'transformNames.json' => array('kind' => 'main', 'roots' => array('localeDisplayNames', 'transformNames')), 'variants.json' => array('kind' => 'main', 'roots' => array('localeDisplayNames', 'variants')), */ 'territoryInfo.json' => array('kind' => 'supplemental', 'roots' => array('supplemental', 'territoryInfo')), 'weekData.json' => array('kind' => 'supplemental', 'roots' => array('supplemental', 'weekData')), 'parentLocales.json' => array('kind' => 'supplemental', 'roots' => array('supplemental', 'parentLocales', 'parentLocale')), 'likelySubtags.json' => array('kind' => 'supplemental', 'roots' => array('supplemental', 'likelySubtags')), 'territoryContainment.json' => array('kind' => 'supplemental', 'roots' => array('supplemental', 'territoryContainment')), 'metaZones.json' => array('kind' => 'supplemental', 'roots' => array('supplemental', 'metaZones')), 'plurals.json' => array('kind' => 'supplemental', 'roots' => array('supplemental', 'plurals-type-cardinal')), ); $src = SOURCE_DIR_DATA . DIRECTORY_SEPARATOR . 'main'; $locales = scandir($src); if ($locales === false) { throw new Exception("Failed to retrieve the file list of $src"); } $locales = array_diff($locales, array('.', '..')); foreach ($locales as $locale) { if (is_dir($src . DIRECTORY_SEPARATOR . $locale)) { echo "Parsing locale $locale... "; $destFolder = DESTINATION_DIR . DIRECTORY_SEPARATOR . $locale; if (is_dir($destFolder)) { deleteFromFilesystem($destFolder); } if (mkdir($destFolder) === false) { throw new Exception("Failed to create $destFolder\n"); } foreach ($copy as $copyFrom => $info) { if ($info['kind'] === 'main') { $copyTo = array_key_exists('save-as', $info) ? $info['save-as'] : $copyFrom; if ($copyTo === false) { $copyTo = $copyFrom; } $dstFile = $destFolder . DIRECTORY_SEPARATOR . $copyTo; $useLocale = $locale; $srcFile = $src . DIRECTORY_SEPARATOR . $useLocale . DIRECTORY_SEPARATOR . $copyFrom; if (!is_file($srcFile)) { $useLocale = 'en'; $srcFile = $src . DIRECTORY_SEPARATOR . $useLocale . DIRECTORY_SEPARATOR . $copyFrom; if (!is_file($srcFile)) { throw new Exception("File not found: $srcFile"); } } $info['roots'] = array_merge(array('main', $useLocale), $info['roots']); $info['unsetByPath'] = array_merge( isset($info['unsetByPath']) ? $info['unsetByPath'] : array(), array( "/main/$useLocale" => array('identity'), ) ); copyDataFile($srcFile, $info, $dstFile); } } echo "done.\n"; } } echo "Parsing supplemental files... "; $src = SOURCE_DIR_DATA . DIRECTORY_SEPARATOR . 'supplemental'; foreach ($copy as $copyFrom => $info) { if ($info['kind'] === 'supplemental') { $copyTo = array_key_exists('save-as', $info) ? $info['save-as'] : $copyFrom; $dstFile = DESTINATION_DIR . DIRECTORY_SEPARATOR . $copyTo; $srcFile = $src . DIRECTORY_SEPARATOR . $copyFrom; if (!is_file($srcFile)) { throw new Exception("File not found: $srcFile"); } $info['unsetByPath'] = array_merge( isset($info['unsetByPath']) ? $info['unsetByPath'] : array(), array( '/supplemental' => array('version', 'generation'), ) ); copyDataFile($srcFile, $info, $dstFile); } } echo "done.\n"; } function copyDataFile($srcFile, $info, $dstFile) { $json = file_get_contents($srcFile); if ($json === false) { throw new Exception("Failed to read from $srcFile"); } $data = json_decode($json, true); if (is_null($data)) { throw new Exception("Failed to decode data in $srcFile"); } $path = ''; foreach ($info['roots'] as $root) { if (!is_array($data)) { throw new Exception("Decoded data should be an array in $srcFile (path: $path)"); } if (isset($info['unsetByPath'][$path])) { foreach ($info['unsetByPath'][$path] as $node) { if (array_key_exists($node, $data)) { unset($data[$node]); } } } checkOneKey($data, $root); $data = $data[$root]; $path .= "/$root"; } if (!is_array($data)) { throw new Exception("Decoded data should be an array in $srcFile (path: $path)"); } $jsonFlags = 0; if (version_compare(PHP_VERSION, '5.4.0') >= 0) { $jsonFlags |= JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; if (DEBUG) { $jsonFlags |= JSON_PRETTY_PRINT; } } switch (basename($dstFile)) { case 'calendar.json': unset($data['dateTimeFormats']['availableFormats']); unset($data['dateTimeFormats']['appendItems']); unset($data['dateTimeFormats']['intervalFormats']); foreach (array_keys($data['dateTimeFormats']) as $key) { $data['dateTimeFormats'][$key] = toPhpSprintf($data['dateTimeFormats'][$key]); } foreach (array('eraNames' => 'wide', 'eraAbbr' => 'abbreviated', 'eraNarrow' => 'narrow') as $keyFrom => $keyTo) { if (array_key_exists($keyFrom, $data['eras'])) { $data['eras'][$keyTo] = $data['eras'][$keyFrom]; unset($data['eras'][$keyFrom]); } } break; case 'territoryInfo.json': // http://www.unicode.org/reports/tr35/tr35-info.html#Supplemental_Territory_Information unset($data['ZZ']); foreach ($data as $k => $v) { $D = array(); foreach ($v as $k2 => $v2) { switch ($k2) { case '_gdp': // Gross domestic product if (!is_int($v2)) { $v3 = @intval($v2); if (strval($v3) !== $v2) { $v3 = @floatval($v2); } if (strval($v3) !== $v2) { throw new Exception("Unable to parse $v2 as an integer ($k2)"); } $v2 = $v3; } $D['gdp'] = $v2; break; case '_literacyPercent': if (!(is_int($v2) || is_float($v2))) { $v3 = @floatval($v2); if (strval($v3) !== $v2) { $v3 = @floatval($v2); } if (strval($v3) !== $v2) { throw new Exception("Unable to parse $v2 as an integer ($k2)"); } $v2 = $v3; } $D['literacy'] = $v2; break; case '_population': if (!is_int($v2)) { $v3 = @intval($v2); if (strval($v3) !== $v2) { $v3 = @floatval($v2); } if (strval($v3) !== $v2) { throw new Exception("Unable to parse $v2 as an integer ($k2)"); } $v2 = $v3; } $D['population'] = $v2; break; case 'languagePopulation': if (!is_array($v2)) { throw new Exception("Invalid node: $k2 is not an array"); } $D['languages'] = array(); foreach ($v2 as $k3 => $v3) { if (!is_array($v3)) { throw new Exception("Invalid node: $k2/$k3 is not an array"); } $D['languages'][$k3] = array(); foreach ($v3 as $k4 => $v4) { switch ($k4) { case '_officialStatus': switch ($v4) { case 'official': $v5 = 'o'; break; case 'official_regional': $v5 = 'r'; break; case 'de_facto_official': $v5 = 'f'; break; case 'official_minority': $v5 = 'm'; break; default: throw new Exception("Unknown language status: $v4"); } $D['languages'][$k3]['status'] = $v5; break; case '_populationPercent': if (!(is_int($v4) || is_float($v4))) { $v5 = @floatval($v4); if (strval($v5) !== $v4) { $v5 = @floatval($v4); } if (strval($v5) !== $v4) { throw new Exception("Unable to parse $v4 as an integer ($k2)"); } $v4 = $v5; } $D['languages'][$k3]['population'] = $v4; break; case '_writingPercent': if (!(is_int($v4) || is_float($v4))) { $v5 = @floatval($v4); if (strval($v5) !== $v4) { $v5 = @floatval($v4); } if (strval($v5) !== $v4) { throw new Exception("Unable to parse $v4 as an integer ($k2)"); } $v4 = $v5; } $D['languages'][$k3]['writing'] = $v4; break; default: throw new Exception("Unknown node: $k2/$k3/$k4"); } } if (!array_key_exists('population', $D['languages'][$k3])) { throw new Exception("Missing _populationPercent node in for $k/$k2/$k3"); } } if (empty($D['languages'])) { throw new Exception("No languages for $k"); } break; default: throw new Exception("Unknown node: $k2"); die($k2); } } if (!array_key_exists('gdp', $D)) { throw new Exception("Missing _gdp node in for $k"); } if (!array_key_exists('literacy', $D)) { throw new Exception("Missing _literacyPercent node in for $k"); } if (!array_key_exists('population', $D)) { throw new Exception("Missing _population node in for $k"); } if (!array_key_exists('languages', $D)) { throw new Exception("Missing languagePopulation node in for $k"); } $data[$k] = $D; } break; case 'weekData.json': foreach (array_keys($data['minDays']) as $key) { $value = $data['minDays'][$key]; if (!preg_match('/^[0-9]+$/', $value)) { throw new Exception("Bad number: $value"); } $data['minDays'][$key] = intval($value); } $dict = array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'); foreach (array_keys($data['firstDay']) as $key) { $val = array_search($data['firstDay'][$key], $dict, true); if ($val === false) { throw new Exception("Unknown weekday name: {$data['firstDay'][$key]}"); } $data['firstDay'][$key] = $val; } unset($data['firstDay-alt-variant']); unset($data['weekendStart']); unset($data['weekendEnd']); break; case 'territoryContainment.json': foreach (array_keys($data) as $key) { if (array_key_exists('_grouping', $data[$key])) { unset($data[$key]['_grouping']); } if (array_key_exists('_contains', $data[$key])) { $data[$key]['contains'] = $data[$key]['_contains']; unset($data[$key]['_contains']); } if (strpos($key, '-status-') !== false) { unset($data[$key]); } } break; case 'metaZones.json': checkOneKey($data['metazoneInfo'], 'timezone'); $data['metazoneInfo'] = $data['metazoneInfo']['timezone']; foreach ($data['metazoneInfo'] as $id0 => $info0) { $values1 = null; foreach ($info0 as $id1 => $info1) { if (is_int($id1)) { $info1 = fixMetazoneInfo($info1); } else { foreach ($info1 as $id2 => $info2) { if (is_int($id2)) { $info2 = fixMetazoneInfo($info2); } else { foreach ($info2 as $id3 => $info3) { if (is_int($id3)) { $info3 = fixMetazoneInfo($info3); } else { throw new Exception('Invalid metazoneInfo node'); } $info2[$id3] = $info3; } } $info1[$id2] = $info2; } } $info0[$id1] = $info1; } $data['metazoneInfo'][$id0] = $info0; } $metazones = array(); if ((!array_key_exists('metazones', $data)) && is_array($data['metazones']) && (count($data['metazones']) > 0)) { throw new Exception('metazones node not found/invalid'); } foreach ($data['metazones'] as $mz) { checkOneKey($mz, 'mapZone'); $mz = $mz['mapZone']; foreach (array_keys($mz) as $i) { switch ($i) { case '_other': case '_territory': case '_type': $mz[substr($i, 1)] = $mz[$i]; unset($mz[$i]); break; default: throw new Exception('Invalid mapZone node key: ' . $i); } } $metazones[] = $mz; } $data['metazones'] = $metazones; break; case 'timeZoneNames.json': foreach (array('gmtFormat', 'gmtZeroFormat', 'regionFormat', 'regionFormat-type-standard', 'regionFormat-type-daylight', 'fallbackFormat') as $k) { if (array_key_exists($k, $data)) { $data[$k] = toPhpSprintf($data[$k]); } } break; case 'listPatterns.json': $keys = array_keys($data); foreach ($keys as $key) { if (!preg_match('/^listPattern-type-(.+)$/', $key, $m)) { throw new Exception("Invalid node '$key' in " . $dstFile); } foreach (array_keys($data[$key]) as $k) { $data[$key][$k] = toPhpSprintf($data[$key][$k]); } $data[$m[1]] = $data[$key]; unset($data[$key]); } break; case 'plurals.json': $testData = array(); foreach ($data as $l => $lData) { $testData[$l] = array(); $keys = array_keys($lData); foreach ($keys as $key) { if (!preg_match('/^pluralRule-count-(.+)$/', $key, $m)) { throw new Exception("Invalid node '$key' in " . $dstFile); } $rule = $m[1]; $testData[$l][$rule] = array(); $vOriginal = $lData[$key]; $examples = explode('@', $vOriginal); $v = trim(array_shift($examples)); foreach ($examples as $example) { list($exampleNumberType, $exampleValues) = explode(' ', $example, 2); switch ($exampleNumberType) { case 'integer': case 'decimal': $exampleValues = preg_replace('/, …$/', '', $exampleValues); $exampleValuesParsed = array(); foreach (explode(', ', trim($exampleValues)) as $ev) { if (preg_match('/^[+\-]?\d+$/', $ev)) { $exampleValuesParsed[] = $ev; $exampleValuesParsed[] = intval($ev); } elseif (preg_match('/^[+\-]?\d+\.\d+$/', $ev)) { $exampleValuesParsed[] = $ev; } elseif (preg_match('/^([+\-]?\d+)~([+\-]?\d+)$/', $ev, $m)) { $exampleValuesParsed[] = $m[1]; $exampleValuesParsed[] = intval($m[1]); $exampleValuesParsed[] = $m[2]; $exampleValuesParsed[] = intval($m[2]); } elseif (preg_match('/^([+\-]?\d+(\.\d+)?)~([+\-]?\d+(\.\d+)?)$/', $ev, $m)) { $exampleValuesParsed[] = $m[1]; $exampleValuesParsed[] = $m[3]; } elseif ($ev !== '…') { throw new Exception("Invalid node '$key' in $dstFile: $vOriginal"); } } $testData[$l][$rule] = $exampleValuesParsed; break; default: throw new Exception("Invalid node '$key' in $dstFile: $vOriginal"); } } if ($rule === 'other') { if (strlen($v) > 0) { throw new Exception("Invalid node '$key' in $dstFile: $vOriginal"); } } else { $v = str_replace(' = ', ' == ', $v); $map = array('==' => 'true', '!=' => 'false'); foreach (array('^', ' and ', ' or ') as $pre) { while (preg_match( '/' . $pre . '(([nivfwft]( % \\d+)?) (==|!=) ((\\d+)(((\\.\\.)|,)+(\\d+))+))/', $v, $m )) { $found = $m[1]; $leftyPart = $m[2]; // eg 'n % 10' $operator = $m[4]; // eg '==' $ranges = explode(',', $m[5]); foreach (array_keys($ranges) as $j) { if (preg_match('/^(\\d+)\\.\\.(\\d+)$/', $ranges[$j], $m)) { $ranges[$j] = "array({$m[1]}, {$m[2]})"; } } $v = str_replace($found, "static::inRange($leftyPart, {$map[$operator]}, " . implode(', ', $ranges) . ")", $v); } } if (strpos($v, '..') !== false) { throw new Exception("Invalid node '$key' in $dstFile: $vOriginal"); } foreach (array( 'n' => '%1$s', // absolute value of the source number (integer and decimals). 'i' => '%2$s', // integer digits of n 'v' => '%3$s', // number of visible fraction digits in n, with trailing zeros. 'w' => '%4$s', // number of visible fraction digits in n, without trailing zeros. 'f' => '%5$s', // visible fractional digits in n, with trailing zeros. 't' => '%6$s', // visible fractional digits in n, without trailing zeros. ) as $from => $to) { $v = preg_replace('/^' . $from .' /', "$to ", $v); $v = preg_replace("/^$from /", "$to ", $v); $v = str_replace(" $from ", " $to ", $v); $v = str_replace("($from, ", "($to, ", $v); $v = str_replace("($from ", "($to ", $v); $v = str_replace(" $from,", " $to,", $v); } $v = str_replace(' % ', ' %% ', $v); $lData[$rule] = $v; } unset($lData[$key]); } $data[$l] = $lData; } $testJson = json_encode($testData, $jsonFlags); if ($testJson === false) { throw new Exception("Failed to serialize test data for $srcFile"); } $testDataFile = TESTS_DIR . DIRECTORY_SEPARATOR . basename($dstFile); if (is_file($testDataFile)) { deleteFromFilesystem($testDataFile); } if (file_put_contents($testDataFile, $testJson) === false) { throw new Exception("Failed write to $testDataFile"); } break; case 'units.json': $compounds = array(); foreach (array_keys($data) as $width) { switch ($width) { case 'long': case 'short': case 'narrow': case 'long': foreach (array_keys($data[$width]) as $unitKey) { switch ($unitKey) { case 'per': if (implode('|', array_keys(($data[$width][$unitKey]))) !== 'compoundUnitPattern') { throw new Exception("Invalid node (1) '$width/$unitKey' in " . $dstFile); } $data[$width]['_compoundPattern'] = toPhpSprintf($data[$width][$unitKey]['compoundUnitPattern']); unset($data[$width][$unitKey]); break; default: if (!preg_match('/^(\\w+)?-(.+)$/', $unitKey, $m)) { throw new Exception("Invalid node (2) '$width/$unitKey' in " . $dstFile); } $unitKind = $m[1]; $unitName = $m[2]; if (!array_key_exists($unitKind, $data[$width])) { $data[$width][$unitKind] = array(); } if (!array_key_exists($unitName, $data[$width][$unitKind])) { $data[$width][$unitKind][$unitName] = array(); } foreach (array_keys($data[$width][$unitKey]) as $pluralRuleSrc) { switch ($pluralRuleSrc) { case 'displayName': $data[$width][$unitKind][$unitName]['_name'] = $data[$width][$unitKey][$pluralRuleSrc]; break; case 'perUnitPattern': $data[$width][$unitKind][$unitName]['_per'] = toPhpSprintf($data[$width][$unitKey][$pluralRuleSrc]); break; default: if (!preg_match('/^unitPattern-count-(.+)$/', $pluralRuleSrc, $m)) { throw new Exception("Invalid node (4) '$width/$unitKey/$pluralRuleSrc' in " . $dstFile); } $pluralRule = $m[1]; $data[$width][$unitKind][$unitName][$pluralRule] = toPhpSprintf($data[$width][$unitKey][$pluralRuleSrc]); break; } } unset($data[$width][$unitKey]); break; } } break; default: if (preg_match('/^durationUnit-type-(.+)/', $width, $m)) { if (implode('|', array_keys(($data[$width]))) !== 'durationUnitPattern') { throw new Exception("Invalid node (5) '$width' in " . $dstFile); } $t = $m[1]; if (!array_key_exists('_durationPattern', $data)) { $data['_durationPattern'] = array(); } $data['_durationPattern'][$t] = $data[$width]['durationUnitPattern']; unset($data[$width]); } else { throw new Exception("Invalid node (6) '$width' in " . $dstFile); } break; } } break; case 'localeDisplayNames.json': if (!array_key_exists('localeDisplayPattern', $data)) { throw new Exception("Missing node 'localeDisplayPattern' in " . $dstFile); } foreach (array_keys($data['localeDisplayPattern']) as $k) { $data['localeDisplayPattern'][$k] = toPhpSprintf($data['localeDisplayPattern'][$k]); } if (!array_key_exists('codePatterns', $data)) { throw new Exception("Missing node 'codePatterns' in " . $dstFile); } foreach (array_keys($data['codePatterns']) as $k) { $data['codePatterns'][$k] = toPhpSprintf($data['codePatterns'][$k]); } break; case 'numbers.json': $final = array(); $numberSystems = array(); foreach ($data as $key => $value) { if (preg_match('/^([a-z]+)-numberSystem-([a-z]+)$/i', $key, $m)) { $keyChunk = $m[1]; $ns = $m[2]; if (!array_key_exists($ns, $numberSystems)) { $numberSystems[$ns] = array(); } if (is_array($value)) { $unitPattern = null; foreach ($value as $k2 => $v2) { if (preg_match('/^unitPattern-(.+)$/i', $k2, $m)) { if (is_null($unitPattern)) { $unitPattern = array(); } $unitPattern[$m[1]] = toPhpSprintf($v2); unset($value[$k2]); } } if (!is_null($unitPattern)) { $value['unitPattern'] = $unitPattern; } } $numberSystems[$ns][$keyChunk] = $value; } else { switch ($key) { case 'defaultNumberingSystem': case 'otherNumberingSystems': break; case 'minimumGroupingDigits': if (is_string($value) && preg_match('/^\\d+$/', $value)) { $value = @intval($value); } if (!is_int($value)) { throw new Exception("Invalid node '$key' in " . $dstFile); } $final[$key] = $value; break; default: throw new Exception("Invalid node '$key' in " . $dstFile); } } } if (!array_key_exists('latn', $numberSystems)) { throw new Exception("Missing 'latn' in " . $dstFile); } foreach ($numberSystems['latn'] as $key => $value) { if (array_key_exists($key, $final)) { throw new Exception("Duplicated node '$key' in " . $dstFile); } // $final[$key] = $value; REMOVED ADVANCED LOCALIZATION if ($key === 'symbols') { // REMOVED ADVANCED LOCALIZATION $final[$key] = $value; } } $data = $final; $symbols = array_key_exists('symbols', $data) ? $data['symbols'] : null; if (empty($symbols) || (!is_array($symbols))) { throw new Exception("Missing symbols in " . $dstFile); } foreach (array_keys($data) as $key) { if (is_array($data[$key]) && preg_match('/\\w+Formats$/', $key) && array_key_exists('standard', $data[$key])) { $format = $data[$key]['standard']; $data[$key]['standard'] = array('format' => $format); foreach (numberFormatToRegularExpressions($symbols, $format) as $rxKey => $rx) { $data[$key]['standard']["rx$rxKey"] = $rx; } } } break; } $json = json_encode($data, $jsonFlags); if ($json === false) { throw new Exception("Failed to serialize data of $srcFile"); } if (is_file($dstFile)) { deleteFromFilesystem($dstFile); } if (file_put_contents($dstFile, $json) === false) { throw new Exception("Failed write to $dstFile"); } } function deleteFromFilesystem($path) { if (is_file($path)) { if (unlink($path) === false) { throw new Exception("Failed to delete file $path"); } } else { $contents = scandir($path); if ($contents === false) { throw new Exception("Failed to retrieve the file list of $path"); } foreach (array_diff($contents, array('.', '..')) as $item) { deleteFromFilesystem($path . DIRECTORY_SEPARATOR . $item); } if (rmdir($path) === false) { throw new Exception("Failed to delete directory $path"); } } } function toPhpSprintf($fmt) { $result = $fmt; if (is_string($fmt)) { $result = str_replace('%', '%%', $result); $result = preg_replace_callback( '/\\{(\\d+)\\}/', function ($matches) { return '%' . (1 + intval($matches[1])) . '$s'; }, $fmt ); } return $result; } function fixMetazoneInfo($a) { checkOneKey($a, 'usesMetazone'); $a = $a['usesMetazone']; foreach (array_keys($a) as $key) { switch ($key) { case '_mzone': case '_from': case '_to': $a[substr($key, 1)] = $a[$key]; unset($a[$key]); break; default: throw new Exception('Invalid metazoneInfo node'); } } return $a; } function checkOneKey($node, $key) { if (!is_array($node)) { throw new Exception("$node is not an array"); } if (count($node) !== 1) { throw new Exception("Expected just one node '$key', found these keys: " . implode(', ', array_keys($node))); } if (!array_key_exists($key, $node)) { throw new Exception("Expected just one node '$key', found this key: " . implode(', ', array_keys($node))); } } function numberFormatToRegularExpressions($symbols, $isoPattern) { $p = explode(';', $isoPattern); $patterns = array( '+' => $p[0], '-' => (count($p) == 1) ? "-{$p[0]}" : $p[1], ); $result = array(); foreach ($patterns as $patternKey => $pattern) { $rxPost = $rxPre = ''; if (preg_match('/(-)?([^0#E,\\.\\-+]*)(.+?)([^0#E,\\.\\-+]*)(-)?$/', $pattern, $m)) { for ($i = 1; $i < 6; $i++) { if (!isset($m[$i])) { $m[$i] = ''; } } if (strlen($m[2]) > 0) { $rxPre = preg_quote($m[2]); } $pattern = $m[1] . $m[3] . $m[5]; if (strlen($m[4]) > 0) { $rxPost = preg_quote($m[4]); } } $rx = ''; if (strpos($pattern, '.') !== false) { list($intPattern, $decimalPattern) = explode('.', $pattern, 2); } else { $intPattern = $pattern; $decimalPattern = ''; } if (strpos($intPattern, 'E') !== false) { switch ($intPattern) { case '#E0': case '#E00': $rx .= '(' . preg_quote($symbols['plusSign']). ')?[0-9]+((' . preg_quote($symbols['decimal']) . ')[0-9]+)*[eE]((' . preg_quote($symbols['minusSign']) . ')|(' . preg_quote($symbols['plusSign']) . '))?[0-9]+'; break; case '-#E0': case '-#E00': $rx .= '(' . preg_quote($symbols['minusSign']). ')?[0-9]+((' . preg_quote($symbols['decimal']) . ')[0-9]+)*[eE]((' . preg_quote($symbols['minusSign']) . ')|(' . preg_quote($symbols['plusSign']) . '))?[0-9]+'; break; default: throw new \Exception("Invalid chunk ('$intPattern') in pattern '$pattern'"); } } elseif (strpos($intPattern, ',') !== false) { $chunks = explode(',', $intPattern); $maxChunkIndex = count($chunks) - 1; $prevChunk = null; for ($chunkIndex = 0; $chunkIndex <= $maxChunkIndex; $chunkIndex++) { $chunk = $chunks[$chunkIndex]; $nextChunk = ($chunkIndex == $maxChunkIndex) ? null : $chunks[$chunkIndex + 1]; switch ($chunk) { case '#': case '-#': if ($chunk === '-#') { $rx .= '(' . preg_quote($symbols['minusSign']) . ')?'; } else { $rx .= '(' . preg_quote($symbols['plusSign']) . ')?'; } if ($nextChunk === '##0') { $rx .= '[0-9]{1,3}'; } elseif ($nextChunk === '##') { $rx .= '[0-9]{1,2}'; } else { throw new \Exception("Invalid chunk #$chunkIndex ('$chunk') in pattern '$pattern'"); } break; case '##': if ($nextChunk === '##0') { $rx .= '((' . preg_quote($symbols['group']) . ')?[0-9]{2})*'; } else { throw new \Exception("Invalid chunk #$chunkIndex ('$chunk') in pattern '$pattern'"); } break; case '##0': if ($prevChunk === '##') { $rx .= '[0-9]'; } elseif (($prevChunk === '#') || ($prevChunk === '-#')) { $rx .= '((' . preg_quote($symbols['group']) . ')?[0-9]{3})*'; } else { throw new \Exception("Invalid chunk #$chunkIndex ('$chunk') in pattern '$pattern'"); } break; case '#0': if ($chunkIndex === 0) { $rx .= '[0-9]*'; } else { throw new \Exception("Invalid chunk #$chunkIndex ('$chunk') in pattern '$pattern'"); } break; } $prevChunk = $chunk; } } else { throw new \Exception("Invalid chunk ('$intPattern') in pattern '$pattern'"); } if (strlen($decimalPattern) > 0) { switch ($decimalPattern) { case '###': $rx .= '((' . preg_quote($symbols['decimal']) . ')[0-9]+)?'; break; case '###-': $rx .= '((' . preg_quote($symbols['decimal']) . ')[0-9]+)?(' . preg_quote($symbols['minusSign']) . ')'; break; default: if (preg_match('/^(0+)(-?)$/', $decimalPattern, $m)) { $n = strlen($m[1]); $rx .= '(' . preg_quote($symbols['decimal']) . ')[0-9]{' . strlen($m[1]) . '}'; if (substr($decimalPattern, -1) === '-') { $rx .= '(' . preg_quote($symbols['minusSign']) . ')'; } } else { throw new \Exception("Invalid chunk ('$decimalPattern') in pattern '$pattern'"); } } } $result[$patternKey] = '/^' . $rxPre . $rx . $rxPost . '$/u'; } return $result; }