commit
f5b6f648a3
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -37,6 +37,7 @@ use \Zend_View_Helper_DateFormat;
|
|||
use \Icinga\Application\Config as IcingaConfig;
|
||||
use \Icinga\Data\ResourceFactory;
|
||||
use \Icinga\Web\Form;
|
||||
use \Icinga\Util\Translator;
|
||||
use \Icinga\Web\Form\Validator\WritablePathValidator;
|
||||
use \Icinga\Web\Form\Validator\TimeFormatValidator;
|
||||
use \Icinga\Web\Form\Validator\DateFormatValidator;
|
||||
|
@ -161,6 +162,35 @@ class GeneralForm extends Form
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a select field for setting the default language
|
||||
*
|
||||
* Possible values are determined by Translator::getAvailableLocaleCodes.
|
||||
*
|
||||
* @param Zend_Config $cfg The "global" section of the config.ini
|
||||
*/
|
||||
private function addLanguageSelection(Zend_Config $cfg)
|
||||
{
|
||||
$languages = array();
|
||||
foreach (Translator::getAvailableLocaleCodes() as $language) {
|
||||
$languages[$language] = $language;
|
||||
}
|
||||
$languages[Translator::DEFAULT_LOCALE] = Translator::DEFAULT_LOCALE;
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'language',
|
||||
array(
|
||||
'label' => t('Default Language'),
|
||||
'required' => true,
|
||||
'multiOptions' => $languages,
|
||||
'helptext' => t('Select the language to use by default. Can be'
|
||||
. ' overwritten by a user in his preferences.'),
|
||||
'value' => $cfg->get('language', Translator::DEFAULT_LOCALE)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a select field for setting the default timezone.
|
||||
*
|
||||
|
@ -353,6 +383,7 @@ class GeneralForm extends Form
|
|||
}
|
||||
$this->setName('form_config_general');
|
||||
$this->addDevelopmentCheckbox($global);
|
||||
$this->addLanguageSelection($global);
|
||||
$this->addTimezoneSelection($global);
|
||||
$this->addModuleSettings($global);
|
||||
$this->addDateFormatSettings($global);
|
||||
|
@ -389,6 +420,7 @@ class GeneralForm extends Form
|
|||
$values = $this->getValues();
|
||||
$cfg = clone $config;
|
||||
$cfg->global->environment = ($values['environment'] == 1) ? 'development' : 'production';
|
||||
$cfg->global->language = $values['language'];
|
||||
$cfg->global->timezone = $values['timezone'];
|
||||
$cfg->global->moduleFolder = $values['module_folder'];
|
||||
$cfg->global->modulePath = $values['module_path'];
|
||||
|
|
|
@ -37,6 +37,7 @@ use \Zend_View_Helper_DateFormat;
|
|||
use \Icinga\Web\Form;
|
||||
use \Icinga\Web\Form\Validator\TimeFormatValidator;
|
||||
use \Icinga\Web\Form\Validator\DateFormatValidator;
|
||||
use \Icinga\Util\Translator;
|
||||
|
||||
/**
|
||||
* General user preferences
|
||||
|
@ -73,13 +74,54 @@ class GeneralForm extends Form
|
|||
$this->dateHelper = $dateHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a select field for setting the user's language
|
||||
*
|
||||
* Possible values are determined by Translator::getAvailableLocaleCodes.
|
||||
* Also, a 'use default format' checkbox is added in order to allow a user to discard his overwritten setting
|
||||
*
|
||||
* @param Zend_Config $cfg The "global" section of the config.ini to be used as default value
|
||||
*/
|
||||
private function addLanguageSelection(Zend_Config $cfg)
|
||||
{
|
||||
$languages = array();
|
||||
foreach (Translator::getAvailableLocaleCodes() as $language) {
|
||||
$languages[$language] = $language;
|
||||
}
|
||||
$languages[Translator::DEFAULT_LOCALE] = Translator::DEFAULT_LOCALE;
|
||||
$prefs = $this->getUserPreferences();
|
||||
$useDefaultLanguage = $this->getRequest()->getParam('default_language', !$prefs->has('app.language'));
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'default_language',
|
||||
array(
|
||||
'label' => t('Use Default Language'),
|
||||
'value' => !$prefs->has('app.language'),
|
||||
'required' => true
|
||||
)
|
||||
);
|
||||
$selectOptions = array(
|
||||
'label' => t('Your Current Language'),
|
||||
'required' => !$useDefaultLanguage,
|
||||
'multiOptions' => $languages,
|
||||
'helptext' => t('Use the following language to display texts and messages'),
|
||||
'value' => $prefs->get('app.language', $cfg->get('language', Translator::DEFAULT_LOCALE))
|
||||
);
|
||||
if ($useDefaultLanguage) {
|
||||
$selectOptions['disabled'] = 'disabled';
|
||||
}
|
||||
$this->addElement('select', 'language', $selectOptions);
|
||||
$this->enableAutoSubmit(array('default_language'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a select field for setting the user's timezone.
|
||||
*
|
||||
* Possible values are determined by DateTimeZone::listIdentifiers
|
||||
* Also, a 'use default format' checkbox is added in order to allow a user to discard his overwritten setting
|
||||
*
|
||||
* @param Zend_Config $cfg The "global" section of the config.ini to be used as default valuse
|
||||
* @param Zend_Config $cfg The "global" section of the config.ini to be used as default value
|
||||
*/
|
||||
private function addTimezoneSelection(Zend_Config $cfg)
|
||||
{
|
||||
|
@ -210,6 +252,7 @@ class GeneralForm extends Form
|
|||
$global = new Zend_Config(array());
|
||||
}
|
||||
|
||||
$this->addLanguageSelection($global);
|
||||
$this->addTimezoneSelection($global);
|
||||
$this->addDateFormatSettings($global);
|
||||
|
||||
|
@ -234,6 +277,7 @@ class GeneralForm extends Form
|
|||
{
|
||||
$values = $this->getValues();
|
||||
return array(
|
||||
'app.language' => $values['language'],
|
||||
'app.timezone' => $values['timezone'],
|
||||
'app.dateFormat' => $values['date_format'],
|
||||
'app.timeFormat' => $values['time_format'],
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
@ -31,13 +31,11 @@ namespace Icinga\Application;
|
|||
|
||||
use \DateTimeZone;
|
||||
use \Exception;
|
||||
use \Zend_Loader_Autoloader;
|
||||
use \Icinga\Application\Modules\Manager as ModuleManager;
|
||||
use \Icinga\Application\Platform;
|
||||
use \Icinga\Application\Config;
|
||||
use \Icinga\Exception\ProgrammingError;
|
||||
use \Icinga\Exception\ConfigurationError;
|
||||
use \Icinga\Util\DateTimeFactory;
|
||||
use \Icinga\Util\Translator;
|
||||
|
||||
use Icinga\Data\ResourceFactory;
|
||||
|
||||
|
@ -427,4 +425,23 @@ abstract class ApplicationBootstrap
|
|||
DateTimeFactory::setConfig(array('timezone' => $tz));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup internationalization using gettext
|
||||
*
|
||||
* Uses the language defined in the global config or the default one
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
protected function setupInternationalization()
|
||||
{
|
||||
Translator::setupLocale($this->config->global->get('language', Translator::DEFAULT_LOCALE));
|
||||
|
||||
$localeDir = $this->getApplicationDir('locale');
|
||||
if (file_exists($localeDir) && is_dir($localeDir)) {
|
||||
Translator::registerDomain('icinga', $localeDir);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ namespace Icinga\Application;
|
|||
|
||||
use Icinga\Application\Platform;
|
||||
use Icinga\Application\ApplicationBootstrap;
|
||||
use Icinga\Application\Modules\Manager as ModuleManager;
|
||||
use Icinga\Cli\Params;
|
||||
use Icinga\Cli\Loader;
|
||||
use Icinga\Cli\Screen;
|
||||
|
@ -63,12 +62,12 @@ class Cli extends ApplicationBootstrap
|
|||
{
|
||||
$this->assertRunningOnCli();
|
||||
$this->setupConfig()
|
||||
->parseBasicParams()
|
||||
->fixLoggingConfig()
|
||||
->setupErrorHandling()
|
||||
->setupResourceFactory()
|
||||
->setupModuleManager()
|
||||
;
|
||||
->setupInternationalization()
|
||||
->parseBasicParams()
|
||||
->fixLoggingConfig()
|
||||
->setupErrorHandling()
|
||||
->setupResourceFactory()
|
||||
->setupModuleManager();
|
||||
}
|
||||
|
||||
protected function fixLoggingConfig()
|
||||
|
|
|
@ -35,6 +35,7 @@ use Icinga\Application\ApplicationBootstrap;
|
|||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Web\Hook;
|
||||
|
||||
/**
|
||||
|
@ -422,7 +423,7 @@ class Module
|
|||
protected function registerLocales()
|
||||
{
|
||||
if (file_exists($this->localedir) && is_dir($this->localedir)) {
|
||||
bindtextdomain($this->name, $this->localedir);
|
||||
Translator::registerDomain($this->name, $this->localedir);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -50,6 +50,7 @@ use Icinga\User\Preferences\SessionStore;
|
|||
use Icinga\Util\DateTimeFactory;
|
||||
use Icinga\Session\Session as BaseSession;
|
||||
use Icinga\Web\Session;
|
||||
use Icinga\Util\Translator;
|
||||
|
||||
/**
|
||||
* Use this if you want to make use of Icinga functionality in other web projects
|
||||
|
@ -116,10 +117,10 @@ class Web extends ApplicationBootstrap
|
|||
->setupResourceFactory()
|
||||
->setupSession()
|
||||
->setupUser()
|
||||
->setupInternationalization()
|
||||
->setupTimezone()
|
||||
->setupRequest()
|
||||
->setupZendMvc()
|
||||
->setupTranslation()
|
||||
->setupModuleManager()
|
||||
->loadEnabledModules()
|
||||
->setupRoute()
|
||||
|
@ -168,25 +169,6 @@ class Web extends ApplicationBootstrap
|
|||
return $this->viewRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load translations
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
private function setupTranslation()
|
||||
{
|
||||
// AuthManager::getInstance()->getSession()->language;
|
||||
$locale = null;
|
||||
if (!$locale) {
|
||||
$locale = 'en_US';
|
||||
}
|
||||
putenv('LC_ALL=' . $locale . '.UTF-8');
|
||||
setlocale(LC_ALL, $locale . '.UTF-8');
|
||||
bindtextdomain('icinga', $this->getApplicationDir() . '/locale');
|
||||
textdomain('icinga');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch public interface
|
||||
*/
|
||||
|
@ -449,4 +431,30 @@ class Web extends ApplicationBootstrap
|
|||
DateTimeFactory::setConfig(array('timezone' => $tz));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup internationalization using gettext
|
||||
*
|
||||
* Uses the preferred user language or the configured default and system default, respectively.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
protected function setupInternationalization()
|
||||
{
|
||||
parent::setupInternationalization();
|
||||
$userLocale = $this->user === null ? null : $this->user->getPreferences()->get('app.language');
|
||||
|
||||
if ($userLocale) {
|
||||
try {
|
||||
Translator::setupLocale($userLocale);
|
||||
} catch (Exception $error) {
|
||||
Logger::error(
|
||||
'Cannot set locale "' . $userLocale . '" configured in ' .
|
||||
'preferences of user "' . $this->user->getUsername() . '"'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,31 +27,25 @@
|
|||
*/
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
if (function_exists('_')) {
|
||||
function t($messageId = null)
|
||||
use \Icinga\Util\Translator;
|
||||
|
||||
if (extension_loaded('gettext')) {
|
||||
function t($messageId)
|
||||
{
|
||||
$msg = _($messageId);
|
||||
if (! $msg) {
|
||||
return $messageId;
|
||||
}
|
||||
return $msg;
|
||||
return Translator::translate($messageId, 'icinga');
|
||||
}
|
||||
|
||||
function mt($domain, $messageId = null)
|
||||
function mt($domain, $messageId)
|
||||
{
|
||||
$msg = dgettext($domain, $messageId);
|
||||
if (! $msg) {
|
||||
return $messageId;
|
||||
}
|
||||
return $msg;
|
||||
return Translator::translate($messageId, $domain);
|
||||
}
|
||||
} else {
|
||||
function t($messageId = null)
|
||||
function t($messageId)
|
||||
{
|
||||
return $messageId;
|
||||
}
|
||||
|
||||
function mt($domain, $messageId = null)
|
||||
function mt($domain, $messageId)
|
||||
{
|
||||
return $messageId;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace Icinga\Cli;
|
||||
|
||||
use Icinga\Cli\Loader;
|
||||
use Icinga\Cli\Screen;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Application\ApplicationBootstrap as App;
|
||||
use Exception;
|
||||
|
||||
|
@ -48,6 +48,21 @@ abstract class Command
|
|||
return $this->trace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a string
|
||||
*
|
||||
* Autoselects the module domain, if any, and falls back to the global one if no translation could be found.
|
||||
*
|
||||
* @param string $text The string to translate
|
||||
*
|
||||
* @return string The translated string
|
||||
*/
|
||||
public function translate($text)
|
||||
{
|
||||
$domain = $this->moduleName === null ? 'icinga' : $this->moduleName;
|
||||
return Translator::translate($text, $domain);
|
||||
}
|
||||
|
||||
public function fail($msg)
|
||||
{
|
||||
throw new Exception($msg);
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
<?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\Util;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Helper class to ease internationalization when using gettext
|
||||
*/
|
||||
class Translator
|
||||
{
|
||||
/**
|
||||
* The default gettext domain used as fallback
|
||||
*/
|
||||
const DEFAULT_DOMAIN = 'icinga';
|
||||
|
||||
/**
|
||||
* The locale code that is used in the project
|
||||
*/
|
||||
const DEFAULT_LOCALE = 'en_US';
|
||||
|
||||
/**
|
||||
* Known gettext domains and directories
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $knownDomains = array();
|
||||
|
||||
/**
|
||||
* Translate a string
|
||||
*
|
||||
* Falls back to the default domain in case the string cannot be translated using the given domain
|
||||
*
|
||||
* @param string $text The string to translate
|
||||
* @param string $domain The primary domain to use
|
||||
*
|
||||
* @return string The translated string
|
||||
*
|
||||
* @throws Exception In case the given domain is unknown
|
||||
*/
|
||||
public static function translate($text, $domain)
|
||||
{
|
||||
if ($domain !== self::DEFAULT_DOMAIN && !array_key_exists($domain, self::$knownDomains)) {
|
||||
throw new Exception("Cannot translate string '$text' with unknown domain '$domain'");
|
||||
}
|
||||
|
||||
$res = dgettext($domain, $text);
|
||||
if ($res === $text && $domain !== self::DEFAULT_DOMAIN) {
|
||||
return dgettext(self::DEFAULT_DOMAIN, $text);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new gettext domain
|
||||
*
|
||||
* @param string $name The name of the domain to register
|
||||
* @param string $directory The directory where message catalogs can be found
|
||||
*
|
||||
* @throws Exception In case the domain was not successfully registered
|
||||
*/
|
||||
public static function registerDomain($name, $directory)
|
||||
{
|
||||
if (bindtextdomain($name, $directory) === false) {
|
||||
throw new Exception("Cannot register domain '$name' with path '$directory'");
|
||||
}
|
||||
bind_textdomain_codeset($name, 'UTF-8');
|
||||
self::$knownDomains[$name] = $directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the locale to use
|
||||
*
|
||||
* @param string $localeName The name of the locale to use
|
||||
*
|
||||
* @throws Exception In case the locale's name is invalid
|
||||
*/
|
||||
public static function setupLocale($localeName)
|
||||
{
|
||||
if (setlocale(LC_ALL, $localeName . '.UTF-8') === false) {
|
||||
throw new Exception("Cannot set locale '$localeName.UTF-8' for category 'LC_ALL'");
|
||||
}
|
||||
putenv('LC_ALL=' . $localeName . '.UTF-8'); // Failsafe, Win and Unix
|
||||
putenv('LANG=' . $localeName . '.UTF-8'); // Windows fix, untested
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all locale codes currently available in the known domains
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getAvailableLocaleCodes()
|
||||
{
|
||||
$codes = array();
|
||||
|
||||
foreach (array_values(self::$knownDomains) as $directory) {
|
||||
$dh = opendir($directory);
|
||||
while (false !== ($name = readdir($dh))) {
|
||||
if (!preg_match('@\.|\.\.@', $name) && is_dir($directory . DIRECTORY_SEPARATOR . $name)) {
|
||||
$codes[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $codes;
|
||||
}
|
||||
}
|
|
@ -32,17 +32,13 @@ namespace Icinga\Web\Controller;
|
|||
use \Exception;
|
||||
use \Zend_Controller_Action;
|
||||
use \Zend_Controller_Request_Abstract;
|
||||
use \Zend_Controller_Front;
|
||||
use \Zend_Controller_Response_Abstract;
|
||||
use \Zend_Controller_Action_HelperBroker;
|
||||
use \Zend_Layout;
|
||||
use Icinga\Authentication\Manager as AuthManager;
|
||||
use Icinga\Application\Benchmark;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Web\Widget\Tabs;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Request;
|
||||
|
||||
/**
|
||||
* Base class for all core action controllers
|
||||
|
@ -152,15 +148,19 @@ class ActionController extends Zend_Controller_Action
|
|||
}
|
||||
|
||||
/**
|
||||
* Translate the given string with the global translation catalog
|
||||
* Translate a string
|
||||
*
|
||||
* @param string $string The string that should be translated
|
||||
* Autoselects the module domain, if any, and falls back to the global one if no translation could be found.
|
||||
*
|
||||
* @return string
|
||||
* @param string $text The string to translate
|
||||
*
|
||||
* @return string The translated string
|
||||
*/
|
||||
public function translate($string)
|
||||
public function translate($text)
|
||||
{
|
||||
return t($string);
|
||||
$module = $this->getRequest()->getModuleName();
|
||||
$domain = $module === 'default' ? 'icinga' : $module;
|
||||
return Translator::translate($text, $domain);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -212,7 +212,6 @@ class ActionController extends Zend_Controller_Action
|
|||
$this->_helper->Redirector->gotoUrlAndExit($url);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect whether the current request requires changes in the layout and apply them before rendering
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue