commit
18aad562dd
|
@ -918,10 +918,21 @@ class Module
|
||||||
* Translate a string with the global mt()
|
* Translate a string with the global mt()
|
||||||
*
|
*
|
||||||
* @param $string
|
* @param $string
|
||||||
|
* @param null $context
|
||||||
|
*
|
||||||
* @return mixed|string
|
* @return mixed|string
|
||||||
*/
|
*/
|
||||||
protected function translate($string)
|
protected function translate($string, $context = null)
|
||||||
{
|
{
|
||||||
return mt($this->name, $string);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,23 +5,85 @@
|
||||||
use Icinga\Util\Translator;
|
use Icinga\Util\Translator;
|
||||||
|
|
||||||
if (extension_loaded('gettext')) {
|
if (extension_loaded('gettext')) {
|
||||||
function t($messageId)
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see Translator::translate() For the function documentation.
|
||||||
|
*/
|
||||||
|
function t($messageId, $context = null)
|
||||||
{
|
{
|
||||||
return Translator::translate($messageId, Translator::DEFAULT_DOMAIN);
|
return Translator::translate($messageId, Translator::DEFAULT_DOMAIN, $context);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mt($domain, $messageId)
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see Translator::translate() For the function documentation.
|
||||||
|
*/
|
||||||
|
function mt($domain, $messageId, $context = null)
|
||||||
{
|
{
|
||||||
return Translator::translate($messageId, $domain);
|
return Translator::translate($messageId, $domain, $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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see Translator::translatePlural() For the function documentation.
|
||||||
|
*/
|
||||||
|
function mtp($domain, $messageId, $messageId2, $number, $context = null)
|
||||||
|
{
|
||||||
|
return Translator::translatePlural($messageId, $messageId2, $number, $domain, $context);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
function t($messageId)
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see Translator::translate() For the function documentation.
|
||||||
|
*/
|
||||||
|
function t($messageId, $context = null)
|
||||||
{
|
{
|
||||||
return $messageId;
|
return $messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mt($domain, $messageId)
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see Translator::translate() For the function documentation.
|
||||||
|
*/
|
||||||
|
function mt($domain, $messageId, $context = null)
|
||||||
{
|
{
|
||||||
return $messageId;
|
return $messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see Translator::translatePlural() For the function documentation.
|
||||||
|
*/
|
||||||
|
function tp($messageId, $messageId2, $number, $context = null)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if ((int) $number !== 1) {
|
||||||
|
return $messageId2;
|
||||||
|
}
|
||||||
|
return $messageId;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,13 +34,18 @@ class Translator
|
||||||
*
|
*
|
||||||
* Falls back to the default domain in case the string cannot be translated using the given domain
|
* Falls back to the default domain in case the string cannot be translated using the given domain
|
||||||
*
|
*
|
||||||
* @param string $text The string to translate
|
* @param string $text The string to translate
|
||||||
* @param string $domain The primary domain to use
|
* @param string $domain The primary domain to use
|
||||||
|
* @param string|null $context Optional parameter for context based translation
|
||||||
*
|
*
|
||||||
* @return string The translated string
|
* @return string The translated string
|
||||||
*/
|
*/
|
||||||
public static function translate($text, $domain)
|
public static function translate($text, $domain, $context = null)
|
||||||
{
|
{
|
||||||
|
if ($context !== null) {
|
||||||
|
return self::pgettext($text, $domain, $context);
|
||||||
|
}
|
||||||
|
|
||||||
$res = dgettext($domain, $text);
|
$res = dgettext($domain, $text);
|
||||||
if ($res === $text && $domain !== self::DEFAULT_DOMAIN) {
|
if ($res === $text && $domain !== self::DEFAULT_DOMAIN) {
|
||||||
return dgettext(self::DEFAULT_DOMAIN, $text);
|
return dgettext(self::DEFAULT_DOMAIN, $text);
|
||||||
|
@ -48,6 +53,77 @@ class Translator
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 integer $number The number to get the plural or singular string
|
||||||
|
* @param string $domain The primary domain to use
|
||||||
|
* @param string|null $context Optional parameter for context based translation
|
||||||
|
*
|
||||||
|
* @return string The translated string
|
||||||
|
*/
|
||||||
|
public static function translatePlural($textSingular, $textPlural, $number, $domain, $context = null)
|
||||||
|
{
|
||||||
|
if ($context !== null) {
|
||||||
|
return self::pngettext($textSingular, $textPlural, $number, $domain, $context);
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = dngettext($domain, $textSingular, $textPlural, $number);
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emulated pgettext()
|
||||||
|
*
|
||||||
|
* @link http://php.net/manual/de/book.gettext.php#89975
|
||||||
|
*
|
||||||
|
* @param $text
|
||||||
|
* @param $domain
|
||||||
|
* @param $context
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function pgettext($text, $domain, $context)
|
||||||
|
{
|
||||||
|
$contextString = "{$context}\004{$text}";
|
||||||
|
|
||||||
|
$translation = dcgettext($domain, $contextString, LC_MESSAGES);
|
||||||
|
|
||||||
|
if ($translation == $contextString) {
|
||||||
|
return $text;
|
||||||
|
} else {
|
||||||
|
return $translation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emulated pngettext()
|
||||||
|
*
|
||||||
|
* @link http://php.net/manual/de/book.gettext.php#89975
|
||||||
|
*
|
||||||
|
* @param $textSingular
|
||||||
|
* @param $textPlural
|
||||||
|
* @param $number
|
||||||
|
* @param $domain
|
||||||
|
* @param $context
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function pngettext($textSingular, $textPlural, $number, $domain, $context)
|
||||||
|
{
|
||||||
|
$contextString = "{$context}\004{$textSingular}";
|
||||||
|
|
||||||
|
$translation = dcngettext($domain, $contextString, $textPlural, $number, LC_MESSAGES);
|
||||||
|
|
||||||
|
if ($translation == $contextString || $translation == $textPlural) {
|
||||||
|
return ($number == 1 ? $textSingular : $textPlural);
|
||||||
|
} else {
|
||||||
|
return $translation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a new gettext domain
|
* Register a new gettext domain
|
||||||
*
|
*
|
||||||
|
|
|
@ -216,13 +216,29 @@ class ActionController extends Zend_Controller_Action
|
||||||
*
|
*
|
||||||
* Autoselects the module domain, if any, and falls back to the global one if no translation could be found.
|
* 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 $text The string to translate
|
||||||
|
* @param string|null $context Optional parameter for context based translation
|
||||||
*
|
*
|
||||||
* @return string The translated string
|
* @return string The translated string
|
||||||
*/
|
*/
|
||||||
public function translate($text)
|
public function translate($text, $context = null)
|
||||||
{
|
{
|
||||||
return Translator::translate($text, $this->view->translationDomain);
|
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()
|
||||||
|
|
|
@ -127,9 +127,19 @@ class View extends Zend_View_Abstract
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function translate($text)
|
public function translate($text, $context = null)
|
||||||
{
|
{
|
||||||
return Translator::translate($text, $this->translationDomain);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -42,6 +42,40 @@ The same works also for views:
|
||||||
If you need to provide placeholders in your messages, you should wrap the `$this->translate()` with `sprintf()` for e.g.
|
If you need to provide placeholders in your messages, you should wrap the `$this->translate()` with `sprintf()` for e.g.
|
||||||
sprintf($this->translate('Hello User: (%s)'), $user->getName())
|
sprintf($this->translate('Hello User: (%s)'), $user->getName())
|
||||||
|
|
||||||
|
## Translating plural forms
|
||||||
|
|
||||||
|
To provide a plural translation, just use the `translatePlural()` function.
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class ExampleController extends Controller
|
||||||
|
{
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
$this->view->message = $this->translatePlural('Service', 'Services', 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Context based translation
|
||||||
|
|
||||||
|
If you want to provide context based translations, you can easily do it with an extra parameter in both methods
|
||||||
|
`translate()` and `translatePlural()`.
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class ExampleController extends Controller
|
||||||
|
{
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
$this->view->title = $this->translate('My Titile', 'mycontext');
|
||||||
|
$this->view->message = $this->translatePlural('Service', 'Services', 3, 'mycontext');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# Translation for Translators
|
# Translation for Translators
|
||||||
|
|
||||||
Icinga Web 2 internally uses the UNIX standard gettext tool to perform internationalization, this means translation
|
Icinga Web 2 internally uses the UNIX standard gettext tool to perform internationalization, this means translation
|
||||||
|
|
|
@ -237,8 +237,16 @@ class GettextTranslationHelper
|
||||||
'/usr/bin/xgettext',
|
'/usr/bin/xgettext',
|
||||||
'--language=PHP',
|
'--language=PHP',
|
||||||
'--keyword=translate',
|
'--keyword=translate',
|
||||||
|
'--keyword=translate:1,2c',
|
||||||
|
'--keyword=translatePlural:1,2',
|
||||||
|
'--keyword=translatePlural:1,2,4c',
|
||||||
'--keyword=mt:2',
|
'--keyword=mt:2',
|
||||||
|
'--keyword=mtp:2,3',
|
||||||
|
'--keyword=mtp:2,3,5c',
|
||||||
'--keyword=t',
|
'--keyword=t',
|
||||||
|
'--keyword=t:1,2c',
|
||||||
|
'--keyword=tp:1,2',
|
||||||
|
'--keyword=tp:1,2,4c',
|
||||||
'--sort-output',
|
'--sort-output',
|
||||||
'--force-po',
|
'--force-po',
|
||||||
'--omit-header',
|
'--omit-header',
|
||||||
|
@ -332,6 +340,7 @@ class GettextTranslationHelper
|
||||||
'"MIME-Version: 1.0\n"',
|
'"MIME-Version: 1.0\n"',
|
||||||
'"Content-Type: text/plain; charset=' . $headerInfo['charset'] . '\n"',
|
'"Content-Type: text/plain; charset=' . $headerInfo['charset'] . '\n"',
|
||||||
'"Content-Transfer-Encoding: 8bit\n"',
|
'"Content-Transfer-Encoding: 8bit\n"',
|
||||||
|
'"Plural-Forms: nplurals=2; plural=(n != 1);\n"',
|
||||||
''
|
''
|
||||||
)
|
)
|
||||||
) . PHP_EOL . substr($content, strpos($content, '#: '))
|
) . PHP_EOL . substr($content, strpos($content, '#: '))
|
||||||
|
|
|
@ -213,4 +213,76 @@ class TranslatorTest extends BaseTestCase
|
||||||
'Translator::getPreferredLocaleCode does not return the default locale if no match could be found'
|
'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'
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -1,2 +1,42 @@
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Icinga Web 2 Test (0.0.1)\n"
|
||||||
|
"Report-Msgid-Bugs-To: dev@icinga.org\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"
|
msgid "Lorem ipsum dolor sit amet"
|
||||||
msgstr "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"
|
||||||
|
|
Loading…
Reference in New Issue