[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Class for a set of entries for translation and their associated headers 4 * 5 * @version $Id: translations.php 1157 2015-11-20 04:30:11Z dd32 $ 6 * @package pomo 7 * @subpackage translations 8 */ 9 10 require_once __DIR__ . '/plural-forms.php'; 11 require_once __DIR__ . '/entry.php'; 12 13 if ( ! class_exists( 'Translations', false ) ) : 14 class Translations { 15 public $entries = array(); 16 public $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 public 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 public 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 public function set_header( $header, $value ) { 67 $this->headers[ $header ] = $value; 68 } 69 70 /** 71 * @param array $headers 72 */ 73 public 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 public function get_header( $header ) { 83 return isset( $this->headers[ $header ] ) ? $this->headers[ $header ] : false; 84 } 85 86 /** 87 * @param Translation_Entry $entry 88 */ 89 public 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 public 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 subclasses. For example MO/PO can derive the logic 117 * from their headers. 118 * 119 * @param int $count number of items 120 */ 121 public function select_plural_form( $count ) { 122 return 1 == $count ? 0 : 1; 123 } 124 125 /** 126 * @return int 127 */ 128 public 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 public 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 */ 163 public function merge_with( &$other ) { 164 foreach ( $other->entries as $entry ) { 165 $this->entries[ $entry->key() ] = $entry; 166 } 167 } 168 169 /** 170 * @param object $other 171 */ 172 public function merge_originals_with( &$other ) { 173 foreach ( $other->entries as $entry ) { 174 if ( ! isset( $this->entries[ $entry->key() ] ) ) { 175 $this->entries[ $entry->key() ] = $entry; 176 } else { 177 $this->entries[ $entry->key() ]->merge_with( $entry ); 178 } 179 } 180 } 181 } 182 183 class Gettext_Translations extends Translations { 184 /** 185 * The gettext implementation of select_plural_form. 186 * 187 * It lives in this class, because there are more than one descendand, which will use it and 188 * they can't share it effectively. 189 * 190 * @param int $count 191 */ 192 public function gettext_select_plural_form( $count ) { 193 if ( ! isset( $this->_gettext_select_plural_form ) || is_null( $this->_gettext_select_plural_form ) ) { 194 list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header( $this->get_header( 'Plural-Forms' ) ); 195 $this->_nplurals = $nplurals; 196 $this->_gettext_select_plural_form = $this->make_plural_form_function( $nplurals, $expression ); 197 } 198 return call_user_func( $this->_gettext_select_plural_form, $count ); 199 } 200 201 /** 202 * @param string $header 203 * @return array 204 */ 205 public function nplurals_and_expression_from_header( $header ) { 206 if ( preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches ) ) { 207 $nplurals = (int) $matches[1]; 208 $expression = trim( $matches[2] ); 209 return array( $nplurals, $expression ); 210 } else { 211 return array( 2, 'n != 1' ); 212 } 213 } 214 215 /** 216 * Makes a function, which will return the right translation index, according to the 217 * plural forms header 218 * 219 * @param int $nplurals 220 * @param string $expression 221 */ 222 public function make_plural_form_function( $nplurals, $expression ) { 223 try { 224 $handler = new Plural_Forms( rtrim( $expression, ';' ) ); 225 return array( $handler, 'get' ); 226 } catch ( Exception $e ) { 227 // Fall back to default plural-form function. 228 return $this->make_plural_form_function( 2, 'n != 1' ); 229 } 230 } 231 232 /** 233 * Adds parentheses to the inner parts of ternary operators in 234 * plural expressions, because PHP evaluates ternary oerators from left to right 235 * 236 * @param string $expression the expression without parentheses 237 * @return string the expression with parentheses added 238 */ 239 public function parenthesize_plural_exression( $expression ) { 240 $expression .= ';'; 241 $res = ''; 242 $depth = 0; 243 for ( $i = 0; $i < strlen( $expression ); ++$i ) { 244 $char = $expression[ $i ]; 245 switch ( $char ) { 246 case '?': 247 $res .= ' ? ('; 248 $depth++; 249 break; 250 case ':': 251 $res .= ') : ('; 252 break; 253 case ';': 254 $res .= str_repeat( ')', $depth ) . ';'; 255 $depth = 0; 256 break; 257 default: 258 $res .= $char; 259 } 260 } 261 return rtrim( $res, ';' ); 262 } 263 264 /** 265 * @param string $translation 266 * @return array 267 */ 268 public function make_headers( $translation ) { 269 $headers = array(); 270 // Sometimes \n's are used instead of real new lines. 271 $translation = str_replace( '\n', "\n", $translation ); 272 $lines = explode( "\n", $translation ); 273 foreach ( $lines as $line ) { 274 $parts = explode( ':', $line, 2 ); 275 if ( ! isset( $parts[1] ) ) { 276 continue; 277 } 278 $headers[ trim( $parts[0] ) ] = trim( $parts[1] ); 279 } 280 return $headers; 281 } 282 283 /** 284 * @param string $header 285 * @param string $value 286 */ 287 public function set_header( $header, $value ) { 288 parent::set_header( $header, $value ); 289 if ( 'Plural-Forms' === $header ) { 290 list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header( $this->get_header( 'Plural-Forms' ) ); 291 $this->_nplurals = $nplurals; 292 $this->_gettext_select_plural_form = $this->make_plural_form_function( $nplurals, $expression ); 293 } 294 } 295 } 296 endif; 297 298 if ( ! class_exists( 'NOOP_Translations', false ) ) : 299 /** 300 * Provides the same interface as Translations, but doesn't do anything 301 */ 302 class NOOP_Translations { 303 public $entries = array(); 304 public $headers = array(); 305 306 public function add_entry( $entry ) { 307 return true; 308 } 309 310 /** 311 * @param string $header 312 * @param string $value 313 */ 314 public function set_header( $header, $value ) { 315 } 316 317 /** 318 * @param array $headers 319 */ 320 public function set_headers( $headers ) { 321 } 322 323 /** 324 * @param string $header 325 * @return false 326 */ 327 public function get_header( $header ) { 328 return false; 329 } 330 331 /** 332 * @param Translation_Entry $entry 333 * @return false 334 */ 335 public function translate_entry( &$entry ) { 336 return false; 337 } 338 339 /** 340 * @param string $singular 341 * @param string $context 342 */ 343 public function translate( $singular, $context = null ) { 344 return $singular; 345 } 346 347 /** 348 * @param int $count 349 * @return bool 350 */ 351 public function select_plural_form( $count ) { 352 return 1 == $count ? 0 : 1; 353 } 354 355 /** 356 * @return int 357 */ 358 public function get_plural_forms_count() { 359 return 2; 360 } 361 362 /** 363 * @param string $singular 364 * @param string $plural 365 * @param int $count 366 * @param string $context 367 */ 368 public function translate_plural( $singular, $plural, $count, $context = null ) { 369 return 1 == $count ? $singular : $plural; 370 } 371 372 /** 373 * @param object $other 374 */ 375 public function merge_with( &$other ) { 376 } 377 } 378 endif;
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Nov 21 01:00:03 2024 | Cross-referenced by PHPXref 0.7.1 |