| Index: trunk/extensions/ParserFunctions/convertTests.txt |
| — | — | @@ -0,0 +1,193 @@ |
| | 2 | +!! test |
| | 3 | +Simple conversion |
| | 4 | +!! input |
| | 5 | +{{#convert: 10 m | km }} |
| | 6 | +!!result |
| | 7 | +<p>0.01 kilometres |
| | 8 | +</p> |
| | 9 | +!! end |
| | 10 | + |
| | 11 | +!! test |
| | 12 | +Position and formatting of numbers and units |
| | 13 | +!! input |
| | 14 | +*{{#convert: 10 m | km }} |
| | 15 | +*{{#convert: 10m | km }} |
| | 16 | +*{{#convert: 10 km | m }} |
| | 17 | +*{{#convert: 10-km | m }} |
| | 18 | +*{{#convert: 10E2 km | m }} |
| | 19 | +*{{#convert: 10E-2 km | m }} |
| | 20 | +*{{#convert: 10.0E2 km | m }} |
| | 21 | +*{{#convert: 10.0E2.5 km | m }} |
| | 22 | +!! result |
| | 23 | +<ul><li>0.01 kilometres |
| | 24 | +</li><li>0.01 kilometres |
| | 25 | +</li><li>10,000 metres |
| | 26 | +</li><li>10,000- metres |
| | 27 | +</li><li>1,000,000 metres |
| | 28 | +</li><li>100 metres |
| | 29 | +</li><li>1,000,000 metres |
| | 30 | +</li><li>1,000,000.5,000 metres |
| | 31 | +</li></ul> |
| | 32 | + |
| | 33 | +!! end |
| | 34 | + |
| | 35 | +!! test |
| | 36 | +Precision 1 |
| | 37 | +!! input |
| | 38 | +*{{#convert: 10 m | km }} |
| | 39 | +*{{#convert: 11 m | km }} |
| | 40 | +*{{#convert: 12 m | km }} |
| | 41 | +*{{#convert: 13 m | km }} |
| | 42 | +*{{#convert: 14 m | km }} |
| | 43 | +*{{#convert: 15 m | km }} |
| | 44 | +*{{#convert: 16 m | km }} |
| | 45 | +*{{#convert: 17 m | km }} |
| | 46 | +*{{#convert: 18 m | km }} |
| | 47 | +*{{#convert: 19 m | km }} |
| | 48 | +*{{#convert: 20 m | km }} |
| | 49 | +!! result |
| | 50 | +<ul><li>0.01 kilometres |
| | 51 | +</li><li>0.011 kilometres |
| | 52 | +</li><li>0.012 kilometres |
| | 53 | +</li><li>0.013 kilometres |
| | 54 | +</li><li>0.014 kilometres |
| | 55 | +</li><li>0.015 kilometres |
| | 56 | +</li><li>0.016 kilometres |
| | 57 | +</li><li>0.017 kilometres |
| | 58 | +</li><li>0.018 kilometres |
| | 59 | +</li><li>0.019 kilometres |
| | 60 | +</li><li>0.02 kilometres |
| | 61 | +</li></ul> |
| | 62 | + |
| | 63 | +!! end |
| | 64 | + |
| | 65 | +!! test |
| | 66 | +Precision 2 |
| | 67 | +!! input |
| | 68 | +*{{#convert: 10.0 m | km }} |
| | 69 | +*{{#convert: 10.1 m | km }} |
| | 70 | +*{{#convert: 10.2 m | km }} |
| | 71 | +*{{#convert: 10.3 m | km }} |
| | 72 | +*{{#convert: 10.4 m | km }} |
| | 73 | +*{{#convert: 10.5 m | km }} |
| | 74 | +*{{#convert: 10.6 m | km }} |
| | 75 | +*{{#convert: 10.7 m | km }} |
| | 76 | +!! result |
| | 77 | +<ul><li>0.0100 kilometres |
| | 78 | +</li><li>0.0101 kilometres |
| | 79 | +</li><li>0.0102 kilometres |
| | 80 | +</li><li>0.0103 kilometres |
| | 81 | +</li><li>0.0104 kilometres |
| | 82 | +</li><li>0.0105 kilometres |
| | 83 | +</li><li>0.0106 kilometres |
| | 84 | +</li><li>0.0107 kilometres |
| | 85 | +</li></ul> |
| | 86 | + |
| | 87 | +!! end |
| | 88 | + |
| | 89 | +!! test |
| | 90 | +String interpolation |
| | 91 | +!! input |
| | 92 | +{{#convert: 25, 26, 27, 28, 29, and 30 km }} |
| | 93 | +!! result |
| | 94 | +<p>25,000, 26,000, 27,000, 28,000, 29,000, and 30,000 metres |
| | 95 | +</p> |
| | 96 | +!! end |
| | 97 | + |
| | 98 | +!! test |
| | 99 | +Precision 3 |
| | 100 | +!! input |
| | 101 | +{{#convert: 25, 26, 27, 28, 29, and 30 miles }} |
| | 102 | +!! result |
| | 103 | +<p>40,000, 42,000, 43,000, 45,000, 47,000, and 50,000 metres |
| | 104 | +</p> |
| | 105 | +!! end |
| | 106 | + |
| | 107 | +!! test |
| | 108 | +Precision 4 |
| | 109 | +!! input |
| | 110 | +{{#convert:35000, 35E3, 35.0E3, 350E2, 3.500E4, 35000E0, 350000E-1 m | km }} |
| | 111 | +!! result |
| | 112 | +<p>35, 35, 35.0, 35, 35.00, 35, 35 kilometres |
| | 113 | +</p> |
| | 114 | +!! end |
| | 115 | + |
| | 116 | +!! test |
| | 117 | +#sourceunit |
| | 118 | +!!input |
| | 119 | +*{{#convert: 25 | #sourceunit = km }} |
| | 120 | +*{{#convert: 25 | #sourceunit=km }} |
| | 121 | +*{{#convert: 25 | #sourceunit = km | #sourceunit = mm }} |
| | 122 | +*{{#convert: 25 | #sourceunit = km | cm }} |
| | 123 | +!! result |
| | 124 | +<ul><li>25,000 metres |
| | 125 | +</li><li>25,000 metres |
| | 126 | +</li><li>0.025 metres |
| | 127 | +</li><li>2,500,000 centimetres |
| | 128 | +</li></ul> |
| | 129 | + |
| | 130 | +!! end |
| | 131 | + |
| | 132 | +!! test |
| | 133 | +Precision overrides |
| | 134 | +!!input |
| | 135 | +*{{#convert: 1 mi | #dp = 0 }} |
| | 136 | +*{{#convert: 1 mi | #dp=1 }} |
| | 137 | +*{{#convert: 1 mi | #dp = -2 }} |
| | 138 | +*{{#convert: 1 mi | #dp = 5 }} |
| | 139 | +*{{#convert: 1 mi | #dp = -8 }} |
| | 140 | +*{{#convert: 1 mi | #sf = 0 }} |
| | 141 | +*{{#convert: 1 mi | #sf=1 }} |
| | 142 | +*{{#convert: 1 mi | #sf = 3 }} |
| | 143 | +*{{#convert: 1 mi | #sf = 5 }} |
| | 144 | +*{{#convert: 1 mi | #sf = -8 }} |
| | 145 | +!! result |
| | 146 | +<ul><li>1,609 metres |
| | 147 | +</li><li>1,609.3 metres |
| | 148 | +</li><li>1,600 metres |
| | 149 | +</li><li>1,609.344 metres |
| | 150 | +</li><li>0 metres |
| | 151 | +</li><li>2,000 metres |
| | 152 | +</li><li>2,000 metres |
| | 153 | +</li><li>1,610 metres |
| | 154 | +</li><li>1,609.3 metres |
| | 155 | +</li><li>2,000 metres |
| | 156 | +</li></ul> |
| | 157 | + |
| | 158 | +!! end |
| | 159 | + |
| | 160 | + |
| | 161 | +!! test |
| | 162 | +Errors |
| | 163 | +!! input |
| | 164 | +*{{#convert: 25 | km }} |
| | 165 | +*{{#convert: 25 foobars | mi }} |
| | 166 | +*{{#convert: 25 mi | #sourceunit = foobar }} |
| | 167 | +*{{#convert: 25 km | s }} |
| | 168 | +*{{#convert: 25 km/Pa | m/Pa }} |
| | 169 | +*{{#convert: 25 km/s/l }} |
| | 170 | +*{{#convert: 25 km/m3 }} |
| | 171 | +!! result |
| | 172 | +<ul><li><strong class="error">Error: no source unit given</strong> |
| | 173 | +</li><li><strong class="error">Error: unknown unit "foobars"</strong> |
| | 174 | +</li><li><strong class="error">Error: unknown unit "foobar"</strong> |
| | 175 | +</li><li><strong class="error">Error: cannot convert between units of "length" and "time"</strong> |
| | 176 | +</li><li><strong class="error">Error: invalid compound unit "length/pressure"</strong> |
| | 177 | +</li><li><strong class="error">Error: cannot parse double compound units like "km/s/l"</strong> |
| | 178 | +</li><li><strong class="error">Error: invalid compound unit "length/volume"</strong> |
| | 179 | +</li></ul> |
| | 180 | + |
| | 181 | +!! end |
| | 182 | + |
| | 183 | + |
| | 184 | +!! test |
| | 185 | +#sourceunit = #targetunit |
| | 186 | +!! input |
| | 187 | +*{{#convert: 25 km | #targetunit = #sourceunit }} |
| | 188 | +*{{#convert: 25 km | #sourceunit = #targetunit }} |
| | 189 | +!! result |
| | 190 | +<ul><li>25 kilometres |
| | 191 | +</li><li>25 kilometres |
| | 192 | +</li></ul> |
| | 193 | + |
| | 194 | +!! end |
| Property changes on: trunk/extensions/ParserFunctions/convertTests.txt |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| 1 | 195 | + native |
| Index: trunk/extensions/ParserFunctions/Convert.php |
| — | — | @@ -0,0 +1,735 @@ |
| | 2 | +<?php |
| | 3 | + |
| | 4 | +if ( !defined( 'MEDIAWIKI' ) ) { |
| | 5 | + die( 'This file is a MediaWiki extension, it is not a valid entry point' ); |
| | 6 | +} |
| | 7 | + |
| | 8 | +class ConvertError extends Exception { |
| | 9 | + public function __construct( $msg /*...*/ ) { |
| | 10 | + $args = func_get_args(); |
| | 11 | + array_shift( $args ); |
| | 12 | + $this->message = '<strong class="error">' . wfMsgExt( "pfunc-convert-$msg", 'parseinline', $args ) . '</strong>'; |
| | 13 | + } |
| | 14 | +} |
| | 15 | + |
| | 16 | +class ConvertParser { |
| | 17 | + |
| | 18 | + # A regex which matches the body of the string and the source unit separately |
| | 19 | + const UNITS_REGEX = '/^(.+?)\s*([a-z]+\^?\d?(?:\/\w+\^?\d?)*)$/i'; |
| | 20 | + |
| | 21 | + # A regex which matches a number |
| | 22 | + const NUM_REGEX = '/\b((?:\+|\-|−|\x2212)?(\d+(?:\.\d+)?)(?:E(?:\+|\-|−|\x2212)?\d+)?)\b/i'; |
| | 23 | + |
| | 24 | + # ConvertUnit objects |
| | 25 | + protected $sourceUnit; |
| | 26 | + protected $targetUnit; |
| | 27 | + |
| | 28 | + # Whether to abbreviate the output unit |
| | 29 | + protected $abbreviate; |
| | 30 | + |
| | 31 | + # Whether to link the output unit, if possible |
| | 32 | + protected $link; |
| | 33 | + |
| | 34 | + # If set, don't output the unit or format the number |
| | 35 | + protected $raw; |
| | 36 | + |
| | 37 | + # What precision to round to. |
| | 38 | + protected $decimalPlaces; |
| | 39 | + protected $significantFigures; |
| | 40 | + |
| | 41 | + # The last value converted, which will be used for PLURAL evaluation |
| | 42 | + protected $lastValue; |
| | 43 | + |
| | 44 | + public function clearState(){ |
| | 45 | + # Make sure we break any references set up in the parameter passing below |
| | 46 | + unset( $this->sourceUnit ); |
| | 47 | + unset( $this->targetUnit ); |
| | 48 | + $this->sourceUnit = null; |
| | 49 | + $this->targetUnit = null; |
| | 50 | + |
| | 51 | + $this->lastValue |
| | 52 | + = $this->link |
| | 53 | + = $this->precision |
| | 54 | + = $this->abbreviate |
| | 55 | + = $this->raw |
| | 56 | + = $this->significantFigures |
| | 57 | + = $this->decimalPlaces |
| | 58 | + = null; |
| | 59 | + } |
| | 60 | + |
| | 61 | + /** |
| | 62 | + * Evaluate a convert expression |
| | 63 | + * @param $args Array of the parameters passed to the original tag function |
| | 64 | + * @return String |
| | 65 | + * @throws ConvertError |
| | 66 | + */ |
| | 67 | + public function execute( $args ) { |
| | 68 | + $this->clearState(); |
| | 69 | + array_shift( $args ); # Dump Parser object |
| | 70 | + |
| | 71 | + if( count( $args ) == 0 ){ |
| | 72 | + # that was easy |
| | 73 | + return ''; |
| | 74 | + } |
| | 75 | + $string = trim( array_shift( $args ) ); |
| | 76 | + |
| | 77 | + # Process the rest of the args |
| | 78 | + $sourceUnit =& MagicWord::get( 'sourceunit' ); |
| | 79 | + $targetUnit =& MagicWord::get( 'targetunit' ); |
| | 80 | + $linkUnit =& MagicWord::get( 'linkunit' ); |
| | 81 | + $dp =& MagicWord::get( 'decimalplaces' ); |
| | 82 | + $sf =& MagicWord::get( 'significantfigures' ); |
| | 83 | + $abbr =& MagicWord::get( 'abbreviate' ); |
| | 84 | + $raw =& MagicWord::get( 'rawsuffix' ); |
| | 85 | + |
| | 86 | + $n = 0; # Count of unnamed parameters |
| | 87 | + foreach ( $args as $arg ) { |
| | 88 | + $parts = array_map( 'trim', explode( '=', $arg, 2 ) ); |
| | 89 | + if ( count( $parts ) == 2 ) { |
| | 90 | + # Found "=" |
| | 91 | + if ( $sourceUnit->matchStartAndRemove( $parts[0] ) ) { |
| | 92 | + if( $targetUnit->matchStartAndRemove( $parts[1] ) ){ |
| | 93 | + $this->targetUnit =& $this->sourceUnit; |
| | 94 | + } else { |
| | 95 | + $this->sourceUnit = new ConvertUnit( $parts[1] ); |
| | 96 | + } |
| | 97 | + |
| | 98 | + } elseif ( $targetUnit->matchStartAndRemove( $parts[0] ) ) { |
| | 99 | + if( $sourceUnit->matchStartAndRemove( $parts[1] ) ){ |
| | 100 | + $this->targetUnit =& $this->sourceUnit; |
| | 101 | + } else { |
| | 102 | + $this->targetUnit = new ConvertUnit( $parts[1] ); |
| | 103 | + } |
| | 104 | + |
| | 105 | + } elseif( $dp->matchStartAndRemove( $parts[0] ) ) { |
| | 106 | + $this->decimalPlaces = intval( $parts[1] ); |
| | 107 | + |
| | 108 | + } elseif( $sf->matchStartAndRemove( $parts[0] ) ) { |
| | 109 | + # It doesn't make any sense to have negative sig-figs |
| | 110 | + if( intval( $parts[1] ) > 0 ){ |
| | 111 | + $this->significantFigures = intval( $parts[1] ); |
| | 112 | + } |
| | 113 | + } |
| | 114 | + } elseif( $linkUnit->matchStartAndRemove( $parts[0] ) ) { |
| | 115 | + $this->link = true; |
| | 116 | + } elseif( $abbr->matchStartAndRemove( $parts[0] ) ) { |
| | 117 | + $this->abbreviate = true; |
| | 118 | + } elseif( $raw->matchStartAndRemove( $parts[0] ) ) { |
| | 119 | + $this->raw = true; |
| | 120 | + } elseif( $parts[0] != '' && !$n++ && !$this->targetUnit instanceof ConvertUnit ){ |
| | 121 | + # First unnamed parameter = output unit |
| | 122 | + $this->targetUnit = new ConvertUnit( $parts[0] ); |
| | 123 | + } |
| | 124 | + } |
| | 125 | + |
| | 126 | + # Get the source unit, if not already set. This throws ConvertError on failure |
| | 127 | + if ( !$this->sourceUnit instanceof ConvertUnit ){ |
| | 128 | + $this->deduceSourceUnit( $string ); |
| | 129 | + } |
| | 130 | + |
| | 131 | + # Use the default unit (SI usually) |
| | 132 | + if( !$this->targetUnit instanceof ConvertUnit ){ |
| | 133 | + $this->targetUnit = $this->sourceUnit->getDefaultUnit(); |
| | 134 | + } |
| | 135 | + |
| | 136 | + if( $this->targetUnit->dimension->value != $this->sourceUnit->dimension->value ){ |
| | 137 | + throw new ConvertError( |
| | 138 | + 'dimensionmismatch', |
| | 139 | + $this->sourceUnit->dimension->getName(true), |
| | 140 | + $this->targetUnit->dimension->getName(true) |
| | 141 | + ); |
| | 142 | + } |
| | 143 | + |
| | 144 | + return $this->processString( $string ); |
| | 145 | + } |
| | 146 | + |
| | 147 | + protected function deduceSourceUnit( $string ){ |
| | 148 | + # Get the unit from the end of the string |
| | 149 | + $matches = array(); |
| | 150 | + preg_match( self::UNITS_REGEX, $string, $matches ); |
| | 151 | + |
| | 152 | + if( count( $matches ) == 3 ){ |
| | 153 | + $this->sourceUnit = new ConvertUnit( $matches[2] ); |
| | 154 | + } else { |
| | 155 | + throw new ConvertError( 'nounit' ); |
| | 156 | + } |
| | 157 | + } |
| | 158 | + |
| | 159 | + /** |
| | 160 | + * Identify the values to be converted, and convert them |
| | 161 | + * @param $string String |
| | 162 | + */ |
| | 163 | + protected function processString( $string ){ |
| | 164 | + # Replace values |
| | 165 | + $string = preg_replace_callback( |
| | 166 | + self::NUM_REGEX, |
| | 167 | + array( $this, 'convert' ), |
| | 168 | + trim( preg_replace( self::UNITS_REGEX, '$1', $string ) ) |
| | 169 | + ); |
| | 170 | + if( $this->raw ){ |
| | 171 | + return $string; |
| | 172 | + } else { |
| | 173 | + $unit = $this->targetUnit->getText( |
| | 174 | + $this->lastValue, |
| | 175 | + $this->link, |
| | 176 | + $this->abbreviate |
| | 177 | + ); |
| | 178 | + return "$string $unit"; |
| | 179 | + } |
| | 180 | + } |
| | 181 | + |
| | 182 | + /** |
| | 183 | + * Express a value in the $sourceUnit in terms of the $targetUnit, preserving |
| | 184 | + * an appropriate degree of accuracy. |
| | 185 | + * @param $value String |
| | 186 | + * @return void |
| | 187 | + */ |
| | 188 | + public function convert( $value ){ |
| | 189 | + global $wgContLang; |
| | 190 | + $valueFloat = floatval( $value[1] ); |
| | 191 | + $newValue = $valueFloat |
| | 192 | + * $this->sourceUnit->getConversion() |
| | 193 | + / $this->targetUnit->getConversion(); |
| | 194 | + if( $this->decimalPlaces !== null && $this->significantFigures !== null ){ |
| | 195 | + # round to the required number of decimal places, or the required number |
| | 196 | + # of significant figures, whichever is the least precise |
| | 197 | + $dp = floor( $this->significantFigures - log10( abs( $newValue ) ) ); # Convert SF to DP |
| | 198 | + $newValue = round( $newValue, max( $dp, $this->decimalPlaces ) ); |
| | 199 | + |
| | 200 | + } elseif( $this->decimalPlaces !== null ){ |
| | 201 | + $newValue = round( $newValue, $this->decimalPlaces ); |
| | 202 | + |
| | 203 | + } elseif( $this->significantFigures !== null ){ |
| | 204 | + $dp = floor( $this->significantFigures - log10( abs( $newValue ) ) ); # Convert SF to DP |
| | 205 | + $newValue = round( $newValue, $dp ); |
| | 206 | + |
| | 207 | + } else { |
| | 208 | + # Need to round to a similar accuracy as the original value. To do that we |
| | 209 | + # select the accuracy which will as closely as possible preserve the maximum |
| | 210 | + # percentage error in the value. So 36ft = 36 � 0.5 ft, so the uncertainty |
| | 211 | + # is �0.5/36 = �1.4%. In metres this is 10.9728 � 1.4%, or 10.9728 � 0.154 |
| | 212 | + # we take the stance of choosing the limit which is *more* precise than the |
| | 213 | + # original value. |
| | 214 | + |
| | 215 | + # Strip sign and exponent |
| | 216 | + $num = preg_replace( self::NUM_REGEX, '$2', $value[1] ); |
| | 217 | + |
| | 218 | + if( strpos( $num, '.' ) !== false ){ |
| | 219 | + # If there is a decimal point, this is the number of digits after it. |
| | 220 | + $dpAfter = strlen( $num ) - strpos( $num, '.' ) - 1; |
| | 221 | + $error = pow( 10, -$dpAfter - 1 ) * 5; |
| | 222 | + |
| | 223 | + } elseif( $num == 0 ) { |
| | 224 | + # The logarithms below will be unhappy, and it doesn't actually matter |
| | 225 | + # what error we come up with, zero is still zero |
| | 226 | + $error = 1; |
| | 227 | + |
| | 228 | + } else { |
| | 229 | + # Number of digits before the point |
| | 230 | + $dpBefore = floor( log10( abs( $num ) ) ); |
| | 231 | + |
| | 232 | + # Number of digits if we reverse the string = number |
| | 233 | + # of digits excluding trailing zeros |
| | 234 | + $dpAfter = floor( log10( abs( strrev( $num ) ) ) ); |
| | 235 | + |
| | 236 | + # How many significant figures to consider numbers like "35000" to have |
| | 237 | + # is a tricky question. We say 2 here because if people want to ensure |
| | 238 | + # that the zeros are included, they could write it as 3.500E4 |
| | 239 | + $error = pow( 10, $dpBefore - $dpAfter - 1 ) * 5; |
| | 240 | + } |
| | 241 | + |
| | 242 | + $errorFraction = $error / $num; |
| | 243 | + |
| | 244 | + $i = 10; |
| | 245 | + while( $i > -10 && ( round( $newValue, $i - 1 ) != 0 ) && |
| | 246 | + # Rounding to 10dp avoids floating point errors in exact conversions, |
| | 247 | + # which are on the order of 1E-16 |
| | 248 | + ( round( 5 * pow( 10, -$i ) / round( $newValue, $i - 1 ), 10 ) <= round( $errorFraction, 10 ) ) ) |
| | 249 | + { |
| | 250 | + $i--; |
| | 251 | + } |
| | 252 | + |
| | 253 | + $newValue = round( $newValue, $i ); |
| | 254 | + # We may need to stick significant zeros back onto the number |
| | 255 | + if( $i > 0 ){ |
| | 256 | + if( strpos( $newValue, '.' ) !== false ){ |
| | 257 | + $newValue = str_pad( $newValue, $i + strpos( $newValue, '.' ) + 1, '0' ); |
| | 258 | + } else { |
| | 259 | + $newValue .= '.' . str_repeat( '0', $i ); |
| | 260 | + } |
| | 261 | + } |
| | 262 | + } |
| | 263 | + |
| | 264 | + # Store the last value for use in PLURAL later |
| | 265 | + $this->lastValue = $newValue; |
| | 266 | + |
| | 267 | + return $this->raw |
| | 268 | + ? $newValue |
| | 269 | + : $wgContLang->formatNum( $newValue ); |
| | 270 | + } |
| | 271 | + |
| | 272 | +} |
| | 273 | + |
| | 274 | +/** |
| | 275 | + * A dimension |
| | 276 | + */ |
| | 277 | +class ConvertDimension { |
| | 278 | + |
| | 279 | + const MASS = 1; # KILOGRAM |
| | 280 | + const LENGTH = 10; # METRE |
| | 281 | + const TIME = 100; # SECOND |
| | 282 | + const TEMPERATURE = 1E3; # KELVIN |
| | 283 | + const QUANTITY = 1E4; # MOLE |
| | 284 | + const CURRENT = 1E5; # AMPERE |
| | 285 | + const INTENSITY = 1E6; # CANDELA |
| | 286 | + |
| | 287 | + # fuel efficiencies are ugly and horrible and dimensionally confused, and have the |
| | 288 | + # same dimensions as LENGTH or 1/LENGTH. But someone wanted to include them... so |
| | 289 | + # we have up to ten dimensions which can be identified by values of this. |
| | 290 | + # 0 = sane unit |
| | 291 | + # 1 = some sort of fuel efficiency |
| | 292 | + const UGLY_HACK_VALUE = 1E7; |
| | 293 | + |
| | 294 | + /** |
| | 295 | + * Dimension constants. These are the values you'd get if you added the SI |
| | 296 | + * base units together with the weighting given above, also the output from |
| | 297 | + * getDimensionHash(). Cool thing is, you can add these together to get new |
| | 298 | + * compound dimensions. |
| | 299 | + */ |
| | 300 | + const DIM_DIMENSIONLESS = 0; # Numbers etc |
| | 301 | + const DIM_LENGTH = 10; |
| | 302 | + const DIM_AREA = 20; |
| | 303 | + const DIM_VOLUME = 30; |
| | 304 | + const DIM_TIME = 100; |
| | 305 | + const DIM_TIME_SQ = 200; |
| | 306 | + const DIM_MASS = 1; |
| | 307 | + const DIM_TEMPERATURE = 1000; |
| | 308 | + const DIM_SPEED = -90; # LENGTH / TIME |
| | 309 | + const DIM_ACCELERATION = -190; # LENGTH / TIME_SQ |
| | 310 | + const DIM_FORCE = -189; # MASS * LENGTH / TIME_SQ |
| | 311 | + const DIM_TORQUE = -179; # also MASS * AREA / TIME_SQ, but all units are single |
| | 312 | + const DIM_ENERGY = -179; # MASS * AREA / TIME_SQ, all units are compound |
| | 313 | + const DIM_PRESSURE = -209; # MASS / ( LENGTH * TIME_SQ ) |
| | 314 | + const DIM_POWER = -79; # MASS * AREA / TIME |
| | 315 | + const DIM_DENSITY = -29; # MASS / VOLUME |
| | 316 | + const DIM_FUELEFFICIENCY_PVE = 10000020; # fuel efficiency in VOLUME / LENGTH |
| | 317 | + const DIM_FUELEFFICIENCY_NVE = 99999990; # fuel efficiency in LENGTH / VOLUME |
| | 318 | + |
| | 319 | + # Map of dimension names to message keys. This also serves as a list of what |
| | 320 | + # dimensions will not throw an error when encountered. |
| | 321 | + public static $legalDimensions = array( |
| | 322 | + self::DIM_LENGTH => 'length', |
| | 323 | + self::DIM_AREA => 'area', |
| | 324 | + self::DIM_VOLUME => 'volume', |
| | 325 | + self::DIM_TIME => 'time', |
| | 326 | + self::DIM_TIME_SQ => 'timesquared', |
| | 327 | + self::DIM_MASS => 'mass', |
| | 328 | + self::DIM_TEMPERATURE => 'temperature', |
| | 329 | + self::DIM_SPEED => 'speed', |
| | 330 | + self::DIM_ACCELERATION => 'acceleration', |
| | 331 | + self::DIM_FORCE => 'force', |
| | 332 | + self::DIM_TORQUE => 'torque', |
| | 333 | + self::DIM_ENERGY => 'energy', |
| | 334 | + self::DIM_PRESSURE => 'pressure', |
| | 335 | + self::DIM_POWER => 'power', |
| | 336 | + self::DIM_DENSITY => 'density', |
| | 337 | + self::DIM_FUELEFFICIENCY_PVE => 'fuelefficiencypositive', |
| | 338 | + self::DIM_FUELEFFICIENCY_NVE => 'fuelefficiencynegative', |
| | 339 | + ); |
| | 340 | + |
| | 341 | + public $value; |
| | 342 | + protected $name; |
| | 343 | + |
| | 344 | + public function __construct( $var, $var2=null ){ |
| | 345 | + static $legalDimensionsFlip; |
| | 346 | + |
| | 347 | + if( is_string( $var ) ){ |
| | 348 | + if( $legalDimensionsFlip === null ){ |
| | 349 | + $legalDimensionsFlip = array_flip( self::$legalDimensions ); |
| | 350 | + } |
| | 351 | + if( isset( $legalDimensionsFlip[$var] ) ){ |
| | 352 | + $dim = $legalDimensionsFlip[$var]; |
| | 353 | + } else { |
| | 354 | + # Should be unreachable |
| | 355 | + throw new ConvertError( 'unknowndimension' ); |
| | 356 | + } |
| | 357 | + } elseif( $var instanceof self ){ |
| | 358 | + $dim = $var->value; |
| | 359 | + } else { |
| | 360 | + $dim = intval( $var ); |
| | 361 | + } |
| | 362 | + |
| | 363 | + if( $var2 === null ){ |
| | 364 | + $this->value = $dim; |
| | 365 | + $this->name = $this->compoundName = self::$legalDimensions[$this->value]; |
| | 366 | + |
| | 367 | + } else { |
| | 368 | + if( is_string( $var2 ) ){ |
| | 369 | + if( $legalDimensionsFlip === null ){ |
| | 370 | + $legalDimensionsFlip = array_flip( self::$legalDimensions ); |
| | 371 | + } |
| | 372 | + if( isset( $legalDimensionsFlip[$var2] ) ){ |
| | 373 | + $dim2 = $legalDimensionsFlip[$var2]; |
| | 374 | + } else { |
| | 375 | + # Should be unreachable |
| | 376 | + throw new ConvertError( 'unknowndimension' ); |
| | 377 | + } |
| | 378 | + } elseif( $var2 instanceof self ){ |
| | 379 | + $dim2 = $var2->value; |
| | 380 | + } else { |
| | 381 | + $dim2 = intval( $var2 ); |
| | 382 | + } |
| | 383 | + |
| | 384 | + $this->value = $dim - $dim2; |
| | 385 | + if( in_array( $this->value, array_keys( self::$legalDimensions ) ) ){ |
| | 386 | + $this->name = self::$legalDimensions[$this->value]; |
| | 387 | + $this->compoundName = array( |
| | 388 | + self::$legalDimensions[$var], |
| | 389 | + self::$legalDimensions[$var2], |
| | 390 | + ); |
| | 391 | + } else { |
| | 392 | + # Some combinations of units are fine (carats per bushel is a perfectly good, |
| | 393 | + # if somewhat bizarre, measure of density, for instance). But others (like |
| | 394 | + # carats per miles-per-gallon) are definitely not. |
| | 395 | + # TODO: this allows compound units like <gigawatthours>/<pascal> as a unit |
| | 396 | + # of volume; is that a good thing or a bad thing? |
| | 397 | + throw new ConvertError( 'invalidcompoundunit', "$var/$var2" ); |
| | 398 | + } |
| | 399 | + } |
| | 400 | + } |
| | 401 | + |
| | 402 | + /** |
| | 403 | + * Convert to string. Magic in PHP 5.1 and above. |
| | 404 | + * @return String |
| | 405 | + */ |
| | 406 | + public function __toString(){ |
| | 407 | + return strval( $this->name ); |
| | 408 | + } |
| | 409 | + |
| | 410 | + /** |
| | 411 | + * Get the name, or names, of the dimension |
| | 412 | + * @return String|Array of String |
| | 413 | + */ |
| | 414 | + public function getName( $expandCompound = false ){ |
| | 415 | + return $expandCompound |
| | 416 | + ? $this->name |
| | 417 | + : $this->compoundName; |
| | 418 | + } |
| | 419 | + |
| | 420 | + /** |
| | 421 | + * Get the localised name of the dimension. Output is unescaped |
| | 422 | + * @return String |
| | 423 | + */ |
| | 424 | + public function getLocalisedName(){ |
| | 425 | + return wfMsg( "pfunc-convert-dimension-{$this->name}" ); |
| | 426 | + } |
| | 427 | + |
| | 428 | +} |
| | 429 | + |
| | 430 | +class ConvertUnit { |
| | 431 | + |
| | 432 | + /** |
| | 433 | + * array( |
| | 434 | + * DIMENSION => array( |
| | 435 | + * UNIT => array( |
| | 436 | + * CONVERSION, |
| | 437 | + * REGEX |
| | 438 | + * ) |
| | 439 | + * ) |
| | 440 | + * ) |
| | 441 | + */ |
| | 442 | + protected static $units = array( |
| | 443 | + ConvertDimension::DIM_LENGTH => array( |
| | 444 | + 'gigametre' => array( 1000000000, 'Gm' ), |
| | 445 | + 'megametre' => array( 1000000, '(?:(?-i)Mm)' ), # Case-sensitivity is forced |
| | 446 | + 'kilometre' => array( 1000, 'km' ), |
| | 447 | + 'hectometre' => array( 100, 'hm' ), |
| | 448 | + 'decametre' => array( 10, 'dam' ), |
| | 449 | + 'metre' => array( 1, 'm' ), |
| | 450 | + 'decimetre' => array( 0.1, 'dm' ), |
| | 451 | + 'centimetre' => array( 0.01, 'cm' ), |
| | 452 | + 'millimetre' => array( 0.001, '(?:(?-i)mm)' ), # Case-sensitivity is forced |
| | 453 | + 'micrometre' => array( 0.0001, '\x03BCm|\x00B5m|um' ), # There are two similar mu characters |
| | 454 | + 'nanometre' => array( 0.0000001, 'nm' ), |
| | 455 | + 'angstrom' => array( 0.00000001, '\x00C5' ), |
| | 456 | + |
| | 457 | + 'mile' => array( 1609.344, 'mi|miles?' ), |
| | 458 | + 'furlong' => array( 201.168, 'furlong' ), |
| | 459 | + 'chain' => array( 20.1168 , 'chain' ), |
| | 460 | + 'rod' => array( 5.0292, 'rod|pole|perch' ), |
| | 461 | + 'fathom' => array( 1.8288, 'fathom' ), |
| | 462 | + 'yard' => array( 0.9144, 'yards?|yd' ), |
| | 463 | + 'foot' => array( 0.3048, 'foot|feet|ft' ), |
| | 464 | + 'hand' => array( 0.1016, 'hands?' ), |
| | 465 | + 'inch' => array( 0.0254, 'inch|inches|in' ), |
| | 466 | + |
| | 467 | + 'nauticalmile' => array( 1852, 'nauticalmiles?|nmi' ), |
| | 468 | + 'nauticalmileuk' => array( 1853.184, 'oldUKnmi|Brnmi|admi' ), |
| | 469 | + 'nauticalmileus' => array( 1853.24496, 'oldUSnmi' ), |
| | 470 | + |
| | 471 | + 'gigaparsec' => array( 3.0856775813057E25, 'gigaparsecs?|Gpc' ), |
| | 472 | + 'megaparsec' => array( 3.0856775813057E22, 'megaparsecs?|Mpc' ), |
| | 473 | + 'kiloparsec' => array( 3.0856775813057E19, 'kiloparsecs?|kpc' ), |
| | 474 | + 'parsec' => array( 3.0856775813057E16, 'parsecs?|pc' ), |
| | 475 | + 'gigalightyear' => array( 9.4607304725808E24, 'gigalightyears?|Gly' ), |
| | 476 | + 'mrgalightyear' => array( 9.4607304725808E21, 'megalightyears?|Mly' ), |
| | 477 | + 'kilolightyear' => array( 9.4607304725808E18, 'kilolightyears?|kly' ), |
| | 478 | + 'lightyear' => array( 9.4607304725808E15, 'lightyears?|ly' ), |
| | 479 | + 'astronomicalunit' => array( 149597870700, 'astronomicalunits?|AU' ), |
| | 480 | + ), |
| | 481 | + |
| | 482 | + ConvertDimension::DIM_AREA => array( |
| | 483 | + 'squarekilometre' => array( 1E6, 'km2|km\^2' ), |
| | 484 | + 'squaremetre' => array( 1, 'm2|m\^2' ), |
| | 485 | + 'squarecentimetre' => array( 1E-4, 'cm2|cm\^2' ), |
| | 486 | + 'squaremillimetre' => array( 1E-6, 'mm2|mm\^2' ), |
| | 487 | + 'hectare' => array( 1E4, 'hectares?|ha' ), |
| | 488 | + |
| | 489 | + 'squaremile' => array( 2589988.110336, 'sqmi|mi2|mi\^2' ), |
| | 490 | + 'acre' => array( 4046.856422 , 'acres?' ), |
| | 491 | + 'squareyard' => array( 0.83612736, 'sqyd|yd2|yd\^2' ), |
| | 492 | + 'squarefoot' => array( 0.09290304, 'sqft|ft2|ft\^2' ), |
| | 493 | + 'squareinch' => array( 0.00064516, 'sqin|in2|in\^2' ), |
| | 494 | + |
| | 495 | + 'squarenauticalmile' => array( 3429904, 'sqnmi|nmi2|nmi\^2' ), |
| | 496 | + 'dunam' => array( 1000, 'dunam' ), |
| | 497 | + 'tsubo' => array( 3.305785, 'tsubo' ), |
| | 498 | + ), |
| | 499 | + |
| | 500 | + ConvertDimension::DIM_VOLUME => array( |
| | 501 | + 'cubicmetre' => array( 1, 'm3|m\^3' ), |
| | 502 | + 'cubiccentimetre' => array( 1E-6, 'cm3|cm\^3' ), |
| | 503 | + 'cubicmillimetre' => array( 1E-9, 'mm3|mm\^3' ), |
| | 504 | + 'kilolitre' => array( 1, 'kl' ), |
| | 505 | + 'litre' => array( 1E-3 , 'l' ), |
| | 506 | + 'centilitre' => array( 1E-5, 'cl' ), |
| | 507 | + 'millilitre' => array( 1E-6, 'ml' ), |
| | 508 | + |
| | 509 | + 'cubicyard' => array( 0.764554857984, 'cuyd|yd3|yd\^3' ), |
| | 510 | + 'cubicfoot' => array( 0.028316846592, 'cuft|ft3|ft\^3' ), |
| | 511 | + 'cubicinch' => array( 0.000016387064, 'cuin|in3|in\^3' ), |
| | 512 | + 'barrel' => array( 0.16365924, 'bbl|barrels?|impbbl' ), |
| | 513 | + 'bushel' => array( 0.03636872, 'bsh|bushels?|impbsh' ), |
| | 514 | + 'gallon' => array( 0.00454609, 'gal|gallons?|impgal' ), |
| | 515 | + 'quart' => array( 0.0011365225, 'qt|quarts?|impqt' ), |
| | 516 | + 'pint' => array( 0.00056826125, 'pt|pints?|imppt' ), |
| | 517 | + 'fluidounce' => array( 0.0000284130625, 'floz|impfloz' ), |
| | 518 | + |
| | 519 | + 'barrelus' => array( 0.119240471196, 'usbbl' ), |
| | 520 | + 'barreloil' => array( 0.158987294928, 'oilbbl' ), |
| | 521 | + 'barrelbeer' => array( 0.117347765304, 'beerbbl' ), |
| | 522 | + 'usgallon' => array( 0.003785411784, 'usgal' ), |
| | 523 | + 'usquart' => array( 0.000946352946, 'usqt' ), |
| | 524 | + 'uspint' => array( 0.000473176473, 'uspt' ), |
| | 525 | + 'usfluidounce' => array( 0.0000295735295625, 'usfloz' ), |
| | 526 | + 'usdrybarrel' => array( 0.11562819898508, 'usdrybbl' ), |
| | 527 | + 'usbushel' => array( 0.03523907016688, 'usbsh' ), |
| | 528 | + 'usdrygallon' => array( 0.00440488377086, 'usdrygal' ), |
| | 529 | + 'usdryquart' => array( 0.001101220942715, 'usdryqt' ), |
| | 530 | + 'usdrypint' => array( 0.0005506104713575, 'usdrypt' ), |
| | 531 | + ), |
| | 532 | + |
| | 533 | + ConvertDimension::DIM_TIME => array( |
| | 534 | + 'year' => array( 31557600, 'yr' ), |
| | 535 | + 'day' => array( 86400, 'days?' ), |
| | 536 | + 'hour' => array( 3600, 'hours?|hr|h' ), |
| | 537 | + 'minute' => array( 60, 'minutes?|mins?' ), |
| | 538 | + 'second' => array( 1, 's' ), |
| | 539 | + ), |
| | 540 | + |
| | 541 | + ConvertDimension::DIM_SPEED => array( |
| | 542 | + 'knot' => array( 0.514444444, 'knot|kn' ), |
| | 543 | + 'speedoflight' => array( 2.9979E8, 'c' ), |
| | 544 | + ), |
| | 545 | + |
| | 546 | + ConvertDimension::DIM_PRESSURE => array( |
| | 547 | + 'gigapascal' => array( 1000000000, 'GPa' ), |
| | 548 | + 'megapascal' => array( 1000000, '(?:(?-i)M[Pp]a)' ), # Case-sensitivity is forced |
| | 549 | + 'kilopascal' => array( 1000, 'kPa' ), |
| | 550 | + 'hectopascal' => array( 100, 'hPa' ), |
| | 551 | + 'pascal' => array( 1, 'Pa' ), |
| | 552 | + 'millipascal' => array( 0.001, '(?:(?-i)m[Pp]a)' ), # Case-sensitivity is forced |
| | 553 | + |
| | 554 | + 'bar' => array( 100000, 'bar' ), |
| | 555 | + 'decibar' => array( 10000, 'dbar' ), |
| | 556 | + 'milibar' => array( 100 , 'mbar|mb' ), |
| | 557 | + 'kilobarye' => array( 100, 'kba' ), |
| | 558 | + 'barye' => array( 0.1, 'ba' ), |
| | 559 | + |
| | 560 | + 'atmosphere' => array( 101325, 'atm|atmospheres?' ), |
| | 561 | + 'torr' => array( 133.32237, 'torr' ), |
| | 562 | + 'mmhg' => array( 133.322387415, 'mmHg' ), |
| | 563 | + 'inhg' => array( 3386.38864034, 'inHg' ), |
| | 564 | + 'psi' => array( 6894.757293, 'psi' ), |
| | 565 | + ), |
| | 566 | + # TODO: other dimensions as needed |
| | 567 | + ); |
| | 568 | + |
| | 569 | + # Default units for each dimension |
| | 570 | + # TODO: this should ideally be localisable |
| | 571 | + protected static $defaultUnit = array( |
| | 572 | + ConvertDimension::DIM_LENGTH => 'metre', |
| | 573 | + ConvertDimension::DIM_AREA => 'squaremetre', |
| | 574 | + ConvertDimension::DIM_VOLUME => 'cubicmetre', |
| | 575 | + ConvertDimension::DIM_TIME => 'second', |
| | 576 | + ConvertDimension::DIM_SPEED => 'metre/second', |
| | 577 | + ConvertDimension::DIM_PRESSURE => 'pascal', |
| | 578 | + ); |
| | 579 | + |
| | 580 | + # An array of preprocessing conversions to apply to units |
| | 581 | + protected static $unitConversions = array( |
| | 582 | + '/^mph$/ui' => 'mi/h', |
| | 583 | + ); |
| | 584 | + |
| | 585 | + # Map of UNIT => DIMENSION, created on construct |
| | 586 | + protected static $dimensionMap = false; |
| | 587 | + |
| | 588 | + /***************** MEMBER VARIABLES *****************/ |
| | 589 | + |
| | 590 | + # @var ConvertDimension |
| | 591 | + public $dimension; |
| | 592 | + |
| | 593 | + # What number you need to multiply this unit by to get the equivalent |
| | 594 | + # value in SI base units |
| | 595 | + protected $conversion = 1; |
| | 596 | + |
| | 597 | + # A regex which matches the unit |
| | 598 | + protected $regex; |
| | 599 | + |
| | 600 | + # The name of the unit (key into $units[$dimension] above |
| | 601 | + protected $unitName; |
| | 602 | + |
| | 603 | + /***************** MEMBER FUNCTIONS *****************/ |
| | 604 | + |
| | 605 | + /** |
| | 606 | + * Constructor |
| | 607 | + * @param $rawUnit String |
| | 608 | + */ |
| | 609 | + public function __construct( $rawUnit ){ |
| | 610 | + if( self::$dimensionMap === false ){ |
| | 611 | + self::$dimensionMap = array(); |
| | 612 | + foreach( self::$units as $dimension => $arr ){ |
| | 613 | + foreach( $arr as $unit => $val ){ |
| | 614 | + self::$dimensionMap[$unit] = $dimension; |
| | 615 | + } |
| | 616 | + } |
| | 617 | + } |
| | 618 | + |
| | 619 | + $this->parseUnit( $rawUnit ); |
| | 620 | + } |
| | 621 | + |
| | 622 | + protected function parseUnit( $rawUnit ){ |
| | 623 | + |
| | 624 | + # Do mappings like 'mph' --> 'mi/h' |
| | 625 | + $rawUnit = preg_replace( |
| | 626 | + array_keys( self::$unitConversions ), |
| | 627 | + array_values( self::$unitConversions ), |
| | 628 | + $rawUnit |
| | 629 | + ); |
| | 630 | + |
| | 631 | + $parts = explode( '/', $rawUnit ); |
| | 632 | + array_map( 'trim', $parts ); |
| | 633 | + if( count( $parts ) == 1 ){ |
| | 634 | + # Single unit |
| | 635 | + foreach( self::$units as $dimension => $units ){ |
| | 636 | + foreach( $units as $unit => $data ){ |
| | 637 | + if( $rawUnit == $unit || preg_match( "/^({$data[1]})$/ui", $parts[0] ) ){ |
| | 638 | + $this->dimension = new ConvertDimension( self::$dimensionMap[$unit] ); |
| | 639 | + $this->conversion = self::$units[$this->dimension->value][$unit][0]; |
| | 640 | + $this->regex = $data[1]; |
| | 641 | + $this->unitName = $unit; |
| | 642 | + return; |
| | 643 | + } |
| | 644 | + } |
| | 645 | + } |
| | 646 | + |
| | 647 | + # Unknown unit |
| | 648 | + throw new ConvertError( 'unknownunit', $rawUnit ); |
| | 649 | + |
| | 650 | + } elseif( count( $parts ) == 2 ){ |
| | 651 | + # Compound unit. |
| | 652 | + $top = new self( $parts[0] ); |
| | 653 | + $bottom = new self( $parts[1] ); |
| | 654 | + $this->dimension = new ConvertDimension( $top->dimension, $bottom->dimension ); |
| | 655 | + $this->conversion = $top->conversion / $bottom->conversion; |
| | 656 | + $this->regex = "(?:{$top->regex})/(?:{$bottom->regex})"; |
| | 657 | + $this->unitName = array( $top->unitName, $bottom->unitName ); |
| | 658 | + return; |
| | 659 | + |
| | 660 | + } else { |
| | 661 | + # Whaaat? Too many parts |
| | 662 | + throw new ConvertError( 'doublecompoundunit', $rawUnit ); |
| | 663 | + } |
| | 664 | + } |
| | 665 | + |
| | 666 | + public function getConversion(){ |
| | 667 | + return $this->conversion; |
| | 668 | + } |
| | 669 | + |
| | 670 | + public function getRegex(){ |
| | 671 | + return $this->regex; |
| | 672 | + } |
| | 673 | + |
| | 674 | + /** |
| | 675 | + * Get the text of the unit |
| | 676 | + * @param $value String number for PLURAL support |
| | 677 | + * @param $link Bool |
| | 678 | + * @return String |
| | 679 | + */ |
| | 680 | + public function getText( $value, $link=false, $abbreviate=false ){ |
| | 681 | + global $wgContLang; |
| | 682 | + $value = $wgContLang->formatNum( $value ); |
| | 683 | + $abbr = $abbreviate ? '-abbr' : ''; |
| | 684 | + |
| | 685 | + if( !is_array( $this->unitName ) ){ |
| | 686 | + $msg = "pfunc-convert-unit-{$this->dimension->getName()}-{$this->unitName}"; |
| | 687 | + $msgText = wfMsgExt( "$msg$abbr", array( 'parsemag', 'content' ), $value ); |
| | 688 | + if( $link && !wfEmptyMsg( "$msg-link" ) ){ |
| | 689 | + $title = Title::newFromText( wfMsgForContentNoTrans( "$msg-link" ) ); |
| | 690 | + $msgText = "[[{$title->getFullText()}|$msgText]]"; |
| | 691 | + } |
| | 692 | + |
| | 693 | + } elseif( !wfEmptyMsg( "pfunc-convert-unit-{$this->dimension->getName(true)}-{$this->unitName[0]}-{$this->unitName[1]}" ) ){ |
| | 694 | + # A wiki has created, say, [[MediaWiki:pfunc-convert-unit-speed-metres-second]] |
| | 695 | + # so they can have it display "<metres per second>" rather than |
| | 696 | + # "<metres>/<second>" |
| | 697 | + $msg = "pfunc-convert-unit-{$this->dimension->getName(true)}-{$this->unitName[0]}-{$this->unitName[1]}"; |
| | 698 | + $msgText = wfMsgExt( "$msg$abbr", array( 'parsemag', 'content' ), $value ); |
| | 699 | + if( $link && !wfEmptyMsg( "$msg-link" ) ){ |
| | 700 | + $title = Title::newFromText( wfMsgForContentNoTrans( "$msg-link" ) ); |
| | 701 | + if( $title instanceof Title ){ |
| | 702 | + $msgText = "[[$title|$msgText]]"; |
| | 703 | + } |
| | 704 | + } |
| | 705 | + |
| | 706 | + } else { |
| | 707 | + $dimensionNames = $this->dimension->getName(); |
| | 708 | + $msg = "pfunc-convert-unit-{$dimensionNames[0]}-{$this->unitName[0]}"; |
| | 709 | + $msgText = wfMsgExt( "$msg$abbr", array( 'parsemag', 'content' ), $value ); |
| | 710 | + if( $link && !wfEmptyMsg( "$msg-link" ) ){ |
| | 711 | + $title = Title::newFromText( wfMsgForContentNoTrans( "$msg-link" ) ); |
| | 712 | + $msgText = "[[{$title->getFullText()}|$msgText]]"; |
| | 713 | + } |
| | 714 | + |
| | 715 | + $msg2 = "pfunc-convert-unit-{$dimensionNames[1]}-{$this->unitName[1]}"; |
| | 716 | + $msg2Text = wfMsgExt( "$msg2$abbr", array( 'parsemag', 'content' ), 1 ); # Singular for denominator |
| | 717 | + if( $link && !wfEmptyMsg( "$msg2-link" ) ){ |
| | 718 | + $title = Title::newFromText( wfMsgForContentNoTrans( "$msg2-link" ) ); |
| | 719 | + if( $title instanceof Title ){ |
| | 720 | + $msg2Text = "[[{$title->getFullText()}|$msg2Text]]"; |
| | 721 | + } |
| | 722 | + } |
| | 723 | + $msgText = "$msgText/$msg2Text"; |
| | 724 | + } |
| | 725 | + |
| | 726 | + return $msgText; |
| | 727 | + } |
| | 728 | + |
| | 729 | + /** |
| | 730 | + * Get the default (usually SI) unit associated with this particular dimension |
| | 731 | + * @return ConvertUnit |
| | 732 | + */ |
| | 733 | + public function getDefaultUnit(){ |
| | 734 | + return new ConvertUnit( self::$defaultUnit[$this->dimension->value] ); |
| | 735 | + } |
| | 736 | +} |
| Property changes on: trunk/extensions/ParserFunctions/Convert.php |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| 1 | 737 | + native |
| Index: trunk/extensions/ParserFunctions/ParserFunctions.i18n.magic.php |
| — | — | @@ -22,6 +22,13 @@ |
| 23 | 23 | 'timel' => array( 0, 'timel' ), |
| 24 | 24 | 'rel2abs' => array( 0, 'rel2abs' ), |
| 25 | 25 | 'titleparts' => array( 0, 'titleparts' ), |
| | 26 | + 'convert' => array( 0, 'convert' ), |
| | 27 | + 'sourceunit' => array( 0, '#sourceunit' ), |
| | 28 | + 'targetunit' => array( 0, '#targetunit' ), |
| | 29 | + 'linkunit' => array( 0, '#linkunit' ), |
| | 30 | + 'decimalplaces' => array( 0, '#dp' ), |
| | 31 | + 'significantfigures' => array( 0, '#sf' ), |
| | 32 | + 'abbreviate' => array( 0, '#abbreviate' ), |
| 26 | 33 | 'len' => array( 0, 'len' ), |
| 27 | 34 | 'pos' => array( 0, 'pos' ), |
| 28 | 35 | 'rpos' => array( 0, 'rpos' ), |
| Index: trunk/extensions/ParserFunctions/ParserFunctions_body.php |
| — | — | @@ -512,6 +512,29 @@ |
| 513 | 513 | } |
| 514 | 514 | } |
| 515 | 515 | |
| | 516 | + /** |
| | 517 | + * Get a ConvertParser object |
| | 518 | + * @return ConvertParser |
| | 519 | + */ |
| | 520 | + protected function &getConvertParser() { |
| | 521 | + if ( !isset( $this->mConvertParser ) ) { |
| | 522 | + if ( !class_exists( 'ConvertParser' ) ) { |
| | 523 | + require( dirname( __FILE__ ) . '/Convert.php' ); |
| | 524 | + } |
| | 525 | + $this->mConvertParser = new ConvertParser; |
| | 526 | + } |
| | 527 | + return $this->mConvertParser; |
| | 528 | + } |
| | 529 | + |
| | 530 | + public function convert( /*...*/ ) { |
| | 531 | + try { |
| | 532 | + $args = func_get_args(); |
| | 533 | + return $this->getConvertParser()->execute( $args ); |
| | 534 | + } catch ( ConvertError $e ) { |
| | 535 | + return $e->getMessage(); |
| | 536 | + } |
| | 537 | + } |
| | 538 | + |
| 516 | 539 | // Verifies parameter is less than max string length. |
| 517 | 540 | private function checkLength( $text ) { |
| 518 | 541 | global $wgPFStringLengthLimit; |
| Index: trunk/extensions/ParserFunctions/ParserFunctions.i18n.php |
| — | — | @@ -27,7 +27,244 @@ |
| 28 | 28 | 'pfunc_expr_invalid_argument_ln' => 'Invalid argument for ln: <= 0', |
| 29 | 29 | 'pfunc_expr_unknown_error' => 'Expression error: Unknown error ($1)', |
| 30 | 30 | 'pfunc_expr_not_a_number' => 'In $1: result is not a number', |
| 31 | | - 'pfunc_string_too_long' => 'Error: String exceeds $1 character limit', |
| | 31 | + 'pfunc_string_too_long' => 'Error: string exceeds $1 character limit', |
| | 32 | + 'pfunc-convert-dimensionmismatch' => 'Error: cannot convert between units of "$1" and "$2"', |
| | 33 | + 'pfunc-convert-unknownunit' => 'Error: unknown unit "$1"', |
| | 34 | + 'pfunc-convert-unknowndimension' => 'Error: unknown dimension "$1"', |
| | 35 | + 'pfunc-convert-invalidcompoundunit' => 'Error: invalid compound unit "$1"', |
| | 36 | + 'pfunc-convert-nounit' => 'Error: no source unit given', |
| | 37 | + 'pfunc-convert-doublecompoundunit' => 'Error: cannot parse double compound units like "$1"', |
| | 38 | + |
| | 39 | + # DIMENSION NAMES |
| | 40 | + 'pfunc-convert-dimension-length' => 'length', |
| | 41 | + 'pfunc-convert-dimension-area' => 'area', |
| | 42 | + 'pfunc-convert-dimension-volume' => 'volume', |
| | 43 | + 'pfunc-convert-dimension-time' => 'time', |
| | 44 | + 'pfunc-convert-dimension-timesquared' => 'time<sup>2</sup>', |
| | 45 | + 'pfunc-convert-dimension-mass' => 'mass', |
| | 46 | + 'pfunc-convert-dimension-speed' => 'speed', |
| | 47 | + 'pfunc-convert-dimension-temperature' => 'temperature', |
| | 48 | + 'pfunc-convert-dimension-acceleration' => 'acceleration', |
| | 49 | + 'pfunc-convert-dimension-force' => 'force', |
| | 50 | + 'pfunc-convert-dimension-torque' => 'torque', |
| | 51 | + 'pfunc-convert-dimension-energy' => 'energy', |
| | 52 | + 'pfunc-convert-dimension-power' => 'power', |
| | 53 | + 'pfunc-convert-dimension-pressure' => 'pressure', |
| | 54 | + 'pfunc-convert-dimension-density' => 'density', |
| | 55 | + 'pfunc-convert-dimension-fuelefficiencypositive' => 'fuelefficiencypositive', |
| | 56 | + 'pfunc-convert-dimension-fuelefficiencynegative' => 'fuelefficiencynegative', |
| | 57 | + |
| | 58 | + # LENGTH |
| | 59 | + 'pfunc-convert-unit-length-gigametre' => '{{PLURAL:$1|gigametre|gigametres}}', |
| | 60 | + 'pfunc-convert-unit-length-megametre' => '{{PLURAL:$1|megametre|megametres}}', |
| | 61 | + 'pfunc-convert-unit-length-kilometre' => '{{PLURAL:$1|kilometre|kilometres}}', |
| | 62 | + 'pfunc-convert-unit-length-hectometre' => '{{PLURAL:$1|hectometre|hectometres}}', |
| | 63 | + 'pfunc-convert-unit-length-decametre' => '{{PLURAL:$1|decametre|decametres}}', |
| | 64 | + 'pfunc-convert-unit-length-metre' => '{{PLURAL:$1|metre|metres}}', |
| | 65 | + 'pfunc-convert-unit-length-decimetre' => '{{PLURAL:$1|decimetre|decimetres}}', |
| | 66 | + 'pfunc-convert-unit-length-centimetre' => '{{PLURAL:$1|centimetre|centimetres}}', |
| | 67 | + 'pfunc-convert-unit-length-millimetre' => '{{PLURAL:$1|millimetre|millimetres}}', |
| | 68 | + 'pfunc-convert-unit-length-micrometre' => '{{PLURAL:$1|micrometre|micrometres}}', |
| | 69 | + 'pfunc-convert-unit-length-nanometre' => '{{PLURAL:$1|nanometre|nanometres}}', |
| | 70 | + 'pfunc-convert-unit-length-angstrom' => '{{PLURAL:$1|angstrom|angstroms}}', |
| | 71 | + 'pfunc-convert-unit-length-mile' => '{{PLURAL:$1|mile|miles}}', |
| | 72 | + 'pfunc-convert-unit-length-furlong' => '{{PLURAL:$1|furlong|furlongs}}', |
| | 73 | + 'pfunc-convert-unit-length-chain' => '{{PLURAL:$1|chain|chains}}', |
| | 74 | + 'pfunc-convert-unit-length-rod' => '{{PLURAL:$1|rod|rods}}', |
| | 75 | + 'pfunc-convert-unit-length-fathom' => '{{PLURAL:$1|fathom|fathoms}}', |
| | 76 | + 'pfunc-convert-unit-length-yard' => '{{PLURAL:$1|yard|yards}}', |
| | 77 | + 'pfunc-convert-unit-length-foot' => '{{PLURAL:$1|foot|feet}}', |
| | 78 | + 'pfunc-convert-unit-length-hand' => '{{PLURAL:$1|hand|hands}}', |
| | 79 | + 'pfunc-convert-unit-length-inch' => '{{PLURAL:$1|inch|inches}}', |
| | 80 | + 'pfunc-convert-unit-length-nauticalmile' => '{{PLURAL:$1|nautical mile|nautical miles}}', |
| | 81 | + 'pfunc-convert-unit-length-nauticalmileuk' => '{{PLURAL:$1|nautical mile (pre-1970 British)|nautical miles (pre-1970 British)}}', |
| | 82 | + 'pfunc-convert-unit-length-nauticalmileus' => '{{PLURAL:$1|nautical mile (pre-1954 US)|nautical miles (pre-1954 US)}}', |
| | 83 | + 'pfunc-convert-unit-length-gigaparsec' => '{{PLURAL:$1|gigaparsec|gigaparsecs}}', |
| | 84 | + 'pfunc-convert-unit-length-megaparsec' => '{{PLURAL:$1|megaparsec|megaparsecs}}', |
| | 85 | + 'pfunc-convert-unit-length-kiloparsec' => '{{PLURAL:$1|kiloparsec|kiloparsecs}}', |
| | 86 | + 'pfunc-convert-unit-length-parsec' => '{{PLURAL:$1|parsec|parsecs}}', |
| | 87 | + 'pfunc-convert-unit-length-gigalightyear' => '{{PLURAL:$1|gigalightyear|gigalightyears}}', |
| | 88 | + 'pfunc-convert-unit-length-mrgalightyear' => '{{PLURAL:$1|megalightyear|megalightyears}}', |
| | 89 | + 'pfunc-convert-unit-length-kilolightyear' => '{{PLURAL:$1|kilolightyear|kilolightyears}}', |
| | 90 | + 'pfunc-convert-unit-length-lightyear' => '{{PLURAL:$1|lightyear|lightyears}}', |
| | 91 | + 'pfunc-convert-unit-length-astronomicalunit' => '{{PLURAL:$1|astronomical unit|astronomical units}}', |
| | 92 | + |
| | 93 | + 'pfunc-convert-unit-length-gigametre-abbr' => 'Gm', |
| | 94 | + 'pfunc-convert-unit-length-megametre-abbr' => 'Mm', |
| | 95 | + 'pfunc-convert-unit-length-kilometre-abbr' => 'km', |
| | 96 | + 'pfunc-convert-unit-length-hectometre-abbr' => 'hm', |
| | 97 | + 'pfunc-convert-unit-length-decametre-abbr' => 'dam', |
| | 98 | + 'pfunc-convert-unit-length-metre-abbr' => 'm', |
| | 99 | + 'pfunc-convert-unit-length-decimetre-abbr' => 'dm', |
| | 100 | + 'pfunc-convert-unit-length-centimetre-abbr' => 'cm', |
| | 101 | + 'pfunc-convert-unit-length-milimetre-abbr' => 'mm', |
| | 102 | + 'pfunc-convert-unit-length-micrometre-abbr' => 'μm', |
| | 103 | + 'pfunc-convert-unit-length-nanometre-abbr' => 'nm', |
| | 104 | + 'pfunc-convert-unit-length-angstrom-abbr' => 'Å', |
| | 105 | + 'pfunc-convert-unit-length-mile-abbr' => 'mi', |
| | 106 | + 'pfunc-convert-unit-length-furlong-abbr' => 'furlong', |
| | 107 | + 'pfunc-convert-unit-length-chain-abbr' => 'chain', |
| | 108 | + 'pfunc-convert-unit-length-rod-abbr' => 'rd', |
| | 109 | + 'pfunc-convert-unit-length-fathom-abbr' => 'fathom', |
| | 110 | + 'pfunc-convert-unit-length-yard-abbr' => 'yd', |
| | 111 | + 'pfunc-convert-unit-length-foot-abbr' => 'ft', |
| | 112 | + 'pfunc-convert-unit-length-hand-abbr' => 'h', |
| | 113 | + 'pfunc-convert-unit-length-inch-abbr' => 'in', |
| | 114 | + 'pfunc-convert-unit-length-nauticalmile-abbr' => 'nmi', |
| | 115 | + 'pfunc-convert-unit-length-nauticalmileuk-abbr' => 'nmi (Brit)', |
| | 116 | + 'pfunc-convert-unit-length-nauticalmileus-abbr' => 'nmi (pre-1954 US)', |
| | 117 | + 'pfunc-convert-unit-length-gigaparsec-abbr' => 'Gpc', |
| | 118 | + 'pfunc-convert-unit-length-megaparsec-abbr' => 'Mpc', |
| | 119 | + 'pfunc-convert-unit-length-kiloparsec-abbr' => 'kpc', |
| | 120 | + 'pfunc-convert-unit-length-parsec-abbr' => 'pc', |
| | 121 | + 'pfunc-convert-unit-length-gigalightyear-abbr' => 'Gly', |
| | 122 | + 'pfunc-convert-unit-length-mrgalightyear-abbr' => 'Mly', |
| | 123 | + 'pfunc-convert-unit-length-kilolightyear-abbr' => 'kly', |
| | 124 | + 'pfunc-convert-unit-length-lightyear-abbr' => 'ly', |
| | 125 | + 'pfunc-convert-unit-length-astronomicalunit-abbr' => 'AU', |
| | 126 | + |
| | 127 | + # AREA # |
| | 128 | + 'pfunc-convert-unit-area-squarekilometre' => '{{PLURAL:$1|square kilometre|square kilometres}}', |
| | 129 | + 'pfunc-convert-unit-area-squaremetre' => '{{PLURAL:$1|square metre|square metres}}', |
| | 130 | + 'pfunc-convert-unit-area-squarecentimetre' => '{{PLURAL:$1|square centimetre|square centimetres}}', |
| | 131 | + 'pfunc-convert-unit-area-squaremillimetre' => '{{PLURAL:$1|square millimetre|square millimetres}}', |
| | 132 | + 'pfunc-convert-unit-area-hectare' => '{{PLURAL:$1|hectare|hectares}}', |
| | 133 | + 'pfunc-convert-unit-area-squaremile' => '{{PLURAL:$1|square mile|square miles}}', |
| | 134 | + 'pfunc-convert-unit-area-acre' => '{{PLURAL:$1|acre|acres}}', |
| | 135 | + 'pfunc-convert-unit-area-squareyard' => '{{PLURAL:$1|square yard|square yards}}', |
| | 136 | + 'pfunc-convert-unit-area-squarefoot' => '{{PLURAL:$1|square foot|square feet}}', |
| | 137 | + 'pfunc-convert-unit-area-squareinch' => '{{PLURAL:$1|square inch|square inches}}', |
| | 138 | + 'pfunc-convert-unit-area-squarenauticalmile' => '{{PLURAL:$1|square nautical mile|square nautical miles}}', |
| | 139 | + 'pfunc-convert-unit-area-dunam' => '{{PLURAL:$1|dunam|dunams}}', |
| | 140 | + 'pfunc-convert-unit-area-tsubo' => '{{PLURAL:$1|tsubo|tsubo}}', |
| | 141 | + |
| | 142 | + 'pfunc-convert-unit-area-squarekilometre-abbr' => 'km<sup>2</sup>', |
| | 143 | + 'pfunc-convert-unit-area-squaremetre-abbr' => 'm<sup>2</sup>', |
| | 144 | + 'pfunc-convert-unit-area-squarecentimetre-abbr' => 'cm<sup>2</sup>', |
| | 145 | + 'pfunc-convert-unit-area-squaremillimetre-abbr' => 'mm<sup>2</sup>', |
| | 146 | + 'pfunc-convert-unit-area-hectare-abbr' => 'ha', |
| | 147 | + 'pfunc-convert-unit-area-squaremile-abbr' => 'sq mi', |
| | 148 | + 'pfunc-convert-unit-area-acre-abbr' => 'acre', |
| | 149 | + 'pfunc-convert-unit-area-squareyard-abbr' => 'sq yd', |
| | 150 | + 'pfunc-convert-unit-area-squarefoot-abbr' => 'sq ft', |
| | 151 | + 'pfunc-convert-unit-area-squareinch-abbr' => 'sq in', |
| | 152 | + 'pfunc-convert-unit-area-squarenauticalmile-abbr' => 'sq nmi', |
| | 153 | + 'pfunc-convert-unit-area-dunam-abbr' => 'dunam', |
| | 154 | + 'pfunc-convert-unit-area-tsubo-abbr' => 'tsubo', |
| | 155 | + |
| | 156 | + # TIME # |
| | 157 | + 'pfunc-convert-unit-time-second' => '{{PLURAL:$1|second|seconds}}', |
| | 158 | + 'pfunc-convert-unit-time-year' => '{{PLURAL:$1|year|years}}', |
| | 159 | + 'pfunc-convert-unit-time-day' => '{{PLURAL:$1|day|days}}', |
| | 160 | + 'pfunc-convert-unit-time-hour' => '{{PLURAL:$1|hour|hours}}', |
| | 161 | + 'pfunc-convert-unit-time-minute' => '{{PLURAL:$1|minute|minutes}}', |
| | 162 | + |
| | 163 | + 'pfunc-convert-unit-time-second-abbr' => 's', |
| | 164 | + 'pfunc-convert-unit-time-year-abbr' => 'yr', |
| | 165 | + 'pfunc-convert-unit-time-day-abbr' => 'day', |
| | 166 | + 'pfunc-convert-unit-time-hour-abbr' => 'hr', |
| | 167 | + 'pfunc-convert-unit-time-minute-abbr' => 'min', |
| | 168 | + |
| | 169 | + # VOLUME # |
| | 170 | + 'pfunc-convert-unit-volume-cubicmetre' => '{{PLURAL:$1|cubic metre|cubic metres}}', |
| | 171 | + 'pfunc-convert-unit-volume-cubiccentimetre' => '{{PLURAL:$1|cubic centimetre|cubic centimetres}}', |
| | 172 | + 'pfunc-convert-unit-volume-cubicmillimetre' => '{{PLURAL:$1|cubic millimetre|cubic millimetres}}', |
| | 173 | + 'pfunc-convert-unit-volume-kilolitre' => '{{PLURAL:$1|kilolitre|kilolitres}}', |
| | 174 | + 'pfunc-convert-unit-volume-litre' => '{{PLURAL:$1|litre|litres}}', |
| | 175 | + 'pfunc-convert-unit-volume-centilitre' => '{{PLURAL:$1|centilitre|centilitres}}', |
| | 176 | + 'pfunc-convert-unit-volume-millilitre' => '{{PLURAL:$1|millilitre|millilitres}}', |
| | 177 | + 'pfunc-convert-unit-volume-cubicyard' => '{{PLURAL:$1|cubic yard|cubic yards}}', |
| | 178 | + 'pfunc-convert-unit-volume-cubicfoot' => '{{PLURAL:$1|cubic foot|cubic feet}}', |
| | 179 | + 'pfunc-convert-unit-volume-cubicinch' => '{{PLURAL:$1|cubic inch|cubic inches}}', |
| | 180 | + 'pfunc-convert-unit-volume-barrel' => '{{PLURAL:$1|barrel|barrels}}', |
| | 181 | + 'pfunc-convert-unit-volume-bushel' => '{{PLURAL:$1|bushel|bushels}}', |
| | 182 | + 'pfunc-convert-unit-volume-gallon' => '{{PLURAL:$1|gallon|gallons}}', |
| | 183 | + 'pfunc-convert-unit-volume-quart' => '{{PLURAL:$1|quart|quarts}}', |
| | 184 | + 'pfunc-convert-unit-volume-pint' => '{{PLURAL:$1|pint|pints}}', |
| | 185 | + 'pfunc-convert-unit-volume-fluidounce' => '{{PLURAL:$1|fluid ounce|fluid ounces}}', |
| | 186 | + 'pfunc-convert-unit-volume-barrelus' => '{{PLURAL:$1|US barrel|US barrels}}', |
| | 187 | + 'pfunc-convert-unit-volume-barreloil' => '{{PLURAL:$1|barrel|barrel}}', |
| | 188 | + 'pfunc-convert-unit-volume-barrelbeer' => '{{PLURAL:$1|barrel|barrel}}', |
| | 189 | + 'pfunc-convert-unit-volume-usgallon' => '{{PLURAL:$1|US gallon|US gallons}}', |
| | 190 | + 'pfunc-convert-unit-volume-usquart' => '{{PLURAL:$1|US quart|US quarts}}', |
| | 191 | + 'pfunc-convert-unit-volume-uspint' => '{{PLURAL:$1|US pint|US pints}}', |
| | 192 | + 'pfunc-convert-unit-volume-usfluidounce' => '{{PLURAL:$1|US fluid ounce|US fluid ounces}}', |
| | 193 | + 'pfunc-convert-unit-volume-usdrybarrel' => '{{PLURAL:$1|US dry barrel|US dry barrels}}', |
| | 194 | + 'pfunc-convert-unit-volume-usbushel' => '{{PLURAL:$1|US bushel|US bushels}}', |
| | 195 | + 'pfunc-convert-unit-volume-usdrygallon' => '{{PLURAL:$1|US dry gallon|US dry gallons}}', |
| | 196 | + 'pfunc-convert-unit-volume-usdryquart' => '{{PLURAL:$1|US dry quart|US dry quarts}}', |
| | 197 | + 'pfunc-convert-unit-volume-usdrypint' => '{{PLURAL:$1|US dry pint|US dry pints}}', |
| | 198 | + |
| | 199 | + 'pfunc-convert-unit-volume-cubicmetre-abbr' => 'm<sup>3</sup>', |
| | 200 | + 'pfunc-convert-unit-volume-cubiccentimetre-abbr' => 'cm<sup>3</sup>', |
| | 201 | + 'pfunc-convert-unit-volume-cubicmillimetre-abbr' => 'mm<sup>3</sup>', |
| | 202 | + 'pfunc-convert-unit-volume-kilolitre-abbr' => 'kl', |
| | 203 | + 'pfunc-convert-unit-volume-litre-abbr' => 'l', |
| | 204 | + 'pfunc-convert-unit-volume-centilitre-abbr' => 'cl', |
| | 205 | + 'pfunc-convert-unit-volume-millilitre-abbr' => 'ml', |
| | 206 | + 'pfunc-convert-unit-volume-cubicyard-abbr' => 'cu yd', |
| | 207 | + 'pfunc-convert-unit-volume-cubicfoot-abbr' => 'cu ft', |
| | 208 | + 'pfunc-convert-unit-volume-cubicinch-abbr' => 'cu in', |
| | 209 | + 'pfunc-convert-unit-volume-barrel-abbr' => 'bbl', |
| | 210 | + 'pfunc-convert-unit-volume-bushel-abbr' => 'bsh', |
| | 211 | + 'pfunc-convert-unit-volume-gallon-abbr' => 'gal', |
| | 212 | + 'pfunc-convert-unit-volume-quart-abbr' => 'qt', |
| | 213 | + 'pfunc-convert-unit-volume-pint-abbr' => 'pt', |
| | 214 | + 'pfunc-convert-unit-volume-fluidounce-abbr' => 'fl oz', |
| | 215 | + 'pfunc-convert-unit-volume-barrelus-abbr' => 'US bbl', |
| | 216 | + 'pfunc-convert-unit-volume-barreloil-abbr' => 'bbl', |
| | 217 | + 'pfunc-convert-unit-volume-barrelbeer-abbr' => 'bbl', |
| | 218 | + 'pfunc-convert-unit-volume-usgallon-abbr' => 'US gal', |
| | 219 | + 'pfunc-convert-unit-volume-usquart-abbr' => 'US qt', |
| | 220 | + 'pfunc-convert-unit-volume-uspint-abbr' => 'US pt', |
| | 221 | + 'pfunc-convert-unit-volume-usfluidounce-abbr' => 'US fl oz', |
| | 222 | + 'pfunc-convert-unit-volume-usdrybarrel-abbr' => 'US bbl', |
| | 223 | + 'pfunc-convert-unit-volume-usbushel-abbr' => 'US bsh', |
| | 224 | + 'pfunc-convert-unit-volume-usdrygallon-abbr' => 'US dry gal', |
| | 225 | + 'pfunc-convert-unit-volume-usdryquart-abbr' => 'US dry qt', |
| | 226 | + 'pfunc-convert-unit-volume-usdrypint-abbr' => 'US dry pt', |
| | 227 | + |
| | 228 | + # SPEED |
| | 229 | + 'pfunc-convert-unit-speed-mile-hour' => 'miles per hour', |
| | 230 | + 'pfunc-convert-unit-speed-speedoflight' => 'c', |
| | 231 | + |
| | 232 | + 'pfunc-convert-unit-speed-mile-hour-abbr' => 'mph', |
| | 233 | + 'pfunc-convert-unit-speed-speedoflight-abbr' => 'c', |
| | 234 | + |
| | 235 | + # PRESSURE |
| | 236 | + 'pfunc-convert-unit-pressure-gigapascal' => '{{PLURAL:$1|gigapascal|gigapascals}}', |
| | 237 | + 'pfunc-convert-unit-pressure-megapascal' => '{{PLURAL:$1|megapascal|megapascals}}', |
| | 238 | + 'pfunc-convert-unit-pressure-kilopascal' => '{{PLURAL:$1|kilopascal|kilopascals}}', |
| | 239 | + 'pfunc-convert-unit-pressure-hectopascal' => '{{PLURAL:$1|hectopascal|hectopascals}}', |
| | 240 | + 'pfunc-convert-unit-pressure-pascal' => '{{PLURAL:$1|pascal|pascals}}', |
| | 241 | + 'pfunc-convert-unit-pressure-millipascal' => '{{PLURAL:$1|millipascal|millipascals}}', |
| | 242 | + 'pfunc-convert-unit-pressure-bar' => 'bar', |
| | 243 | + 'pfunc-convert-unit-pressure-decibar' => 'decibar', |
| | 244 | + 'pfunc-convert-unit-pressure-millibar' => 'millibar', |
| | 245 | + 'pfunc-convert-unit-pressure-kilobarye' => 'kilobarye', |
| | 246 | + 'pfunc-convert-unit-pressure-barye' => 'barye', |
| | 247 | + 'pfunc-convert-unit-pressure-atmosphere' => '{{PLURAL:$1|atmosphere|atmospheres}}', |
| | 248 | + 'pfunc-convert-unit-pressure-torr' => '{{PLURAL:$1|Torr|Torr}}', |
| | 249 | + 'pfunc-convert-unit-pressure-mmhg' => '{{PLURAL:$1|milimetre of mercury|milimetres of mercury}}', |
| | 250 | + 'pfunc-convert-unit-pressure-inhg' => '{{PLURAL:$1|inch of mercury|inches of mercury}}', |
| | 251 | + 'pfunc-convert-unit-pressure-psi' => '{{PLURAL:$1|pound per square-inch|pounds per square-inch}}', |
| | 252 | + |
| | 253 | + 'pfunc-convert-unit-pressure-gigapascal-abbr' => 'GPa', |
| | 254 | + 'pfunc-convert-unit-pressure-megapascal-abbr' => 'MPa', |
| | 255 | + 'pfunc-convert-unit-pressure-kilopascal-abbr' => 'kPa', |
| | 256 | + 'pfunc-convert-unit-pressure-hectopascal-abbr' => 'hPa', |
| | 257 | + 'pfunc-convert-unit-pressure-pascal-abbr' => 'Pa', |
| | 258 | + 'pfunc-convert-unit-pressure-millipascal-abbr' => 'mPa', |
| | 259 | + 'pfunc-convert-unit-pressure-bar-abbr' => 'bar', |
| | 260 | + 'pfunc-convert-unit-pressure-decibar-abbr' => 'dbar', |
| | 261 | + 'pfunc-convert-unit-pressure-milibar-abbr' => 'mbar', |
| | 262 | + 'pfunc-convert-unit-pressure-kilobarye-abbr' => 'kBa', |
| | 263 | + 'pfunc-convert-unit-pressure-barye-abbr' => 'Ba', |
| | 264 | + 'pfunc-convert-unit-pressure-atmosphere-abbr' => 'atm', |
| | 265 | + 'pfunc-convert-unit-pressure-torr-abbr' => 'Torr', |
| | 266 | + 'pfunc-convert-unit-pressure-mmhg-abbr' => 'mmHg', |
| | 267 | + 'pfunc-convert-unit-pressure-inhg-abbr' => 'inHg', |
| | 268 | + 'pfunc-convert-unit-pressure-psi-abbr' => 'psi', |
| 32 | 269 | ); |
| 33 | 270 | |
| 34 | 271 | /** Message documentation (Message documentation) |
| Index: trunk/extensions/ParserFunctions/ParserFunctions.php |
| — | — | @@ -46,6 +46,7 @@ |
| 47 | 47 | |
| 48 | 48 | $wgParserTestFiles[] = dirname( __FILE__ ) . "/funcsParserTests.txt"; |
| 49 | 49 | $wgParserTestFiles[] = dirname( __FILE__ ) . "/stringFunctionTests.txt"; |
| | 50 | +$wgParserTestFiles[] = dirname( __FILE__ ) . "/convertTests.txt"; |
| 50 | 51 | |
| 51 | 52 | function wfSetupParserFunctions() { |
| 52 | 53 | global $wgPFHookStub, $wgHooks; |
| — | — | @@ -89,6 +90,7 @@ |
| 90 | 91 | $parser->setFunctionHook( 'timel', array( &$this, 'localTime' ) ); |
| 91 | 92 | $parser->setFunctionHook( 'rel2abs', array( &$this, 'rel2abs' ) ); |
| 92 | 93 | $parser->setFunctionHook( 'titleparts', array( &$this, 'titleparts' ) ); |
| | 94 | + $parser->setFunctionHook( 'convert', array( &$this, 'convert' ) ); |
| 93 | 95 | |
| 94 | 96 | // String Functions |
| 95 | 97 | if ( $wgPFEnableStringFunctions ) { |