Skip to content
Snippets Groups Projects
Commit 3fda2274 authored by Bjørn Johansen's avatar Bjørn Johansen
Browse files

Version 0.1.0

parent c0f0f49e
No related branches found
No related tags found
No related merge requests found
# wplang
Composer plugin to download translation files from wordpress.org
# bjornjohansen/wplang
Composer plugin to download translation files for WordPress core, plugins and themes from wordpress.org.
## Installation
First run:
```
composer require bjornjohansen/wplang
```
Then you’ll have to edit your `composer.json` file. You need to add the following section:
```
"extra": {
"wordpress-languages": [ "en_GB", "nb_NO", "sv_SE" ],
"wordpress-language-dir": "wp-content/languages"
}
```
You should propbably want to customize these values to suit your needs.
Finally run:
```
composer update
```
Now Composer will try to pull down translations for your packages from wordpress.org every time you install or update a package.
## Credits
This package Started as a fork of Angry Creative’s [Composer Auto Language Updates](https://github.com/Angrycreative/composer-plugin-language-update), but has since been rewritten. It is not compatible with the original package at all, but this package would probably not have existed with the first. There are probably some code in this package that the original author will still recognize.
{
"name": "bjornjohansen/wplang",
"description": "Composer plugin to download translation files from wordpress.org",
"version": "0.1.0",
"license": "GPL-2.0+",
"type": "composer-plugin",
"authors": [
{
"name": "Bjørn Johansen",
"email": "post@bjornjohansen.no"
}
],
"require": {
"composer-plugin-api": "^1.0"
},
"autoload": {
"psr-4": {
"BJ\\Wplang\\": "src"
}
},
"extra": {
"class": "BJ\\Wplang\\Wplang"
}
}
\ No newline at end of file
<?php
/**
* @package BJ\WPlang
*/
namespace BJ\WPlang;
/**
* Class Translatable
*
* @package BJ\WPlang
*/
class Translatable {
/**
* The package type: 'plugin', 'theme' or 'core'.
*
* @var string
*/
protected $type;
/**
* The plugin/theme slug, E.g. 'query-monitor'. In case of core, this is 'wordpress'.
*
* @var string
*/
protected $slug;
/**
* The package version.
*
* @var float|string
*/
protected $version;
/**
* Array of the languages we are using.
*
* @var array
*/
protected $languages = [];
/**
* Full path to the language files target directory.
*
* @var string
*/
protected $wpLanguageDir;
/**
* Array of translation packs available in our languages.
*
* @var array
*/
protected $translations = [];
/**
* Constructor.
*
* @param string $type The package type: 'plugin', 'theme' or 'core'.
* @param string $slug The plugin/theme slug, E.g. 'query-monitor'. In case of core, this is 'wordpress'.
* @param string $version The package version.
* @param string $languages Array of the languages we are using.
* @param string $wpLanguageDir Full path to the language files target directory.
*/
public function __construct( $type, $slug, $version, $languages, $wpLanguageDir ) {
$this->type = $type;
$this->slug = $slug;
$this->version = $version;
$this->languages = $languages;
$this->wpLanguageDir = $wpLanguageDir;
try {
$this->translations = $this->getAvailableTranslations();
} catch ( \Exception $e ) {
throw new \Exception( $e->getMessage() );
}
}
/**
* Get a list of available translations in our languages from the API.
*
* @throws \Exception
* @return array
*/
protected function getAvailableTranslations() : array {
switch ( $this->type ) {
case 'plugin':
$url = sprintf( 'https://api.wordpress.org/translations/plugins/1.0/?slug=%s&version=%s', $this->slug, $this->version );
break;
case 'theme':
$url = sprintf( 'https://api.wordpress.org/translations/themes/1.0/?slug=%s&version=%s', $this->slug, $this->version );
break;
case 'core':
$url = sprintf( 'https://api.wordpress.org/translations/core/1.0/?version=%s', $this->version );
break;
default:
throw new \Exception( 'Unknown package type' );
}
$body = file_get_contents( $url );
$res = json_decode( $body );
if ( ! isset( $res->translations ) || empty( $res->translations ) ) {
throw new \Exception( 'No translations found' );
}
$translations = [];
foreach ( $res->translations as $translation ) {
if ( in_array( $translation->language, $this->languages, true ) ) {
$translations[ $translation->language ][] = $translation;
}
}
return $translations;
}
/**
* Fetch the translations to our languages for our package.
*
* @return array
*/
public function fetch() : array {
$results = [];
foreach ( $this->languages as $language ) {
$result = $this->installTranslation( $this->translations[ $language ][0]->package );
if ( $result ) {
$results[] = $language;
}
}
return $results;
}
/**
* Get the destination path for type type of object.
*
* This will also create the directory if if doesn't exist.
*
* @throws \Exception
* @return string path to the destination directory.
*/
public function getDestPath() : string {
$destPath = $this->wpLanguageDir;
switch ( $this->type ) {
case 'plugin':
$destPath .= '/plugins';
break;
case 'theme':
$destPath .= '/themes';
break;
}
if ( ! is_dir( $destPath ) ) {
$result = mkdir( $destPath, 0775, true );
if ( ! $result ) {
throw new \Exception( 'Failed to create directory at: ' . $destPath );
}
}
return $destPath;
}
/**
* Unpack the downloaded translation ZIP file in the destination directory.
*
* @param string $tmpZipFileName Path to the translation ZIP file.
* @return bool Whether the operation was successful or not.
*
* @throws \Exception
*/
public function unpackTranslation( $tmpZipFileName ) : bool {
$result = false;
$destPath = $this->getDestPath();
$zip = new \ZipArchive();
if ( true === $zip->open( $tmpZipFileName ) ) {
for ( $i = 0; $i < $zip->numFiles; $i++ ) {
$ok = $zip->extractTo( $destPath, [ $zip->getNameIndex( $i ) ] );
if ( false === $ok ) {
throw new \Exception( 'There was an error moving the translation to the destination directory' );
}
}
$zip->close();
$result = true;
} else {
throw new \Exception( 'The was an error unzipping the translation files' );
}
return $result;
}
/**
* Download and extract the translation ZIP file in our destination directory.
*
* @param string $packageUrl The URL to the translation package ZIP file.
* @return bool Whether the operation was successful or not.
*/
public function installTranslation( $packageUrl ) : bool {
$result = false;
try {
$tmpZipFileName = sys_get_temp_dir() . '/' . $this->type . '-' . $this->slug . '-' . $this->version . '-' . basename( $packageUrl );
$result = copy( $packageUrl, $tmpZipFileName );
if ( $result ) {
$result = $this->unpackTranslation( $tmpZipFileName );
unlink( $tmpZipFileName );
}
} catch ( \Exception $e ) {
}
return $result;
}
}
<?php
namespace BJ\Wplang;
use Composer\Composer;
use Composer\Script\Event;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
use Composer\Installer\PackageEvent;
use Composer\Package\PackageInterface;
class Wplang implements PluginInterface, EventSubscriberInterface {
/**
* Array of the languages we are using.
*
* @var array
*/
protected $languages = [];
/**
* Full path to the language files target directory.
*
* @var string
*/
protected $wpLanguageDir = '';
/**
* @var Composer
*/
protected $composer;
/**
* @var IOInterface
*/
protected $io;
/**
* Composer plugin activation.
*/
public function activate( Composer $composer, IOInterface $io ) {
$this->composer = $composer;
$this->io = $io;
$extra = $this->composer->getPackage()->getExtra();
if ( ! empty( $extra['wordpress-languages'] ) ) {
$this->languages = $extra['wordpress-languages'];
}
if ( ! empty( $extra['wordpress-language-dir'] ) ) {
$this->wpLanguageDir = dirname( dirname( dirname( dirname( __DIR__ ) ) ) ) . '/' . $extra['wordpress-language-dir'];
}
}
/**
* Subscribe to Composer events.
*
* @return array The events and callbacks.
*/
public static function getSubscribedEvents() {
return [
'post-package-install' => [
[ 'onPackageAction', 0 ],
],
'post-package-update' => [
[ 'onPackageAction', 0 ],
],
];
}
/**
* Our callback for the post-package-install|update events.
*
* @param PackageEvent $event The package event object.
*/
public function onPackageAction( PackageEvent $event ) {
$package = $event->getOperation()->getPackage();
$this->getTranslations( $package );
}
/**
* Get translations for a package, where applicable.
*
* @param PackageInterface $package
*/
protected function getTranslations( PackageInterface $package ) {
try {
$t = new \stdClass();
list( $provider, $name ) = explode( '/', $package->getName(), 2 );
switch ( $package->getType() ) {
case 'wordpress-plugin':
$t = new Translatable( 'plugin', $name, $package->getVersion(), $this->languages, $this->wpLanguageDir );
break;
case 'wordpress-theme':
$t = new Translatable( 'theme', $name, $package->getVersion(), $this->languages, $this->wpLanguageDir );
break;
case 'package':
if ( 'johnpbloch' === $provider && 'wordpress' === $name ) {
$t = new Translatable( 'core', $name, $package->getVersion(), $this->languages, $this->wpLanguageDir );
}
break;
default:
break;
}
if ( is_a( $t, __NAMESPACE__ . '\Translatable' ) ) {
$results = $t->fetch();
if ( empty( $results ) ) {
$this->io->write( ' - ' . sprintf( 'No translations updated for %s', $package->getName() ) );
} else {
foreach ( $results as $result ) {
$this->io->write( ' - ' . sprintf( 'Updated translation to %1$s for %2$s', $result, $package->getName() ) );
}
}
}
} catch ( \Exception $e ) {
$this->io->writeError( $e->getMessage() );
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment