Pārlūkot izejas kodu

Allow translate rules descriptions.

Ferreyra, Maximiliano Gastón 9 gadi atpakaļ
vecāks
revīzija
2d10144a6b

+ 12 - 1
README.md

@@ -47,7 +47,18 @@ Option | Description
 `noResponseCalls` | Disable API response calls
 `actAsUserId` | The user ID to use for authenticated API response calls
 `router` | The router to use, when processing the route files (can be Laravel or Dingo - defaults to Laravel)
-`bindings` | List of route bindings that should be replaced when trying to retrieve route results. Syntax format: `binding_one,id|binding_two,id` 
+`bindings` | List of route bindings that should be replaced when trying to retrieve route results. Syntax format: `binding_one,id|binding_two,id`
+
+## Publish rule descriptions for customisation or translate.
+
+ For default, this package returns the descriptions in the main language of the application. But provides the possibility of publish the language files for customisation or translate.
+
+ ```sh
+ $ php artisan vendor:publish
+ ```
+
+ After to publish you can customize or translate the descriptions in the language you want by editing the files in `public/vendor/apidoc/resources/lang`.
+
 
 ### How does it work?
 

+ 5 - 0
src/Mpociot/ApiDoc/ApiDocGeneratorServiceProvider.php

@@ -16,6 +16,11 @@ class ApiDocGeneratorServiceProvider extends ServiceProvider
     public function boot()
     {
         $this->loadViewsFrom(__DIR__.'/../../resources/views/', 'apidoc');
+        $this->loadTranslationsFrom(__DIR__.'/../../resources/lang', 'apidoc');
+
+        $this->publishes([
+            __DIR__.'/../../resources/lang' => resource_path('lang/vendor/apidoc'),
+        ]);
     }
 
     /**

+ 32 - 31
src/Mpociot/ApiDoc/Generators/AbstractGenerator.php

@@ -3,11 +3,12 @@
 namespace Mpociot\ApiDoc\Generators;
 
 use Faker\Factory;
-use ReflectionClass;
+use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Support\Facades\Validator;
 use Illuminate\Support\Str;
+use Mpociot\ApiDoc\Parsers\RuleDescriptionParser as Description;
+use ReflectionClass;
 use phpDocumentor\Reflection\DocBlock;
-use Illuminate\Support\Facades\Validator;
-use Illuminate\Foundation\Http\FormRequest;
 
 abstract class AbstractGenerator
 {
@@ -196,102 +197,102 @@ abstract class AbstractGenerator
                 break;
             case 'after':
                 $attributeData['type'] = 'date';
-                $attributeData['description'][] = 'Must be a date after: `'.date(DATE_RFC850, strtotime($parameters[0])).'`';
+                $attributeData['description'][] = Description::parse($rule)->with(date(DATE_RFC850, strtotime($parameters[0])))->getDescription();
                 $attributeData['value'] = date(DATE_RFC850, strtotime('+1 day', strtotime($parameters[0])));
                 break;
             case 'alpha':
-                $attributeData['description'][] = 'Only alphabetic characters allowed';
+                $attributeData['description'][] = Description::parse($rule)->getDescription();
                 $attributeData['value'] = $faker->word;
                 break;
             case 'alpha_dash':
-                $attributeData['description'][] = 'Allowed: alpha-numeric characters, as well as dashes and underscores.';
+                $attributeData['description'][] = Description::parse($rule)->getDescription();
                 break;
             case 'alpha_num':
-                $attributeData['description'][] = 'Only alpha-numeric characters allowed';
+                $attributeData['description'][] = Description::parse($rule)->getDescription();
                 break;
             case 'in':
-                $attributeData['description'][] = $this->fancyImplode($parameters, ', ', ' or ');
+                $attributeData['description'][] = Description::parse($rule)->with($this->fancyImplode($parameters, ', ', ' or '))->getDescription();
                 $attributeData['value'] = $faker->randomElement($parameters);
                 break;
             case 'not_in':
-                $attributeData['description'][] = 'Not in: '.$this->fancyImplode($parameters, ', ', ' or ');
+                $attributeData['description'][] = Description::parse($rule)->with($this->fancyImplode($parameters, ', ', ' or '))->getDescription();
                 $attributeData['value'] = $faker->word;
                 break;
             case 'min':
-                $attributeData['description'][] = 'Minimum: `'.$parameters[0].'`';
+                $attributeData['description'][] = Description::parse($rule)->with($parameters)->getDescription();
                 break;
             case 'max':
-                $attributeData['description'][] = 'Maximum: `'.$parameters[0].'`';
+                $attributeData['description'][] = Description::parse($rule)->with($parameters)->getDescription();
                 break;
             case 'between':
                 $attributeData['type'] = 'numeric';
-                $attributeData['description'][] = 'Between: `'.$parameters[0].'` and `'.$parameters[1].'`';
+                $attributeData['description'][] = Description::parse($rule)->with($parameters)->getDescription();
                 $attributeData['value'] = $faker->numberBetween($parameters[0], $parameters[1]);
                 break;
             case 'before':
                 $attributeData['type'] = 'date';
-                $attributeData['description'][] = 'Must be a date preceding: `'.date(DATE_RFC850, strtotime($parameters[0])).'`';
+                $attributeData['description'][] = Description::parse($rule)->with(date(DATE_RFC850, strtotime($parameters[0])))->getDescription();
                 $attributeData['value'] = date(DATE_RFC850, strtotime('-1 day', strtotime($parameters[0])));
                 break;
             case 'date_format':
                 $attributeData['type'] = 'date';
-                $attributeData['description'][] = 'Date format: `'.$parameters[0].'`';
+                $attributeData['description'][] = Description::parse($rule)->with($parameters)->getDescription();
                 break;
             case 'different':
-                $attributeData['description'][] = 'Must have a different value than parameter: `'.$parameters[0].'`';
+                $attributeData['description'][] = Description::parse($rule)->with($parameters)->getDescription();
                 break;
             case 'digits':
                 $attributeData['type'] = 'numeric';
-                $attributeData['description'][] = 'Must have an exact length of `'.$parameters[0].'`';
+                $attributeData['description'][] = Description::parse($rule)->with($parameters)->getDescription();
                 $attributeData['value'] = $faker->randomNumber($parameters[0], true);
                 break;
             case 'digits_between':
                 $attributeData['type'] = 'numeric';
-                $attributeData['description'][] = 'Must have a length between `'.$parameters[0].'` and `'.$parameters[1].'`';
+                $attributeData['description'][] = Description::parse($rule)->with($parameters)->getDescription();
                 break;
             case 'image':
                 $attributeData['type'] = 'image';
-                $attributeData['description'][] = 'Must be an image (jpeg, png, bmp, gif, or svg)';
+                $attributeData['description'][] = Description::parse($rule)->getDescription();
                 break;
             case 'json':
                 $attributeData['type'] = 'string';
-                $attributeData['description'][] = 'Must be a valid JSON string.';
+                $attributeData['description'][] = Description::parse($rule)->getDescription();
                 $attributeData['value'] = json_encode(['foo', 'bar', 'baz']);
                 break;
             case 'mimetypes':
             case 'mimes':
-                $attributeData['description'][] = 'Allowed mime types: '.$this->fancyImplode($parameters, ', ', ' or ');
+                $attributeData['description'][] = Description::parse($rule)->with($this->fancyImplode($parameters, ', ', ' or '))->getDescription();
                 break;
             case 'required_if':
-                $attributeData['description'][] = 'Required if `'.$parameters[0].'` is `'.$parameters[1].'`';
+                $attributeData['description'][] = Description::parse($rule)->with($parameters)->getDescription();
                 break;
             case 'required_unless':
-                $attributeData['description'][] = 'Required unless `'.$parameters[0].'` is `'.$parameters[1].'`';
+                $attributeData['description'][] = Description::parse($rule)->with($parameters)->getDescription();
                 break;
             case 'required_with':
-                $attributeData['description'][] = 'Required if the parameters '.$this->fancyImplode($parameters, ', ', ' or ').' are present.';
+                $attributeData['description'][] = Description::parse($rule)->with($this->fancyImplode($parameters, ', ', ' or '))->getDescription();
                 break;
             case 'required_with_all':
-                $attributeData['description'][] = 'Required if the parameters '.$this->fancyImplode($parameters, ', ', ' and ').' are present.';
+                $attributeData['description'][] = Description::parse($rule)->with($this->fancyImplode($parameters, ', ', ' and '))->getDescription();
                 break;
             case 'required_without':
-                $attributeData['description'][] = 'Required if the parameters '.$this->fancyImplode($parameters, ', ', ' or ').' are not present.';
+                $attributeData['description'][] = Description::parse($rule)->with($this->fancyImplode($parameters, ', ', ' or '))->getDescription();
                 break;
             case 'required_without_all':
-                $attributeData['description'][] = 'Required if the parameters '.$this->fancyImplode($parameters, ', ', ' and ').' are not present.';
+                $attributeData['description'][] = Description::parse($rule)->with($this->fancyImplode($parameters, ', ', ' and '))->getDescription();
                 break;
             case 'same':
-                $attributeData['description'][] = 'Must be the same as `'.$parameters[0].'`';
+                $attributeData['description'][] = Description::parse($rule)->with($parameters)->getDescription();
                 break;
             case 'size':
-                $attributeData['description'][] = 'Must have the size of `'.$parameters[0].'`';
+                $attributeData['description'][] = Description::parse($rule)->with($parameters)->getDescription();
                 break;
             case 'timezone':
-                $attributeData['description'][] = 'Must be a valid timezone identifier';
+                $attributeData['description'][] = Description::parse($rule)->getDescription();
                 $attributeData['value'] = $faker->timezone;
                 break;
             case 'exists':
-                $attributeData['description'][] = 'Valid '.Str::singular($parameters[0]).' '.$parameters[1];
+                $attributeData['description'][] = Description::parse($rule)->with([Str::singular($parameters[0]), $parameters[1]])->getDescription();
                 break;
             case 'active_url':
                 $attributeData['type'] = 'url';
@@ -299,7 +300,7 @@ abstract class AbstractGenerator
                 break;
             case 'regex':
                 $attributeData['type'] = 'string';
-                $attributeData['description'][] = 'Must match this regular expression: `'.$parameters[0].'`';
+                $attributeData['description'][] = Description::parse($rule)->with($parameters)->getDescription();
                 break;
             case 'boolean':
                 $attributeData['value'] = true;

+ 75 - 0
src/Mpociot/ApiDoc/Parsers/RuleDescriptionParser.php

@@ -0,0 +1,75 @@
+<?php
+
+namespace Mpociot\ApiDoc\Parsers;
+
+class RuleDescriptionParser
+{
+    private $rule;
+
+    private $parameters = [];
+
+    /**
+     * RuleDescriptionParser constructor.
+     * 
+     * @param null $rule
+     */
+    public function __construct($rule = null)
+    {
+        $this->rule = $rule;
+    }
+
+    /**
+     * Returns the description in the main language of the application.
+     * 
+     * @return array|string
+     */
+    public function getDescription()
+    {
+        $key = "apidoc::rules.{$this->rule}";
+
+        $description = $this->parameters ? $this->translateWithAttributes($key) : trans($key);
+
+        return $description != $key ? $description : [];
+    }
+
+    /**
+     * Sets the parameters for the description string.
+     * @param string|array $parameters
+     * 
+     * @return $this
+     */
+    public function with($parameters)
+    {
+        is_array($parameters) ? $this->parameters += $parameters : $this->parameters[] = $parameters;
+
+        return $this;
+    }
+
+    /**
+     * Returns the description string with the replaced attributes.
+     * @param $key
+     * 
+     * @return string
+     */
+    protected function translateWithAttributes($key)
+    {
+        $translate = trans($key);
+
+        foreach ($this->parameters as $parameter) {
+            $translate = preg_replace('/:attribute/', $parameter, $translate, 1);
+        }
+
+        return $translate;
+    }
+
+    /**
+     * Provides a named constructor.
+     * @param null $rule
+     * 
+     * @return static
+     */
+    public static function parse($rule = null)
+    {
+        return new static($rule);
+    }
+}

+ 33 - 0
src/resources/lang/en/rules.php

@@ -0,0 +1,33 @@
+<?php
+
+return [
+    'after' => 'Must be a date after: `:attribute`',
+    'alpha' => 'Only alphabetic characters allowed',
+    'alpha_dash' => 'Allowed: alpha-numeric characters, as well as dashes and underscores.',
+    'alpha_num' => 'Only alpha-numeric characters allowed',
+    'in' => ':attribute',
+    'not_in' => 'Not in: :attribute',
+    'min' => 'Minimum: `:attribute`',
+    'max' => 'Maximum: `:attribute`',
+    'between' => 'Between: `:attribute` and `:attribute`',
+    'before' => 'Must be a date preceding: `:attribute`',
+    'date_format' => 'Date format: `:attribute`',
+    'different' => 'Must have a different value than parameter: `:attribute`',
+    'digits' => 'Must have an exact length of `:attribute`',
+    'digits_between' => 'Must have a length between `:attribute` and `:attribute`',
+    'image' => 'Must be an image (jpeg, png, bmp, gif, or svg)',
+    'json' => 'Must be a valid JSON string.',
+    'mimetypes' => 'Allowed mime types: :attribute',
+    'mimes' => 'Allowed mime types: :attribute',
+    'required_if' => 'Required if `:attribute` is `:attribute`',
+    'required_unless' => 'Required unless `:attribute` is `:attribute`',
+    'required_with' => 'Required if the parameters :attribute are present.',
+    'required_with_all' => 'Required if the parameters :attribute are present.',
+    'required_without' => 'Required if the parameters :attribute are not present.',
+    'required_without_all' => 'Required if the parameters :attribute are not present.',
+    'same' => 'Must be the same as `:attribute`',
+    'size' => 'Must have the size of `:attribute`',
+    'timezone' => 'Must be a valid timezone identifier',
+    'exists' => 'Valid :attribute :attribute',
+    'regex' => 'Must match this regular expression: `:attribute`',
+];

+ 11 - 3
tests/ApiDocGeneratorTest.php

@@ -3,11 +3,12 @@
 namespace Mpociot\ApiDoc\Tests;
 
 use Illuminate\Routing\Route;
+use Illuminate\Support\Facades\Route as RouteFacade;
+use Mpociot\ApiDoc\ApiDocGeneratorServiceProvider;
 use Mpociot\ApiDoc\Generators\LaravelGenerator;
-use Orchestra\Testbench\TestCase;
-use Mpociot\ApiDoc\Tests\Fixtures\TestRequest;
 use Mpociot\ApiDoc\Tests\Fixtures\TestController;
-use Illuminate\Support\Facades\Route as RouteFacade;
+use Mpociot\ApiDoc\Tests\Fixtures\TestRequest;
+use Orchestra\Testbench\TestCase;
 
 class ApiDocGeneratorTest extends TestCase
 {
@@ -16,6 +17,13 @@ class ApiDocGeneratorTest extends TestCase
      */
     protected $generator;
 
+    protected function getPackageProviders($app)
+    {
+        return [
+            ApiDocGeneratorServiceProvider::class,
+        ];
+    }
+
     /**
      * Setup the test environment.
      */

+ 5 - 3
tests/DingoGeneratorTest.php

@@ -3,11 +3,12 @@
 namespace Mpociot\ApiDoc\Tests;
 
 use Dingo\Api\Provider\LaravelServiceProvider;
-use Mpociot\ApiDoc\Tests\Fixtures\DingoTestController;
-use Orchestra\Testbench\TestCase;
+use Mpociot\ApiDoc\ApiDocGeneratorServiceProvider;
 use Mpociot\ApiDoc\Generators\DingoGenerator;
-use Mpociot\ApiDoc\Tests\Fixtures\TestRequest;
+use Mpociot\ApiDoc\Tests\Fixtures\DingoTestController;
 use Mpociot\ApiDoc\Tests\Fixtures\TestController;
+use Mpociot\ApiDoc\Tests\Fixtures\TestRequest;
+use Orchestra\Testbench\TestCase;
 
 class DingoGeneratorTest extends TestCase
 {
@@ -20,6 +21,7 @@ class DingoGeneratorTest extends TestCase
     {
         return [
             LaravelServiceProvider::class,
+            ApiDocGeneratorServiceProvider::class,
         ];
     }
 

+ 90 - 0
tests/RuleDescriptionParserTest.php

@@ -0,0 +1,90 @@
+<?php
+
+namespace Mpociot\ApiDoc\Tests;
+
+use Mpociot\ApiDoc\ApiDocGeneratorServiceProvider;
+use Mpociot\ApiDoc\Parsers\RuleDescriptionParser;
+use Orchestra\Testbench\TestCase;
+
+class RuleDescriptionParserTest extends TestCase
+{
+    public function testReturnsAnEmptyDescriptionIfARuleIsNotParsed()
+    {
+        $rule = new RuleDescriptionParser();
+
+        $this->assertEmpty($rule->getDescription());
+    }
+
+    public function testProvidesANamedContructor()
+    {
+        $this->assertInstanceOf(RuleDescriptionParser::class, RuleDescriptionParser::parse());
+    }
+
+    public function testReturnsADescriptionInTheMainLanguageOfTheApplication()
+    {
+        $expected = 'Only alphabetic characters allowed';
+        $rule = new RuleDescriptionParser('alpha');
+
+        $this->assertEquals($expected, $rule->getDescription());
+    }
+
+    public function testReturnsAnEmptyDescriptionIfNotAvailable()
+    {
+        $rule = new RuleDescriptionParser('dummy_rule');
+
+        $description = $rule->getDescription();
+
+        $this->assertEmpty($description);
+    }
+
+    public function testAllowsToPassParametersToTheDescription()
+    {
+        $expected = 'Must have an exact length of `2`';
+        $rule = new RuleDescriptionParser('digits');
+
+        $actual = $rule->with(2)->getDescription();
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testOnlyPassesParametersIfTheDescriptionAllows()
+    {
+        $expected = 'Only alphabetic characters allowed';
+        $rule = new RuleDescriptionParser('alpha');
+
+        $actual = $rule->with("dummy parameter")->getDescription();
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    public function testAllowsToPassMultipleParametersToTheDescription()
+    {
+        $expected = 'Required if `2 + 2` is `4`';
+        $rule = new RuleDescriptionParser('required_if');
+
+        $actual = $rule->with(['2 + 2', 4])->getDescription();
+
+        $this->assertEquals($expected, $actual);
+    }
+
+    /**
+     * @param \Illuminate\Foundation\Application $app
+     *
+     * @return array
+     */
+    protected function getPackageProviders($app)
+    {
+        return [ApiDocGeneratorServiceProvider::class];
+    }
+    
+    /**
+     * Define environment setup.
+     *
+     * @param  \Illuminate\Foundation\Application  $app
+     * @return void
+     */
+    protected function getEnvironmentSetUp($app)
+    {
+        $app['config']->set('app.locale', 'en');
+    }
+}