Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add wp i18n make-php command #363

Merged
merged 12 commits into from
Jan 30, 2024
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,32 @@ wp i18n make-mo <source> [<destination>]



### wp i18n make-php

Create PHP files from PO files.

~~~
wp i18n make-php <source> [<destination>]
~~~

**OPTIONS**

<source>
Path to an existing PO file or a directory containing multiple PO files.

[<destination>]
Path to the destination directory for the resulting PHP files. Defaults to the source directory.

**EXAMPLES**

# Create PHP files for all PO files in the current directory.
$ wp i18n make-php .

# Create a PHP file from a single PO file in a specific directory.
$ wp i18n make-php example-plugin-de_DE.po languages



### wp i18n update-po

Update PO files from a POT file.
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"i18n make-pot",
"i18n make-json",
"i18n make-mo",
"i18n make-php",
"i18n update-po"
]
},
Expand Down
167 changes: 167 additions & 0 deletions features/makephp.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
Feature: Generate PHP files from PO files

Background:
Given an empty directory

Scenario: Bail for invalid source directories
When I try `wp i18n make-php foo`
Then STDERR should contain:
"""
Error: Source file or directory does not exist!
"""
And the return code should be 1

Scenario: Uses source folder as destination by default
Given an empty foo-plugin directory
And a foo-plugin/foo-plugin-de_DE.po file:
"""
# Copyright (C) 2018 Foo Plugin
# This file is distributed under the same license as the Foo Plugin package.
msgid ""
msgstr ""
"Project-Id-Version: Foo Plugin\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/foo-plugin\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2018-05-02T22:06:24+00:00\n"
"PO-Revision-Date: 2018-05-02T22:06:24+00:00\n"
"X-Domain: foo-plugin\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: foo-plugin.js:15
msgid "Foo Plugin"
msgstr "Foo Plugin"
"""

When I run `wp i18n make-php foo-plugin`
Then STDOUT should contain:
"""
Success: Created 1 file.
"""
And the return code should be 0
And the foo-plugin/foo-plugin-de_DE.php file should exist

Scenario: Allows setting custom destination directory
Given an empty foo-plugin directory
And a foo-plugin/foo-plugin-de_DE.po file:
"""
# Copyright (C) 2018 Foo Plugin
# This file is distributed under the same license as the Foo Plugin package.
msgid ""
msgstr ""
"Project-Id-Version: Foo Plugin\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/foo-plugin\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2018-05-02T22:06:24+00:00\n"
"PO-Revision-Date: 2018-05-02T22:06:24+00:00\n"
"X-Domain: foo-plugin\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: foo-plugin.js:15
msgid "Foo Plugin"
msgstr "Foo Plugin"
"""

When I run `wp i18n make-php foo-plugin result`
Then STDOUT should contain:
"""
Success: Created 1 file.
"""
And the return code should be 0
And the result/foo-plugin-de_DE.php file should exist

Scenario: Does include headers
Given an empty foo-plugin directory
And a foo-plugin/foo-plugin-de_DE.po file:
"""
# Copyright (C) 2018 Foo Plugin
# This file is distributed under the same license as the Foo Plugin package.
msgid ""
msgstr ""
"Project-Id-Version: Foo Plugin\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/foo-plugin\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2018-05-02T22:06:24+00:00\n"
"PO-Revision-Date: 2018-05-02T22:06:24+00:00\n"
"X-Domain: foo-plugin\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: foo-plugin.js:15
msgid "Foo Plugin"
msgstr "Foo Plugin"
"""

When I run `wp i18n make-php foo-plugin`
Then STDOUT should contain:
"""
Success: Created 1 file.
"""
And the return code should be 0
And STDERR should be empty
And the foo-plugin/foo-plugin-de_DE.php file should contain:
"""
'language'=>'de_DE'
"""
And the foo-plugin/foo-plugin-de_DE.php file should contain:
"""
'domain'=>'foo-plugin'
"""
And the foo-plugin/foo-plugin-de_DE.php file should contain:
"""
'plural-forms'=>'nplurals=2; plural=(n != 1);'
"""
And the foo-plugin/foo-plugin-de_DE.php file should contain:
"""
'messages'=>[''=>['Foo Plugin'=>['Foo Plugin']]]
"""

Scenario: Does include translations
Given an empty foo-plugin directory
And a foo-plugin/foo-plugin-de_DE.po file:
"""
# Copyright (C) 2018 Foo Plugin
# This file is distributed under the same license as the Foo Plugin package.
msgid ""
msgstr ""
"Project-Id-Version: Foo Plugin\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/foo-plugin\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2018-05-02T22:06:24+00:00\n"
"PO-Revision-Date: 2018-05-02T22:06:24+00:00\n"
"X-Domain: foo-plugin\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: foo-plugin.js:15
msgid "Foo Plugin"
msgstr "Bar Plugin"
"""

When I run `wp i18n make-php foo-plugin`
Then STDOUT should contain:
"""
Success: Created 1 file.
"""
And the return code should be 0
And the foo-plugin/foo-plugin-de_DE.php file should contain:
"""
'messages'=>[''=>['Foo Plugin'=>['Bar Plugin']]]
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a test that verifies a valid PHP translation file is produced?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid as in syntax or as in translation gets loaded properly in WordPress?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking the latter but we could check both, I suppose.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably best done in a future PR because we don't have similar assertions for the other file formats, and the PHP format especially is not yet merged into core.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good 👍

2 changes: 2 additions & 0 deletions i18n-command.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@

WP_CLI::add_command( 'i18n make-mo', '\WP_CLI\I18n\MakeMoCommand' );

WP_CLI::add_command( 'i18n make-php', '\WP_CLI\I18n\MakePhpCommand' );

WP_CLI::add_command( 'i18n update-po', '\WP_CLI\I18n\UpdatePoCommand' );
88 changes: 88 additions & 0 deletions src/MakePhpCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

namespace WP_CLI\I18n;

use DirectoryIterator;
use Gettext\Translations;
use IteratorIterator;
use SplFileInfo;
use WP_CLI;
use WP_CLI\Utils;
use WP_CLI_Command;

class MakePhpCommand extends WP_CLI_Command {
/**
* Create PHP files from PO files.
*
* ## OPTIONS
*
* <source>
* : Path to an existing PO file or a directory containing multiple PO files.
*
* [<destination>]
* : Path to the destination directory for the resulting PHP files. Defaults to the source directory.
*
* ## EXAMPLES
*
* # Create PHP files for all PO files in the current directory.
* $ wp i18n make-php .
*
* # Create a PHP file from a single PO file in a specific directory.
* $ wp i18n make-php example-plugin-de_DE.po languages
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
*
* @when before_wp_load
*
* @throws WP_CLI\ExitException
*/
public function __invoke( $args, $assoc_args ) {
$source = realpath( $args[0] );
if ( ! $source || ( ! is_file( $source ) && ! is_dir( $source ) ) ) {
WP_CLI::error( 'Source file or directory does not exist!' );
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
}

$destination = is_file( $source ) ? dirname( $source ) : $source;
if ( isset( $args[1] ) ) {
$destination = $args[1];
}

// Two is_dir() checks in case of a race condition.
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
if ( ! is_dir( $destination )
&& ! mkdir( $destination, 0777, true )
&& ! is_dir( $destination )
) {
WP_CLI::error( 'Could not create destination directory!' );
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
}

if ( is_file( $source ) ) {
$files = [ new SplFileInfo( $source ) ];
} else {
$files = new IteratorIterator( new DirectoryIterator( $source ) );
}

$result_count = 0;
/** @var DirectoryIterator $file */
foreach ( $files as $file ) {
if ( 'po' !== $file->getExtension() ) {
continue;
}

if ( ! $file->isFile() || ! $file->isReadable() ) {
WP_CLI::warning( sprintf( 'Could not read file %s', $file->getFilename() ) );
continue;
}

$file_basename = basename( $file->getFilename(), '.po' );
$destination_file = "{$destination}/{$file_basename}.php";
swissspidy marked this conversation as resolved.
Show resolved Hide resolved

$translations = Translations::fromPoFile( $file->getPathname() );
if ( ! PhpArrayGenerator::toFile( $translations, $destination_file ) ) {
WP_CLI::warning( sprintf( 'Could not create file %s', $destination_file ) );
continue;
}

++$result_count;
}

WP_CLI::success( sprintf( 'Created %d %s.', $result_count, Utils\pluralize( 'file', $result_count ) ) );
swissspidy marked this conversation as resolved.
Show resolved Hide resolved
}
}
Loading