WordPress.org

Make WordPress Core

Ticket #41305: 41305.5.diff

File 41305.5.diff, 56.9 KB (added by TimothyBlynJacobs, 7 months ago)
  • src/wp-includes/class-wp-locale.php

    diff --git a/src/wp-includes/class-wp-locale.php b/src/wp-includes/class-wp-locale.php
    index ee92bee317..07b9fcf1ab 100644
    a b class WP_Locale { 
    127127                $this->weekday[6] = /* translators: weekday */ __( 'Saturday' );
    128128
    129129                // The first letter of each day.
    130                 $this->weekday_initial[ __( 'Sunday' ) ]    = /* translators: one-letter abbreviation of the weekday */ _x( 'S', 'Sunday initial' );
    131                 $this->weekday_initial[ __( 'Monday' ) ]    = /* translators: one-letter abbreviation of the weekday */ _x( 'M', 'Monday initial' );
    132                 $this->weekday_initial[ __( 'Tuesday' ) ]  = /* translators: one-letter abbreviation of the weekday */ _x( 'T', 'Tuesday initial' );
    133                 $this->weekday_initial[ __( 'Wednesday' ) ] = /* translators: one-letter abbreviation of the weekday */ _x( 'W', 'Wednesday initial' );
    134                 $this->weekday_initial[ __( 'Thursday' ) ] = /* translators: one-letter abbreviation of the weekday */ _x( 'T', 'Thursday initial' );
    135                 $this->weekday_initial[ __( 'Friday' ) ]    = /* translators: one-letter abbreviation of the weekday */ _x( 'F', 'Friday initial' );
    136                 $this->weekday_initial[ __( 'Saturday' ) ] = /* translators: one-letter abbreviation of the weekday */ _x( 'S', 'Saturday initial' );
     130                $this->weekday_initial[ (string) $this->weekday[0] ] = /* translators: one-letter abbreviation of the weekday */ _x( 'S', 'Sunday initial' );
     131                $this->weekday_initial[ (string) $this->weekday[1] ] = /* translators: one-letter abbreviation of the weekday */ _x( 'M', 'Monday initial' );
     132                $this->weekday_initial[ (string) $this->weekday[2] ] = /* translators: one-letter abbreviation of the weekday */ _x( 'T', 'Tuesday initial' );
     133                $this->weekday_initial[ (string) $this->weekday[3] ] = /* translators: one-letter abbreviation of the weekday */ _x( 'W', 'Wednesday initial' );
     134                $this->weekday_initial[ (string) $this->weekday[4] ] = /* translators: one-letter abbreviation of the weekday */ _x( 'T', 'Thursday initial' );
     135                $this->weekday_initial[ (string) $this->weekday[5] ] = /* translators: one-letter abbreviation of the weekday */ _x( 'F', 'Friday initial' );
     136                $this->weekday_initial[ (string) $this->weekday[6] ] = /* translators: one-letter abbreviation of the weekday */ _x( 'S', 'Saturday initial' );
    137137
    138138                // Abbreviations for each day.
    139                 $this->weekday_abbrev[ __( 'Sunday' ) ]    = /* translators: three-letter abbreviation of the weekday */ __( 'Sun' );
    140                 $this->weekday_abbrev[ __( 'Monday' ) ]    = /* translators: three-letter abbreviation of the weekday */ __( 'Mon' );
    141                 $this->weekday_abbrev[ __( 'Tuesday' ) ]  = /* translators: three-letter abbreviation of the weekday */ __( 'Tue' );
    142                 $this->weekday_abbrev[ __( 'Wednesday' ) ] = /* translators: three-letter abbreviation of the weekday */ __( 'Wed' );
    143                 $this->weekday_abbrev[ __( 'Thursday' ) ] = /* translators: three-letter abbreviation of the weekday */ __( 'Thu' );
    144                 $this->weekday_abbrev[ __( 'Friday' ) ]    = /* translators: three-letter abbreviation of the weekday */ __( 'Fri' );
    145                 $this->weekday_abbrev[ __( 'Saturday' ) ] = /* translators: three-letter abbreviation of the weekday */ __( 'Sat' );
     139                $this->weekday_abbrev[ (string) $this->weekday[0] ] = /* translators: three-letter abbreviation of the weekday */ __( 'Sun' );
     140                $this->weekday_abbrev[ (string) $this->weekday[1] ] = /* translators: three-letter abbreviation of the weekday */ __( 'Mon' );
     141                $this->weekday_abbrev[ (string) $this->weekday[2] ] = /* translators: three-letter abbreviation of the weekday */ __( 'Tue' );
     142                $this->weekday_abbrev[ (string) $this->weekday[3] ] = /* translators: three-letter abbreviation of the weekday */ __( 'Wed' );
     143                $this->weekday_abbrev[ (string) $this->weekday[4] ] = /* translators: three-letter abbreviation of the weekday */ __( 'Thu' );
     144                $this->weekday_abbrev[ (string) $this->weekday[5] ] = /* translators: three-letter abbreviation of the weekday */ __( 'Fri' );
     145                $this->weekday_abbrev[ (string) $this->weekday[6] ] = /* translators: three-letter abbreviation of the weekday */ __( 'Sat' );
    146146
    147147                // The Months
    148148                $this->month['01'] = /* translators: month name */ __( 'January' );
    class WP_Locale { 
    173173                $this->month_genitive['12'] = /* translators: month name, genitive */ _x( 'December', 'genitive' );
    174174
    175175                // Abbreviations for each month.
    176                 $this->month_abbrev[ __( 'January' ) ]  = /* translators: three-letter abbreviation of the month */ _x( 'Jan', 'January abbreviation' );
    177                 $this->month_abbrev[ __( 'February' ) ] = /* translators: three-letter abbreviation of the month */ _x( 'Feb', 'February abbreviation' );
    178                 $this->month_abbrev[ __( 'March' ) ]    = /* translators: three-letter abbreviation of the month */ _x( 'Mar', 'March abbreviation' );
    179                 $this->month_abbrev[ __( 'April' ) ]    = /* translators: three-letter abbreviation of the month */ _x( 'Apr', 'April abbreviation' );
    180                 $this->month_abbrev[ __( 'May' ) ]      = /* translators: three-letter abbreviation of the month */ _x( 'May', 'May abbreviation' );
    181                 $this->month_abbrev[ __( 'June' ) ]      = /* translators: three-letter abbreviation of the month */ _x( 'Jun', 'June abbreviation' );
    182                 $this->month_abbrev[ __( 'July' ) ]      = /* translators: three-letter abbreviation of the month */ _x( 'Jul', 'July abbreviation' );
    183                 $this->month_abbrev[ __( 'August' ) ]    = /* translators: three-letter abbreviation of the month */ _x( 'Aug', 'August abbreviation' );
    184                 $this->month_abbrev[ __( 'September' ) ] = /* translators: three-letter abbreviation of the month */ _x( 'Sep', 'September abbreviation' );
    185                 $this->month_abbrev[ __( 'October' ) ]  = /* translators: three-letter abbreviation of the month */ _x( 'Oct', 'October abbreviation' );
    186                 $this->month_abbrev[ __( 'November' ) ] = /* translators: three-letter abbreviation of the month */ _x( 'Nov', 'November abbreviation' );
    187                 $this->month_abbrev[ __( 'December' ) ] = /* translators: three-letter abbreviation of the month */ _x( 'Dec', 'December abbreviation' );
     176                $this->month_abbrev[ (string) $this->month['01'] ] = /* translators: three-letter abbreviation of the month */ _x( 'Jan', 'January abbreviation' );
     177                $this->month_abbrev[ (string) $this->month['02'] ] = /* translators: three-letter abbreviation of the month */ _x( 'Feb', 'February abbreviation' );
     178                $this->month_abbrev[ (string) $this->month['03'] ] = /* translators: three-letter abbreviation of the month */ _x( 'Mar', 'March abbreviation' );
     179                $this->month_abbrev[ (string) $this->month['04'] ] = /* translators: three-letter abbreviation of the month */ _x( 'Apr', 'April abbreviation' );
     180                $this->month_abbrev[ (string) $this->month['05'] ] = /* translators: three-letter abbreviation of the month */ _x( 'May', 'May abbreviation' );
     181                $this->month_abbrev[ (string) $this->month['06'] ] = /* translators: three-letter abbreviation of the month */ _x( 'Jun', 'June abbreviation' );
     182                $this->month_abbrev[ (string) $this->month['07'] ] = /* translators: three-letter abbreviation of the month */ _x( 'Jul', 'July abbreviation' );
     183                $this->month_abbrev[ (string) $this->month['08'] ] = /* translators: three-letter abbreviation of the month */ _x( 'Aug', 'August abbreviation' );
     184                $this->month_abbrev[ (string) $this->month['09'] ] = /* translators: three-letter abbreviation of the month */ _x( 'Sep', 'September abbreviation' );
     185                $this->month_abbrev[ (string) $this->month['10'] ] = /* translators: three-letter abbreviation of the month */ _x( 'Oct', 'October abbreviation' );
     186                $this->month_abbrev[ (string) $this->month['11'] ] = /* translators: three-letter abbreviation of the month */ _x( 'Nov', 'November abbreviation' );
     187                $this->month_abbrev[ (string) $this->month['12'] ] = /* translators: three-letter abbreviation of the month */ _x( 'Dec', 'December abbreviation' );
    188188
    189189                // The Meridiems
    190190                $this->meridiem['am'] = __( 'am' );
    class WP_Locale { 
    196196                // See https://secure.php.net/number_format
    197197
    198198                /* translators: $thousands_sep argument for https://secure.php.net/number_format, default is , */
    199                 $thousands_sep = __( 'number_format_thousands_sep' );
     199                $thousands_sep = (string) __( 'number_format_thousands_sep' );
    200200
    201201                if ( version_compare( PHP_VERSION, '5.4', '>=' ) ) {
    202202                        // Replace space with a non-breaking space to avoid wrapping.
    class WP_Locale { 
    209209                $this->number_format['thousands_sep'] = ( 'number_format_thousands_sep' === $thousands_sep ) ? ',' : $thousands_sep;
    210210
    211211                /* translators: $dec_point argument for https://secure.php.net/number_format, default is . */
    212                 $decimal_point = __( 'number_format_decimal_point' );
     212                $decimal_point = (string) __( 'number_format_decimal_point' );
    213213
    214214                $this->number_format['decimal_point'] = ( 'number_format_decimal_point' === $decimal_point ) ? '.' : $decimal_point;
    215215
    class WP_Locale { 
    251251         * @return string Full translated weekday.
    252252         */
    253253        public function get_weekday( $weekday_number ) {
    254                 return $this->weekday[ $weekday_number ];
     254                return $this->weekday[ (string) $weekday_number ];
    255255        }
    256256
    257257        /**
    class WP_Locale { 
    268268         * @return string Translated weekday initial.
    269269         */
    270270        public function get_weekday_initial( $weekday_name ) {
    271                 return $this->weekday_initial[ $weekday_name ];
     271                return $this->weekday_initial[ (string) $weekday_name ];
    272272        }
    273273
    274274        /**
    class WP_Locale { 
    283283         * @return string Translated weekday abbreviation.
    284284         */
    285285        public function get_weekday_abbrev( $weekday_name ) {
    286                 return $this->weekday_abbrev[ $weekday_name ];
     286                return $this->weekday_abbrev[ (string) $weekday_name ];
    287287        }
    288288
    289289        /**
    class WP_Locale { 
    318318         * @return string Translated abbreviated month.
    319319         */
    320320        public function get_month_abbrev( $month_name ) {
    321                 return $this->month_abbrev[ $month_name ];
     321                return $this->month_abbrev[ (string) $month_name ];
    322322        }
    323323
    324324        /**
    class WP_Locale { 
    332332         * @return string Translated version
    333333         */
    334334        public function get_meridiem( $meridiem ) {
    335                 return $this->meridiem[ $meridiem ];
     335                return $this->meridiem[ (string) $meridiem ];
    336336        }
    337337
    338338        /**
  • src/wp-includes/comment-template.php

    diff --git a/src/wp-includes/comment-template.php b/src/wp-includes/comment-template.php
    index a386b61ed8..bbe108c6ef 100644
    a b function get_comments_number_text( $zero = false, $one = false, $more = false ) 
    906906                        /* translators: If comment number in your language requires declension,
    907907                         * translate this to 'on'. Do not translate into your own language.
    908908                         */
    909                         if ( 'on' === _x( 'off', 'Comment number declension: on or off' ) ) {
     909                        if ( 'on' === (string) _x( 'off', 'Comment number declension: on or off' ) ) {
    910910                                $text = preg_replace( '#<span class="screen-reader-text">.+?</span>#', '', $more );
    911911                                $text = preg_replace( '/&.+?;/', '', $text ); // Kill entities
    912912                                $text = trim( strip_tags( $text ), '% ' );
  • src/wp-includes/functions.php

    diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php
    index 214c134d01..2a08d26621 100644
    a b function wp_maybe_decline_date( $date ) { 
    218218        /* translators: If months in your language require a genitive case,
    219219         * translate this to 'on'. Do not translate into your own language.
    220220         */
    221         if ( 'on' === _x( 'off', 'decline months names: on or off' ) ) {
     221        if ( 'on' === (string) _x( 'off', 'decline months names: on or off' ) ) {
    222222                // Match a format like 'j F Y' or 'j. F'
    223223                if ( @preg_match( '#^\d{1,2}\.? [^\d ]+#u', $date ) ) {
    224224                        $months          = $wp_locale->month;
    function wp_die( $message = '', $title = '', $args = array() ) { 
    30093009                $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
    30103010        }
    30113011
    3012         call_user_func( $function, $message, $title, $args );
     3012        call_user_func( $function, $message instanceof WP_String_Proxy ? (string) $message : $message, $title, $args );
    30133013}
    30143014
    30153015/**
  • src/wp-includes/l10n.php

    diff --git a/src/wp-includes/l10n.php b/src/wp-includes/l10n.php
    index 39aa6d498e..2d5e26ae49 100644
    a b function translate_with_gettext_context( $text, $context, $domain = 'default' ) 
    240240 * If there is no translation, or the text domain isn't loaded, the original text is returned.
    241241 *
    242242 * @since 2.1.0
     243 * @since 5.2.0 Returns a lazily-translating proxy object.
    243244 *
    244245 * @param string $text   Text to translate.
    245246 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
    246247 *                       Default 'default'.
    247  * @return string Translated text.
     248 * @return WP_String_Proxy Proxy object representing a string.
    248249 */
    249250function __( $text, $domain = 'default' ) {
    250         return translate( $text, $domain );
     251        return new WP_Translation_Proxy( $text, $domain );
    251252}
    252253
    253254/**
    function __( $text, $domain = 'default' ) { 
    256257 * If there is no translation, or the text domain isn't loaded, the original text is returned.
    257258 *
    258259 * @since 2.8.0
     260 * @since 5.2.0 Returns a lazily-translating proxy object.
    259261 *
    260262 * @param string $text   Text to translate.
    261263 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
    262264 *                       Default 'default'.
    263  * @return string Translated text on success, original text on failure.
     265 * @return WP_String_Proxy Proxy object representing a string.
    264266 */
    265267function esc_attr__( $text, $domain = 'default' ) {
    266         return esc_attr( translate( $text, $domain ) );
     268        return new WP_Escape_Attribute_Proxy(
     269                new WP_Translation_Proxy( $text, $domain )
     270        );
    267271}
    268272
    269273/**
    function esc_attr__( $text, $domain = 'default' ) { 
    273277 * is escaped and returned.
    274278 *
    275279 * @since 2.8.0
     280 * @since 5.2.0 Returns a lazily-translating proxy object.
    276281 *
    277282 * @param string $text   Text to translate.
    278283 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
    279284 *                       Default 'default'.
    280  * @return string Translated text
     285 * @return WP_String_Proxy Proxy object representing a string.
    281286 */
    282287function esc_html__( $text, $domain = 'default' ) {
    283         return esc_html( translate( $text, $domain ) );
     288        return new WP_Escape_HTML_Proxy(
     289                new WP_Translation_Proxy( $text, $domain )
     290        );
    284291}
    285292
    286293/**
    function esc_html_e( $text, $domain = 'default' ) { 
    332339 * strings differently.
    333340 *
    334341 * @since 2.8.0
     342 * @since 5.2.0 Returns a lazily-translating proxy object.
    335343 *
    336344 * @param string $text    Text to translate.
    337345 * @param string $context Context information for the translators.
    338346 * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
    339347 *                        Default 'default'.
    340  * @return string Translated context string without pipe.
     348 * @return WP_String_Proxy Proxy object representing a string.
    341349 */
    342350function _x( $text, $context, $domain = 'default' ) {
    343         return translate_with_gettext_context( $text, $context, $domain );
     351        return new WP_Contextual_Translation_Proxy( $text, $context, $domain );
    344352}
    345353
    346354/**
    function _ex( $text, $context, $domain = 'default' ) { 
    362370 * Translate string with gettext context, and escapes it for safe use in an attribute.
    363371 *
    364372 * @since 2.8.0
     373 * @since 5.2.0 Returns a lazily-translating proxy object.
    365374 *
    366375 * @param string $text    Text to translate.
    367376 * @param string $context Context information for the translators.
    368377 * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
    369378 *                        Default 'default'.
    370  * @return string Translated text
     379 * @return WP_String_Proxy Proxy object representing a string.
    371380 */
    372381function esc_attr_x( $text, $context, $domain = 'default' ) {
    373         return esc_attr( translate_with_gettext_context( $text, $context, $domain ) );
     382        return new WP_Escape_Attribute_Proxy(
     383                new WP_Contextual_Translation_Proxy( $text, $context, $domain )
     384        );
    374385}
    375386
    376387/**
    377388 * Translate string with gettext context, and escapes it for safe use in HTML output.
    378389 *
    379390 * @since 2.9.0
     391 * @since 5.2.0 Returns a lazily-translating proxy object.
    380392 *
    381393 * @param string $text    Text to translate.
    382394 * @param string $context Context information for the translators.
    383395 * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
    384396 *                        Default 'default'.
    385  * @return string Translated text.
     397 * @return WP_String_Proxy Proxy object representing a string.
    386398 */
    387399function esc_html_x( $text, $context, $domain = 'default' ) {
    388         return esc_html( translate_with_gettext_context( $text, $context, $domain ) );
     400        return new WP_Escape_HTML_Proxy(
     401                new WP_Contextual_Translation_Proxy( $text, $context, $domain )
     402        );
    389403}
    390404
    391405/**
    function is_locale_switched() { 
    15971611
    15981612        return $wp_locale_switcher->is_switched();
    15991613}
     1614
     1615/**
     1616 * Get the instance for caching translations.
     1617 *
     1618 * @since 5.2.0
     1619 *
     1620 * @return WP_Translation_Cache
     1621 */
     1622function wp_translation_cache() {
     1623        static $wp_translation_cache = null;
     1624
     1625        if ( null === $wp_translation_cache ) {
     1626                $wp_translation_cache = new WP_Translation_Cache();
     1627                $wp_translation_cache->init();
     1628        }
     1629
     1630        return $wp_translation_cache;
     1631}
  • new file src/wp-includes/l10n/class-wp-contextual-translation-proxy.php

    diff --git a/src/wp-includes/l10n/class-wp-contextual-translation-proxy.php b/src/wp-includes/l10n/class-wp-contextual-translation-proxy.php
    new file mode 100644
    index 0000000000..6439f66f6c
    - +  
     1<?php
     2
     3/**
     4 * L10n: WP_Contextual_Translation_Proxy class.
     5 *
     6 * @package    WordPress
     7 * @subpackage L10n
     8 * @since      5.2.0
     9 */
     10final class WP_Contextual_Translation_Proxy extends WP_String_Proxy {
     11
     12        private $text;
     13        private $context;
     14        private $domain;
     15
     16        /**
     17         * Instantiate a WP_Translation_Proxy object.
     18         *
     19         * @since 5.2.0
     20         *
     21         * @param string $text    Text to translate.
     22         * @param string $context Context of the test to translate.
     23         * @param string $domain  Optional. Text domain to use for the translation.
     24         */
     25        public function __construct( $text, $context, $domain = 'default' ) {
     26                $this->text    = $text;
     27                $this->context = $context;
     28                $this->domain  = $domain;
     29
     30                parent::__construct();
     31        }
     32
     33        /**
     34         * Lazily evaluate the result the first time it is being requested.
     35         *
     36         * @since 5.2.0
     37         *
     38         * @return string
     39         */
     40        protected function result() {
     41                return wp_translation_cache()->translate_with_context( $this->cache_id, $this->text, $this->context, $this->domain );
     42        }
     43
     44        /**
     45         * When the proxy object leaves memory, clear the cache entry.
     46         *
     47         * @since 5.2.0
     48         */
     49        public function __destruct() {
     50                wp_translation_cache()->clear_translation( $this->cache_id );
     51        }
     52}
  • new file src/wp-includes/l10n/class-wp-escape-attribute-proxy.php

    diff --git a/src/wp-includes/l10n/class-wp-escape-attribute-proxy.php b/src/wp-includes/l10n/class-wp-escape-attribute-proxy.php
    new file mode 100644
    index 0000000000..a970be6c0c
    - +  
     1<?php
     2
     3/**
     4 * L10n: WP_Escape_Attribute_Proxy class.
     5 *
     6 * @package    WordPress
     7 * @subpackage L10n
     8 * @since      5.2.0
     9 */
     10final class WP_Escape_Attribute_Proxy extends WP_String_Proxy {
     11
     12        private $value;
     13
     14        /**
     15         * Instantiate a WP_Translation_Proxy object.
     16         *
     17         * @since 5.2.0
     18         *
     19         * @param mixed $value Value to be escaped. Needs to be castable to a
     20         *                     string.
     21         */
     22        public function __construct( $value ) {
     23                $this->value = $value;
     24
     25                parent::__construct();
     26        }
     27
     28        /**
     29         * Lazily evaluate the result the first time it is being requested.
     30         *
     31         * @since 5.2.0
     32         *
     33         * @return string
     34         */
     35        protected function result() {
     36                return esc_attr( (string) $this->value );
     37        }
     38}
  • new file src/wp-includes/l10n/class-wp-escape-html-proxy.php

    diff --git a/src/wp-includes/l10n/class-wp-escape-html-proxy.php b/src/wp-includes/l10n/class-wp-escape-html-proxy.php
    new file mode 100644
    index 0000000000..eb2d748c02
    - +  
     1<?php
     2
     3/**
     4 * L10n: WP_Escape_HTML_Proxy class.
     5 *
     6 * @package    WordPress
     7 * @subpackage L10n
     8 * @since      5.2.0
     9 */
     10final class WP_Escape_HTML_Proxy extends WP_String_Proxy {
     11
     12        private $value;
     13
     14        /**
     15         * Instantiate a WP_Translation_Proxy object.
     16         *
     17         * @since 5.2.0
     18         *
     19         * @param mixed $value Value to be escaped. Needs to be castable to a
     20         *                     string.
     21         */
     22        public function __construct( $value ) {
     23                $this->value = $value;
     24
     25                parent::__construct();
     26        }
     27
     28        /**
     29         * Lazily evaluate the result the first time it is being requested.
     30         *
     31         * @since 5.2.0
     32         *
     33         * @return string
     34         */
     35        protected function result() {
     36                return esc_html( (string) $this->value );
     37        }
     38}
  • new file src/wp-includes/l10n/class-wp-string-proxy.php

    diff --git a/src/wp-includes/l10n/class-wp-string-proxy.php b/src/wp-includes/l10n/class-wp-string-proxy.php
    new file mode 100644
    index 0000000000..841edb2669
    - +  
     1<?php
     2
     3/**
     4 * L10n: WP_String_Proxy class.
     5 *
     6 * Implements `JsonSerializable` interface so that it gets converted to a
     7 * translated string on `json_encode()`.
     8 *
     9 * Implements the `ArrayAccess` interface so that you can directly access
     10 * individual characters in the translated string
     11 *
     12 * @package    WordPress
     13 * @subpackage L10n
     14 * @since      5.2.0
     15 */
     16abstract class WP_String_Proxy implements JsonSerializable, ArrayAccess {
     17
     18        private static $count = 0;
     19
     20        protected $cache_id;
     21
     22        /**
     23         * Store a copy of the result when the string is modified through `offsetSet`.
     24         *
     25         * @var string|null
     26         */
     27        private $modified;
     28
     29        /**
     30         * WP_String_Proxy constructor.
     31         */
     32        public function __construct() {
     33                $this->cache_id = ++ self::$count;
     34        }
     35
     36        /**
     37         * Return the string representation of the proxy object.
     38         *
     39         * @since 5.2.0
     40         *
     41         * @return string
     42         */
     43        public function __toString() {
     44                return $this->get_modified_or_result();
     45        }
     46
     47        /**
     48         * Return the JSON representation of the proxy object.
     49         *
     50         * @since 5.2.0
     51         *
     52         * @return string
     53         */
     54        public function jsonSerialize() {
     55                return $this->get_modified_or_result();
     56        }
     57
     58        /**
     59         * Lazily evaluate the result the first time it is being requested.
     60         *
     61         * @since 5.2.0
     62         *
     63         * @return string
     64         */
     65        abstract protected function result();
     66
     67        /**
     68         * Check whether an offset into the array exists.
     69         *
     70         * @since 5.2.0
     71         *
     72         * @param mixed $offset Offset to check for.
     73         *
     74         * @return bool
     75         */
     76        public function offsetExists( $offset ) {
     77                return mb_strlen( $this->get_modified_or_result() ) > $offset;
     78        }
     79
     80        /**
     81         * Retrieve a specific offset into the array.
     82         *
     83         * @since 5.2.0
     84         *
     85         * @param mixed $offset The offset to retrieve.
     86         *
     87         * @return mixed
     88         */
     89        public function offsetGet( $offset ) {
     90                $result = $this->get_modified_or_result();
     91
     92                return $result[ $offset ];
     93        }
     94
     95        /**
     96         * Set a specific offset in the array.
     97         *
     98         * @since 5.2.0
     99         *
     100         * @param mixed $offset The offset to assign the value to.
     101         * @param mixed $value  The value to set the offset to.
     102         */
     103        public function offsetSet( $offset, $value ) {
     104
     105                if ( null === $this->modified ) {
     106                        $this->modified = $this->result();
     107                }
     108
     109                $this->modified[ $offset ] = $value;
     110        }
     111
     112        /**
     113         * Unset a specific offset in the array.
     114         *
     115         * @since 5.2.0
     116         *
     117         * @param mixed $offset The offset to unset.
     118         */
     119        public function offsetUnset( $offset ) {
     120                trigger_error( 'Cannot unset string offset', E_USER_ERROR );
     121        }
     122
     123        /**
     124         * Get the modified string or call the result function.
     125         *
     126         * @since 5.2.0
     127         *
     128         * @return string
     129         */
     130        private function get_modified_or_result() {
     131                return null === $this->modified ? $this->result() : $this->modified;
     132        }
     133}
  • new file src/wp-includes/l10n/class-wp-translation-cache.php

    diff --git a/src/wp-includes/l10n/class-wp-translation-cache.php b/src/wp-includes/l10n/class-wp-translation-cache.php
    new file mode 100644
    index 0000000000..1eb1c7b7de
    - +  
     1<?php
     2
     3/**
     4 * L10n: WP_Translation_Cache class.
     5 *
     6 * @package    WordPress
     7 * @subpackage L10n
     8 * @since      5.2.0
     9 */
     10class WP_Translation_Cache {
     11
     12        const MAX_LOCALES = 5;
     13
     14        /**
     15         * The translation cache.
     16         *
     17         * Keyed by locale then cache ID.
     18         *
     19         * @since 5.2.0
     20         * @var array
     21         */
     22        private $cache = array();
     23
     24        /**
     25         * The original locale for the request.
     26         *
     27         * This locale will never be pruned from the cache.
     28         *
     29         * @since 5.2.0
     30         * @var string
     31         */
     32        private $original_locale;
     33
     34        /**
     35         * The current locale. Determines the current cache key.
     36         *
     37         * @since 5.2.0
     38         * @var string
     39         */
     40        private $current_locale;
     41
     42        /**
     43         * WP_Translation_Cache constructor.
     44         *
     45         * @since 5.2.0
     46         */
     47        public function __construct() {
     48                $this->original_locale = $this->current_locale = determine_locale();
     49        }
     50
     51        /**
     52         * Initialize the translation cache.
     53         *
     54         * @since 5.2.0
     55         */
     56        public function init() {
     57                add_action( 'change_locale', array( $this, 'on_change_locale' ) );
     58        }
     59
     60        /**
     61         * When the locale is changed, update the current cache key.
     62         *
     63         * @since 5.2.0
     64         *
     65         * @param string $locale
     66         */
     67        public function on_change_locale( $locale ) {
     68                $this->current_locale = $locale;
     69                $this->prune_cache();
     70        }
     71
     72        /**
     73         * Lazily translate the given text.
     74         *
     75         * @since 5.2.0
     76         *
     77         * @param int    $cache_id The cache ID identifying this translation.
     78         * @param string $text     The untranslated text.
     79         * @param string $domain   The text domain.
     80         *
     81         * @return string
     82         */
     83        public function translate( $cache_id, $text, $domain ) {
     84                if ( ! isset( $this->cache[ $this->current_locale ][ $cache_id ] ) ) {
     85                        $this->cache[ $this->current_locale ][ $cache_id ] = translate( $text, $domain );
     86                }
     87
     88                return $this->cache[ $this->current_locale ][ $cache_id ];
     89        }
     90
     91        /**
     92         * Lazily translate the given text with context.
     93         *
     94         * @since 5.2.0
     95         *
     96         * @param int    $cache_id The cache ID identifying this translation.
     97         * @param string $text     The untranslated text.
     98         * @param string $context  The translation context.
     99         * @param string $domain   The text domain.
     100         *
     101         * @return string
     102         */
     103        public function translate_with_context( $cache_id, $text, $context, $domain ) {
     104                if ( ! isset( $this->cache[ $this->current_locale ][ $cache_id ] ) ) {
     105                        $this->cache[ $this->current_locale ][ $cache_id ] = translate_with_gettext_context( $text, $context, $domain );
     106                }
     107
     108                return $this->cache[ $this->current_locale ][ $cache_id ];
     109        }
     110
     111        /**
     112         * Remove the entry from the cache.
     113         *
     114         * @since 5.2.0
     115         *
     116         * @param int $cache_id
     117         */
     118        public function clear_translation( $cache_id ) {
     119                foreach ( $this->cache as $locale => $translations ) {
     120                        unset( $this->cache[ $locale ][ $cache_id ] );
     121                }
     122        }
     123
     124        /**
     125         * Completely clear the translation cache.
     126         *
     127         * @since 5.2.0
     128         */
     129        public function clear() {
     130                $this->cache = array();
     131        }
     132
     133        /**
     134         * Prune the translation cache.
     135         *
     136         * @since 5.2.0
     137         */
     138        private function prune_cache() {
     139                $i = 0;
     140
     141                foreach ( array_reverse( $this->cache ) as $locale => $items ) {
     142                        $i ++;
     143
     144                        if ( $locale === $this->original_locale ) {
     145                                continue;
     146                        }
     147
     148                        if ( $i > self::MAX_LOCALES ) {
     149                                unset( $this->cache[ $locale ] );
     150                        }
     151                }
     152        }
     153}
  • new file src/wp-includes/l10n/class-wp-translation-proxy.php

    diff --git a/src/wp-includes/l10n/class-wp-translation-proxy.php b/src/wp-includes/l10n/class-wp-translation-proxy.php
    new file mode 100644
    index 0000000000..b8d72b6e1e
    - +  
     1<?php
     2
     3/**
     4 * L10n: WP_Translation_Proxy class.
     5 *
     6 * @package    WordPress
     7 * @subpackage L10n
     8 * @since      5.2.0
     9 */
     10final class WP_Translation_Proxy extends WP_String_Proxy {
     11
     12        private $text;
     13        private $domain;
     14
     15        /**
     16         * Instantiate a WP_Translation_Proxy object.
     17         *
     18         * @since 5.2.0
     19         *
     20         * @param string $text   Text to translate.
     21         * @param string $domain Optional. Text domain to use for the translation.
     22         */
     23        public function __construct( $text, $domain = 'default' ) {
     24                $this->text   = $text;
     25                $this->domain = $domain;
     26
     27                parent::__construct();
     28        }
     29
     30        /**
     31         * Lazily evaluate the result the first time it is being requested.
     32         *
     33         * @since 5.2.0
     34         *
     35         * @return string
     36         */
     37        protected function result() {
     38                return wp_translation_cache()->translate( $this->cache_id, $this->text, $this->domain );
     39        }
     40
     41        /**
     42         * When the proxy object leaves memory, clear the cache entry.
     43         *
     44         * @since 5.2.0
     45         */
     46        public function __destruct() {
     47                wp_translation_cache()->clear_translation( $this->cache_id );
     48        }
     49}
  • src/wp-includes/load.php

    diff --git a/src/wp-includes/load.php b/src/wp-includes/load.php
    index 245ecb1e61..b1ef8fc9e6 100644
    a b function wp_load_translations_early() { 
    994994        require_once ABSPATH . WPINC . '/l10n.php';
    995995        require_once ABSPATH . WPINC . '/class-wp-locale.php';
    996996        require_once ABSPATH . WPINC . '/class-wp-locale-switcher.php';
     997        require_once ABSPATH . WPINC . '/l10n/class-wp-translation-cache.php';
     998        require_once ABSPATH . WPINC . '/l10n/class-wp-string-proxy.php';
     999        require_once ABSPATH . WPINC . '/l10n/class-wp-translation-proxy.php';
     1000        require_once ABSPATH . WPINC . '/l10n/class-wp-contextual-translation-proxy.php';
     1001        require_once ABSPATH . WPINC . '/l10n/class-wp-escape-attribute-proxy.php';
     1002        require_once ABSPATH . WPINC . '/l10n/class-wp-escape-html-proxy.php';
    9971003
    9981004        // General libraries
    9991005        require_once ABSPATH . WPINC . '/plugin.php';
  • src/wp-includes/wp-db.php

    diff --git a/src/wp-includes/wp-db.php b/src/wp-includes/wp-db.php
    index a9d707464c..d055864363 100644
    a b class wpdb { 
    13141314                }
    13151315
    13161316                foreach ( $args as $arg ) {
    1317                         if ( ! is_scalar( $arg ) && ! is_null( $arg ) ) {
     1317                        if ( ! is_scalar( $arg ) && ! is_null( $arg ) && ! $arg instanceof WP_String_Proxy) {
    13181318                                wp_load_translations_early();
    13191319                                _doing_it_wrong( 'wpdb::prepare', sprintf( __( 'Unsupported value type (%s).' ), gettype( $arg ) ), '4.8.2' );
    13201320                        }
  • src/wp-settings.php

    diff --git a/src/wp-settings.php b/src/wp-settings.php
    index b54d6f39d9..5a88ddfe28 100644
    a b if ( SHORTINIT ) { 
    137137
    138138// Load the L10n library.
    139139require_once( ABSPATH . WPINC . '/l10n.php' );
     140require_once( ABSPATH . WPINC . '/l10n/class-wp-translation-cache.php' );
     141require_once( ABSPATH . WPINC . '/l10n/class-wp-string-proxy.php' );
     142require_once( ABSPATH . WPINC . '/l10n/class-wp-translation-proxy.php' );
     143require_once( ABSPATH . WPINC . '/l10n/class-wp-contextual-translation-proxy.php' );
     144require_once( ABSPATH . WPINC . '/l10n/class-wp-escape-attribute-proxy.php' );
     145require_once( ABSPATH . WPINC . '/l10n/class-wp-escape-html-proxy.php' );
    140146require_once( ABSPATH . WPINC . '/class-wp-locale.php' );
    141147require_once( ABSPATH . WPINC . '/class-wp-locale-switcher.php' );
    142148
  • tests/phpunit/data/plugins/internationalized-plugin.php

    diff --git a/tests/phpunit/data/plugins/internationalized-plugin.php b/tests/phpunit/data/plugins/internationalized-plugin.php
    index 4b56846ad3..2362cf6180 100644
    a b Text Domain: internationalized-plugin 
    88*/
    99
    1010function i18n_plugin_test() {
    11         return __( 'This is a dummy plugin', 'internationalized-plugin' );
     11        return (string) __( 'This is a dummy plugin', 'internationalized-plugin' );
    1212}
  • tests/phpunit/includes/abstract-testcase.php

    diff --git a/tests/phpunit/includes/abstract-testcase.php b/tests/phpunit/includes/abstract-testcase.php
    index c90a1614e8..c42cceea64 100644
    a b abstract class WP_UnitTestCase_Base extends PHPUnit_Framework_TestCase { 
    163163                remove_filter( 'wp_die_handler', array( $this, 'get_wp_die_handler' ) );
    164164                $this->_restore_hooks();
    165165                wp_set_current_user( 0 );
     166                wp_translation_cache()->clear();
    166167        }
    167168
    168169        function clean_up_global_scope() {
    abstract class WP_UnitTestCase_Base extends PHPUnit_Framework_TestCase { 
    437438                }
    438439        }
    439440
     441        /**
     442         * Resolve proxies in arrays to be tested.
     443         *
     444         * @since 5.2.0
     445         *
     446         * @param mixed  $value Reference to the array value to be checked.
     447         * @param string $key   Index key of the array value to be checked.
     448         */
     449        protected static function resolve_proxies( &$value, $key ) {
     450                if ( is_array( $value ) ) {
     451                        array_walk( $value, 'WP_UnitTestCase_Base::resolve_proxies' );
     452                }
     453
     454                $value = self::resolve_proxy( $value );
     455        }
     456
     457        /**
     458         * Resolve an individual proxy.
     459         *
     460         * @since 0.1.0
     461         *
     462         * @param $value
     463         *
     464         * @return string
     465         */
     466        protected static function resolve_proxy( $value ) {
     467                if ( $value instanceof WP_String_Proxy ) {
     468                        return (string) $value;
     469                }
     470
     471                return $value;
     472        }
     473
    440474        /**
    441475         * Detect post-test failure conditions.
    442476         *
  • tests/phpunit/includes/phpunit7/testcase.php

    diff --git a/tests/phpunit/includes/phpunit7/testcase.php b/tests/phpunit/includes/phpunit7/testcase.php
    index 9edc885e6a..7a3fd2ae04 100644
    a b class WP_UnitTestCase extends WP_UnitTestCase_Base { 
    2929        public static function assertNotFalse( $condition, string $message = '' ): void {
    3030                self::assertThat( $condition, self::logicalNot( self::isFalse() ), $message );
    3131        }
     32
     33        /**
     34         * Assert that two elements are equal.
     35         *
     36         * Override to handle special cases for equality checks.
     37         *
     38         * @since 5.2.0 Added WP_String_Proxy object <=> string equality.
     39         *
     40         * @param mixed  $expected
     41         * @param mixed  $actual
     42         * @param string $message
     43         * @param int    $delta
     44         * @param int    $maxDepth
     45         * @param bool   $canonicalize
     46         * @param bool   $ignoreCase
     47         */
     48        public static function assertEquals( $expected, $actual, string $message = '', float $delta = 0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false ): void {
     49                if ( is_array( $actual ) ) {
     50                        array_walk( $actual, 'WP_UnitTestCase_Base::resolve_proxies', $expected );
     51                }
     52
     53                $actual   = self::resolve_proxy( $actual );
     54                $expected = self::resolve_proxy( $expected );
     55
     56                parent::assertEquals( $expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase );
     57        }
     58
     59        /**
     60         * Asserts that two variables have the same type and value.
     61         * Used on objects, it asserts that two variables reference
     62         * the same object.
     63         *
     64         * Override to handle special cases for equality checks.
     65         *
     66         * @since 5.2.0 Added WP_String_Proxy object <=> string equality.
     67         *
     68         * @param mixed  $expected
     69         * @param mixed  $actual
     70         * @param string $message
     71         */
     72        public static function assertSame( $expected, $actual, string $message = '' ): void {
     73                if ( is_array( $actual ) ) {
     74                        array_walk( $actual, 'WP_UnitTestCase_Base::resolve_proxies' );
     75                }
     76
     77                if ( is_array( $expected ) ) {
     78                        array_walk( $expected, 'WP_UnitTestCase_Base::resolve_proxies' );
     79                }
     80
     81                $actual   = self::resolve_proxy( $actual );
     82                $expected = self::resolve_proxy( $expected );
     83
     84                parent::assertSame( $expected, $actual, $message );
     85        }
     86
     87        /**
     88         * Asserts that a variable is of a given type.
     89         *
     90         * Override to handle special cases for equality checks.
     91         *
     92         * @since 5.2.0 Added WP_String_Proxy object <=> string equality.
     93         *
     94         * @param string $expected
     95         * @param mixed  $actual
     96         * @param string $message
     97         */
     98        public static function assertInternalType( string $expected, $actual, string $message = '' ): void {
     99                if ( 'string' === $expected ) {
     100                        $actual = self::resolve_proxy( $actual );
     101                }
     102
     103                parent::assertInternalType( $expected, $actual, $message );
     104        }
     105
     106        /**
     107         * Asserts that a haystack contains a needle.
     108         *
     109         * @since 5.2.0 Added WP_String_Proxy object <=> string equality.
     110         */
     111        public static function assertContains( $needle, $haystack, string $message = '', bool $ignoreCase = false, bool $checkForObjectIdentity = true, bool $checkForNonObjectIdentity = false ): void {
     112                if ( is_array( $haystack ) ) {
     113                        array_walk( $haystack, 'WP_UnitTestCase_Base::resolve_proxies' );
     114                }
     115
     116                parent::assertContains( $needle, $haystack, $message, $ignoreCase, $checkForObjectIdentity, $checkForNonObjectIdentity );
     117        }
    32118}
  • tests/phpunit/includes/testcase.php

    diff --git a/tests/phpunit/includes/testcase.php b/tests/phpunit/includes/testcase.php
    index 964af64ca3..cbcca1f5da 100644
    a b class WP_UnitTestCase extends WP_UnitTestCase_Base { 
    2929        public static function assertNotFalse( $condition, $message = '' ) {
    3030                self::assertThat( $condition, self::logicalNot( self::isFalse() ), $message );
    3131        }
     32
     33        /**
     34         * Assert that two elements are equal.
     35         *
     36         * Override to handle special cases for equality checks.
     37         *
     38         * @since 5.2.0 Added WP_String_Proxy object <=> string equality.
     39         *
     40         * @param mixed  $expected
     41         * @param mixed  $actual
     42         * @param string $message
     43         * @param int    $delta
     44         * @param int    $maxDepth
     45         * @param bool   $canonicalize
     46         * @param bool   $ignoreCase
     47         */
     48        public static function assertEquals( $expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false ) {
     49                if ( is_array( $actual ) ) {
     50                        array_walk( $actual, 'WP_UnitTestCase_Base::resolve_proxies', $expected );
     51                }
     52
     53                $actual   = self::resolve_proxy( $actual );
     54                $expected = self::resolve_proxy( $expected );
     55
     56                parent::assertEquals( $expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase );
     57        }
     58
     59        /**
     60         * Asserts that two variables have the same type and value.
     61         * Used on objects, it asserts that two variables reference
     62         * the same object.
     63         *
     64         * Override to handle special cases for equality checks.
     65         *
     66         * @since 5.2.0 Added WP_String_Proxy object <=> string equality.
     67         *
     68         * @param mixed  $expected
     69         * @param mixed  $actual
     70         * @param string $message
     71         */
     72        public static function assertSame( $expected, $actual, $message = '' ) {
     73                if ( is_array( $actual ) ) {
     74                        array_walk( $actual, 'WP_UnitTestCase_Base::resolve_proxies' );
     75                }
     76
     77                if ( is_array( $expected ) ) {
     78                        array_walk( $expected, 'WP_UnitTestCase_Base::resolve_proxies' );
     79                }
     80
     81                $actual   = self::resolve_proxy( $actual );
     82                $expected = self::resolve_proxy( $expected );
     83
     84                parent::assertSame( $expected, $actual, $message );
     85        }
     86
     87        /**
     88         * Asserts that a variable is of a given type.
     89         *
     90         * Override to handle special cases for equality checks.
     91         *
     92         * @since 5.2.0 Added WP_String_Proxy object <=> string equality.
     93         *
     94         * @param string $expected
     95         * @param mixed  $actual
     96         * @param string $message
     97         */
     98        public static function assertInternalType( $expected, $actual, $message = '' ) {
     99                if ( 'string' === $expected ) {
     100                        $actual = self::resolve_proxy( $actual );
     101                }
     102
     103                parent::assertInternalType( $expected, $actual, $message );
     104        }
     105
     106        /**
     107         * Asserts that a haystack contains a needle.
     108         *
     109         * @since 5.2.0 Added WP_String_Proxy object <=> string equality.
     110         */
     111        public static function assertContains( $needle, $haystack, $message = '', $ignoreCase = false, $checkForObjectIdentity = true, $checkForNonObjectIdentity = false ) {
     112                if ( is_array( $haystack ) ) {
     113                        array_walk( $haystack, 'WP_UnitTestCase_Base::resolve_proxies' );
     114                }
     115
     116                parent::assertContains( $needle, $haystack, $message, $ignoreCase, $checkForObjectIdentity, $checkForNonObjectIdentity );
     117        }
    32118}
  • tests/phpunit/tests/customize/nav-menus.php

    diff --git a/tests/phpunit/tests/customize/nav-menus.php b/tests/phpunit/tests/customize/nav-menus.php
    index e7387773ac..951d766fd9 100644
    a b class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase { 
    390390                $results = $menus->search_available_items_query(
    391391                        array(
    392392                                'pagenum' => 1,
    393                                 's'       => $title,
     393                                's'       => (string) $title,
    394394                        )
    395395                );
    396396                $this->assertCount( 1, $results );
  • tests/phpunit/tests/l10n/loadTextdomainJustInTime.php

    diff --git a/tests/phpunit/tests/l10n/loadTextdomainJustInTime.php b/tests/phpunit/tests/l10n/loadTextdomainJustInTime.php
    index 7fb85a5427..49c40d480c 100644
    a b class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase { 
    7575                $expected_output             = i18n_plugin_test();
    7676                $is_textdomain_loaded_after  = is_textdomain_loaded( 'internationalized-plugin' );
    7777
    78                 remove_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) );
    79 
    8078                $this->assertFalse( $is_textdomain_loaded_before );
    8179                $this->assertSame( 'Das ist ein Dummy Plugin', $expected_output );
    8280                $this->assertTrue( $is_textdomain_loaded_after );
     81
     82                remove_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) );
    8383        }
    8484
    8585        /**
    class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase { 
    9494
    9595                $is_textdomain_loaded_before = is_textdomain_loaded( 'internationalized-theme' );
    9696                $expected_output             = i18n_theme_test();
    97                 $is_textdomain_loaded_after  = is_textdomain_loaded( 'internationalized-theme' );
    98 
    99                 remove_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) );
    10097
    10198                $this->assertFalse( $is_textdomain_loaded_before );
    10299                $this->assertSame( 'Das ist ein Dummy Theme', $expected_output );
     100
     101                $is_textdomain_loaded_after  = is_textdomain_loaded( 'internationalized-theme' );
    103102                $this->assertTrue( $is_textdomain_loaded_after );
     103
     104                remove_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) );
    104105        }
    105106
    106107        /**
    class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase { 
    110111                add_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) );
    111112                add_filter( 'override_load_textdomain', '__return_true' );
    112113                $translations = get_translations_for_domain( 'internationalized-plugin' );
    113                 remove_filter( 'override_load_textdomain', '__return_true' );
    114                 remove_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) );
    115114
    116115                $this->assertTrue( $translations instanceof NOOP_Translations );
     116
     117                remove_filter( 'override_load_textdomain', '__return_true' );
     118                remove_filter( 'locale', array( $this, 'filter_set_locale_to_german' ) );
    117119        }
    118120
    119121        /**
    class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase { 
    163165
    164166                switch_to_locale( 'de_DE' );
    165167                $expected = i18n_plugin_test();
    166                 restore_previous_locale();
    167168
    168169                $this->assertSame( 'Das ist ein Dummy Plugin', $expected );
     170
     171                restore_previous_locale();
    169172        }
    170173
    171174        /**
    class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase { 
    180183                switch_to_locale( 'es_ES' );
    181184                $expected_es_ES = i18n_plugin_test();
    182185
    183                 restore_current_locale();
    184 
    185186                $this->assertSame( 'Das ist ein Dummy Plugin', $expected_de_DE );
    186187                $this->assertSame( 'This is a dummy plugin', $expected_es_ES );
     188
     189                restore_current_locale();
    187190        }
    188191
    189192        /**
    class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase { 
    196199
    197200                switch_to_locale( 'de_DE' );
    198201                $expected = i18n_theme_test();
     202
     203                $this->assertSame( 'Das ist ein Dummy Theme', $expected );
     204
    199205                restore_previous_locale();
    200206
    201207                switch_theme( WP_DEFAULT_THEME );
    202 
    203                 $this->assertSame( 'Das ist ein Dummy Theme', $expected );
    204208        }
    205209
    206210        /**
    class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase { 
    231235
    232236                $expected = i18n_theme_test();
    233237
     238                $this->assertSame( 'Das ist ein Dummy Theme', $expected );
     239
    234240                set_current_screen( 'front' );
    235241                switch_theme( WP_DEFAULT_THEME );
    236 
    237                 $this->assertSame( 'Das ist ein Dummy Theme', $expected );
    238242        }
    239243
    240244        /**
    class Tests_L10n_loadTextdomainJustInTime extends WP_UnitTestCase { 
    245249
    246250                add_filter( 'locale', array( $this, '_filter_locale_count' ) );
    247251
    248                 __( 'Foo', $textdomain );
    249                 __( 'Bar', $textdomain );
    250                 __( 'Baz', $textdomain );
    251                 __( 'Foo Bar', $textdomain );
    252                 __( 'Foo Bar Baz', $textdomain );
    253 
    254                 remove_filter( 'locale', array( $this, '_filter_locale_count' ) );
     252                $foo         = (string) __( 'Foo', $textdomain );
     253                $bar         = (string) __( 'Bar', $textdomain );
     254                $baz         = (string) __( 'Baz', $textdomain );
     255                $foo_bar     = (string) __( 'Foo Bar', $textdomain );
     256                $foo_bar_baz = (string) __( 'Foo Bar Baz', $textdomain );
    255257
    256258                $this->assertFalse( is_textdomain_loaded( $textdomain ) );
    257259                $this->assertSame( 1, $this->locale_count );
     260
     261                remove_filter( 'locale', array( $this, '_filter_locale_count' ) );
    258262        }
    259263
    260264        public function _filter_locale_count( $locale ) {
  • tests/phpunit/tests/l10n/localeSwitcher.php

    diff --git a/tests/phpunit/tests/l10n/localeSwitcher.php b/tests/phpunit/tests/l10n/localeSwitcher.php
    index f100c8a1db..84190c1961 100644
    a b class Tests_Locale_Switcher extends WP_UnitTestCase { 
    4848        public function test_switch_to_locale_returns_true() {
    4949                $expected = switch_to_locale( 'en_GB' );
    5050
     51                $this->assertTrue( $expected );
     52
    5153                // Cleanup.
    5254                restore_previous_locale();
    53 
    54                 $this->assertTrue( $expected );
    5555        }
    5656
    5757        public function test_switch_to_locale_changes_the_locale() {
    class Tests_Locale_Switcher extends WP_UnitTestCase { 
    5959
    6060                $locale = get_locale();
    6161
     62                $this->assertSame( 'en_GB', $locale );
     63
    6264                // Cleanup.
    6365                restore_previous_locale();
    64 
    65                 $this->assertSame( 'en_GB', $locale );
    6666        }
    6767
    6868        public function test_switch_to_locale_loads_translation() {
    class Tests_Locale_Switcher extends WP_UnitTestCase { 
    7070
    7171                $actual = __( 'Invalid parameter.' );
    7272
     73                $this->assertSame( 'Parámetro no válido. ', $actual );
     74
    7375                // Cleanup.
    7476                restore_previous_locale();
    75 
    76                 $this->assertSame( 'Parámetro no válido. ', $actual );
    7777        }
    7878
    7979        public function test_switch_to_locale_changes_wp_locale_global() {
    class Tests_Locale_Switcher extends WP_UnitTestCase { 
    8888
    8989                $wp_locale_de_DE = clone $wp_locale;
    9090
     91                $this->assertEqualSetsWithIndex( $expected, $wp_locale_de_DE->number_format );
     92
    9193                // Cleanup.
    9294                restore_previous_locale();
    93 
    94                 $this->assertEqualSetsWithIndex( $expected, $wp_locale_de_DE->number_format );
    9595        }
    9696
    9797        public function test_switch_to_locale_en_US() {
    class Tests_Locale_Switcher extends WP_UnitTestCase { 
    100100                switch_to_locale( 'en_US' );
    101101                $locale_en_US = get_locale();
    102102
    103                 // Cleanup.
    104                 restore_current_locale();
    105 
    106103                $this->assertSame( 'en_GB', $locale_en_GB );
    107104                $this->assertSame( 'en_US', $locale_en_US );
     105
     106                // Cleanup.
     107                restore_current_locale();
    108108        }
    109109
    110110        public function test_switch_to_locale_multiple_times() {
    class Tests_Locale_Switcher extends WP_UnitTestCase { 
    112112                switch_to_locale( 'es_ES' );
    113113                $locale = get_locale();
    114114
     115                $this->assertSame( 'es_ES', $locale );
     116
    115117                // Cleanup.
    116118                restore_previous_locale();
    117119                restore_previous_locale();
    118 
    119                 $this->assertSame( 'es_ES', $locale );
    120120        }
    121121
    122122        public function test_switch_to_locale_multiple_times_loads_translation() {
    class Tests_Locale_Switcher extends WP_UnitTestCase { 
    126126
    127127                $actual = __( 'Invalid parameter.' );
    128128
     129                $this->assertSame( 'Parámetro no válido. ', $actual );
     130
    129131                // Cleanup.
    130132                restore_previous_locale();
    131133                restore_previous_locale();
    132134                restore_previous_locale();
    133 
    134                 $this->assertSame( 'Parámetro no válido. ', $actual );
    135135        }
    136136
    137137        public function test_restore_previous_locale_without_switching() {
  • tests/phpunit/tests/locale.php

    diff --git a/tests/phpunit/tests/locale.php b/tests/phpunit/tests/locale.php
    index 4788d57d90..63cc5d062d 100644
    a b class Tests_Locale extends WP_UnitTestCase { 
    2121        }
    2222
    2323        public function test_get_weekday() {
    24                 $this->assertEquals( __( 'Sunday' ), $this->locale->get_weekday( 0 ) );
    25                 $this->assertEquals( __( 'Monday' ), $this->locale->get_weekday( 1 ) );
    26                 $this->assertEquals( __( 'Tuesday' ), $this->locale->get_weekday( 2 ) );
    27                 $this->assertEquals( __( 'Wednesday' ), $this->locale->get_weekday( 3 ) );
    28                 $this->assertEquals( __( 'Thursday' ), $this->locale->get_weekday( 4 ) );
    29                 $this->assertEquals( __( 'Friday' ), $this->locale->get_weekday( 5 ) );
    30                 $this->assertEquals( __( 'Saturday' ), $this->locale->get_weekday( 6 ) );
     24                $this->assertEquals( (string) __( 'Sunday' ), $this->locale->get_weekday( 0 ) );
     25                $this->assertEquals( (string) __( 'Monday' ), $this->locale->get_weekday( 1 ) );
     26                $this->assertEquals( (string) __( 'Tuesday' ), $this->locale->get_weekday( 2 ) );
     27                $this->assertEquals( (string) __( 'Wednesday' ), $this->locale->get_weekday( 3 ) );
     28                $this->assertEquals( (string) __( 'Thursday' ), $this->locale->get_weekday( 4 ) );
     29                $this->assertEquals( (string) __( 'Friday' ), $this->locale->get_weekday( 5 ) );
     30                $this->assertEquals( (string) __( 'Saturday' ), $this->locale->get_weekday( 6 ) );
    3131        }
    3232
    3333        /**
    class Tests_Locale extends WP_UnitTestCase { 
    3838        }
    3939
    4040        public function test_get_weekday_initial() {
    41                 $this->assertEquals( __( 'S' ), $this->locale->get_weekday_initial( __( 'Sunday' ) ) );
    42                 $this->assertEquals( __( 'M' ), $this->locale->get_weekday_initial( __( 'Monday' ) ) );
    43                 $this->assertEquals( __( 'T' ), $this->locale->get_weekday_initial( __( 'Tuesday' ) ) );
    44                 $this->assertEquals( __( 'W' ), $this->locale->get_weekday_initial( __( 'Wednesday' ) ) );
    45                 $this->assertEquals( __( 'T' ), $this->locale->get_weekday_initial( __( 'Thursday' ) ) );
    46                 $this->assertEquals( __( 'F' ), $this->locale->get_weekday_initial( __( 'Friday' ) ) );
    47                 $this->assertEquals( __( 'S' ), $this->locale->get_weekday_initial( __( 'Saturday' ) ) );
     41                $this->assertEquals( (string) __( 'S' ), $this->locale->get_weekday_initial( __( 'Sunday' ) ) );
     42                $this->assertEquals( (string) __( 'M' ), $this->locale->get_weekday_initial( __( 'Monday' ) ) );
     43                $this->assertEquals( (string) __( 'T' ), $this->locale->get_weekday_initial( __( 'Tuesday' ) ) );
     44                $this->assertEquals( (string) __( 'W' ), $this->locale->get_weekday_initial( __( 'Wednesday' ) ) );
     45                $this->assertEquals( (string) __( 'T' ), $this->locale->get_weekday_initial( __( 'Thursday' ) ) );
     46                $this->assertEquals( (string) __( 'F' ), $this->locale->get_weekday_initial( __( 'Friday' ) ) );
     47                $this->assertEquals( (string) __( 'S' ), $this->locale->get_weekday_initial( __( 'Saturday' ) ) );
    4848        }
    4949
    5050        public function test_get_weekday_abbrev() {
    51                 $this->assertEquals( __( 'Sun' ), $this->locale->get_weekday_abbrev( __( 'Sunday' ) ) );
    52                 $this->assertEquals( __( 'Mon' ), $this->locale->get_weekday_abbrev( __( 'Monday' ) ) );
    53                 $this->assertEquals( __( 'Tue' ), $this->locale->get_weekday_abbrev( __( 'Tuesday' ) ) );
    54                 $this->assertEquals( __( 'Wed' ), $this->locale->get_weekday_abbrev( __( 'Wednesday' ) ) );
    55                 $this->assertEquals( __( 'Thu' ), $this->locale->get_weekday_abbrev( __( 'Thursday' ) ) );
    56                 $this->assertEquals( __( 'Fri' ), $this->locale->get_weekday_abbrev( __( 'Friday' ) ) );
    57                 $this->assertEquals( __( 'Sat' ), $this->locale->get_weekday_abbrev( __( 'Saturday' ) ) );
     51                $this->assertEquals( (string) __( 'Sun' ), $this->locale->get_weekday_abbrev( __( 'Sunday' ) ) );
     52                $this->assertEquals( (string) __( 'Mon' ), $this->locale->get_weekday_abbrev( __( 'Monday' ) ) );
     53                $this->assertEquals( (string) __( 'Tue' ), $this->locale->get_weekday_abbrev( __( 'Tuesday' ) ) );
     54                $this->assertEquals( (string) __( 'Wed' ), $this->locale->get_weekday_abbrev( __( 'Wednesday' ) ) );
     55                $this->assertEquals( (string) __( 'Thu' ), $this->locale->get_weekday_abbrev( __( 'Thursday' ) ) );
     56                $this->assertEquals( (string) __( 'Fri' ), $this->locale->get_weekday_abbrev( __( 'Friday' ) ) );
     57                $this->assertEquals( (string) __( 'Sat' ), $this->locale->get_weekday_abbrev( __( 'Saturday' ) ) );
    5858        }
    5959
    6060        public function test_get_month() {
    61                 $this->assertEquals( __( 'January' ), $this->locale->get_month( 1 ) );
    62                 $this->assertEquals( __( 'February' ), $this->locale->get_month( 2 ) );
    63                 $this->assertEquals( __( 'March' ), $this->locale->get_month( 3 ) );
    64                 $this->assertEquals( __( 'April' ), $this->locale->get_month( 4 ) );
    65                 $this->assertEquals( __( 'May' ), $this->locale->get_month( 5 ) );
    66                 $this->assertEquals( __( 'June' ), $this->locale->get_month( 6 ) );
    67                 $this->assertEquals( __( 'July' ), $this->locale->get_month( 7 ) );
    68                 $this->assertEquals( __( 'August' ), $this->locale->get_month( 8 ) );
    69                 $this->assertEquals( __( 'September' ), $this->locale->get_month( 9 ) );
    70                 $this->assertEquals( __( 'October' ), $this->locale->get_month( 10 ) );
    71                 $this->assertEquals( __( 'November' ), $this->locale->get_month( 11 ) );
    72                 $this->assertEquals( __( 'December' ), $this->locale->get_month( 12 ) );
     61                $this->assertEquals( (string) __( 'January' ), $this->locale->get_month( 1 ) );
     62                $this->assertEquals( (string) __( 'February' ), $this->locale->get_month( 2 ) );
     63                $this->assertEquals( (string) __( 'March' ), $this->locale->get_month( 3 ) );
     64                $this->assertEquals( (string) __( 'April' ), $this->locale->get_month( 4 ) );
     65                $this->assertEquals( (string) __( 'May' ), $this->locale->get_month( 5 ) );
     66                $this->assertEquals( (string) __( 'June' ), $this->locale->get_month( 6 ) );
     67                $this->assertEquals( (string) __( 'July' ), $this->locale->get_month( 7 ) );
     68                $this->assertEquals( (string) __( 'August' ), $this->locale->get_month( 8 ) );
     69                $this->assertEquals( (string) __( 'September' ), $this->locale->get_month( 9 ) );
     70                $this->assertEquals( (string) __( 'October' ), $this->locale->get_month( 10 ) );
     71                $this->assertEquals( (string) __( 'November' ), $this->locale->get_month( 11 ) );
     72                $this->assertEquals( (string) __( 'December' ), $this->locale->get_month( 12 ) );
    7373        }
    7474
    7575        public function test_get_month_leading_zero() {
    76                 $this->assertEquals( __( 'January' ), $this->locale->get_month( '01' ) );
    77                 $this->assertEquals( __( 'February' ), $this->locale->get_month( '02' ) );
    78                 $this->assertEquals( __( 'March' ), $this->locale->get_month( '03' ) );
    79                 $this->assertEquals( __( 'April' ), $this->locale->get_month( '04' ) );
    80                 $this->assertEquals( __( 'May' ), $this->locale->get_month( '05' ) );
    81                 $this->assertEquals( __( 'June' ), $this->locale->get_month( '06' ) );
    82                 $this->assertEquals( __( 'July' ), $this->locale->get_month( '07' ) );
    83                 $this->assertEquals( __( 'August' ), $this->locale->get_month( '08' ) );
    84                 $this->assertEquals( __( 'September' ), $this->locale->get_month( '09' ) );
     76                $this->assertEquals( (string) __( 'January' ), $this->locale->get_month( '01' ) );
     77                $this->assertEquals( (string) __( 'February' ), $this->locale->get_month( '02' ) );
     78                $this->assertEquals( (string) __( 'March' ), $this->locale->get_month( '03' ) );
     79                $this->assertEquals( (string) __( 'April' ), $this->locale->get_month( '04' ) );
     80                $this->assertEquals( (string) __( 'May' ), $this->locale->get_month( '05' ) );
     81                $this->assertEquals( (string) __( 'June' ), $this->locale->get_month( '06' ) );
     82                $this->assertEquals( (string) __( 'July' ), $this->locale->get_month( '07' ) );
     83                $this->assertEquals( (string) __( 'August' ), $this->locale->get_month( '08' ) );
     84                $this->assertEquals( (string) __( 'September' ), $this->locale->get_month( '09' ) );
    8585        }
    8686
    8787        public function test_get_month_abbrev() {
    88                 $this->assertEquals( __( 'Jan' ), $this->locale->get_month_abbrev( __( 'January' ) ) );
    89                 $this->assertEquals( __( 'Feb' ), $this->locale->get_month_abbrev( __( 'February' ) ) );
    90                 $this->assertEquals( __( 'Mar' ), $this->locale->get_month_abbrev( __( 'March' ) ) );
    91                 $this->assertEquals( __( 'Apr' ), $this->locale->get_month_abbrev( __( 'April' ) ) );
    92                 $this->assertEquals( __( 'May' ), $this->locale->get_month_abbrev( __( 'May' ) ) );
    93                 $this->assertEquals( __( 'Jun' ), $this->locale->get_month_abbrev( __( 'June' ) ) );
    94                 $this->assertEquals( __( 'Jul' ), $this->locale->get_month_abbrev( __( 'July' ) ) );
    95                 $this->assertEquals( __( 'Aug' ), $this->locale->get_month_abbrev( __( 'August' ) ) );
    96                 $this->assertEquals( __( 'Sep' ), $this->locale->get_month_abbrev( __( 'September' ) ) );
    97                 $this->assertEquals( __( 'Oct' ), $this->locale->get_month_abbrev( __( 'October' ) ) );
    98                 $this->assertEquals( __( 'Nov' ), $this->locale->get_month_abbrev( __( 'November' ) ) );
    99                 $this->assertEquals( __( 'Dec' ), $this->locale->get_month_abbrev( __( 'December' ) ) );
     88                $this->assertEquals( (string) __( 'Jan' ), $this->locale->get_month_abbrev( __( 'January' ) ) );
     89                $this->assertEquals( (string) __( 'Feb' ), $this->locale->get_month_abbrev( __( 'February' ) ) );
     90                $this->assertEquals( (string) __( 'Mar' ), $this->locale->get_month_abbrev( __( 'March' ) ) );
     91                $this->assertEquals( (string) __( 'Apr' ), $this->locale->get_month_abbrev( __( 'April' ) ) );
     92                $this->assertEquals( (string) __( 'May' ), $this->locale->get_month_abbrev( __( 'May' ) ) );
     93                $this->assertEquals( (string) __( 'Jun' ), $this->locale->get_month_abbrev( __( 'June' ) ) );
     94                $this->assertEquals( (string) __( 'Jul' ), $this->locale->get_month_abbrev( __( 'July' ) ) );
     95                $this->assertEquals( (string) __( 'Aug' ), $this->locale->get_month_abbrev( __( 'August' ) ) );
     96                $this->assertEquals( (string) __( 'Sep' ), $this->locale->get_month_abbrev( __( 'September' ) ) );
     97                $this->assertEquals( (string) __( 'Oct' ), $this->locale->get_month_abbrev( __( 'October' ) ) );
     98                $this->assertEquals( (string) __( 'Nov' ), $this->locale->get_month_abbrev( __( 'November' ) ) );
     99                $this->assertEquals( (string) __( 'Dec' ), $this->locale->get_month_abbrev( __( 'December' ) ) );
    100100        }
    101101
    102102        public function test_get_meridiem() {
    103                 $this->assertEquals( __( 'am' ), $this->locale->get_meridiem( 'am' ) );
    104                 $this->assertEquals( __( 'AM' ), $this->locale->get_meridiem( 'AM' ) );
    105                 $this->assertEquals( __( 'pm' ), $this->locale->get_meridiem( 'pm' ) );
    106                 $this->assertEquals( __( 'PM' ), $this->locale->get_meridiem( 'PM' ) );
     103                $this->assertEquals( (string) __( 'am' ), $this->locale->get_meridiem( 'am' ) );
     104                $this->assertEquals( (string) __( 'AM' ), $this->locale->get_meridiem( 'AM' ) );
     105                $this->assertEquals( (string) __( 'pm' ), $this->locale->get_meridiem( 'pm' ) );
     106                $this->assertEquals( (string) __( 'PM' ), $this->locale->get_meridiem( 'PM' ) );
    107107        }
    108108
    109109        public function test_is_rtl() {