MediaWiki fundraising/REL1_35
CLDRParser.php
Go to the documentation of this file.
1<?php
2
13class CLDRParser {
18 public function parse( $inputFile, $outputFile ) {
19 // Open the input file for reading
20
21 $contents = file_get_contents( $inputFile );
22 $doc = new SimpleXMLElement( $contents );
23
24 $data = [
25 'languageNames' => [],
26 'currencyNames' => [],
27 'currencySymbols' => [],
28 'countryNames' => [],
29 'timeUnits' => [],
30 ];
31
32 foreach ( $doc->xpath( '//languages/language' ) as $elem ) {
33 if ( (string)$elem['alt'] !== '' ) {
34 continue;
35 }
36
37 if ( (string)$elem['type'] === 'root' ) {
38 continue;
39 }
40
41 $key = str_replace( '_', '-', strtolower( $elem['type'] ) );
42
43 $data['languageNames'][$key] = (string)$elem;
44 }
45
46 foreach ( $doc->xpath( '//currencies/currency' ) as $elem ) {
47 if ( (string)$elem->displayName[0] === '' ) {
48 continue;
49 }
50
51 $data['currencyNames'][(string)$elem['type']] = (string)$elem->displayName[0];
52 if ( (string)$elem->symbol[0] !== '' ) {
53 $data['currencySymbols'][(string)$elem['type']] = (string)$elem->symbol[0];
54 }
55 }
56
57 foreach ( $doc->xpath( '//territories/territory' ) as $elem ) {
58 if ( (string)$elem['alt'] !== '' && (string)$elem['alt'] !== 'short' ) {
59 continue;
60 }
61
62 if ( (string)$elem['type'] === 'ZZ' ||
63 !preg_match( '/^[A-Z][A-Z]$/', $elem['type'] )
64 ) {
65 continue;
66 }
67
68 $data['countryNames'][(string)$elem['type']] = (string)$elem;
69 }
70 foreach ( $doc->xpath( '//units/unitLength' ) as $unitLength ) {
71 if ( (string)$unitLength['type'] !== 'long' ) {
72 continue;
73 }
74 foreach ( $unitLength->unit as $elem ) {
75 $type = (string)$elem['type'];
76 $pos = strpos( $type, 'duration' );
77 if ( $pos === false ) {
78 continue;
79 }
80 $type = substr( $type, strlen( 'duration-' ) );
81 foreach ( $elem->unitPattern as $pattern ) {
82 $data['timeUnits'][$type . '-' . (string)$pattern['count']] = (string)$pattern;
83 }
84 }
85 }
86 foreach ( $doc->xpath( '//fields/field' ) as $field ) {
87 $fieldType = (string)$field['type'];
88
89 foreach ( $field->relativeTime as $relative ) {
90 $type = (string)$relative['type'];
91 foreach ( $relative->relativeTimePattern as $pattern ) {
92 $data['timeUnits'][$fieldType . '-' . $type
93 . '-' . (string)$pattern['count']] = (string)$pattern;
94 }
95 }
96 }
97
98 ksort( $data['timeUnits'] );
99
100 $this->savephp( $data, $outputFile );
101 }
102
108 public function parse_supplemental( $inputFile, $outputFile ) {
109 // Open the input file for reading
110
111 $contents = file_get_contents( $inputFile );
112 $doc = new SimpleXMLElement( $contents );
113
114 $data = [
115 'currencyFractions' => [],
116 'localeCurrencies' => [],
117 ];
118
119 // Pull currency attributes - digits, rounding, and cashRounding.
120 // This will tell us how many decmal places make sense to use with any currency,
121 // or if the currency is totally non-fractional
122 foreach ( $doc->xpath( '//currencyData/fractions/info' ) as $elem ) {
123 if ( (string)$elem['iso4217'] === '' ) {
124 continue;
125 }
126
127 $attributes = [ 'digits', 'rounding', 'cashDigits', 'cashRounding' ];
128 foreach ( $attributes as $att ) {
129 if ( (string)$elem[$att] !== '' ) {
130 $data['currencyFractions'][(string)$elem['iso4217']][$att] = (string)$elem[$att];
131 }
132 }
133 }
134
135 // Pull a map of regions to currencies in order of preference.
136 foreach ( $doc->xpath( '//currencyData/region' ) as $elem ) {
137 if ( (string)$elem['iso3166'] === '' ) {
138 continue;
139 }
140
141 $region = (string)$elem['iso3166'];
142
143 foreach ( $elem->currency as $currencynode ) {
144 if ( (string)$currencynode['to'] === '' && (string)$currencynode['tender'] !== 'false' ) {
145 $data['localeCurrencies'][$region][] = (string)$currencynode['iso4217'];
146 }
147 }
148 }
149
150 $this->savephp( $data, $outputFile );
151 }
152
161 public function parse_currency_symbols( $inputDir, $outputFile ) {
162 if ( !file_exists( $inputDir ) ) {
163 return;
164 }
165 $files = scandir( $inputDir );
166
167 $data = [
168 'currencySymbols' => [],
169 ];
170
171 // Foreach files!
172 foreach ( $files as $inputFile ) {
173 if ( strpos( $inputFile, '.xml' ) < 1 ) {
174 continue;
175 }
176
177 $contents = file_get_contents( $inputDir . '/' . $inputFile );
178 $doc = new SimpleXMLElement( $contents );
179
180 // Tags in the <identity> section are guaranteed to appear once
181 $languages = $doc->xpath( '//identity/language/@type' );
182 $language = $languages
183 ? (string)$languages[0]
184 : pathinfo( $inputFile, PATHINFO_FILENAME );
185
186 // The <territory> element is optional
187 $territories = $doc->xpath( '//identity/territory/@type' );
188 $territory = $territories ? (string)$territories[0] : 'DEFAULT';
189
190 foreach ( $doc->xpath( '//currencies/currency' ) as $elem ) {
191 if ( (string)$elem->symbol[0] !== '' ) {
192 $data['currencySymbols'][(string)$elem['type']][$language][$territory] =
193 (string)$elem->symbol[0];
194 }
195 }
196 }
197
198 // now massage the data somewhat. It's pretty blown up at this point.
199
211 foreach ( $data['currencySymbols'] as $currency => $language ) {
212 // get the currency default symbol. This will either be defined in the
213 // 'root' language file, or taken from the ISO code.
214 $default = $language['root']['DEFAULT'] ?? $currency;
215
216 foreach ( $language as $lang => $territories ) {
217 // Collapse a language (no locality) array if it's just the default. One value will do fine.
218 if ( is_array( $territories ) ) {
219 if ( count( $territories ) === 1 && array_key_exists( 'DEFAULT', $territories ) ) {
220 $data['currencySymbols'][$currency][$lang] = $territories['DEFAULT'];
221 if ( $territories['DEFAULT'] === $default && $lang !== 'root' ) {
222 unset( $data['currencySymbols'][$currency][$lang] );
223 }
224 } else {
225 ksort( $data['currencySymbols'][$currency][$lang] );
226 }
227 }
228 }
229
230 ksort( $data['currencySymbols'][$currency] );
231 }
232
233 ksort( $data['currencySymbols'] );
234
235 $this->savephp( $data, $outputFile );
236 }
237
244 protected function savephp( $data, $location ) {
245 $hasData = false;
246 foreach ( $data as $v ) {
247 if ( count( $v ) ) {
248 $hasData = true;
249 break;
250 }
251 }
252
253 if ( !$hasData ) {
254 return;
255 }
256
257 // Yes, I am aware I could have simply used var_export.
258 // ...the spacing was ugly.
259 $output = "<?php\n";
260 foreach ( $data as $varname => $values ) {
261 if ( !count( $values ) ) {
262 // Don't output empty arrays
263 continue;
264 }
265 $output .= "\n\$$varname = [\n";
266 if ( $this->isAssoc( $values ) ) {
267 foreach ( $values as $key => $value ) {
268 if ( is_array( $value ) ) {
269 $output .= $this->makePrettyArrayOuts( $key, $value, 1 );
270 } else {
271 $key = addcslashes( $key, "'" );
272 $value = addcslashes( $value, "'" );
273 if ( !is_numeric( $key ) ) {
274 $key = "'$key'";
275 }
276 $output .= "\t$key => '$value',\n";
277 }
278 }
279 } else {
280 foreach ( $values as $value ) {
281 if ( is_array( $value ) ) {
282 $output .= $this->makePrettyArrayOuts( null, $value, 1 );
283 } else {
284 $value = addcslashes( $value, "'" );
285 $output .= "\t'$value',\n";
286 }
287 }
288 }
289 $output .= "];\n";
290 }
291
292 file_put_contents( $location, $output );
293 }
294
302 protected function makePrettyArrayOuts( $key, $value, $level = 1 ) {
303 $subKeys = '';
304 $isAssoc = $this->isAssoc( $value );
305 $tabs = str_repeat( "\t", $level );
306
307 foreach ( $value as $subkey => $subvalue ) {
308 $subkey = $isAssoc ? $subkey : null;
309
310 if ( is_array( $subvalue ) ) {
311 $subKeys .= $this->makePrettyArrayOuts( $subkey, $subvalue, $level + 1 );
312 } else {
313 $subkey = $isAssoc ? $this->formatKey( $subkey ) : '';
314 $subvalue = addcslashes( $subvalue, "'" );
315 $subKeys .= "$tabs\t$subkey'$subvalue',\n";
316 }
317 }
318
319 if ( $subKeys === '' ) {
320 return '';
321 }
322
323 $key = $key !== null ? $this->formatKey( $key ) : '';
324 return "$tabs$key" . "[\n$subKeys$tabs],\n";
325 }
326
332 protected function formatKey( $key ) {
333 $key = addcslashes( $key, "'" );
334 if ( !is_numeric( $key ) ) {
335 $key = "'$key'";
336 }
337
338 return "$key => ";
339 }
340
347 protected function isAssoc( array $arr ) {
348 return array_keys( $arr ) !== range( 0, count( $arr ) - 1 );
349 }
350}
if(!isset( $args[0])) $lang