| [ 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 406 2010-02-07 11:10:24Z nbachiyski $ 6 * @package pomo 7 * @subpackage translations 8 */ 9 10 require_once dirname(__FILE__) . '/entry.php'; 11 12 if ( !class_exists( 'Translations' ) ): 13 class Translations { 14 var $entries = array(); 15 var $headers = array(); 16 17 /** 18 * Add entry to the PO structure 19 * 20 * @param object &$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 * Sets $header PO header to $value 35 * 36 * If the header already exists, it will be overwritten 37 * 38 * TODO: this should be out of this class, it is gettext specific 39 * 40 * @param string $header header name, without trailing : 41 * @param string $value header value, without trailing \n 42 */ 43 function set_header($header, $value) { 44 $this->headers[$header] = $value; 45 } 46 47 function set_headers(&$headers) { 48 foreach($headers as $header => $value) { 49 $this->set_header($header, $value); 50 } 51 } 52 53 function get_header($header) { 54 return isset($this->headers[$header])? $this->headers[$header] : false; 55 } 56 57 function translate_entry(&$entry) { 58 $key = $entry->key(); 59 return isset($this->entries[$key])? $this->entries[$key] : false; 60 } 61 62 function translate($singular, $context=null) { 63 $entry = new Translation_Entry(array('singular' => $singular, 'context' => $context)); 64 $translated = $this->translate_entry($entry); 65 return ($translated && !empty($translated->translations))? $translated->translations[0] : $singular; 66 } 67 68 /** 69 * Given the number of items, returns the 0-based index of the plural form to use 70 * 71 * Here, in the base Translations class, the commong logic for English is implmented: 72 * 0 if there is one element, 1 otherwise 73 * 74 * This function should be overrided by the sub-classes. For example MO/PO can derive the logic 75 * from their headers. 76 * 77 * @param integer $count number of items 78 */ 79 function select_plural_form($count) { 80 return 1 == $count? 0 : 1; 81 } 82 83 function get_plural_forms_count() { 84 return 2; 85 } 86 87 function translate_plural($singular, $plural, $count, $context = null) { 88 $entry = new Translation_Entry(array('singular' => $singular, 'plural' => $plural, 'context' => $context)); 89 $translated = $this->translate_entry($entry); 90 $index = $this->select_plural_form($count); 91 $total_plural_forms = $this->get_plural_forms_count(); 92 if ($translated && 0 <= $index && $index < $total_plural_forms && 93 is_array($translated->translations) && 94 isset($translated->translations[$index])) 95 return $translated->translations[$index]; 96 else 97 return 1 == $count? $singular : $plural; 98 } 99 100 /** 101 * Merge $other in the current object. 102 * 103 * @param Object &$other Another Translation object, whose translations will be merged in this one 104 * @return void 105 **/ 106 function merge_with(&$other) { 107 foreach( $other->entries as $entry ) { 108 $this->entries[$entry->key()] = $entry; 109 } 110 } 111 } 112 113 class Gettext_Translations extends Translations { 114 /** 115 * The gettext implmentation of select_plural_form. 116 * 117 * It lives in this class, because there are more than one descendand, which will use it and 118 * they can't share it effectively. 119 * 120 */ 121 function gettext_select_plural_form($count) { 122 if (!isset($this->_gettext_select_plural_form) || is_null($this->_gettext_select_plural_form)) { 123 list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms')); 124 $this->_nplurals = $nplurals; 125 $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression); 126 } 127 return call_user_func($this->_gettext_select_plural_form, $count); 128 } 129 130 function nplurals_and_expression_from_header($header) { 131 if (preg_match('/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches)) { 132 $nplurals = (int)$matches[1]; 133 $expression = trim($this->parenthesize_plural_exression($matches[2])); 134 return array($nplurals, $expression); 135 } else { 136 return array(2, 'n != 1'); 137 } 138 } 139 140 /** 141 * Makes a function, which will return the right translation index, according to the 142 * plural forms header 143 */ 144 function make_plural_form_function($nplurals, $expression) { 145 $expression = str_replace('n', '$n', $expression); 146 $func_body = " 147 \$index = (int)($expression); 148 return (\$index < $nplurals)? \$index : $nplurals - 1;"; 149 return create_function('$n', $func_body); 150 } 151 152 /** 153 * Adds parantheses to the inner parts of ternary operators in 154 * plural expressions, because PHP evaluates ternary oerators from left to right 155 * 156 * @param string $expression the expression without parentheses 157 * @return string the expression with parentheses added 158 */ 159 function parenthesize_plural_exression($expression) { 160 $expression .= ';'; 161 $res = ''; 162 $depth = 0; 163 for ($i = 0; $i < strlen($expression); ++$i) { 164 $char = $expression[$i]; 165 switch ($char) { 166 case '?': 167 $res .= ' ? ('; 168 $depth++; 169 break; 170 case ':': 171 $res .= ') : ('; 172 break; 173 case ';': 174 $res .= str_repeat(')', $depth) . ';'; 175 $depth= 0; 176 break; 177 default: 178 $res .= $char; 179 } 180 } 181 return rtrim($res, ';'); 182 } 183 184 function make_headers($translation) { 185 $headers = array(); 186 // sometimes \ns are used instead of real new lines 187 $translation = str_replace('\n', "\n", $translation); 188 $lines = explode("\n", $translation); 189 foreach($lines as $line) { 190 $parts = explode(':', $line, 2); 191 if (!isset($parts[1])) continue; 192 $headers[trim($parts[0])] = trim($parts[1]); 193 } 194 return $headers; 195 } 196 197 function set_header($header, $value) { 198 parent::set_header($header, $value); 199 if ('Plural-Forms' == $header) { 200 list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms')); 201 $this->_nplurals = $nplurals; 202 $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression); 203 } 204 } 205 } 206 endif; 207 208 if ( !class_exists( 'NOOP_Translations' ) ): 209 /** 210 * Provides the same interface as Translations, but doesn't do anything 211 */ 212 class NOOP_Translations { 213 var $entries = array(); 214 var $headers = array(); 215 216 function add_entry($entry) { 217 return true; 218 } 219 220 function set_header($header, $value) { 221 } 222 223 function set_headers(&$headers) { 224 } 225 226 function get_header($header) { 227 return false; 228 } 229 230 function translate_entry(&$entry) { 231 return false; 232 } 233 234 function translate($singular, $context=null) { 235 return $singular; 236 } 237 238 function select_plural_form($count) { 239 return 1 == $count? 0 : 1; 240 } 241 242 function get_plural_forms_count() { 243 return 2; 244 } 245 246 function translate_plural($singular, $plural, $count, $context = null) { 247 return 1 == $count? $singular : $plural; 248 } 249 250 function merge_with(&$other) { 251 } 252 } 253 endif;
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Sep 2 03:55:41 2010 | Hosted by follow the white rabbit. |