As the sun rises and the forest mist clears, and the clouds return and the caves darken, these changes of light and shadow are the morning and evening in the mountains. Wildflowers bloom with their subtle fragrance, fine trees flourish with their dense shade, the wind and frost are pure and clean, and the water recedes to reveal the rocks—these are the four seasons in the mountains. Going out in the morning and returning in the evening, the scenery of the four seasons is different, and the joy is endless.至于负者歌于途,行者休于树,前者呼,后者应,伛偻提携,往来而不绝者,滁人游也。临溪而渔,溪深而鱼肥,酿泉为酒,泉香而酒洌,山肴野蔌,杂然而前陈者,太守宴也。宴酣之乐,非丝非竹,射者中,弈者胜,觥筹交错,起坐而喧哗者,众宾欢也。苍颜白发,颓然乎其间者,太守醉也。
<?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();
}