313 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			313 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * I18N: WP_Translation_File class.
 | |
|  *
 | |
|  * @package WordPress
 | |
|  * @subpackage I18N
 | |
|  * @since 6.5.0
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Class WP_Translation_File.
 | |
|  *
 | |
|  * @since 6.5.0
 | |
|  */
 | |
| abstract class WP_Translation_File {
 | |
| 	/**
 | |
| 	 * List of headers.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 * @var array<string, string>
 | |
| 	 */
 | |
| 	protected $headers = array();
 | |
| 
 | |
| 	/**
 | |
| 	 * Whether file has been parsed.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 * @var bool
 | |
| 	 */
 | |
| 	protected $parsed = false;
 | |
| 
 | |
| 	/**
 | |
| 	 * Error information.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 * @var string|null Error message or null if no error.
 | |
| 	 */
 | |
| 	protected $error;
 | |
| 
 | |
| 	/**
 | |
| 	 * File name.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 * @var string
 | |
| 	 */
 | |
| 	protected $file = '';
 | |
| 
 | |
| 	/**
 | |
| 	 * Translation entries.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 * @var array<string, string>
 | |
| 	 */
 | |
| 	protected $entries = array();
 | |
| 
 | |
| 	/**
 | |
| 	 * Plural forms function.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 * @var callable|null Plural forms.
 | |
| 	 */
 | |
| 	protected $plural_forms = null;
 | |
| 
 | |
| 	/**
 | |
| 	 * Constructor.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @param string $file File to load.
 | |
| 	 */
 | |
| 	protected function __construct( string $file ) {
 | |
| 		$this->file = $file;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Creates a new WP_Translation_File instance for a given file.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @param string      $file     File name.
 | |
| 	 * @param string|null $filetype Optional. File type. Default inferred from file name.
 | |
| 	 * @return false|WP_Translation_File
 | |
| 	 */
 | |
| 	public static function create( string $file, string $filetype = null ) {
 | |
| 		if ( ! is_readable( $file ) ) {
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		if ( null === $filetype ) {
 | |
| 			$pos = strrpos( $file, '.' );
 | |
| 			if ( false !== $pos ) {
 | |
| 				$filetype = substr( $file, $pos + 1 );
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		switch ( $filetype ) {
 | |
| 			case 'mo':
 | |
| 				return new WP_Translation_File_MO( $file );
 | |
| 			case 'php':
 | |
| 				return new WP_Translation_File_PHP( $file );
 | |
| 			default:
 | |
| 				return false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Creates a new WP_Translation_File instance for a given file.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @param string $file     Source file name.
 | |
| 	 * @param string $filetype Desired target file type.
 | |
| 	 * @return string|false Transformed translation file contents on success, false otherwise.
 | |
| 	 */
 | |
| 	public static function transform( string $file, string $filetype ) {
 | |
| 		$source = self::create( $file );
 | |
| 
 | |
| 		if ( false === $source ) {
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		switch ( $filetype ) {
 | |
| 			case 'mo':
 | |
| 				$destination = new WP_Translation_File_MO( '' );
 | |
| 				break;
 | |
| 			case 'php':
 | |
| 				$destination = new WP_Translation_File_PHP( '' );
 | |
| 				break;
 | |
| 			default:
 | |
| 				return false;
 | |
| 		}
 | |
| 
 | |
| 		$success = $destination->import( $source );
 | |
| 
 | |
| 		if ( ! $success ) {
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		return $destination->export();
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Returns all headers.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @return array<string, string> Headers.
 | |
| 	 */
 | |
| 	public function headers(): array {
 | |
| 		if ( ! $this->parsed ) {
 | |
| 			$this->parse_file();
 | |
| 		}
 | |
| 		return $this->headers;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Returns all entries.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @return array<string, string[]> Entries.
 | |
| 	 */
 | |
| 	public function entries(): array {
 | |
| 		if ( ! $this->parsed ) {
 | |
| 			$this->parse_file();
 | |
| 		}
 | |
| 
 | |
| 		return $this->entries;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Returns the current error information.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @return string|null Error message or null if no error.
 | |
| 	 */
 | |
| 	public function error() {
 | |
| 		return $this->error;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Returns the file name.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @return string File name.
 | |
| 	 */
 | |
| 	public function get_file(): string {
 | |
| 		return $this->file;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Translates a given string.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @param string $text String to translate.
 | |
| 	 * @return false|string Translation(s) on success, false otherwise.
 | |
| 	 */
 | |
| 	public function translate( string $text ) {
 | |
| 		if ( ! $this->parsed ) {
 | |
| 			$this->parse_file();
 | |
| 		}
 | |
| 
 | |
| 		return $this->entries[ $text ] ?? false;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Returns the plural form for a given number.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @param int $number Count.
 | |
| 	 * @return int Plural form.
 | |
| 	 */
 | |
| 	public function get_plural_form( int $number ): int {
 | |
| 		if ( ! $this->parsed ) {
 | |
| 			$this->parse_file();
 | |
| 		}
 | |
| 
 | |
| 		if ( null === $this->plural_forms && isset( $this->headers['plural-forms'] ) ) {
 | |
| 			$expression         = $this->get_plural_expression_from_header( $this->headers['plural-forms'] );
 | |
| 			$this->plural_forms = $this->make_plural_form_function( $expression );
 | |
| 		}
 | |
| 
 | |
| 		if ( is_callable( $this->plural_forms ) ) {
 | |
| 			/**
 | |
| 			 * Plural form.
 | |
| 			 *
 | |
| 			 * @var int $result Plural form.
 | |
| 			 */
 | |
| 			$result = call_user_func( $this->plural_forms, $number );
 | |
| 
 | |
| 			return $result;
 | |
| 		}
 | |
| 
 | |
| 		// Default plural form matches English, only "One" is considered singular.
 | |
| 		return ( 1 === $number ? 0 : 1 );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Returns the plural forms expression as a tuple.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @param string $header Plural-Forms header string.
 | |
| 	 * @return string Plural forms expression.
 | |
| 	 */
 | |
| 	protected function get_plural_expression_from_header( string $header ): string {
 | |
| 		if ( preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches ) ) {
 | |
| 			return trim( $matches[2] );
 | |
| 		}
 | |
| 
 | |
| 		return 'n != 1';
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Makes a function, which will return the right translation index, according to the
 | |
| 	 * plural forms header.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @param string $expression Plural form expression.
 | |
| 	 * @return callable(int $num): int Plural forms function.
 | |
| 	 */
 | |
| 	protected function make_plural_form_function( string $expression ): callable {
 | |
| 		try {
 | |
| 			$handler = new Plural_Forms( rtrim( $expression, ';' ) );
 | |
| 			return array( $handler, 'get' );
 | |
| 		} catch ( Exception $e ) {
 | |
| 			// Fall back to default plural-form function.
 | |
| 			return $this->make_plural_form_function( 'n != 1' );
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Imports translations from another file.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @param WP_Translation_File $source Source file.
 | |
| 	 * @return bool True on success, false otherwise.
 | |
| 	 */
 | |
| 	protected function import( WP_Translation_File $source ): bool {
 | |
| 		if ( null !== $source->error() ) {
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		$this->headers = $source->headers();
 | |
| 		$this->entries = $source->entries();
 | |
| 		$this->error   = $source->error();
 | |
| 
 | |
| 		return null === $this->error;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Parses the file.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 */
 | |
| 	abstract protected function parse_file();
 | |
| 
 | |
| 	/**
 | |
| 	 * Exports translation contents as a string.
 | |
| 	 *
 | |
| 	 * @since 6.5.0
 | |
| 	 *
 | |
| 	 * @return string Translation file contents.
 | |
| 	 */
 | |
| 	abstract public function export();
 | |
| }
 |