From 4ad86f6ed47ede5579e846012cf1b0b7747a17a3 Mon Sep 17 00:00:00 2001 From: ewinslow Date: Mon, 2 Mar 2015 02:32:22 +0000 Subject: [PATCH] chore(i18n): Introduce Locale, Message, and MessageBundle These concepts will help us clean up the i18n code significantly. --- .../classes/Elgg/I18n/ArrayMessageBundle.php | 39 +++++++++++++++ engine/classes/Elgg/I18n/Locale.php | 49 +++++++++++++++++++ engine/classes/Elgg/I18n/Message.php | 32 ++++++++++++ engine/classes/Elgg/I18n/MessageBundle.php | 23 +++++++++ engine/classes/Elgg/I18n/NullMessage.php | 29 +++++++++++ engine/classes/Elgg/I18n/NullTranslator.php | 8 ++- engine/classes/Elgg/I18n/SprintfMessage.php | 33 +++++++++++++ .../phpunit/Elgg/I18n/TranslatorTest.php | 29 ++++++++++- 8 files changed, 236 insertions(+), 6 deletions(-) create mode 100644 engine/classes/Elgg/I18n/ArrayMessageBundle.php create mode 100644 engine/classes/Elgg/I18n/Locale.php create mode 100644 engine/classes/Elgg/I18n/Message.php create mode 100644 engine/classes/Elgg/I18n/MessageBundle.php create mode 100644 engine/classes/Elgg/I18n/NullMessage.php create mode 100644 engine/classes/Elgg/I18n/SprintfMessage.php diff --git a/engine/classes/Elgg/I18n/ArrayMessageBundle.php b/engine/classes/Elgg/I18n/ArrayMessageBundle.php new file mode 100644 index 00000000000..85c00943307 --- /dev/null +++ b/engine/classes/Elgg/I18n/ArrayMessageBundle.php @@ -0,0 +1,39 @@ +messages = $messages; + } + + /** @inheritDoc */ + public function get($key) { + if (!is_string($key) || !isset($this->messages[$key]) || !is_string($this->messages[$key])) { + // TODO(ewinslow): Throw an exception in strict mode? + return null; + } + + return new SprintfMessage($this->messages[$key]); + } +} diff --git a/engine/classes/Elgg/I18n/Locale.php b/engine/classes/Elgg/I18n/Locale.php new file mode 100644 index 00000000000..ff31813f1db --- /dev/null +++ b/engine/classes/Elgg/I18n/Locale.php @@ -0,0 +1,49 @@ +locale = $locale; + } + + /** @inheritDoc */ + public function __toString() { + return $this->locale; + } + + /** + * Create a language, asserting that the language code is valid. + * + * @param string $locale Language code + * + * @return Locale + * + * @throws InvalidLocaleException + */ + public static function parse($locale) { + // TODO(evan): Better sanitizing of locales using \Locale perhaps + if (strlen($locale) < 2 || strlen($locale) > 5) { + throw new InvalidLocaleException("Unrecognized locale: $locale"); + } + + return new Locale($locale); + } +} \ No newline at end of file diff --git a/engine/classes/Elgg/I18n/Message.php b/engine/classes/Elgg/I18n/Message.php new file mode 100644 index 00000000000..271bab062f7 --- /dev/null +++ b/engine/classes/Elgg/I18n/Message.php @@ -0,0 +1,32 @@ + when PHP supports generics? + * + * @since 1.11 + * + * @access private + */ +interface MessageBundle { + + /** + * Fetch the translatable message associated with the given key + * + * @param string $key + * + * @return Message? + */ + public function get($key); +} \ No newline at end of file diff --git a/engine/classes/Elgg/I18n/NullMessage.php b/engine/classes/Elgg/I18n/NullMessage.php new file mode 100644 index 00000000000..240f8abc903 --- /dev/null +++ b/engine/classes/Elgg/I18n/NullMessage.php @@ -0,0 +1,29 @@ +template = $template; + } + + /** @inheritDoc */ + public function format(array $args) { + return $this->template; + } + + public function getTemplate() { + return $this->template; + } +} \ No newline at end of file diff --git a/engine/classes/Elgg/I18n/NullTranslator.php b/engine/classes/Elgg/I18n/NullTranslator.php index 028a1e5e9e2..bf625b255f9 100644 --- a/engine/classes/Elgg/I18n/NullTranslator.php +++ b/engine/classes/Elgg/I18n/NullTranslator.php @@ -5,13 +5,11 @@ /** * WARNING: API IN FLUX. DO NOT USE DIRECTLY. * - * @access private + * @since 1.10.0 * - * @package Elgg.Core - * @subpackage I18n - * @since 1.10.0 + * @access private */ -class NullTranslator extends Translator { +final class NullTranslator extends Translator { /** @inheritDoc */ public function translate($key, $args = array(), $lang = '') { return $key; diff --git a/engine/classes/Elgg/I18n/SprintfMessage.php b/engine/classes/Elgg/I18n/SprintfMessage.php new file mode 100644 index 00000000000..f455413e616 --- /dev/null +++ b/engine/classes/Elgg/I18n/SprintfMessage.php @@ -0,0 +1,33 @@ +template = $template; + } + + /** @inheritDoc */ + public function format(array $args = []) { + return vsprintf($this->template, $args); + } + + /** @inheritDoc */ + public function getTemplate() { + return $this->template; + } +} \ No newline at end of file diff --git a/engine/tests/phpunit/Elgg/I18n/TranslatorTest.php b/engine/tests/phpunit/Elgg/I18n/TranslatorTest.php index e61db7fa2ad..e3d12512c82 100644 --- a/engine/tests/phpunit/Elgg/I18n/TranslatorTest.php +++ b/engine/tests/phpunit/Elgg/I18n/TranslatorTest.php @@ -12,7 +12,34 @@ public function testSetLanguageFromGetParameter() { _elgg_services()->input->set('hl', $input_lang); $lang = $translator->getLanguage(); - $this->assertEquals($lang, $input_lang); + $this->assertEquals($lang, $input_lang); } + public function testKeyIsReturnedIfNoTranslationCanBeFound() { + $translator = new Translator(); + + $this->assertEquals('foobar', $translator->translate('foobar')); + } + + public function testTranslateReturnsTranslationForSpecifiedLanguageIfAvailable() { + $this->markTestIncomplete(); + } + + public function testTranslateReturnsTranslationForUserLanguageIfNoLanguageWasSpecified() { + $this->markTestIncomplete(); + } + + public function testFallsBackToUserLanguageIfTranslationForSpecifiedLanguageIsNotAvailable() { + $this->markTestIncomplete(); + } + + public function testDoesNotPerformSprintfFormattingIfArgsNotProvided() { + $this->markTestSkipped('Translator requires refactoring before this can work'); + + $messages = new ArrayMessageBundle(['foo' => '%s']); + $translator = new Translator(['en' => $messages]); + + $this->assertEquals('%s', $translator->translate('foo')); + $this->assertEquals('%s', $translator->translate('foo', 'es')); + } } \ No newline at end of file