diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 07:56:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 07:56:49 +0000 |
commit | a415c29efee45520ae252d2aa28f1083a521cd7b (patch) | |
tree | f4ade4b6668ecc0765de7e1424f7c1427ad433ff /wp-includes/pomo/translations.php | |
parent | Initial commit. (diff) | |
download | wordpress-a415c29efee45520ae252d2aa28f1083a521cd7b.tar.xz wordpress-a415c29efee45520ae252d2aa28f1083a521cd7b.zip |
Adding upstream version 6.4.3+dfsg1.upstream/6.4.3+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'wp-includes/pomo/translations.php')
-rw-r--r-- | wp-includes/pomo/translations.php | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/wp-includes/pomo/translations.php b/wp-includes/pomo/translations.php new file mode 100644 index 0000000..a5534a8 --- /dev/null +++ b/wp-includes/pomo/translations.php @@ -0,0 +1,395 @@ +<?php +/** + * Class for a set of entries for translation and their associated headers + * + * @version $Id: translations.php 1157 2015-11-20 04:30:11Z dd32 $ + * @package pomo + * @subpackage translations + */ + +require_once __DIR__ . '/plural-forms.php'; +require_once __DIR__ . '/entry.php'; + +if ( ! class_exists( 'Translations', false ) ) : + #[AllowDynamicProperties] + class Translations { + public $entries = array(); + public $headers = array(); + + /** + * Add entry to the PO structure + * + * @param array|Translation_Entry $entry + * @return bool true on success, false if the entry doesn't have a key + */ + public function add_entry( $entry ) { + if ( is_array( $entry ) ) { + $entry = new Translation_Entry( $entry ); + } + $key = $entry->key(); + if ( false === $key ) { + return false; + } + $this->entries[ $key ] = &$entry; + return true; + } + + /** + * @param array|Translation_Entry $entry + * @return bool + */ + public function add_entry_or_merge( $entry ) { + if ( is_array( $entry ) ) { + $entry = new Translation_Entry( $entry ); + } + $key = $entry->key(); + if ( false === $key ) { + return false; + } + if ( isset( $this->entries[ $key ] ) ) { + $this->entries[ $key ]->merge_with( $entry ); + } else { + $this->entries[ $key ] = &$entry; + } + return true; + } + + /** + * Sets $header PO header to $value + * + * If the header already exists, it will be overwritten + * + * TODO: this should be out of this class, it is gettext specific + * + * @param string $header header name, without trailing : + * @param string $value header value, without trailing \n + */ + public function set_header( $header, $value ) { + $this->headers[ $header ] = $value; + } + + /** + * @param array $headers + */ + public function set_headers( $headers ) { + foreach ( $headers as $header => $value ) { + $this->set_header( $header, $value ); + } + } + + /** + * @param string $header + */ + public function get_header( $header ) { + return isset( $this->headers[ $header ] ) ? $this->headers[ $header ] : false; + } + + /** + * @param Translation_Entry $entry + */ + public function translate_entry( &$entry ) { + $key = $entry->key(); + return isset( $this->entries[ $key ] ) ? $this->entries[ $key ] : false; + } + + /** + * @param string $singular + * @param string $context + * @return string + */ + public function translate( $singular, $context = null ) { + $entry = new Translation_Entry( + array( + 'singular' => $singular, + 'context' => $context, + ) + ); + $translated = $this->translate_entry( $entry ); + return ( $translated && ! empty( $translated->translations ) ) ? $translated->translations[0] : $singular; + } + + /** + * Given the number of items, returns the 0-based index of the plural form to use + * + * Here, in the base Translations class, the common logic for English is implemented: + * 0 if there is one element, 1 otherwise + * + * This function should be overridden by the subclasses. For example MO/PO can derive the logic + * from their headers. + * + * @param int $count number of items + */ + public function select_plural_form( $count ) { + return 1 === (int) $count ? 0 : 1; + } + + /** + * @return int + */ + public function get_plural_forms_count() { + return 2; + } + + /** + * @param string $singular + * @param string $plural + * @param int $count + * @param string $context + */ + public function translate_plural( $singular, $plural, $count, $context = null ) { + $entry = new Translation_Entry( + array( + 'singular' => $singular, + 'plural' => $plural, + 'context' => $context, + ) + ); + $translated = $this->translate_entry( $entry ); + $index = $this->select_plural_form( $count ); + $total_plural_forms = $this->get_plural_forms_count(); + if ( $translated && 0 <= $index && $index < $total_plural_forms && + is_array( $translated->translations ) && + isset( $translated->translations[ $index ] ) ) { + return $translated->translations[ $index ]; + } else { + return 1 === (int) $count ? $singular : $plural; + } + } + + /** + * Merge $other in the current object. + * + * @param Object $other Another Translation object, whose translations will be merged in this one (passed by reference). + */ + public function merge_with( &$other ) { + foreach ( $other->entries as $entry ) { + $this->entries[ $entry->key() ] = $entry; + } + } + + /** + * @param object $other + */ + public function merge_originals_with( &$other ) { + foreach ( $other->entries as $entry ) { + if ( ! isset( $this->entries[ $entry->key() ] ) ) { + $this->entries[ $entry->key() ] = $entry; + } else { + $this->entries[ $entry->key() ]->merge_with( $entry ); + } + } + } + } + + class Gettext_Translations extends Translations { + + /** + * Number of plural forms. + * + * @var int + */ + public $_nplurals; + + /** + * Callback to retrieve the plural form. + * + * @var callable + */ + public $_gettext_select_plural_form; + + /** + * The gettext implementation of select_plural_form. + * + * It lives in this class, because there are more than one descendand, which will use it and + * they can't share it effectively. + * + * @param int $count + */ + public function gettext_select_plural_form( $count ) { + if ( ! isset( $this->_gettext_select_plural_form ) || is_null( $this->_gettext_select_plural_form ) ) { + list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header( $this->get_header( 'Plural-Forms' ) ); + $this->_nplurals = $nplurals; + $this->_gettext_select_plural_form = $this->make_plural_form_function( $nplurals, $expression ); + } + return call_user_func( $this->_gettext_select_plural_form, $count ); + } + + /** + * @param string $header + * @return array + */ + public function nplurals_and_expression_from_header( $header ) { + if ( preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches ) ) { + $nplurals = (int) $matches[1]; + $expression = trim( $matches[2] ); + return array( $nplurals, $expression ); + } else { + return array( 2, 'n != 1' ); + } + } + + /** + * Makes a function, which will return the right translation index, according to the + * plural forms header + * + * @param int $nplurals + * @param string $expression + */ + public function make_plural_form_function( $nplurals, $expression ) { + 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( 2, 'n != 1' ); + } + } + + /** + * Adds parentheses to the inner parts of ternary operators in + * plural expressions, because PHP evaluates ternary oerators from left to right + * + * @param string $expression the expression without parentheses + * @return string the expression with parentheses added + */ + public function parenthesize_plural_exression( $expression ) { + $expression .= ';'; + $res = ''; + $depth = 0; + for ( $i = 0; $i < strlen( $expression ); ++$i ) { + $char = $expression[ $i ]; + switch ( $char ) { + case '?': + $res .= ' ? ('; + ++$depth; + break; + case ':': + $res .= ') : ('; + break; + case ';': + $res .= str_repeat( ')', $depth ) . ';'; + $depth = 0; + break; + default: + $res .= $char; + } + } + return rtrim( $res, ';' ); + } + + /** + * @param string $translation + * @return array + */ + public function make_headers( $translation ) { + $headers = array(); + // Sometimes \n's are used instead of real new lines. + $translation = str_replace( '\n', "\n", $translation ); + $lines = explode( "\n", $translation ); + foreach ( $lines as $line ) { + $parts = explode( ':', $line, 2 ); + if ( ! isset( $parts[1] ) ) { + continue; + } + $headers[ trim( $parts[0] ) ] = trim( $parts[1] ); + } + return $headers; + } + + /** + * @param string $header + * @param string $value + */ + public function set_header( $header, $value ) { + parent::set_header( $header, $value ); + if ( 'Plural-Forms' === $header ) { + list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header( $this->get_header( 'Plural-Forms' ) ); + $this->_nplurals = $nplurals; + $this->_gettext_select_plural_form = $this->make_plural_form_function( $nplurals, $expression ); + } + } + } +endif; + +if ( ! class_exists( 'NOOP_Translations', false ) ) : + /** + * Provides the same interface as Translations, but doesn't do anything + */ + #[AllowDynamicProperties] + class NOOP_Translations { + public $entries = array(); + public $headers = array(); + + public function add_entry( $entry ) { + return true; + } + + /** + * @param string $header + * @param string $value + */ + public function set_header( $header, $value ) { + } + + /** + * @param array $headers + */ + public function set_headers( $headers ) { + } + + /** + * @param string $header + * @return false + */ + public function get_header( $header ) { + return false; + } + + /** + * @param Translation_Entry $entry + * @return false + */ + public function translate_entry( &$entry ) { + return false; + } + + /** + * @param string $singular + * @param string $context + */ + public function translate( $singular, $context = null ) { + return $singular; + } + + /** + * @param int $count + * @return bool + */ + public function select_plural_form( $count ) { + return 1 === (int) $count ? 0 : 1; + } + + /** + * @return int + */ + public function get_plural_forms_count() { + return 2; + } + + /** + * @param string $singular + * @param string $plural + * @param int $count + * @param string $context + */ + public function translate_plural( $singular, $plural, $count, $context = null ) { + return 1 === (int) $count ? $singular : $plural; + } + + /** + * @param object $other + */ + public function merge_with( &$other ) { + } + } +endif; |