Implement localization for API responses and error messages

- Added localization support for API responses in English and Spanish.
- Introduced a middleware to set the API locale based on the Accept-Language header.
- Updated various exception messages and validation responses to use localized strings.
- Created new language files for English and Spanish translations.
- Refactored existing code to replace hardcoded messages with localized strings.
- Added tests to verify localization functionality and response correctness.
This commit is contained in:
2026-07-28 10:19:39 -03:00
parent 754aeebe3a
commit ff9d7728e8
34 changed files with 654 additions and 114 deletions

View File

@@ -35,7 +35,9 @@ class LoginControllerTest extends TestCase
$response
->assertOk()
->assertJsonPath('message', 'Sesion iniciada correctamente.')
->assertHeader('Content-Language', 'es')
->assertJsonPath('code', 'auth.login_success')
->assertJsonPath('message', 'Sesión iniciada correctamente.')
->assertJsonPath('token_type', 'Bearer')
->assertJsonPath('user.id', $user->id)
->assertJsonPath('user.nombre_apellido', 'Grace Hopper')
@@ -85,7 +87,8 @@ class LoginControllerTest extends TestCase
$this->withHeader('Authorization', 'Bearer '.$token)
->postJson('/api/logout')
->assertOk()
->assertJsonPath('message', 'Sesion cerrada correctamente.');
->assertJsonPath('code', 'auth.logout_success')
->assertJsonPath('message', 'Sesión cerrada correctamente.');
$this->assertDatabaseCount('personal_access_tokens', 0);
}
@@ -118,6 +121,34 @@ class LoginControllerTest extends TestCase
]);
}
public function test_it_localizes_success_and_validation_responses_from_accept_language(): void
{
$tenant = $this->createTenant('acme');
User::query()->create([
'nombre_apellido' => 'Grace Hopper',
'email' => 'grace@example.com',
'password' => Hash::make('secret123'),
]);
$this->withHeader('Accept-Language', 'en-US,en;q=0.9')
->postJson('/api/login', [
'email' => 'grace@example.com',
'password' => 'secret123',
'tenant_codigo' => $tenant->codigo,
])
->assertOk()
->assertHeader('Content-Language', 'en')
->assertJsonPath('code', 'auth.login_success')
->assertJsonPath('message', 'Signed in successfully.');
$this->withHeader('Accept-Language', 'en')
->postJson('/api/login', [])
->assertUnprocessable()
->assertHeader('Content-Language', 'en')
->assertJsonPath('errors.email.0', 'The email field is required.')
->assertJsonPath('errors.password.0', 'The password field is required.');
}
public function test_it_replaces_the_active_user_cart_with_the_guest_cart_on_login(): void
{
$tenant = $this->createTenant('acme');

View File

@@ -31,7 +31,7 @@ class TenantIntegrationControllerTest extends TestCase
Mockery::on(fn (Integration $argument) => $argument->is($integration)),
['api_key' => 'secret']
)
->andReturn(new TenantIntegration());
->andReturn(new TenantIntegration);
});
$this->postJson('/api/test-tenant/integrations/test_integration', [
@@ -40,7 +40,8 @@ class TenantIntegrationControllerTest extends TestCase
],
])->assertOk()
->assertExactJson([
'message' => 'integration configured correctly',
'code' => 'integration.configured',
'message' => 'Integración configurada correctamente.',
]);
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Tests\Feature\Localization;
use Tests\TestCase;
class ApiLocalizationTest extends TestCase
{
public function test_it_negotiates_spanish_from_accept_language(): void
{
$this->withHeader('Accept-Language', 'es-AR,es;q=0.9')
->postJson('/api/login')
->assertUnprocessable()
->assertHeader('Content-Language', 'es')
->assertJsonPath('errors.email.0', 'El campo email es obligatorio.')
->assertJsonPath('errors.password.0', 'El campo contraseña es obligatorio.');
}
public function test_it_negotiates_english_from_accept_language(): void
{
$this->withHeader('Accept-Language', 'en-US,en;q=0.9')
->postJson('/api/login')
->assertUnprocessable()
->assertHeader('Content-Language', 'en')
->assertJsonPath('errors.email.0', 'The email field is required.')
->assertJsonPath('errors.password.0', 'The password field is required.');
}
public function test_it_localizes_framework_error_responses(): void
{
$this->withHeader('Accept-Language', 'en')
->getJson('/api/route-that-does-not-exist')
->assertNotFound()
->assertHeader('Content-Language', 'en')
->assertJson([
'code' => 'errors.not_found',
'message' => 'The requested resource was not found.',
]);
}
}