From 69867a34dbb7e236953f63c7c4b739323122ed76 Mon Sep 17 00:00:00 2001 From: herregroen Date: Thu, 1 Nov 2018 13:51:47 +0000 Subject: [PATCH] I18N: Improve JavaScript translation support. Improves upon [43825] by adding unit tests to cover additional use-cases and changes loading translations to only occur when outputting the script to allow setting translations on dependencies. Props atimmer, omarreiss, nerrad, swissspidy, ocean90. Fixes #45103. Built from https://develop.svn.wordpress.org/branches/5.0@43859 git-svn-id: http://core.svn.wordpress.org/branches/5.0@43688 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/class-wp-dependency.php | 23 ++++++++++++ wp-includes/class.wp-scripts.php | 54 +++++++++++++++++++++------- wp-includes/functions.wp-scripts.php | 7 +--- wp-includes/l10n.php | 12 ++++--- wp-includes/version.php | 2 +- 5 files changed, 75 insertions(+), 23 deletions(-) diff --git a/wp-includes/class-wp-dependency.php b/wp-includes/class-wp-dependency.php index cd808e8ece..76b58e15a9 100644 --- a/wp-includes/class-wp-dependency.php +++ b/wp-includes/class-wp-dependency.php @@ -67,6 +67,22 @@ class _WP_Dependency { */ public $extra = array(); + /** + * Translation textdomain set for this dependency. + * + * @since 5.0.0 + * @var string + */ + public $textdomain; + + /** + * Translation path set for this dependency. + * + * @since 5.0.0 + * @var string + */ + public $translations_path; + /** * Setup dependencies. * @@ -94,4 +110,11 @@ class _WP_Dependency { return true; } + public function set_translations( $domain, $path = null ) { + if ( !is_string($domain) ) + return false; + $this->textdomain = $domain; + $this->translations_path = $path; + return true; + } } diff --git a/wp-includes/class.wp-scripts.php b/wp-includes/class.wp-scripts.php index 22469d8332..424239ca99 100644 --- a/wp-includes/class.wp-scripts.php +++ b/wp-includes/class.wp-scripts.php @@ -325,6 +325,11 @@ class WP_Scripts extends WP_Dependencies { return true; } + $translations = $this->print_translations( $handle, false ); + if ( $translations ) { + $translations = sprintf( "\n", $translations ); + } + if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $this->content_url && 0 === strpos( $src, $this->content_url ) ) ) { $src = $this->base_url . $src; } @@ -338,7 +343,7 @@ class WP_Scripts extends WP_Dependencies { if ( ! $src ) return true; - $tag = "{$cond_before}{$before_handle}\n{$after_handle}{$cond_after}"; + $tag = "{$translations}{$cond_before}{$before_handle}\n{$after_handle}{$cond_after}"; /** * Filters the HTML script tag of an enqueued script. @@ -478,7 +483,7 @@ class WP_Scripts extends WP_Dependencies { } /** - * Register a translation textdomain. + * Sets a translation textdomain. * * @since 5.0.0 * @@ -493,23 +498,48 @@ class WP_Scripts extends WP_Dependencies { return false; } + /** @var \_WP_Dependency $obj */ + $obj = $this->registered[ $handle ]; + + if ( ! in_array( 'wp-i18n', $obj->deps, true ) ) { + $obj->deps[] = 'wp-i18n'; + } + return $obj->set_translations( $domain, $path ); + } + + /** + * Prints translations set for a specific handle. + * + * @since 5.0.0 + * + * @param string $handle Name of the script to add the inline script to. Must be lowercase. + * @param bool $echo Optional. Whether to echo the script instead of just returning it. + * Default true. + * @return string|false Script on success, false otherwise. + */ + public function print_translations( $handle, $echo = true ) { + if ( ! isset( $this->registered[ $handle ] ) || empty( $this->registered[ $handle ]->textdomain ) ) { + return false; + } + + $domain = $this->registered[ $handle ]->textdomain; + $path = $this->registered[ $handle ]->translations_path; + $json_translations = load_script_textdomain( $handle, $domain, $path ); if ( ! $json_translations ) { return false; } - /** @var \_WP_Dependency $obj */ - $obj = $this->registered[ $handle ]; - $obj->deps[] = 'wp-i18n'; + $output = '(function( translations ){' . + 'wp.i18n.setLocaleData( translations.locale_data, "' . $domain . '" );' . + '})(' . $json_translations . ');'; - return $this->add_inline_script( - $handle, - '(function( translations ){' . - 'wp.i18n.setLocaleData( translations.locale_data, "' . $domain . '" );' . - '})(' . $json_translations . ');', - 'before' - ); + if ( $echo ) { + printf( "\n", $output ); + } + + return $output; } /** diff --git a/wp-includes/functions.wp-scripts.php b/wp-includes/functions.wp-scripts.php index efe82d9774..dfb660907b 100644 --- a/wp-includes/functions.wp-scripts.php +++ b/wp-includes/functions.wp-scripts.php @@ -193,12 +193,11 @@ function wp_localize_script( $handle, $object_name, $l10n ) { } /** - * Register translated strings for a script. + * Sets translated strings for a script. * * Works only if the script has already been added. * * @see WP_Scripts::set_translations() - * @link https://core.trac.wordpress.org/ticket/45103 * @global WP_Scripts $wp_scripts The WP_Scripts object for printing scripts. * * @since 5.0.0 @@ -216,10 +215,6 @@ function wp_set_script_translations( $handle, $domain, $path = null ) { return false; } - if ( ! wp_script_is( $handle, 'enqueued' ) ) { - _doing_it_wrong( __FUNCTION__, __( 'Script translations may only be set if the script is enqueued.' ), '5.0.0' ); - } - return $wp_scripts->set_translations( $handle, $domain, $path ); } diff --git a/wp-includes/l10n.php b/wp-includes/l10n.php index d0b2f38b98..feaf89d653 100644 --- a/wp-includes/l10n.php +++ b/wp-includes/l10n.php @@ -876,6 +876,8 @@ function load_child_theme_textdomain( $domain, $path = false ) { * @link https://core.trac.wordpress.org/ticket/45103 * @global WP_Scripts $wp_scripts The WP_Scripts object for printing scripts. * + * @since 5.0.0 + * * @param string $handle Name of the script to register a translation domain to. * @param string $domain The textdomain. * @param string $path Optional. The full file path to the directory containing translation files. @@ -886,10 +888,12 @@ function load_child_theme_textdomain( $domain, $path = false ) { function load_script_textdomain( $handle, $domain, $path = null ) { global $wp_scripts; + $path = untrailingslashit( $path ); $locale = is_admin() ? get_locale() : get_user_locale(); // If a path was given and the handle file exists simply return it. - $handle_filename = $domain . '-' . $locale . '-' . $handle . '.json'; + $file_base = $domain === 'default' ? $locale : $domain . '-' . $locale; + $handle_filename = $file_base . '-' . $handle . '.json'; if ( $path && file_exists( $path . '/' . $handle_filename ) ) { return file_get_contents( $path . '/' . $handle_filename ); } @@ -908,7 +912,7 @@ function load_script_textdomain( $handle, $domain, $path = null ) { // If the host is the same or it's a relative URL. if ( - strpos( $content_url['path'], $src_url['path'] ) === 0 && + strpos( $src_url['path'], $content_url['path'] ) === 0 && ( ! isset( $src_url['host'] ) || $src_url['host'] !== $content_url['host'] ) ) { // Make the src relative the specific plugin or theme. @@ -925,7 +929,7 @@ function load_script_textdomain( $handle, $domain, $path = null ) { ) { $relative = trim( $src_url['path'], '/' ); } else if ( - ( strpos( $site_url['path'], $src_url['path'] ) === 0 ) && + ( strpos( $src_url['path'], $site_url['path'] ) === 0 ) && ( ! isset( $src_url['host'] ) || $src_url['host'] !== $site_url['host'] ) ) { // Make the src relative to the WP root. @@ -943,7 +947,7 @@ function load_script_textdomain( $handle, $domain, $path = null ) { $relative = substr( $relative, 0, -7 ) . '.js'; } - $md5_filename = $domain . '-' . $locale . '-' . md5( $relative ) . '.json'; + $md5_filename = $file_base . '-' . md5( $relative ) . '.json'; if ( $path && file_exists( $path . '/' . $md5_filename ) ) { return file_get_contents( $path . '/' . $md5_filename ); } diff --git a/wp-includes/version.php b/wp-includes/version.php index 93ea9f1ff2..c21a6df2f2 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '5.0-beta2-43858'; +$wp_version = '5.0-beta2-43859'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.