home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / pomo / translations.php < prev   
Encoding:
PHP Script  |  2017-10-03  |  8.6 KB  |  362 lines

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