Changeset 42343 for trunk/src/wp-includes/pomo/translations.php
- Timestamp:
- 11/30/2017 11:09:33 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/pomo/translations.php
r41722 r42343 8 8 */ 9 9 10 require_once dirname(__FILE__) . '/plural-forms.php'; 11 require_once dirname(__FILE__) . '/entry.php'; 12 13 if ( ! class_exists( 'Translations', false ) ): 14 class Translations { 15 var $entries = array(); 16 var $headers = array(); 17 10 require_once dirname( __FILE__ ) . '/plural-forms.php'; 11 require_once dirname( __FILE__ ) . '/entry.php'; 12 13 if ( ! class_exists( 'Translations', false ) ) : 14 class Translations { 15 var $entries = array(); 16 var $headers = array(); 17 18 /** 19 * Add entry to the PO structure 20 * 21 * @param array|Translation_Entry $entry 22 * @return bool true on success, false if the entry doesn't have a key 23 */ 24 function add_entry( $entry ) { 25 if ( is_array( $entry ) ) { 26 $entry = new Translation_Entry( $entry ); 27 } 28 $key = $entry->key(); 29 if ( false === $key ) { 30 return false; 31 } 32 $this->entries[ $key ] = &$entry; 33 return true; 34 } 35 36 /** 37 * @param array|Translation_Entry $entry 38 * @return bool 39 */ 40 function add_entry_or_merge( $entry ) { 41 if ( is_array( $entry ) ) { 42 $entry = new Translation_Entry( $entry ); 43 } 44 $key = $entry->key(); 45 if ( false === $key ) { 46 return false; 47 } 48 if ( isset( $this->entries[ $key ] ) ) { 49 $this->entries[ $key ]->merge_with( $entry ); 50 } else { 51 $this->entries[ $key ] = &$entry; 52 } 53 return true; 54 } 55 56 /** 57 * Sets $header PO header to $value 58 * 59 * If the header already exists, it will be overwritten 60 * 61 * TODO: this should be out of this class, it is gettext specific 62 * 63 * @param string $header header name, without trailing : 64 * @param string $value header value, without trailing \n 65 */ 66 function set_header( $header, $value ) { 67 $this->headers[ $header ] = $value; 68 } 69 70 /** 71 * @param array $headers 72 */ 73 function set_headers( $headers ) { 74 foreach ( $headers as $header => $value ) { 75 $this->set_header( $header, $value ); 76 } 77 } 78 79 /** 80 * @param string $header 81 */ 82 function get_header( $header ) { 83 return isset( $this->headers[ $header ] ) ? $this->headers[ $header ] : false; 84 } 85 86 /** 87 * @param Translation_Entry $entry 88 */ 89 function translate_entry( &$entry ) { 90 $key = $entry->key(); 91 return isset( $this->entries[ $key ] ) ? $this->entries[ $key ] : false; 92 } 93 94 /** 95 * @param string $singular 96 * @param string $context 97 * @return string 98 */ 99 function translate( $singular, $context = null ) { 100 $entry = new Translation_Entry( 101 array( 102 'singular' => $singular, 103 'context' => $context, 104 ) 105 ); 106 $translated = $this->translate_entry( $entry ); 107 return ( $translated && ! empty( $translated->translations ) ) ? $translated->translations[0] : $singular; 108 } 109 110 /** 111 * Given the number of items, returns the 0-based index of the plural form to use 112 * 113 * Here, in the base Translations class, the common logic for English is implemented: 114 * 0 if there is one element, 1 otherwise 115 * 116 * This function should be overridden by the sub-classes. For example MO/PO can derive the logic 117 * from their headers. 118 * 119 * @param integer $count number of items 120 */ 121 function select_plural_form( $count ) { 122 return 1 == $count ? 0 : 1; 123 } 124 125 /** 126 * @return int 127 */ 128 function get_plural_forms_count() { 129 return 2; 130 } 131 132 /** 133 * @param string $singular 134 * @param string $plural 135 * @param int $count 136 * @param string $context 137 */ 138 function translate_plural( $singular, $plural, $count, $context = null ) { 139 $entry = new Translation_Entry( 140 array( 141 'singular' => $singular, 142 'plural' => $plural, 143 'context' => $context, 144 ) 145 ); 146 $translated = $this->translate_entry( $entry ); 147 $index = $this->select_plural_form( $count ); 148 $total_plural_forms = $this->get_plural_forms_count(); 149 if ( $translated && 0 <= $index && $index < $total_plural_forms && 150 is_array( $translated->translations ) && 151 isset( $translated->translations[ $index ] ) ) { 152 return $translated->translations[ $index ]; 153 } else { 154 return 1 == $count ? $singular : $plural; 155 } 156 } 157 158 /** 159 * Merge $other in the current object. 160 * 161 * @param Object $other Another Translation object, whose translations will be merged in this one (passed by reference). 162 * @return void 163 */ 164 function merge_with( &$other ) { 165 foreach ( $other->entries as $entry ) { 166 $this->entries[ $entry->key() ] = $entry; 167 } 168 } 169 170 /** 171 * @param object $other 172 */ 173 function merge_originals_with( &$other ) { 174 foreach ( $other->entries as $entry ) { 175 if ( ! isset( $this->entries[ $entry->key() ] ) ) { 176 $this->entries[ $entry->key() ] = $entry; 177 } else { 178 $this->entries[ $entry->key() ]->merge_with( $entry ); 179 } 180 } 181 } 182 } 183 184 class Gettext_Translations extends Translations { 185 /** 186 * The gettext implementation of select_plural_form. 187 * 188 * It lives in this class, because there are more than one descendand, which will use it and 189 * they can't share it effectively. 190 * 191 * @param int $count 192 */ 193 function gettext_select_plural_form( $count ) { 194 if ( ! isset( $this->_gettext_select_plural_form ) || is_null( $this->_gettext_select_plural_form ) ) { 195 list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header( $this->get_header( 'Plural-Forms' ) ); 196 $this->_nplurals = $nplurals; 197 $this->_gettext_select_plural_form = $this->make_plural_form_function( $nplurals, $expression ); 198 } 199 return call_user_func( $this->_gettext_select_plural_form, $count ); 200 } 201 202 /** 203 * @param string $header 204 * @return array 205 */ 206 function nplurals_and_expression_from_header( $header ) { 207 if ( preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches ) ) { 208 $nplurals = (int) $matches[1]; 209 $expression = trim( $matches[2] ); 210 return array( $nplurals, $expression ); 211 } else { 212 return array( 2, 'n != 1' ); 213 } 214 } 215 216 /** 217 * Makes a function, which will return the right translation index, according to the 218 * plural forms header 219 * 220 * @param int $nplurals 221 * @param string $expression 222 */ 223 function make_plural_form_function( $nplurals, $expression ) { 224 try { 225 $handler = new Plural_Forms( rtrim( $expression, ';' ) ); 226 return array( $handler, 'get' ); 227 } catch ( Exception $e ) { 228 // Fall back to default plural-form function. 229 return $this->make_plural_form_function( 2, 'n != 1' ); 230 } 231 } 232 233 /** 234 * Adds parentheses to the inner parts of ternary operators in 235 * plural expressions, because PHP evaluates ternary oerators from left to right 236 * 237 * @param string $expression the expression without parentheses 238 * @return string the expression with parentheses added 239 */ 240 function parenthesize_plural_exression( $expression ) { 241 $expression .= ';'; 242 $res = ''; 243 $depth = 0; 244 for ( $i = 0; $i < strlen( $expression ); ++$i ) { 245 $char = $expression[ $i ]; 246 switch ( $char ) { 247 case '?': 248 $res .= ' ? ('; 249 $depth++; 250 break; 251 case ':': 252 $res .= ') : ('; 253 break; 254 case ';': 255 $res .= str_repeat( ')', $depth ) . ';'; 256 $depth = 0; 257 break; 258 default: 259 $res .= $char; 260 } 261 } 262 return rtrim( $res, ';' ); 263 } 264 265 /** 266 * @param string $translation 267 * @return array 268 */ 269 function make_headers( $translation ) { 270 $headers = array(); 271 // sometimes \ns are used instead of real new lines 272 $translation = str_replace( '\n', "\n", $translation ); 273 $lines = explode( "\n", $translation ); 274 foreach ( $lines as $line ) { 275 $parts = explode( ':', $line, 2 ); 276 if ( ! isset( $parts[1] ) ) { 277 continue; 278 } 279 $headers[ trim( $parts[0] ) ] = trim( $parts[1] ); 280 } 281 return $headers; 282 } 283 284 /** 285 * @param string $header 286 * @param string $value 287 */ 288 function set_header( $header, $value ) { 289 parent::set_header( $header, $value ); 290 if ( 'Plural-Forms' == $header ) { 291 list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header( $this->get_header( 'Plural-Forms' ) ); 292 $this->_nplurals = $nplurals; 293 $this->_gettext_select_plural_form = $this->make_plural_form_function( $nplurals, $expression ); 294 } 295 } 296 } 297 endif; 298 299 if ( ! class_exists( 'NOOP_Translations', false ) ) : 18 300 /** 19 * Add entry to the PO structure 20 * 21 * @param array|Translation_Entry $entry 22 * @return bool true on success, false if the entry doesn't have a key 301 * Provides the same interface as Translations, but doesn't do anything 23 302 */ 24 function add_entry($entry) { 25 if (is_array($entry)) { 26 $entry = new Translation_Entry($entry); 27 } 28 $key = $entry->key(); 29 if (false === $key) return false; 30 $this->entries[$key] = &$entry; 31 return true; 303 class NOOP_Translations { 304 var $entries = array(); 305 var $headers = array(); 306 307 function add_entry( $entry ) { 308 return true; 309 } 310 311 /** 312 * @param string $header 313 * @param string $value 314 */ 315 function set_header( $header, $value ) { 316 } 317 318 /** 319 * @param array $headers 320 */ 321 function set_headers( $headers ) { 322 } 323 324 /** 325 * @param string $header 326 * @return false 327 */ 328 function get_header( $header ) { 329 return false; 330 } 331 332 /** 333 * @param Translation_Entry $entry 334 * @return false 335 */ 336 function translate_entry( &$entry ) { 337 return false; 338 } 339 340 /** 341 * @param string $singular 342 * @param string $context 343 */ 344 function translate( $singular, $context = null ) { 345 return $singular; 346 } 347 348 /** 349 * @param int $count 350 * @return bool 351 */ 352 function select_plural_form( $count ) { 353 return 1 == $count ? 0 : 1; 354 } 355 356 /** 357 * @return int 358 */ 359 function get_plural_forms_count() { 360 return 2; 361 } 362 363 /** 364 * @param string $singular 365 * @param string $plural 366 * @param int $count 367 * @param string $context 368 */ 369 function translate_plural( $singular, $plural, $count, $context = null ) { 370 return 1 == $count ? $singular : $plural; 371 } 372 373 /** 374 * @param object $other 375 */ 376 function merge_with( &$other ) { 377 } 32 378 } 33 34 /**35 * @param array|Translation_Entry $entry36 * @return bool37 */38 function add_entry_or_merge($entry) {39 if (is_array($entry)) {40 $entry = new Translation_Entry($entry);41 }42 $key = $entry->key();43 if (false === $key) return false;44 if (isset($this->entries[$key]))45 $this->entries[$key]->merge_with($entry);46 else47 $this->entries[$key] = &$entry;48 return true;49 }50 51 /**52 * Sets $header PO header to $value53 *54 * If the header already exists, it will be overwritten55 *56 * TODO: this should be out of this class, it is gettext specific57 *58 * @param string $header header name, without trailing :59 * @param string $value header value, without trailing \n60 */61 function set_header($header, $value) {62 $this->headers[$header] = $value;63 }64 65 /**66 * @param array $headers67 */68 function set_headers($headers) {69 foreach($headers as $header => $value) {70 $this->set_header($header, $value);71 }72 }73 74 /**75 * @param string $header76 */77 function get_header($header) {78 return isset($this->headers[$header])? $this->headers[$header] : false;79 }80 81 /**82 * @param Translation_Entry $entry83 */84 function translate_entry(&$entry) {85 $key = $entry->key();86 return isset($this->entries[$key])? $this->entries[$key] : false;87 }88 89 /**90 * @param string $singular91 * @param string $context92 * @return string93 */94 function translate($singular, $context=null) {95 $entry = new Translation_Entry(array('singular' => $singular, 'context' => $context));96 $translated = $this->translate_entry($entry);97 return ($translated && !empty($translated->translations))? $translated->translations[0] : $singular;98 }99 100 /**101 * Given the number of items, returns the 0-based index of the plural form to use102 *103 * Here, in the base Translations class, the common logic for English is implemented:104 * 0 if there is one element, 1 otherwise105 *106 * This function should be overridden by the sub-classes. For example MO/PO can derive the logic107 * from their headers.108 *109 * @param integer $count number of items110 */111 function select_plural_form($count) {112 return 1 == $count? 0 : 1;113 }114 115 /**116 * @return int117 */118 function get_plural_forms_count() {119 return 2;120 }121 122 /**123 * @param string $singular124 * @param string $plural125 * @param int $count126 * @param string $context127 */128 function translate_plural($singular, $plural, $count, $context = null) {129 $entry = new Translation_Entry(array('singular' => $singular, 'plural' => $plural, 'context' => $context));130 $translated = $this->translate_entry($entry);131 $index = $this->select_plural_form($count);132 $total_plural_forms = $this->get_plural_forms_count();133 if ($translated && 0 <= $index && $index < $total_plural_forms &&134 is_array($translated->translations) &&135 isset($translated->translations[$index]))136 return $translated->translations[$index];137 else138 return 1 == $count? $singular : $plural;139 }140 141 /**142 * Merge $other in the current object.143 *144 * @param Object $other Another Translation object, whose translations will be merged in this one (passed by reference).145 * @return void146 **/147 function merge_with(&$other) {148 foreach( $other->entries as $entry ) {149 $this->entries[$entry->key()] = $entry;150 }151 }152 153 /**154 * @param object $other155 */156 function merge_originals_with(&$other) {157 foreach( $other->entries as $entry ) {158 if ( !isset( $this->entries[$entry->key()] ) )159 $this->entries[$entry->key()] = $entry;160 else161 $this->entries[$entry->key()]->merge_with($entry);162 }163 }164 }165 166 class Gettext_Translations extends Translations {167 /**168 * The gettext implementation of select_plural_form.169 *170 * It lives in this class, because there are more than one descendand, which will use it and171 * they can't share it effectively.172 *173 * @param int $count174 */175 function gettext_select_plural_form($count) {176 if (!isset($this->_gettext_select_plural_form) || is_null($this->_gettext_select_plural_form)) {177 list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));178 $this->_nplurals = $nplurals;179 $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression);180 }181 return call_user_func($this->_gettext_select_plural_form, $count);182 }183 184 /**185 * @param string $header186 * @return array187 */188 function nplurals_and_expression_from_header($header) {189 if (preg_match('/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches)) {190 $nplurals = (int)$matches[1];191 $expression = trim( $matches[2] );192 return array($nplurals, $expression);193 } else {194 return array(2, 'n != 1');195 }196 }197 198 /**199 * Makes a function, which will return the right translation index, according to the200 * plural forms header201 * @param int $nplurals202 * @param string $expression203 */204 function make_plural_form_function($nplurals, $expression) {205 try {206 $handler = new Plural_Forms( rtrim( $expression, ';' ) );207 return array( $handler, 'get' );208 } catch ( Exception $e ) {209 // Fall back to default plural-form function.210 return $this->make_plural_form_function( 2, 'n != 1' );211 }212 }213 214 /**215 * Adds parentheses to the inner parts of ternary operators in216 * plural expressions, because PHP evaluates ternary oerators from left to right217 *218 * @param string $expression the expression without parentheses219 * @return string the expression with parentheses added220 */221 function parenthesize_plural_exression($expression) {222 $expression .= ';';223 $res = '';224 $depth = 0;225 for ($i = 0; $i < strlen($expression); ++$i) {226 $char = $expression[$i];227 switch ($char) {228 case '?':229 $res .= ' ? (';230 $depth++;231 break;232 case ':':233 $res .= ') : (';234 break;235 case ';':236 $res .= str_repeat(')', $depth) . ';';237 $depth= 0;238 break;239 default:240 $res .= $char;241 }242 }243 return rtrim($res, ';');244 }245 246 /**247 * @param string $translation248 * @return array249 */250 function make_headers($translation) {251 $headers = array();252 // sometimes \ns are used instead of real new lines253 $translation = str_replace('\n', "\n", $translation);254 $lines = explode("\n", $translation);255 foreach($lines as $line) {256 $parts = explode(':', $line, 2);257 if (!isset($parts[1])) continue;258 $headers[trim($parts[0])] = trim($parts[1]);259 }260 return $headers;261 }262 263 /**264 * @param string $header265 * @param string $value266 */267 function set_header($header, $value) {268 parent::set_header($header, $value);269 if ('Plural-Forms' == $header) {270 list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));271 $this->_nplurals = $nplurals;272 $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression);273 }274 }275 }276 379 endif; 277 278 if ( ! class_exists( 'NOOP_Translations', false ) ):279 /**280 * Provides the same interface as Translations, but doesn't do anything281 */282 class NOOP_Translations {283 var $entries = array();284 var $headers = array();285 286 function add_entry($entry) {287 return true;288 }289 290 /**291 *292 * @param string $header293 * @param string $value294 */295 function set_header($header, $value) {296 }297 298 /**299 *300 * @param array $headers301 */302 function set_headers($headers) {303 }304 305 /**306 * @param string $header307 * @return false308 */309 function get_header($header) {310 return false;311 }312 313 /**314 * @param Translation_Entry $entry315 * @return false316 */317 function translate_entry(&$entry) {318 return false;319 }320 321 /**322 * @param string $singular323 * @param string $context324 */325 function translate($singular, $context=null) {326 return $singular;327 }328 329 /**330 *331 * @param int $count332 * @return bool333 */334 function select_plural_form($count) {335 return 1 == $count? 0 : 1;336 }337 338 /**339 * @return int340 */341 function get_plural_forms_count() {342 return 2;343 }344 345 /**346 * @param string $singular347 * @param string $plural348 * @param int $count349 * @param string $context350 */351 function translate_plural($singular, $plural, $count, $context = null) {352 return 1 == $count? $singular : $plural;353 }354 355 /**356 * @param object $other357 */358 function merge_with(&$other) {359 }360 }361 endif;
Note: See TracChangeset
for help on using the changeset viewer.