3 * Class for a set of entries for translation and their associated headers |
3 * Class for a set of entries for translation and their associated headers |
4 * |
4 * |
5 * @version $Id: translations.php 1157 2015-11-20 04:30:11Z dd32 $ |
5 * @version $Id: translations.php 1157 2015-11-20 04:30:11Z dd32 $ |
6 * @package pomo |
6 * @package pomo |
7 * @subpackage translations |
7 * @subpackage translations |
|
8 * @since 2.8.0 |
8 */ |
9 */ |
9 |
10 |
10 require_once __DIR__ . '/plural-forms.php'; |
11 require_once __DIR__ . '/plural-forms.php'; |
11 require_once __DIR__ . '/entry.php'; |
12 require_once __DIR__ . '/entry.php'; |
12 |
13 |
13 if ( ! class_exists( 'Translations', false ) ) : |
14 if ( ! class_exists( 'Translations', false ) ) : |
|
15 /** |
|
16 * Translations class. |
|
17 * |
|
18 * @since 2.8.0 |
|
19 */ |
|
20 #[AllowDynamicProperties] |
14 class Translations { |
21 class Translations { |
|
22 /** |
|
23 * List of translation entries. |
|
24 * |
|
25 * @since 2.8.0 |
|
26 * |
|
27 * @var Translation_Entry[] |
|
28 */ |
15 public $entries = array(); |
29 public $entries = array(); |
|
30 |
|
31 /** |
|
32 * List of translation headers. |
|
33 * |
|
34 * @since 2.8.0 |
|
35 * |
|
36 * @var array<string, string> |
|
37 */ |
16 public $headers = array(); |
38 public $headers = array(); |
17 |
39 |
18 /** |
40 /** |
19 * Add entry to the PO structure |
41 * Adds an entry to the PO structure. |
|
42 * |
|
43 * @since 2.8.0 |
20 * |
44 * |
21 * @param array|Translation_Entry $entry |
45 * @param array|Translation_Entry $entry |
22 * @return bool true on success, false if the entry doesn't have a key |
46 * @return bool True on success, false if the entry doesn't have a key. |
23 */ |
47 */ |
24 public function add_entry( $entry ) { |
48 public function add_entry( $entry ) { |
25 if ( is_array( $entry ) ) { |
49 if ( is_array( $entry ) ) { |
26 $entry = new Translation_Entry( $entry ); |
50 $entry = new Translation_Entry( $entry ); |
27 } |
51 } |
58 * |
86 * |
59 * If the header already exists, it will be overwritten |
87 * If the header already exists, it will be overwritten |
60 * |
88 * |
61 * TODO: this should be out of this class, it is gettext specific |
89 * TODO: this should be out of this class, it is gettext specific |
62 * |
90 * |
|
91 * @since 2.8.0 |
|
92 * |
63 * @param string $header header name, without trailing : |
93 * @param string $header header name, without trailing : |
64 * @param string $value header value, without trailing \n |
94 * @param string $value header value, without trailing \n |
65 */ |
95 */ |
66 public function set_header( $header, $value ) { |
96 public function set_header( $header, $value ) { |
67 $this->headers[ $header ] = $value; |
97 $this->headers[ $header ] = $value; |
68 } |
98 } |
69 |
99 |
70 /** |
100 /** |
71 * @param array $headers |
101 * Sets translation headers. |
|
102 * |
|
103 * @since 2.8.0 |
|
104 * |
|
105 * @param array $headers Associative array of headers. |
72 */ |
106 */ |
73 public function set_headers( $headers ) { |
107 public function set_headers( $headers ) { |
74 foreach ( $headers as $header => $value ) { |
108 foreach ( $headers as $header => $value ) { |
75 $this->set_header( $header, $value ); |
109 $this->set_header( $header, $value ); |
76 } |
110 } |
77 } |
111 } |
78 |
112 |
79 /** |
113 /** |
|
114 * Returns a given translation header. |
|
115 * |
|
116 * @since 2.8.0 |
|
117 * |
80 * @param string $header |
118 * @param string $header |
|
119 * @return string|false Header if it exists, false otherwise. |
81 */ |
120 */ |
82 public function get_header( $header ) { |
121 public function get_header( $header ) { |
83 return isset( $this->headers[ $header ] ) ? $this->headers[ $header ] : false; |
122 return isset( $this->headers[ $header ] ) ? $this->headers[ $header ] : false; |
84 } |
123 } |
85 |
124 |
86 /** |
125 /** |
87 * @param Translation_Entry $entry |
126 * Returns a given translation entry. |
|
127 * |
|
128 * @since 2.8.0 |
|
129 * |
|
130 * @param Translation_Entry $entry Translation entry. |
|
131 * @return Translation_Entry|false Translation entry if it exists, false otherwise. |
88 */ |
132 */ |
89 public function translate_entry( &$entry ) { |
133 public function translate_entry( &$entry ) { |
90 $key = $entry->key(); |
134 $key = $entry->key(); |
91 return isset( $this->entries[ $key ] ) ? $this->entries[ $key ] : false; |
135 return isset( $this->entries[ $key ] ) ? $this->entries[ $key ] : false; |
92 } |
136 } |
93 |
137 |
94 /** |
138 /** |
|
139 * Translates a singular string. |
|
140 * |
|
141 * @since 2.8.0 |
|
142 * |
95 * @param string $singular |
143 * @param string $singular |
96 * @param string $context |
144 * @param string $context |
97 * @return string |
145 * @return string |
98 */ |
146 */ |
99 public function translate( $singular, $context = null ) { |
147 public function translate( $singular, $context = null ) { |
114 * 0 if there is one element, 1 otherwise |
162 * 0 if there is one element, 1 otherwise |
115 * |
163 * |
116 * This function should be overridden by the subclasses. For example MO/PO can derive the logic |
164 * This function should be overridden by the subclasses. For example MO/PO can derive the logic |
117 * from their headers. |
165 * from their headers. |
118 * |
166 * |
119 * @param int $count number of items |
167 * @since 2.8.0 |
|
168 * |
|
169 * @param int $count Number of items. |
|
170 * @return int Plural form to use. |
120 */ |
171 */ |
121 public function select_plural_form( $count ) { |
172 public function select_plural_form( $count ) { |
122 return 1 == $count ? 0 : 1; |
173 return 1 === (int) $count ? 0 : 1; |
123 } |
174 } |
124 |
175 |
125 /** |
176 /** |
126 * @return int |
177 * Returns the plural forms count. |
|
178 * |
|
179 * @since 2.8.0 |
|
180 * |
|
181 * @return int Plural forms count. |
127 */ |
182 */ |
128 public function get_plural_forms_count() { |
183 public function get_plural_forms_count() { |
129 return 2; |
184 return 2; |
130 } |
185 } |
131 |
186 |
132 /** |
187 /** |
|
188 * Translates a plural string. |
|
189 * |
|
190 * @since 2.8.0 |
|
191 * |
133 * @param string $singular |
192 * @param string $singular |
134 * @param string $plural |
193 * @param string $plural |
135 * @param int $count |
194 * @param int $count |
136 * @param string $context |
195 * @param string $context |
|
196 * @return string |
137 */ |
197 */ |
138 public function translate_plural( $singular, $plural, $count, $context = null ) { |
198 public function translate_plural( $singular, $plural, $count, $context = null ) { |
139 $entry = new Translation_Entry( |
199 $entry = new Translation_Entry( |
140 array( |
200 array( |
141 'singular' => $singular, |
201 'singular' => $singular, |
149 if ( $translated && 0 <= $index && $index < $total_plural_forms && |
209 if ( $translated && 0 <= $index && $index < $total_plural_forms && |
150 is_array( $translated->translations ) && |
210 is_array( $translated->translations ) && |
151 isset( $translated->translations[ $index ] ) ) { |
211 isset( $translated->translations[ $index ] ) ) { |
152 return $translated->translations[ $index ]; |
212 return $translated->translations[ $index ]; |
153 } else { |
213 } else { |
154 return 1 == $count ? $singular : $plural; |
214 return 1 === (int) $count ? $singular : $plural; |
155 } |
215 } |
156 } |
216 } |
157 |
217 |
158 /** |
218 /** |
159 * Merge $other in the current object. |
219 * Merges other translations into the current one. |
160 * |
220 * |
161 * @param Object $other Another Translation object, whose translations will be merged in this one (passed by reference). |
221 * @since 2.8.0 |
|
222 * |
|
223 * @param Translations $other Another Translation object, whose translations will be merged in this one (passed by reference). |
162 */ |
224 */ |
163 public function merge_with( &$other ) { |
225 public function merge_with( &$other ) { |
164 foreach ( $other->entries as $entry ) { |
226 foreach ( $other->entries as $entry ) { |
165 $this->entries[ $entry->key() ] = $entry; |
227 $this->entries[ $entry->key() ] = $entry; |
166 } |
228 } |
167 } |
229 } |
168 |
230 |
169 /** |
231 /** |
170 * @param object $other |
232 * Merges originals with existing entries. |
|
233 * |
|
234 * @since 2.8.0 |
|
235 * |
|
236 * @param Translations $other |
171 */ |
237 */ |
172 public function merge_originals_with( &$other ) { |
238 public function merge_originals_with( &$other ) { |
173 foreach ( $other->entries as $entry ) { |
239 foreach ( $other->entries as $entry ) { |
174 if ( ! isset( $this->entries[ $entry->key() ] ) ) { |
240 if ( ! isset( $this->entries[ $entry->key() ] ) ) { |
175 $this->entries[ $entry->key() ] = $entry; |
241 $this->entries[ $entry->key() ] = $entry; |
178 } |
244 } |
179 } |
245 } |
180 } |
246 } |
181 } |
247 } |
182 |
248 |
|
249 /** |
|
250 * Gettext_Translations class. |
|
251 * |
|
252 * @since 2.8.0 |
|
253 */ |
183 class Gettext_Translations extends Translations { |
254 class Gettext_Translations extends Translations { |
|
255 |
|
256 /** |
|
257 * Number of plural forms. |
|
258 * |
|
259 * @var int |
|
260 * |
|
261 * @since 2.8.0 |
|
262 */ |
|
263 public $_nplurals; |
|
264 |
|
265 /** |
|
266 * Callback to retrieve the plural form. |
|
267 * |
|
268 * @var callable |
|
269 * |
|
270 * @since 2.8.0 |
|
271 */ |
|
272 public $_gettext_select_plural_form; |
|
273 |
184 /** |
274 /** |
185 * The gettext implementation of select_plural_form. |
275 * The gettext implementation of select_plural_form. |
186 * |
276 * |
187 * It lives in this class, because there are more than one descendand, which will use it and |
277 * It lives in this class, because there are more than one descendant, which will use it and |
188 * they can't share it effectively. |
278 * they can't share it effectively. |
189 * |
279 * |
190 * @param int $count |
280 * @since 2.8.0 |
|
281 * |
|
282 * @param int $count Plural forms count. |
|
283 * @return int Plural form to use. |
191 */ |
284 */ |
192 public function gettext_select_plural_form( $count ) { |
285 public function gettext_select_plural_form( $count ) { |
193 if ( ! isset( $this->_gettext_select_plural_form ) || is_null( $this->_gettext_select_plural_form ) ) { |
286 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' ) ); |
287 list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header( $this->get_header( 'Plural-Forms' ) ); |
195 $this->_nplurals = $nplurals; |
288 $this->_nplurals = $nplurals; |
197 } |
290 } |
198 return call_user_func( $this->_gettext_select_plural_form, $count ); |
291 return call_user_func( $this->_gettext_select_plural_form, $count ); |
199 } |
292 } |
200 |
293 |
201 /** |
294 /** |
|
295 * Returns the nplurals and plural forms expression from the Plural-Forms header. |
|
296 * |
|
297 * @since 2.8.0 |
|
298 * |
202 * @param string $header |
299 * @param string $header |
203 * @return array |
300 * @return array{0: int, 1: string} |
204 */ |
301 */ |
205 public function nplurals_and_expression_from_header( $header ) { |
302 public function nplurals_and_expression_from_header( $header ) { |
206 if ( preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches ) ) { |
303 if ( preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches ) ) { |
207 $nplurals = (int) $matches[1]; |
304 $nplurals = (int) $matches[1]; |
208 $expression = trim( $matches[2] ); |
305 $expression = trim( $matches[2] ); |
212 } |
309 } |
213 } |
310 } |
214 |
311 |
215 /** |
312 /** |
216 * Makes a function, which will return the right translation index, according to the |
313 * Makes a function, which will return the right translation index, according to the |
217 * plural forms header |
314 * plural forms header. |
|
315 * |
|
316 * @since 2.8.0 |
218 * |
317 * |
219 * @param int $nplurals |
318 * @param int $nplurals |
220 * @param string $expression |
319 * @param string $expression |
|
320 * @return callable |
221 */ |
321 */ |
222 public function make_plural_form_function( $nplurals, $expression ) { |
322 public function make_plural_form_function( $nplurals, $expression ) { |
223 try { |
323 try { |
224 $handler = new Plural_Forms( rtrim( $expression, ';' ) ); |
324 $handler = new Plural_Forms( rtrim( $expression, ';' ) ); |
225 return array( $handler, 'get' ); |
325 return array( $handler, 'get' ); |
260 } |
365 } |
261 return rtrim( $res, ';' ); |
366 return rtrim( $res, ';' ); |
262 } |
367 } |
263 |
368 |
264 /** |
369 /** |
|
370 * Prepare translation headers. |
|
371 * |
|
372 * @since 2.8.0 |
|
373 * |
265 * @param string $translation |
374 * @param string $translation |
266 * @return array |
375 * @return array<string, string> Translation headers |
267 */ |
376 */ |
268 public function make_headers( $translation ) { |
377 public function make_headers( $translation ) { |
269 $headers = array(); |
378 $headers = array(); |
270 // Sometimes \n's are used instead of real new lines. |
379 // Sometimes \n's are used instead of real new lines. |
271 $translation = str_replace( '\n', "\n", $translation ); |
380 $translation = str_replace( '\n', "\n", $translation ); |
295 } |
408 } |
296 endif; |
409 endif; |
297 |
410 |
298 if ( ! class_exists( 'NOOP_Translations', false ) ) : |
411 if ( ! class_exists( 'NOOP_Translations', false ) ) : |
299 /** |
412 /** |
300 * Provides the same interface as Translations, but doesn't do anything |
413 * Provides the same interface as Translations, but doesn't do anything. |
|
414 * |
|
415 * @since 2.8.0 |
301 */ |
416 */ |
|
417 #[AllowDynamicProperties] |
302 class NOOP_Translations { |
418 class NOOP_Translations { |
|
419 /** |
|
420 * List of translation entries. |
|
421 * |
|
422 * @since 2.8.0 |
|
423 * |
|
424 * @var Translation_Entry[] |
|
425 */ |
303 public $entries = array(); |
426 public $entries = array(); |
|
427 |
|
428 /** |
|
429 * List of translation headers. |
|
430 * |
|
431 * @since 2.8.0 |
|
432 * |
|
433 * @var array<string, string> |
|
434 */ |
304 public $headers = array(); |
435 public $headers = array(); |
305 |
436 |
306 public function add_entry( $entry ) { |
437 public function add_entry( $entry ) { |
307 return true; |
438 return true; |
308 } |
439 } |
309 |
440 |
310 /** |
441 /** |
|
442 * Sets a translation header. |
|
443 * |
|
444 * @since 2.8.0 |
|
445 * |
311 * @param string $header |
446 * @param string $header |
312 * @param string $value |
447 * @param string $value |
313 */ |
448 */ |
314 public function set_header( $header, $value ) { |
449 public function set_header( $header, $value ) { |
315 } |
450 } |
316 |
451 |
317 /** |
452 /** |
|
453 * Sets translation headers. |
|
454 * |
|
455 * @since 2.8.0 |
|
456 * |
318 * @param array $headers |
457 * @param array $headers |
319 */ |
458 */ |
320 public function set_headers( $headers ) { |
459 public function set_headers( $headers ) { |
321 } |
460 } |
322 |
461 |
323 /** |
462 /** |
|
463 * Returns a translation header. |
|
464 * |
|
465 * @since 2.8.0 |
|
466 * |
324 * @param string $header |
467 * @param string $header |
325 * @return false |
468 * @return false |
326 */ |
469 */ |
327 public function get_header( $header ) { |
470 public function get_header( $header ) { |
328 return false; |
471 return false; |
329 } |
472 } |
330 |
473 |
331 /** |
474 /** |
|
475 * Returns a given translation entry. |
|
476 * |
|
477 * @since 2.8.0 |
|
478 * |
332 * @param Translation_Entry $entry |
479 * @param Translation_Entry $entry |
333 * @return false |
480 * @return false |
334 */ |
481 */ |
335 public function translate_entry( &$entry ) { |
482 public function translate_entry( &$entry ) { |
336 return false; |
483 return false; |
337 } |
484 } |
338 |
485 |
339 /** |
486 /** |
|
487 * Translates a singular string. |
|
488 * |
|
489 * @since 2.8.0 |
|
490 * |
340 * @param string $singular |
491 * @param string $singular |
341 * @param string $context |
492 * @param string $context |
342 */ |
493 */ |
343 public function translate( $singular, $context = null ) { |
494 public function translate( $singular, $context = null ) { |
344 return $singular; |
495 return $singular; |
345 } |
496 } |
346 |
497 |
347 /** |
498 /** |
|
499 * Returns the plural form to use. |
|
500 * |
|
501 * @since 2.8.0 |
|
502 * |
348 * @param int $count |
503 * @param int $count |
349 * @return bool |
504 * @return int |
350 */ |
505 */ |
351 public function select_plural_form( $count ) { |
506 public function select_plural_form( $count ) { |
352 return 1 == $count ? 0 : 1; |
507 return 1 === (int) $count ? 0 : 1; |
353 } |
508 } |
354 |
509 |
355 /** |
510 /** |
|
511 * Returns the plural forms count. |
|
512 * |
|
513 * @since 2.8.0 |
|
514 * |
356 * @return int |
515 * @return int |
357 */ |
516 */ |
358 public function get_plural_forms_count() { |
517 public function get_plural_forms_count() { |
359 return 2; |
518 return 2; |
360 } |
519 } |
361 |
520 |
362 /** |
521 /** |
|
522 * Translates a plural string. |
|
523 * |
|
524 * @since 2.8.0 |
|
525 * |
363 * @param string $singular |
526 * @param string $singular |
364 * @param string $plural |
527 * @param string $plural |
365 * @param int $count |
528 * @param int $count |
366 * @param string $context |
529 * @param string $context |
|
530 * @return string |
367 */ |
531 */ |
368 public function translate_plural( $singular, $plural, $count, $context = null ) { |
532 public function translate_plural( $singular, $plural, $count, $context = null ) { |
369 return 1 == $count ? $singular : $plural; |
533 return 1 === (int) $count ? $singular : $plural; |
370 } |
534 } |
371 |
535 |
372 /** |
536 /** |
373 * @param object $other |
537 * Merges other translations into the current one. |
|
538 * |
|
539 * @since 2.8.0 |
|
540 * |
|
541 * @param Translations $other |
374 */ |
542 */ |
375 public function merge_with( &$other ) { |
543 public function merge_with( &$other ) { |
376 } |
544 } |
377 } |
545 } |
378 endif; |
546 endif; |