]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/pomo/translations.php
Wordpress 2.9.2-scripts
[autoinstalls/wordpress.git] / wp-includes / pomo / translations.php
1 <?php
2 /**
3  * Class for a set of entries for translation and their associated headers
4  *
5  * @version $Id: translations.php 291 2009-10-21 05:46:08Z 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                 $this->entries = array_merge($this->entries, $other->entries);
108         }
109 }
110
111 class Gettext_Translations extends Translations {
112         /**
113          * The gettext implmentation of select_plural_form.
114          *
115          * It lives in this class, because there are more than one descendand, which will use it and
116          * they can't share it effectively.
117          *
118          */
119         function gettext_select_plural_form($count) {
120                 if (!isset($this->_gettext_select_plural_form) || is_null($this->_gettext_select_plural_form)) {
121                         list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));
122                         $this->_nplurals = $nplurals;
123                         $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression);
124                 }
125                 return call_user_func($this->_gettext_select_plural_form, $count);
126         }
127         
128         function nplurals_and_expression_from_header($header) {
129                 if (preg_match('/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches)) {
130                         $nplurals = (int)$matches[1];
131                         $expression = trim($this->parenthesize_plural_exression($matches[2]));
132                         return array($nplurals, $expression);
133                 } else {
134                         return array(2, 'n != 1');
135                 }
136         }
137
138         /**
139          * Makes a function, which will return the right translation index, according to the
140          * plural forms header
141          */
142         function make_plural_form_function($nplurals, $expression) {
143                 $expression = str_replace('n', '$n', $expression);
144                 $func_body = "
145                         \$index = (int)($expression);
146                         return (\$index < $nplurals)? \$index : $nplurals - 1;";
147                 return create_function('$n', $func_body);
148         }
149
150         /**
151          * Adds parantheses to the inner parts of ternary operators in
152          * plural expressions, because PHP evaluates ternary oerators from left to right
153          * 
154          * @param string $expression the expression without parentheses
155          * @return string the expression with parentheses added
156          */
157         function parenthesize_plural_exression($expression) {
158                 $expression .= ';';
159                 $res = '';
160                 $depth = 0;
161                 for ($i = 0; $i < strlen($expression); ++$i) {
162                         $char = $expression[$i];
163                         switch ($char) {
164                                 case '?':
165                                         $res .= ' ? (';
166                                         $depth++;
167                                         break;
168                                 case ':':
169                                         $res .= ') : (';
170                                         break;
171                                 case ';':
172                                         $res .= str_repeat(')', $depth) . ';';
173                                         $depth= 0;
174                                         break;
175                                 default:
176                                         $res .= $char;
177                         }
178                 }
179                 return rtrim($res, ';');
180         }
181         
182         function make_headers($translation) {
183                 $headers = array();
184                 // sometimes \ns are used instead of real new lines
185                 $translation = str_replace('\n', "\n", $translation);
186                 $lines = explode("\n", $translation);
187                 foreach($lines as $line) {
188                         $parts = explode(':', $line, 2);
189                         if (!isset($parts[1])) continue;
190                         $headers[trim($parts[0])] = trim($parts[1]);
191                 }
192                 return $headers;
193         }
194         
195         function set_header($header, $value) {
196                 parent::set_header($header, $value);
197                 if ('Plural-Forms' == $header) {
198                         list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));
199                         $this->_nplurals = $nplurals;
200                         $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression);
201                 }
202         }
203 }
204 endif;
205
206 if ( !class_exists( 'NOOP_Translations' ) ):
207 /**
208  * Provides the same interface as Translations, but doesn't do anything
209  */
210 class NOOP_Translations {
211         var $entries = array();
212         var $headers = array();
213         
214         function add_entry($entry) {
215                 return true;
216         }
217
218         function set_header($header, $value) {
219         }
220
221         function set_headers(&$headers) {
222         }
223
224         function get_header($header) {
225                 return false;
226         }
227
228         function translate_entry(&$entry) {
229                 return false;
230         }
231
232         function translate($singular, $context=null) {
233                 return $singular;
234         }
235
236         function select_plural_form($count) {
237                 return 1 == $count? 0 : 1;
238         }
239
240         function get_plural_forms_count() {
241                 return 2;
242         }
243
244         function translate_plural($singular, $plural, $count, $context = null) {
245                         return 1 == $count? $singular : $plural;
246         }
247
248         function merge_with(&$other) {
249         }
250 }
251 endif;