From b92149f4f3b59f9aa3589dc21f7469ffe55a7a9c Mon Sep 17 00:00:00 2001 From: Amegatron Date: Sun, 22 Jun 2014 19:55:04 +0400 Subject: [PATCH] Initial commit --- .gitignore | 4 + .travis.yml | 14 +++ README.md | 98 +++++++++++++++++++ composer.json | 21 ++++ docs/README-ru.md | 98 +++++++++++++++++++ phpunit.xml | 18 ++++ .../LocalizedCarbon/DiffFactoryFacade.php | 15 +++ .../LocalizedCarbon/DiffFormatterFactory.php | 55 +++++++++++ .../DiffFormatters/DiffFormatterInterface.php | 5 + .../DiffFormatters/EnDiffFormatter.php | 18 ++++ .../DiffFormatters/RuDiffFormatter.php | 28 ++++++ .../LocalizedCarbon/LocalizedCarbon.php | 61 ++++++++++++ .../LocalizedCarbonServiceProvider.php | 46 +++++++++ src/lang/.gitkeep | 0 src/lang/ru/units.php | 11 +++ tests/.gitkeep | 0 16 files changed, 492 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 README.md create mode 100644 composer.json create mode 100644 docs/README-ru.md create mode 100644 phpunit.xml create mode 100644 src/Laravelrus/LocalizedCarbon/DiffFactoryFacade.php create mode 100644 src/Laravelrus/LocalizedCarbon/DiffFormatterFactory.php create mode 100644 src/Laravelrus/LocalizedCarbon/DiffFormatters/DiffFormatterInterface.php create mode 100644 src/Laravelrus/LocalizedCarbon/DiffFormatters/EnDiffFormatter.php create mode 100644 src/Laravelrus/LocalizedCarbon/DiffFormatters/RuDiffFormatter.php create mode 100644 src/Laravelrus/LocalizedCarbon/LocalizedCarbon.php create mode 100644 src/Laravelrus/LocalizedCarbon/LocalizedCarbonServiceProvider.php create mode 100644 src/lang/.gitkeep create mode 100644 src/lang/ru/units.php create mode 100644 tests/.gitkeep diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5826402 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/vendor +composer.phar +composer.lock +.DS_Store diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..aa14ee5 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,14 @@ +language: php + +php: + - 5.3 + - 5.4 + - 5.5 + - 5.6 + - hhvm + +before_script: + - composer self-update + - composer install --prefer-source --no-interaction --dev + +script: phpunit diff --git a/README.md b/README.md new file mode 100644 index 0000000..9aceee4 --- /dev/null +++ b/README.md @@ -0,0 +1,98 @@ +# Localized Carbon + ++ [Introduction](#intro) ++ [Usage](#usage) ++ [Supported languages](#languages) ++ [Extending](#extending) ++ [Contributing](#contributing) + + +## Introduction + +Localized Carbon is an extension of a popular Carbon package, designed specially for Laravel framework. By localization I mean its `diffForHumans` function, which returns a human-readable string of time interval. + + +## Usage + +Imagine you have a `Comment` model which has default timestamp fields. You want to display, how much time has gone since its `create_at` in a human-readable format. You can achieve it this way in your Blade template: + +``` +{{ LocalizedCarbon::instance($comment->created_at)->diffForHumans() }} +``` + +In this case the class will output something like "5 minutes ago". Note that for just an English version of the string original Carbon would be enough. This `LocalizedCarbon` is used to display the message in the current application language. For example, for Russian language it will display "5 минут назад". + +As in original Carbon, `diffForHumans` functions has an optional first argument (which is another Carbon instance). It specified the time to which difference should be calculated. By default (a missing or `null` value) current time is used. + +Also `LocalizedCarbon` adds an optional second argument, in which you may specify the desired language, or directly a `formatter` class which is used to format the difference-string (see [extending Localized Carbon](#extending)). By default current application language is used. + + +## Supported languages + +Current version of Localized Carbon ships with two localizations: + ++ English ++ Russian + +But it is extendable, so you may write and use your own localization without altering the contents of the package. See [extending Localized Carbon](#extending). + +## Installation + +Add the following requirement to your `composer.json`: `"laravelrus/localized-carbon": "dev-master"`. + +Next, add package's Service Provider to `app/config/app.php` in `providers` section: + +``` + 'Laravelrus\LocalizedCarbon\LocalizedCarbonServiceProvider', +``` + +After that you may want to add some Aliases (`aliases` section of the same config): + +``` + 'LocalizedCarbon' => 'Laravelrus\LocalizedCarbon\LocalizedCarbon', + 'DiffFormatter' => 'Laravelrus\LocalizedCarbon\DiffFactoryFacade', +``` + +Note that `DiffFormatter` will only be used for extending default localizations. See [extending Localized Carbon](#extending). + + +## Extending Localized Carbon + +If needed localization is not shipped with this package, you may write your own and extend Localized Carbon with it, not even touching the vendor folder itself. + +For this you should first write your `DiffFormatter` class, implementing `Laravelrus\LocalizedCarbon\DiffFormatters\DiffFormatterInterface`. This interface forces the class to have a single `format` method which looks like this: + +``` +public function format($isNow, $isFuture, $delta, $unit); +``` + +`$isNow` is a boolean, which is `true` when the time difference is calculated relevant to current time. +`$isFuture` is boolean, which is `true` if the DateTime object is in the future relevant to comparable time. +`$delta` is an integer, equals to number of units of difference. +`$unit` is a time-"unit". It can be either: `second`, `minute`, `hour`, `day`, `week`, `month` or `year`. + +So, your `format` method should return a string based on this arguments. As an example see an existing DiffFormatters in `vendor\laravelrus\localized-carbon\src\Laravelrus\LocalizedCarbon\DiffFormatters` directory. You can also reference a lang-files, using `Lang::choice` as it is done in Russian localization for example. + +When your class is ready, you must register it within the Localized Carbon. For this you must call `DiffFormatter::extend` method from within ane file which is loaded by the framework. For example, you can do it somewhere in `app/start/global.php`. + +The `extend` method expects two parameters: first is the language you want to be supported (most often it would be `App::getLocale()` if you want just to use application's language). Next is the instance of your formatter, OR just a name of the class if it can be autoloaded. Consider these examples: + +``` +$formatter = new Acme\DiffFormatters\FrDiffFormatter; +DiffFormatter::extend('fr', $formatter); + +// OR + +DiffFormatter::extend('fr', 'Acme\\DiffFormatters\\FrDiffFormatter'); +``` + +In the latter case the formatter will be autoloaded when it is needed using IoC. Also note that formatter is loaded only once during application life-cycle due to optimization considerations. + + +## Contributing + +If you've written a formatter for the language which is not supported by current version of Localized Carbon out of the box - feel free to make a pull request with it, but be sure to adjust your formatter for been used by the package. + +The formatter should lie in `src/Laravelrus/LocalizedCarbon/DiffFormatters` directory, following a simple naming convention: the class name should start with the desired language in lower-case, but the first letter in upper-case. The rest part of the name should be "DiffFormatter". The file name should correspond to the class name. + +For example, the formatter for `fr` language would lie in `src/Laravelrus/LocalizedCarbon/DiffFormatters/FrDiffFormatter.php`, and the class name would be `FrDiffFormatter`. \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..b3a058a --- /dev/null +++ b/composer.json @@ -0,0 +1,21 @@ +{ + "name": "laravelrus/localized-carbon", + "description": "A localizable version of Carbon", + "keywords": ["laravel", "carbon", "datetime", "date", "time"], + "authors": [ + { + "name": "Aleksandr Egorov", + "email": "amego2006@gmail.com" + } + ], + "require": { + "php": ">=5.4.0", + "illuminate/support": "4.2.*" + }, + "autoload": { + "psr-0": { + "Laravelrus\\LocalizedCarbon\\": "src/" + } + }, + "minimum-stability": "stable" +} diff --git a/docs/README-ru.md b/docs/README-ru.md new file mode 100644 index 0000000..435034e --- /dev/null +++ b/docs/README-ru.md @@ -0,0 +1,98 @@ +# Localized Carbon + ++ [Вступление](#intro) ++ [Использование](#usage) ++ [Поддерживаемые языки](#languages) ++ [Расширение пакета](#extending) ++ [Вклад в развитие пакета](#contributing) + + +## Вступление + +`Localized Carbon` - это расширение популярного пакета `Carbon`. Оно предназначено для использования исключительно во фреймворке Laravel. Под локализацией подразумевается локализация функции `diffForHumans` оригинального Carbon'а, предназначенная для вывода удобочитамой разницы в датах. + + +## Использование + +Представте, что у вас есть модель `Comment` (комментарий), в которой имеются временные поля по умолчанию (`created_at` и `updated_at`). И вам требуется вывести информацию о том, сколько времени прошло с момента создания комментария (поле `created_at`), в удобочитаемом формате. Это можно сделать следующим образом в Blade-шаблоне: + +``` +{{ LocalizedCarbon::instance($comment->created_at)->diffForHumans() }} +``` + +В этом случае класс выведет что-то вроде "5 минут назад" для русского языка. + +Как и в исходном Carbon'е, метод `diffForHumans` имеет первый необязательный аргумент (который является другим экземпляром класса `Carbon`). Он указывает время, относительно которого вычислять разницу. По умолчанию (если этот параметр не задан, или равен `null`) используется текущее время. + +В методе классе `LocalizedCarbon` имеется и второе необязательный аргумент, в котором вы можете указать желаемый язык, или напрямую класс-форматтер, используемый для формирования строки-разницы между временами (см. [расширение](#extending)). По умолчанию будет использоваться текущий язык приложения. + + +## Поддерживаемые языки + +Текущая версия Localized Carbon поставляетс со следующими локализациями: + ++ Английский ++ Русский + +Но пакет расширяем, то есть вы можете написать и использоваться свою собственную локализацию, не трогая само содержимое пакета. См. [расширение пакета](#extending). + +## Установка + +Добавте следующее определение в секуцию `require` файла `composer.json` вашего проекта: `"laravelrus/localized-carbon": "dev-master"`. + +Далее нужно добавить сервис провайдер (Service Provider), поставляемый с пакетом, в раздел `providers` файла `app/config/app.php`: + +``` + 'Laravelrus\LocalizedCarbon\LocalizedCarbonServiceProvider', +``` + +После этого рекомендуется добавить следующие алиасы (секция `aliases` того же конфига): + +``` + 'LocalizedCarbon' => 'Laravelrus\LocalizedCarbon\LocalizedCarbon', + 'DiffFormatter' => 'Laravelrus\LocalizedCarbon\DiffFactoryFacade', +``` + +Стоит отметить, что класс `DiffFormatter` будет использоваться только для расширения пакета дополнительными локализациями. См. [расширение пакета](#extending). + + +## Расширение пакета + +Если требуемая локализация не поствляется с пакетом, вы можете написать свою собственную и расширить пакет, не трогая его содержимое. + +Для этого нужно сперва написать свой класс `DiffFormatter`, который реализует интерфейс `Laravelrus\LocalizedCarbon\DiffFormatters\DiffFormatterInterface`. Этот интерфейс требует от класса реализовать единственный метод `format`, который имеет следующий вид: + +``` +public function format($isNow, $isFuture, $delta, $unit); +``` + ++ `$isNow` - это флаг, который равен `true`, если разница во времени вычисляется относительно текущего времени. ++ `$isFuture` - это флаг, который равен `true`, если время находится в будущем относительно проверяемого времени. ++ `$delta` - это число, содержащее разницу во времени в единицах, указанных в `$unit`. ++ `$unit` - это единица измерения параметра `$delta`. Может принимать одно из следующих значений: `second` (секунды), `minute` (минуты), `hour` (часы), `day` (дни), `week` (недели), `month` (месяцы) или `year` (года). + +Таким образом, ваш метод `format` должен возвращать строку, сформированную на основе этих аргументов. Для примера смотрите существующие форметтеры в директории `vendor\laravelrus\localized-carbon\src\Laravelrus\LocalizedCarbon\DiffFormatters`. Вы также можете например ссылаться на языковые файлы, посредством `Lang::choice`, как это сделано, например, в русской локализации. + +Как только ваш класс будет готов, нужно зарегистрировать его в пакете. Для этого нужно вызвать `DiffFormatter::extend` из любого файла, который подключается фреймворком. Например, это можно сделать где-нибудь в файле `app/start/global.php`. + +Этот метод `extend` принимает два аргумента. Первый - это язык, для которого написан этот форматтер (чаще всего это будет `App::getLocale()`, если вы пишете локализацию для текущего языка приложения). Следующий аргумент - это экземпляр вашего класса, ЛИБО просто полное имя вашего класса, принимая во внимание то, что он должен быть доступен для автозагрузки. Взгляните на примеры: + +``` +$formatter = new Acme\DiffFormatters\FrDiffFormatter; +DiffFormatter::extend('fr', $formatter); + +// ИЛИ + +DiffFormatter::extend('fr', 'Acme\\DiffFormatters\\FrDiffFormatter'); +``` + +В последнем случае форматтер будет автоматически загружен, как только в нем будет необходимость (посредством IoC). Имейте также ввиду, что форматтер будет загружен только однажды за весь цикл приложениия из соображений оптимизации. + + +## Вклад в развитие пакета + +Если вы написали локализацию для языка, которые не поставляется с текущей версией пакета, будет здорово, если вы сделаете pull request с ним, убедившись только, что вы "настроили" его для использования внутри пакета. + +Форматтер должен находиться в директории `src/Laravelrus/LocalizedCarbon/DiffFormatters` и следовать следующим соглашениям: имя класса должно начинаться с языка, для которого он написан, в нижнем регистре, но первый символ - в верхнем. Осальная часть имени должна заканчиваться на `DiffFormatter`. Имя файла должно соответствовать имени класса. + +Например, форматтер для языка `fr` (французский) будет находится в файле `src/Laravelrus/LocalizedCarbon/DiffFormatters/FrDiffFormatter.php`, а имя класса будет соответственно `FrDiffFormatter`. \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..3347b75 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ./tests/ + + + diff --git a/src/Laravelrus/LocalizedCarbon/DiffFactoryFacade.php b/src/Laravelrus/LocalizedCarbon/DiffFactoryFacade.php new file mode 100644 index 0000000..37492f8 --- /dev/null +++ b/src/Laravelrus/LocalizedCarbon/DiffFactoryFacade.php @@ -0,0 +1,15 @@ +formatters[$language] = $formatter; + } + + public function get($language) { + $language = strtolower($language); + + if (isset($this->formatters[$language])) { + $formatter = $this->formatters[$language]; + + if (is_string($formatter)) { + $formatter = \App::make($formatter); + } + } else { + $formatterClass = $this->getFormatterClassName($language); + try { + $formatter = \App::make($formatterClass); + } catch (\Exception $e) { + // In case desired formatter could not be loaded + // load a formatter for application's fallback locale + $language = $this->getFallbackLanguage(); + $formatterClass = $this->getFormatterClassName($language); + $formatter = \App::make($formatterClass); + } + } + + if (! $formatter instanceof DiffFormatterInterface) { + throw new \Exception('Formatter for language ' . $language . ' should implement DiffFormatterInterface.'); + } + + // Remember instance for further use + $this->extend($language, $formatter); + + return $formatter; + } + + protected function getFormatterClassName($language) { + $name = ucfirst(strtolower($language)); + $name = 'Laravelrus\\LocalizedCarbon\\DiffFormatters\\' . $name . 'DiffFormatter'; + + return $name; + } + + protected function getFallbackLanguage() { + return \Config::get('app.fallback_locale'); + } +} diff --git a/src/Laravelrus/LocalizedCarbon/DiffFormatters/DiffFormatterInterface.php b/src/Laravelrus/LocalizedCarbon/DiffFormatters/DiffFormatterInterface.php new file mode 100644 index 0000000..c997fb3 --- /dev/null +++ b/src/Laravelrus/LocalizedCarbon/DiffFormatters/DiffFormatterInterface.php @@ -0,0 +1,5 @@ +tz); + } + + $isFuture = $this->gt($other); + + $delta = $other->diffInSeconds($this); + + // 4 weeks per month, 365 days per year... good enough!! + $divs = array( + 'second' => self::SECONDS_PER_MINUTE, + 'minute' => self::MINUTES_PER_HOUR, + 'hour' => self::HOURS_PER_DAY, + 'day' => self::DAYS_PER_WEEK, + 'week' => 4, + 'month' => self::MONTHS_PER_YEAR + ); + + $unit = 'year'; + + foreach ($divs as $divUnit => $divValue) { + if ($delta < $divValue) { + $unit = $divUnit; + break; + } + + $delta = floor($delta / $divValue); + } + + if ($delta == 0) { + $delta = 1; + } + + // Format and return + return $formatter->format($isNow, $isFuture, $delta, $unit); + } +} diff --git a/src/Laravelrus/LocalizedCarbon/LocalizedCarbonServiceProvider.php b/src/Laravelrus/LocalizedCarbon/LocalizedCarbonServiceProvider.php new file mode 100644 index 0000000..a7f4abf --- /dev/null +++ b/src/Laravelrus/LocalizedCarbon/LocalizedCarbonServiceProvider.php @@ -0,0 +1,46 @@ +package('laravelrus/localized-carbon'); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + $this->app->singleton('difffactory', function() { + return new DiffFormatterFactory(); + }); + } + + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return array('diffformatter'); + } + +} diff --git a/src/lang/.gitkeep b/src/lang/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/lang/ru/units.php b/src/lang/ru/units.php new file mode 100644 index 0000000..cb78316 --- /dev/null +++ b/src/lang/ru/units.php @@ -0,0 +1,11 @@ + "секунду|секунды|секунд", + "minute" => "минуту|минуты|минут", + "hour" => "час|часа|часов", + "day" => "день|дня|дней", + "week" => "неделю|недели|недель", + "month" => "месяц|месяца|месяцев", + "year" => "год|года|лет", +); diff --git a/tests/.gitkeep b/tests/.gitkeep new file mode 100644 index 0000000..e69de29