Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.45% covered (success)
95.45%
21 / 22
100.00% covered (success)
100.00%
1 / 1
CRAP
n/a
0 / 0
wpcom_wp_build_script_translations
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
12
1<?php
2/**
3 * Translations for mu-wpcom's wp-build pages.
4 *
5 * @package automattic/jetpack-mu-wpcom
6 */
7
8if ( ! function_exists( 'wpcom_wp_build_script_translations' ) ) {
9    /**
10     * Inline JS that installs the translation catalogs of a page's wp-build bundles into `wp.i18n`.
11     *
12     * Core's `load_script_textdomain()` on a registered, never-enqueued handle per bundle picks up the
13     * platform filters that point this package's catalogs at `languages/mu-plugins/`, which no URL
14     * serves for the client-side loader the other wp-build dashboards use.
15     *
16     * @param string          $manifest_file Path to the build's `i18n-manifest.json` (from `stamp-textdomains`).
17     * @param string          $build_url     URL of the build directory the bundles are served from.
18     * @param string|string[] $routes        The wp-build route(s) whose bundles to cover, besides the shared modules and scripts.
19     * @param string          $domain        The text domain.
20     * @return string|null The inline script, or null when no bundle has a catalog for this locale.
21     */
22    function wpcom_wp_build_script_translations( $manifest_file, $build_url, $routes, $domain = 'jetpack-mu-wpcom' ) {
23        if ( ! is_readable( $manifest_file ) ) {
24            return null;
25        }
26        $manifest = json_decode( (string) file_get_contents( $manifest_file ), true ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Local build artifact.
27        $bundles  = is_array( $manifest ) && isset( $manifest['bundles'] ) && is_array( $manifest['bundles'] ) ? $manifest['bundles'] : array();
28
29        $pattern = implode( '|', array_map( static fn( $name ) => preg_quote( $name, '#' ), (array) $routes ) );
30        $scripts = array();
31        foreach ( $bundles as $index => $bundle ) {
32            // The manifest lists paths under the build directory's own name, e.g. `build/routes/x/content.js`.
33            if ( ! is_string( $bundle ) || ! preg_match( '#^[^/]+/(routes/(?:' . $pattern . ')|scripts|modules)/#', $bundle ) ) {
34                continue;
35            }
36            $handle = 'wpcom-wp-build-i18n-' . $index;
37            wp_register_script( $handle, trailingslashit( $build_url ) . substr( $bundle, strpos( $bundle, '/' ) + 1 ), array(), false, false ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NoExplicitVersion -- Never printed; only registered so core can locate its catalog.
38            $json = load_script_textdomain( $handle, $domain );
39            wp_deregister_script( $handle );
40            if ( ! $json ) {
41                continue;
42            }
43
44            $data     = json_decode( $json, true );
45            $messages = $data['locale_data'][ $domain ] ?? $data['locale_data']['messages'] ?? null;
46            if ( ! is_array( $messages ) || array() === $messages ) {
47                continue;
48            }
49            // HEX_TAG keeps a literal "</script>" in a translation from closing the inline script tag.
50            $scripts[] = 'wp.i18n.setLocaleData( ' . wp_json_encode( $messages, JSON_HEX_TAG | JSON_HEX_AMP ) . ', ' . wp_json_encode( $domain, JSON_HEX_TAG | JSON_HEX_AMP ) . ' );';
51        }
52
53        return $scripts ? implode( "\n", $scripts ) : null;
54    }
55}