[ Index ] |
PHP Cross Reference of BuddyPress |
[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 dirname(__FILE__) . '/entry.php'; 11 12 if ( ! class_exists( 'Translations', false ) ): 13 class Translations { 14 var $entries = array(); 15 var $headers = array(); 16 17 /** 18 * Add entry to the PO structure 19 * 20 * @param array|Translation_Entry &$entry 21 * @return bool true on success, false if the entry doesn't have a key 22 */ 23 function add_entry($entry) { 24 if (is_array($entry)) { 25 $entry = new Translation_Entry($entry); 26 } 27 $key = $entry->key(); 28 if (false === $key) return false; 29 $this->entries[$key] = &$entry; 30 return true; 31 } 32 33 /** 34 * @param array|Translation_Entry $entry 35 * @return bool 36 */ 37 function add_entry_or_merge($entry) { 38 if (is_array($entry)) { 39 $entry = new Translation_Entry($entry); 40 } 41 $key = $entry->key(); 42 if (false === $key) return false; 43 if (isset($this->entries[$key])) 44 $this->entries[$key]->merge_with($entry); 45 else 46 $this->entries[$key] = &$entry; 47 return true; 48 } 49 50 /** 51 * Sets $header PO header to $value 52 * 53 * If the header already exists, it will be overwritten 54 * 55 * TODO: this should be out of this class, it is gettext specific 56 * 57 * @param string $header header name, without trailing : 58 * @param string $value header value, without trailing \n 59 */ 60 function set_header($header, $value) { 61 $this->headers[$header] = $value; 62 } 63 64 /** 65 * @param array $headers 66 */ 67 function set_headers($headers) { 68 foreach($headers as $header => $value) { 69 $this->set_header($header, $value); 70 } 71 } 72 73 /** 74 * @param string $header 75 */ 76 function get_header($header) { 77 return isset($this->headers[$header])? $this->headers[$header] : false; 78 } 79 80 /** 81 * @param Translation_Entry $entry 82 */ 83 function translate_entry(&$entry) { 84 $key = $entry->key(); 85 return isset($this->entries[$key])? $this->entries[$key] : false; 86 } 87 88 /** 89 * @param string $singular 90 * @param string $context 91 * @return string 92 */ 93 function translate($singular, $context=null) { 94 $entry = new Translation_Entry(array('singular' => $singular, 'context' => $context)); 95 $translated = $this->translate_entry($entry); 96 return ($translated && !empty($translated->translations))? $translated->translations[0] : $singular; 97 } 98 99 /** 100 * Given the number of items, returns the 0-based index of the plural form to use 101 * 102 * Here, in the base Translations class, the common logic for English is implemented: 103 * 0 if there is one element, 1 otherwise 104 * 105 * This function should be overrided by the sub-classes. For example MO/PO can derive the logic 106 * from their headers. 107 * 108 * @param integer $count number of items 109 */ 110 function select_plural_form($count) { 111 return 1 == $count? 0 : 1; 112 } 113 114 /** 115 * @return int 116 */ 117 function get_plural_forms_count() { 118 return 2; 119 } 120 121 /** 122 * @param string $singular 123 * @param string $plural 124 * @param int $count 125 * @param string $context 126 */ 127 function translate_plural($singular, $plural, $count, $context = null) { 128 $entry = new Translation_Entry(array('singular' => $singular, 'plural' => $plural, 'context' => $context)); 129 $translated = $this->translate_entry($entry); 130 $index = $this->select_plural_form($count); 131 $total_plural_forms = $this->get_plural_forms_count(); 132 if ($translated && 0 <= $index && $index < $total_plural_forms && 133 is_array($translated->translations) && 134 isset($translated->translations[$index])) 135 return $translated->translations[$index]; 136 else 137 return 1 == $count? $singular : $plural; 138 } 139 140 /** 141 * Merge $other in the current object. 142 * 143 * @param Object &$other Another Translation object, whose translations will be merged in this one 144 * @return void 145 **/ 146 function merge_with(&$other) { 147 foreach( $other->entries as $entry ) { 148 $this->entries[$entry->key()] = $entry; 149 } 150 } 151 152 /** 153 * @param object $other 154 */ 155 function merge_originals_with(&$other) { 156 foreach( $other->entries as $entry ) { 157 if ( !isset( $this->entries[$entry->key()] ) ) 158 $this->entries[$entry->key()] = $entry; 159 else 160 $this->entries[$entry->key()]->merge_with($entry); 161 } 162 } 163 } 164 165 class Gettext_Translations extends Translations { 166 /** 167 * The gettext implementation of select_plural_form. 168 * 169 * It lives in this class, because there are more than one descendand, which will use it and 170 * they can't share it effectively. 171 * 172 * @param int $count 173 */ 174 function gettext_select_plural_form($count) { 175 if (!isset($this->_gettext_select_plural_form) || is_null($this->_gettext_select_plural_form)) { 176 list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms')); 177 $this->_nplurals = $nplurals; 178 $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression); 179 } 180 return call_user_func($this->_gettext_select_plural_form, $count); 181 } 182 183 /** 184 * @param string $header 185 * @return array 186 */ 187 function nplurals_and_expression_from_header($header) { 188 if (preg_match('/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches)) { 189 $nplurals = (int)$matches[1]; 190 $expression = trim($this->parenthesize_plural_exression($matches[2])); 191 return array($nplurals, $expression); 192 } else { 193 return array(2, 'n != 1'); 194 } 195 } 196 197 /** 198 * Makes a function, which will return the right translation index, according to the 199 * plural forms header 200 * @param int $nplurals 201 * @param string $expression 202 */ 203 function make_plural_form_function($nplurals, $expression) { 204 $expression = str_replace('n', '$n', $expression); 205 $func_body = " 206 \$index = (int)($expression); 207 return (\$index < $nplurals)? \$index : $nplurals - 1;"; 208 return create_function('$n', $func_body); 209 } 210 211 /** 212 * Adds parentheses to the inner parts of ternary operators in 213 * plural expressions, because PHP evaluates ternary oerators from left to right 214 * 215 * @param string $expression the expression without parentheses 216 * @return string the expression with parentheses added 217 */ 218 function parenthesize_plural_exression($expression) { 219 $expression .= ';'; 220 $res = ''; 221 $depth = 0; 222 for ($i = 0; $i < strlen($expression); ++$i) { 223 $char = $expression[$i]; 224 switch ($char) { 225 case '?': 226 $res .= ' ? ('; 227 $depth++; 228 break; 229 case ':': 230 $res .= ') : ('; 231 break; 232 case ';': 233 $res .= str_repeat(')', $depth) . ';'; 234 $depth= 0; 235 break; 236 default: 237 $res .= $char; 238 } 239 } 240 return rtrim($res, ';'); 241 } 242 243 /** 244 * @param string $translation 245 * @return array 246 */ 247 function make_headers($translation) { 248 $headers = array(); 249 // sometimes \ns are used instead of real new lines 250 $translation = str_replace('\n', "\n", $translation); 251 $lines = explode("\n", $translation); 252 foreach($lines as $line) { 253 $parts = explode(':', $line, 2); 254 if (!isset($parts[1])) continue; 255 $headers[trim($parts[0])] = trim($parts[1]); 256 } 257 return $headers; 258 } 259 260 /** 261 * @param string $header 262 * @param string $value 263 */ 264 function set_header($header, $value) { 265 parent::set_header($header, $value); 266 if ('Plural-Forms' == $header) { 267 list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms')); 268 $this->_nplurals = $nplurals; 269 $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression); 270 } 271 } 272 } 273 endif; 274 275 if ( ! class_exists( 'NOOP_Translations', false ) ): 276 /** 277 * Provides the same interface as Translations, but doesn't do anything 278 */ 279 class NOOP_Translations { 280 var $entries = array(); 281 var $headers = array(); 282 283 function add_entry($entry) { 284 return true; 285 } 286 287 /** 288 * 289 * @param string $header 290 * @param string $value 291 */ 292 function set_header($header, $value) { 293 } 294 295 /** 296 * 297 * @param array $headers 298 */ 299 function set_headers($headers) { 300 } 301 302 /** 303 * @param string $header 304 * @return false 305 */ 306 function get_header($header) { 307 return false; 308 } 309 310 /** 311 * @param Translation_Entry $entry 312 * @return false 313 */ 314 function translate_entry(&$entry) { 315 return false; 316 } 317 318 /** 319 * @param string $singular 320 * @param string $context 321 */ 322 function translate($singular, $context=null) { 323 return $singular; 324 } 325 326 /** 327 * 328 * @param int $count 329 * @return bool 330 */ 331 function select_plural_form($count) { 332 return 1 == $count? 0 : 1; 333 } 334 335 /** 336 * @return int 337 */ 338 function get_plural_forms_count() { 339 return 2; 340 } 341 342 /** 343 * @param string $singular 344 * @param string $plural 345 * @param int $count 346 * @param string $context 347 */ 348 function translate_plural($singular, $plural, $count, $context = null) { 349 return 1 == $count? $singular : $plural; 350 } 351 352 /** 353 * @param object $other 354 */ 355 function merge_with(&$other) { 356 } 357 } 358 endif;
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Nov 21 01:00:57 2024 | Cross-referenced by PHPXref 0.7.1 |