1<?php 2use Gettext\Languages\Exporter\Exporter; 3use Gettext\Languages\Language; 4 5// Let's start by imposing that we don't accept any error or warning. 6// This is a really life-saving approach. 7error_reporting(E_ALL); 8set_error_handler(function ($errno, $errstr, $errfile, $errline) { 9 Enviro::echoErr("$errstr\nFile: $errfile\nLine: $errline\nCode: $errno\n"); 10 die(5); 11}); 12 13require_once dirname(__DIR__).'/src/autoloader.php'; 14 15// Parse the command line options 16Enviro::initialize(); 17 18try { 19 if (isset(Enviro::$languages)) { 20 $languages = array(); 21 foreach (Enviro::$languages as $languageId) { 22 $language = Language::getById($languageId); 23 if (!isset($language)) { 24 throw new Exception("Unable to find the language with id '$languageId'"); 25 } 26 $languages[] = $language; 27 } 28 } else { 29 $languages = Language::getAll(); 30 } 31 if (Enviro::$reduce) { 32 $languages = Enviro::reduce($languages); 33 } 34 if (isset(Enviro::$outputFilename)) { 35 echo call_user_func(array(Exporter::getExporterClassName(Enviro::$outputFormat), 'toFile'), $languages, Enviro::$outputFilename, array('us-ascii' => Enviro::$outputUSAscii)); 36 } else { 37 echo call_user_func(array(Exporter::getExporterClassName(Enviro::$outputFormat), 'toString'), $languages, array('us-ascii' => Enviro::$outputUSAscii)); 38 } 39} catch (Exception $x) { 40 Enviro::echoErr($x->getMessage()."\n"); 41 Enviro::echoErr("Trace:\n"); 42 Enviro::echoErr($x->getTraceAsString()."\n"); 43 die(4); 44} 45 46die(0); 47 48/** 49 * Helper class to handle command line options. 50 */ 51class Enviro 52{ 53 /** 54 * Shall the output contain only US-ASCII characters? 55 * @var bool 56 */ 57 public static $outputUSAscii; 58 /** 59 * The output format. 60 * @var string 61 */ 62 public static $outputFormat; 63 /** 64 * Output file name. 65 * @var string 66 */ 67 public static $outputFilename; 68 /** 69 * List of wanted language IDs; it not set: all languages will be returned. 70 * @var array|null 71 */ 72 public static $languages; 73 /** 74 * Reduce the language list to the minimum common denominator. 75 * @var bool 76 */ 77 public static $reduce; 78 /** 79 * Parse the command line options. 80 */ 81 public static function initialize() 82 { 83 global $argv; 84 self::$outputUSAscii = false; 85 self::$outputFormat = null; 86 self::$outputFilename = null; 87 self::$languages = null; 88 self::$reduce = null; 89 $exporters = Exporter::getExporters(); 90 if (isset($argv) && is_array($argv)) { 91 foreach ($argv as $argi => $arg) { 92 if ($argi === 0) { 93 continue; 94 } 95 if (is_string($arg)) { 96 $argLC = trim(strtolower($arg)); 97 switch ($argLC) { 98 case '--us-ascii': 99 self::$outputUSAscii = true; 100 break; 101 case '--reduce=yes': 102 self::$reduce = true; 103 break; 104 case '--reduce=no': 105 self::$reduce = false; 106 break; 107 default: 108 if (preg_match('/^--output=.+$/', $argLC)) { 109 if (isset(self::$outputFilename)) { 110 self::echoErr("The output file name has been specified more than once!\n"); 111 self::showSyntax(); 112 die(3); 113 } 114 list(, self::$outputFilename) = explode('=', $arg, 2); 115 self::$outputFilename = trim(self::$outputFilename); 116 } elseif (preg_match('/^--languages?=.+$/', $argLC)) { 117 list(, $s) = explode('=', $arg, 2); 118 $list = explode(',', $s); 119 if (is_array(self::$languages)) { 120 self::$languages = array_merge(self::$languages, $list); 121 } else { 122 self::$languages = $list; 123 } 124 } elseif (isset($exporters[$argLC])) { 125 if (isset(self::$outputFormat)) { 126 self::echoErr("The output format has been specified more than once!\n"); 127 self::showSyntax(); 128 die(3); 129 } 130 self::$outputFormat = $argLC; 131 } else { 132 self::echoErr("Unknown option: $arg\n"); 133 self::showSyntax(); 134 die(2); 135 } 136 break; 137 } 138 } 139 } 140 } 141 if (!isset(self::$outputFormat)) { 142 self::showSyntax(); 143 die(1); 144 } 145 if (isset(self::$languages)) { 146 self::$languages = array_values(array_unique(self::$languages)); 147 } 148 if (!isset(self::$reduce)) { 149 self::$reduce = isset(self::$languages) ? false : true; 150 } 151 } 152 153 /** 154 * Write out the syntax. 155 */ 156 public static function showSyntax() 157 { 158 $exporters = array_keys(Exporter::getExporters(true)); 159 self::echoErr("Syntax: php ".basename(__FILE__)." [--us-ascii] [--languages=<LanguageId>[,<LanguageId>,...]] [--reduce=yes|no] [--output=<file name>] <".implode('|', $exporters).">\n"); 160 self::echoErr("Where:\n"); 161 self::echoErr("--us-ascii : if specified, the output will contain only US-ASCII characters.\n"); 162 self::echoErr("--languages: (or --language) export only the specified language codes.\n"); 163 self::echoErr(" Separate languages with commas; you can also use this argument\n"); 164 self::echoErr(" more than once; it's case insensitive and accepts both '_' and\n"); 165 self::echoErr(" '-' as locale chunks separator (eg we accept 'it_IT' as well as\n"); 166 self::echoErr(" 'it-it').\n"); 167 self::echoErr("--reduce : if set to yes the output won't contain languages with the same\n"); 168 self::echoErr(" base language and rules.\n For instance nl_BE ('Flemish') will be\n"); 169 self::echoErr(" omitted because it's the same as nl ('Dutch').\n"); 170 self::echoErr(" Defaults to 'no' --languages is specified, to 'yes' otherwise.\n"); 171 self::echoErr("--output : if specified, the output will be saved to <file name>. If not\n"); 172 self::echoErr(" specified we'll output to standard output.\n"); 173 self::echoErr("Output formats\n"); 174 $len = max(array_map('strlen', $exporters)); 175 foreach ($exporters as $exporter) { 176 self::echoErr(str_pad($exporter, $len).": ".Exporter::getExporterDescription($exporter)."\n"); 177 } 178 } 179 /** 180 * Print a string to stderr. 181 * @param string $str The string to be printed out. 182 */ 183 public static function echoErr($str) 184 { 185 $hStdErr = @fopen('php://stderr', 'a'); 186 if ($hStdErr === false) { 187 echo $str; 188 } else { 189 fwrite($hStdErr, $str); 190 fclose($hStdErr); 191 } 192 } 193 /** 194 * Reduce a language list to the minimum common denominator. 195 * @param Language[] $languages 196 * @return Language[] 197 */ 198 public static function reduce($languages) 199 { 200 for ($numChunks = 3; $numChunks >= 2; $numChunks--) { 201 $filtered = array(); 202 foreach ($languages as $language) { 203 $chunks = explode('_', $language->id); 204 $compatibleFound = false; 205 if (count($chunks) === $numChunks) { 206 $categoriesHash = serialize($language->categories); 207 $otherIds = array(); 208 $otherIds[] = $chunks[0]; 209 for ($k = 2; $k < $numChunks; $k++) { 210 $otherIds[] = $chunks[0].'_'.$chunks[$numChunks - 1]; 211 } 212 213 foreach ($languages as $check) { 214 foreach ($otherIds as $otherId) { 215 if (($check->id === $otherId) && ($check->formula === $language->formula) && (serialize($check->categories) === $categoriesHash)) { 216 $compatibleFound = true; 217 break; 218 } 219 } 220 if ($compatibleFound === true) { 221 break; 222 } 223 } 224 } 225 if (!$compatibleFound) { 226 $filtered[] = $language; 227 } 228 } 229 $languages = $filtered; 230 } 231 232 return $languages; 233 } 234} 235