diff options
author | Igor Scheller <igor.scheller@igorshp.de> | 2018-10-18 23:34:18 +0200 |
---|---|---|
committer | msquare <msquare@notrademark.de> | 2018-10-30 22:50:22 +0100 |
commit | b443b53919f50bd0176e7b67dfd1efc28276a770 (patch) | |
tree | df4d089d9d431f5223a71e6b40f9d87361705929 | |
parent | 90e1a949623ead173c0952f802d7b5c5487251b1 (diff) |
Translation: added pluralization support
-rw-r--r-- | includes/controller/user_angeltypes_controller.php | 13 | ||||
-rw-r--r-- | includes/view/ShiftCalendarShiftRenderer.php | 6 | ||||
-rw-r--r-- | includes/view/User_view.php | 5 | ||||
-rw-r--r-- | src/Helpers/Translator.php | 50 | ||||
-rw-r--r-- | src/Renderer/Twig/Extensions/Translation.php | 1 | ||||
-rw-r--r-- | src/helpers.php | 17 | ||||
-rw-r--r-- | tests/Unit/Helpers/TranslatorTest.php | 43 | ||||
-rw-r--r-- | tests/Unit/HelpersTest.php | 20 | ||||
-rw-r--r-- | tests/Unit/Renderer/Twig/Extensions/TranslationTest.php | 1 |
9 files changed, 130 insertions, 26 deletions
diff --git a/includes/controller/user_angeltypes_controller.php b/includes/controller/user_angeltypes_controller.php index aa614cf3..734bd1e9 100644 --- a/includes/controller/user_angeltypes_controller.php +++ b/includes/controller/user_angeltypes_controller.php @@ -23,10 +23,15 @@ function user_angeltypes_unconfirmed_hint() . '</a>'; } - return sprintf(ngettext('There is %d unconfirmed angeltype.', 'There are %d unconfirmed angeltypes.', - count($unconfirmed_user_angeltypes)), - count($unconfirmed_user_angeltypes)) . ' ' . __('Angel types which need approvals:') . ' ' . join(', ', - $unconfirmed_links); + $count = count($unconfirmed_user_angeltypes); + return _e( + 'There is %d unconfirmed angeltype.', + 'There are %d unconfirmed angeltypes.', + $count, + [$count] + ) + . ' ' . __('Angel types which need approvals:') + . ' ' . join(', ', $unconfirmed_links); } /** diff --git a/includes/view/ShiftCalendarShiftRenderer.php b/includes/view/ShiftCalendarShiftRenderer.php index 9e40b1c6..80cea241 100644 --- a/includes/view/ShiftCalendarShiftRenderer.php +++ b/includes/view/ShiftCalendarShiftRenderer.php @@ -175,10 +175,8 @@ class ShiftCalendarShiftRenderer $angeltype, $shift_entries ); - $inner_text = sprintf( - ngettext('%d helper needed', '%d helpers needed', $shift_signup_state->getFreeEntries()), - $shift_signup_state->getFreeEntries() - ); + $freeEntriesCount = $shift_signup_state->getFreeEntries(); + $inner_text = _e('%d helper needed', '%d helpers needed', $freeEntriesCount, [$freeEntriesCount]); switch ($shift_signup_state->getState()) { case ShiftSignupState::ADMIN: diff --git a/includes/view/User_view.php b/includes/view/User_view.php index fb541619..f8160765 100644 --- a/includes/view/User_view.php +++ b/includes/view/User_view.php @@ -727,10 +727,7 @@ function User_view_state_admin($freeloader, $user_source) if ($user_source['got_voucher'] > 0) { $state[] = '<span class="text-success">' . glyph('cutlery') - . sprintf( - ngettext('Got %s voucher', 'Got %s vouchers', $user_source['got_voucher']), - $user_source['got_voucher'] - ) + . _e('Got %s voucher', 'Got %s vouchers', $user_source['got_voucher'], [$user_source['got_voucher']]) . '</span>'; } else { $state[] = '<span class="text-danger">' . __('Got no vouchers') . '</span>'; diff --git a/src/Helpers/Translator.php b/src/Helpers/Translator.php index 1e953a21..94fbd795 100644 --- a/src/Helpers/Translator.php +++ b/src/Helpers/Translator.php @@ -39,11 +39,39 @@ class Translator { $translated = $this->translateGettext($key); - if (!empty($replace)) { - $translated = call_user_func_array('sprintf', array_merge([$translated], $replace)); + return $this->replaceText($translated, $replace); + } + + /** + * Get the translation for a given key + * + * @param string $key + * @param string $pluralKey + * @param int $number + * @param array $replace + * @return string + */ + public function translatePlural(string $key, string $pluralKey, int $number, array $replace = []): string + { + $translated = $this->translateGettextPlural($key, $pluralKey, $number); + + return $this->replaceText($translated, $replace); + } + + /** + * Replace placeholders + * + * @param string $key + * @param array $replace + * @return mixed|string + */ + protected function replaceText(string $key, array $replace = []) + { + if (empty($replace)) { + return $key; } - return $translated; + return call_user_func_array('sprintf', array_merge([$key], $replace)); } /** @@ -55,7 +83,21 @@ class Translator */ protected function translateGettext(string $key): string { - return _($key); + return gettext($key); + } + + /** + * Translate the key via gettext + * + * @param string $key + * @param string $keyPlural + * @param int $number + * @return string + * @codeCoverageIgnore + */ + protected function translateGettextPlural(string $key, string $keyPlural, int $number): string + { + return ngettext($key, $keyPlural, $number); } /** diff --git a/src/Renderer/Twig/Extensions/Translation.php b/src/Renderer/Twig/Extensions/Translation.php index 63f9800e..41619c19 100644 --- a/src/Renderer/Twig/Extensions/Translation.php +++ b/src/Renderer/Twig/Extensions/Translation.php @@ -44,6 +44,7 @@ class Translation extends TwigExtension { return [ new TwigFunction('__', [$this->translator, 'translate']), + new TwigFunction('_e', [$this->translator, 'translatePlural']), ]; } diff --git a/src/helpers.php b/src/helpers.php index 84f26dfa..64ca9ec8 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -154,6 +154,23 @@ function __($key, $replace = []) } /** + * Translate the given message + * + * @param string $key + * @param string $keyPlural + * @param int $number + * @param array $replace + * @return string + */ +function _e($key, $keyPlural, $number, $replace = []) +{ + /** @var Translator $translator */ + $translator = app('translator'); + + return $translator->translatePlural($key, $keyPlural, $number, $replace); +} + +/** * @param string $path * @param array $parameters * @return UrlGeneratorInterface|string diff --git a/tests/Unit/Helpers/TranslatorTest.php b/tests/Unit/Helpers/TranslatorTest.php index 396d2b65..34050e42 100644 --- a/tests/Unit/Helpers/TranslatorTest.php +++ b/tests/Unit/Helpers/TranslatorTest.php @@ -10,12 +10,12 @@ use stdClass; class TranslatorTest extends ServiceProviderTest { /** - * @covers \Engelsystem\Helpers\Translator::__construct() - * @covers \Engelsystem\Helpers\Translator::setLocale() - * @covers \Engelsystem\Helpers\Translator::setLocales() - * @covers \Engelsystem\Helpers\Translator::getLocale() - * @covers \Engelsystem\Helpers\Translator::getLocales() - * @covers \Engelsystem\Helpers\Translator::hasLocale() + * @covers \Engelsystem\Helpers\Translator::__construct + * @covers \Engelsystem\Helpers\Translator::setLocale + * @covers \Engelsystem\Helpers\Translator::setLocales + * @covers \Engelsystem\Helpers\Translator::getLocale + * @covers \Engelsystem\Helpers\Translator::getLocales + * @covers \Engelsystem\Helpers\Translator::hasLocale */ public function testInit() { @@ -47,7 +47,8 @@ class TranslatorTest extends ServiceProviderTest } /** - * @covers \Engelsystem\Helpers\Translator::translate() + * @covers \Engelsystem\Helpers\Translator::translate + * @covers \Engelsystem\Helpers\Translator::replaceText */ public function testTranslate() { @@ -56,14 +57,36 @@ class TranslatorTest extends ServiceProviderTest ->setConstructorArgs(['de_DE.UTF-8', ['de_DE.UTF-8' => 'Deutsch']]) ->setMethods(['translateGettext']) ->getMock(); - $translator->expects($this->once()) + $translator->expects($this->exactly(2)) ->method('translateGettext') - ->with('My favourite number is %u!') - ->willReturn('Meine Lieblingszahl ist die %u!'); + ->withConsecutive(['Hello!'], ['My favourite number is %u!']) + ->willReturnOnConsecutiveCalls('Hallo!', 'Meine Lieblingszahl ist die %u!'); + + $return = $translator->translate('Hello!'); + $this->assertEquals('Hallo!', $return); $return = $translator->translate('My favourite number is %u!', [3]); $this->assertEquals('Meine Lieblingszahl ist die 3!', $return); } + + /** + * @covers \Engelsystem\Helpers\Translator::translatePlural + */ + public function testTranslatePlural() + { + /** @var Translator|MockObject $translator */ + $translator = $this->getMockBuilder(Translator::class) + ->setConstructorArgs(['de_DE.UTF-8', ['de_DE.UTF-8' => 'Deutsch']]) + ->setMethods(['translateGettextPlural']) + ->getMock(); + $translator->expects($this->once()) + ->method('translateGettextPlural') + ->with('%s apple', '%s apples', 2) + ->willReturn('2 Äpfel'); + + $return = $translator->translatePlural('%s apple', '%s apples', 2, [2]); + $this->assertEquals('2 Äpfel', $return); + } } diff --git a/tests/Unit/HelpersTest.php b/tests/Unit/HelpersTest.php index b9cedd30..b36abc64 100644 --- a/tests/Unit/HelpersTest.php +++ b/tests/Unit/HelpersTest.php @@ -219,6 +219,26 @@ class HelpersTest extends TestCase } /** + * @covers \_e + */ + public function testTranslatePlural() + { + /** @var Translator|MockObject $translator */ + $translator = $this->getMockBuilder(Translator::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->getAppMock('translator', $translator); + + $translator->expects($this->once()) + ->method('translatePlural') + ->with('One: %u', 'Multiple: %u', 4, [4]) + ->willReturn('Multiple: 4'); + + $this->assertEquals('Multiple: 4', _e('One: %u', 'Multiple: %u', 4, [4])); + } + + /** * @covers \url */ public function testUrl() diff --git a/tests/Unit/Renderer/Twig/Extensions/TranslationTest.php b/tests/Unit/Renderer/Twig/Extensions/TranslationTest.php index f1548604..18705683 100644 --- a/tests/Unit/Renderer/Twig/Extensions/TranslationTest.php +++ b/tests/Unit/Renderer/Twig/Extensions/TranslationTest.php @@ -40,6 +40,7 @@ class TranslationTest extends ExtensionTest $functions = $extension->getFunctions(); $this->assertExtensionExists('__', [$translator, 'translate'], $functions); + $this->assertExtensionExists('_e', [$translator, 'translatePlural'], $functions); } /** |