Refactor translation cli commands and implement po-file compilation

refs #5533
This commit is contained in:
Johannes Meyer 2014-01-30 10:51:10 +01:00
parent bd34669357
commit 005c52bb4a
7 changed files with 689 additions and 273 deletions

View File

@ -1,43 +0,0 @@
<?php
namespace Icinga\Clicommands;
use Icinga\Cli\Command;
use Icinga\Application\TranslationHelper;
/**
* Translation command
*
* This command provides different utilities useful for translators. It
* allows to add new languages and also to refresh existing translations. All
* functionality is available for core components and for modules.
*
* This is another parapragh.
*/
class TranslationCommand extends Command
{
protected $translator;
public function init()
{
$this->translator = new TranslationHelper(
$this->application,
$this->params->get('locale', 'C'),
$this->params->get('module', 'monitoring') // bullshit. NULL?
);
}
/**
* Refresh translation catalogs
*
* Extracts all translatable strings for a given module (or core) from the
* Icingaweb source code, adds those to the existing catalog for the given
* locale and marks obsolete translations.
*
* Usage: icingaweb translation refresh --module <modulename> --locale <lc_LC>
*/
public function refreshAction()
{
$this->translator->createTemporaryFileList()->extractTexts();
}
}

View File

@ -1,56 +0,0 @@
#!/usr/bin/php
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*
*/
// {{{ICINGA_LICENSE_HEADER}}}
require_once dirname(__FILE__) . '/../library/Icinga/Application/Cli.php';
use Icinga\Application\Cli;
use Icinga\Application\TranslationHelper;
$bootstrap = Cli::start();
if (count($argv) < 2) {
die(sprintf(
"Usage: ./%s lc_LC [module]\n",
basename($argv[0])
));
}
$locale = $argv[1];
if (array_key_exists(2, $argv)) {
$module = $argv[2];
} else {
$module = null;
}
$translation = new TranslationHelper($bootstrap, $locale, $module);
$translation->createTemporaryFileList()
->extractTexts();

View File

@ -1,174 +0,0 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Application;
class TranslationHelper
{
protected $basedir;
protected $moduledir;
protected $tmpfile;
protected $potfile;
protected $locale;
protected $module;
public function __construct(ApplicationBootstrap $bootstrap, $locale, $module = null)
{
$this->moduledir = $bootstrap->getModuleDir();
if ($module) {
$this->basedir = $bootstrap->getModuleDir($module) . '/application';
} else {
$this->basedir = $bootstrap->getApplicationDir();
}
$this->locale = $locale;
$this->module = $module;
$this->targetfile = $this->basedir
. '/locale/'
. $this->locale
. '/LC_MESSAGES/'
. ($module ? $module : 'icinga')
. '.po';
$target_dir = dirname($this->targetfile);
if (! is_dir($target_dir)) {
mkdir($target_dir, 0755, true);
}
}
public function __destruct()
{
if ($this->tmpfile !== null) {
unlink($this->tmpfile);
}
if ($this->potfile !== null) {
unlink($this->potfile);
}
}
public function extractTexts()
{
$tmpdir = sys_get_temp_dir();
$this->potfile = tempnam($tmpdir, 'IcingaPot_');
$cmd = '/usr/bin/xgettext'
. ' --language=PHP'
. ' --from-code=iso-8859-15'
. ' --keyword='
. ($this->module ? '_mt:2' : '_t')
. ' --sort-output'
. ' --force-po'
. ' --package-name=Icinga'
. ' --package-version=0.1'
. ' --copyright-holder="Icinga Team"'
. ' --msgid-bugs-address="dev@icinga.org"'
. ' --files-from=' . $this->tmpfile
. ' --output=' . $this->potfile
;
`$cmd`;
$this->fixPotfile();
$this->mergeOldTranslations();
return $this;
}
protected function fixPotfile()
{
$content = file_get_contents($this->potfile);
$fh = fopen($this->potfile, 'w');
foreach (preg_split('~\n~', $content) as $line) {
// if (preg_match('~^"Language:~', $line)) continue;
if (preg_match('~^"Content-Type:~', $line)) {
$line = '"Content-Type: text/plain; charset=utf-8\n"';
}
fwrite($fh, $line . "\n");
}
fclose($fh);
}
protected function mergeOldTranslations()
{
if (is_file($this->targetfile)) {
$cmd = sprintf(
'/usr/bin/msgmerge %s %s -o %s 2>&1',
$this->targetfile,
$this->potfile,
$this->targetfile . '.new'
);
`$cmd`;
rename($this->targetfile . '.new', $this->targetfile);
} else {
file_put_contents($this->targetfile, file_get_contents($this->potfile));
}
}
public function createTemporaryFileList()
{
$tmpdir = sys_get_temp_dir();
$this->tmpfile = tempnam($tmpdir, 'IcingaTranslation_');
$tmp_fh = fopen($this->tmpfile, 'w');
if (! $tmp_fh) {
throw new \Exception('Unable to create ' . $this->tmpfile);
}
if ($this->module) {
$blacklist = array();
} else {
$blacklist = array(
$this->moduledir
);
}
$this->getSourceFileNames($this->basedir, $tmp_fh, $blacklist);
$this->getSourceFileNames(ICINGA_LIBDIR, $tmp_fh, $blacklist);
fclose($tmp_fh);
return $this;
}
protected function getSourceFileNames($dir, & $fh, $blacklist = array())
{
$dh = opendir($dir);
if (! $dh) {
throw new \Exception("Unable to read files from $dir");
}
$subdirs = array();
while ($filename = readdir($dh)) {
if ($filename[0] === '.') {
continue;
}
$fullname = $dir . '/' . $filename;
if (preg_match('~\.(?:php|phtml)$~', $filename)) {
fwrite($fh, "$fullname\n");
} elseif (is_dir($fullname)) {
if (in_array($fullname, $blacklist)) {
continue;
}
$subdirs[] = $fullname;
}
}
closedir($dh);
foreach ($subdirs as $dir) {
$this->getSourceFileNames($dir, $fh, $blacklist);
}
}
}

View File

@ -0,0 +1,93 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2014 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2014 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Translation\Clicommands;
use Icinga\Module\Translation\Cli\TranslationCommand;
use Icinga\Module\Translation\Util\GettextTranslationHelper;
/**
* Translation compiler
*
* This command will compile the PO-file of a domain. The actions below allow
* you to select a particular domain for which the PO-file should be compiled.
*
* Domains are the global one 'icinga' and all available and enabled modules
* identified by their name.
*
* Once a PO-file is compiled it's content is used by Icinga Web 2 to display
* messages in the configured language.
*/
class CompileCommand extends TranslationCommand
{
/**
* Compile the global domain
*
* This will compile the PO-file of the global 'icinga' domain.
*
* USAGE:
*
* icingaweb translation compile icinga <locale>
*
* EXAMPLES:
*
* icingaweb translation compile icinga de_DE
* icingaweb translation compile icinga fr_FR
*/
public function icingaAction()
{
$locale = $this->validateLocaleCode($this->params->shift());
$helper = new GettextTranslationHelper($this->app, $locale);
$helper->compileIcingaTranslation();
}
/**
* Compile a module domain
*
* This will compile the PO-file of the given module domain.
*
* USAGE:
*
* icingaweb translation compile <module> <locale>
*
* EXAMPLES:
*
* icingaweb translation compile monitoring de_DE
* icingaweb trnslations compile monitoring de_DE
*/
public function moduleAction()
{
$module = $this->validateModuleName($this->params->shift());
$locale = $this->validateLocaleCode($this->params->shift());
$helper = new GettextTranslationHelper($this->app, $locale);
$helper->compileModuleTranslation($module);
}
}

View File

@ -0,0 +1,93 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2014 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2014 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Translation\Clicommands;
use Icinga\Module\Translation\Cli\TranslationCommand;
use Icinga\Module\Translation\Util\GettextTranslationHelper;
/**
* Translation updater
*
* This command will create a new or update any existing PO-file of a domain. The
* actions below allow to select a particular domain for whom to touch the PO-file.
*
* Domains are the global one 'icinga' and all available and enabled modules
* identified by their name.
*
* Once a PO-file has been created/updated one can open it with a editor for
* PO-files and start with the actual translation.
*/
class RefreshCommand extends TranslationCommand
{
/**
* Touch the global domain
*
* This will create/update the PO-file of the global 'icinga' domain.
*
* USAGE:
*
* icingaweb translation refresh icinga <locale>
*
* EXAMPLES:
*
* icingaweb translation refresh icinga de_DE
* icingaweb translation refresh icinga fr_FR
*/
public function icingaAction()
{
$locale = $this->validateLocaleCode($this->params->shift());
$helper = new GettextTranslationHelper($this->app, $locale);
$helper->updateIcingaTranslations();
}
/**
* Touch a module domain
*
* This will create/update the PO-file of the given module domain.
*
* USAGE:
*
* icingaweb translation refresh module <module> <locale>
*
* EXAMPLES:
*
* icingaweb translation refresh module monitoring de_DE
* icingaweb translation refresh module monitoring fr_FR
*/
public function moduleAction()
{
$module = $this->validateModuleName($this->params->shift());
$locale = $this->validateLocaleCode($this->params->shift());
$helper = new GettextTranslationHelper($this->app, $locale);
$helper->updateModuleTranslations($module);
}
}

View File

@ -0,0 +1,81 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2014 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2014 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Translation\Cli;
use \Exception;
use Icinga\Cli\Command;
/**
* Base class for translation commands
*/
class TranslationCommand extends Command
{
/**
* Check whether the given locale code is valid
*
* @param string $code The locale code to validate
*
* @return string The validated locale code
*
* @throws Exception In case the locale code is invalid
*/
public function validateLocaleCode($code)
{
$current = setlocale(LC_ALL, '0');
$result = setlocale(LC_ALL, $code);
setlocale(LC_ALL, $current);
if ($result === false) {
throw new Exception("Locale code '$code' is not valid");
}
return $code;
}
/**
* Check whether the given module is available and enabled
*
* @param string $name The module name to validate
*
* @return string The validated module name
*
* @throws Exception In case the given module is not available or not enabled
*/
public function validateModuleName($name)
{
$enabledModules = $this->app->getModuleManager()->listEnabledModules();
if (!in_array($name, $enabledModules)) {
throw new Exception("Module with name '$name' not found or is not enabled");
}
return $name;
}
}

View File

@ -0,0 +1,422 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga Web 2.
*
* Icinga Web 2 - Head for multiple monitoring backends.
* Copyright (C) 2014 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2014 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Module\Translation\Util;
use \Exception;
use Icinga\Application\Modules\Manager;
use Icinga\Application\ApplicationBootstrap;
/**
* This class provides some useful utility functions to handle gettext translations
*/
class GettextTranslationHelper
{
/**
* All project files are supposed to have the same/this encoding
*/
const FILE_ENCODING = 'UTF-8';
/**
* The source files to parse
*
* @var array
*/
private $sourceExtensions = array(
'php',
'phtml'
);
/**
* The module manager of the application's bootstrap
*
* @var Manager
*/
private $moduleMgr;
/**
* The current version of IcingaWeb2
*
* @var string
*/
private $version;
/**
* The locale used by this helper
*
* @var string
*/
private $locale;
/**
* The path to the Zend application root
*
* @var string
*/
private $appDir;
/**
* The path to the module, if any
*
* @var string
*/
private $moduleDir;
/**
* The path to the file catalog
*
* @var string
*/
private $catalogPath;
/**
* The path to the *.pot file
*
* @var string
*/
private $templatePath;
/**
* The path to the *.po file
*
* @var string
*/
private $tablePath;
/**
* Create a new TranslationHelper object
*
* @param ApplicationBootstrap $bootstrap The application's bootstrap object
* @param string $locale The locale to be used by this helper
*/
public function __construct(ApplicationBootstrap $bootstrap, $locale)
{
$this->version = $bootstrap->getConfig()->app()->global->get('version', '0.1');
$this->moduleMgr = $bootstrap->getModuleManager();
$this->appDir = $bootstrap->getApplicationDir();
$this->locale = $locale;
}
/**
* Update the translation table for the main application
*/
public function updateIcingaTranslations()
{
$this->catalogPath = tempnam(sys_get_temp_dir(), 'IcingaTranslation_');
$this->templatePath = tempnam(sys_get_temp_dir(), 'IcingaPot_');
$this->moduleDir = null;
$this->tablePath = implode(
DIRECTORY_SEPARATOR,
array(
$this->appDir,
'locale',
$this->locale,
'LC_MESSAGES',
'icinga.po'
)
);
$this->createFileCatalog();
$this->createTemplateFile();
$this->updateTranslationTable();
}
/**
* Update the translation table for a particular module
*
* @param string $module The name of the module for which to update the translation table
*/
public function updateModuleTranslations($module)
{
$this->catalogPath = tempnam(sys_get_temp_dir(), 'IcingaTranslation_');
$this->templatePath = tempnam(sys_get_temp_dir(), 'IcingaPot_');
$this->moduleDir = $this->moduleMgr->getModuleDir($module);
$this->tablePath = implode(
DIRECTORY_SEPARATOR,
array(
$this->moduleDir,
'application',
'locale',
$this->locale,
'LC_MESSAGES',
$module . '.po'
)
);
$this->createFileCatalog();
$this->createTemplateFile();
$this->updateTranslationTable();
}
/**
* Compile the translation table for the main application
*/
public function compileIcingaTranslation()
{
$this->tablePath = implode(
DIRECTORY_SEPARATOR,
array(
$this->appDir,
'locale',
$this->locale,
'LC_MESSAGES',
'icinga.po'
)
);
$this->compileTranslationTable();
}
/**
* Compile the translation table for a particular module
*
* @param string $module The name of the module for which to compile the translation table
*/
public function compileModuleTranslation($module)
{
$this->moduleDir = $this->moduleMgr->getModuleDir($module);
$this->tablePath = implode(
DIRECTORY_SEPARATOR,
array(
$this->moduleDir,
'application',
'locale',
$this->locale,
'LC_MESSAGES',
$module . '.po'
)
);
$this->compileTranslationTable();
}
/**
* Update any existing or create a new translation table using the gettext tools
*
* @throws Exception In case the translation table does not yet exist and cannot be created
*/
private function updateTranslationTable()
{
if (is_file($this->tablePath)) {
shell_exec(sprintf('/usr/bin/msgmerge --update %s %s 2>&1', $this->tablePath, $this->templatePath));
} else {
if ((!is_dir(dirname($this->tablePath)) && !@mkdir(dirname($this->tablePath), 0755, true)) ||
!rename($this->templatePath, $this->tablePath)) {
throw new Exception('Unable to create ' . $this->tablePath);
}
}
$this->updateHeader($this->tablePath);
}
/**
* Create the template file using the gettext tools
*/
private function createTemplateFile()
{
shell_exec(
implode(
' ',
array(
'/usr/bin/xgettext',
'--language=PHP',
'--keyword=translate',
'--keyword=mt:2',
'--keyword=t',
'--sort-output',
'--force-po',
'--omit-header',
'--from-code=' . self::FILE_ENCODING,
'--files-from="' . $this->catalogPath . '"',
'--output="' . $this->templatePath . '"'
)
)
);
}
/**
* Create or update a gettext conformant header in the given file
*
* @param string $path The path to the file
*/
private function updateHeader($path)
{
$headerInfo = array(
'title' => 'Icinga Web 2 - Head for multiple monitoring backends',
'copyright_holder' => 'Icinga Development Team',
'copyright_year' => date('Y'),
'author_name' => 'FIRST AUTHOR',
'author_mail' => 'EMAIL@ADDRESS',
'author_year' => 'YEAR',
'project_name' => 'Icinga Web 2',
'project_version' => $this->version,
'project_bug_mail' => 'dev@icinga.org',
'pot_creation_date' => date('Y-m-d H:iO'),
'po_revision_date' => 'YEAR-MO-DA HO:MI+ZONE',
'translator_name' => 'FULL NAME',
'translator_mail' => 'EMAIL@ADDRESS',
'language_team_name' => 'LANGUAGE',
'language_team_url' => 'LL@li.org',
'charset' => self::FILE_ENCODING
);
$content = file_get_contents($path);
if (strpos($content, '# ') === 0) {
$authorInfo = array();
if (preg_match('@# (.+) <(.+)>, (\d+|YEAR)\.@', $content, $authorInfo)) {
$headerInfo['author_name'] = $authorInfo[1];
$headerInfo['author_mail'] = $authorInfo[2];
$headerInfo['author_year'] = $authorInfo[3];
}
$revisionInfo = array();
if (preg_match('@Revision-Date: (\d{4}-\d{2}-\d{2} \d{2}:\d{2}\+\d{4})@', $content, $revisionInfo)) {
$headerInfo['po_revision_date'] = $revisionInfo[1];
}
$translatorInfo = array();
if (preg_match('@Last-Translator: (.+) <(.+)>@', $content, $translatorInfo)) {
$headerInfo['translator_name'] = $translatorInfo[1];
$headerInfo['translator_mail'] = $translatorInfo[2];
}
$languageInfo = array();
if (preg_match('@Language-Team: (.+) <(.+)>@', $content, $languageInfo)) {
$headerInfo['language_team_name'] = $languageInfo[1];
$headerInfo['language_team_url'] = $languageInfo[2];
}
}
file_put_contents(
$path,
implode(
PHP_EOL,
array(
'# ' . $headerInfo['title'] . '.',
'# Copyright (C) ' . $headerInfo['copyright_year'] . ' ' . $headerInfo['copyright_holder'],
'# This file is distributed under the same license as ' . $headerInfo['project_name'] . '.',
'# ' . $headerInfo['author_name'] . ' <' . $headerInfo['author_mail']
. '>, ' . $headerInfo['author_year'] . '.',
'# ',
'#, fuzzy',
'msgid ""',
'msgstr ""',
'"Project-Id-Version: ' . $headerInfo['project_name'] . ' ('
. $headerInfo['project_version'] . ')\n"',
'"Report-Msgid-Bugs-To: ' . $headerInfo['project_bug_mail'] . '\n"',
'"POT-Creation-Date: ' . $headerInfo['pot_creation_date'] . '\n"',
'"PO-Revision-Date: ' . $headerInfo['po_revision_date'] . '\n"',
'"Last-Translator: ' . $headerInfo['translator_name'] . ' <'
. $headerInfo['translator_mail'] . '>\n"',
'"Language-Team: ' . $headerInfo['language_team_name'] . ' <'
. $headerInfo['language_team_url'] . '>\n"',
'"MIME-Version: 1.0\n"',
'"Content-Type: text/plain; charset=' . $headerInfo['charset'] . '\n"',
'"Content-Transfer-Encoding: 8bit\n"',
''
)
) . PHP_EOL . substr($content, strpos($content, '#: '))
);
}
/**
* Create the file catalog
*
* @throws Exception In case the catalog-file cannot be created
*/
private function createFileCatalog()
{
$catalogHandle = fopen($this->catalogPath, 'w');
if (!$catalogHandle) {
throw new Exception('Unable to create ' . $this->catalogPath);
}
try {
if ($this->moduleDir) {
$this->getSourceFileNames($this->moduleDir, $catalogHandle);
} else {
$this->getSourceFileNames($this->appDir, $catalogHandle);
$this->getSourceFileNames(realpath($this->appDir . '/../library/Icinga'), $catalogHandle);
}
} catch (Exception $error) {
fclose($catalogHandle);
throw $error;
}
fclose($catalogHandle);
}
/**
* Recursively scan the given directory for translatable source files
*
* @param string $directory The directory where to search for sources
* @param resource $fileHandle The file where to write the results
* @param array $blacklist A list of directories to omit
*
* @throws Exception In case the given directory is not readable
*/
private function getSourceFileNames($directory, &$fileHandle)
{
$directoryHandle = opendir($directory);
if (!$directoryHandle) {
throw new Exception('Unable to read files from ' . $directory);
}
$subdirs = array();
while (($filename = readdir($directoryHandle)) !== false) {
$filepath = $directory . DIRECTORY_SEPARATOR . $filename;
if (preg_match('@^[^\.].+\.(' . implode('|', $this->sourceExtensions) . ')$@', $filename)) {
fwrite($fileHandle, $filepath . PHP_EOL);
} elseif (is_dir($filepath) && !preg_match('@^(\.|\.\.)$@', $filename)) {
$subdirs[] = $filepath;
}
}
closedir($directoryHandle);
foreach ($subdirs as $subdir) {
$this->getSourceFileNames($subdir, $fileHandle);
}
}
/**
* Compile the translation table
*/
private function compileTranslationTable()
{
$targetPath = substr($this->tablePath, 0, strrpos($this->tablePath, '.')) . '.mo';
shell_exec(
implode(
' ',
array(
'/usr/bin/msgfmt',
'-o ' . $targetPath,
$this->tablePath
)
)
);
}
}