diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 4ca606ac5..a8d303edf 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -105,9 +105,7 @@ jobs: extensions: mysql, pgsql, ldap - name: Setup dependencies - run: | - sudo locale-gen en_US.UTF-8 de_DE.UTF-8 fr_FR.UTF-8 - composer require -n --no-progress mockery/mockery + run: composer require -n --no-progress mockery/mockery ipl/i18n:@dev - name: PHPUnit env: diff --git a/application/forms/PreferenceForm.php b/application/forms/PreferenceForm.php index 7f4297478..f05737a2c 100644 --- a/application/forms/PreferenceForm.php +++ b/application/forms/PreferenceForm.php @@ -12,12 +12,13 @@ use Icinga\Authentication\Auth; use Icinga\User\Preferences; use Icinga\User\Preferences\PreferencesStore; use Icinga\Util\TimezoneDetect; -use Icinga\Util\Translator; -use Icinga\Web\Cookie; use Icinga\Web\Form; use Icinga\Web\Notification; use Icinga\Web\Session; use Icinga\Web\StyleSheet; +use ipl\I18n\GettextTranslator; +use ipl\I18n\Locale; +use ipl\I18n\StaticTranslator; /** * 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) { $languages['autodetect'] = sprintf($this->translate('Browser (%s)', 'preferences.form'), $locale); } - foreach (Translator::getAvailableLocaleCodes() as $language) { + foreach ($availableLocales as $language) { $languages[$language] = $language; } @@ -410,10 +415,10 @@ class PreferenceForm extends Form * * @return string|null */ - protected function getLocale() + protected function getLocale($availableLocales) { return isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) - ? Translator::getPreferredLocaleCode($_SERVER['HTTP_ACCEPT_LANGUAGE']) + ? (new Locale())->getPreferred($_SERVER['HTTP_ACCEPT_LANGUAGE'], $availableLocales) : null; } diff --git a/application/layouts/scripts/external-logout.phtml b/application/layouts/scripts/external-logout.phtml index 607ad4be5..19c35e4e2 100644 --- a/application/layouts/scripts/external-logout.phtml +++ b/application/layouts/scripts/external-logout.phtml @@ -1,8 +1,13 @@ language; +/** @var GettextTranslator $translator */ +$translator = StaticTranslator::$instance; + +$lang = (new Locale())->parseLocale($translator->getLocale())->language; $showFullscreen = $this->layout()->showFullscreen; $innerLayoutScript = $this->layout()->innerLayout . '.phtml'; diff --git a/application/layouts/scripts/layout.phtml b/application/layouts/scripts/layout.phtml index 1d22c9798..1800f2c15 100644 --- a/application/layouts/scripts/layout.phtml +++ b/application/layouts/scripts/layout.phtml @@ -1,6 +1,8 @@ parseLocale($translator->getLocale())->language; $timezone = date_default_timezone_get(); -$lang = Translator::splitLocaleCode()->language; $isIframe = $this->layout()->isIframe; $showFullscreen = $this->layout()->showFullscreen; $iframeClass = $isIframe ? ' iframe' : ''; diff --git a/library/Icinga/Application/ApplicationBootstrap.php b/library/Icinga/Application/ApplicationBootstrap.php index 025ecb8c5..06ed5731c 100644 --- a/library/Icinga/Application/ApplicationBootstrap.php +++ b/library/Icinga/Application/ApplicationBootstrap.php @@ -6,13 +6,14 @@ namespace Icinga\Application; use DirectoryIterator; use ErrorException; use Exception; +use ipl\I18n\GettextTranslator; +use ipl\I18n\StaticTranslator; use LogicException; use Icinga\Application\Modules\Manager as ModuleManager; use Icinga\Authentication\User\UserBackend; use Icinga\Data\ConfigObject; use Icinga\Exception\ConfigurationError; use Icinga\Exception\NotReadableError; -use Icinga\Util\Translator; use Icinga\Exception\IcingaException; /** @@ -699,6 +700,19 @@ abstract class ApplicationBootstrap return null; } + /** + * Prepare internationalization using gettext + * + * @return $this + */ + protected function prepareInternationalization() + { + StaticTranslator::$instance = (new GettextTranslator()) + ->setDefaultDomain('icinga'); + + return $this; + } + /** * Set up internationalization using gettext * @@ -706,17 +720,20 @@ abstract class ApplicationBootstrap */ final protected function setupInternationalization() { + /** @var GettextTranslator $translator */ + $translator = StaticTranslator::$instance; + if ($this->hasLocales()) { - Translator::registerDomain(Translator::DEFAULT_DOMAIN, $this->getLocaleDir()); + $translator->addTranslationDirectory($this->getLocaleDir(), 'icinga'); } $locale = $this->detectLocale(); if ($locale === null) { - $locale = Translator::DEFAULT_LOCALE; + $locale = $translator->getDefaultLocale(); } try { - Translator::setupLocale($locale); + $translator->setLocale($locale); } catch (Exception $error) { Logger::error($error); } @@ -753,27 +770,15 @@ abstract class ApplicationBootstrap /** * 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() { - $locales = array(); - if (! $this->hasLocales()) { - return $locales; - } - $localedir = $this->getLocaleDir(); + /** @var GettextTranslator $translator */ + $translator = StaticTranslator::$instance; - $dh = opendir($localedir); - 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; + return $translator->listLocales(); } } diff --git a/library/Icinga/Application/Cli.php b/library/Icinga/Application/Cli.php index 70bd1c8e3..d07e76602 100644 --- a/library/Icinga/Application/Cli.php +++ b/library/Icinga/Application/Cli.php @@ -41,6 +41,7 @@ class Cli extends ApplicationBootstrap ->loadLibraries() ->loadConfig() ->setupTimezone() + ->prepareInternationalization() ->setupInternationalization() ->parseBasicParams() ->setupLogger() diff --git a/library/Icinga/Application/EmbeddedWeb.php b/library/Icinga/Application/EmbeddedWeb.php index 4ca3caca1..763ced121 100644 --- a/library/Icinga/Application/EmbeddedWeb.php +++ b/library/Icinga/Application/EmbeddedWeb.php @@ -7,6 +7,8 @@ require_once dirname(__FILE__) . '/ApplicationBootstrap.php'; use Icinga\Web\Request; 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 @@ -72,6 +74,7 @@ class EmbeddedWeb extends ApplicationBootstrap ->setupRequest() ->setupResponse() ->setupTimezone() + ->prepareFakeInternationalization() ->setupModuleManager() ->loadEnabledModules(); } @@ -97,4 +100,16 @@ class EmbeddedWeb extends ApplicationBootstrap $this->response = new Response(); return $this; } + + /** + * Prepare fake internationalization + * + * @return $this + */ + protected function prepareFakeInternationalization() + { + StaticTranslator::$instance = new NoopTranslator(); + + return $this; + } } diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index 6f4003622..195376f1c 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -13,9 +13,11 @@ use Icinga\Exception\IcingaException; use Icinga\Exception\ProgrammingError; use Icinga\Module\Setup\SetupWizard; use Icinga\Util\File; -use Icinga\Util\Translator; use Icinga\Web\Navigation\Navigation; use Icinga\Web\Widget; +use ipl\I18n\GettextTranslator; +use ipl\I18n\StaticTranslator; +use ipl\I18n\Translation; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; use Zend_Controller_Router_Route; @@ -29,6 +31,11 @@ use Zend_Controller_Router_Route_Regex; */ class Module { + use Translation { + translate as protected; + translatePlural as protected; + } + /** * Module name * @@ -300,6 +307,8 @@ class Module $this->runScript = $basedir . '/run.php'; $this->configScript = $basedir . '/configuration.php'; $this->metadataFile = $basedir . '/module.info'; + + $this->translationDomain = $name; } /** @@ -1418,9 +1427,10 @@ class Module */ protected function registerLocales() { - if ($this->hasLocales()) { - Translator::registerDomain($this->name, $this->localedir); + if ($this->hasLocales() && StaticTranslator::$instance instanceof GettextTranslator) { + StaticTranslator::$instance->addTranslationDirectory($this->localedir, $this->name); } + return $this; } @@ -1633,22 +1643,4 @@ class Module $this->routes[$name] = $route; 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); - } } diff --git a/library/Icinga/Application/Web.php b/library/Icinga/Application/Web.php index 43f2e5a8a..3cf6faeac 100644 --- a/library/Icinga/Application/Web.php +++ b/library/Icinga/Application/Web.php @@ -6,6 +6,9 @@ namespace Icinga\Application; require_once __DIR__ . '/EmbeddedWeb.php'; use ErrorException; +use ipl\I18n\GettextTranslator; +use ipl\I18n\Locale; +use ipl\I18n\StaticTranslator; use Zend_Controller_Action_HelperBroker; use Zend_Controller_Front; use Zend_Controller_Router_Route; @@ -16,7 +19,6 @@ use Icinga\Authentication\Auth; use Icinga\User; use Icinga\Util\DirectoryIterator; use Icinga\Util\TimezoneDetect; -use Icinga\Util\Translator; use Icinga\Web\Controller\Dispatcher; use Icinga\Web\Menu; use Icinga\Web\Navigation\Navigation; @@ -91,6 +93,7 @@ class Web extends EmbeddedWeb ->setupNotifications() ->setupResponse() ->setupZendMvc() + ->prepareInternationalization() ->setupModuleManager() ->loadSetupModuleIfNecessary() ->loadEnabledModules() @@ -493,9 +496,7 @@ class Web extends EmbeddedWeb * * Uses the preferred user language or the browser suggested language or our default. * - * @return string Detected locale code - * - * @see Translator::DEFAULT_LOCALE For the default locale code. + * @return string Detected locale code */ protected function detectLocale() { @@ -505,9 +506,14 @@ class Web extends EmbeddedWeb ) { return $locale; } + + /** @var GettextTranslator $translator */ + $translator = StaticTranslator::$instance; + 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(); } } diff --git a/library/Icinga/Application/functions.php b/library/Icinga/Application/functions.php index 6144c729b..0fc99f836 100644 --- a/library/Icinga/Application/functions.php +++ b/library/Icinga/Application/functions.php @@ -1,7 +1,8 @@ translate($messageId, $context); } /** - * (non-PHPDoc) - * @see Translator::translate() For the function documentation. + * @see Translator::translateInDomain() For the function documentation. */ 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. */ 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::translatePlural() For the function documentation. + * @see Translator::translatePluralInDomain() For the function documentation. */ 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 { /** - * (non-PHPDoc) * @see Translator::translate() For the function documentation. */ function t($messageId, $context = null) @@ -74,7 +76,6 @@ if (extension_loaded('gettext')) { } /** - * (non-PHPDoc) * @see Translator::translate() For the function documentation. */ function mt($domain, $messageId, $context = null) @@ -83,7 +84,6 @@ if (extension_loaded('gettext')) { } /** - * (non-PHPDoc) * @see Translator::translatePlural() For the function documentation. */ function tp($messageId, $messageId2, $number, $context = null) @@ -91,11 +91,11 @@ if (extension_loaded('gettext')) { if ((int) $number !== 1) { return $messageId2; } + return $messageId; } /** - * (non-PHPDoc) * @see Translator::translatePlural() For the function documentation. */ function mtp($domain, $messageId, $messageId2, $number, $context = null) @@ -103,6 +103,7 @@ if (extension_loaded('gettext')) { if ((int) $number !== 1) { return $messageId2; } + return $messageId; } diff --git a/library/Icinga/Cli/Command.php b/library/Icinga/Cli/Command.php index 0f15bdb75..d1a19862a 100644 --- a/library/Icinga/Cli/Command.php +++ b/library/Icinga/Cli/Command.php @@ -8,10 +8,12 @@ use Icinga\Application\Config; use Icinga\Application\Logger; use Icinga\Exception\IcingaException; use Icinga\Exception\NotReadableError; -use Icinga\Util\Translator; +use ipl\I18n\Translation; abstract class Command { + use Translation; + protected $app; protected $docs; @@ -61,6 +63,8 @@ abstract class Command $this->isDebugging = $this->params->shift('debug', false); $this->configs = []; + $this->translationDomain = $moduleName ?: 'icinga'; + if ($this->loadEnabledModules) { try { $app->getModuleManager()->loadEnabledModules(); @@ -134,21 +138,6 @@ 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 IcingaException('%s', $msg); diff --git a/library/Icinga/Test/BaseTestCase.php b/library/Icinga/Test/BaseTestCase.php index aea79210f..4509315ec 100644 --- a/library/Icinga/Test/BaseTestCase.php +++ b/library/Icinga/Test/BaseTestCase.php @@ -21,6 +21,8 @@ namespace { namespace Icinga\Test { use Exception; + use ipl\I18n\NoopTranslator; + use ipl\I18n\StaticTranslator; use RuntimeException; use Mockery; use Icinga\Application\Icinga; @@ -140,6 +142,8 @@ namespace Icinga\Test { public function setUp(): void { parent::setUp(); + + StaticTranslator::$instance = new NoopTranslator(); $this->setupIcingaMock(); } diff --git a/library/Icinga/Util/Translator.php b/library/Icinga/Util/Translator.php index 8238a7830..15b3c727e 100644 --- a/library/Icinga/Util/Translator.php +++ b/library/Icinga/Util/Translator.php @@ -3,10 +3,14 @@ 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 + * + * @deprecated Use {@see \ipl\I18n\StaticTranslator::$instance} or {@see \ipl\I18n\Translation} instead */ class Translator { @@ -20,13 +24,6 @@ class Translator */ const DEFAULT_LOCALE = 'en_US'; - /** - * Known gettext domains and directories - * - * @var array - */ - private static $knownDomains = array(); - /** * Translate a string * @@ -40,19 +37,7 @@ class Translator */ public static function translate($text, $domain, $context = null) { - if ($context !== null) { - $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; + return StaticTranslator::$instance->translateInDomain($domain, $text, $context); } /** @@ -70,19 +55,13 @@ class Translator */ public static function translatePlural($textSingular, $textPlural, $number, $domain, $context = null) { - if ($context !== null) { - $res = self::pngettext($textSingular, $textPlural, $number, $domain, $context); - if (($res === $textSingular || $res === $textPlural) && $domain !== self::DEFAULT_DOMAIN) { - $res = self::pngettext($textSingular, $textPlural, $number, self::DEFAULT_DOMAIN, $context); - } - return $res; - } - - $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; + return StaticTranslator::$instance->translatePluralInDomain( + $domain, + $textSingular, + $textPlural, + $number, + $context + ); } /** @@ -98,19 +77,7 @@ class Translator */ public static function pgettext($text, $domain, $context) { - $contextString = "{$context}\004{$text}"; - - $translation = dcgettext( - $domain, - $contextString, - defined('LC_MESSAGES') ? LC_MESSAGES : LC_ALL - ); - - if ($translation == $contextString) { - return $text; - } else { - return $translation; - } + return StaticTranslator::$instance->translateInDomain($domain, $text, $context); } /** @@ -128,21 +95,13 @@ class Translator */ public static function pngettext($textSingular, $textPlural, $number, $domain, $context) { - $contextString = "{$context}\004{$textSingular}"; - - $translation = dcngettext( + return StaticTranslator::$instance->translatePluralInDomain( $domain, - $contextString, + $textSingular, $textPlural, $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 $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) { - if (bindtextdomain($name, $directory) === false) { - throw new IcingaException( - 'Cannot register domain \'%s\' with path \'%s\'', - $name, - $directory - ); - } - bind_textdomain_codeset($name, 'UTF-8'); - self::$knownDomains[$name] = $directory; + /** @var GettextTranslator $translator */ + $translator = StaticTranslator::$instance; + + $translator->addTranslationDirectory($directory, $name); } /** @@ -171,26 +125,14 @@ class Translator * * @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) { - if (setlocale(LC_ALL, $localeName . '.UTF-8') === false && setlocale(LC_ALL, $localeName) === false) { - setlocale(LC_ALL, 'C'); // C == "use whatever is hardcoded" - 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 + /** @var GettextTranslator $translator */ + $translator = StaticTranslator::$instance; - // https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html - putenv('LANGUAGE=' . $localeName . ':' . getenv('LANGUAGE')); - } + $translator->setLocale($localeName); } /** @@ -202,18 +144,14 @@ class Translator */ public static function splitLocaleCode($locale = null) { - $matches = array(); - $locale = $locale !== null ? $locale : setlocale(LC_ALL, 0); - if (preg_match('@([a-z]{2})[_-]([a-z]{2})@i', $locale, $matches)) { - list($languageCode, $countryCode) = array_slice($matches, 1); - } elseif ($locale === 'C') { - list($languageCode, $countryCode) = preg_split('@[_-]@', static::DEFAULT_LOCALE, 2); - } else { - $languageCode = $locale; - $countryCode = null; + /** @var GettextTranslator $translator */ + $translator = StaticTranslator::$instance; + + if ($locale === null) { + $locale = $translator->getLocale(); } - return (object) array('language' => $languageCode, 'country' => $countryCode); + return (new Locale())->parseLocale($locale); } /** @@ -223,21 +161,10 @@ class Translator */ public static function getAvailableLocaleCodes() { - $codes = array(static::DEFAULT_LOCALE); - foreach (array_values(self::$knownDomains) as $directory) { - $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); + /** @var GettextTranslator $translator */ + $translator = StaticTranslator::$instance; - return $codes; + return $translator->listLocales(); } /** @@ -249,68 +176,9 @@ class Translator */ public static function getPreferredLocaleCode($header) { - $headerValues = explode(',', $header); - for ($i = 0; $i < count($headerValues); $i++) { - // 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) - ); + /** @var GettextTranslator $translator */ + $translator = StaticTranslator::$instance; - $availableLocales = static::getAvailableLocaleCodes(); - $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; + return (new Locale())->getPreferred($header, $translator->listLocales()); } } diff --git a/library/Icinga/Web/Controller/ActionController.php b/library/Icinga/Web/Controller/ActionController.php index 4ec2ddebb..434e07f8b 100644 --- a/library/Icinga/Web/Controller/ActionController.php +++ b/library/Icinga/Web/Controller/ActionController.php @@ -3,6 +3,7 @@ namespace Icinga\Web\Controller; +use ipl\I18n\Translation; use Zend_Controller_Action; use Zend_Controller_Action_HelperBroker; use Zend_Controller_Request_Abstract; @@ -16,7 +17,6 @@ use Icinga\Exception\ProgrammingError; use Icinga\File\Pdf; use Icinga\Forms\AutoRefreshForm; use Icinga\Security\SecurityException; -use Icinga\Util\Translator; use Icinga\Web\Session; use Icinga\Web\Url; use Icinga\Web\UrlParams; @@ -40,6 +40,8 @@ use Icinga\Web\Window; */ class ActionController extends Zend_Controller_Action { + use Translation; + /** * The login route to use when requiring authentication */ @@ -131,7 +133,8 @@ class ActionController extends Zend_Controller_Action $moduleName = $this->getModuleName(); $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()->showFullscreen = $request->getUrl()->shift('showFullscreen'); $this->_helper->layout()->moduleName = $moduleName; @@ -305,42 +308,6 @@ class ActionController extends Zend_Controller_Action 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() { if ($this->isXhr()) { diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php index f836d0f78..bc7f44457 100644 --- a/library/Icinga/Web/Form.php +++ b/library/Icinga/Web/Form.php @@ -4,6 +4,7 @@ namespace Icinga\Web; use Icinga\Web\Form\Element\DateTimePicker; +use ipl\I18n\Translation; use Zend_Config; use Zend_Form; use Zend_Form_Element; @@ -12,7 +13,6 @@ use Icinga\Application\Icinga; use Icinga\Authentication\Auth; use Icinga\Exception\ProgrammingError; use Icinga\Security\SecurityException; -use Icinga\Util\Translator; use Icinga\Web\Form\ErrorLabeller; use Icinga\Web\Form\Decorator\Autosubmit; use Icinga\Web\Form\Element\CsrfCounterMeasure; @@ -27,6 +27,11 @@ use Icinga\Web\Form\Element\CsrfCounterMeasure; */ 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 */ @@ -1519,7 +1524,9 @@ class Form extends Zend_Form */ 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) { - return Translator::translatePlural( - $textSingular, - $textPlural, - $number, - $this->getTranslationDomain(), - $context - ); + $this->translationDomain = $this->getTranslationDomain(); + + return $this->i18nTranslatePlural($textSingular, $textPlural, $number, $context); } /** diff --git a/library/Icinga/Web/View.php b/library/Icinga/Web/View.php index 55ee4543b..bdc7b6d6b 100644 --- a/library/Icinga/Web/View.php +++ b/library/Icinga/Web/View.php @@ -5,10 +5,10 @@ namespace Icinga\Web; use Closure; use Icinga\Application\Icinga; +use ipl\I18n\Translation; use Zend_View_Abstract; use Icinga\Authentication\Auth; use Icinga\Exception\ProgrammingError; -use Icinga\Util\Translator; /** * Icinga view @@ -54,6 +54,8 @@ use Icinga\Util\Translator; */ class View extends Zend_View_Abstract { + use Translation; + /** * 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 */ diff --git a/modules/migrate/application/clicommands/DashboardCommand.php b/modules/migrate/application/clicommands/DashboardCommand.php index 01b15477f..36a12fc5e 100644 --- a/modules/migrate/application/clicommands/DashboardCommand.php +++ b/modules/migrate/application/clicommands/DashboardCommand.php @@ -9,8 +9,8 @@ use Icinga\Application\Icinga; use Icinga\Application\Modules\DashboardContainer; use Icinga\Cli\Command; use Icinga\Application\Logger; -use Icinga\Exception\IcingaException; -use Icinga\Util\Translator; +use ipl\I18n\GettextTranslator; +use ipl\I18n\StaticTranslator; use ReflectionClass; 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 $paneItemsProperty = $moduleReflection->getProperty('paneItems'); $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(); - $modules = Icinga::app()->getModuleManager()->loadEnabledModules()->getLoadedModules(); + /** @var GettextTranslator $translator */ + $translator = StaticTranslator::$instance; + + $locales = $translator->listLocales(); + $modules = Icinga::app()->getModuleManager()->getLoadedModules(); foreach ($this->listDashboardConfigs() as $path) { Logger::info('Migrating dashboard config: %s', $path); $config = Config::fromIni($path); foreach ($modules as $module) { - $localePath = $localeDirProperty->getValue($module); - if (! is_dir($localePath)) { + if (! $module->hasLocales()) { // Modules without any translations are not affected continue; } $launchConfigScriptMethod->invoke($module); - Translator::registerDomain($module->getName(), $localePath); foreach ($locales as $locale) { if ($locale === 'en_US') { @@ -60,8 +58,8 @@ class DashboardCommand extends Command } try { - Translator::setupLocale($locale); - } catch (IcingaException $e) { + $translator->setLocale($locale); + } catch (Exception $e) { Logger::debug('Ignoring locale "%s". Reason: %s', $locale, $e->getMessage()); continue; } diff --git a/modules/translation/application/clicommands/CompileCommand.php b/modules/translation/application/clicommands/CompileCommand.php index 52047db2a..840800950 100644 --- a/modules/translation/application/clicommands/CompileCommand.php +++ b/modules/translation/application/clicommands/CompileCommand.php @@ -4,48 +4,21 @@ 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. + * This command will compile gettext catalogs of modules. * - * Domains are the global one 'icinga' and all available and enabled modules - * identified by their name. - * - * Once a PO-file is compiled its content is used by Icinga Web 2 to display + * Once a catalog is compiled its content is used by Icinga Web 2 to display * messages in the configured language. */ class CompileCommand extends TranslationCommand { /** - * Compile the global domain + * Compile a module gettext catalog * - * This will compile the PO-file of the global 'icinga' domain. - * - * USAGE: - * - * icingacli translation compile icinga - * - * 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. + * This will compile the catalog of the given module and locale. * * USAGE: * @@ -53,8 +26,8 @@ class CompileCommand extends TranslationCommand * * EXAMPLES: * - * icingacli translation compile monitoring de_DE - * icingacli trnslations compile monitoring de_DE + * icingacli translation compile demo de_DE + * icingacli translation compile demo fr_FR */ public function moduleAction() { diff --git a/modules/translation/application/clicommands/RefreshCommand.php b/modules/translation/application/clicommands/RefreshCommand.php index bd22065cb..b4b2dc0d3 100644 --- a/modules/translation/application/clicommands/RefreshCommand.php +++ b/modules/translation/application/clicommands/RefreshCommand.php @@ -4,48 +4,21 @@ 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. + * This command will create a new or update any existing gettext catalog of a module. * - * 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 + * Once a catalog 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 + * Generate or update a module gettext catalog * - * This will create/update the PO-file of the global 'icinga' domain. - * - * USAGE: - * - * icingacli translation refresh icinga - * - * 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. + * This will create/update the PO-file of the given module and locale. * * USAGE: * @@ -53,8 +26,8 @@ class RefreshCommand extends TranslationCommand * * EXAMPLES: * - * icingacli translation refresh module monitoring de_DE - * icingacli translation refresh module monitoring fr_FR + * icingacli translation refresh module demo de_DE + * icingacli translation refresh module demo fr_FR */ public function moduleAction() { diff --git a/modules/translation/application/clicommands/TestCommand.php b/modules/translation/application/clicommands/TestCommand.php index 3e395286e..347c2c9f8 100644 --- a/modules/translation/application/clicommands/TestCommand.php +++ b/modules/translation/application/clicommands/TestCommand.php @@ -6,7 +6,8 @@ namespace Icinga\Module\Translation\Clicommands; use Icinga\Date\DateFormatter; use Icinga\Module\Translation\Cli\ArrayToTextTableHelper; use Icinga\Module\Translation\Cli\TranslationCommand; -use Icinga\Util\Translator; +use ipl\I18n\GettextTranslator; +use ipl\I18n\StaticTranslator; /** * Timestamp test helper @@ -89,12 +90,19 @@ class TestCommand extends TranslationCommand foreach ($this->params->getAllStandalone() as $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); } diff --git a/modules/translation/doc/03-Translation.md b/modules/translation/doc/03-Translation.md index 46260b7a5..1ea65bde0 100644 --- a/modules/translation/doc/03-Translation.md +++ b/modules/translation/doc/03-Translation.md @@ -1,13 +1,12 @@ # Introduction -Icinga Web 2 provides localization out of the box - for the core application and the modules, that means -that you can with a lightness use existent localizations, update or even create you own localizations. +Icinga Web 2 provides localization out of the box - for itself and the core modules. +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), [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 -part on localizing Icinga Web 2 for different languages and how to use the -`translation module` to make your life much easier. +[Testing Translations](03-Translation.md#module-translation-tests) will introduce and +explain you, how to take part on localizing modules to different languages. ## Translation for Developers diff --git a/modules/translation/library/Translation/Util/GettextTranslationHelper.php b/modules/translation/library/Translation/Util/GettextTranslationHelper.php index 1c8d04de6..d1e6ac287 100644 --- a/modules/translation/library/Translation/Util/GettextTranslationHelper.php +++ b/modules/translation/library/Translation/Util/GettextTranslationHelper.php @@ -65,13 +65,6 @@ class GettextTranslationHelper */ private $locale; - /** - * The path to the Zend application root - * - * @var string - */ - private $appDir; - /** * The path to the module, if any * @@ -79,13 +72,6 @@ class GettextTranslationHelper */ private $moduleDir; - /** - * Path to the Icinga library - * - * @var string - */ - protected $libDir; - /** * The path to the file catalog * @@ -115,9 +101,7 @@ class GettextTranslationHelper */ public function __construct(ApplicationBootstrap $bootstrap, $locale) { - $this->moduleMgr = $bootstrap->getModuleManager()->loadEnabledModules(); - $this->appDir = $bootstrap->getApplicationDir(); - $this->libDir = $bootstrap->getLibraryDir('Icinga'); + $this->moduleMgr = $bootstrap->getModuleManager(); $this->locale = $locale; } @@ -158,32 +142,6 @@ class GettextTranslationHelper 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 * @@ -214,25 +172,6 @@ class GettextTranslationHelper $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 * @@ -296,8 +235,12 @@ class GettextTranslationHelper '--language=PHP', '--keyword=translate', '--keyword=translate:1,2c', + '--keyword=translateInDomain:2', + '--keyword=translateInDomain:2,3c', '--keyword=translatePlural:1,2', '--keyword=translatePlural:1,2,4c', + '--keyword=translatePluralInDomain:2,3', + '--keyword=translatePluralInDomain:2,3,5c', '--keyword=mt:2', '--keyword=mt:2,3c', '--keyword=mtp:2,3', @@ -326,15 +269,15 @@ class GettextTranslationHelper private function updateHeader($path) { $headerInfo = array( - 'title' => 'Icinga Web 2 - Head for multiple monitoring backends', - 'copyright_holder' => 'Icinga Development Team', + 'title' => $this->moduleMgr->getModule($this->moduleName)->getTitle(), + 'copyright_holder' => 'TEAM NAME', 'copyright_year' => date('Y'), 'author_name' => 'FIRST AUTHOR', 'author_mail' => 'EMAIL@ADDRESS', '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_bug_mail' => 'dev@icinga.com', + 'project_bug_mail' => 'ISSUE TRACKER', 'pot_creation_date' => date('Y-m-d H:iO'), 'po_revision_date' => 'YEAR-MO-DA HO:MI+ZONE', 'translator_name' => 'FULL NAME', @@ -418,7 +361,7 @@ class GettextTranslationHelper { shell_exec(sprintf( "sed -i 's;%s;../../../..;g' %s", - $this->moduleDir ?: dirname($this->appDir), + $this->moduleDir, $path )); } @@ -433,12 +376,7 @@ class GettextTranslationHelper $catalog = new File($this->catalogPath, 'w'); try { - if ($this->moduleDir) { - $this->getSourceFileNames($this->moduleDir, $catalog); - } else { - $this->getSourceFileNames($this->appDir, $catalog); - $this->getSourceFileNames($this->libDir, $catalog); - } + $this->getSourceFileNames($this->moduleDir, $catalog); } catch (Exception $error) { throw $error; } diff --git a/modules/translation/module.info b/modules/translation/module.info index 196c63dce..8dc9467a4 100644 --- a/modules/translation/module.info +++ b/modules/translation/module.info @@ -1,7 +1,7 @@ Module: translation Version: 2.8.2 Description: Translation module - This module allows developers and translators to translate Icinga Web 2 and - its modules for multiple languages. You do not need this module to run an - internationalized web frontend. This is only for people who want to contribute - translations or translate just their own modules. + This module allows developers and translators to translate modules for multiple + languages. You do not need this module to run an internationalized web frontend. + This is only for people who want to contribute translations or translate just + their own modules. diff --git a/test/php/library/Icinga/Util/TranslatorTest.php b/test/php/library/Icinga/Util/TranslatorTest.php deleted file mode 100644 index 1ebb7b414..000000000 --- a/test/php/library/Icinga/Util/TranslatorTest.php +++ /dev/null @@ -1,286 +0,0 @@ -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' - ); - } -} diff --git a/test/php/regression/Bug6432Test.php b/test/php/regression/Bug6432Test.php deleted file mode 100644 index 410bd9d00..000000000 --- a/test/php/regression/Bug6432Test.php +++ /dev/null @@ -1,22 +0,0 @@ -assertEquals('test', Translator::translate('test', 'invalid_domain')); - } -} diff --git a/test/php/res/locale/de_DE/LC_MESSAGES/icingatest.mo b/test/php/res/locale/de_DE/LC_MESSAGES/icingatest.mo deleted file mode 100644 index 621eab2bf..000000000 Binary files a/test/php/res/locale/de_DE/LC_MESSAGES/icingatest.mo and /dev/null differ diff --git a/test/php/res/locale/de_DE/LC_MESSAGES/icingatest.po b/test/php/res/locale/de_DE/LC_MESSAGES/icingatest.po deleted file mode 100644 index 71cf37221..000000000 --- a/test/php/res/locale/de_DE/LC_MESSAGES/icingatest.po +++ /dev/null @@ -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 \n" -"Language: de_DE\n" -"Language-Team: LANGUAGE \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" diff --git a/test/php/res/locale/fr_FR/LC_MESSAGES/icingatest.mo b/test/php/res/locale/fr_FR/LC_MESSAGES/icingatest.mo deleted file mode 100644 index 0f7d69f2a..000000000 Binary files a/test/php/res/locale/fr_FR/LC_MESSAGES/icingatest.mo and /dev/null differ diff --git a/test/php/res/locale/fr_FR/LC_MESSAGES/icingatest.po b/test/php/res/locale/fr_FR/LC_MESSAGES/icingatest.po deleted file mode 100644 index 8ae17d6aa..000000000 --- a/test/php/res/locale/fr_FR/LC_MESSAGES/icingatest.po +++ /dev/null @@ -1,2 +0,0 @@ -msgid "Lorem ipsum dolor sit amet" -msgstr "Lorem ipsum dolor sit amet?" \ No newline at end of file