• File: class-wp-translation-file.php
  • Full Path: /home/u505525515/domains/medineeestates.com/public_html/wp-includes/l10n/class-wp-translation-file.php
  • Date Modified: 05/25/2026 6:29 AM
  • File size: 6.13 KB
  • MIME-type: text/x-php
  • Charset: utf-8
<?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();
}