Skip to content

Instantly share code, notes, and snippets.

@aiphee
Created October 29, 2019 22:46
Show Gist options
  • Save aiphee/b48790c6a07686a4c37aacf3754af78e to your computer and use it in GitHub Desktop.
Save aiphee/b48790c6a07686a4c37aacf3754af78e to your computer and use it in GitHub Desktop.
Lokalise.com for CakePhp 3.6 using official API
<?php
namespace App\Shell;
use Cake\Console\Shell;
use Cake\Core\App;
use Cake\Core\Configure;
use Cake\Network\Http\Client;
use Cake\Utility\Hash;
use ZipArchive;
class LokaliseShell extends Shell {
/**
* {@inheritDocs}
*
*/
public function getOptionParser()
{
return parent::getOptionParser()
->addSubCommand('push', [
'help' => 'Pushes the translation template files (.pot) to lokalise and merges with existing translations upstream',
'parser' => [
'options' => [
'locales' => [
'short' => 'l',
'help' => 'A comma separated list of all the locales that should be updated with the template files'
],
'cleanup' => [
'help' => 'Remove old keys - compare src/Locale from server fst',
'boolean' => true,
'default' => false
],
'replace' => [
'help' => 'Replace translations from code to lokalise, backup fst',
'boolean' => true,
'default' => false
],
'tags' => [
'help' => 'A comma separated list of words that should be used as tags for the uploaded files'
],
'hidden' => [
'help' => 'Add this flag if you wish to make the new translation strings hidden in the interface',
'boolean' => true,
'default' => false
]
]
]
])
->addSubcommand('pull', [
'help' => 'Dowloads all translation strings from lokalise and place them in the right folders for Cake to pick up',
'parser' => [
'options' => [
'locales' => [
'short' => 'l',
'help' => 'A comma separated list of all the locales that should be downloaded. By default all locales are downloaded'
],
]
]
]);
}
/**
* Downloads all translations and upakcs them into the Locale folder
*
* @return mixed
*/
public function pull()
{
$project = Configure::read('Lokalise.project');
$token = Configure::read('Lokalise.api_key');
$client = new \Lokalise\LokaliseApiClient($token);
$locales = array_filter(array_map('trim', explode(',', Hash::get($this->params, 'locales', ''))));
$response = $client->files->download($project, [
'format' => 'po',
'filter_langs' => $locales,
'original_filenames' => true,
'export_sort' => 'first_added'
]);
$this->processFile($response->body['bundle_url']);
$this->out('<success>Replaced translation files. You can now commit the changes</success>');
}
/**
* Download file by link provided by API response
*
* @param string $path Path to zip file
* @return mixed
*/
protected function processFile($path)
{
$this->verbose("Starting download of <info>$path</info>");
$date = gmdate('Y-m-d.H.i.s');
$destination = sys_get_temp_dir() . DS;
$filename = $destination . "translations_$date.zip";
$client = new Client();
$response = $client->get($path);
if ($response->getStatusCode() !== 200) {
return $this->abort('Could not download translations file');
}
file_put_contents($filename, $response->body());
$this->out('<success>Successfully downloaded bundle file</success>');
$zip = new ZipArchive;
$zip->open($filename);
for ($i = 0; $i < $zip->numFiles; $i++) {
$stat = $zip->statIndex($i);
if (preg_match('/\.pot$/', $stat['name'])) {
$zip->renameIndex($i, preg_replace('/\.pot$/', '.po', $stat['name']));
}
}
$zip->close();
$zip->open($filename);
$zip->extractTo(App::path('Locale')[0]);
$this->verbose('Successfully extracted bundle file');
unlink($filename);
$this->verbose('Deleted bundle file');
}
/**
* Pushs all pot files to lokalise
*
* @return void
*/
public function push()
{
$paths = App::path('Locale');
$project = Configure::read('Lokalise.project');
$token = Configure::read('Lokalise.api_key');
$client = new \Lokalise\LokaliseApiClient($token);
$locales = array_filter(array_map('trim', explode(',', Hash::get($this->params, 'locales', ''))));
$tags = array_filter(array_map('trim', explode(',', Hash::get($this->params, 'tags', ''))));
if (empty($locales)) {
$locales = [Configure::read('App.defaultLocale')];
}
$progress = $this->helper('Progress');
$this->clear();
$this->out('Starting the file upload');
if ($this->params['cleanup']) {
$this->verbose('Deleting old');
}
if ($this->params['replace']) {
$this->verbose('Replacing changed from old');
}
collection($paths)
->map(function ($path) {
return glob($path . '*.pot');
})
->unfold()
->unfold(function ($file) use ($locales) {
foreach ($locales as $l) {
yield $file => $l;
}
})
->through(function ($all) use ($progress) {
$total = iterator_count($all);
$progress->init(['total' => $total]);
return $all;
})
->each(function ($locale, $file) use ($client, $project, $token, $tags, $progress) {
// We need to observe the API throttling from lokalise
sleep(5);
$this->verbose(sprintf('Uploading file <info>%s</info> for locale <info>%s</info>', $file, $locale));
// It is easier for all if tje files terminate with .po
$dest = str_replace('.pot', '.po', sys_get_temp_dir() . DS . basename($file));
file_put_contents($dest, file_get_contents($file));
$body = [
'data' => base64_encode(file_get_contents($dest)),
'filename' => str_replace('.pot', '.po', basename($file)),
'lang_iso' => $locale,
'replace_modified' => true,
'distinguish_by_file' => true,
'hidden' => (int) $this->params['hidden'],
'tags' => $tags
];
if ($this->params['cleanup']) {
$body['cleanup_mode'] = true;
}
if ($this->params['replace']) {
$body['replace_modified'] = true;
}
$response = $client->files->upload($project, $body);
$progress->increment(1);
$progress->draw();
});
$this->clear();
$this->nl(2);
$this->out('<success>All Done.</success>');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment