From 0b8750685d9bbf8e12da2bf5ef32687ef30518aa Mon Sep 17 00:00:00 2001 From: Jorge Date: Mon, 30 Nov 2020 18:21:31 +0000 Subject: [PATCH 1/4] Add JSON specifying which theme.json paths are translatable; theme.json translation mechanism. --- lib/class-wp-theme-json-resolver.php | 82 ++++++++++++++++++++++++++++ lib/experimental-i18n-theme.json | 30 ++++++++++ 2 files changed, 112 insertions(+) create mode 100644 lib/experimental-i18n-theme.json diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index a94dbb1fde86d..378641457c184 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -71,6 +71,86 @@ private static function get_from_file( $file_path ) { return $config; } + /** + * Processes a tree from i18n-theme.json into a liner array + * containing the a translatable path from theme.json and an array + * of properties that are translatable. + * + * @param array $file_structure_partial A part of a theme.json i18n tree. + * @param array $current_path An array with a path on the theme.json i18n tree. + * + * @return array An array of arrays each one containing a translatable path and an array of properties that are translatable. + */ + private static function theme_json_i18_file_structure_to_paths( $file_structure_partial, $current_path = array() ) { + $result = array(); + foreach ( $file_structure_partial as $property => $partial_child ) { + if ( is_numeric( $property ) ) { + return array( + array( + 'path' => $current_path, + 'translatable_keys' => $file_structure_partial, + ), + ); + } + $result = array_merge( + $result, + self::theme_json_i18_file_structure_to_paths( $partial_child, array_merge( $current_path, array( $property ) ) ) + ); + } + return $result; + } + + /** + * Returns a data structure used in theme.json translation. + * + * @return array An array of theme.json paths that are translatable and the keys that are translatable + */ + private static function get_theme_json_i18n() { + static $theme_json_i18n = null; + if ( null === $theme_json_i18n ) { + $file_structure = self::get_from_file( __DIR__ . '/experimental-i18n-theme.json' ); + $theme_json_i18n = self::theme_json_i18_file_structure_to_paths( $file_structure ); + + } + return $theme_json_i18n; + } + + /** + * Translates a theme.json structure. + * + * @param array $theme_json_structure A theme.json structure that is going to be translatable. + * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. + * Default 'default'. + */ + private static function apply_theme_json_translations( &$theme_json_structure, $domain = 'default' ) { + $theme_json_i18n = self::get_theme_json_i18n(); + foreach ( $theme_json_structure as &$context_value ) { + if ( empty( $context_value ) || empty( $context_value['settings'] ) ) { + continue; + } + $settings = &$context_value['settings']; + foreach ( $theme_json_i18n as $theme_json_i18n_value ) { + $path = $theme_json_i18n_value['path']; + $translatable_keys = $theme_json_i18n_value['translatable_keys']; + $array_to_translate = gutenberg_experimental_get( $settings, $path, null ); + if ( null === $array_to_translate ) { + continue; + } + foreach ( $array_to_translate as &$item_to_translate ) { + foreach ( $translatable_keys as $translatable_key ) { + if ( empty( $item_to_translate[ $translatable_key ] ) ) { + continue; + } + // phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain + $item_to_translate[ $translatable_key ] = translate( $item_to_translate[ $translatable_key ], $domain ); + // phpcs:enable + } + } + gutenberg_experimental_set( $settings, $path, $array_to_translate ); + } + } + } + /** * Return core's origin config. * @@ -82,6 +162,7 @@ private static function get_core_origin() { } $config = self::get_from_file( __DIR__ . '/experimental-default-theme.json' ); + self::apply_theme_json_translations( $config ); // Start i18n logic to remove when JSON i18 strings are extracted. $default_colors_i18n = array( @@ -155,6 +236,7 @@ private static function get_core_origin() { */ private function get_theme_origin( $theme_support_data = array() ) { $theme_json_data = self::get_from_file( locate_template( 'experimental-theme.json' ) ); + self::apply_theme_json_translations( $theme_json_data, wp_get_theme()->get_stylesheet() ); /* * We want the presets and settings declared in theme.json diff --git a/lib/experimental-i18n-theme.json b/lib/experimental-i18n-theme.json new file mode 100644 index 0000000000000..6d5db8d2f2128 --- /dev/null +++ b/lib/experimental-i18n-theme.json @@ -0,0 +1,30 @@ +{ + "typography": { + "fontSizes": [ + "name" + ], + "fontStyles": [ + "name" + ], + "fontWeights": [ + "name" + ], + "fontFamilies": [ + "name" + ], + "textTransforms": [ + "name" + ], + "textDecorations": [ + "name" + ] + }, + "color": { + "palette": [ + "name" + ], + "gradients": [ + "name" + ] + } +} From 03ceff9fe7ba06509523268740225bc134734dbb Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Wed, 9 Dec 2020 21:21:31 +0000 Subject: [PATCH 2/4] Update lib/class-wp-theme-json-resolver.php Co-authored-by: Miguel Fonseca --- lib/class-wp-theme-json-resolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index 378641457c184..0b273003832ed 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -72,7 +72,7 @@ private static function get_from_file( $file_path ) { } /** - * Processes a tree from i18n-theme.json into a liner array + * Processes a tree from i18n-theme.json into a linear array * containing the a translatable path from theme.json and an array * of properties that are translatable. * From 9afc5cdd1e03153cb94f7cf7582a69208eb2c5f3 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Wed, 9 Dec 2020 21:26:47 +0000 Subject: [PATCH 3/4] Update lib/class-wp-theme-json-resolver.php Co-authored-by: Pascal Birchler --- lib/class-wp-theme-json-resolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index 0b273003832ed..b5ae4accafaec 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -236,7 +236,7 @@ private static function get_core_origin() { */ private function get_theme_origin( $theme_support_data = array() ) { $theme_json_data = self::get_from_file( locate_template( 'experimental-theme.json' ) ); - self::apply_theme_json_translations( $theme_json_data, wp_get_theme()->get_stylesheet() ); + self::apply_theme_json_translations( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) ); /* * We want the presets and settings declared in theme.json From 93c3c8703672d45848a099eb21b2644e7558a7c0 Mon Sep 17 00:00:00 2001 From: Jorge Date: Wed, 9 Dec 2020 22:04:55 +0000 Subject: [PATCH 4/4] Not assume settings --- lib/class-wp-theme-json-resolver.php | 29 +++++++------- lib/experimental-i18n-theme.json | 56 ++++++++++++++-------------- 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index b5ae4accafaec..3341c4071ac2b 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -81,7 +81,7 @@ private static function get_from_file( $file_path ) { * * @return array An array of arrays each one containing a translatable path and an array of properties that are translatable. */ - private static function theme_json_i18_file_structure_to_paths( $file_structure_partial, $current_path = array() ) { + private static function theme_json_i18_file_structure_to_preset_paths( $file_structure_partial, $current_path = array() ) { $result = array(); foreach ( $file_structure_partial as $property => $partial_child ) { if ( is_numeric( $property ) ) { @@ -94,7 +94,7 @@ private static function theme_json_i18_file_structure_to_paths( $file_structure_ } $result = array_merge( $result, - self::theme_json_i18_file_structure_to_paths( $partial_child, array_merge( $current_path, array( $property ) ) ) + self::theme_json_i18_file_structure_to_preset_paths( $partial_child, array_merge( $current_path, array( $property ) ) ) ); } return $result; @@ -105,11 +105,11 @@ private static function theme_json_i18_file_structure_to_paths( $file_structure_ * * @return array An array of theme.json paths that are translatable and the keys that are translatable */ - private static function get_theme_json_i18n() { + private static function get_presets_to_translate() { static $theme_json_i18n = null; if ( null === $theme_json_i18n ) { $file_structure = self::get_from_file( __DIR__ . '/experimental-i18n-theme.json' ); - $theme_json_i18n = self::theme_json_i18_file_structure_to_paths( $file_structure ); + $theme_json_i18n = self::theme_json_i18_file_structure_to_preset_paths( $file_structure ); } return $theme_json_i18n; @@ -122,17 +122,16 @@ private static function get_theme_json_i18n() { * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. * Default 'default'. */ - private static function apply_theme_json_translations( &$theme_json_structure, $domain = 'default' ) { - $theme_json_i18n = self::get_theme_json_i18n(); + private static function translate_presets( &$theme_json_structure, $domain = 'default' ) { + $preset_to_translate = self::get_presets_to_translate(); foreach ( $theme_json_structure as &$context_value ) { - if ( empty( $context_value ) || empty( $context_value['settings'] ) ) { + if ( empty( $context_value ) ) { continue; } - $settings = &$context_value['settings']; - foreach ( $theme_json_i18n as $theme_json_i18n_value ) { - $path = $theme_json_i18n_value['path']; - $translatable_keys = $theme_json_i18n_value['translatable_keys']; - $array_to_translate = gutenberg_experimental_get( $settings, $path, null ); + foreach ( $preset_to_translate as $preset ) { + $path = $preset['path']; + $translatable_keys = $preset['translatable_keys']; + $array_to_translate = gutenberg_experimental_get( $context_value, $path, null ); if ( null === $array_to_translate ) { continue; } @@ -146,7 +145,7 @@ private static function apply_theme_json_translations( &$theme_json_structure, $ // phpcs:enable } } - gutenberg_experimental_set( $settings, $path, $array_to_translate ); + gutenberg_experimental_set( $context_value, $path, $array_to_translate ); } } } @@ -162,7 +161,7 @@ private static function get_core_origin() { } $config = self::get_from_file( __DIR__ . '/experimental-default-theme.json' ); - self::apply_theme_json_translations( $config ); + self::translate_presets( $config ); // Start i18n logic to remove when JSON i18 strings are extracted. $default_colors_i18n = array( @@ -236,7 +235,7 @@ private static function get_core_origin() { */ private function get_theme_origin( $theme_support_data = array() ) { $theme_json_data = self::get_from_file( locate_template( 'experimental-theme.json' ) ); - self::apply_theme_json_translations( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) ); + self::translate_presets( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) ); /* * We want the presets and settings declared in theme.json diff --git a/lib/experimental-i18n-theme.json b/lib/experimental-i18n-theme.json index 6d5db8d2f2128..4731a59df0e97 100644 --- a/lib/experimental-i18n-theme.json +++ b/lib/experimental-i18n-theme.json @@ -1,30 +1,32 @@ { - "typography": { - "fontSizes": [ - "name" - ], - "fontStyles": [ - "name" - ], - "fontWeights": [ - "name" - ], - "fontFamilies": [ - "name" - ], - "textTransforms": [ - "name" - ], - "textDecorations": [ - "name" - ] - }, - "color": { - "palette": [ - "name" - ], - "gradients": [ - "name" - ] + "settings": { + "typography": { + "fontSizes": [ + "name" + ], + "fontStyles": [ + "name" + ], + "fontWeights": [ + "name" + ], + "fontFamilies": [ + "name" + ], + "textTransforms": [ + "name" + ], + "textDecorations": [ + "name" + ] + }, + "color": { + "palette": [ + "name" + ], + "gradients": [ + "name" + ] + } } }