Make WordPress Core

Ticket #41305: 41305.all-in.diff

File 41305.all-in.diff, 39.9 KB (added by schlessera, 7 years ago)

Direct change to default translation mechanism

  • src/wp-includes/class-wp-locale.php

    diff --git src/wp-includes/class-wp-locale.php src/wp-includes/class-wp-locale.php
    index 287914e880..a12b2ce26c 100644
    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 { 
    250250         * @return string Full translated weekday.
    251251         */
    252252        public function get_weekday( $weekday_number ) {
    253                 return $this->weekday[ $weekday_number ];
     253                return $this->weekday[ (string) $weekday_number ];
    254254        }
    255255
    256256        /**
    class WP_Locale { 
    267267         * @return string Translated weekday initial.
    268268         */
    269269        public function get_weekday_initial( $weekday_name ) {
    270                 return $this->weekday_initial[ $weekday_name ];
     270                return $this->weekday_initial[ (string) $weekday_name ];
    271271        }
    272272
    273273        /**
    class WP_Locale { 
    282282         * @return string Translated weekday abbreviation.
    283283         */
    284284        public function get_weekday_abbrev( $weekday_name ) {
    285                 return $this->weekday_abbrev[ $weekday_name ];
     285                return $this->weekday_abbrev[ (string) $weekday_name ];
    286286        }
    287287
    288288        /**
    class WP_Locale { 
    317317         * @return string Translated abbreviated month.
    318318         */
    319319        public function get_month_abbrev( $month_name ) {
    320                 return $this->month_abbrev[ $month_name ];
     320                return $this->month_abbrev[ (string) $month_name ];
    321321        }
    322322
    323323        /**
    class WP_Locale { 
    331331         * @return string Translated version
    332332         */
    333333        public function get_meridiem( $meridiem ) {
    334                 return $this->meridiem[ $meridiem ];
     334                return $this->meridiem[ (string) $meridiem ];
    335335        }
    336336
    337337        /**
  • src/wp-includes/comment-template.php

    diff --git src/wp-includes/comment-template.php src/wp-includes/comment-template.php
    index bcda28f87c..af108883cf 100644
    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 src/wp-includes/functions.php src/wp-includes/functions.php
    index 6f9e77c5b7..987a24028c 100644
    function wp_maybe_decline_date( $date ) { 
    178178        /* translators: If months in your language require a genitive case,
    179179         * translate this to 'on'. Do not translate into your own language.
    180180         */
    181         if ( 'on' === _x( 'off', 'decline months names: on or off' ) ) {
     181        if ( 'on' === (string) _x( 'off', 'decline months names: on or off' ) ) {
    182182                // Match a format like 'j F Y' or 'j. F'
    183183                if ( @preg_match( '#^\d{1,2}\.? [^\d ]+#u', $date ) ) {
    184184                        $months          = $wp_locale->month;
    function wp_die( $message = '', $title = '', $args = array() ) { 
    28132813                $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
    28142814        }
    28152815
    2816         call_user_func( $function, $message, $title, $args );
     2816        call_user_func( $function, (string) $message, $title, $args );
    28172817}
    28182818
    28192819/**
    function wp_privacy_anonymize_data( $type, $data = '' ) { 
    62506250 * Trigger the check for policy text changes.
    62516251 *
    62526252 * @since 4.9.6
    6253  * @access private 
     6253 * @access private
    62546254 */
    62556255function _wp_privacy_active_plugins_change() {
    62566256        update_option( '_wp_privacy_text_change_check', 'check' );
  • src/wp-includes/l10n.php

    diff --git src/wp-includes/l10n.php src/wp-includes/l10n.php
    index 4aef972490..5d22b24537 100644
    function translate_with_gettext_context( $text, $context, $domain = 'default' ) 
    192192 * If there is no translation, or the text domain isn't loaded, the original text is returned.
    193193 *
    194194 * @since 2.1.0
     195 * @since 5.0.0 Returns a lazily-translating proxy object.
    195196 *
    196197 * @param string $text   Text to translate.
    197198 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
    198199 *                       Default 'default'.
    199  * @return string Translated text.
     200 * @return WP_String_Proxy Proxy object representing a string.
    200201 */
    201202function __( $text, $domain = 'default' ) {
    202         return translate( $text, $domain );
     203        return new WP_Translation_Proxy( $text, $domain );
    203204}
    204205
    205206/**
    function __( $text, $domain = 'default' ) { 
    208209 * If there is no translation, or the text domain isn't loaded, the original text is returned.
    209210 *
    210211 * @since 2.8.0
     212 * @since 5.0.0 Returns a lazily-translating proxy object.
    211213 *
    212214 * @param string $text   Text to translate.
    213215 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
    214216 *                       Default 'default'.
    215  * @return string Translated text on success, original text on failure.
     217 * @return WP_String_Proxy Proxy object representing a string.
    216218 */
    217219function esc_attr__( $text, $domain = 'default' ) {
    218         return esc_attr( translate( $text, $domain ) );
     220        return new WP_Escape_Attribute_Proxy(
     221                new WP_Translation_Proxy( $text, $domain )
     222        );
    219223}
    220224
    221225/**
    function esc_attr__( $text, $domain = 'default' ) { 
    225229 * is escaped and returned.
    226230 *
    227231 * @since 2.8.0
     232 * @since 5.0.0 Returns a lazily-translating proxy object.
    228233 *
    229234 * @param string $text   Text to translate.
    230235 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings.
    231236 *                       Default 'default'.
    232  * @return string Translated text
     237 * @return WP_String_Proxy Proxy object representing a string.
    233238 */
    234239function esc_html__( $text, $domain = 'default' ) {
    235         return esc_html( translate( $text, $domain ) );
     240        return new WP_Escape_HTML_Proxy(
     241                new WP_Translation_Proxy( $text, $domain )
     242        );
    236243}
    237244
    238245/**
    function esc_html_e( $text, $domain = 'default' ) { 
    284291 * strings differently.
    285292 *
    286293 * @since 2.8.0
     294 * @since 5.0.0 Returns a lazily-translating proxy object.
    287295 *
    288296 * @param string $text    Text to translate.
    289297 * @param string $context Context information for the translators.
    290298 * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
    291299 *                        Default 'default'.
    292  * @return string Translated context string without pipe.
     300 * @return WP_String_Proxy Proxy object representing a string.
    293301 */
    294302function _x( $text, $context, $domain = 'default' ) {
    295         return translate_with_gettext_context( $text, $context, $domain );
     303        return new WP_Contextual_Translation_Proxy( $text, $context, $domain );
    296304}
    297305
    298306/**
    function _ex( $text, $context, $domain = 'default' ) { 
    314322 * Translate string with gettext context, and escapes it for safe use in an attribute.
    315323 *
    316324 * @since 2.8.0
     325 * @since 5.0.0 Returns a lazily-translating proxy object.
    317326 *
    318327 * @param string $text    Text to translate.
    319328 * @param string $context Context information for the translators.
    320329 * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
    321330 *                        Default 'default'.
    322  * @return string Translated text
     331 * @return WP_String_Proxy Proxy object representing a string.
    323332 */
    324333function esc_attr_x( $text, $context, $domain = 'default' ) {
    325         return esc_attr( translate_with_gettext_context( $text, $context, $domain ) );
     334        return new WP_Escape_Attribute_Proxy(
     335                new WP_Contextual_Translation_Proxy( $text, $context, $domain )
     336        );
    326337}
    327338
    328339/**
    329340 * Translate string with gettext context, and escapes it for safe use in HTML output.
    330341 *
    331342 * @since 2.9.0
     343 * @since 5.0.0 Returns a lazily-translating proxy object.
    332344 *
    333345 * @param string $text    Text to translate.
    334346 * @param string $context Context information for the translators.
    335347 * @param string $domain  Optional. Text domain. Unique identifier for retrieving translated strings.
    336348 *                        Default 'default'.
    337  * @return string Translated text.
     349 * @return WP_String_Proxy Proxy object representing a string.
    338350 */
    339351function esc_html_x( $text, $context, $domain = 'default' ) {
    340         return esc_html( translate_with_gettext_context( $text, $context, $domain ) );
     352        return new WP_Escape_HTML_Proxy(
     353                new WP_Contextual_Translation_Proxy( $text, $context, $domain )
     354        );
    341355}
    342356
    343357/**
  • new file src/wp-includes/l10n/class-wp-contextual_translation-proxy.php

    diff --git src/wp-includes/l10n/class-wp-contextual_translation-proxy.php src/wp-includes/l10n/class-wp-contextual_translation-proxy.php
    new file mode 100644
    index 0000000000..02707c9289
    - +  
     1<?php
     2
     3/**
     4 * L10n: WP_Contextual_Translation_Proxy class.
     5 *
     6 * @package    WordPress
     7 * @subpackage L10n
     8 * @since      5.0.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.0.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
     31        /**
     32         * Get the result of evaluating the string proxy object.
     33         *
     34         * @since 5.0.0
     35         *
     36         * @return string
     37         */
     38        protected function get_result() {
     39                return translate_with_gettext_context(
     40                        $this->text,
     41                        $this->context,
     42                        $this->domain
     43                );
     44        }
     45}
  • new file src/wp-includes/l10n/class-wp-escape-attribute-proxy.php

    diff --git src/wp-includes/l10n/class-wp-escape-attribute-proxy.php src/wp-includes/l10n/class-wp-escape-attribute-proxy.php
    new file mode 100644
    index 0000000000..1f1a895212
    - +  
     1<?php
     2
     3/**
     4 * L10n: WP_Escape_Attribute_Proxy class.
     5 *
     6 * @package    WordPress
     7 * @subpackage L10n
     8 * @since      5.0.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.0.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
     26        /**
     27         * Get the result of evaluating the string proxy object.
     28         *
     29         * @since 5.0.0
     30         *
     31         * @return string
     32         */
     33        protected function get_result() {
     34                return esc_attr( (string) $this->value );
     35        }
     36}
  • new file src/wp-includes/l10n/class-wp-escape-html-proxy.php

    diff --git src/wp-includes/l10n/class-wp-escape-html-proxy.php src/wp-includes/l10n/class-wp-escape-html-proxy.php
    new file mode 100644
    index 0000000000..b77e94708b
    - +  
     1<?php
     2
     3/**
     4 * L10n: WP_Escape_HTML_Proxy class.
     5 *
     6 * @package    WordPress
     7 * @subpackage L10n
     8 * @since      5.0.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.0.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
     26        /**
     27         * Get the result of evaluating the string proxy object.
     28         *
     29         * @since 5.0.0
     30         *
     31         * @return string
     32         */
     33        protected function get_result() {
     34                return esc_html( (string) $this->value );
     35        }
     36}
  • new file src/wp-includes/l10n/class-wp-string-proxy.php

    diff --git src/wp-includes/l10n/class-wp-string-proxy.php src/wp-includes/l10n/class-wp-string-proxy.php
    new file mode 100644
    index 0000000000..8ed28101ed
    - +  
     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 * Uses magic `__get()` to make sure the result is only generated once.
     13 *
     14 * @package    WordPress
     15 * @subpackage L10n
     16 * @since      5.0.0
     17 */
     18abstract class WP_String_Proxy implements JsonSerializable, ArrayAccess {
     19
     20        /**
     21         * Return the string representation of the proxy object.
     22         *
     23         * @since 5.0.0
     24         *
     25         * @return string
     26         */
     27        public function __toString() {
     28                return $this->result;
     29        }
     30
     31        /**
     32         * Return the JSON representation of the proxy object.
     33         *
     34         * @since 5.0.0
     35         *
     36         * @return string
     37         */
     38        public function jsonSerialize() {
     39                return $this->result;
     40        }
     41
     42        /**
     43         * Lazily evaluate the `result` property the first time it is being
     44         * requested.
     45         *
     46         * The property is then set to the resulting value, so that the
     47         * `__get()` magic method will not be called again.
     48         *
     49         * @since 5.0.0
     50         *
     51         * @param string $property Property that was requested.
     52         *
     53         * @return string
     54         */
     55        public function __get( $property ) {
     56                if ( 'result' === $property ) {
     57                        $this->result = $this->get_result();
     58
     59                        return $this->result;
     60                }
     61
     62                $message = sprintf(
     63                        'Undefined property: %s::$%s',
     64                        get_class(),
     65                        $property
     66                );
     67
     68                trigger_error( $message, E_USER_NOTICE );
     69
     70                return null;
     71        }
     72
     73        /**
     74         * Check whether an offset into the array exists.
     75         *
     76         * @since 5.0.0
     77         *
     78         * @param mixed $offset Offset to check for.
     79         *
     80         * @return bool
     81         */
     82        public function offsetExists( $offset ) {
     83                return mb_strlen( $this->result ) > $offset;
     84        }
     85
     86        /**
     87         * Retrieve a specific offset into the array.
     88         *
     89         * @since 5.0.0
     90         *
     91         * @param mixed $offset The offset to retrieve.
     92         *
     93         * @return mixed
     94         */
     95        public function offsetGet( $offset ) {
     96                return $this->result[ $offset ];
     97        }
     98
     99        /**
     100         * Set a specific offset in the array.
     101         *
     102         * @since 5.0.0
     103         *
     104         * @param mixed $offset The offset to assign the value to.
     105         * @param mixed $value  The value to set the offset to.
     106         */
     107        public function offsetSet( $offset, $value ) {
     108                $this->result[ $offset ] = $value;
     109        }
     110
     111        /**
     112         * Unset a specific offset in the array.
     113         *
     114         * @since 5.0.0
     115         *
     116         * @param mixed $offset The offset to unset.
     117         */
     118        public function offsetUnset( $offset ) {
     119                trigger_error( 'Cannot unset string offset', E_USER_ERROR );
     120        }
     121
     122        /**
     123         * Get the result of evaluating the string proxy object.
     124         *
     125         * @since 5.0.0
     126         *
     127         * @return string
     128         */
     129        abstract protected function get_result();
     130}
  • new file src/wp-includes/l10n/class-wp-translation-proxy.php

    diff --git src/wp-includes/l10n/class-wp-translation-proxy.php src/wp-includes/l10n/class-wp-translation-proxy.php
    new file mode 100644
    index 0000000000..28b73e63f3
    - +  
     1<?php
     2
     3/**
     4 * L10n: WP_Translation_Proxy class.
     5 *
     6 * @package    WordPress
     7 * @subpackage L10n
     8 * @since      5.0.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.0.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
     28        /**
     29         * Get the result of evaluating the string proxy object.
     30         *
     31         * @since 5.0.0
     32         *
     33         * @return string
     34         */
     35        protected function get_result() {
     36                return translate( $this->text, $this->domain );
     37        }
     38}
  • src/wp-includes/wp-db.php

    diff --git src/wp-includes/wp-db.php src/wp-includes/wp-db.php
    index 77b64da839..3e01e80f9b 100644
    class wpdb { 
    13131313                }
    13141314
    13151315                foreach ( $args as $arg ) {
    1316                         if ( ! is_scalar( $arg ) && ! is_null( $arg ) ) {
     1316                        if ( ! is_scalar( $arg ) && ! is_null( $arg ) && ! $arg instanceof WP_String_Proxy) {
    13171317                                wp_load_translations_early();
    13181318                                _doing_it_wrong( 'wpdb::prepare', sprintf( __( 'Unsupported value type (%s).' ), gettype( $arg ) ), '4.8.2' );
    13191319                        }
  • src/wp-settings.php

    diff --git src/wp-settings.php src/wp-settings.php
    index eb632238f0..047836a987 100644
    require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-comment-meta-fields.p 
    240240require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-post-meta-fields.php' );
    241241require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-term-meta-fields.php' );
    242242require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-user-meta-fields.php' );
     243require( ABSPATH . WPINC . '/l10n/class-wp-string-proxy.php' );
     244require( ABSPATH . WPINC . '/l10n/class-wp-translation-proxy.php' );
     245require( ABSPATH . WPINC . '/l10n/class-wp-contextual_translation-proxy.php' );
     246require( ABSPATH . WPINC . '/l10n/class-wp-escape-attribute-proxy.php' );
     247require( ABSPATH . WPINC . '/l10n/class-wp-escape-html-proxy.php' );
    243248
    244249$GLOBALS['wp_embed'] = new WP_Embed();
    245250
  • tests/phpunit/data/plugins/internationalized-plugin.php

    diff --git tests/phpunit/data/plugins/internationalized-plugin.php tests/phpunit/data/plugins/internationalized-plugin.php
    index 4b56846ad3..2362cf6180 100644
    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/testcase.php

    diff --git tests/phpunit/includes/testcase.php tests/phpunit/includes/testcase.php
    index db3f0b9fb6..26fa83f75f 100644
    class WP_UnitTestCase extends PHPUnit_Framework_TestCase { 
    582582        }
    583583
    584584        /**
     585         * Assert that two elements are equal.
     586         *
     587         * Override to handle special cases for equality checks.
     588         *
     589         * @since 5.0.0 Added WP_String_Proxy object <=> string equality.
     590         *
     591         * @param mixed  $expected
     592         * @param mixed  $actual
     593         * @param string $message
     594         * @param int    $delta
     595         * @param int    $maxDepth
     596         * @param bool   $canonicalize
     597         * @param bool   $ignoreCase
     598         */
     599        public static function assertEquals( $expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false ) {
     600                if ( is_array( $actual ) ) {
     601                        array_walk( $actual, 'WP_UnitTestCase::resolve_proxies', $expected );
     602                }
     603
     604                $actual   = self::resolve_proxy( $actual );
     605                $expected = self::resolve_proxy( $expected );
     606
     607                parent::assertEquals( $expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase );
     608        }
     609
     610        /**
     611         * Resolve proxies in arrays to be tested.
     612         *
     613         * @since 5.0.0
     614         *
     615         * @param mixed  $value Reference to the array value to be checked.
     616         * @param string $key   Index key of the array value to be checked.
     617         */
     618        protected static function resolve_proxies( &$value, $key ) {
     619                if ( is_array( $value ) ) {
     620                        array_walk( $value, 'WP_UnitTestCase::resolve_proxies' );
     621                }
     622
     623                $value = self::resolve_proxy( $value );
     624        }
     625
     626        /**
     627         * Resolve an individual proxy.
     628         *
     629         * @since 0.1.0
     630         *
     631         * @param $value
     632         *
     633         * @return string
     634         */
     635        protected static function resolve_proxy( $value ) {
     636                if ( $value instanceof WP_String_Proxy ) {
     637                        return (string) $value;
     638                }
     639
     640                return $value;
     641        }
     642
     643        /**
     644         * Asserts that two variables have the same type and value.
     645         * Used on objects, it asserts that two variables reference
     646         * the same object.
     647         *
     648         * Override to handle special cases for equality checks.
     649         *
     650         * @since 5.0.0 Added WP_String_Proxy object <=> string equality.
     651         *
     652         * @param mixed  $expected
     653         * @param mixed  $actual
     654         * @param string $message
     655         */
     656        public static function assertSame( $expected, $actual, $message = '' ) {
     657                if ( is_array( $actual ) ) {
     658                        array_walk( $actual, 'WP_UnitTestCase::resolve_proxies' );
     659                }
     660
     661                if ( is_array( $expected ) ) {
     662                        array_walk( $expected, 'WP_UnitTestCase::resolve_proxies' );
     663                }
     664
     665                $actual   = self::resolve_proxy( $actual );
     666                $expected = self::resolve_proxy( $expected );
     667
     668                parent::assertSame( $expected, $actual, $message );
     669        }
     670
     671        /**
     672         * Asserts that a variable is of a given type.
     673         *
     674         * Override to handle special cases for equality checks.
     675         *
     676         * @since 5.0.0 Added WP_String_Proxy object <=> string equality.
     677         *
     678         * @param string $expected
     679         * @param mixed  $actual
     680         * @param string $message
     681         */
     682        public static function assertInternalType( $expected, $actual, $message = '' ) {
     683                if ( 'string' === $expected ) {
     684                        $actual = self::resolve_proxy( $actual );
     685                }
     686
     687                parent::assertInternalType( $expected, $actual, $message );
     688        }
     689
     690    /**
    585691         * Sets the global state to as if a given URL has been requested.
    586692         *
    587693         * This sets:
  • tests/phpunit/tests/customize/nav-menus.php

    diff --git tests/phpunit/tests/customize/nav-menus.php tests/phpunit/tests/customize/nav-menus.php
    index e37b94b09f..3af5744fe3 100644
    class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase { 
    389389                $results = $menus->search_available_items_query(
    390390                        array(
    391391                                'pagenum' => 1,
    392                                 's'       => $title,
     392                                's'       => (string) $title,
    393393                        )
    394394                );
    395395                $this->assertCount( 1, $results );
  • tests/phpunit/tests/locale.php

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