wp/wp-includes/pomo/mo.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
     5  * @version $Id: mo.php 1157 2015-11-20 04:30:11Z dd32 $
     5  * @version $Id: mo.php 1157 2015-11-20 04:30:11Z dd32 $
     6  * @package pomo
     6  * @package pomo
     7  * @subpackage mo
     7  * @subpackage mo
     8  */
     8  */
     9 
     9 
    10 require_once dirname(__FILE__) . '/translations.php';
    10 require_once dirname( __FILE__ ) . '/translations.php';
    11 require_once dirname(__FILE__) . '/streams.php';
    11 require_once dirname( __FILE__ ) . '/streams.php';
    12 
    12 
    13 if ( ! class_exists( 'MO', false ) ):
    13 if ( ! class_exists( 'MO', false ) ) :
    14 class MO extends Gettext_Translations {
    14 	class MO extends Gettext_Translations {
    15 
    15 
    16 	var $_nplurals = 2;
    16 		var $_nplurals = 2;
    17 
    17 
    18 	/**
    18 		/**
    19 	 * Loaded MO file.
    19 		 * Loaded MO file.
    20 	 *
    20 		 *
    21 	 * @var string
    21 		 * @var string
    22 	 */
    22 		 */
    23 	private $filename = '';
    23 		private $filename = '';
    24 
    24 
    25 	/**
    25 		/**
    26 	 * Returns the loaded MO file.
    26 		 * Returns the loaded MO file.
    27 	 *
    27 		 *
    28 	 * @return string The loaded MO file.
    28 		 * @return string The loaded MO file.
    29 	 */
    29 		 */
    30 	public function get_filename() {
    30 		public function get_filename() {
    31 		return $this->filename;
    31 			return $this->filename;
       
    32 		}
       
    33 
       
    34 		/**
       
    35 		 * Fills up with the entries from MO file $filename
       
    36 		 *
       
    37 		 * @param string $filename MO file to load
       
    38 		 * @return bool True if the import from file was successful, otherwise false.
       
    39 		 */
       
    40 		function import_from_file( $filename ) {
       
    41 			$reader = new POMO_FileReader( $filename );
       
    42 
       
    43 			if ( ! $reader->is_resource() ) {
       
    44 				return false;
       
    45 			}
       
    46 
       
    47 			$this->filename = (string) $filename;
       
    48 
       
    49 			return $this->import_from_reader( $reader );
       
    50 		}
       
    51 
       
    52 		/**
       
    53 		 * @param string $filename
       
    54 		 * @return bool
       
    55 		 */
       
    56 		function export_to_file( $filename ) {
       
    57 			$fh = fopen( $filename, 'wb' );
       
    58 			if ( ! $fh ) {
       
    59 				return false;
       
    60 			}
       
    61 			$res = $this->export_to_file_handle( $fh );
       
    62 			fclose( $fh );
       
    63 			return $res;
       
    64 		}
       
    65 
       
    66 		/**
       
    67 		 * @return string|false
       
    68 		 */
       
    69 		function export() {
       
    70 			$tmp_fh = fopen( 'php://temp', 'r+' );
       
    71 			if ( ! $tmp_fh ) {
       
    72 				return false;
       
    73 			}
       
    74 			$this->export_to_file_handle( $tmp_fh );
       
    75 			rewind( $tmp_fh );
       
    76 			return stream_get_contents( $tmp_fh );
       
    77 		}
       
    78 
       
    79 		/**
       
    80 		 * @param Translation_Entry $entry
       
    81 		 * @return bool
       
    82 		 */
       
    83 		function is_entry_good_for_export( $entry ) {
       
    84 			if ( empty( $entry->translations ) ) {
       
    85 				return false;
       
    86 			}
       
    87 
       
    88 			if ( ! array_filter( $entry->translations ) ) {
       
    89 				return false;
       
    90 			}
       
    91 
       
    92 			return true;
       
    93 		}
       
    94 
       
    95 		/**
       
    96 		 * @param resource $fh
       
    97 		 * @return true
       
    98 		 */
       
    99 		function export_to_file_handle( $fh ) {
       
   100 			$entries = array_filter( $this->entries, array( $this, 'is_entry_good_for_export' ) );
       
   101 			ksort( $entries );
       
   102 			$magic                     = 0x950412de;
       
   103 			$revision                  = 0;
       
   104 			$total                     = count( $entries ) + 1; // all the headers are one entry
       
   105 			$originals_lenghts_addr    = 28;
       
   106 			$translations_lenghts_addr = $originals_lenghts_addr + 8 * $total;
       
   107 			$size_of_hash              = 0;
       
   108 			$hash_addr                 = $translations_lenghts_addr + 8 * $total;
       
   109 			$current_addr              = $hash_addr;
       
   110 			fwrite(
       
   111 				$fh,
       
   112 				pack(
       
   113 					'V*',
       
   114 					$magic,
       
   115 					$revision,
       
   116 					$total,
       
   117 					$originals_lenghts_addr,
       
   118 					$translations_lenghts_addr,
       
   119 					$size_of_hash,
       
   120 					$hash_addr
       
   121 				)
       
   122 			);
       
   123 			fseek( $fh, $originals_lenghts_addr );
       
   124 
       
   125 			// headers' msgid is an empty string
       
   126 			fwrite( $fh, pack( 'VV', 0, $current_addr ) );
       
   127 			$current_addr++;
       
   128 			$originals_table = "\0";
       
   129 
       
   130 			$reader = new POMO_Reader();
       
   131 
       
   132 			foreach ( $entries as $entry ) {
       
   133 				$originals_table .= $this->export_original( $entry ) . "\0";
       
   134 				$length           = $reader->strlen( $this->export_original( $entry ) );
       
   135 				fwrite( $fh, pack( 'VV', $length, $current_addr ) );
       
   136 				$current_addr += $length + 1; // account for the NULL byte after
       
   137 			}
       
   138 
       
   139 			$exported_headers = $this->export_headers();
       
   140 			fwrite( $fh, pack( 'VV', $reader->strlen( $exported_headers ), $current_addr ) );
       
   141 			$current_addr      += strlen( $exported_headers ) + 1;
       
   142 			$translations_table = $exported_headers . "\0";
       
   143 
       
   144 			foreach ( $entries as $entry ) {
       
   145 				$translations_table .= $this->export_translations( $entry ) . "\0";
       
   146 				$length              = $reader->strlen( $this->export_translations( $entry ) );
       
   147 				fwrite( $fh, pack( 'VV', $length, $current_addr ) );
       
   148 				$current_addr += $length + 1;
       
   149 			}
       
   150 
       
   151 			fwrite( $fh, $originals_table );
       
   152 			fwrite( $fh, $translations_table );
       
   153 			return true;
       
   154 		}
       
   155 
       
   156 		/**
       
   157 		 * @param Translation_Entry $entry
       
   158 		 * @return string
       
   159 		 */
       
   160 		function export_original( $entry ) {
       
   161 			//TODO: warnings for control characters
       
   162 			$exported = $entry->singular;
       
   163 			if ( $entry->is_plural ) {
       
   164 				$exported .= "\0" . $entry->plural;
       
   165 			}
       
   166 			if ( $entry->context ) {
       
   167 				$exported = $entry->context . "\4" . $exported;
       
   168 			}
       
   169 			return $exported;
       
   170 		}
       
   171 
       
   172 		/**
       
   173 		 * @param Translation_Entry $entry
       
   174 		 * @return string
       
   175 		 */
       
   176 		function export_translations( $entry ) {
       
   177 			//TODO: warnings for control characters
       
   178 			return $entry->is_plural ? implode( "\0", $entry->translations ) : $entry->translations[0];
       
   179 		}
       
   180 
       
   181 		/**
       
   182 		 * @return string
       
   183 		 */
       
   184 		function export_headers() {
       
   185 			$exported = '';
       
   186 			foreach ( $this->headers as $header => $value ) {
       
   187 				$exported .= "$header: $value\n";
       
   188 			}
       
   189 			return $exported;
       
   190 		}
       
   191 
       
   192 		/**
       
   193 		 * @param int $magic
       
   194 		 * @return string|false
       
   195 		 */
       
   196 		function get_byteorder( $magic ) {
       
   197 			// The magic is 0x950412de
       
   198 
       
   199 			// bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
       
   200 			$magic_little    = (int) - 1794895138;
       
   201 			$magic_little_64 = (int) 2500072158;
       
   202 			// 0xde120495
       
   203 			$magic_big = ( (int) - 569244523 ) & 0xFFFFFFFF;
       
   204 			if ( $magic_little == $magic || $magic_little_64 == $magic ) {
       
   205 				return 'little';
       
   206 			} elseif ( $magic_big == $magic ) {
       
   207 				return 'big';
       
   208 			} else {
       
   209 				return false;
       
   210 			}
       
   211 		}
       
   212 
       
   213 		/**
       
   214 		 * @param POMO_FileReader $reader
       
   215 		 * @return bool True if the import was successful, otherwise false.
       
   216 		 */
       
   217 		function import_from_reader( $reader ) {
       
   218 			$endian_string = MO::get_byteorder( $reader->readint32() );
       
   219 			if ( false === $endian_string ) {
       
   220 				return false;
       
   221 			}
       
   222 			$reader->setEndian( $endian_string );
       
   223 
       
   224 			$endian = ( 'big' == $endian_string ) ? 'N' : 'V';
       
   225 
       
   226 			$header = $reader->read( 24 );
       
   227 			if ( $reader->strlen( $header ) != 24 ) {
       
   228 				return false;
       
   229 			}
       
   230 
       
   231 			// parse header
       
   232 			$header = unpack( "{$endian}revision/{$endian}total/{$endian}originals_lenghts_addr/{$endian}translations_lenghts_addr/{$endian}hash_length/{$endian}hash_addr", $header );
       
   233 			if ( ! is_array( $header ) ) {
       
   234 				return false;
       
   235 			}
       
   236 
       
   237 			// support revision 0 of MO format specs, only
       
   238 			if ( $header['revision'] != 0 ) {
       
   239 				return false;
       
   240 			}
       
   241 
       
   242 			// seek to data blocks
       
   243 			$reader->seekto( $header['originals_lenghts_addr'] );
       
   244 
       
   245 			// read originals' indices
       
   246 			$originals_lengths_length = $header['translations_lenghts_addr'] - $header['originals_lenghts_addr'];
       
   247 			if ( $originals_lengths_length != $header['total'] * 8 ) {
       
   248 				return false;
       
   249 			}
       
   250 
       
   251 			$originals = $reader->read( $originals_lengths_length );
       
   252 			if ( $reader->strlen( $originals ) != $originals_lengths_length ) {
       
   253 				return false;
       
   254 			}
       
   255 
       
   256 			// read translations' indices
       
   257 			$translations_lenghts_length = $header['hash_addr'] - $header['translations_lenghts_addr'];
       
   258 			if ( $translations_lenghts_length != $header['total'] * 8 ) {
       
   259 				return false;
       
   260 			}
       
   261 
       
   262 			$translations = $reader->read( $translations_lenghts_length );
       
   263 			if ( $reader->strlen( $translations ) != $translations_lenghts_length ) {
       
   264 				return false;
       
   265 			}
       
   266 
       
   267 			// transform raw data into set of indices
       
   268 			$originals    = $reader->str_split( $originals, 8 );
       
   269 			$translations = $reader->str_split( $translations, 8 );
       
   270 
       
   271 			// skip hash table
       
   272 			$strings_addr = $header['hash_addr'] + $header['hash_length'] * 4;
       
   273 
       
   274 			$reader->seekto( $strings_addr );
       
   275 
       
   276 			$strings = $reader->read_all();
       
   277 			$reader->close();
       
   278 
       
   279 			for ( $i = 0; $i < $header['total']; $i++ ) {
       
   280 				$o = unpack( "{$endian}length/{$endian}pos", $originals[ $i ] );
       
   281 				$t = unpack( "{$endian}length/{$endian}pos", $translations[ $i ] );
       
   282 				if ( ! $o || ! $t ) {
       
   283 					return false;
       
   284 				}
       
   285 
       
   286 				// adjust offset due to reading strings to separate space before
       
   287 				$o['pos'] -= $strings_addr;
       
   288 				$t['pos'] -= $strings_addr;
       
   289 
       
   290 				$original    = $reader->substr( $strings, $o['pos'], $o['length'] );
       
   291 				$translation = $reader->substr( $strings, $t['pos'], $t['length'] );
       
   292 
       
   293 				if ( '' === $original ) {
       
   294 					$this->set_headers( $this->make_headers( $translation ) );
       
   295 				} else {
       
   296 					$entry                          = &$this->make_entry( $original, $translation );
       
   297 					$this->entries[ $entry->key() ] = &$entry;
       
   298 				}
       
   299 			}
       
   300 			return true;
       
   301 		}
       
   302 
       
   303 		/**
       
   304 		 * Build a Translation_Entry from original string and translation strings,
       
   305 		 * found in a MO file
       
   306 		 *
       
   307 		 * @static
       
   308 		 * @param string $original original string to translate from MO file. Might contain
       
   309 		 *  0x04 as context separator or 0x00 as singular/plural separator
       
   310 		 * @param string $translation translation string from MO file. Might contain
       
   311 		 *  0x00 as a plural translations separator
       
   312 		 * @return Translation_Entry Entry instance.
       
   313 		 */
       
   314 		function &make_entry( $original, $translation ) {
       
   315 			$entry = new Translation_Entry();
       
   316 			// Look for context, separated by \4.
       
   317 			$parts = explode( "\4", $original );
       
   318 			if ( isset( $parts[1] ) ) {
       
   319 				$original       = $parts[1];
       
   320 				$entry->context = $parts[0];
       
   321 			}
       
   322 			// look for plural original
       
   323 			$parts           = explode( "\0", $original );
       
   324 			$entry->singular = $parts[0];
       
   325 			if ( isset( $parts[1] ) ) {
       
   326 				$entry->is_plural = true;
       
   327 				$entry->plural    = $parts[1];
       
   328 			}
       
   329 			// plural translations are also separated by \0
       
   330 			$entry->translations = explode( "\0", $translation );
       
   331 			return $entry;
       
   332 		}
       
   333 
       
   334 		/**
       
   335 		 * @param int $count
       
   336 		 * @return string
       
   337 		 */
       
   338 		function select_plural_form( $count ) {
       
   339 			return $this->gettext_select_plural_form( $count );
       
   340 		}
       
   341 
       
   342 		/**
       
   343 		 * @return int
       
   344 		 */
       
   345 		function get_plural_forms_count() {
       
   346 			return $this->_nplurals;
       
   347 		}
    32 	}
   348 	}
    33 
       
    34 	/**
       
    35 	 * Fills up with the entries from MO file $filename
       
    36 	 *
       
    37 	 * @param string $filename MO file to load
       
    38 	 */
       
    39 	function import_from_file($filename) {
       
    40 		$reader = new POMO_FileReader( $filename );
       
    41 
       
    42 		if ( ! $reader->is_resource() ) {
       
    43 			return false;
       
    44 		}
       
    45 
       
    46 		$this->filename = (string) $filename;
       
    47 
       
    48 		return $this->import_from_reader( $reader );
       
    49 	}
       
    50 
       
    51 	/**
       
    52 	 * @param string $filename
       
    53 	 * @return bool
       
    54 	 */
       
    55 	function export_to_file($filename) {
       
    56 		$fh = fopen($filename, 'wb');
       
    57 		if ( !$fh ) return false;
       
    58 		$res = $this->export_to_file_handle( $fh );
       
    59 		fclose($fh);
       
    60 		return $res;
       
    61 	}
       
    62 
       
    63 	/**
       
    64 	 * @return string|false
       
    65 	 */
       
    66 	function export() {
       
    67 		$tmp_fh = fopen("php://temp", 'r+');
       
    68 		if ( !$tmp_fh ) return false;
       
    69 		$this->export_to_file_handle( $tmp_fh );
       
    70 		rewind( $tmp_fh );
       
    71 		return stream_get_contents( $tmp_fh );
       
    72 	}
       
    73 
       
    74 	/**
       
    75 	 * @param Translation_Entry $entry
       
    76 	 * @return bool
       
    77 	 */
       
    78 	function is_entry_good_for_export( $entry ) {
       
    79 		if ( empty( $entry->translations ) ) {
       
    80 			return false;
       
    81 		}
       
    82 
       
    83 		if ( !array_filter( $entry->translations ) ) {
       
    84 			return false;
       
    85 		}
       
    86 
       
    87 		return true;
       
    88 	}
       
    89 
       
    90 	/**
       
    91 	 * @param resource $fh
       
    92 	 * @return true
       
    93 	 */
       
    94 	function export_to_file_handle($fh) {
       
    95 		$entries = array_filter( $this->entries, array( $this, 'is_entry_good_for_export' ) );
       
    96 		ksort($entries);
       
    97 		$magic = 0x950412de;
       
    98 		$revision = 0;
       
    99 		$total = count($entries) + 1; // all the headers are one entry
       
   100 		$originals_lenghts_addr = 28;
       
   101 		$translations_lenghts_addr = $originals_lenghts_addr + 8 * $total;
       
   102 		$size_of_hash = 0;
       
   103 		$hash_addr = $translations_lenghts_addr + 8 * $total;
       
   104 		$current_addr = $hash_addr;
       
   105 		fwrite($fh, pack('V*', $magic, $revision, $total, $originals_lenghts_addr,
       
   106 			$translations_lenghts_addr, $size_of_hash, $hash_addr));
       
   107 		fseek($fh, $originals_lenghts_addr);
       
   108 
       
   109 		// headers' msgid is an empty string
       
   110 		fwrite($fh, pack('VV', 0, $current_addr));
       
   111 		$current_addr++;
       
   112 		$originals_table = chr(0);
       
   113 
       
   114 		$reader = new POMO_Reader();
       
   115 
       
   116 		foreach($entries as $entry) {
       
   117 			$originals_table .= $this->export_original($entry) . chr(0);
       
   118 			$length = $reader->strlen($this->export_original($entry));
       
   119 			fwrite($fh, pack('VV', $length, $current_addr));
       
   120 			$current_addr += $length + 1; // account for the NULL byte after
       
   121 		}
       
   122 
       
   123 		$exported_headers = $this->export_headers();
       
   124 		fwrite($fh, pack('VV', $reader->strlen($exported_headers), $current_addr));
       
   125 		$current_addr += strlen($exported_headers) + 1;
       
   126 		$translations_table = $exported_headers . chr(0);
       
   127 
       
   128 		foreach($entries as $entry) {
       
   129 			$translations_table .= $this->export_translations($entry) . chr(0);
       
   130 			$length = $reader->strlen($this->export_translations($entry));
       
   131 			fwrite($fh, pack('VV', $length, $current_addr));
       
   132 			$current_addr += $length + 1;
       
   133 		}
       
   134 
       
   135 		fwrite($fh, $originals_table);
       
   136 		fwrite($fh, $translations_table);
       
   137 		return true;
       
   138 	}
       
   139 
       
   140 	/**
       
   141 	 * @param Translation_Entry $entry
       
   142 	 * @return string
       
   143 	 */
       
   144 	function export_original($entry) {
       
   145 		//TODO: warnings for control characters
       
   146 		$exported = $entry->singular;
       
   147 		if ($entry->is_plural) $exported .= chr(0).$entry->plural;
       
   148 		if ($entry->context) $exported = $entry->context . chr(4) . $exported;
       
   149 		return $exported;
       
   150 	}
       
   151 
       
   152 	/**
       
   153 	 * @param Translation_Entry $entry
       
   154 	 * @return string
       
   155 	 */
       
   156 	function export_translations($entry) {
       
   157 		//TODO: warnings for control characters
       
   158 		return $entry->is_plural ? implode(chr(0), $entry->translations) : $entry->translations[0];
       
   159 	}
       
   160 
       
   161 	/**
       
   162 	 * @return string
       
   163 	 */
       
   164 	function export_headers() {
       
   165 		$exported = '';
       
   166 		foreach($this->headers as $header => $value) {
       
   167 			$exported.= "$header: $value\n";
       
   168 		}
       
   169 		return $exported;
       
   170 	}
       
   171 
       
   172 	/**
       
   173 	 * @param int $magic
       
   174 	 * @return string|false
       
   175 	 */
       
   176 	function get_byteorder($magic) {
       
   177 		// The magic is 0x950412de
       
   178 
       
   179 		// bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
       
   180 		$magic_little = (int) - 1794895138;
       
   181 		$magic_little_64 = (int) 2500072158;
       
   182 		// 0xde120495
       
   183 		$magic_big = ((int) - 569244523) & 0xFFFFFFFF;
       
   184 		if ($magic_little == $magic || $magic_little_64 == $magic) {
       
   185 			return 'little';
       
   186 		} else if ($magic_big == $magic) {
       
   187 			return 'big';
       
   188 		} else {
       
   189 			return false;
       
   190 		}
       
   191 	}
       
   192 
       
   193 	/**
       
   194 	 * @param POMO_FileReader $reader
       
   195 	 */
       
   196 	function import_from_reader($reader) {
       
   197 		$endian_string = MO::get_byteorder($reader->readint32());
       
   198 		if (false === $endian_string) {
       
   199 			return false;
       
   200 		}
       
   201 		$reader->setEndian($endian_string);
       
   202 
       
   203 		$endian = ('big' == $endian_string)? 'N' : 'V';
       
   204 
       
   205 		$header = $reader->read(24);
       
   206 		if ($reader->strlen($header) != 24)
       
   207 			return false;
       
   208 
       
   209 		// parse header
       
   210 		$header = unpack("{$endian}revision/{$endian}total/{$endian}originals_lenghts_addr/{$endian}translations_lenghts_addr/{$endian}hash_length/{$endian}hash_addr", $header);
       
   211 		if (!is_array($header))
       
   212 			return false;
       
   213 
       
   214 		// support revision 0 of MO format specs, only
       
   215 		if ( $header['revision'] != 0 ) {
       
   216 			return false;
       
   217 		}
       
   218 
       
   219 		// seek to data blocks
       
   220 		$reader->seekto( $header['originals_lenghts_addr'] );
       
   221 
       
   222 		// read originals' indices
       
   223 		$originals_lengths_length = $header['translations_lenghts_addr'] - $header['originals_lenghts_addr'];
       
   224 		if ( $originals_lengths_length != $header['total'] * 8 ) {
       
   225 			return false;
       
   226 		}
       
   227 
       
   228 		$originals = $reader->read($originals_lengths_length);
       
   229 		if ( $reader->strlen( $originals ) != $originals_lengths_length ) {
       
   230 			return false;
       
   231 		}
       
   232 
       
   233 		// read translations' indices
       
   234 		$translations_lenghts_length = $header['hash_addr'] - $header['translations_lenghts_addr'];
       
   235 		if ( $translations_lenghts_length != $header['total'] * 8 ) {
       
   236 			return false;
       
   237 		}
       
   238 
       
   239 		$translations = $reader->read($translations_lenghts_length);
       
   240 		if ( $reader->strlen( $translations ) != $translations_lenghts_length ) {
       
   241 			return false;
       
   242 		}
       
   243 
       
   244 		// transform raw data into set of indices
       
   245 		$originals    = $reader->str_split( $originals, 8 );
       
   246 		$translations = $reader->str_split( $translations, 8 );
       
   247 
       
   248 		// skip hash table
       
   249 		$strings_addr = $header['hash_addr'] + $header['hash_length'] * 4;
       
   250 
       
   251 		$reader->seekto($strings_addr);
       
   252 
       
   253 		$strings = $reader->read_all();
       
   254 		$reader->close();
       
   255 
       
   256 		for ( $i = 0; $i < $header['total']; $i++ ) {
       
   257 			$o = unpack( "{$endian}length/{$endian}pos", $originals[$i] );
       
   258 			$t = unpack( "{$endian}length/{$endian}pos", $translations[$i] );
       
   259 			if ( !$o || !$t ) return false;
       
   260 
       
   261 			// adjust offset due to reading strings to separate space before
       
   262 			$o['pos'] -= $strings_addr;
       
   263 			$t['pos'] -= $strings_addr;
       
   264 
       
   265 			$original    = $reader->substr( $strings, $o['pos'], $o['length'] );
       
   266 			$translation = $reader->substr( $strings, $t['pos'], $t['length'] );
       
   267 
       
   268 			if ('' === $original) {
       
   269 				$this->set_headers($this->make_headers($translation));
       
   270 			} else {
       
   271 				$entry = &$this->make_entry($original, $translation);
       
   272 				$this->entries[$entry->key()] = &$entry;
       
   273 			}
       
   274 		}
       
   275 		return true;
       
   276 	}
       
   277 
       
   278 	/**
       
   279 	 * Build a Translation_Entry from original string and translation strings,
       
   280 	 * found in a MO file
       
   281 	 *
       
   282 	 * @static
       
   283 	 * @param string $original original string to translate from MO file. Might contain
       
   284 	 * 	0x04 as context separator or 0x00 as singular/plural separator
       
   285 	 * @param string $translation translation string from MO file. Might contain
       
   286 	 * 	0x00 as a plural translations separator
       
   287 	 */
       
   288 	function &make_entry($original, $translation) {
       
   289 		$entry = new Translation_Entry();
       
   290 		// look for context
       
   291 		$parts = explode(chr(4), $original);
       
   292 		if (isset($parts[1])) {
       
   293 			$original = $parts[1];
       
   294 			$entry->context = $parts[0];
       
   295 		}
       
   296 		// look for plural original
       
   297 		$parts = explode(chr(0), $original);
       
   298 		$entry->singular = $parts[0];
       
   299 		if (isset($parts[1])) {
       
   300 			$entry->is_plural = true;
       
   301 			$entry->plural = $parts[1];
       
   302 		}
       
   303 		// plural translations are also separated by \0
       
   304 		$entry->translations = explode(chr(0), $translation);
       
   305 		return $entry;
       
   306 	}
       
   307 
       
   308 	/**
       
   309 	 * @param int $count
       
   310 	 * @return string
       
   311 	 */
       
   312 	function select_plural_form($count) {
       
   313 		return $this->gettext_select_plural_form($count);
       
   314 	}
       
   315 
       
   316 	/**
       
   317 	 * @return int
       
   318 	 */
       
   319 	function get_plural_forms_count() {
       
   320 		return $this->_nplurals;
       
   321 	}
       
   322 }
       
   323 endif;
   349 endif;