mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-25 23:04:51 +02:00
Merge pull request #4376 from Icinga/utilize-ipl-i18n-4366
Utilize ipl-i18n
This commit is contained in:
commit
229e24519a
4
.github/workflows/php.yml
vendored
4
.github/workflows/php.yml
vendored
@ -105,9 +105,7 @@ jobs:
|
|||||||
extensions: mysql, pgsql, ldap
|
extensions: mysql, pgsql, ldap
|
||||||
|
|
||||||
- name: Setup dependencies
|
- name: Setup dependencies
|
||||||
run: |
|
run: composer require -n --no-progress mockery/mockery ipl/i18n:@dev
|
||||||
sudo locale-gen en_US.UTF-8 de_DE.UTF-8 fr_FR.UTF-8
|
|
||||||
composer require -n --no-progress mockery/mockery
|
|
||||||
|
|
||||||
- name: PHPUnit
|
- name: PHPUnit
|
||||||
env:
|
env:
|
||||||
|
@ -12,12 +12,13 @@ use Icinga\Authentication\Auth;
|
|||||||
use Icinga\User\Preferences;
|
use Icinga\User\Preferences;
|
||||||
use Icinga\User\Preferences\PreferencesStore;
|
use Icinga\User\Preferences\PreferencesStore;
|
||||||
use Icinga\Util\TimezoneDetect;
|
use Icinga\Util\TimezoneDetect;
|
||||||
use Icinga\Util\Translator;
|
|
||||||
use Icinga\Web\Cookie;
|
|
||||||
use Icinga\Web\Form;
|
use Icinga\Web\Form;
|
||||||
use Icinga\Web\Notification;
|
use Icinga\Web\Notification;
|
||||||
use Icinga\Web\Session;
|
use Icinga\Web\Session;
|
||||||
use Icinga\Web\StyleSheet;
|
use Icinga\Web\StyleSheet;
|
||||||
|
use ipl\I18n\GettextTranslator;
|
||||||
|
use ipl\I18n\Locale;
|
||||||
|
use ipl\I18n\StaticTranslator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Form class to adjust user preferences
|
* Form class to adjust user preferences
|
||||||
@ -201,14 +202,18 @@ class PreferenceForm extends Form
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$languages = array();
|
/** @var GettextTranslator $translator */
|
||||||
|
$translator = StaticTranslator::$instance;
|
||||||
|
|
||||||
$locale = $this->getLocale();
|
$languages = array();
|
||||||
|
$availableLocales = $translator->listLocales();
|
||||||
|
|
||||||
|
$locale = $this->getLocale($availableLocales);
|
||||||
if ($locale !== null) {
|
if ($locale !== null) {
|
||||||
$languages['autodetect'] = sprintf($this->translate('Browser (%s)', 'preferences.form'), $locale);
|
$languages['autodetect'] = sprintf($this->translate('Browser (%s)', 'preferences.form'), $locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Translator::getAvailableLocaleCodes() as $language) {
|
foreach ($availableLocales as $language) {
|
||||||
$languages[$language] = $language;
|
$languages[$language] = $language;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,10 +415,10 @@ class PreferenceForm extends Form
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
protected function getLocale()
|
protected function getLocale($availableLocales)
|
||||||
{
|
{
|
||||||
return isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])
|
return isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])
|
||||||
? Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE'])
|
? (new Locale())->getPreferred($_SERVER['HTTP_ACCEPT_LANGUAGE'], $availableLocales)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Icinga\Util\Translator;
|
use ipl\I18n\Locale;
|
||||||
|
use ipl\I18n\GettextTranslator;
|
||||||
|
use ipl\I18n\StaticTranslator;
|
||||||
|
|
||||||
$lang = Translator::splitLocaleCode()->language;
|
/** @var GettextTranslator $translator */
|
||||||
|
$translator = StaticTranslator::$instance;
|
||||||
|
|
||||||
|
$lang = (new Locale())->parseLocale($translator->getLocale())->language;
|
||||||
$showFullscreen = $this->layout()->showFullscreen;
|
$showFullscreen = $this->layout()->showFullscreen;
|
||||||
$innerLayoutScript = $this->layout()->innerLayout . '.phtml';
|
$innerLayoutScript = $this->layout()->innerLayout . '.phtml';
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Icinga\Util\Translator;
|
use ipl\I18n\Locale;
|
||||||
|
use ipl\I18n\GettextTranslator;
|
||||||
|
use ipl\I18n\StaticTranslator;
|
||||||
use ipl\Web\Widget\Icon;
|
use ipl\Web\Widget\Icon;
|
||||||
|
|
||||||
if (array_key_exists('_dev', $_GET)) {
|
if (array_key_exists('_dev', $_GET)) {
|
||||||
@ -11,8 +13,11 @@ if (array_key_exists('_dev', $_GET)) {
|
|||||||
$cssfile = 'css/icinga.min.css';
|
$cssfile = 'css/icinga.min.css';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var GettextTranslator $translator */
|
||||||
|
$translator = StaticTranslator::$instance;
|
||||||
|
|
||||||
|
$lang = (new Locale())->parseLocale($translator->getLocale())->language;
|
||||||
$timezone = date_default_timezone_get();
|
$timezone = date_default_timezone_get();
|
||||||
$lang = Translator::splitLocaleCode()->language;
|
|
||||||
$isIframe = $this->layout()->isIframe;
|
$isIframe = $this->layout()->isIframe;
|
||||||
$showFullscreen = $this->layout()->showFullscreen;
|
$showFullscreen = $this->layout()->showFullscreen;
|
||||||
$iframeClass = $isIframe ? ' iframe' : '';
|
$iframeClass = $isIframe ? ' iframe' : '';
|
||||||
|
@ -6,13 +6,14 @@ namespace Icinga\Application;
|
|||||||
use DirectoryIterator;
|
use DirectoryIterator;
|
||||||
use ErrorException;
|
use ErrorException;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use ipl\I18n\GettextTranslator;
|
||||||
|
use ipl\I18n\StaticTranslator;
|
||||||
use LogicException;
|
use LogicException;
|
||||||
use Icinga\Application\Modules\Manager as ModuleManager;
|
use Icinga\Application\Modules\Manager as ModuleManager;
|
||||||
use Icinga\Authentication\User\UserBackend;
|
use Icinga\Authentication\User\UserBackend;
|
||||||
use Icinga\Data\ConfigObject;
|
use Icinga\Data\ConfigObject;
|
||||||
use Icinga\Exception\ConfigurationError;
|
use Icinga\Exception\ConfigurationError;
|
||||||
use Icinga\Exception\NotReadableError;
|
use Icinga\Exception\NotReadableError;
|
||||||
use Icinga\Util\Translator;
|
|
||||||
use Icinga\Exception\IcingaException;
|
use Icinga\Exception\IcingaException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -699,6 +700,19 @@ abstract class ApplicationBootstrap
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare internationalization using gettext
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
protected function prepareInternationalization()
|
||||||
|
{
|
||||||
|
StaticTranslator::$instance = (new GettextTranslator())
|
||||||
|
->setDefaultDomain('icinga');
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up internationalization using gettext
|
* Set up internationalization using gettext
|
||||||
*
|
*
|
||||||
@ -706,17 +720,20 @@ abstract class ApplicationBootstrap
|
|||||||
*/
|
*/
|
||||||
final protected function setupInternationalization()
|
final protected function setupInternationalization()
|
||||||
{
|
{
|
||||||
|
/** @var GettextTranslator $translator */
|
||||||
|
$translator = StaticTranslator::$instance;
|
||||||
|
|
||||||
if ($this->hasLocales()) {
|
if ($this->hasLocales()) {
|
||||||
Translator::registerDomain(Translator::DEFAULT_DOMAIN, $this->getLocaleDir());
|
$translator->addTranslationDirectory($this->getLocaleDir(), 'icinga');
|
||||||
}
|
}
|
||||||
|
|
||||||
$locale = $this->detectLocale();
|
$locale = $this->detectLocale();
|
||||||
if ($locale === null) {
|
if ($locale === null) {
|
||||||
$locale = Translator::DEFAULT_LOCALE;
|
$locale = $translator->getDefaultLocale();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Translator::setupLocale($locale);
|
$translator->setLocale($locale);
|
||||||
} catch (Exception $error) {
|
} catch (Exception $error) {
|
||||||
Logger::error($error);
|
Logger::error($error);
|
||||||
}
|
}
|
||||||
@ -753,27 +770,15 @@ abstract class ApplicationBootstrap
|
|||||||
/**
|
/**
|
||||||
* List all available locales
|
* List all available locales
|
||||||
*
|
*
|
||||||
* NOTE: Might be a candidate for a static function in Translator
|
* @return array Locale list
|
||||||
*
|
*
|
||||||
* return array Locale list
|
* @deprecated Use {@see \ipl\I18n\GettextTranslator::listLocales()} instead
|
||||||
*/
|
*/
|
||||||
public function listLocales()
|
public function listLocales()
|
||||||
{
|
{
|
||||||
$locales = array();
|
/** @var GettextTranslator $translator */
|
||||||
if (! $this->hasLocales()) {
|
$translator = StaticTranslator::$instance;
|
||||||
return $locales;
|
|
||||||
}
|
|
||||||
$localedir = $this->getLocaleDir();
|
|
||||||
|
|
||||||
$dh = opendir($localedir);
|
return $translator->listLocales();
|
||||||
while (false !== ($file = readdir($dh))) {
|
|
||||||
$filename = $localedir . DIRECTORY_SEPARATOR . $file;
|
|
||||||
if (preg_match('/^[a-z]{2}_[A-Z]{2}$/', $file) && is_dir($filename)) {
|
|
||||||
$locales[] = $file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir($dh);
|
|
||||||
sort($locales);
|
|
||||||
return $locales;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ class Cli extends ApplicationBootstrap
|
|||||||
->loadLibraries()
|
->loadLibraries()
|
||||||
->loadConfig()
|
->loadConfig()
|
||||||
->setupTimezone()
|
->setupTimezone()
|
||||||
|
->prepareInternationalization()
|
||||||
->setupInternationalization()
|
->setupInternationalization()
|
||||||
->parseBasicParams()
|
->parseBasicParams()
|
||||||
->setupLogger()
|
->setupLogger()
|
||||||
|
@ -7,6 +7,8 @@ require_once dirname(__FILE__) . '/ApplicationBootstrap.php';
|
|||||||
|
|
||||||
use Icinga\Web\Request;
|
use Icinga\Web\Request;
|
||||||
use Icinga\Web\Response;
|
use Icinga\Web\Response;
|
||||||
|
use ipl\I18n\NoopTranslator;
|
||||||
|
use ipl\I18n\StaticTranslator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use this if you want to make use of Icinga functionality in other web projects
|
* Use this if you want to make use of Icinga functionality in other web projects
|
||||||
@ -72,6 +74,7 @@ class EmbeddedWeb extends ApplicationBootstrap
|
|||||||
->setupRequest()
|
->setupRequest()
|
||||||
->setupResponse()
|
->setupResponse()
|
||||||
->setupTimezone()
|
->setupTimezone()
|
||||||
|
->prepareFakeInternationalization()
|
||||||
->setupModuleManager()
|
->setupModuleManager()
|
||||||
->loadEnabledModules();
|
->loadEnabledModules();
|
||||||
}
|
}
|
||||||
@ -97,4 +100,16 @@ class EmbeddedWeb extends ApplicationBootstrap
|
|||||||
$this->response = new Response();
|
$this->response = new Response();
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare fake internationalization
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
protected function prepareFakeInternationalization()
|
||||||
|
{
|
||||||
|
StaticTranslator::$instance = new NoopTranslator();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,11 @@ use Icinga\Exception\IcingaException;
|
|||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
use Icinga\Module\Setup\SetupWizard;
|
use Icinga\Module\Setup\SetupWizard;
|
||||||
use Icinga\Util\File;
|
use Icinga\Util\File;
|
||||||
use Icinga\Util\Translator;
|
|
||||||
use Icinga\Web\Navigation\Navigation;
|
use Icinga\Web\Navigation\Navigation;
|
||||||
use Icinga\Web\Widget;
|
use Icinga\Web\Widget;
|
||||||
|
use ipl\I18n\GettextTranslator;
|
||||||
|
use ipl\I18n\StaticTranslator;
|
||||||
|
use ipl\I18n\Translation;
|
||||||
use RecursiveDirectoryIterator;
|
use RecursiveDirectoryIterator;
|
||||||
use RecursiveIteratorIterator;
|
use RecursiveIteratorIterator;
|
||||||
use Zend_Controller_Router_Route;
|
use Zend_Controller_Router_Route;
|
||||||
@ -29,6 +31,11 @@ use Zend_Controller_Router_Route_Regex;
|
|||||||
*/
|
*/
|
||||||
class Module
|
class Module
|
||||||
{
|
{
|
||||||
|
use Translation {
|
||||||
|
translate as protected;
|
||||||
|
translatePlural as protected;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module name
|
* Module name
|
||||||
*
|
*
|
||||||
@ -300,6 +307,8 @@ class Module
|
|||||||
$this->runScript = $basedir . '/run.php';
|
$this->runScript = $basedir . '/run.php';
|
||||||
$this->configScript = $basedir . '/configuration.php';
|
$this->configScript = $basedir . '/configuration.php';
|
||||||
$this->metadataFile = $basedir . '/module.info';
|
$this->metadataFile = $basedir . '/module.info';
|
||||||
|
|
||||||
|
$this->translationDomain = $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1418,9 +1427,10 @@ class Module
|
|||||||
*/
|
*/
|
||||||
protected function registerLocales()
|
protected function registerLocales()
|
||||||
{
|
{
|
||||||
if ($this->hasLocales()) {
|
if ($this->hasLocales() && StaticTranslator::$instance instanceof GettextTranslator) {
|
||||||
Translator::registerDomain($this->name, $this->localedir);
|
StaticTranslator::$instance->addTranslationDirectory($this->localedir, $this->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1633,22 +1643,4 @@ class Module
|
|||||||
$this->routes[$name] = $route;
|
$this->routes[$name] = $route;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* (non-PHPDoc)
|
|
||||||
* @see Translator::translate() For the function documentation.
|
|
||||||
*/
|
|
||||||
protected function translate($string, $context = null)
|
|
||||||
{
|
|
||||||
return mt($this->name, $string, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* (non-PHPDoc)
|
|
||||||
* @see Translator::translatePlural() For the function documentation.
|
|
||||||
*/
|
|
||||||
protected function translatePlural($textSingular, $textPlural, $number, $context = null)
|
|
||||||
{
|
|
||||||
return mtp($this->name, $textSingular, $textPlural, $number, $context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@ namespace Icinga\Application;
|
|||||||
require_once __DIR__ . '/EmbeddedWeb.php';
|
require_once __DIR__ . '/EmbeddedWeb.php';
|
||||||
|
|
||||||
use ErrorException;
|
use ErrorException;
|
||||||
|
use ipl\I18n\GettextTranslator;
|
||||||
|
use ipl\I18n\Locale;
|
||||||
|
use ipl\I18n\StaticTranslator;
|
||||||
use Zend_Controller_Action_HelperBroker;
|
use Zend_Controller_Action_HelperBroker;
|
||||||
use Zend_Controller_Front;
|
use Zend_Controller_Front;
|
||||||
use Zend_Controller_Router_Route;
|
use Zend_Controller_Router_Route;
|
||||||
@ -16,7 +19,6 @@ use Icinga\Authentication\Auth;
|
|||||||
use Icinga\User;
|
use Icinga\User;
|
||||||
use Icinga\Util\DirectoryIterator;
|
use Icinga\Util\DirectoryIterator;
|
||||||
use Icinga\Util\TimezoneDetect;
|
use Icinga\Util\TimezoneDetect;
|
||||||
use Icinga\Util\Translator;
|
|
||||||
use Icinga\Web\Controller\Dispatcher;
|
use Icinga\Web\Controller\Dispatcher;
|
||||||
use Icinga\Web\Menu;
|
use Icinga\Web\Menu;
|
||||||
use Icinga\Web\Navigation\Navigation;
|
use Icinga\Web\Navigation\Navigation;
|
||||||
@ -91,6 +93,7 @@ class Web extends EmbeddedWeb
|
|||||||
->setupNotifications()
|
->setupNotifications()
|
||||||
->setupResponse()
|
->setupResponse()
|
||||||
->setupZendMvc()
|
->setupZendMvc()
|
||||||
|
->prepareInternationalization()
|
||||||
->setupModuleManager()
|
->setupModuleManager()
|
||||||
->loadSetupModuleIfNecessary()
|
->loadSetupModuleIfNecessary()
|
||||||
->loadEnabledModules()
|
->loadEnabledModules()
|
||||||
@ -493,9 +496,7 @@ class Web extends EmbeddedWeb
|
|||||||
*
|
*
|
||||||
* Uses the preferred user language or the browser suggested language or our default.
|
* Uses the preferred user language or the browser suggested language or our default.
|
||||||
*
|
*
|
||||||
* @return string Detected locale code
|
* @return string Detected locale code
|
||||||
*
|
|
||||||
* @see Translator::DEFAULT_LOCALE For the default locale code.
|
|
||||||
*/
|
*/
|
||||||
protected function detectLocale()
|
protected function detectLocale()
|
||||||
{
|
{
|
||||||
@ -505,9 +506,14 @@ class Web extends EmbeddedWeb
|
|||||||
) {
|
) {
|
||||||
return $locale;
|
return $locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var GettextTranslator $translator */
|
||||||
|
$translator = StaticTranslator::$instance;
|
||||||
|
|
||||||
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||||
return Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
return (new Locale())->getPreferred($_SERVER['HTTP_ACCEPT_LANGUAGE'], $translator->listLocales());
|
||||||
}
|
}
|
||||||
return Translator::DEFAULT_LOCALE;
|
|
||||||
|
return $translator->getDefaultLocale();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
|
/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
use Icinga\Util\Translator;
|
use ipl\Stdlib\Contract\Translator;
|
||||||
|
use ipl\I18n\StaticTranslator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No-op translate
|
* No-op translate
|
||||||
@ -27,45 +28,46 @@ if (function_exists('t')) {
|
|||||||
if (extension_loaded('gettext')) {
|
if (extension_loaded('gettext')) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (non-PHPDoc)
|
|
||||||
* @see Translator::translate() For the function documentation.
|
* @see Translator::translate() For the function documentation.
|
||||||
*/
|
*/
|
||||||
function t($messageId, $context = null)
|
function t($messageId, $context = null)
|
||||||
{
|
{
|
||||||
return Translator::translate($messageId, Translator::DEFAULT_DOMAIN, $context);
|
return StaticTranslator::$instance->translate($messageId, $context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (non-PHPDoc)
|
* @see Translator::translateInDomain() For the function documentation.
|
||||||
* @see Translator::translate() For the function documentation.
|
|
||||||
*/
|
*/
|
||||||
function mt($domain, $messageId, $context = null)
|
function mt($domain, $messageId, $context = null)
|
||||||
{
|
{
|
||||||
return Translator::translate($messageId, $domain, $context);
|
return StaticTranslator::$instance->translateInDomain($domain, $messageId, $context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (non-PHPDoc)
|
|
||||||
* @see Translator::translatePlural() For the function documentation.
|
* @see Translator::translatePlural() For the function documentation.
|
||||||
*/
|
*/
|
||||||
function tp($messageId, $messageId2, $number, $context = null)
|
function tp($messageId, $messageId2, $number, $context = null)
|
||||||
{
|
{
|
||||||
return Translator::translatePlural($messageId, $messageId2, $number, Translator::DEFAULT_DOMAIN, $context);
|
return StaticTranslator::$instance->translatePlural($messageId, $messageId2, $number, $context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (non-PHPDoc)
|
* @see Translator::translatePluralInDomain() For the function documentation.
|
||||||
* @see Translator::translatePlural() For the function documentation.
|
|
||||||
*/
|
*/
|
||||||
function mtp($domain, $messageId, $messageId2, $number, $context = null)
|
function mtp($domain, $messageId, $messageId2, $number, $context = null)
|
||||||
{
|
{
|
||||||
return Translator::translatePlural($messageId, $messageId2, $number, $domain, $context);
|
return StaticTranslator::$instance->translatePluralInDomain(
|
||||||
|
$domain,
|
||||||
|
$messageId,
|
||||||
|
$messageId2,
|
||||||
|
$number,
|
||||||
|
$context
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (non-PHPDoc)
|
|
||||||
* @see Translator::translate() For the function documentation.
|
* @see Translator::translate() For the function documentation.
|
||||||
*/
|
*/
|
||||||
function t($messageId, $context = null)
|
function t($messageId, $context = null)
|
||||||
@ -74,7 +76,6 @@ if (extension_loaded('gettext')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (non-PHPDoc)
|
|
||||||
* @see Translator::translate() For the function documentation.
|
* @see Translator::translate() For the function documentation.
|
||||||
*/
|
*/
|
||||||
function mt($domain, $messageId, $context = null)
|
function mt($domain, $messageId, $context = null)
|
||||||
@ -83,7 +84,6 @@ if (extension_loaded('gettext')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (non-PHPDoc)
|
|
||||||
* @see Translator::translatePlural() For the function documentation.
|
* @see Translator::translatePlural() For the function documentation.
|
||||||
*/
|
*/
|
||||||
function tp($messageId, $messageId2, $number, $context = null)
|
function tp($messageId, $messageId2, $number, $context = null)
|
||||||
@ -91,11 +91,11 @@ if (extension_loaded('gettext')) {
|
|||||||
if ((int) $number !== 1) {
|
if ((int) $number !== 1) {
|
||||||
return $messageId2;
|
return $messageId2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $messageId;
|
return $messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (non-PHPDoc)
|
|
||||||
* @see Translator::translatePlural() For the function documentation.
|
* @see Translator::translatePlural() For the function documentation.
|
||||||
*/
|
*/
|
||||||
function mtp($domain, $messageId, $messageId2, $number, $context = null)
|
function mtp($domain, $messageId, $messageId2, $number, $context = null)
|
||||||
@ -103,6 +103,7 @@ if (extension_loaded('gettext')) {
|
|||||||
if ((int) $number !== 1) {
|
if ((int) $number !== 1) {
|
||||||
return $messageId2;
|
return $messageId2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $messageId;
|
return $messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,10 +8,12 @@ use Icinga\Application\Config;
|
|||||||
use Icinga\Application\Logger;
|
use Icinga\Application\Logger;
|
||||||
use Icinga\Exception\IcingaException;
|
use Icinga\Exception\IcingaException;
|
||||||
use Icinga\Exception\NotReadableError;
|
use Icinga\Exception\NotReadableError;
|
||||||
use Icinga\Util\Translator;
|
use ipl\I18n\Translation;
|
||||||
|
|
||||||
abstract class Command
|
abstract class Command
|
||||||
{
|
{
|
||||||
|
use Translation;
|
||||||
|
|
||||||
protected $app;
|
protected $app;
|
||||||
protected $docs;
|
protected $docs;
|
||||||
|
|
||||||
@ -61,6 +63,8 @@ abstract class Command
|
|||||||
$this->isDebugging = $this->params->shift('debug', false);
|
$this->isDebugging = $this->params->shift('debug', false);
|
||||||
$this->configs = [];
|
$this->configs = [];
|
||||||
|
|
||||||
|
$this->translationDomain = $moduleName ?: 'icinga';
|
||||||
|
|
||||||
if ($this->loadEnabledModules) {
|
if ($this->loadEnabledModules) {
|
||||||
try {
|
try {
|
||||||
$app->getModuleManager()->loadEnabledModules();
|
$app->getModuleManager()->loadEnabledModules();
|
||||||
@ -134,21 +138,6 @@ abstract class Command
|
|||||||
return $this->trace;
|
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)
|
public function fail($msg)
|
||||||
{
|
{
|
||||||
throw new IcingaException('%s', $msg);
|
throw new IcingaException('%s', $msg);
|
||||||
|
@ -21,6 +21,8 @@ namespace {
|
|||||||
namespace Icinga\Test {
|
namespace Icinga\Test {
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use ipl\I18n\NoopTranslator;
|
||||||
|
use ipl\I18n\StaticTranslator;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Mockery;
|
use Mockery;
|
||||||
use Icinga\Application\Icinga;
|
use Icinga\Application\Icinga;
|
||||||
@ -140,6 +142,8 @@ namespace Icinga\Test {
|
|||||||
public function setUp(): void
|
public function setUp(): void
|
||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
StaticTranslator::$instance = new NoopTranslator();
|
||||||
$this->setupIcingaMock();
|
$this->setupIcingaMock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,10 +3,14 @@
|
|||||||
|
|
||||||
namespace Icinga\Util;
|
namespace Icinga\Util;
|
||||||
|
|
||||||
use Icinga\Exception\IcingaException;
|
use ipl\I18n\GettextTranslator;
|
||||||
|
use ipl\I18n\Locale;
|
||||||
|
use ipl\I18n\StaticTranslator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to ease internationalization when using gettext
|
* Helper class to ease internationalization when using gettext
|
||||||
|
*
|
||||||
|
* @deprecated Use {@see \ipl\I18n\StaticTranslator::$instance} or {@see \ipl\I18n\Translation} instead
|
||||||
*/
|
*/
|
||||||
class Translator
|
class Translator
|
||||||
{
|
{
|
||||||
@ -20,13 +24,6 @@ class Translator
|
|||||||
*/
|
*/
|
||||||
const DEFAULT_LOCALE = 'en_US';
|
const DEFAULT_LOCALE = 'en_US';
|
||||||
|
|
||||||
/**
|
|
||||||
* Known gettext domains and directories
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private static $knownDomains = array();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translate a string
|
* Translate a string
|
||||||
*
|
*
|
||||||
@ -40,19 +37,7 @@ class Translator
|
|||||||
*/
|
*/
|
||||||
public static function translate($text, $domain, $context = null)
|
public static function translate($text, $domain, $context = null)
|
||||||
{
|
{
|
||||||
if ($context !== null) {
|
return StaticTranslator::$instance->translateInDomain($domain, $text, $context);
|
||||||
$res = self::pgettext($text, $domain, $context);
|
|
||||||
if ($res === $text && $domain !== self::DEFAULT_DOMAIN) {
|
|
||||||
$res = self::pgettext($text, self::DEFAULT_DOMAIN, $context);
|
|
||||||
}
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
|
|
||||||
$res = dgettext($domain, $text);
|
|
||||||
if ($res === $text && $domain !== self::DEFAULT_DOMAIN) {
|
|
||||||
return dgettext(self::DEFAULT_DOMAIN, $text);
|
|
||||||
}
|
|
||||||
return $res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,19 +55,13 @@ class Translator
|
|||||||
*/
|
*/
|
||||||
public static function translatePlural($textSingular, $textPlural, $number, $domain, $context = null)
|
public static function translatePlural($textSingular, $textPlural, $number, $domain, $context = null)
|
||||||
{
|
{
|
||||||
if ($context !== null) {
|
return StaticTranslator::$instance->translatePluralInDomain(
|
||||||
$res = self::pngettext($textSingular, $textPlural, $number, $domain, $context);
|
$domain,
|
||||||
if (($res === $textSingular || $res === $textPlural) && $domain !== self::DEFAULT_DOMAIN) {
|
$textSingular,
|
||||||
$res = self::pngettext($textSingular, $textPlural, $number, self::DEFAULT_DOMAIN, $context);
|
$textPlural,
|
||||||
}
|
$number,
|
||||||
return $res;
|
$context
|
||||||
}
|
);
|
||||||
|
|
||||||
$res = dngettext($domain, $textSingular, $textPlural, $number);
|
|
||||||
if (($res === $textSingular || $res === $textPlural) && $domain !== self::DEFAULT_DOMAIN) {
|
|
||||||
$res = dngettext(self::DEFAULT_DOMAIN, $textSingular, $textPlural, $number);
|
|
||||||
}
|
|
||||||
return $res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,19 +77,7 @@ class Translator
|
|||||||
*/
|
*/
|
||||||
public static function pgettext($text, $domain, $context)
|
public static function pgettext($text, $domain, $context)
|
||||||
{
|
{
|
||||||
$contextString = "{$context}\004{$text}";
|
return StaticTranslator::$instance->translateInDomain($domain, $text, $context);
|
||||||
|
|
||||||
$translation = dcgettext(
|
|
||||||
$domain,
|
|
||||||
$contextString,
|
|
||||||
defined('LC_MESSAGES') ? LC_MESSAGES : LC_ALL
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($translation == $contextString) {
|
|
||||||
return $text;
|
|
||||||
} else {
|
|
||||||
return $translation;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,21 +95,13 @@ class Translator
|
|||||||
*/
|
*/
|
||||||
public static function pngettext($textSingular, $textPlural, $number, $domain, $context)
|
public static function pngettext($textSingular, $textPlural, $number, $domain, $context)
|
||||||
{
|
{
|
||||||
$contextString = "{$context}\004{$textSingular}";
|
return StaticTranslator::$instance->translatePluralInDomain(
|
||||||
|
|
||||||
$translation = dcngettext(
|
|
||||||
$domain,
|
$domain,
|
||||||
$contextString,
|
$textSingular,
|
||||||
$textPlural,
|
$textPlural,
|
||||||
$number,
|
$number,
|
||||||
defined('LC_MESSAGES') ? LC_MESSAGES : LC_ALL
|
$context
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($translation == $contextString || $translation == $textPlural) {
|
|
||||||
return ($number == 1 ? $textSingular : $textPlural);
|
|
||||||
} else {
|
|
||||||
return $translation;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -151,19 +110,14 @@ class Translator
|
|||||||
* @param string $name The name of the domain to register
|
* @param string $name The name of the domain to register
|
||||||
* @param string $directory The directory where message catalogs can be found
|
* @param string $directory The directory where message catalogs can be found
|
||||||
*
|
*
|
||||||
* @throws IcingaException In case the domain was not successfully registered
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function registerDomain($name, $directory)
|
public static function registerDomain($name, $directory)
|
||||||
{
|
{
|
||||||
if (bindtextdomain($name, $directory) === false) {
|
/** @var GettextTranslator $translator */
|
||||||
throw new IcingaException(
|
$translator = StaticTranslator::$instance;
|
||||||
'Cannot register domain \'%s\' with path \'%s\'',
|
|
||||||
$name,
|
$translator->addTranslationDirectory($directory, $name);
|
||||||
$directory
|
|
||||||
);
|
|
||||||
}
|
|
||||||
bind_textdomain_codeset($name, 'UTF-8');
|
|
||||||
self::$knownDomains[$name] = $directory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,26 +125,14 @@ class Translator
|
|||||||
*
|
*
|
||||||
* @param string $localeName The name of the locale to use
|
* @param string $localeName The name of the locale to use
|
||||||
*
|
*
|
||||||
* @throws IcingaException In case the locale's name is invalid
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function setupLocale($localeName)
|
public static function setupLocale($localeName)
|
||||||
{
|
{
|
||||||
if (setlocale(LC_ALL, $localeName . '.UTF-8') === false && setlocale(LC_ALL, $localeName) === false) {
|
/** @var GettextTranslator $translator */
|
||||||
setlocale(LC_ALL, 'C'); // C == "use whatever is hardcoded"
|
$translator = StaticTranslator::$instance;
|
||||||
if ($localeName !== self::DEFAULT_LOCALE) {
|
|
||||||
throw new IcingaException(
|
|
||||||
'Cannot set locale \'%s\' for category \'LC_ALL\'',
|
|
||||||
$localeName
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$locale = setlocale(LC_ALL, 0);
|
|
||||||
putenv('LC_ALL=' . $locale); // Failsafe, Win and Unix
|
|
||||||
putenv('LANG=' . $locale); // Windows fix, untested
|
|
||||||
|
|
||||||
// https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html
|
$translator->setLocale($localeName);
|
||||||
putenv('LANGUAGE=' . $localeName . ':' . getenv('LANGUAGE'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -202,18 +144,14 @@ class Translator
|
|||||||
*/
|
*/
|
||||||
public static function splitLocaleCode($locale = null)
|
public static function splitLocaleCode($locale = null)
|
||||||
{
|
{
|
||||||
$matches = array();
|
/** @var GettextTranslator $translator */
|
||||||
$locale = $locale !== null ? $locale : setlocale(LC_ALL, 0);
|
$translator = StaticTranslator::$instance;
|
||||||
if (preg_match('@([a-z]{2})[_-]([a-z]{2})@i', $locale, $matches)) {
|
|
||||||
list($languageCode, $countryCode) = array_slice($matches, 1);
|
if ($locale === null) {
|
||||||
} elseif ($locale === 'C') {
|
$locale = $translator->getLocale();
|
||||||
list($languageCode, $countryCode) = preg_split('@[_-]@', static::DEFAULT_LOCALE, 2);
|
|
||||||
} else {
|
|
||||||
$languageCode = $locale;
|
|
||||||
$countryCode = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (object) array('language' => $languageCode, 'country' => $countryCode);
|
return (new Locale())->parseLocale($locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -223,21 +161,10 @@ class Translator
|
|||||||
*/
|
*/
|
||||||
public static function getAvailableLocaleCodes()
|
public static function getAvailableLocaleCodes()
|
||||||
{
|
{
|
||||||
$codes = array(static::DEFAULT_LOCALE);
|
/** @var GettextTranslator $translator */
|
||||||
foreach (array_values(self::$knownDomains) as $directory) {
|
$translator = StaticTranslator::$instance;
|
||||||
$dh = opendir($directory);
|
|
||||||
while (false !== ($name = readdir($dh))) {
|
|
||||||
if (substr($name, 0, 1) !== '.'
|
|
||||||
&& false === in_array($name, $codes)
|
|
||||||
&& is_dir($directory . DIRECTORY_SEPARATOR . $name)
|
|
||||||
) {
|
|
||||||
$codes[] = $name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort($codes);
|
|
||||||
|
|
||||||
return $codes;
|
return $translator->listLocales();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -249,68 +176,9 @@ class Translator
|
|||||||
*/
|
*/
|
||||||
public static function getPreferredLocaleCode($header)
|
public static function getPreferredLocaleCode($header)
|
||||||
{
|
{
|
||||||
$headerValues = explode(',', $header);
|
/** @var GettextTranslator $translator */
|
||||||
for ($i = 0; $i < count($headerValues); $i++) {
|
$translator = StaticTranslator::$instance;
|
||||||
// In order to accomplish a stable sort we need to take the original
|
|
||||||
// index into account as well during element comparison
|
|
||||||
$headerValues[$i] = array($headerValues[$i], $i);
|
|
||||||
}
|
|
||||||
usort( // Sort DESC but keep equal elements ASC
|
|
||||||
$headerValues,
|
|
||||||
function ($a, $b) {
|
|
||||||
$tagA = explode(';', $a[0], 2);
|
|
||||||
$tagB = explode(';', $b[0], 2);
|
|
||||||
$qValA = (float) (strpos($a[0], ';') > 0 ? substr(array_pop($tagA), 2) : 1);
|
|
||||||
$qValB = (float) (strpos($b[0], ';') > 0 ? substr(array_pop($tagB), 2) : 1);
|
|
||||||
return $qValA < $qValB ? 1 : ($qValA > $qValB ? -1 : ($a[1] > $b[1] ? 1 : ($a[1] < $b[1] ? -1 : 0)));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
for ($i = 0; $i < count($headerValues); $i++) {
|
|
||||||
// We need to reset the array to its original structure once it's sorted
|
|
||||||
$headerValues[$i] = $headerValues[$i][0];
|
|
||||||
}
|
|
||||||
$requestedLocales = array();
|
|
||||||
foreach ($headerValues as $headerValue) {
|
|
||||||
if (strpos($headerValue, ';') > 0) {
|
|
||||||
$parts = explode(';', $headerValue, 2);
|
|
||||||
$headerValue = $parts[0];
|
|
||||||
}
|
|
||||||
$requestedLocales[] = str_replace('-', '_', $headerValue);
|
|
||||||
}
|
|
||||||
$requestedLocales = array_combine(
|
|
||||||
array_map('strtolower', array_values($requestedLocales)),
|
|
||||||
array_values($requestedLocales)
|
|
||||||
);
|
|
||||||
|
|
||||||
$availableLocales = static::getAvailableLocaleCodes();
|
return (new Locale())->getPreferred($header, $translator->listLocales());
|
||||||
$availableLocales = array_combine(
|
|
||||||
array_map('strtolower', array_values($availableLocales)),
|
|
||||||
array_values($availableLocales)
|
|
||||||
);
|
|
||||||
|
|
||||||
$similarMatch = null;
|
|
||||||
|
|
||||||
foreach ($requestedLocales as $requestedLocaleLowered => $requestedLocale) {
|
|
||||||
$localeObj = static::splitLocaleCode($requestedLocaleLowered);
|
|
||||||
|
|
||||||
if (isset($availableLocales[$requestedLocaleLowered])
|
|
||||||
&& (! $similarMatch || static::splitLocaleCode($similarMatch)->language === $localeObj->language)
|
|
||||||
) {
|
|
||||||
// Prefer perfect match only if no similar match has been found yet or the perfect match is more precise
|
|
||||||
// than the similar match
|
|
||||||
return $availableLocales[$requestedLocaleLowered];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! $similarMatch) {
|
|
||||||
foreach ($availableLocales as $availableLocaleLowered => $availableLocale) {
|
|
||||||
if (static::splitLocaleCode($availableLocaleLowered)->language === $localeObj->language) {
|
|
||||||
$similarMatch = $availableLocaleLowered;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $similarMatch ? $availableLocales[$similarMatch] : static::DEFAULT_LOCALE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
namespace Icinga\Web\Controller;
|
namespace Icinga\Web\Controller;
|
||||||
|
|
||||||
|
use ipl\I18n\Translation;
|
||||||
use Zend_Controller_Action;
|
use Zend_Controller_Action;
|
||||||
use Zend_Controller_Action_HelperBroker;
|
use Zend_Controller_Action_HelperBroker;
|
||||||
use Zend_Controller_Request_Abstract;
|
use Zend_Controller_Request_Abstract;
|
||||||
@ -16,7 +17,6 @@ use Icinga\Exception\ProgrammingError;
|
|||||||
use Icinga\File\Pdf;
|
use Icinga\File\Pdf;
|
||||||
use Icinga\Forms\AutoRefreshForm;
|
use Icinga\Forms\AutoRefreshForm;
|
||||||
use Icinga\Security\SecurityException;
|
use Icinga\Security\SecurityException;
|
||||||
use Icinga\Util\Translator;
|
|
||||||
use Icinga\Web\Session;
|
use Icinga\Web\Session;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\UrlParams;
|
use Icinga\Web\UrlParams;
|
||||||
@ -40,6 +40,8 @@ use Icinga\Web\Window;
|
|||||||
*/
|
*/
|
||||||
class ActionController extends Zend_Controller_Action
|
class ActionController extends Zend_Controller_Action
|
||||||
{
|
{
|
||||||
|
use Translation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The login route to use when requiring authentication
|
* The login route to use when requiring authentication
|
||||||
*/
|
*/
|
||||||
@ -131,7 +133,8 @@ class ActionController extends Zend_Controller_Action
|
|||||||
|
|
||||||
$moduleName = $this->getModuleName();
|
$moduleName = $this->getModuleName();
|
||||||
$this->view->defaultTitle = static::DEFAULT_TITLE;
|
$this->view->defaultTitle = static::DEFAULT_TITLE;
|
||||||
$this->view->translationDomain = $moduleName !== 'default' ? $moduleName : 'icinga';
|
$this->translationDomain = $moduleName !== 'default' ? $moduleName : 'icinga';
|
||||||
|
$this->view->translationDomain = $this->translationDomain;
|
||||||
$this->_helper->layout()->isIframe = $request->getUrl()->shift('isIframe');
|
$this->_helper->layout()->isIframe = $request->getUrl()->shift('isIframe');
|
||||||
$this->_helper->layout()->showFullscreen = $request->getUrl()->shift('showFullscreen');
|
$this->_helper->layout()->showFullscreen = $request->getUrl()->shift('showFullscreen');
|
||||||
$this->_helper->layout()->moduleName = $moduleName;
|
$this->_helper->layout()->moduleName = $moduleName;
|
||||||
@ -305,42 +308,6 @@ class ActionController extends Zend_Controller_Action
|
|||||||
return $this->view->tabs;
|
return $this->view->tabs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
* @param string|null $context Optional parameter for context based translation
|
|
||||||
*
|
|
||||||
* @return string The translated string
|
|
||||||
*/
|
|
||||||
public function translate($text, $context = null)
|
|
||||||
{
|
|
||||||
return Translator::translate($text, $this->view->translationDomain, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate a plural string
|
|
||||||
*
|
|
||||||
* @param string $textSingular The string in singular form to translate
|
|
||||||
* @param string $textPlural The string in plural form to translate
|
|
||||||
* @param string $number The number to get the plural or singular string
|
|
||||||
* @param string|null $context Optional parameter for context based translation
|
|
||||||
*
|
|
||||||
* @return string The translated string
|
|
||||||
*/
|
|
||||||
public function translatePlural($textSingular, $textPlural, $number, $context = null)
|
|
||||||
{
|
|
||||||
return Translator::translatePlural(
|
|
||||||
$textSingular,
|
|
||||||
$textPlural,
|
|
||||||
$number,
|
|
||||||
$this->view->translationDomain,
|
|
||||||
$context
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function ignoreXhrBody()
|
protected function ignoreXhrBody()
|
||||||
{
|
{
|
||||||
if ($this->isXhr()) {
|
if ($this->isXhr()) {
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
namespace Icinga\Web;
|
namespace Icinga\Web;
|
||||||
|
|
||||||
use Icinga\Web\Form\Element\DateTimePicker;
|
use Icinga\Web\Form\Element\DateTimePicker;
|
||||||
|
use ipl\I18n\Translation;
|
||||||
use Zend_Config;
|
use Zend_Config;
|
||||||
use Zend_Form;
|
use Zend_Form;
|
||||||
use Zend_Form_Element;
|
use Zend_Form_Element;
|
||||||
@ -12,7 +13,6 @@ use Icinga\Application\Icinga;
|
|||||||
use Icinga\Authentication\Auth;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
use Icinga\Security\SecurityException;
|
use Icinga\Security\SecurityException;
|
||||||
use Icinga\Util\Translator;
|
|
||||||
use Icinga\Web\Form\ErrorLabeller;
|
use Icinga\Web\Form\ErrorLabeller;
|
||||||
use Icinga\Web\Form\Decorator\Autosubmit;
|
use Icinga\Web\Form\Decorator\Autosubmit;
|
||||||
use Icinga\Web\Form\Element\CsrfCounterMeasure;
|
use Icinga\Web\Form\Element\CsrfCounterMeasure;
|
||||||
@ -27,6 +27,11 @@ use Icinga\Web\Form\Element\CsrfCounterMeasure;
|
|||||||
*/
|
*/
|
||||||
class Form extends Zend_Form
|
class Form extends Zend_Form
|
||||||
{
|
{
|
||||||
|
use Translation {
|
||||||
|
translate as i18nTranslate;
|
||||||
|
translatePlural as i18nTranslatePlural;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The suffix to append to a field's hidden default field name
|
* The suffix to append to a field's hidden default field name
|
||||||
*/
|
*/
|
||||||
@ -1519,7 +1524,9 @@ class Form extends Zend_Form
|
|||||||
*/
|
*/
|
||||||
protected function translate($text, $context = null)
|
protected function translate($text, $context = null)
|
||||||
{
|
{
|
||||||
return Translator::translate($text, $this->getTranslationDomain(), $context);
|
$this->translationDomain = $this->getTranslationDomain();
|
||||||
|
|
||||||
|
return $this->i18nTranslate($text, $context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1534,13 +1541,9 @@ class Form extends Zend_Form
|
|||||||
*/
|
*/
|
||||||
protected function translatePlural($textSingular, $textPlural, $number, $context = null)
|
protected function translatePlural($textSingular, $textPlural, $number, $context = null)
|
||||||
{
|
{
|
||||||
return Translator::translatePlural(
|
$this->translationDomain = $this->getTranslationDomain();
|
||||||
$textSingular,
|
|
||||||
$textPlural,
|
return $this->i18nTranslatePlural($textSingular, $textPlural, $number, $context);
|
||||||
$number,
|
|
||||||
$this->getTranslationDomain(),
|
|
||||||
$context
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,10 +5,10 @@ namespace Icinga\Web;
|
|||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Icinga\Application\Icinga;
|
use Icinga\Application\Icinga;
|
||||||
|
use ipl\I18n\Translation;
|
||||||
use Zend_View_Abstract;
|
use Zend_View_Abstract;
|
||||||
use Icinga\Authentication\Auth;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
use Icinga\Util\Translator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Icinga view
|
* Icinga view
|
||||||
@ -54,6 +54,8 @@ use Icinga\Util\Translator;
|
|||||||
*/
|
*/
|
||||||
class View extends Zend_View_Abstract
|
class View extends Zend_View_Abstract
|
||||||
{
|
{
|
||||||
|
use Translation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Charset to be used - we only support UTF-8
|
* Charset to be used - we only support UTF-8
|
||||||
*/
|
*/
|
||||||
@ -178,21 +180,6 @@ class View extends Zend_View_Abstract
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function translate($text, $context = null)
|
|
||||||
{
|
|
||||||
return Translator::translate($text, $this->translationDomain, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate a plural string
|
|
||||||
*
|
|
||||||
* @see Translator::translatePlural()
|
|
||||||
*/
|
|
||||||
public function translatePlural($textSingular, $textPlural, $number, $context = null)
|
|
||||||
{
|
|
||||||
return Translator::translatePlural($textSingular, $textPlural, $number, $this->translationDomain, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load helpers
|
* Load helpers
|
||||||
*/
|
*/
|
||||||
|
@ -9,8 +9,8 @@ use Icinga\Application\Icinga;
|
|||||||
use Icinga\Application\Modules\DashboardContainer;
|
use Icinga\Application\Modules\DashboardContainer;
|
||||||
use Icinga\Cli\Command;
|
use Icinga\Cli\Command;
|
||||||
use Icinga\Application\Logger;
|
use Icinga\Application\Logger;
|
||||||
use Icinga\Exception\IcingaException;
|
use ipl\I18n\GettextTranslator;
|
||||||
use Icinga\Util\Translator;
|
use ipl\I18n\StaticTranslator;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
|
|
||||||
class DashboardCommand extends Command
|
class DashboardCommand extends Command
|
||||||
@ -34,25 +34,23 @@ class DashboardCommand extends Command
|
|||||||
// Calling getDashboard() results in Url::fromPath() getting called as well == the CLI's death
|
// Calling getDashboard() results in Url::fromPath() getting called as well == the CLI's death
|
||||||
$paneItemsProperty = $moduleReflection->getProperty('paneItems');
|
$paneItemsProperty = $moduleReflection->getProperty('paneItems');
|
||||||
$paneItemsProperty->setAccessible(true);
|
$paneItemsProperty->setAccessible(true);
|
||||||
// Again, no direct way to access this nor to let the module setup its own translation domain
|
|
||||||
$localeDirProperty = $moduleReflection->getProperty('localedir');
|
|
||||||
$localeDirProperty->setAccessible(true);
|
|
||||||
|
|
||||||
$locales = Translator::getAvailableLocaleCodes();
|
/** @var GettextTranslator $translator */
|
||||||
$modules = Icinga::app()->getModuleManager()->loadEnabledModules()->getLoadedModules();
|
$translator = StaticTranslator::$instance;
|
||||||
|
|
||||||
|
$locales = $translator->listLocales();
|
||||||
|
$modules = Icinga::app()->getModuleManager()->getLoadedModules();
|
||||||
foreach ($this->listDashboardConfigs() as $path) {
|
foreach ($this->listDashboardConfigs() as $path) {
|
||||||
Logger::info('Migrating dashboard config: %s', $path);
|
Logger::info('Migrating dashboard config: %s', $path);
|
||||||
|
|
||||||
$config = Config::fromIni($path);
|
$config = Config::fromIni($path);
|
||||||
foreach ($modules as $module) {
|
foreach ($modules as $module) {
|
||||||
$localePath = $localeDirProperty->getValue($module);
|
if (! $module->hasLocales()) {
|
||||||
if (! is_dir($localePath)) {
|
|
||||||
// Modules without any translations are not affected
|
// Modules without any translations are not affected
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$launchConfigScriptMethod->invoke($module);
|
$launchConfigScriptMethod->invoke($module);
|
||||||
Translator::registerDomain($module->getName(), $localePath);
|
|
||||||
|
|
||||||
foreach ($locales as $locale) {
|
foreach ($locales as $locale) {
|
||||||
if ($locale === 'en_US') {
|
if ($locale === 'en_US') {
|
||||||
@ -60,8 +58,8 @@ class DashboardCommand extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Translator::setupLocale($locale);
|
$translator->setLocale($locale);
|
||||||
} catch (IcingaException $e) {
|
} catch (Exception $e) {
|
||||||
Logger::debug('Ignoring locale "%s". Reason: %s', $locale, $e->getMessage());
|
Logger::debug('Ignoring locale "%s". Reason: %s', $locale, $e->getMessage());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -4,48 +4,21 @@
|
|||||||
namespace Icinga\Module\Translation\Clicommands;
|
namespace Icinga\Module\Translation\Clicommands;
|
||||||
|
|
||||||
use Icinga\Module\Translation\Cli\TranslationCommand;
|
use Icinga\Module\Translation\Cli\TranslationCommand;
|
||||||
use Icinga\Module\Translation\Util\GettextTranslationHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translation compiler
|
* Translation compiler
|
||||||
*
|
*
|
||||||
* This command will compile the PO-file of a domain. The actions below allow
|
* This command will compile gettext catalogs of modules.
|
||||||
* 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
|
* Once a catalog is compiled its content is used by Icinga Web 2 to display
|
||||||
* identified by their name.
|
|
||||||
*
|
|
||||||
* Once a PO-file is compiled its content is used by Icinga Web 2 to display
|
|
||||||
* messages in the configured language.
|
* messages in the configured language.
|
||||||
*/
|
*/
|
||||||
class CompileCommand extends TranslationCommand
|
class CompileCommand extends TranslationCommand
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Compile the global domain
|
* Compile a module gettext catalog
|
||||||
*
|
*
|
||||||
* This will compile the PO-file of the global 'icinga' domain.
|
* This will compile the catalog of the given module and locale.
|
||||||
*
|
|
||||||
* USAGE:
|
|
||||||
*
|
|
||||||
* icingacli translation compile icinga <locale>
|
|
||||||
*
|
|
||||||
* EXAMPLES:
|
|
||||||
*
|
|
||||||
* icingacli translation compile icinga de_DE
|
|
||||||
* icingacli translation compile icinga fr_FR
|
|
||||||
*/
|
|
||||||
public function icingaAction()
|
|
||||||
{
|
|
||||||
$locale = $this->validateLocaleCode($this->params->shift());
|
|
||||||
|
|
||||||
$helper = $this->getTranslationHelper($locale);
|
|
||||||
$helper->compileIcingaTranslation();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compile a module domain
|
|
||||||
*
|
|
||||||
* This will compile the PO-file of the given module domain.
|
|
||||||
*
|
*
|
||||||
* USAGE:
|
* USAGE:
|
||||||
*
|
*
|
||||||
@ -53,8 +26,8 @@ class CompileCommand extends TranslationCommand
|
|||||||
*
|
*
|
||||||
* EXAMPLES:
|
* EXAMPLES:
|
||||||
*
|
*
|
||||||
* icingacli translation compile monitoring de_DE
|
* icingacli translation compile demo de_DE
|
||||||
* icingacli trnslations compile monitoring de_DE
|
* icingacli translation compile demo fr_FR
|
||||||
*/
|
*/
|
||||||
public function moduleAction()
|
public function moduleAction()
|
||||||
{
|
{
|
||||||
|
@ -4,48 +4,21 @@
|
|||||||
namespace Icinga\Module\Translation\Clicommands;
|
namespace Icinga\Module\Translation\Clicommands;
|
||||||
|
|
||||||
use Icinga\Module\Translation\Cli\TranslationCommand;
|
use Icinga\Module\Translation\Cli\TranslationCommand;
|
||||||
use Icinga\Module\Translation\Util\GettextTranslationHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translation updater
|
* Translation updater
|
||||||
*
|
*
|
||||||
* This command will create a new or update any existing PO-file of a domain. The
|
* This command will create a new or update any existing gettext catalog of a module.
|
||||||
* 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
|
* Once a catalog has been created/updated one can open it with a editor for
|
||||||
* 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.
|
* PO-files and start with the actual translation.
|
||||||
*/
|
*/
|
||||||
class RefreshCommand extends TranslationCommand
|
class RefreshCommand extends TranslationCommand
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Touch the global domain
|
* Generate or update a module gettext catalog
|
||||||
*
|
*
|
||||||
* This will create/update the PO-file of the global 'icinga' domain.
|
* This will create/update the PO-file of the given module and locale.
|
||||||
*
|
|
||||||
* USAGE:
|
|
||||||
*
|
|
||||||
* icingacli translation refresh icinga <locale>
|
|
||||||
*
|
|
||||||
* EXAMPLES:
|
|
||||||
*
|
|
||||||
* icingacli translation refresh icinga de_DE
|
|
||||||
* icingacli translation refresh icinga fr_FR
|
|
||||||
*/
|
|
||||||
public function icingaAction()
|
|
||||||
{
|
|
||||||
$locale = $this->validateLocaleCode($this->params->shift());
|
|
||||||
|
|
||||||
$helper = $this->getTranslationHelper($locale);
|
|
||||||
$helper->updateIcingaTranslations();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Touch a module domain
|
|
||||||
*
|
|
||||||
* This will create/update the PO-file of the given module domain.
|
|
||||||
*
|
*
|
||||||
* USAGE:
|
* USAGE:
|
||||||
*
|
*
|
||||||
@ -53,8 +26,8 @@ class RefreshCommand extends TranslationCommand
|
|||||||
*
|
*
|
||||||
* EXAMPLES:
|
* EXAMPLES:
|
||||||
*
|
*
|
||||||
* icingacli translation refresh module monitoring de_DE
|
* icingacli translation refresh module demo de_DE
|
||||||
* icingacli translation refresh module monitoring fr_FR
|
* icingacli translation refresh module demo fr_FR
|
||||||
*/
|
*/
|
||||||
public function moduleAction()
|
public function moduleAction()
|
||||||
{
|
{
|
||||||
|
@ -6,7 +6,8 @@ namespace Icinga\Module\Translation\Clicommands;
|
|||||||
use Icinga\Date\DateFormatter;
|
use Icinga\Date\DateFormatter;
|
||||||
use Icinga\Module\Translation\Cli\ArrayToTextTableHelper;
|
use Icinga\Module\Translation\Cli\ArrayToTextTableHelper;
|
||||||
use Icinga\Module\Translation\Cli\TranslationCommand;
|
use Icinga\Module\Translation\Cli\TranslationCommand;
|
||||||
use Icinga\Util\Translator;
|
use ipl\I18n\GettextTranslator;
|
||||||
|
use ipl\I18n\StaticTranslator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timestamp test helper
|
* Timestamp test helper
|
||||||
@ -89,12 +90,19 @@ class TestCommand extends TranslationCommand
|
|||||||
foreach ($this->params->getAllStandalone() as $l) {
|
foreach ($this->params->getAllStandalone() as $l) {
|
||||||
$this->locales[] = $l;
|
$this->locales[] = $l;
|
||||||
}
|
}
|
||||||
// TODO: get from to environment by default?
|
|
||||||
|
if (empty($this->locales)) {
|
||||||
|
/** @var GettextTranslator $translator */
|
||||||
|
$translator = StaticTranslator::$instance;
|
||||||
|
$this->locales = $translator->listLocales();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function callTranslated($callback, $arguments, $locale = 'C')
|
protected function callTranslated($callback, $arguments, $locale = 'en_US')
|
||||||
{
|
{
|
||||||
Translator::setupLocale($locale);
|
/** @var GettextTranslator $translator */
|
||||||
|
$translator = StaticTranslator::$instance;
|
||||||
|
$translator->setLocale($locale);
|
||||||
return call_user_func_array($callback, $arguments);
|
return call_user_func_array($callback, $arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
# Introduction <a id="module-translation-introduction"></a>
|
# Introduction <a id="module-translation-introduction"></a>
|
||||||
|
|
||||||
Icinga Web 2 provides localization out of the box - for the core application and the modules, that means
|
Icinga Web 2 provides localization out of the box - for itself and the core modules.
|
||||||
that you can with a lightness use existent localizations, update or even create you own localizations.
|
This module is for third party module developers to aid them to localize their work.
|
||||||
|
|
||||||
The chapters [Translation for Developers](03-Translation.md#module-translation-developers),
|
The chapters [Translation for Developers](03-Translation.md#module-translation-developers),
|
||||||
[Translation for Translators](03-Translation.md#module-translation-translators) and
|
[Translation for Translators](03-Translation.md#module-translation-translators) and
|
||||||
[Testing Translations](03-Translation.md#module-translation-tests) will introduce and explain you, how to take
|
[Testing Translations](03-Translation.md#module-translation-tests) will introduce and
|
||||||
part on localizing Icinga Web 2 for different languages and how to use the
|
explain you, how to take part on localizing modules to different languages.
|
||||||
`translation module` to make your life much easier.
|
|
||||||
|
|
||||||
## Translation for Developers <a id="module-translation-developers"></a>
|
## Translation for Developers <a id="module-translation-developers"></a>
|
||||||
|
|
||||||
|
@ -65,13 +65,6 @@ class GettextTranslationHelper
|
|||||||
*/
|
*/
|
||||||
private $locale;
|
private $locale;
|
||||||
|
|
||||||
/**
|
|
||||||
* The path to the Zend application root
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $appDir;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The path to the module, if any
|
* The path to the module, if any
|
||||||
*
|
*
|
||||||
@ -79,13 +72,6 @@ class GettextTranslationHelper
|
|||||||
*/
|
*/
|
||||||
private $moduleDir;
|
private $moduleDir;
|
||||||
|
|
||||||
/**
|
|
||||||
* Path to the Icinga library
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $libDir;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The path to the file catalog
|
* The path to the file catalog
|
||||||
*
|
*
|
||||||
@ -115,9 +101,7 @@ class GettextTranslationHelper
|
|||||||
*/
|
*/
|
||||||
public function __construct(ApplicationBootstrap $bootstrap, $locale)
|
public function __construct(ApplicationBootstrap $bootstrap, $locale)
|
||||||
{
|
{
|
||||||
$this->moduleMgr = $bootstrap->getModuleManager()->loadEnabledModules();
|
$this->moduleMgr = $bootstrap->getModuleManager();
|
||||||
$this->appDir = $bootstrap->getApplicationDir();
|
|
||||||
$this->libDir = $bootstrap->getLibraryDir('Icinga');
|
|
||||||
$this->locale = $locale;
|
$this->locale = $locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,32 +142,6 @@ class GettextTranslationHelper
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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->version = 'None'; // TODO: Access icinga version from a file or property
|
|
||||||
|
|
||||||
$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
|
* Update the translation table for a particular module
|
||||||
*
|
*
|
||||||
@ -214,25 +172,6 @@ class GettextTranslationHelper
|
|||||||
$this->updateTranslationTable();
|
$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
|
* Compile the translation table for a particular module
|
||||||
*
|
*
|
||||||
@ -296,8 +235,12 @@ class GettextTranslationHelper
|
|||||||
'--language=PHP',
|
'--language=PHP',
|
||||||
'--keyword=translate',
|
'--keyword=translate',
|
||||||
'--keyword=translate:1,2c',
|
'--keyword=translate:1,2c',
|
||||||
|
'--keyword=translateInDomain:2',
|
||||||
|
'--keyword=translateInDomain:2,3c',
|
||||||
'--keyword=translatePlural:1,2',
|
'--keyword=translatePlural:1,2',
|
||||||
'--keyword=translatePlural:1,2,4c',
|
'--keyword=translatePlural:1,2,4c',
|
||||||
|
'--keyword=translatePluralInDomain:2,3',
|
||||||
|
'--keyword=translatePluralInDomain:2,3,5c',
|
||||||
'--keyword=mt:2',
|
'--keyword=mt:2',
|
||||||
'--keyword=mt:2,3c',
|
'--keyword=mt:2,3c',
|
||||||
'--keyword=mtp:2,3',
|
'--keyword=mtp:2,3',
|
||||||
@ -326,15 +269,15 @@ class GettextTranslationHelper
|
|||||||
private function updateHeader($path)
|
private function updateHeader($path)
|
||||||
{
|
{
|
||||||
$headerInfo = array(
|
$headerInfo = array(
|
||||||
'title' => 'Icinga Web 2 - Head for multiple monitoring backends',
|
'title' => $this->moduleMgr->getModule($this->moduleName)->getTitle(),
|
||||||
'copyright_holder' => 'Icinga Development Team',
|
'copyright_holder' => 'TEAM NAME',
|
||||||
'copyright_year' => date('Y'),
|
'copyright_year' => date('Y'),
|
||||||
'author_name' => 'FIRST AUTHOR',
|
'author_name' => 'FIRST AUTHOR',
|
||||||
'author_mail' => 'EMAIL@ADDRESS',
|
'author_mail' => 'EMAIL@ADDRESS',
|
||||||
'author_year' => 'YEAR',
|
'author_year' => 'YEAR',
|
||||||
'project_name' => $this->moduleName ? ucfirst($this->moduleName) . ' Module' : 'Icinga Web 2',
|
'project_name' => ucfirst($this->moduleName) . ' Module',
|
||||||
'project_version' => $this->version,
|
'project_version' => $this->version,
|
||||||
'project_bug_mail' => 'dev@icinga.com',
|
'project_bug_mail' => 'ISSUE TRACKER',
|
||||||
'pot_creation_date' => date('Y-m-d H:iO'),
|
'pot_creation_date' => date('Y-m-d H:iO'),
|
||||||
'po_revision_date' => 'YEAR-MO-DA HO:MI+ZONE',
|
'po_revision_date' => 'YEAR-MO-DA HO:MI+ZONE',
|
||||||
'translator_name' => 'FULL NAME',
|
'translator_name' => 'FULL NAME',
|
||||||
@ -418,7 +361,7 @@ class GettextTranslationHelper
|
|||||||
{
|
{
|
||||||
shell_exec(sprintf(
|
shell_exec(sprintf(
|
||||||
"sed -i 's;%s;../../../..;g' %s",
|
"sed -i 's;%s;../../../..;g' %s",
|
||||||
$this->moduleDir ?: dirname($this->appDir),
|
$this->moduleDir,
|
||||||
$path
|
$path
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -433,12 +376,7 @@ class GettextTranslationHelper
|
|||||||
$catalog = new File($this->catalogPath, 'w');
|
$catalog = new File($this->catalogPath, 'w');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($this->moduleDir) {
|
$this->getSourceFileNames($this->moduleDir, $catalog);
|
||||||
$this->getSourceFileNames($this->moduleDir, $catalog);
|
|
||||||
} else {
|
|
||||||
$this->getSourceFileNames($this->appDir, $catalog);
|
|
||||||
$this->getSourceFileNames($this->libDir, $catalog);
|
|
||||||
}
|
|
||||||
} catch (Exception $error) {
|
} catch (Exception $error) {
|
||||||
throw $error;
|
throw $error;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Module: translation
|
Module: translation
|
||||||
Version: 2.8.2
|
Version: 2.8.2
|
||||||
Description: Translation module
|
Description: Translation module
|
||||||
This module allows developers and translators to translate Icinga Web 2 and
|
This module allows developers and translators to translate modules for multiple
|
||||||
its modules for multiple languages. You do not need this module to run an
|
languages. You do not need this module to run an internationalized web frontend.
|
||||||
internationalized web frontend. This is only for people who want to contribute
|
This is only for people who want to contribute translations or translate just
|
||||||
translations or translate just their own modules.
|
their own modules.
|
||||||
|
@ -1,286 +0,0 @@
|
|||||||
<?php
|
|
||||||
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
|
||||||
|
|
||||||
namespace Tests\Icinga\Util;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use Icinga\Test\BaseTestCase;
|
|
||||||
use Icinga\Util\Translator;
|
|
||||||
|
|
||||||
class TranslatorWithHardcodedLocaleCodes extends Translator
|
|
||||||
{
|
|
||||||
public static function getAvailableLocaleCodes()
|
|
||||||
{
|
|
||||||
return array('en_US', 'de_DE', 'de_AT');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TranslatorTest extends BaseTestCase
|
|
||||||
{
|
|
||||||
public function setUp(): void
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
Translator::registerDomain('icingatest', BaseTestCase::$testDir . '/res/locale');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testWhetherGetAvailableLocaleCodesReturnsAllAvailableLocaleCodes()
|
|
||||||
{
|
|
||||||
$expected = array(Translator::DEFAULT_LOCALE, 'de_DE', 'fr_FR');
|
|
||||||
$result = Translator::getAvailableLocaleCodes();
|
|
||||||
|
|
||||||
sort($expected);
|
|
||||||
sort($result);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
$expected,
|
|
||||||
$result,
|
|
||||||
'Translator::getAvailableLocaleCodes does not return all available locale codes'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testWhetherSetupLocaleSetsUpTheGivenLocale()
|
|
||||||
{
|
|
||||||
Translator::setupLocale('de_DE');
|
|
||||||
$this->assertContains(
|
|
||||||
setlocale(LC_ALL, 0),
|
|
||||||
array('de_DE', 'de_DE.UTF-8'),
|
|
||||||
'Translator::setupLocale does not properly set up a given locale'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testWhetherSetupLocaleThrowsAnExceptionWhenGivenAnInvalidLocale()
|
|
||||||
{
|
|
||||||
$this->expectException(\Icinga\Exception\IcingaException::class);
|
|
||||||
|
|
||||||
Translator::setupLocale('foobar');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testWhetherSetupLocaleSetsCAsLocaleWhenGivenAnInvalidLocale()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
Translator::setupLocale('foobar');
|
|
||||||
$this->fail('Translator::setupLocale does not throw an exception when given an invalid locale');
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$this->assertEquals(
|
|
||||||
'C',
|
|
||||||
setlocale(LC_ALL, 0),
|
|
||||||
'Translator::setupLocale does not set C as locale in case the given one is invalid'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testWhetherTranslateReturnsTheCorrectMessageForTheCurrentLocale()
|
|
||||||
{
|
|
||||||
Translator::setupLocale('de_DE');
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
'Lorem ipsum dolor sit amet!',
|
|
||||||
Translator::translate('Lorem ipsum dolor sit amet', 'icingatest'),
|
|
||||||
'Translator::translate does not translate the given message correctly to German'
|
|
||||||
);
|
|
||||||
|
|
||||||
Translator::setupLocale('fr_FR');
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
'Lorem ipsum dolor sit amet?',
|
|
||||||
Translator::translate('Lorem ipsum dolor sit amet', 'icingatest'),
|
|
||||||
'Translator::translate does not translate the given message correctly to French'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testWhetherSplitLocaleCodeSplitsValidLocalesCorrectly()
|
|
||||||
{
|
|
||||||
$localeObj = Translator::splitLocaleCode('de_DE');
|
|
||||||
$this->assertEquals(
|
|
||||||
'de',
|
|
||||||
$localeObj->language,
|
|
||||||
'Translator::splitLocaleCode does not split the language code correctly'
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
'DE',
|
|
||||||
$localeObj->country,
|
|
||||||
'Translator::splitLocaleCode does not split the country code correctly'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @depends testWhetherSplitLocaleCodeSplitsValidLocalesCorrectly
|
|
||||||
*/
|
|
||||||
public function testWhetherSplitLocaleCodeCanHandleEncodingSuffixes()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
'US',
|
|
||||||
Translator::splitLocaleCode('en_US.UTF-8')->country,
|
|
||||||
'Translator::splitLocaleCode does not handle encoding suffixes correctly'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testWhetherSplitLocaleCodeInterpretsInvalidLocaleCodesAsLanguageCodes()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
'de',
|
|
||||||
Translator::splitLocaleCode('de')->language,
|
|
||||||
'Translator::splitLocaleCode does not interpret invalid locale codes as language codes'
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
'en~US',
|
|
||||||
Translator::splitLocaleCode('en~US')->language,
|
|
||||||
'Translator::splitLocaleCode does not interpret invalid locale codes as language codes'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @depends testWhetherSplitLocaleCodeSplitsValidLocalesCorrectly
|
|
||||||
*/
|
|
||||||
public function testWhetherSplitLocaleCodeReturnsTheDefaultLocaleWhenGivenCAsLocale()
|
|
||||||
{
|
|
||||||
$cLocaleObj = Translator::splitLocaleCode('C');
|
|
||||||
$defaultLocaleObj = Translator::splitLocaleCode(Translator::DEFAULT_LOCALE);
|
|
||||||
$this->assertEquals(
|
|
||||||
$defaultLocaleObj->language,
|
|
||||||
$cLocaleObj->language,
|
|
||||||
'Translator::splitLocaleCode does not return the default language code when given C as locale'
|
|
||||||
);
|
|
||||||
$this->assertEquals(
|
|
||||||
$defaultLocaleObj->country,
|
|
||||||
$cLocaleObj->country,
|
|
||||||
'Translator::splitLocaleCode does not return the default country code when given C as locale'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @depends testWhetherSplitLocaleCodeSplitsValidLocalesCorrectly
|
|
||||||
* @depends testWhetherSplitLocaleCodeInterpretsInvalidLocaleCodesAsLanguageCodes
|
|
||||||
*/
|
|
||||||
public function testWhetherGetPreferredLocaleCodeFavorsPerfectMatches()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
'de_DE',
|
|
||||||
TranslatorWithHardcodedLocaleCodes::getPreferredLocaleCode('jp,de_DE;q=0.8,de;q=0.6'),
|
|
||||||
'Translator::getPreferredLocaleCode does not favor perfect matches'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @depends testWhetherSplitLocaleCodeSplitsValidLocalesCorrectly
|
|
||||||
* @depends testWhetherSplitLocaleCodeInterpretsInvalidLocaleCodesAsLanguageCodes
|
|
||||||
*/
|
|
||||||
public function testWhetherGetPreferredLocaleCodeReturnsThePreferredSimilarMatchEvenThoughAPerfectMatchWasFound()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
'de_DE',
|
|
||||||
TranslatorWithHardcodedLocaleCodes::getPreferredLocaleCode('de_CH,en_US;q=0.8'),
|
|
||||||
'Translator::getPreferredLocaleCode does not return the preferred similar match'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @depends testWhetherSplitLocaleCodeSplitsValidLocalesCorrectly
|
|
||||||
* @depends testWhetherSplitLocaleCodeInterpretsInvalidLocaleCodesAsLanguageCodes
|
|
||||||
*/
|
|
||||||
public function testWhetherGetPreferredLocaleCodeReturnsAPerfectMatchEvenThoughASimilarMatchWasFound()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
'de_AT',
|
|
||||||
TranslatorWithHardcodedLocaleCodes::getPreferredLocaleCode('de,de_AT;q=0.5'),
|
|
||||||
'Translator::getPreferredLocaleCode does not return a perfect '
|
|
||||||
. 'match if a similar match with higher priority was found'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @depends testWhetherSplitLocaleCodeInterpretsInvalidLocaleCodesAsLanguageCodes
|
|
||||||
*/
|
|
||||||
public function testWhetherGetPreferredLocaleCodeReturnsASimilarMatchIfNoPerfectMatchCouldBeFound()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
'de_DE',
|
|
||||||
TranslatorWithHardcodedLocaleCodes::getPreferredLocaleCode('de,en'),
|
|
||||||
'Translator::getPreferredLocaleCode does not return the most preferred similar match'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @depends testWhetherSplitLocaleCodeSplitsValidLocalesCorrectly
|
|
||||||
*/
|
|
||||||
public function testWhetherGetPreferredLocaleCodeReturnsTheDefaultLocaleIfNoMatchCouldBeFound()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
Translator::DEFAULT_LOCALE,
|
|
||||||
TranslatorWithHardcodedLocaleCodes::getPreferredLocaleCode('fr_FR,jp_JP'),
|
|
||||||
'Translator::getPreferredLocaleCode does not return the default locale if no match could be found'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @depends testWhetherSetupLocaleSetsUpTheGivenLocale
|
|
||||||
*/
|
|
||||||
public function testWhetherTranslatePluralReturnsTheSingularForm()
|
|
||||||
{
|
|
||||||
Translator::setupLocale('de_DE');
|
|
||||||
|
|
||||||
$result = Translator::translatePlural('test service', 'test services', 1, 'icingatest');
|
|
||||||
|
|
||||||
$expected = 'test dienst';
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
$expected,
|
|
||||||
$result,
|
|
||||||
'Translator::translatePlural() could not return the translated singular form'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @depends testWhetherSetupLocaleSetsUpTheGivenLocale
|
|
||||||
*/
|
|
||||||
public function testWhetherTranslatePluralReturnsThePluralForm()
|
|
||||||
{
|
|
||||||
Translator::setupLocale('de_DE');
|
|
||||||
|
|
||||||
$result = Translator::translatePlural('test service', 'test services', 2, 'icingatest');
|
|
||||||
|
|
||||||
$expected = 'test dienste';
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
$expected,
|
|
||||||
$result,
|
|
||||||
'Translator::translatePlural() could not return the translated plural form'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @depends testWhetherSetupLocaleSetsUpTheGivenLocale
|
|
||||||
*/
|
|
||||||
public function testWhetherTranslateReturnsTheContextForm()
|
|
||||||
{
|
|
||||||
Translator::setupLocale('de_DE');
|
|
||||||
|
|
||||||
$result = Translator::translate('context service', 'icingatest', 'test2');
|
|
||||||
|
|
||||||
$expected = 'context dienst test2';
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
$expected,
|
|
||||||
$result,
|
|
||||||
'Translator::translate() could not return the translated context form'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @depends testWhetherSetupLocaleSetsUpTheGivenLocale
|
|
||||||
*/
|
|
||||||
public function testWhetherTranslatePluralReturnsTheContextForm()
|
|
||||||
{
|
|
||||||
Translator::setupLocale('de_DE');
|
|
||||||
|
|
||||||
$result = Translator::translatePlural('context service', 'context services', 3, 'icingatest', 'test-context');
|
|
||||||
|
|
||||||
$expected = 'context plural dienste';
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
$expected,
|
|
||||||
$result,
|
|
||||||
'Translator::translatePlural() could not return the translated context form'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
|
||||||
|
|
||||||
namespace Tests\Icinga\Regression;
|
|
||||||
|
|
||||||
use Icinga\Test\BaseTestCase;
|
|
||||||
use Icinga\Util\Translator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Regression-Test for bug #6432
|
|
||||||
*
|
|
||||||
* Translating strings must not throw an exception even if the given domain is not valid.
|
|
||||||
*
|
|
||||||
* @see https://dev.icinga.com/issues/6432
|
|
||||||
*/
|
|
||||||
class Bug6432Test extends BaseTestCase
|
|
||||||
{
|
|
||||||
public function testWhetherTranslateReturnsTheInputStringInCaseTheGivenDomainIsNotValid()
|
|
||||||
{
|
|
||||||
$this->assertEquals('test', Translator::translate('test', 'invalid_domain'));
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
@ -1,42 +0,0 @@
|
|||||||
msgid ""
|
|
||||||
msgstr ""
|
|
||||||
"Project-Id-Version: Icinga Web 2 Test (0.0.1)\n"
|
|
||||||
"Report-Msgid-Bugs-To: dev@icinga.com\n"
|
|
||||||
"POT-Creation-Date: 2014-09-16 13:29+0200\n"
|
|
||||||
"PO-Revision-Date: 2014-09-16 16:08+0100\n"
|
|
||||||
"Last-Translator: Alexander Fuhr <alexander.fuhr@netways.de>\n"
|
|
||||||
"Language: de_DE\n"
|
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
|
||||||
"X-Generator: Poedit 1.5.4\n"
|
|
||||||
|
|
||||||
msgid "Lorem ipsum dolor sit amet"
|
|
||||||
msgstr "Lorem ipsum dolor sit amet!"
|
|
||||||
|
|
||||||
msgid "test service"
|
|
||||||
msgid_plural "test services"
|
|
||||||
msgstr[0] "test dienst"
|
|
||||||
msgstr[1] "test dienste"
|
|
||||||
|
|
||||||
msgctxt "test"
|
|
||||||
msgid "context service"
|
|
||||||
msgstr "context dienst test"
|
|
||||||
|
|
||||||
msgctxt "test2"
|
|
||||||
msgid "context service"
|
|
||||||
msgstr "context dienst test2"
|
|
||||||
|
|
||||||
msgctxt "test-contextu"
|
|
||||||
msgid "context service"
|
|
||||||
msgid_plural "context services"
|
|
||||||
msgstr[0] "context plural dienstu"
|
|
||||||
msgstr[1] "context plural diensteu"
|
|
||||||
|
|
||||||
msgctxt "test-context"
|
|
||||||
msgid "context service"
|
|
||||||
msgid_plural "context services"
|
|
||||||
msgstr[0] "context plural dienst"
|
|
||||||
msgstr[1] "context plural dienste"
|
|
Binary file not shown.
@ -1,2 +0,0 @@
|
|||||||
msgid "Lorem ipsum dolor sit amet"
|
|
||||||
msgstr "Lorem ipsum dolor sit amet?"
|
|
Loading…
x
Reference in New Issue
Block a user