Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement support for proper translation #731

Merged
merged 27 commits into from
Dec 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9d34956
Create ValidationTranslator.php
caendesilva Dec 4, 2022
920965a
Move bulky translation logic to dedicated class
caendesilva Dec 4, 2022
057a215
Add PHPDocs
caendesilva Dec 4, 2022
8d8c383
Create validation.php
caendesilva Dec 4, 2022
7c9b745
Copy over language lines from default Laravel install
caendesilva Dec 4, 2022
c5ac0eb
Add attribution PHPDoc
caendesilva Dec 4, 2022
f624599
Add locale configuration to app.php config
caendesilva Dec 4, 2022
c3020c5
Use Laravel validation
caendesilva Dec 4, 2022
7d81e26
Inline method ValidationTranslator::translate
caendesilva Dec 4, 2022
08ba2c1
Revert "Create ValidationTranslator.php"
caendesilva Dec 4, 2022
d1ad53d
Create TranslationServiceProvider.php
caendesilva Dec 4, 2022
bde7985
Register TranslationServiceProvider
caendesilva Dec 4, 2022
60e18c7
Extends ServiceProvider implements DeferrableProvider
caendesilva Dec 4, 2022
8966651
Add provider method stubs
caendesilva Dec 4, 2022
1b6d6af
Load the translation file
caendesilva Dec 4, 2022
5ae09bd
Implement provides method
caendesilva Dec 4, 2022
f37a99a
Fix relative path
caendesilva Dec 4, 2022
55813f4
Register the language path
caendesilva Dec 4, 2022
8bb71ab
Add todo
caendesilva Dec 4, 2022
7579a23
Register the locales in the service provider
caendesilva Dec 4, 2022
e6d3603
Allow locales to still be configured
caendesilva Dec 4, 2022
26a0c03
Revert "Add locale configuration to app.php config"
caendesilva Dec 4, 2022
352c49a
Don't register custom lang path if a project lang directory exists
caendesilva Dec 4, 2022
7a90341
Apply fixes from StyleCI
StyleCIBot Dec 4, 2022
03379d5
Remove unused provides method
caendesilva Dec 4, 2022
1ff221b
Create TranslationServiceProviderTest.php
caendesilva Dec 4, 2022
ccefa98
Unit test validation
caendesilva Dec 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions packages/framework/resources/lang/en/validation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<?php

declare(strict_types=1);

/**
* The default validation language lines from Laravel.
*
* @link https://github.com/laravel/laravel/blob/9.x/lang/en/validation.php
*
* @license MIT
*/
return [

/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/

'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.',
'after' => 'The :attribute must be a date after :date.',
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
'alpha' => 'The :attribute must only contain letters.',
'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.',
'alpha_num' => 'The :attribute must only contain letters and numbers.',
'array' => 'The :attribute must be an array.',
'before' => 'The :attribute must be a date before :date.',
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
'between' => [
'array' => 'The :attribute must have between :min and :max items.',
'file' => 'The :attribute must be between :min and :max kilobytes.',
'numeric' => 'The :attribute must be between :min and :max.',
'string' => 'The :attribute must be between :min and :max characters.',
],
'boolean' => 'The :attribute field must be true or false.',
'confirmed' => 'The :attribute confirmation does not match.',
'current_password' => 'The password is incorrect.',
'date' => 'The :attribute is not a valid date.',
'date_equals' => 'The :attribute must be a date equal to :date.',
'date_format' => 'The :attribute does not match the format :format.',
'declined' => 'The :attribute must be declined.',
'declined_if' => 'The :attribute must be declined when :other is :value.',
'different' => 'The :attribute and :other must be different.',
'digits' => 'The :attribute must be :digits digits.',
'digits_between' => 'The :attribute must be between :min and :max digits.',
'dimensions' => 'The :attribute has invalid image dimensions.',
'distinct' => 'The :attribute field has a duplicate value.',
'doesnt_end_with' => 'The :attribute may not end with one of the following: :values.',
'doesnt_start_with' => 'The :attribute may not start with one of the following: :values.',
'email' => 'The :attribute must be a valid email address.',
'ends_with' => 'The :attribute must end with one of the following: :values.',
'enum' => 'The selected :attribute is invalid.',
'exists' => 'The selected :attribute is invalid.',
'file' => 'The :attribute must be a file.',
'filled' => 'The :attribute field must have a value.',
'gt' => [
'array' => 'The :attribute must have more than :value items.',
'file' => 'The :attribute must be greater than :value kilobytes.',
'numeric' => 'The :attribute must be greater than :value.',
'string' => 'The :attribute must be greater than :value characters.',
],
'gte' => [
'array' => 'The :attribute must have :value items or more.',
'file' => 'The :attribute must be greater than or equal to :value kilobytes.',
'numeric' => 'The :attribute must be greater than or equal to :value.',
'string' => 'The :attribute must be greater than or equal to :value characters.',
],
'image' => 'The :attribute must be an image.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field does not exist in :other.',
'integer' => 'The :attribute must be an integer.',
'ip' => 'The :attribute must be a valid IP address.',
'ipv4' => 'The :attribute must be a valid IPv4 address.',
'ipv6' => 'The :attribute must be a valid IPv6 address.',
'json' => 'The :attribute must be a valid JSON string.',
'lowercase' => 'The :attribute must be lowercase.',
'lt' => [
'array' => 'The :attribute must have less than :value items.',
'file' => 'The :attribute must be less than :value kilobytes.',
'numeric' => 'The :attribute must be less than :value.',
'string' => 'The :attribute must be less than :value characters.',
],
'lte' => [
'array' => 'The :attribute must not have more than :value items.',
'file' => 'The :attribute must be less than or equal to :value kilobytes.',
'numeric' => 'The :attribute must be less than or equal to :value.',
'string' => 'The :attribute must be less than or equal to :value characters.',
],
'mac_address' => 'The :attribute must be a valid MAC address.',
'max' => [
'array' => 'The :attribute must not have more than :max items.',
'file' => 'The :attribute must not be greater than :max kilobytes.',
'numeric' => 'The :attribute must not be greater than :max.',
'string' => 'The :attribute must not be greater than :max characters.',
],
'max_digits' => 'The :attribute must not have more than :max digits.',
'mimes' => 'The :attribute must be a file of type: :values.',
'mimetypes' => 'The :attribute must be a file of type: :values.',
'min' => [
'array' => 'The :attribute must have at least :min items.',
'file' => 'The :attribute must be at least :min kilobytes.',
'numeric' => 'The :attribute must be at least :min.',
'string' => 'The :attribute must be at least :min characters.',
],
'min_digits' => 'The :attribute must have at least :min digits.',
'multiple_of' => 'The :attribute must be a multiple of :value.',
'not_in' => 'The selected :attribute is invalid.',
'not_regex' => 'The :attribute format is invalid.',
'numeric' => 'The :attribute must be a number.',
'password' => [
'letters' => 'The :attribute must contain at least one letter.',
'mixed' => 'The :attribute must contain at least one uppercase and one lowercase letter.',
'numbers' => 'The :attribute must contain at least one number.',
'symbols' => 'The :attribute must contain at least one symbol.',
'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',
],
'present' => 'The :attribute field must be present.',
'prohibited' => 'The :attribute field is prohibited.',
'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',
'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',
'prohibits' => 'The :attribute field prohibits :other from being present.',
'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.',
'required_array_keys' => 'The :attribute field must contain entries for: :values.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_if_accepted' => 'The :attribute field is required when :other is accepted.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values are present.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'same' => 'The :attribute and :other must match.',
'size' => [
'array' => 'The :attribute must contain :size items.',
'file' => 'The :attribute must be :size kilobytes.',
'numeric' => 'The :attribute must be :size.',
'string' => 'The :attribute must be :size characters.',
],
'starts_with' => 'The :attribute must start with one of the following: :values.',
'string' => 'The :attribute must be a string.',
'timezone' => 'The :attribute must be a valid timezone.',
'unique' => 'The :attribute has already been taken.',
'uploaded' => 'The :attribute failed to upload.',
'uppercase' => 'The :attribute must be uppercase.',
'url' => 'The :attribute must be a valid URL.',
'uuid' => 'The :attribute must be a valid UUID.',

/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/

'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
],

/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap our attribute placeholder
| with something more reader friendly such as "E-Mail Address" instead
| of "email". This simply helps us make our message more expressive.
|
*/

'attributes' => [],

];
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Hyde\Console\Commands;

use Exception;
use Hyde\Console\Commands\Interfaces\CommandHandleInterface;
use Hyde\Console\Concerns\ValidatingCommand;
use Hyde\Framework\Actions\CreatesNewPublicationType;
Expand Down
96 changes: 5 additions & 91 deletions packages/framework/src/Console/Concerns/ValidatingCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@

namespace Hyde\Console\Concerns;

use function array_keys;
use function array_values;
use function __;
use Exception;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use LaravelZero\Framework\Commands\Command;
use RuntimeException;
use function str_ends_with;
use function str_replace;
use function ucfirst;

/**
Expand Down Expand Up @@ -114,93 +111,10 @@ public function infoComment(string $info, string $comment, ?string $moreInfo = n
$this->line("<info>$info</info> [<comment>$comment</comment>]".($moreInfo ? " <info>$moreInfo</info>" : ''));
}

protected function translate($name, string $error): string
protected function translate(string $name, string $error): string
{
return $this->makeReplacements($name, Str::after($error, 'validation.'), $this->getTranslationLines());
}

protected function makeReplacements(string $name, string $line, array $replace): string
{
return str_replace(':attribute', $name, str_replace(array_keys($replace), array_values($replace), $line));
}

protected function getTranslationLines(): array
{
return [
'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.',
'after' => 'The :attribute must be a date after :date.',
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
'alpha' => 'The :attribute must only contain letters.',
'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.',
'alpha_num' => 'The :attribute must only contain letters and numbers.',
'array' => 'The :attribute must be an array.',
'before' => 'The :attribute must be a date before :date.',
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
'boolean' => 'The :attribute field must be true or false.',
'confirmed' => 'The :attribute confirmation does not match.',
'current_password' => 'The password is incorrect.',
'date' => 'The :attribute is not a valid date.',
'date_equals' => 'The :attribute must be a date equal to :date.',
'date_format' => 'The :attribute does not match the format :format.',
'declined' => 'The :attribute must be declined.',
'declined_if' => 'The :attribute must be declined when :other is :value.',
'different' => 'The :attribute and :other must be different.',
'digits' => 'The :attribute must be :digits digits.',
'digits_between' => 'The :attribute must be between :min and :max digits.',
'dimensions' => 'The :attribute has invalid image dimensions.',
'distinct' => 'The :attribute field has a duplicate value.',
'doesnt_end_with' => 'The :attribute may not end with one of the following: :values.',
'doesnt_start_with' => 'The :attribute may not start with one of the following: :values.',
'email' => 'The :attribute must be a valid email address.',
'ends_with' => 'The :attribute must end with one of the following: :values.',
'enum' => 'The selected :attribute is invalid.',
'exists' => 'The selected :attribute is invalid.',
'file' => 'The :attribute must be a file.',
'filled' => 'The :attribute field must have a value.',
'image' => 'The :attribute must be an image.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field does not exist in :other.',
'integer' => 'The :attribute must be an integer.',
'ip' => 'The :attribute must be a valid IP address.',
'ipv4' => 'The :attribute must be a valid IPv4 address.',
'ipv6' => 'The :attribute must be a valid IPv6 address.',
'json' => 'The :attribute must be a valid JSON string.',
'lowercase' => 'The :attribute must be lowercase.',
'mac_address' => 'The :attribute must be a valid MAC address.',
'max_digits' => 'The :attribute must not have more than :max digits.',
'mimes' => 'The :attribute must be a file of type: :values.',
'mimetypes' => 'The :attribute must be a file of type: :values.',
'min_digits' => 'The :attribute must have at least :min digits.',
'multiple_of' => 'The :attribute must be a multiple of :value.',
'not_in' => 'The selected :attribute is invalid.',
'not_regex' => 'The :attribute format is invalid.',
'numeric' => 'The :attribute must be a number.',
'present' => 'The :attribute field must be present.',
'prohibited' => 'The :attribute field is prohibited.',
'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',
'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',
'prohibits' => 'The :attribute field prohibits :other from being present.',
'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.',
'required_array_keys' => 'The :attribute field must contain entries for: :values.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_if_accepted' => 'The :attribute field is required when :other is accepted.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values are present.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'same' => 'The :attribute and :other must match.',
'starts_with' => 'The :attribute must start with one of the following: :values.',
'string' => 'The :attribute must be a string.',
'timezone' => 'The :attribute must be a valid timezone.',
'unique' => 'The :attribute has already been taken.',
'uploaded' => 'The :attribute failed to upload.',
'uppercase' => 'The :attribute must be uppercase.',
'url' => 'The :attribute must be a valid URL.',
'uuid' => 'The :attribute must be a valid UUID.',
];
return __($error, [
'attribute' => $name,
]);
}
}
2 changes: 2 additions & 0 deletions packages/framework/src/Framework/HydeServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Hyde\Framework\Concerns\RegistersFileLocations;
use Hyde\Framework\Features\DataCollections\DataCollectionServiceProvider;
use Hyde\Framework\Features\Session\SessionServiceProvider;
use Hyde\Framework\Providers\TranslationServiceProvider;
use Hyde\Framework\Services\AssetService;
use Hyde\Framework\Services\YamlConfigurationService;
use Hyde\Framework\Views\Components\LinkComponent;
Expand Down Expand Up @@ -114,5 +115,6 @@ protected function registerModuleServiceProviders(): void
$this->app->register(SessionServiceProvider::class);
$this->app->register(HydeConsoleServiceProvider::class);
$this->app->register(DataCollectionServiceProvider::class);
$this->app->register(TranslationServiceProvider::class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Hyde\Framework\Providers;

use function config;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
use function is_dir;
use function lang_path;

class TranslationServiceProvider extends ServiceProvider implements DeferrableProvider
{
public function register(): void
{
if (! is_dir(lang_path())) {
$this->app->useLangPath(__DIR__.'/../../../resources/lang');
}

config([
'app.locale' => config('app.locale', 'en'),
'app.fallback_locale' => config('app.fallback_locale', 'en'),
]);
}

public function boot(): void
{
$this->loadTranslationsFrom(__DIR__.'/../../../resources/lang/en/validation.php', 'validation');
}
}
34 changes: 34 additions & 0 deletions packages/framework/tests/Unit/TranslationServiceProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace Hyde\Framework\Testing\Unit;

use Hyde\Framework\Providers\TranslationServiceProvider;
use Hyde\Testing\TestCase;

/**
* @covers \Hyde\Framework\Providers\TranslationServiceProvider
*/
class TranslationServiceProviderTest extends TestCase
{
public function testRegister()
{
(new TranslationServiceProvider($this->app))->register();

$this->assertSame('en', config('app.locale'));
$this->assertSame('en', config('app.fallback_locale'));
}

public function testBoot()
{
(new TranslationServiceProvider($this->app))->boot();

$this->assertTrue(true);
}

public function testValidation()
{
$this->assertSame('The :attribute must be accepted.', __('validation.accepted'));
}
}