diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 3f82748..e280aad 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -29,4 +29,6 @@ jobs: run: composer require symfony/console:^${{ matrix.symfony }} symfony/finder:^${{ matrix.symfony }} - name: Execute tests - run: sudo vendor/bin/phpunit --colors=always + run: | + sudo vendor/bin/phpunit --colors=always --exclude-group Translate + sudo vendor/bin/phpunit --colors=always --group Translate diff --git a/src/Commands/Translate.php b/src/Commands/Translate.php index e07c49a..70b1b55 100644 --- a/src/Commands/Translate.php +++ b/src/Commands/Translate.php @@ -5,7 +5,9 @@ namespace LaravelLang\StatusGenerator\Commands; use LaravelLang\StatusGenerator\Constants\Command as CommandName; +use LaravelLang\StatusGenerator\Constants\Option; use LaravelLang\StatusGenerator\Processors\Translate\Translate as TranslateProcessor; +use Symfony\Component\Console\Input\InputOption; class Translate extends Command { @@ -17,6 +19,12 @@ protected function configure(): Command { return parent::configure() ->setName(CommandName::TRANSLATE()) - ->setDescription('Translation of untranslated keys'); + ->setDescription('Translation of untranslated keys') + ->addOption( + Option::LOCALE(), + null, + InputOption::VALUE_OPTIONAL, + 'Translation of values only for the selected localization. By default, translation of all localizations' + ); } } diff --git a/src/Concerns/Parameters.php b/src/Concerns/Parameters.php index 5221ca3..ead5974 100644 --- a/src/Concerns/Parameters.php +++ b/src/Concerns/Parameters.php @@ -3,6 +3,7 @@ namespace LaravelLang\StatusGenerator\Concerns; use DragonCode\Support\Facades\Helpers\Arr; +use DragonCode\Support\Facades\Helpers\Str; use LaravelLang\StatusGenerator\Constants\Option; /** @mixin \LaravelLang\StatusGenerator\Processors\Processor */ @@ -30,7 +31,7 @@ protected function getFileParameter(): ?string protected function getLocaleParameter(): ?string { - return $this->parameter(Option::LOCALE()); + return Str::replace($this->parameter(Option::LOCALE()), '-', '_'); } protected function getProjectParameter(): ?string diff --git a/src/Processors/Create/CreateLocale.php b/src/Processors/Create/CreateLocale.php index eca69f0..a8e8330 100644 --- a/src/Processors/Create/CreateLocale.php +++ b/src/Processors/Create/CreateLocale.php @@ -4,7 +4,6 @@ use DragonCode\Support\Facades\Filesystem\Directory; use DragonCode\Support\Facades\Filesystem\File; -use DragonCode\Support\Facades\Helpers\Str; use Exception; use LaravelLang\StatusGenerator\Processors\Processor; @@ -27,7 +26,7 @@ protected function copy(): void $this->output->task($filename, function () use ($filename) { File::copy( $this->makePath($filename, $this->default_locale), - $this->makePath($filename, $this->getLocale()) + $this->makePath($filename, $this->getLocaleParameter()) ); }); } @@ -40,12 +39,7 @@ protected function sourceFiles(): array protected function exists(): bool { - return Directory::exists($this->getLocalesPath($this->getLocale())); - } - - protected function getLocale(): string - { - return Str::replace($this->getLocaleParameter(), '-', '_'); + return Directory::exists($this->getLocalesPath($this->getLocaleParameter())); } protected function makePath(string $filename, string $locale): string diff --git a/src/Processors/Translate/Translate.php b/src/Processors/Translate/Translate.php index a883482..f5972c1 100644 --- a/src/Processors/Translate/Translate.php +++ b/src/Processors/Translate/Translate.php @@ -15,8 +15,8 @@ public function handle(): void { $source = $this->locales()->getSource(); - foreach ($this->directories() as $locale) { - $this->output->task($locale . ' translation', function () use ($locale, $source) { + foreach ($this->getLocales() as $locale) { + $this->output->task($locale, function () use ($locale, $source) { $locales = $this->locales()->getLocale($locale); $excludes = $this->locales()->getExcludes($locale); @@ -78,6 +78,15 @@ protected function isSameValue(array $source, int|string $key, string $value): b protected function doesntExclude(array $excludes, string $value): bool { - return ! in_array($value, $excludes, true); + return ! in_array($value, $excludes); + } + + protected function getLocales(): array + { + if ($locale = $this->getLocaleParameter()) { + return Arr::filter($this->directories(), fn (string $dir) => $dir === $locale); + } + + return $this->directories(); } } diff --git a/tests/Concerns/Commands.php b/tests/Concerns/Commands.php index 163153c..ae296c3 100644 --- a/tests/Concerns/Commands.php +++ b/tests/Concerns/Commands.php @@ -11,6 +11,8 @@ trait Commands { protected ?CommandName $call = null; + protected array $call_options = []; + protected int $call_tries = 1; protected function command(CommandName $name, array $options = []): void @@ -22,7 +24,7 @@ protected function runCommand(): void { if ($name = $this->call) { for ($i = 0; $i < $this->call_tries; ++$i) { - $this->command($name); + $this->command($name, $this->call_options); } } } diff --git a/tests/Fixtures/Resources/Translate/locales/fr/_excludes.json b/tests/Fixtures/Resources/Translate/locales/fr/_excludes.json new file mode 100644 index 0000000..611048f --- /dev/null +++ b/tests/Fixtures/Resources/Translate/locales/fr/_excludes.json @@ -0,0 +1,5 @@ +[ + "Administrator", + "This field must be accepted.", + "The :attribute must be accepted." +] diff --git a/tests/Fixtures/Resources/Translate/locales/fr/json.json b/tests/Fixtures/Resources/Translate/locales/fr/json.json new file mode 100644 index 0000000..4fccfdb --- /dev/null +++ b/tests/Fixtures/Resources/Translate/locales/fr/json.json @@ -0,0 +1,6 @@ +{ + "Added.": "Added.", + "Administrator": "Administrator", + "Foo": "Foo", + "Bar.": "Bar." +} diff --git a/tests/Fixtures/Resources/Translate/locales/fr/php-inline.json b/tests/Fixtures/Resources/Translate/locales/fr/php-inline.json new file mode 100644 index 0000000..50e21f7 --- /dev/null +++ b/tests/Fixtures/Resources/Translate/locales/fr/php-inline.json @@ -0,0 +1,7 @@ +{ + "accepted": "This field must be accepted.", + "accepted_if": "This field must be accepted when :other is :value.", + "active_url": "This field is not a valid URL.", + "custom2": "Custom field 2", + "sub.array2": "Sub Array 2" +} diff --git a/tests/Fixtures/Resources/Translate/locales/fr/php.json b/tests/Fixtures/Resources/Translate/locales/fr/php.json new file mode 100644 index 0000000..0fcd351 --- /dev/null +++ b/tests/Fixtures/Resources/Translate/locales/fr/php.json @@ -0,0 +1,10 @@ +{ + "0": "Numeric Zero", + "10": "Numeric Ten", + "100": "Numeric One Hundred", + "accepted": "The :attribute must be accepted.", + "accepted_if": "The :attribute must be accepted when :other is :value.", + "active_url": "The :attribute is not a valid URL.", + "custom": "Custom field", + "sub.array": "Sub Array" +} diff --git a/tests/Unit/Commands/Translate/EnglishTest.php b/tests/Unit/Commands/Translate/EnglishTest.php index 15a6079..5bbeb5b 100644 --- a/tests/Unit/Commands/Translate/EnglishTest.php +++ b/tests/Unit/Commands/Translate/EnglishTest.php @@ -4,6 +4,9 @@ namespace Tests\Unit\Commands\Translate; +/** + * @group Translate + */ class EnglishTest extends Base { public function testJson(): void diff --git a/tests/Unit/Commands/Translate/FrenchTest.php b/tests/Unit/Commands/Translate/FrenchTest.php new file mode 100644 index 0000000..e6439a1 --- /dev/null +++ b/tests/Unit/Commands/Translate/FrenchTest.php @@ -0,0 +1,56 @@ +assertJsonFileEqualsJson([ + 'Added.' => 'Ajoutée.', + 'Administrator' => 'Administrator', + ], 'locales/fr/json.json', __FUNCTION__); + } + + public function testPhp(): void + { + $values = $this->filesystem->load($this->tempPath('locales/fr/php.json')); + + $this->assertContainsEquals($values[0], ['Zéro numérique']); + $this->assertContainsEquals($values[10], ['Dix numériques']); + $this->assertContainsEquals($values[100], ['Cent numérique']); + + $this->assertSame($values['accepted'], 'The :attribute must be accepted.'); + + $this->assertContainsEquals($values['accepted_if'], ['Le :attribute doit être accepté quand :other vaut :value.']); + + $this->assertContainsEquals($values['active_url'], ['Le :attribute n\'est pas une URL valide.']); + + $this->assertContainsEquals($values['between.array'], ['The :attribute must have between :min and :max items.']); + $this->assertContainsEquals($values['between.file'], ['The :attribute must be between :min and :max kilobytes.']); + } + + public function testPhpInline(): void + { + $values = $this->filesystem->load($this->tempPath('locales/fr/php-inline.json')); + + $this->assertSame($values['accepted'], 'This field must be accepted.'); + + $this->assertContainsEquals($values['accepted_if'], ['Ce champ doit être accepté lorsque :other vaut :value.']); + + $this->assertContainsEquals($values['active_url'], ['Ce champ n\'est pas une URL valide.']); + + $this->assertContainsEquals($values['between.array'], ['This field must have between :min and :max items.']); + $this->assertContainsEquals($values['between.file'], ['This field must be between :min and :max kilobytes.']); + } + + public function testExcludes(): void + { + $this->assertFileExists($this->tempPath('locales/fr/_excludes.json')); + } +} diff --git a/tests/Unit/Commands/Translate/GermanTest.php b/tests/Unit/Commands/Translate/GermanTest.php index 7db6c08..79572c4 100644 --- a/tests/Unit/Commands/Translate/GermanTest.php +++ b/tests/Unit/Commands/Translate/GermanTest.php @@ -4,6 +4,9 @@ namespace Tests\Unit\Commands\Translate; +/** + * @group Translate + */ class GermanTest extends Base { public function testJson(): void diff --git a/tests/Unit/Commands/Translate/PerLocaleTest.php b/tests/Unit/Commands/Translate/PerLocaleTest.php new file mode 100644 index 0000000..f8e1318 --- /dev/null +++ b/tests/Unit/Commands/Translate/PerLocaleTest.php @@ -0,0 +1,66 @@ + 'de', + ]; + + public function testJson(): void + { + $this->assertJsonFileEqualsJson([ + 'Added.' => 'Hinzugefügt.', + 'Administrator' => 'Administrator', + ], 'locales/de/json.json', __FUNCTION__); + + $this->assertJsonFileEqualsJson([ + 'Added.' => 'Added.', + 'Administrator' => 'Administrator', + 'Foo' => 'Foo', + 'Bar.' => 'Bar.', + ], 'locales/fr/json.json', __FUNCTION__); + } + + public function testPhp(): void + { + // German + $values = $this->filesystem->load($this->tempPath('locales/de/php.json')); + + $this->assertContainsEquals($values[0], ['Numerische Null']); + $this->assertContainsEquals($values[10], ['Numerische Zehn']); + $this->assertContainsEquals($values[100], ['Numerisch Hundert']); + + // French + $values = $this->filesystem->load($this->tempPath('locales/fr/php.json')); + + $this->assertContainsEquals($values[0], ['Numeric Zero']); + $this->assertContainsEquals($values[10], ['Numeric Ten']); + $this->assertContainsEquals($values[100], ['Numeric One Hundred']); + } + + public function testPhpInline(): void + { + // German + $values = $this->filesystem->load($this->tempPath('locales/de/php-inline.json')); + + $this->assertContainsEquals( + $values['accepted_if'], + ['Dieses Feld muss akzeptiert werden, wenn :other gleich :value ist.', 'Dieses Feld muss akzeptiert werden, wenn :other :value ist.'] + ); + + $this->assertContainsEquals($values['active_url'], ['Dieses Feld ist keine gültige URL.', 'Das ist keine gültige Internet-Adresse.']); + + // French + $values = $this->filesystem->load($this->tempPath('locales/fr/php-inline.json')); + + $this->assertSame($values['accepted_if'], 'This field must be accepted when :other is :value.'); + $this->assertSame($values['active_url'], 'This field is not a valid URL.'); + } +}