diff options
Diffstat (limited to 'wp-includes/l10n/class-wp-translation-file.php')
-rw-r--r-- | wp-includes/l10n/class-wp-translation-file.php | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/wp-includes/l10n/class-wp-translation-file.php b/wp-includes/l10n/class-wp-translation-file.php new file mode 100644 index 0000000..e550f9c --- /dev/null +++ b/wp-includes/l10n/class-wp-translation-file.php @@ -0,0 +1,312 @@ +<?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(); +} |