diff --git a/README.md b/README.md index 6f0633d..01c9a9e 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ A library for managing asset registration and enqueuing in WordPress. * [Support for wp-scripts](#support-for-wp-scripts) * [Default example](#default-example) * [Overriding the default asset file location](#overriding-the-default-asset-file-location) + * [Specifying translations for a JS asset](#specifying-translations-for-a-js-asset) * [Conditional enqueuing](#conditional-enqueuing) * [Firing a callback after enqueuing occurs](#firing-a-callback-after-enqueuing-occurs) * [Output JS data](#output-js-data) @@ -438,6 +439,27 @@ Asset::add( 'my-thing', 'js/something.js' ) Note: You can provide the JS file extension (`other-asset-directory/something.js`), the asset file extension (`other-asset-directory/something.asset.php`), or leave it off entirely (`other-asset-directory/something`). +#### Specifying translations for a JS asset + +You can specify translations for a JS asset like so: + +```php +// Using the default path of 'languages/'. +Asset::add( 'my-thing', 'js/something.js' ) + ->with_translations( $textdomain ) + ->register(); + +// Specifying a different path. +Asset::add( 'my-thing', 'js/something.js' ) + ->with_translations( $textdomain, 'relative/path/to/json/lang/files' ) + ->register(); + +// Using the 'default' textdomain and the default path of 'languages/'. +Asset::add( 'my-thing', 'js/something.js' ) + ->with_translations() + ->register(); +``` + ### Conditional enqueuing It is rare that you will want to enqueue an asset on every page load. Luckily, you can specify a condition for when an diff --git a/src/Assets/Asset.php b/src/Assets/Asset.php index eff3a46..4c5631a 100644 --- a/src/Assets/Asset.php +++ b/src/Assets/Asset.php @@ -217,6 +217,20 @@ class Asset { */ protected ?string $slug = null; + /** + * The asset textdomain. + * + * @var string + */ + protected string $textdomain = ''; + + /** + * Translation path. + * + * @var string + */ + protected string $translations_path = ''; + /** * The asset type. * @@ -947,6 +961,26 @@ public function get_slug(): string { return $this->slug; } + /** + * Get the asset textdomain. + * + * @return string + */ + public function get_textdomain(): string { + return $this->textdomain; + } + + /** + * Get the asset translation path. + * + * @since 1.3.1 + * + * @return string + */ + public function get_translation_path(): string { + return Config::get_path() . $this->translations_path; + } + /** * Get the asset style data. * @@ -1664,6 +1698,19 @@ public function set_priority( int $priority ) { return $this; } + /** + * Set the translation path. Alias of with_translations(). + * + * @since 1.3.1 + * + * @param string $textdomain The textdomain of the asset. + * @param string $path Relative path to the translations directory. + * @return self + */ + public function set_translations( string $textdomain, string $path ): self { + return $this->with_translations( $textdomain, $path ); + } + /** * Set the asset type. * @@ -1701,4 +1748,26 @@ public function use_asset_file( bool $use_asset_file = true ): self { $this->use_asset_file = $use_asset_file; return $this; } + + /** + * Set the translation path. + * + * @since 1.3.1 + * + * @param string $textdomain The textdomain of the asset. + * @param string $path Relative path to the translations directory. + * + * @throws InvalidArgumentException If the asset is not a JS asset. + * + * @return self + */ + public function with_translations( string $textdomain = 'default', string $path = 'languages' ): self { + if ( ! $this->is_js() ) { + throw new InvalidArgumentException( 'Translations may only be set for JS assets.' ); + } + + $this->translations_path = $path; + $this->textdomain = $textdomain; + return $this; + } } diff --git a/src/Assets/Assets.php b/src/Assets/Assets.php index feb8f04..e9f719a 100755 --- a/src/Assets/Assets.php +++ b/src/Assets/Assets.php @@ -713,37 +713,46 @@ public function register_in_wp( $assets = null ) { continue; } + $asset_slug = $asset->get_slug(); + if ( 'js' === $asset->get_type() ) { // Script is already registered. - if ( wp_script_is( $asset->get_slug(), 'registered' ) ) { + if ( wp_script_is( $asset_slug, 'registered' ) ) { continue; } - wp_register_script( $asset->get_slug(), $asset->get_url(), $asset->get_dependencies(), $asset->get_version(), $asset->is_in_footer() ); + wp_register_script( $asset_slug, $asset->get_url(), $asset->get_dependencies(), $asset->get_version(), $asset->is_in_footer() ); // Register that this asset is actually registered on the WP methods. // @phpstan-ignore-next-line - if ( wp_script_is( $asset->get_slug(), 'registered' ) ) { + if ( wp_script_is( $asset_slug, 'registered' ) ) { $asset->set_as_registered(); } + + if ( + ! empty( $asset->get_translation_path() ) + && ! empty( $asset->get_textdomain() ) + ) { + wp_set_script_translations( $asset_slug, $asset->get_textdomain(), $asset->get_translation_path() ); + } } else { // Style is already registered. - if ( wp_style_is( $asset->get_slug(), 'registered' ) ) { + if ( wp_style_is( $asset_slug, 'registered' ) ) { continue; } - wp_register_style( $asset->get_slug(), $asset->get_url(), $asset->get_dependencies(), $asset->get_version(), $asset->get_media() ); + wp_register_style( $asset_slug, $asset->get_url(), $asset->get_dependencies(), $asset->get_version(), $asset->get_media() ); // Register that this asset is actually registered on the WP methods. // @phpstan-ignore-next-line - if ( wp_style_is( $asset->get_slug(), 'registered' ) ) { + if ( wp_style_is( $asset_slug, 'registered' ) ) { $asset->set_as_registered(); } $style_data = $asset->get_style_data(); if ( $style_data ) { foreach ( $style_data as $datum_key => $datum_value ) { - wp_style_add_data( $asset->get_slug(), $datum_key, $datum_value ); + wp_style_add_data( $asset_slug, $datum_key, $datum_value ); } } } diff --git a/tests/_data/lang/fake1-en_US-fake1.json b/tests/_data/lang/fake1-en_US-fake1.json new file mode 100644 index 0000000..28265bd --- /dev/null +++ b/tests/_data/lang/fake1-en_US-fake1.json @@ -0,0 +1,8 @@ +{ + "fake1.php": { + "Fake plugin": "" + }, + "src/fake1.php:82": { + "Page title": "Fake title" + } +} \ No newline at end of file diff --git a/tests/acceptance/EnqueueJSCest.php b/tests/acceptance/EnqueueJSCest.php index d018b99..f5ffc45 100644 --- a/tests/acceptance/EnqueueJSCest.php +++ b/tests/acceptance/EnqueueJSCest.php @@ -17,7 +17,6 @@ public function it_should_register_and_enqueue_js( AcceptanceTester $I ) { $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( 'script', [ 'src' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/js/fake.js?ver=1.0.0' ] ); } @@ -35,7 +34,6 @@ public function it_should_enqueue_from_alternate_path( AcceptanceTester $I ) { $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( 'script', [ 'src' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/other-asset-root/js/fake-alt.js?ver=1.0.0' ] ); } @@ -53,7 +51,6 @@ public function it_should_enqueue_from_alternate_path_with_js_in_path( Acceptanc $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( 'script', [ 'src' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/other-asset-root/js/fake-alt.js?ver=1.0.0' ] ); } @@ -91,7 +88,6 @@ public function it_should_enqueue_min( AcceptanceTester $I ) { $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( 'script', [ 'src' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/js/fake-with-min.min.js?ver=1.0.0' ] ); } @@ -109,7 +105,6 @@ public function it_should_enqueue_min_from_different_dir( AcceptanceTester $I ) $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( 'script', [ 'src' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/minified/js/fake.min.js?ver=1.0.0' ] ); } @@ -127,7 +122,6 @@ public function it_should_not_enqueue_if_dependencies_missing( AcceptanceTester $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->dontSeeElement( 'script', [ 'src' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/js/fake.js?ver=1.0.0' ] ); } @@ -144,7 +138,6 @@ public function it_should_enqueue_with_custom_version( AcceptanceTester $I ) { $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( 'script', [ 'src' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/js/fake.js?ver=2.0.0' ] ); } @@ -162,7 +155,6 @@ public function it_should_enqueue_when_missing_extension( AcceptanceTester $I ) $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( 'script', [ 'src' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/js/fake-js-with-no-extension?ver=1.0.0' ] ); } @@ -179,7 +171,6 @@ public function it_should_not_enqueue_if_action_is_not_fired( AcceptanceTester $ $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->dontSeeElement( 'script', [ 'src' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/js/fake.js?ver=1.0.0' ] ); } @@ -197,7 +188,6 @@ public function it_should_be_deferred( AcceptanceTester $I ) { $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( '#fake-js-js[defer]' ); } @@ -215,7 +205,6 @@ public function it_should_be_async( AcceptanceTester $I ) { $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( '#fake-js-js[async]' ); } @@ -233,7 +222,6 @@ public function it_should_be_a_module( AcceptanceTester $I ) { $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( '#fake-js-js[type=module]' ); } @@ -260,7 +248,6 @@ public function it_should_localize( AcceptanceTester $I ) { $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( '#fake-js-js-extra' ); $contents = $I->grabTextFrom( '#fake-js-js-extra' ); @@ -280,7 +267,6 @@ public function it_should_enqueue_and_use_asset_file( AcceptanceTester $I ) { $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( 'script', [ 'src' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/js/fake4.js?ver=12345' ] ); } @@ -298,9 +284,26 @@ public function it_should_enqueue_css_when_using_register_with_css( AcceptanceTe $I->haveMuPlugin( 'enqueue.php', $code ); - $I->amOnPage( '/' ); $I->seeElement( 'link', [ 'href' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/build/something.css?ver=1.0.0' ] ); $I->seeElement( 'script', [ 'src' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/build/something.js?ver=12345' ] ); } -} + + public function it_should_register_translations( AcceptanceTester $I ) { + $code = file_get_contents( codecept_data_dir( 'enqueue-template.php' ) ); + $code .= <<enqueue_on( 'wp_enqueue_scripts' ) + ->with_translations( 'fake1', 'tests/_data/lang' ) + ->register(); + }, 100 ); + PHP; + + $I->haveMuPlugin( 'enqueue.php', $code ); + + $I->amOnPage( '/' ); + $I->seeElement( '#fake1-js-translations' ); + } + +} \ No newline at end of file diff --git a/tests/wpunit/AssetsTest.php b/tests/wpunit/AssetsTest.php index 45d2200..56ddcbe 100644 --- a/tests/wpunit/AssetsTest.php +++ b/tests/wpunit/AssetsTest.php @@ -771,6 +771,32 @@ public function it_should_throw_errors_when_cloning_css_to_css() { ->clone_to( 'css' ); } + /** + * @test + */ + public function it_should_register_translations() { + $slug = 'something-' . uniqid() . '-js'; + + $asset = Asset::add( $slug, 'something.js' ) + ->set_translations( 'fake1', 'tests/_data/lang' ) + ->register(); + + $this->assertEquals( 'fake1', $asset->get_textdomain() ); + $this->assertEquals( dirname( dirname( __DIR__ ) ) . '/tests/_data/lang', $asset->get_translation_path() ); + } + + /** + * @test + */ + public function it_should_throw_exception_when_registering_translations_for_css() { + $this->expectException( \InvalidArgumentException::class ); + $slug = 'something-' . uniqid() . '-css'; + + Asset::add( $slug, 'something.css' ) + ->set_translations( 'fake1', 'tests/_data/lang' ) + ->register(); + } + /** * Evaluates if a script and style have been registered. */